display_test.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  1. // Copyright 2014 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package display
  5. import (
  6. "fmt"
  7. "reflect"
  8. "strings"
  9. "testing"
  10. "unicode"
  11. "golang.org/x/text/internal/testtext"
  12. "golang.org/x/text/language"
  13. "golang.org/x/text/message"
  14. )
  15. // TODO: test that tables are properly dropped by the linker for various use
  16. // cases.
  17. var (
  18. firstLang2aa = language.MustParseBase("aa")
  19. lastLang2zu = language.MustParseBase("zu")
  20. firstLang3ace = language.MustParseBase("ace")
  21. lastLang3zza = language.MustParseBase("zza")
  22. firstTagAr001 = language.MustParse("ar-001")
  23. lastTagZhHant = language.MustParse("zh-Hant")
  24. )
  25. // TestValues tests that for all languages, regions, and scripts in Values, at
  26. // least one language has a name defined for it by checking it exists in
  27. // English, which is assumed to be the most comprehensive. It is also tested
  28. // that a Namer returns "" for unsupported values.
  29. func TestValues(t *testing.T) {
  30. type testcase struct {
  31. kind string
  32. n Namer
  33. }
  34. // checkDefined checks that a value exists in a Namer.
  35. checkDefined := func(x interface{}, namers []testcase) {
  36. for _, n := range namers {
  37. testtext.Run(t, fmt.Sprintf("%s.Name(%s)", n.kind, x), func(t *testing.T) {
  38. if n.n.Name(x) == "" {
  39. // As of version 28 there is no data for az-Arab in English,
  40. // although there is useful data in other languages.
  41. if x.(fmt.Stringer).String() == "az-Arab" {
  42. return
  43. }
  44. t.Errorf("supported but no result")
  45. }
  46. })
  47. }
  48. }
  49. // checkUnsupported checks that a value does not exist in a Namer.
  50. checkUnsupported := func(x interface{}, namers []testcase) {
  51. for _, n := range namers {
  52. if got := n.n.Name(x); got != "" {
  53. t.Fatalf("%s.Name(%s): unsupported tag gave non-empty result: %q", n.kind, x, got)
  54. }
  55. }
  56. }
  57. tags := map[language.Tag]bool{}
  58. namers := []testcase{
  59. {"Languages(en)", Languages(language.English)},
  60. {"Tags(en)", Tags(language.English)},
  61. {"English.Languages()", English.Languages()},
  62. {"English.Tags()", English.Tags()},
  63. }
  64. for _, tag := range Values.Tags() {
  65. checkDefined(tag, namers)
  66. tags[tag] = true
  67. }
  68. for _, base := range language.Supported.BaseLanguages() {
  69. tag, _ := language.All.Compose(base)
  70. if !tags[tag] {
  71. checkUnsupported(tag, namers)
  72. }
  73. }
  74. regions := map[language.Region]bool{}
  75. namers = []testcase{
  76. {"Regions(en)", Regions(language.English)},
  77. {"English.Regions()", English.Regions()},
  78. }
  79. for _, r := range Values.Regions() {
  80. checkDefined(r, namers)
  81. regions[r] = true
  82. }
  83. for _, r := range language.Supported.Regions() {
  84. if r = r.Canonicalize(); !regions[r] {
  85. checkUnsupported(r, namers)
  86. }
  87. }
  88. scripts := map[language.Script]bool{}
  89. namers = []testcase{
  90. {"Scripts(en)", Scripts(language.English)},
  91. {"English.Scripts()", English.Scripts()},
  92. }
  93. for _, s := range Values.Scripts() {
  94. checkDefined(s, namers)
  95. scripts[s] = true
  96. }
  97. for _, s := range language.Supported.Scripts() {
  98. // Canonicalize the script.
  99. tag, _ := language.DeprecatedScript.Compose(s)
  100. if _, s, _ = tag.Raw(); !scripts[s] {
  101. checkUnsupported(s, namers)
  102. }
  103. }
  104. }
  105. // TestSupported tests that we have at least some Namers for languages that we
  106. // claim to support. To test the claims in the documentation, it also verifies
  107. // that if a Namer is returned, it will have at least some data.
  108. func TestSupported(t *testing.T) {
  109. supportedTags := Supported.Tags()
  110. if len(supportedTags) != numSupported {
  111. t.Errorf("number of supported was %d; want %d", len(supportedTags), numSupported)
  112. }
  113. namerFuncs := []struct {
  114. kind string
  115. fn func(language.Tag) Namer
  116. }{
  117. {"Tags", Tags},
  118. {"Languages", Languages},
  119. {"Regions", Regions},
  120. {"Scripts", Scripts},
  121. }
  122. // Verify that we have at least one Namer for all tags we claim to support.
  123. tags := make(map[language.Tag]bool)
  124. for _, tag := range supportedTags {
  125. // Test we have at least one Namer for this supported Tag.
  126. found := false
  127. for _, kind := range namerFuncs {
  128. if defined(t, kind.kind, kind.fn(tag), tag) {
  129. found = true
  130. }
  131. }
  132. if !found {
  133. t.Errorf("%s: supported, but no data available", tag)
  134. }
  135. if tags[tag] {
  136. t.Errorf("%s: included in Supported.Tags more than once", tag)
  137. }
  138. tags[tag] = true
  139. }
  140. // Verify that we have no Namers for tags we don't claim to support.
  141. for _, base := range language.Supported.BaseLanguages() {
  142. tag, _ := language.All.Compose(base)
  143. // Skip tags that are supported after matching.
  144. if _, _, conf := matcher.Match(tag); conf != language.No {
  145. continue
  146. }
  147. // Test there are no Namers for this tag.
  148. for _, kind := range namerFuncs {
  149. if defined(t, kind.kind, kind.fn(tag), tag) {
  150. t.Errorf("%[1]s(%[2]s) returns a Namer, but %[2]s is not in the set of supported Tags.", kind.kind, tag)
  151. }
  152. }
  153. }
  154. }
  155. // defined reports whether n is a proper Namer, which means it is non-nil and
  156. // must have at least one non-empty value.
  157. func defined(t *testing.T, kind string, n Namer, tag language.Tag) bool {
  158. if n == nil {
  159. return false
  160. }
  161. switch kind {
  162. case "Tags":
  163. for _, t := range Values.Tags() {
  164. if n.Name(t) != "" {
  165. return true
  166. }
  167. }
  168. case "Languages":
  169. for _, t := range Values.BaseLanguages() {
  170. if n.Name(t) != "" {
  171. return true
  172. }
  173. }
  174. case "Regions":
  175. for _, t := range Values.Regions() {
  176. if n.Name(t) != "" {
  177. return true
  178. }
  179. }
  180. case "Scripts":
  181. for _, t := range Values.Scripts() {
  182. if n.Name(t) != "" {
  183. return true
  184. }
  185. }
  186. }
  187. t.Errorf("%s(%s) returns non-nil Namer without content", kind, tag)
  188. return false
  189. }
  190. func TestCoverage(t *testing.T) {
  191. en := language.English
  192. tests := []struct {
  193. n Namer
  194. x interface{}
  195. }{
  196. {Languages(en), Values.Tags()},
  197. {Scripts(en), Values.Scripts()},
  198. {Regions(en), Values.Regions()},
  199. }
  200. for i, tt := range tests {
  201. uniq := make(map[string]interface{})
  202. v := reflect.ValueOf(tt.x)
  203. for j := 0; j < v.Len(); j++ {
  204. x := v.Index(j).Interface()
  205. // As of version 28 there is no data for az-Arab in English,
  206. // although there is useful data in other languages.
  207. if x.(fmt.Stringer).String() == "az-Arab" {
  208. continue
  209. }
  210. s := tt.n.Name(x)
  211. if s == "" {
  212. t.Errorf("%d:%d:%s: missing content", i, j, x)
  213. } else if uniq[s] != nil {
  214. t.Errorf("%d:%d:%s: identical return value %q for %v and %v", i, j, x, s, x, uniq[s])
  215. }
  216. uniq[s] = x
  217. }
  218. }
  219. }
  220. // TestUpdate tests whether dictionary entries for certain languages need to be
  221. // updated. For some languages, some of the headers may be empty or they may be
  222. // identical to the parent. This code detects if such entries need to be updated
  223. // after a table update.
  224. func TestUpdate(t *testing.T) {
  225. tests := []struct {
  226. d *Dictionary
  227. tag string
  228. }{
  229. {ModernStandardArabic, "ar-001"},
  230. {AmericanEnglish, "en-US"},
  231. {EuropeanSpanish, "es-ES"},
  232. {BrazilianPortuguese, "pt-BR"},
  233. {SimplifiedChinese, "zh-Hans"},
  234. }
  235. for _, tt := range tests {
  236. _, i, _ := matcher.Match(language.MustParse(tt.tag))
  237. if !reflect.DeepEqual(tt.d.lang, langHeaders[i]) {
  238. t.Errorf("%s: lang table update needed", tt.tag)
  239. }
  240. if !reflect.DeepEqual(tt.d.script, scriptHeaders[i]) {
  241. t.Errorf("%s: script table update needed", tt.tag)
  242. }
  243. if !reflect.DeepEqual(tt.d.region, regionHeaders[i]) {
  244. t.Errorf("%s: region table update needed", tt.tag)
  245. }
  246. }
  247. }
  248. func TestIndex(t *testing.T) {
  249. notIn := []string{"aa", "xx", "zz", "aaa", "xxx", "zzz", "Aaaa", "Xxxx", "Zzzz"}
  250. tests := []tagIndex{
  251. {
  252. "",
  253. "",
  254. "",
  255. },
  256. {
  257. "bb",
  258. "",
  259. "",
  260. },
  261. {
  262. "",
  263. "bbb",
  264. "",
  265. },
  266. {
  267. "",
  268. "",
  269. "Bbbb",
  270. },
  271. {
  272. "bb",
  273. "bbb",
  274. "Bbbb",
  275. },
  276. {
  277. "bbccddyy",
  278. "bbbcccdddyyy",
  279. "BbbbCcccDdddYyyy",
  280. },
  281. }
  282. for i, tt := range tests {
  283. // Create the test set from the tagIndex.
  284. cnt := 0
  285. for sz := 2; sz <= 4; sz++ {
  286. a := tt[sz-2]
  287. for j := 0; j < len(a); j += sz {
  288. s := a[j : j+sz]
  289. if idx := tt.index(s); idx != cnt {
  290. t.Errorf("%d:%s: index was %d; want %d", i, s, idx, cnt)
  291. }
  292. cnt++
  293. }
  294. }
  295. if n := tt.len(); n != cnt {
  296. t.Errorf("%d: len was %d; want %d", i, n, cnt)
  297. }
  298. for _, x := range notIn {
  299. if idx := tt.index(x); idx != -1 {
  300. t.Errorf("%d:%s: index was %d; want -1", i, x, idx)
  301. }
  302. }
  303. }
  304. }
  305. func TestTag(t *testing.T) {
  306. tests := []struct {
  307. dict string
  308. tag string
  309. name string
  310. }{
  311. // sr is in Value.Languages(), but is not supported by agq.
  312. {"agq", "sr", "|[language: sr]"},
  313. {"nl", "nl", "Nederlands"},
  314. // CLDR 30 dropped Vlaams as the word for nl-BE. It is still called
  315. // Flemish in English, though. TODO: check if this is a CLDR bug.
  316. // {"nl", "nl-BE", "Vlaams"},
  317. {"nl", "nl-BE", "Nederlands (België)"},
  318. {"nl", "vls", "West-Vlaams"},
  319. {"en", "nl-BE", "Flemish"},
  320. {"en", "en", "English"},
  321. {"en", "en-GB", "British English"},
  322. {"en", "en-US", "American English"}, // American English in CLDR 24+
  323. {"ru", "ru", "русский"},
  324. {"ru", "ru-RU", "русский (Россия)"},
  325. {"ru", "ru-Cyrl", "русский (кириллица)"},
  326. {"en", lastLang2zu.String(), "Zulu"},
  327. {"en", firstLang2aa.String(), "Afar"},
  328. {"en", lastLang3zza.String(), "Zaza"},
  329. {"en", firstLang3ace.String(), "Achinese"},
  330. {"en", firstTagAr001.String(), "Modern Standard Arabic"},
  331. {"en", lastTagZhHant.String(), "Traditional Chinese"},
  332. {"en", "aaa", "|Unknown language (aaa)"},
  333. {"en", "zzj", "|Unknown language (zzj)"},
  334. // If full tag doesn't match, try without script or region.
  335. {"en", "aa-Hans", "Afar (Simplified Han)"},
  336. {"en", "af-Arab", "Afrikaans (Arabic)"},
  337. {"en", "zu-Cyrl", "Zulu (Cyrillic)"},
  338. {"en", "aa-GB", "Afar (United Kingdom)"},
  339. {"en", "af-NA", "Afrikaans (Namibia)"},
  340. {"en", "zu-BR", "Zulu (Brazil)"},
  341. // Correct inheritance and language selection.
  342. {"zh", "zh-TW", "中文 (台湾)"},
  343. {"zh", "zh-Hant-TW", "繁体中文 (台湾)"},
  344. {"zh-Hant", "zh-TW", "中文 (台灣)"},
  345. {"zh-Hant", "zh-Hant-TW", "繁體中文 (台灣)"},
  346. // Some rather arbitrary interpretations for Serbian. This is arguably
  347. // correct and consistent with the way zh-[Hant-]TW is handled. It will
  348. // also give results more in line with the expectations if users
  349. // explicitly use "sh".
  350. {"sr-Latn", "sr-ME", "srpski (Crna Gora)"},
  351. {"sr-Latn", "sr-Latn-ME", "srpskohrvatski (Crna Gora)"},
  352. // Double script and region
  353. {"nl", "en-Cyrl-BE", "Engels (Cyrillisch, België)"},
  354. }
  355. for _, tt := range tests {
  356. t.Run(tt.dict+"/"+tt.tag, func(t *testing.T) {
  357. name, fmtName := splitName(tt.name)
  358. dict := language.MustParse(tt.dict)
  359. tag := language.Raw.MustParse(tt.tag)
  360. d := Tags(dict)
  361. if n := d.Name(tag); n != name {
  362. // There are inconsistencies w.r.t. capitalization in the tests
  363. // due to CLDR's update procedure which treats modern and other
  364. // languages differently.
  365. // See https://unicode.org/cldr/trac/ticket/8051.
  366. // TODO: use language capitalization to sanitize the strings.
  367. t.Errorf("Name(%s) = %q; want %q", tag, n, name)
  368. }
  369. p := message.NewPrinter(dict)
  370. if n := p.Sprint(Tag(tag)); n != fmtName {
  371. t.Errorf("Tag(%s) = %q; want %q", tag, n, fmtName)
  372. }
  373. })
  374. }
  375. }
  376. func splitName(names string) (name, formatName string) {
  377. split := strings.Split(names, "|")
  378. name, formatName = split[0], split[0]
  379. if len(split) > 1 {
  380. formatName = split[1]
  381. }
  382. return name, formatName
  383. }
  384. func TestLanguage(t *testing.T) {
  385. tests := []struct {
  386. dict string
  387. tag string
  388. name string
  389. }{
  390. // sr is in Value.Languages(), but is not supported by agq.
  391. {"agq", "sr", "|[language: sr]"},
  392. // CLDR 30 dropped Vlaams as the word for nl-BE. It is still called
  393. // Flemish in English, though. TODO: this is probably incorrect.
  394. // West-Vlaams (vls) is not Vlaams. West-Vlaams could be considered its
  395. // own language, whereas Vlaams is generally Dutch. So expect to have
  396. // to change these tests back.
  397. {"nl", "nl", "Nederlands"},
  398. {"nl", "vls", "West-Vlaams"},
  399. {"nl", "nl-BE", "Nederlands"},
  400. {"en", "pt", "Portuguese"},
  401. {"en", "pt-PT", "European Portuguese"},
  402. {"en", "pt-BR", "Brazilian Portuguese"},
  403. {"en", "en", "English"},
  404. {"en", "en-GB", "British English"},
  405. {"en", "en-US", "American English"}, // American English in CLDR 24+
  406. {"en", lastLang2zu.String(), "Zulu"},
  407. {"en", firstLang2aa.String(), "Afar"},
  408. {"en", lastLang3zza.String(), "Zaza"},
  409. {"en", firstLang3ace.String(), "Achinese"},
  410. {"en", firstTagAr001.String(), "Modern Standard Arabic"},
  411. {"en", lastTagZhHant.String(), "Traditional Chinese"},
  412. {"en", "aaa", "|Unknown language (aaa)"},
  413. {"en", "zzj", "|Unknown language (zzj)"},
  414. // If full tag doesn't match, try without script or region.
  415. {"en", "aa-Hans", "Afar"},
  416. {"en", "af-Arab", "Afrikaans"},
  417. {"en", "zu-Cyrl", "Zulu"},
  418. {"en", "aa-GB", "Afar"},
  419. {"en", "af-NA", "Afrikaans"},
  420. {"en", "zu-BR", "Zulu"},
  421. {"agq", "zh-Hant", "|[language: zh-Hant]"},
  422. {"en", "sh", "Serbo-Croatian"},
  423. {"en", "sr-Latn", "Serbo-Croatian"},
  424. {"en", "sr", "Serbian"},
  425. {"en", "sr-ME", "Serbian"},
  426. {"en", "sr-Latn-ME", "Serbo-Croatian"}, // See comments in TestTag.
  427. }
  428. for _, tt := range tests {
  429. testtext.Run(t, tt.dict+"/"+tt.tag, func(t *testing.T) {
  430. name, fmtName := splitName(tt.name)
  431. dict := language.MustParse(tt.dict)
  432. tag := language.Raw.MustParse(tt.tag)
  433. p := message.NewPrinter(dict)
  434. d := Languages(dict)
  435. if n := d.Name(tag); n != name {
  436. t.Errorf("Name(%v) = %q; want %q", tag, n, name)
  437. }
  438. if n := p.Sprint(Language(tag)); n != fmtName {
  439. t.Errorf("Language(%v) = %q; want %q", tag, n, fmtName)
  440. }
  441. if len(tt.tag) <= 3 {
  442. base := language.MustParseBase(tt.tag)
  443. if n := d.Name(base); n != name {
  444. t.Errorf("Name(%v) = %q; want %q", base, n, name)
  445. }
  446. if n := p.Sprint(Language(base)); n != fmtName {
  447. t.Errorf("Language(%v) = %q; want %q", base, n, fmtName)
  448. }
  449. }
  450. })
  451. }
  452. }
  453. func TestScript(t *testing.T) {
  454. tests := []struct {
  455. dict string
  456. scr string
  457. name string
  458. }{
  459. {"nl", "Arab", "Arabisch"},
  460. {"en", "Arab", "Arabic"},
  461. {"en", "Zzzz", "Unknown Script"},
  462. {"zh-Hant", "Hang", "韓文字"},
  463. {"zh-Hant-HK", "Hang", "韓文字"},
  464. {"zh", "Arab", "阿拉伯文"},
  465. {"zh-Hans-HK", "Arab", "阿拉伯文"}, // same as zh
  466. {"zh-Hant", "Arab", "阿拉伯文"},
  467. {"zh-Hant-HK", "Arab", "阿拉伯文"}, // same as zh
  468. // Canonicalized form
  469. {"en", "Qaai", "Inherited"}, // deprecated script, now is Zinh
  470. {"en", "sh", "Unknown Script"}, // sh canonicalizes to sr-Latn
  471. {"en", "en", "Unknown Script"},
  472. // Don't introduce scripts with canonicalization.
  473. {"en", "sh", "Unknown Script"}, // sh canonicalizes to sr-Latn
  474. }
  475. for _, tt := range tests {
  476. t.Run(tt.dict+"/"+tt.scr, func(t *testing.T) {
  477. name, fmtName := splitName(tt.name)
  478. dict := language.MustParse(tt.dict)
  479. p := message.NewPrinter(dict)
  480. d := Scripts(dict)
  481. var tag language.Tag
  482. if unicode.IsUpper(rune(tt.scr[0])) {
  483. x := language.MustParseScript(tt.scr)
  484. if n := d.Name(x); n != name {
  485. t.Errorf("Name(%v) = %q; want %q", x, n, name)
  486. }
  487. if n := p.Sprint(Script(x)); n != fmtName {
  488. t.Errorf("Script(%v) = %q; want %q", x, n, fmtName)
  489. }
  490. tag, _ = language.Raw.Compose(x)
  491. } else {
  492. tag = language.Raw.MustParse(tt.scr)
  493. }
  494. if n := d.Name(tag); n != name {
  495. t.Errorf("Name(%v) = %q; want %q", tag, n, name)
  496. }
  497. if n := p.Sprint(Script(tag)); n != fmtName {
  498. t.Errorf("Script(%v) = %q; want %q", tag, n, fmtName)
  499. }
  500. })
  501. }
  502. }
  503. func TestRegion(t *testing.T) {
  504. tests := []struct {
  505. dict string
  506. reg string
  507. name string
  508. }{
  509. {"nl", "NL", "Nederland"},
  510. {"en", "US", "United States"},
  511. {"en", "ZZ", "Unknown Region"},
  512. {"en-GB", "NL", "Netherlands"},
  513. // Canonical equivalents
  514. {"en", "UK", "United Kingdom"},
  515. // No region
  516. {"en", "pt", "Unknown Region"},
  517. {"en", "und", "Unknown Region"},
  518. // Don't introduce regions with canonicalization.
  519. {"en", "mo", "Unknown Region"},
  520. }
  521. for _, tt := range tests {
  522. t.Run(tt.dict+"/"+tt.reg, func(t *testing.T) {
  523. dict := language.MustParse(tt.dict)
  524. p := message.NewPrinter(dict)
  525. d := Regions(dict)
  526. var tag language.Tag
  527. if unicode.IsUpper(rune(tt.reg[0])) {
  528. // Region
  529. x := language.MustParseRegion(tt.reg)
  530. if n := d.Name(x); n != tt.name {
  531. t.Errorf("Name(%v) = %q; want %q", x, n, tt.name)
  532. }
  533. if n := p.Sprint(Region(x)); n != tt.name {
  534. t.Errorf("Region(%v) = %q; want %q", x, n, tt.name)
  535. }
  536. tag, _ = language.Raw.Compose(x)
  537. } else {
  538. tag = language.Raw.MustParse(tt.reg)
  539. }
  540. if n := d.Name(tag); n != tt.name {
  541. t.Errorf("Name(%v) = %q; want %q", tag, n, tt.name)
  542. }
  543. if n := p.Sprint(Region(tag)); n != tt.name {
  544. t.Errorf("Region(%v) = %q; want %q", tag, n, tt.name)
  545. }
  546. })
  547. }
  548. }
  549. func TestSelf(t *testing.T) {
  550. tests := []struct {
  551. tag string
  552. name string
  553. }{
  554. {"nl", "Nederlands"},
  555. // CLDR 30 dropped Vlaams as the word for nl-BE. It is still called
  556. // Flemish in English, though. TODO: check if this is a CLDR bug.
  557. // {"nl-BE", "Vlaams"},
  558. {"nl-BE", "Nederlands"},
  559. {"en-GB", "British English"},
  560. {lastLang2zu.String(), "isiZulu"},
  561. {firstLang2aa.String(), ""}, // not defined
  562. {lastLang3zza.String(), ""}, // not defined
  563. {firstLang3ace.String(), ""}, // not defined
  564. {firstTagAr001.String(), "العربية الرسمية الحديثة"},
  565. {"ar", "العربية"},
  566. {lastTagZhHant.String(), "繁體中文"},
  567. {"aaa", ""},
  568. {"zzj", ""},
  569. // Drop entries that are not in the requested script, even if there is
  570. // an entry for the language.
  571. {"aa-Hans", ""},
  572. {"af-Arab", ""},
  573. {"zu-Cyrl", ""},
  574. // Append the country name in the language of the matching language.
  575. {"af-NA", "Afrikaans"},
  576. {"zh", "中文"},
  577. // zh-TW should match zh-Hant instead of zh!
  578. {"zh-TW", "繁體中文"},
  579. {"zh-Hant", "繁體中文"},
  580. {"zh-Hans", "简体中文"},
  581. {"zh-Hant-TW", "繁體中文"},
  582. {"zh-Hans-TW", "简体中文"},
  583. // Take the entry for sr which has the matching script.
  584. // TODO: Capitalization changed as of CLDR 26, but change seems
  585. // arbitrary. Revisit capitalization with revision 27. See
  586. // https://unicode.org/cldr/trac/ticket/8051.
  587. {"sr", "српски"},
  588. // TODO: sr-ME should show up as Serbian or Montenegrin, not Serbo-
  589. // Croatian. This is an artifact of the current algorithm, which is the
  590. // way it is to have the preferred behavior for other languages such as
  591. // Chinese. We can hardwire this case in the table generator or package
  592. // code, but we first check if CLDR can be updated.
  593. // {"sr-ME", "Srpski"}, // Is Srpskohrvatski
  594. {"sr-Latn-ME", "srpskohrvatski"},
  595. {"sr-Cyrl-ME", "српски"},
  596. {"sr-NL", "српски"},
  597. // NOTE: kk is defined, but in Cyrillic script. For China, Arab is the
  598. // dominant script. We do not have data for kk-Arab and we chose to not
  599. // fall back in such cases.
  600. {"kk-CN", ""},
  601. }
  602. for i, tt := range tests {
  603. d := Self
  604. if n := d.Name(language.Raw.MustParse(tt.tag)); n != tt.name {
  605. t.Errorf("%d:%s: was %q; want %q", i, tt.tag, n, tt.name)
  606. }
  607. }
  608. }
  609. func TestEquivalence(t *testing.T) {
  610. testCases := []struct {
  611. desc string
  612. namer Namer
  613. }{
  614. {"Self", Self},
  615. {"Tags", Tags(language.Romanian)},
  616. {"Languages", Languages(language.Romanian)},
  617. {"Scripts", Scripts(language.Romanian)},
  618. }
  619. for _, tc := range testCases {
  620. t.Run(tc.desc, func(t *testing.T) {
  621. ro := tc.namer.Name(language.Raw.MustParse("ro-MD"))
  622. mo := tc.namer.Name(language.Raw.MustParse("mo"))
  623. if ro != mo {
  624. t.Errorf("%q != %q", ro, mo)
  625. }
  626. })
  627. }
  628. }
  629. func TestDictionaryLang(t *testing.T) {
  630. tests := []struct {
  631. d *Dictionary
  632. tag string
  633. name string
  634. }{
  635. {English, "en", "English"},
  636. {Portuguese, "af", "africâner"},
  637. {EuropeanPortuguese, "af", "africanês"},
  638. {English, "nl-BE", "Flemish"},
  639. }
  640. for i, test := range tests {
  641. tag := language.MustParse(test.tag)
  642. if got := test.d.Tags().Name(tag); got != test.name {
  643. t.Errorf("%d:%v: got %s; want %s", i, tag, got, test.name)
  644. }
  645. if base, _ := language.Compose(tag.Base()); base == tag {
  646. if got := test.d.Languages().Name(base); got != test.name {
  647. t.Errorf("%d:%v: got %s; want %s", i, tag, got, test.name)
  648. }
  649. }
  650. }
  651. }
  652. func TestDictionaryRegion(t *testing.T) {
  653. tests := []struct {
  654. d *Dictionary
  655. region string
  656. name string
  657. }{
  658. {English, "FR", "France"},
  659. {Portuguese, "009", "Oceania"},
  660. {EuropeanPortuguese, "009", "Oceânia"},
  661. }
  662. for i, test := range tests {
  663. tag := language.MustParseRegion(test.region)
  664. if got := test.d.Regions().Name(tag); got != test.name {
  665. t.Errorf("%d:%v: got %s; want %s", i, tag, got, test.name)
  666. }
  667. }
  668. }
  669. func TestDictionaryScript(t *testing.T) {
  670. tests := []struct {
  671. d *Dictionary
  672. script string
  673. name string
  674. }{
  675. {English, "Cyrl", "Cyrillic"},
  676. {EuropeanPortuguese, "Gujr", "guzerate"},
  677. }
  678. for i, test := range tests {
  679. tag := language.MustParseScript(test.script)
  680. if got := test.d.Scripts().Name(tag); got != test.name {
  681. t.Errorf("%d:%v: got %s; want %s", i, tag, got, test.name)
  682. }
  683. }
  684. }