func ExampleRegion_TLD() { us := language.MustParseRegion("US") gb := language.MustParseRegion("GB") uk := language.MustParseRegion("UK") bu := language.MustParseRegion("BU") fmt.Println(us.TLD()) fmt.Println(gb.TLD()) fmt.Println(uk.TLD()) fmt.Println(bu.TLD()) fmt.Println(us.Canonicalize().TLD()) fmt.Println(gb.Canonicalize().TLD()) fmt.Println(uk.Canonicalize().TLD()) fmt.Println(bu.Canonicalize().TLD()) // Output: // US <nil> // UK <nil> // UK <nil> // ZZ language: region is not a valid ccTLD // US <nil> // UK <nil> // UK <nil> // MM <nil> }
func supportedRegions() []language.Region { reg := make([]language.Region, 0, regionIndex.len()) regionIndex.keys(func(s string) { reg = append(reg, language.MustParseRegion(s)) }) return reg }
func (r *regionInfo) Region() language.Region { // TODO: this could be much faster. var buf [2]byte buf[0] = uint8(r.region >> 8) buf[1] = uint8(r.region) return language.MustParseRegion(string(buf[:])) }
func TestCountry(t *testing.T) { ch := language.MustParseRegion("CH") tld, err := ch.Canonicalize().TLD() assert.NoError(t, err) t.Logf("\n%#v\n", tld.String()) }
func TestDictionaryRegion(t *testing.T) { tests := []struct { d *Dictionary region string name string }{ {English, "FR", "France"}, {Portuguese, "009", "Oceania"}, {EuropeanPortuguese, "009", "Oceânia"}, } for i, test := range tests { tag := language.MustParseRegion(test.region) if got := test.d.Regions().Name(tag); got != test.name { t.Errorf("%d:%v: got %s; want %s", i, tag, got, test.name) } } }
func ExampleTag_values() { us := language.MustParseRegion("US") en := language.MustParseBase("en") lang, _, region := language.AmericanEnglish.Raw() fmt.Println(lang == en, region == us) lang, _, region = language.BritishEnglish.Raw() fmt.Println(lang == en, region == us) // Tags can be compared for exact equivalence using '=='. en_us, _ := language.Compose(en, us) fmt.Println(en_us == language.AmericanEnglish) // Output: // true true // true false // true }
func TestRegion(t *testing.T) { tests := []struct { dict string reg string name string }{ {"nl", "NL", "Nederland"}, {"en", "US", "United States"}, {"en", "ZZ", "Unknown Region"}, {"en", "UM", "U.S. Outlying Islands"}, {"en-GB", "UM", "U.S. Outlying Islands"}, {"en-GB", "NL", "Netherlands"}, // Canonical equivalents {"en", "UK", "United Kingdom"}, // No region {"en", "pt", "Unknown Region"}, {"en", "und", "Unknown Region"}, // Don't introduce regions with canonicalization. {"en", "mo", "Unknown Region"}, } for i, tt := range tests { d := Regions(language.MustParse(tt.dict)) var x interface{} if unicode.IsUpper(rune(tt.reg[0])) { // Region x = language.MustParseRegion(tt.reg) tag, _ := language.Raw.Compose(x) if n := d.Name(tag); n != tt.name { t.Errorf("%d:%s:%s: was %q; want %q", i, tt.dict, tt.reg, n, tt.name) } } else { // Tag x = language.Raw.MustParse(tt.reg) } if n := d.Name(x); n != tt.name { t.Errorf("%d:%s:%s: was %q; want %q", i, tt.dict, tt.reg, n, tt.name) } } }
func TestFromRegion(t *testing.T) { testCases := []struct { region, currency string ok bool }{ {"NL", "EUR", true}, {"BE", "EUR", true}, {"AG", "XCD", true}, {"CH", "CHF", true}, {"CU", "CUP", true}, // first of multiple {"DG", "USD", true}, // does not have M49 code {"150", "XXX", false}, // implicit false {"CP", "XXX", false}, // explicit false in CLDR {"CS", "XXX", false}, // all expired {"ZZ", "XXX", false}, // none match } for _, tc := range testCases { cur, ok := FromRegion(language.MustParseRegion(tc.region)) if cur.String() != tc.currency || ok != tc.ok { t.Errorf("%s: got %v, %v; want %v, %v", tc.region, cur, ok, tc.currency, tc.ok) } } }
func (b *builder) genCurrencies(w *gen.CodeWriter, data *cldr.SupplementalData) { // 3-letter ISO currency codes // Start with dummy to let index start at 1. currencies := []string{"\x00\x00\x00\x00"} // currency codes for _, reg := range data.CurrencyData.Region { for _, cur := range reg.Currency { currencies = append(currencies, cur.Iso4217) } } // Not included in the list for some reasons: currencies = append(currencies, "MVP") sort.Strings(currencies) // Unique the elements. k := 0 for i := 1; i < len(currencies); i++ { if currencies[k] != currencies[i] { currencies[k+1] = currencies[i] k++ } } currencies = currencies[:k+1] // Close with dummy for simpler and faster searching. currencies = append(currencies, "\xff\xff\xff\xff") // Write currency values. fmt.Fprintln(w, "const (") for _, c := range constants { index := sort.SearchStrings(currencies, c) fmt.Fprintf(w, "\t%s = %d\n", strings.ToLower(c), index) } fmt.Fprint(w, ")") // Compute currency-related data that we merge into the table. for _, info := range data.CurrencyData.Fractions[0].Info { if info.Iso4217 == "DEFAULT" { continue } standard := getRoundingIndex(info.Digits, info.Rounding, 0) cash := getRoundingIndex(info.CashDigits, info.CashRounding, standard) index := sort.SearchStrings(currencies, info.Iso4217) currencies[index] += mkCurrencyInfo(standard, cash) } // Set default values for entries that weren't touched. for i, c := range currencies { if len(c) == 3 { currencies[i] += mkCurrencyInfo(0, 0) } } b.currencies = tag.Index(strings.Join(currencies, "")) w.WriteComment(` currency holds an alphabetically sorted list of canonical 3-letter currency identifiers. Each identifier is followed by a byte of type currencyInfo, defined in gen_common.go.`) w.WriteConst("currency", b.currencies) // Hack alert: gofmt indents a trailing comment after an indented string. // Ensure that the next thing written is not a comment. b.numCurrencies = (len(b.currencies) / 4) - 2 w.WriteConst("numCurrencies", b.numCurrencies) // Create a table that maps regions to currencies. regionToCurrency := []toCurrency{} for _, reg := range data.CurrencyData.Region { if len(reg.Iso3166) != 2 { log.Fatalf("Unexpected group %q in region data", reg.Iso3166) } if len(reg.Currency) == 0 { continue } cur := reg.Currency[0] if cur.To != "" || cur.Tender == "false" { continue } regionToCurrency = append(regionToCurrency, toCurrency{ region: regionToCode(language.MustParseRegion(reg.Iso3166)), code: uint16(b.currencies.Index([]byte(cur.Iso4217))), }) } sort.Sort(byRegion(regionToCurrency)) w.WriteType(toCurrency{}) w.WriteVar("regionToCurrency", regionToCurrency) }
var ( langTagSet = tagSet{ single: langIndex, long: langTagsLong, } // selfTagSet is used for indexing the language strings in their own // language. selfTagSet = tagSet{ single: selfIndex, long: selfTagsLong, } zzzz = language.MustParseScript("Zzzz") zz = language.MustParseRegion("ZZ") ) // index returns the index of the tag for the given base, script and region or // its parent if the tag is not available. If the match is for a parent entry, // the excess script and region are returned. func (ts *tagSet) index(base language.Base, scr language.Script, reg language.Region) (int, language.Script, language.Region) { lang := base.String() index := -1 if (scr != language.Script{} || reg != language.Region{}) { if scr == zzzz { scr = language.Script{} } if reg == zz { reg = language.Region{} }
// generate builds and writes all tables. func (b *builder) generate() { fmt.Fprintf(b.w, versionInfo, cldr.Version) b.filter() b.setData("lang", func(g *group, loc language.Tag, ldn *cldr.LocaleDisplayNames) { if ldn.Languages != nil { for _, v := range ldn.Languages.Language { tag := tagForm.MustParse(v.Type) if tags.contains(tag) { g.set(loc, tag.String(), v.Data()) } } } }) b.setData("script", func(g *group, loc language.Tag, ldn *cldr.LocaleDisplayNames) { if ldn.Scripts != nil { for _, v := range ldn.Scripts.Script { g.set(loc, language.MustParseScript(v.Type).String(), v.Data()) } } }) b.setData("region", func(g *group, loc language.Tag, ldn *cldr.LocaleDisplayNames) { if ldn.Territories != nil { for _, v := range ldn.Territories.Territory { g.set(loc, language.MustParseRegion(v.Type).String(), v.Data()) } } }) b.makeSupported() n := b.writeParents() n += b.writeGroup("lang") n += b.writeGroup("script") n += b.writeGroup("region") b.writeSupported() n += b.writeDictionaries() b.supported = []language.Tag{self} // Compute the names of locales in their own language. Some of these names // may be specified in their parent locales. We iterate the maximum depth // of the parent three times to match successive parents of tags until a // possible match is found. for i := 0; i < 4; i++ { b.setData("self", func(g *group, tag language.Tag, ldn *cldr.LocaleDisplayNames) { parent := tag if b, s, r := tag.Raw(); i > 0 && (s != language.Script{} && r == language.Region{}) { parent, _ = language.Raw.Compose(b) } if ldn.Languages != nil { for _, v := range ldn.Languages.Language { key := tagForm.MustParse(v.Type) saved := key if key == parent { g.set(self, tag.String(), v.Data()) } for k := 0; k < i; k++ { key = key.Parent() } if key == tag { g.set(self, saved.String(), v.Data()) // set does not overwrite a value. } } } }) } n += b.writeGroup("self") fmt.Fprintf(b.w, "// TOTAL %d Bytes (%d KB)", n, n/1000) }
func TestTables(t *testing.T) { testtext.SkipIfNotLong(t) // Read the CLDR zip file. r := gen.OpenCLDRCoreZip() defer r.Close() d := &cldr.Decoder{} d.SetDirFilter("supplemental", "main") d.SetSectionFilter("numbers") data, err := d.DecodeZip(r) if err != nil { t.Fatalf("DecodeZip: %v", err) } dr, err := cldr.ParseDraft(*draft) if err != nil { t.Fatalf("filter: %v", err) } for _, lang := range data.Locales() { p := message.NewPrinter(language.MustParse(lang)) ldml := data.RawLDML(lang) if ldml.Numbers == nil || ldml.Numbers.Currencies == nil { continue } for _, c := range ldml.Numbers.Currencies.Currency { syms := cldr.MakeSlice(&c.Symbol) syms.SelectDraft(dr) for _, sym := range c.Symbol { cur, err := ParseISO(c.Type) if err != nil { continue } formatter := Symbol switch sym.Alt { case "": case "narrow": formatter = NarrowSymbol default: continue } want := sym.Data() if got := p.Sprint(formatter(cur)); got != want { t.Errorf("%s:%sSymbol(%s) = %s; want %s", lang, strings.Title(sym.Alt), c.Type, got, want) } } } } for _, reg := range data.Supplemental().CurrencyData.Region { i := 0 for ; regionData[i].Region().String() != reg.Iso3166; i++ { } it := Query(Historical, NonTender, Region(language.MustParseRegion(reg.Iso3166))) for _, cur := range reg.Currency { from, _ := time.Parse("2006-01-02", cur.From) to, _ := time.Parse("2006-01-02", cur.To) it.Next() for j, r := range []QueryIter{&iter{regionInfo: ®ionData[i]}, it} { if got, _ := r.From(); from != got { t.Errorf("%d:%s:%s:from: got %v; want %v", j, reg.Iso3166, cur.Iso4217, got, from) } if got, _ := r.To(); to != got { t.Errorf("%d:%s:%s:to: got %v; want %v", j, reg.Iso3166, cur.Iso4217, got, to) } } i++ } } }
func TestQuery(t *testing.T) { r := func(region string) language.Region { return language.MustParseRegion(region) } t1800, _ := time.Parse("2006-01-02", "1800-01-01") type result struct { region language.Region unit Unit isTender bool from, to string } testCases := []struct { name string opts []QueryOption results []result }{{ name: "XA", opts: []QueryOption{Region(r("XA"))}, results: []result{}, }, { name: "AC", opts: []QueryOption{Region(r("AC"))}, results: []result{ {r("AC"), MustParseISO("SHP"), true, "1976-01-01", ""}, }, }, { name: "US", opts: []QueryOption{Region(r("US"))}, results: []result{ {r("US"), MustParseISO("USD"), true, "1792-01-01", ""}, }, }, { name: "US-hist", opts: []QueryOption{Region(r("US")), Historical}, results: []result{ {r("US"), MustParseISO("USD"), true, "1792-01-01", ""}, }, }, { name: "US-non-tender", opts: []QueryOption{Region(r("US")), NonTender}, results: []result{ {r("US"), MustParseISO("USD"), true, "1792-01-01", ""}, {r("US"), MustParseISO("USN"), false, "", ""}, }, }, { name: "US-historical+non-tender", opts: []QueryOption{Region(r("US")), Historical, NonTender}, results: []result{ {r("US"), MustParseISO("USD"), true, "1792-01-01", ""}, {r("US"), MustParseISO("USN"), false, "", ""}, {r("US"), MustParseISO("USS"), false, "", "2014-03-01"}, }, }, { name: "1800", opts: []QueryOption{Date(t1800)}, results: []result{ {r("CH"), MustParseISO("CHF"), true, "1799-03-17", ""}, {r("GB"), MustParseISO("GBP"), true, "1694-07-27", ""}, {r("GI"), MustParseISO("GIP"), true, "1713-01-01", ""}, // The date for IE and PR seem wrong, so these may be updated at // some point causing the tests to fail. {r("IE"), MustParseISO("GBP"), true, "1800-01-01", "1922-01-01"}, {r("PR"), MustParseISO("ESP"), true, "1800-01-01", "1898-12-10"}, {r("US"), MustParseISO("USD"), true, "1792-01-01", ""}, }, }} for _, tc := range testCases { n := 0 for it := Query(tc.opts...); it.Next(); n++ { if n < len(tc.results) { got := result{ it.Region(), it.Unit(), it.IsTender(), getTime(it.From()), getTime(it.To()), } if got != tc.results[n] { t.Errorf("%s:%d: got %v; want %v", tc.name, n, got, tc.results[n]) } } } if n != len(tc.results) { t.Errorf("%s: unexpected number of results: got %d; want %d", tc.name, n, len(tc.results)) } } }
// generate builds and writes all tables. func (b *builder) generate() { fmt.Fprintf(b.w, versionInfo, cldr.Version) b.filter() b.setData("lang", func(g *group, loc language.Tag, ldn *cldr.LocaleDisplayNames) { if ldn.Languages != nil { for _, v := range ldn.Languages.Language { tag := tagForm.MustParse(v.Type) if tags.contains(tag) { g.set(loc, tag.String(), v.Data()) } } } }) b.setData("script", func(g *group, loc language.Tag, ldn *cldr.LocaleDisplayNames) { if ldn.Scripts != nil { for _, v := range ldn.Scripts.Script { code := language.MustParseScript(v.Type) if code.IsPrivateUse() { // Qaaa..Qabx // TODO: data currently appears to be very meager. // Reconsider if we have data for English. if loc == language.English { log.Fatal("Consider including data for private use scripts.") } continue } g.set(loc, code.String(), v.Data()) } } }) b.setData("region", func(g *group, loc language.Tag, ldn *cldr.LocaleDisplayNames) { if ldn.Territories != nil { for _, v := range ldn.Territories.Territory { g.set(loc, language.MustParseRegion(v.Type).String(), v.Data()) } } }) b.makeSupported() b.writeParents() b.writeGroup("lang") b.writeGroup("script") b.writeGroup("region") b.w.WriteConst("numSupported", len(b.supported)) buf := bytes.Buffer{} for _, tag := range b.supported { fmt.Fprint(&buf, tag.String(), "|") } b.w.WriteConst("supported", buf.String()) b.writeDictionaries() b.supported = []language.Tag{self} // Compute the names of locales in their own language. Some of these names // may be specified in their parent locales. We iterate the maximum depth // of the parent three times to match successive parents of tags until a // possible match is found. for i := 0; i < 4; i++ { b.setData("self", func(g *group, tag language.Tag, ldn *cldr.LocaleDisplayNames) { parent := tag if b, s, r := tag.Raw(); i > 0 && (s != language.Script{} && r == language.Region{}) { parent, _ = language.Raw.Compose(b) } if ldn.Languages != nil { for _, v := range ldn.Languages.Language { key := tagForm.MustParse(v.Type) saved := key if key == parent { g.set(self, tag.String(), v.Data()) } for k := 0; k < i; k++ { key = key.Parent() } if key == tag { g.set(self, saved.String(), v.Data()) // set does not overwrite a value. } } } }) } b.writeGroup("self") }