language: move to CLDR test format
This helps exchanging test files between
platforms.
Change-Id: I1ed8e2a9d99d85afdeb0e8bd76cb1d6354cbbd67
Reviewed-on: https://go-review.googlesource.com/55391
Run-TryBot: Marcel van Lohuizen <mpvl@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Nigel Tao <nigeltao@golang.org>
diff --git a/language/data_test.go b/language/data_test.go
deleted file mode 100644
index e1b9606..0000000
--- a/language/data_test.go
+++ /dev/null
@@ -1,461 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package language
-
-import (
- "flag"
- "fmt"
- "os"
- "testing"
-)
-
-var outfile = flag.String("genucd", "", "generate UCD file from test data")
-
-func TestGenerate(t *testing.T) {
- if *outfile == "" {
- return
- }
-
- w, err := os.Create(*outfile)
- if err != nil {
- t.Error(err)
- }
- defer w.Close()
-
- for _, tc := range matchTests {
- fmt.Fprintln(w, "# "+tc.comment)
- for _, t := range tc.test {
- fmt.Fprintf(w, "%s ; %s ; %s\n", tc.supported, t.desired, t.match)
- }
- fmt.Fprintln(w)
- }
-}
-
-type matchTest struct {
- comment string
- supported string
- test []struct{ match, desired string }
-}
-
-var matchTests = []matchTest{
- {
- "basics",
- "fr, en-GB, en",
- []struct{ match, desired string }{
- {"en-GB", "en-GB"},
- {"en", "en-US"},
- {"fr", "fr-FR"},
- {"fr", "ja-JP"},
- },
- },
- {
- "script fallbacks",
- "zh-CN, zh-TW, iw",
- []struct{ match, desired string }{
- {"zh-TW", "zh-Hant"},
- {"zh-CN", "zh"},
- {"zh-CN", "zh-Hans-CN"},
- {"zh-TW", "zh-Hant-HK"},
- {"iw", "he-IT"},
- },
- },
- {
- "language-specific script fallbacks 1",
- "en, sr, nl",
- []struct{ match, desired string }{
- {"sr", "sr-Latn"},
- {"en", "sh"},
- {"en", "hr"},
- {"en", "bs"},
- // TODO: consider if the following match is a good one.
- // Due to new script first rule, which maybe should be an option.
- {"sr", "nl-Cyrl"},
- },
- },
- {
- "language-specific script fallbacks 2",
- "en, sh",
- []struct{ match, desired string }{
- {"sh", "sr"},
- {"sh", "sr-Cyrl"},
- {"sh", "hr"},
- },
- },
- {
- "don't match hr to sr-Latn",
- "en, sr-Latn",
- []struct{ match, desired string }{
- {"en", "hr"},
- },
- },
- {
- "both deprecated and not",
- "fil, tl, iw, he",
- []struct{ match, desired string }{
- {"he", "he-IT"},
- {"he", "he"},
- {"iw", "iw"},
- {"fil", "fil-IT"},
- {"fil", "fil"},
- {"tl", "tl"},
- },
- },
- {
- "nearby languages",
- "en, fil, ro, nn",
- []struct{ match, desired string }{
- {"fil", "tl"},
- {"ro", "mo"},
- {"nn", "nb"},
- {"en", "ja"}, // make sure default works
- },
- },
- {
- "nearby languages: Nynorsk to Bokmål",
- "en, nb",
- []struct{ match, desired string }{
- {"nb", "nn"},
- },
- },
- {
- "nearby languages: Danish does not match nn",
- "en, nn",
- []struct{ match, desired string }{
- {"en", "da"},
- },
- },
- {
- "nearby languages: Danish matches no",
- "en, no",
- []struct{ match, desired string }{
- {"no", "da"},
- },
- },
- {
- "nearby languages: Danish matches nb",
- "en, nb",
- []struct{ match, desired string }{
- {"nb", "da"},
- },
- },
- {
- "prefer matching languages over language variants.",
- "nn, en-GB",
- []struct{ match, desired string }{
- {"en-GB", "no, en-US"},
- {"en-GB", "nb, en-US"},
- },
- },
- {
- "deprecated version is closer than same language with other differences",
- "nl, he, en-GB",
- []struct{ match, desired string }{
- {"he", "iw, en-US"},
- },
- },
- {
- "macro equivalent is closer than same language with other differences",
- "nl, zh, en-GB, no",
- []struct{ match, desired string }{
- {"zh", "cmn, en-US"},
- {"no", "nb, en-US"},
- },
- },
- {
- "legacy equivalent is closer than same language with other differences",
- "nl, fil, en-GB",
- []struct{ match, desired string }{
- {"fil", "tl, en-US"},
- },
- },
- {
- "exact over equivalent",
- "en, ro, mo, ro-MD",
- []struct{ match, desired string }{
- {"ro", "ro"},
- {"mo", "mo"},
- {"ro-MD", "ro-MD"},
- },
- },
- {
- "maximization of legacy",
- "sr-Cyrl, sr-Latn, ro, ro-MD",
- []struct{ match, desired string }{
- {"sr-Latn", "sh"},
- {"ro-MD", "mo"},
- },
- },
- {
- "empty",
- "",
- []struct{ match, desired string }{
- {"und", "fr"},
- {"und", "en"},
- },
- },
- {
- "private use subtags",
- "fr, en-GB, x-bork, es-ES, es-419",
- []struct{ match, desired string }{
- {"fr", "x-piglatin"},
- {"x-bork", "x-bork"},
- },
- },
- {
- "grandfathered codes",
- "fr, i-klingon, en-Latn-US",
- []struct{ match, desired string }{
- {"en-Latn-US", "en-GB-oed"},
- {"tlh", "i-klingon"},
- },
- },
- {
- "exact match",
- "fr, en-GB, ja, es-ES, es-MX",
- []struct{ match, desired string }{
- {"ja", "ja, de"},
- },
- },
- {
- "simple variant match",
- "fr, en-GB, ja, es-ES, es-MX",
- []struct{ match, desired string }{
- // Intentionally avoiding a perfect-match or two candidates for variant matches.
- {"en-GB", "de, en-US"},
- // Fall back.
- {"fr", "de, zh"},
- },
- },
- {
- "best match for traditional Chinese",
- // Scenario: An application that only supports Simplified Chinese (and some
- // other languages), but does not support Traditional Chinese. zh-Hans-CN
- // could be replaced with zh-CN, zh, or zh-Hans, it wouldn't make much of
- // a difference.
- "fr, zh-Hans-CN, en-US",
- []struct{ match, desired string }{
- {"zh-Hans-CN", "zh-TW"},
- {"zh-Hans-CN", "zh-Hant"},
- // One can avoid a zh-Hant to zh-Hans match by including a second language
- // preference which is a better match.
- {"en-US", "zh-TW, en"},
- {"en-US", "zh-Hant-CN, en"},
- {"zh-Hans-CN", "zh-Hans, en"},
- },
- },
- // More specific region and script tie-breakers.
- {
- "more specific script should win in case regions are identical",
- "af, af-Latn, af-Arab",
- []struct{ match, desired string }{
- {"af", "af"},
- {"af", "af-ZA"},
- {"af-Latn", "af-Latn-ZA"},
- {"af-Latn", "af-Latn"},
- },
- },
- {
- "more specific region should win",
- "nl, nl-NL, nl-BE",
- []struct{ match, desired string }{
- {"nl", "nl"},
- {"nl", "nl-Latn"},
- {"nl-NL", "nl-Latn-NL"},
- {"nl-NL", "nl-NL"},
- },
- },
- {
- "region may replace matched if matched is enclosing",
- "es-419,es",
- []struct{ match, desired string }{
- {"es-MX", "es-MX"},
- {"es", "es-SG"},
- },
- },
- {
- "more specific region wins over more specific script",
- "nl, nl-Latn, nl-NL, nl-BE",
- []struct{ match, desired string }{
- {"nl", "nl"},
- {"nl-Latn", "nl-Latn"},
- {"nl-NL", "nl-NL"},
- {"nl-NL", "nl-Latn-NL"},
- },
- },
- // Region distance tie-breakers.
- {
- "region distance Portuguese",
- "pt, pt-PT",
- []struct{ match, desired string }{
- {"pt-PT", "pt-ES"},
- },
- },
- {
- "region distance French",
- "en, fr, fr-CA, fr-CH",
- []struct{ match, desired string }{
- {"fr-CA", "fr-US"},
- },
- },
- {
- "region distance German",
- "de-AT, de-DE, de-CH",
- []struct{ match, desired string }{
- {"de-DE", "de"},
- },
- },
- {
- "en-AU is closer to en-GB than to en (which is en-US)",
- "en, en-GB, es-ES, es-419",
- []struct{ match, desired string }{
- {"en-GB", "en-AU"},
- {"es-MX", "es-MX"},
- {"es-ES", "es-PT"},
- },
- },
- // Test exceptions with "und".
- // When the undefined language doesn't match anything in the list, return the default, as usual.
- // max("und") = "en-Latn-US", and since matching is based on maximized tags, the undefined
- // language would normally match English. But that would produce the counterintuitive results.
- // Matching "und" to "it,en" would be "en" matching "en" to "it,und" would be "und".
- // To avoid this max("und") is defined as "und"
- {
- "undefined",
- "it, fr",
- []struct{ match, desired string }{
- {"it", "und"},
- },
- },
- {
- "und does not match en",
- "it, en",
- []struct{ match, desired string }{
- {"it", "und"},
- },
- },
- {
- "undefined in priority list",
- "it, und",
- []struct{ match, desired string }{
- {"und", "und"},
- {"it", "en"},
- },
- },
- // Undefined scripts and regions.
- {
- "undefined",
- "it, fr, zh",
- []struct{ match, desired string }{
- {"fr", "und-FR"},
- {"zh", "und-CN"},
- {"zh", "und-Hans"},
- {"zh", "und-Hant"},
- {"it", "und-Latn"},
- },
- },
- // Early termination conditions: do not consider all desired strings if
- // a match is good enough.
- {
- "match on maximized tag",
- "fr, en-GB, ja, es-ES, es-MX",
- []struct{ match, desired string }{
- // ja-JP matches ja on likely subtags, and it's listed first,
- // thus it wins over the second preference en-GB.
- {"ja", "ja-JP, en-GB"},
- {"ja", "ja-Jpan-JP, en-GB"},
- },
- },
- {
- "pick best maximized tag",
- "ja, ja-Jpan-US, ja-JP, en, ru",
- []struct{ match, desired string }{
- {"ja", "ja-Jpan, ru"},
- {"ja-JP", "ja-JP, ru"},
- {"ja-Jpan-US", "ja-US, ru"},
- },
- },
- {
- "termination: pick best maximized match",
- "ja, ja-Jpan, ja-JP, en, ru",
- []struct{ match, desired string }{
- {"ja-JP", "ja-Jpan-JP, ru"},
- {"ja-Jpan", "ja-Jpan, ru"},
- },
- },
- {
- "no match on maximized",
- "en, de, fr, ja",
- []struct{ match, desired string }{
- // de maximizes to de-DE.
- // Pick the exact match for the secondary language instead.
- {"fr", "de-CH, fr"},
- },
- },
-
- // Test that the CLDR parent relations are correctly preserved by the matcher.
- // These matches may change for different CLDR versions.
- {
- "parent relation preserved",
- "en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK",
- []struct{ match, desired string }{
- {"en-GB", "en-150"},
- // {"en-GB", "en-001"}, // TODO: currently en, should probably be en-GB
- {"en-GB", "en-AU"},
- {"en-GB", "en-BE"},
- {"en-GB", "en-GG"},
- {"en-GB", "en-GI"},
- {"en-GB", "en-HK"},
- {"en-GB", "en-IE"},
- {"en-GB", "en-IM"},
- {"en-GB", "en-IN"},
- {"en-GB", "en-JE"},
- {"en-GB", "en-MT"},
- {"en-GB", "en-NZ"},
- {"en-GB", "en-PK"},
- {"en-GB", "en-SG"},
- {"en-GB", "en-DE"},
- {"en-GB", "en-MT"},
- {"es-AR", "es-AR"},
- {"es-BO", "es-BO"},
- {"es-CL", "es-CL"},
- {"es-CO", "es-CO"},
- {"es-CR", "es-CR"},
- {"es-CU", "es-CU"},
- {"es-DO", "es-DO"},
- {"es-EC", "es-EC"},
- {"es-GT", "es-GT"},
- {"es-HN", "es-HN"},
- {"es-MX", "es-MX"},
- {"es-NI", "es-NI"},
- {"es-PA", "es-PA"},
- {"es-PE", "es-PE"},
- {"es-PR", "es-PR"},
- {"es", "es-PT"},
- {"es-PY", "es-PY"},
- {"es-SV", "es-SV"},
- {"es-419", "es-US"}, // US is not in Latin America, so don't make more specific.
- {"es-UY", "es-UY"},
- {"es-VE", "es-VE"},
- {"pt-PT", "pt-AO"},
- {"pt-PT", "pt-CV"},
- {"pt-PT", "pt-GW"},
- {"pt-PT", "pt-MO"},
- {"pt-PT", "pt-MZ"},
- {"pt-PT", "pt-ST"},
- {"pt-PT", "pt-TL"},
- },
- },
- // Options and variants are inherited from user-defined settings.
- {
- "preserve Unicode extension",
- "en, de, sl-nedis",
- []struct{ match, desired string }{
- {"de-u-co-phonebk", "de-FR-u-co-phonebk"},
- {"sl-nedis-u-cu-eur", "sl-nedis-u-cu-eur"},
- {"sl-nedis-u-cu-eur", "sl-u-cu-eur"},
- {"sl-nedis-u-cu-eur", "sl-HR-nedis-u-cu-eur"},
- },
- },
-}
diff --git a/language/match_test.go b/language/match_test.go
index 4fb56a0..ae9a2f6 100644
--- a/language/match_test.go
+++ b/language/match_test.go
@@ -10,6 +10,7 @@
"fmt"
"os"
"path"
+ "path/filepath"
"strings"
"testing"
@@ -19,31 +20,37 @@
var verbose = flag.Bool("verbose", false, "set to true to print the internal tables of matchers")
-func TestCLDRCompliance(t *testing.T) {
- r, err := os.Open("testdata/localeMatcherTest.txt")
- if err != nil {
- t.Fatal(err)
- }
- ucd.Parse(r, func(p *ucd.Parser) {
- name := strings.Replace(path.Join(p.String(0), p.String(1)), " ", "", -1)
- if skip[name] {
- return
+func TestCompliance(t *testing.T) {
+ filepath.Walk("testdata", func(file string, info os.FileInfo, err error) error {
+ if info.IsDir() {
+ return nil
}
- t.Run(name, func(t *testing.T) {
- supported := makeTagList(p.String(0))
- desired := makeTagList(p.String(1))
- gotCombined, index, _ := NewMatcher(supported).Match(desired...)
+ r, err := os.Open(file)
+ if err != nil {
+ t.Fatal(err)
+ }
+ ucd.Parse(r, func(p *ucd.Parser) {
+ name := strings.Replace(path.Join(p.String(0), p.String(1)), " ", "", -1)
+ if skip[name] {
+ return
+ }
+ t.Run(info.Name()+"/"+name, func(t *testing.T) {
+ supported := makeTagList(p.String(0))
+ desired := makeTagList(p.String(1))
+ gotCombined, index, _ := NewMatcher(supported).Match(desired...)
- gotMatch := supported[index]
- wantMatch := Make(p.String(2))
- if gotMatch != wantMatch {
- t.Fatalf("match: got %q; want %q", gotMatch, wantMatch)
- }
- wantCombined, err := Parse(p.String(3))
- if err == nil && gotCombined != wantCombined {
- t.Errorf("combined: got %q; want %q", gotCombined, wantCombined)
- }
+ gotMatch := supported[index]
+ wantMatch := mk(p.String(2))
+ if gotMatch != wantMatch {
+ t.Fatalf("match: got %q; want %q", gotMatch, wantMatch)
+ }
+ wantCombined, err := Raw.Parse(p.String(3))
+ if err == nil && gotCombined != wantCombined {
+ t.Errorf("combined: got %q; want %q", gotCombined, wantCombined)
+ }
+ })
})
+ return nil
})
}
@@ -106,7 +113,7 @@
func makeTagList(s string) (tags []Tag) {
for _, s := range strings.Split(s, ",") {
- tags = append(tags, Make(strings.TrimSpace(s)))
+ tags = append(tags, mk(strings.TrimSpace(s)))
}
return tags
}
@@ -370,35 +377,8 @@
return fmt.Sprintf("%v:%d:%v:%v-%v|%v", t.tag, t.index, t.conf, t.maxRegion, t.maxScript, t.altScript)
}
-func parseSupported(list string) (out []Tag) {
- for _, s := range strings.Split(list, ",") {
- out = append(out, mk(strings.TrimSpace(s)))
- }
- return out
-}
-
-// The test set for TestBestMatch is defined in data_test.go.
-func TestBestMatch(t *testing.T) {
- for _, tt := range matchTests {
- supported := parseSupported(tt.supported)
- m := newMatcher(supported, nil)
- if *verbose {
- fmt.Printf("%s:\n%v\n", tt.comment, m)
- }
- for _, tm := range tt.test {
- t.Run(path.Join(tt.comment, tt.supported, tm.desired), func(t *testing.T) {
- tag, _, conf := m.Match(parseSupported(tm.desired)...)
- if tag.String() != tm.match {
- t.Errorf("find %s in %q: have %s; want %s (%v)", tm.desired, tt.supported, tag, tm.match, conf)
- }
- })
-
- }
- }
-}
-
func TestBestMatchAlloc(t *testing.T) {
- m := NewMatcher(parseSupported("en sr nl"))
+ m := NewMatcher(makeTagList("en sr nl"))
// Go allocates when creating a list of tags from a single tag!
list := []Tag{English}
avg := testtext.AllocsPerRun(1, func() {
diff --git a/language/testdata/localeMatcherTest.txt b/language/testdata/CLDRLocaleMatcherTest.txt
similarity index 100%
rename from language/testdata/localeMatcherTest.txt
rename to language/testdata/CLDRLocaleMatcherTest.txt
diff --git a/language/testdata/GoLocaleMatcherTest.txt b/language/testdata/GoLocaleMatcherTest.txt
index cc59e9b..7817979 100644
--- a/language/testdata/GoLocaleMatcherTest.txt
+++ b/language/testdata/GoLocaleMatcherTest.txt
@@ -9,7 +9,7 @@
zh-CN, zh-TW, iw ; zh ; zh-CN
zh-CN, zh-TW, iw ; zh-Hans-CN ; zh-CN
zh-CN, zh-TW, iw ; zh-Hant-HK ; zh-TW
-zh-CN, zh-TW, iw ; he-IT ; iw
+zh-CN, zh-TW, iw ; he-IT ; iw ; iw # should the surface tag be he?
# language-specific script fallbacks 1
en, sr, nl ; sr-Latn ; sr
@@ -114,7 +114,7 @@
nl, nl-NL, nl-BE ; nl-NL ; nl-NL
# region may replace matched if matched is enclosing
-es-419,es ; es-MX ; es-MX
+es-419,es ; es-MX ; es-419 ; es-MX
es-419,es ; es-SG ; es
# more specific region wins over more specific script
@@ -134,7 +134,7 @@
# en-AU is closer to en-GB than to en (which is en-US)
en, en-GB, es-ES, es-419 ; en-AU ; en-GB
-en, en-GB, es-ES, es-419 ; es-MX ; es-MX
+en, en-GB, es-ES, es-419 ; es-MX ; es-419 ; es-MX
en, en-GB, es-ES, es-419 ; es-PT ; es-ES
# undefined
@@ -187,27 +187,27 @@
en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; en-SG ; en-GB
en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; en-DE ; en-GB
en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; en-MT ; en-GB
-en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-AR ; es-AR
-en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-BO ; es-BO
-en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-CL ; es-CL
-en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-CO ; es-CO
-en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-CR ; es-CR
-en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-CU ; es-CU
-en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-DO ; es-DO
-en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-EC ; es-EC
-en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-GT ; es-GT
-en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-HN ; es-HN
-en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-MX ; es-MX
-en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-NI ; es-NI
-en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-PA ; es-PA
-en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-PE ; es-PE
-en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-PR ; es-PR
+en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-AR ; es-419 ; es-AR
+en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-BO ; es-419 ; es-BO
+en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-CL ; es-419 ; es-CL
+en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-CO ; es-419 ; es-CO
+en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-CR ; es-419 ; es-CR
+en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-CU ; es-419 ; es-CU
+en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-DO ; es-419 ; es-DO
+en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-EC ; es-419 ; es-EC
+en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-GT ; es-419 ; es-GT
+en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-HN ; es-419 ; es-HN
+en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-MX ; es-419 ; es-MX
+en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-NI ; es-419 ; es-NI
+en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-PA ; es-419 ; es-PA
+en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-PE ; es-419 ; es-PE
+en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-PR ; es-419 ; es-PR
en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-PT ; es
-en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-PY ; es-PY
-en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-SV ; es-SV
+en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-PY ; es-419 ; es-PY
+en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-SV ; es-419 ; es-SV
en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-US ; es-419
-en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-UY ; es-UY
-en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-VE ; es-VE
+en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-UY ; es-419 ; es-UY
+en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; es-VE ; es-419 ; es-VE
en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; pt-AO ; pt-PT
en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; pt-CV ; pt-PT
en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; pt-GW ; pt-PT
@@ -217,8 +217,8 @@
en, en-US, en-GB, es, es-419, pt, pt-BR, pt-PT, zh, zh-Hant, zh-Hant-HK ; pt-TL ; pt-PT
# preserve Unicode extension
-en, de, sl-nedis ; de-FR-u-co-phonebk ; de-u-co-phonebk
-en, de, sl-nedis ; sl-nedis-u-cu-eur ; sl-nedis-u-cu-eur
-en, de, sl-nedis ; sl-u-cu-eur ; sl-nedis-u-cu-eur
-en, de, sl-nedis ; sl-HR-nedis-u-cu-eur ; sl-nedis-u-cu-eur
+en, de, sl-nedis ; de-FR-u-co-phonebk ; de ; de-u-co-phonebk
+en, de, sl-nedis ; sl-nedis-u-cu-eur ; sl-nedis ; sl-nedis-u-cu-eur
+en, de, sl-nedis ; sl-u-cu-eur ; sl-nedis ; sl-nedis-u-cu-eur
+en, de, sl-nedis ; sl-HR-nedis-u-cu-eur ; sl-nedis ; sl-nedis-u-cu-eur