1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
4 * COPYRIGHT:
5 * Copyright (c) 1997-2016, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 ********************************************************************/
8
9 #include <algorithm>
10 #include <functional>
11 #include <iterator>
12 #include <set>
13 #include <utility>
14
15 #include "loctest.h"
16 #include "unicode/localebuilder.h"
17 #include "unicode/localpointer.h"
18 #include "unicode/decimfmt.h"
19 #include "unicode/ucurr.h"
20 #include "unicode/smpdtfmt.h"
21 #include "unicode/strenum.h"
22 #include "unicode/dtfmtsym.h"
23 #include "unicode/brkiter.h"
24 #include "unicode/coll.h"
25 #include "unicode/ustring.h"
26 #include "unicode/std_string.h"
27 #include "charstr.h"
28 #include "cmemory.h"
29 #include "cstring.h"
30 #include <stdio.h>
31 #include <string.h>
32 #include "putilimp.h"
33 #include "hash.h"
34 #include "locmap.h"
35 #include "uparse.h"
36 #include "ulocimp.h"
37
38 static const char* const rawData[33][8] = {
39
40 // language code
41 { "en", "fr", "ca", "el", "no", "it", "xx", "zh" },
42 // script code
43 { "", "", "", "", "", "", "", "Hans" },
44 // country code
45 { "US", "FR", "ES", "GR", "NO", "", "YY", "CN" },
46 // variant code
47 { "", "", "", "", "NY", "", "", "" },
48 // full name
49 { "en_US", "fr_FR", "ca_ES", "el_GR", "no_NO_NY", "it", "xx_YY", "zh_Hans_CN" },
50 // ISO-3 language
51 { "eng", "fra", "cat", "ell", "nor", "ita", "", "zho" },
52 // ISO-3 country
53 { "USA", "FRA", "ESP", "GRC", "NOR", "", "", "CHN" },
54 // LCID
55 { "409", "40c", "403", "408", "814", "10", "0", "804" },
56
57 // display language (English)
58 { "English", "French", "Catalan", "Greek", "Norwegian", "Italian", "xx", "Chinese" },
59 // display script (English)
60 { "", "", "", "", "", "", "", "Simplified Han" },
61 // display country (English)
62 { "United States", "France", "Spain", "Greece", "Norway", "", "YY", "China" },
63 // display variant (English)
64 { "", "", "", "", "NY", "", "", ""},
65 // display name (English)
66 // Updated no_NO_NY English display name for new pattern-based algorithm
67 // (part of Euro support).
68 { "English (United States)", "French (France)", "Catalan (Spain)", "Greek (Greece)", "Norwegian (Norway, NY)", "Italian", "xx (YY)", "Chinese (Simplified, China)" },
69
70 // display language (French)
71 { "anglais", "fran\\u00E7ais", "catalan", "grec", "norv\\u00E9gien", "italien", "xx", "chinois" },
72 // display script (French)
73 { "", "", "", "", "", "", "", "sinogrammes simplifi\\u00E9s" },
74 // display country (French)
75 { "\\u00C9tats-Unis", "France", "Espagne", "Gr\\u00E8ce", "Norv\\u00E8ge", "", "YY", "Chine" },
76 // display variant (French)
77 { "", "", "", "", "NY", "", "", "" },
78 // display name (French)
79 //{ "anglais (Etats-Unis)", "francais (France)", "catalan (Espagne)", "grec (Grece)", "norvegien (Norvege,Nynorsk)", "italien", "xx (YY)" },
80 { "anglais (\\u00C9tats-Unis)", "fran\\u00E7ais (France)", "catalan (Espagne)", "grec (Gr\\u00E8ce)", "norv\\u00E9gien (Norv\\u00E8ge, NY)", "italien", "xx (YY)", "chinois (simplifi\\u00E9, Chine)" },
81
82
83 /* display language (Catalan) */
84 { "angl\\u00E8s", "franc\\u00E8s", "catal\\u00E0", "grec", "noruec", "itali\\u00E0", "", "xin\\u00E8s" },
85 /* display script (Catalan) */
86 { "", "", "", "", "", "", "", "han simplificat" },
87 /* display country (Catalan) */
88 { "Estats Units", "Fran\\u00E7a", "Espanya", "Gr\\u00E8cia", "Noruega", "", "", "Xina" },
89 /* display variant (Catalan) */
90 { "", "", "", "", "NY", "", "" },
91 /* display name (Catalan) */
92 { "angl\\u00E8s (Estats Units)", "franc\\u00E8s (Fran\\u00E7a)", "catal\\u00E0 (Espanya)", "grec (Gr\\u00E8cia)", "noruec (Noruega, NY)", "itali\\u00E0", "", "xin\\u00E8s (simplificat, Xina)" },
93
94 // display language (Greek)[actual values listed below]
95 { "\\u0391\\u03b3\\u03b3\\u03bb\\u03b9\\u03ba\\u03ac",
96 "\\u0393\\u03b1\\u03bb\\u03bb\\u03b9\\u03ba\\u03ac",
97 "\\u039a\\u03b1\\u03c4\\u03b1\\u03bb\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac",
98 "\\u0395\\u03bb\\u03bb\\u03b7\\u03bd\\u03b9\\u03ba\\u03ac",
99 "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03b9\\u03ba\\u03ac",
100 "\\u0399\\u03c4\\u03b1\\u03bb\\u03b9\\u03ba\\u03ac",
101 "",
102 "\\u039A\\u03B9\\u03BD\\u03B5\\u03B6\\u03B9\\u03BA\\u03AC"
103 },
104 // display script (Greek)
105 { "", "", "", "", "", "", "", "\\u0391\\u03c0\\u03bb\\u03bf\\u03c0\\u03bf\\u03b9\\u03b7\\u03bc\\u03ad\\u03bd\\u03bf \\u03a7\\u03b1\\u03bd" },
106 // display country (Greek)[actual values listed below]
107 { "\\u0397\\u03BD\\u03C9\\u03BC\\u03AD\\u03BD\\u03B5\\u03C2 \\u03A0\\u03BF\\u03BB\\u03B9\\u03C4\\u03B5\\u03AF\\u03B5\\u03C2",
108 "\\u0393\\u03b1\\u03bb\\u03bb\\u03af\\u03b1",
109 "\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03af\\u03b1",
110 "\\u0395\\u03bb\\u03bb\\u03ac\\u03b4\\u03b1",
111 "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03af\\u03b1",
112 "",
113 "",
114 "\\u039A\\u03AF\\u03BD\\u03B1"
115 },
116 // display variant (Greek)
117 { "", "", "", "", "NY", "", "" },
118 // display name (Greek)[actual values listed below]
119 { "\\u0391\\u03b3\\u03b3\\u03bb\\u03b9\\u03ba\\u03ac (\\u0397\\u03BD\\u03C9\\u03BC\\u03AD\\u03BD\\u03B5\\u03C2 \\u03A0\\u03BF\\u03BB\\u03B9\\u03C4\\u03B5\\u03AF\\u03B5\\u03C2)",
120 "\\u0393\\u03b1\\u03bb\\u03bb\\u03b9\\u03ba\\u03ac (\\u0393\\u03b1\\u03bb\\u03bb\\u03af\\u03b1)",
121 "\\u039a\\u03b1\\u03c4\\u03b1\\u03bb\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac (\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03af\\u03b1)",
122 "\\u0395\\u03bb\\u03bb\\u03b7\\u03bd\\u03b9\\u03ba\\u03ac (\\u0395\\u03bb\\u03bb\\u03ac\\u03b4\\u03b1)",
123 "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03b9\\u03ba\\u03ac (\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03af\\u03b1, NY)",
124 "\\u0399\\u03c4\\u03b1\\u03bb\\u03b9\\u03ba\\u03ac",
125 "",
126 "\\u039A\\u03B9\\u03BD\\u03B5\\u03B6\\u03B9\\u03BA\\u03AC (\\u0391\\u03c0\\u03bb\\u03bf\\u03c0\\u03bf\\u03b9\\u03b7\\u03bc\\u03ad\\u03bd\\u03bf, \\u039A\\u03AF\\u03BD\\u03B1)"
127 },
128
129 // display language (<root>)
130 { "English", "French", "Catalan", "Greek", "Norwegian", "Italian", "xx", "" },
131 // display script (<root>)
132 { "", "", "", "", "", "", "", ""},
133 // display country (<root>)
134 { "United States", "France", "Spain", "Greece", "Norway", "", "YY", "" },
135 // display variant (<root>)
136 { "", "", "", "", "Nynorsk", "", "", ""},
137 // display name (<root>)
138 //{ "English (United States)", "French (France)", "Catalan (Spain)", "Greek (Greece)", "Norwegian (Norway,Nynorsk)", "Italian", "xx (YY)" },
139 { "English (United States)", "French (France)", "Catalan (Spain)", "Greek (Greece)", "Norwegian (Norway,NY)", "Italian", "xx (YY)", "" }
140 };
141
142
143 /*
144 Usage:
145 test_assert( Test (should be TRUE) )
146
147 Example:
148 test_assert(i==3);
149
150 the macro is ugly but makes the tests pretty.
151 */
152
153 #define test_assert(test) UPRV_BLOCK_MACRO_BEGIN { \
154 if(!(test)) \
155 errln("FAIL: " #test " was not true. In " __FILE__ " on line %d", __LINE__ ); \
156 else \
157 logln("PASS: asserted " #test); \
158 } UPRV_BLOCK_MACRO_END
159
160 /*
161 Usage:
162 test_assert_print( Test (should be TRUE), printable )
163
164 Example:
165 test_assert(i==3, toString(i));
166
167 the macro is ugly but makes the tests pretty.
168 */
169
170 #define test_assert_print(test,print) UPRV_BLOCK_MACRO_BEGIN { \
171 if(!(test)) \
172 errln("FAIL: " #test " was not true. " + UnicodeString(print) ); \
173 else \
174 logln("PASS: asserted " #test "-> " + UnicodeString(print)); \
175 } UPRV_BLOCK_MACRO_END
176
177
178 #define test_dumpLocale(l) UPRV_BLOCK_MACRO_BEGIN { \
179 logln(#l " = " + UnicodeString(l.getName(), "")); \
180 } UPRV_BLOCK_MACRO_END
181
LocaleTest()182 LocaleTest::LocaleTest()
183 : dataTable(NULL)
184 {
185 setUpDataTable();
186 }
187
~LocaleTest()188 LocaleTest::~LocaleTest()
189 {
190 if (dataTable != 0) {
191 for (int32_t i = 0; i < 33; i++) {
192 delete []dataTable[i];
193 }
194 delete []dataTable;
195 dataTable = 0;
196 }
197 }
198
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)199 void LocaleTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
200 {
201 TESTCASE_AUTO_BEGIN;
202 TESTCASE_AUTO(TestBug11421); // Must run early in list to trigger failure.
203 TESTCASE_AUTO(TestBasicGetters);
204 TESTCASE_AUTO(TestSimpleResourceInfo);
205 TESTCASE_AUTO(TestDisplayNames);
206 TESTCASE_AUTO(TestSimpleObjectStuff);
207 TESTCASE_AUTO(TestPOSIXParsing);
208 TESTCASE_AUTO(TestGetAvailableLocales);
209 TESTCASE_AUTO(TestDataDirectory);
210 TESTCASE_AUTO(TestISO3Fallback);
211 TESTCASE_AUTO(TestGetLangsAndCountries);
212 TESTCASE_AUTO(TestSimpleDisplayNames);
213 TESTCASE_AUTO(TestUninstalledISO3Names);
214 TESTCASE_AUTO(TestAtypicalLocales);
215 #if !UCONFIG_NO_FORMATTING
216 TESTCASE_AUTO(TestThaiCurrencyFormat);
217 TESTCASE_AUTO(TestEuroSupport);
218 #endif
219 TESTCASE_AUTO(TestToString);
220 #if !UCONFIG_NO_FORMATTING
221 TESTCASE_AUTO(Test4139940);
222 TESTCASE_AUTO(Test4143951);
223 #endif
224 TESTCASE_AUTO(Test4147315);
225 TESTCASE_AUTO(Test4147317);
226 TESTCASE_AUTO(Test4147552);
227 TESTCASE_AUTO(TestVariantParsing);
228 TESTCASE_AUTO(Test20639_DeprecatesISO3Language);
229 #if !UCONFIG_NO_FORMATTING
230 TESTCASE_AUTO(Test4105828);
231 #endif
232 TESTCASE_AUTO(TestSetIsBogus);
233 TESTCASE_AUTO(TestParallelAPIValues);
234 TESTCASE_AUTO(TestAddLikelySubtags);
235 TESTCASE_AUTO(TestMinimizeSubtags);
236 TESTCASE_AUTO(TestAddLikelyAndMinimizeSubtags);
237 TESTCASE_AUTO(TestKeywordVariants);
238 TESTCASE_AUTO(TestCreateUnicodeKeywords);
239 TESTCASE_AUTO(TestKeywordVariantParsing);
240 TESTCASE_AUTO(TestCreateKeywordSet);
241 TESTCASE_AUTO(TestCreateKeywordSetEmpty);
242 TESTCASE_AUTO(TestCreateUnicodeKeywordSet);
243 TESTCASE_AUTO(TestCreateUnicodeKeywordSetEmpty);
244 TESTCASE_AUTO(TestGetKeywordValueStdString);
245 TESTCASE_AUTO(TestGetUnicodeKeywordValueStdString);
246 TESTCASE_AUTO(TestSetKeywordValue);
247 TESTCASE_AUTO(TestSetKeywordValueStringPiece);
248 TESTCASE_AUTO(TestSetUnicodeKeywordValueStringPiece);
249 TESTCASE_AUTO(TestGetBaseName);
250 #if !UCONFIG_NO_FILE_IO
251 TESTCASE_AUTO(TestGetLocale);
252 #endif
253 TESTCASE_AUTO(TestVariantWithOutCountry);
254 TESTCASE_AUTO(TestCanonicalization);
255 TESTCASE_AUTO(TestCurrencyByDate);
256 TESTCASE_AUTO(TestGetVariantWithKeywords);
257 TESTCASE_AUTO(TestIsRightToLeft);
258 TESTCASE_AUTO(TestBug13277);
259 TESTCASE_AUTO(TestBug13554);
260 TESTCASE_AUTO(TestBug20410);
261 TESTCASE_AUTO(TestBug20900);
262 TESTCASE_AUTO(TestLocaleCanonicalizationFromFile);
263 TESTCASE_AUTO(TestKnownCanonicalizedListCorrect);
264 TESTCASE_AUTO(TestConstructorAcceptsBCP47);
265 TESTCASE_AUTO(TestForLanguageTag);
266 TESTCASE_AUTO(TestToLanguageTag);
267 TESTCASE_AUTO(TestToLanguageTagOmitTrue);
268 TESTCASE_AUTO(TestMoveAssign);
269 TESTCASE_AUTO(TestMoveCtor);
270 TESTCASE_AUTO(TestBug20407iVariantPreferredValue);
271 TESTCASE_AUTO(TestBug13417VeryLongLanguageTag);
272 TESTCASE_AUTO(TestBug11053UnderlineTimeZone);
273 TESTCASE_AUTO(TestUnd);
274 TESTCASE_AUTO(TestUndScript);
275 TESTCASE_AUTO(TestUndRegion);
276 TESTCASE_AUTO(TestUndCAPI);
277 TESTCASE_AUTO(TestRangeIterator);
278 TESTCASE_AUTO(TestPointerConvertingIterator);
279 TESTCASE_AUTO(TestTagConvertingIterator);
280 TESTCASE_AUTO(TestCapturingTagConvertingIterator);
281 TESTCASE_AUTO(TestSetUnicodeKeywordValueInLongLocale);
282 TESTCASE_AUTO(TestSetUnicodeKeywordValueNullInLongLocale);
283 TESTCASE_AUTO(TestCanonicalize);
284 TESTCASE_AUTO(TestLeak21419);
285 TESTCASE_AUTO_END;
286 }
287
TestBasicGetters()288 void LocaleTest::TestBasicGetters() {
289 UnicodeString temp;
290
291 int32_t i;
292 for (i = 0; i <= MAX_LOCALES; i++) {
293 Locale testLocale("");
294 if (rawData[SCRIPT][i] && rawData[SCRIPT][i][0] != 0) {
295 testLocale = Locale(rawData[LANG][i], rawData[SCRIPT][i], rawData[CTRY][i], rawData[VAR][i]);
296 }
297 else {
298 testLocale = Locale(rawData[LANG][i], rawData[CTRY][i], rawData[VAR][i]);
299 }
300 logln("Testing " + (UnicodeString)testLocale.getName() + "...");
301
302 if ( (temp=testLocale.getLanguage()) != (dataTable[LANG][i]))
303 errln(" Language code mismatch: " + temp + " versus "
304 + dataTable[LANG][i]);
305 if ( (temp=testLocale.getScript()) != (dataTable[SCRIPT][i]))
306 errln(" Script code mismatch: " + temp + " versus "
307 + dataTable[SCRIPT][i]);
308 if ( (temp=testLocale.getCountry()) != (dataTable[CTRY][i]))
309 errln(" Country code mismatch: " + temp + " versus "
310 + dataTable[CTRY][i]);
311 if ( (temp=testLocale.getVariant()) != (dataTable[VAR][i]))
312 errln(" Variant code mismatch: " + temp + " versus "
313 + dataTable[VAR][i]);
314 if ( (temp=testLocale.getName()) != (dataTable[NAME][i]))
315 errln(" Locale name mismatch: " + temp + " versus "
316 + dataTable[NAME][i]);
317 }
318
319 logln("Same thing without variant codes...");
320 for (i = 0; i <= MAX_LOCALES; i++) {
321 Locale testLocale("");
322 if (rawData[SCRIPT][i] && rawData[SCRIPT][i][0] != 0) {
323 testLocale = Locale(rawData[LANG][i], rawData[SCRIPT][i], rawData[CTRY][i]);
324 }
325 else {
326 testLocale = Locale(rawData[LANG][i], rawData[CTRY][i]);
327 }
328 logln("Testing " + (temp=testLocale.getName()) + "...");
329
330 if ( (temp=testLocale.getLanguage()) != (dataTable[LANG][i]))
331 errln("Language code mismatch: " + temp + " versus "
332 + dataTable[LANG][i]);
333 if ( (temp=testLocale.getScript()) != (dataTable[SCRIPT][i]))
334 errln("Script code mismatch: " + temp + " versus "
335 + dataTable[SCRIPT][i]);
336 if ( (temp=testLocale.getCountry()) != (dataTable[CTRY][i]))
337 errln("Country code mismatch: " + temp + " versus "
338 + dataTable[CTRY][i]);
339 if (testLocale.getVariant()[0] != 0)
340 errln("Variant code mismatch: something versus \"\"");
341 }
342
343 logln("Testing long language names and getters");
344 Locale test8 = Locale::createFromName("x-klingon-latn-zx.utf32be@special");
345
346 temp = test8.getLanguage();
347 if (temp != UnicodeString("x-klingon") )
348 errln("Language code mismatch: " + temp + " versus \"x-klingon\"");
349
350 temp = test8.getScript();
351 if (temp != UnicodeString("Latn") )
352 errln("Script code mismatch: " + temp + " versus \"Latn\"");
353
354 temp = test8.getCountry();
355 if (temp != UnicodeString("ZX") )
356 errln("Country code mismatch: " + temp + " versus \"ZX\"");
357
358 temp = test8.getVariant();
359 //if (temp != UnicodeString("SPECIAL") )
360 // errln("Variant code mismatch: " + temp + " versus \"SPECIAL\"");
361 // As of 3.0, the "@special" will *not* be parsed by uloc_getName()
362 if (temp != UnicodeString("") )
363 errln("Variant code mismatch: " + temp + " versus \"\"");
364
365 if (Locale::getDefault() != Locale::createFromName(NULL))
366 errln("Locale::getDefault() == Locale::createFromName(NULL)");
367
368 /*----------*/
369 // NOTE: There used to be a special test for locale names that had language or
370 // country codes that were longer than two letters. The new version of Locale
371 // doesn't support anything that isn't an officially recognized language or
372 // country code, so we no longer support this feature.
373
374 Locale bogusLang("THISISABOGUSLANGUAGE"); // Jitterbug 2864: language code too long
375 if(!bogusLang.isBogus()) {
376 errln("Locale(\"THISISABOGUSLANGUAGE\").isBogus()==FALSE");
377 }
378
379 bogusLang=Locale("eo");
380 if( bogusLang.isBogus() ||
381 strcmp(bogusLang.getLanguage(), "eo")!=0 ||
382 *bogusLang.getCountry()!=0 ||
383 *bogusLang.getVariant()!=0 ||
384 strcmp(bogusLang.getName(), "eo")!=0
385 ) {
386 errln("assignment to bogus Locale does not unbogus it or sets bad data");
387 }
388
389 Locale a("eo_DE@currency=DEM");
390 Locale *pb=a.clone();
391 if(pb==&a || *pb!=a) {
392 errln("Locale.clone() failed");
393 }
394 delete pb;
395 }
396
TestParallelAPIValues()397 void LocaleTest::TestParallelAPIValues() {
398 logln("Test synchronization between C and C++ API");
399 if (strcmp(Locale::getChinese().getName(), ULOC_CHINESE) != 0) {
400 errln("Differences for ULOC_CHINESE Locale");
401 }
402 if (strcmp(Locale::getEnglish().getName(), ULOC_ENGLISH) != 0) {
403 errln("Differences for ULOC_ENGLISH Locale");
404 }
405 if (strcmp(Locale::getFrench().getName(), ULOC_FRENCH) != 0) {
406 errln("Differences for ULOC_FRENCH Locale");
407 }
408 if (strcmp(Locale::getGerman().getName(), ULOC_GERMAN) != 0) {
409 errln("Differences for ULOC_GERMAN Locale");
410 }
411 if (strcmp(Locale::getItalian().getName(), ULOC_ITALIAN) != 0) {
412 errln("Differences for ULOC_ITALIAN Locale");
413 }
414 if (strcmp(Locale::getJapanese().getName(), ULOC_JAPANESE) != 0) {
415 errln("Differences for ULOC_JAPANESE Locale");
416 }
417 if (strcmp(Locale::getKorean().getName(), ULOC_KOREAN) != 0) {
418 errln("Differences for ULOC_KOREAN Locale");
419 }
420 if (strcmp(Locale::getSimplifiedChinese().getName(), ULOC_SIMPLIFIED_CHINESE) != 0) {
421 errln("Differences for ULOC_SIMPLIFIED_CHINESE Locale");
422 }
423 if (strcmp(Locale::getTraditionalChinese().getName(), ULOC_TRADITIONAL_CHINESE) != 0) {
424 errln("Differences for ULOC_TRADITIONAL_CHINESE Locale");
425 }
426
427
428 if (strcmp(Locale::getCanada().getName(), ULOC_CANADA) != 0) {
429 errln("Differences for ULOC_CANADA Locale");
430 }
431 if (strcmp(Locale::getCanadaFrench().getName(), ULOC_CANADA_FRENCH) != 0) {
432 errln("Differences for ULOC_CANADA_FRENCH Locale");
433 }
434 if (strcmp(Locale::getChina().getName(), ULOC_CHINA) != 0) {
435 errln("Differences for ULOC_CHINA Locale");
436 }
437 if (strcmp(Locale::getPRC().getName(), ULOC_PRC) != 0) {
438 errln("Differences for ULOC_PRC Locale");
439 }
440 if (strcmp(Locale::getFrance().getName(), ULOC_FRANCE) != 0) {
441 errln("Differences for ULOC_FRANCE Locale");
442 }
443 if (strcmp(Locale::getGermany().getName(), ULOC_GERMANY) != 0) {
444 errln("Differences for ULOC_GERMANY Locale");
445 }
446 if (strcmp(Locale::getItaly().getName(), ULOC_ITALY) != 0) {
447 errln("Differences for ULOC_ITALY Locale");
448 }
449 if (strcmp(Locale::getJapan().getName(), ULOC_JAPAN) != 0) {
450 errln("Differences for ULOC_JAPAN Locale");
451 }
452 if (strcmp(Locale::getKorea().getName(), ULOC_KOREA) != 0) {
453 errln("Differences for ULOC_KOREA Locale");
454 }
455 if (strcmp(Locale::getTaiwan().getName(), ULOC_TAIWAN) != 0) {
456 errln("Differences for ULOC_TAIWAN Locale");
457 }
458 if (strcmp(Locale::getUK().getName(), ULOC_UK) != 0) {
459 errln("Differences for ULOC_UK Locale");
460 }
461 if (strcmp(Locale::getUS().getName(), ULOC_US) != 0) {
462 errln("Differences for ULOC_US Locale");
463 }
464 }
465
466
TestSimpleResourceInfo()467 void LocaleTest::TestSimpleResourceInfo() {
468 UnicodeString temp;
469 char temp2[20];
470 UErrorCode err = U_ZERO_ERROR;
471 int32_t i = 0;
472
473 for (i = 0; i <= MAX_LOCALES; i++) {
474 Locale testLocale(rawData[LANG][i], rawData[CTRY][i], rawData[VAR][i]);
475 logln("Testing " + (temp=testLocale.getName()) + "...");
476
477 if ( (temp=testLocale.getISO3Language()) != (dataTable[LANG3][i]))
478 errln(" ISO-3 language code mismatch: " + temp
479 + " versus " + dataTable[LANG3][i]);
480 if ( (temp=testLocale.getISO3Country()) != (dataTable[CTRY3][i]))
481 errln(" ISO-3 country code mismatch: " + temp
482 + " versus " + dataTable[CTRY3][i]);
483
484 sprintf(temp2, "%x", (int)testLocale.getLCID());
485 if (UnicodeString(temp2) != dataTable[LCID][i])
486 errln((UnicodeString)" LCID mismatch: " + temp2 + " versus "
487 + dataTable[LCID][i]);
488
489 if(U_FAILURE(err))
490 {
491 errln((UnicodeString)"Some error on number " + i + u_errorName(err));
492 }
493 err = U_ZERO_ERROR;
494 }
495
496 Locale locale("en");
497 if(strcmp(locale.getName(), "en") != 0||
498 strcmp(locale.getLanguage(), "en") != 0) {
499 errln("construction of Locale(en) failed\n");
500 }
501 /*-----*/
502
503 }
504
505 /*
506 * Jitterbug 2439 -- markus 20030425
507 *
508 * The lookup of display names must not fall back through the default
509 * locale because that yields useless results.
510 */
511 void
TestDisplayNames()512 LocaleTest::TestDisplayNames()
513 {
514 Locale english("en", "US");
515 Locale french("fr", "FR");
516 Locale croatian("ca", "ES");
517 Locale greek("el", "GR");
518
519 logln(" In locale = en_US...");
520 doTestDisplayNames(english, DLANG_EN);
521 logln(" In locale = fr_FR...");
522 doTestDisplayNames(french, DLANG_FR);
523 logln(" In locale = ca_ES...");
524 doTestDisplayNames(croatian, DLANG_CA);
525 logln(" In locale = el_GR...");
526 doTestDisplayNames(greek, DLANG_EL);
527
528 UnicodeString s;
529 UErrorCode status = U_ZERO_ERROR;
530
531 #if !UCONFIG_NO_FORMATTING
532 DecimalFormatSymbols symb(status);
533 /* Check to see if ICU supports this locale */
534 if (symb.getLocale(ULOC_VALID_LOCALE, status) != Locale("root")) {
535 /* test that the default locale has a display name for its own language */
536 /* Currently, there is no language information in the "tl" data file so this test will fail if default locale is "tl" */
537 if (uprv_strcmp(Locale().getLanguage(), "tl") != 0) {
538 Locale().getDisplayLanguage(Locale(), s);
539 if(s.length()<=3 && s.charAt(0)<=0x7f) {
540 /* check <=3 to reject getting the language code as a display name */
541 dataerrln("unable to get a display string for the language of the default locale: " + s);
542 }
543
544 /*
545 * API coverage improvements: call
546 * Locale::getDisplayLanguage(UnicodeString &) and
547 * Locale::getDisplayCountry(UnicodeString &)
548 */
549 s.remove();
550 Locale().getDisplayLanguage(s);
551 if(s.length()<=3 && s.charAt(0)<=0x7f) {
552 dataerrln("unable to get a display string for the language of the default locale [2]: " + s);
553 }
554 }
555 }
556 else {
557 logln("Default locale %s is unsupported by ICU\n", Locale().getName());
558 }
559 s.remove();
560 #endif
561
562 french.getDisplayCountry(s);
563 if(s.isEmpty()) {
564 errln("unable to get any default-locale display string for the country of fr_FR\n");
565 }
566 s.remove();
567 Locale("zh", "Hant").getDisplayScript(s);
568 if(s.isEmpty()) {
569 errln("unable to get any default-locale display string for the country of zh_Hant\n");
570 }
571 }
572
TestSimpleObjectStuff()573 void LocaleTest::TestSimpleObjectStuff() {
574 Locale test1("aa", "AA");
575 Locale test2("aa", "AA");
576 Locale test3(test1);
577 Locale test4("zz", "ZZ");
578 Locale test5("aa", "AA", "");
579 Locale test6("aa", "AA", "ANTARES");
580 Locale test7("aa", "AA", "JUPITER");
581 Locale test8 = Locale::createFromName("aa-aa-jupiTER"); // was "aa-aa.utf8@jupiter" but in 3.0 getName won't normalize that
582
583 // now list them all for debugging usage.
584 test_dumpLocale(test1);
585 test_dumpLocale(test2);
586 test_dumpLocale(test3);
587 test_dumpLocale(test4);
588 test_dumpLocale(test5);
589 test_dumpLocale(test6);
590 test_dumpLocale(test7);
591 test_dumpLocale(test8);
592
593 // Make sure things compare to themselves!
594 test_assert(test1 == test1);
595 test_assert(test2 == test2);
596 test_assert(test3 == test3);
597 test_assert(test4 == test4);
598 test_assert(test5 == test5);
599 test_assert(test6 == test6);
600 test_assert(test7 == test7);
601 test_assert(test8 == test8);
602
603 // make sure things are not equal to themselves.
604 test_assert(!(test1 != test1));
605 test_assert(!(test2 != test2));
606 test_assert(!(test3 != test3));
607 test_assert(!(test4 != test4));
608 test_assert(!(test5 != test5));
609 test_assert(!(test6 != test6));
610 test_assert(!(test7 != test7));
611 test_assert(!(test8 != test8));
612
613 // make sure things that are equal to each other don't show up as unequal.
614 test_assert(!(test1 != test2));
615 test_assert(!(test2 != test1));
616 test_assert(!(test1 != test3));
617 test_assert(!(test2 != test3));
618 test_assert(test5 == test1);
619 test_assert(test6 != test2);
620 test_assert(test6 != test5);
621
622 test_assert(test6 != test7);
623
624 // test for things that shouldn't compare equal.
625 test_assert(!(test1 == test4));
626 test_assert(!(test2 == test4));
627 test_assert(!(test3 == test4));
628
629 test_assert(test7 == test8);
630
631 // test for hash codes to be the same.
632 int32_t hash1 = test1.hashCode();
633 int32_t hash2 = test2.hashCode();
634 int32_t hash3 = test3.hashCode();
635
636 test_assert(hash1 == hash2);
637 test_assert(hash1 == hash3);
638 test_assert(hash2 == hash3);
639
640 // test that the assignment operator works.
641 test4 = test1;
642 logln("test4=test1;");
643 test_dumpLocale(test4);
644 test_assert(test4 == test4);
645
646 test_assert(!(test1 != test4));
647 test_assert(!(test2 != test4));
648 test_assert(!(test3 != test4));
649 test_assert(test1 == test4);
650 test_assert(test4 == test1);
651
652 // test assignments with a variant
653 logln("test7 = test6");
654 test7 = test6;
655 test_dumpLocale(test7);
656 test_assert(test7 == test7);
657 test_assert(test7 == test6);
658 test_assert(test7 != test5);
659
660 logln("test6 = test1");
661 test6=test1;
662 test_dumpLocale(test6);
663 test_assert(test6 != test7);
664 test_assert(test6 == test1);
665 test_assert(test6 == test6);
666 }
667
668 // A class which exposes constructors that are implemented in terms of the POSIX parsing code.
669 class POSIXLocale : public Locale
670 {
671 public:
POSIXLocale(const UnicodeString & l)672 POSIXLocale(const UnicodeString& l)
673 :Locale()
674 {
675 char *ch;
676 ch = new char[l.length() + 1];
677 ch[l.extract(0, 0x7fffffff, ch, "")] = 0;
678 setFromPOSIXID(ch);
679 delete [] ch;
680 }
POSIXLocale(const char * l)681 POSIXLocale(const char *l)
682 :Locale()
683 {
684 setFromPOSIXID(l);
685 }
686 };
687
TestPOSIXParsing()688 void LocaleTest::TestPOSIXParsing()
689 {
690 POSIXLocale test1("ab_AB");
691 POSIXLocale test2(UnicodeString("ab_AB"));
692 Locale test3("ab","AB");
693
694 POSIXLocale test4("ab_AB_Antares");
695 POSIXLocale test5(UnicodeString("ab_AB_Antares"));
696 Locale test6("ab", "AB", "Antares");
697
698 test_dumpLocale(test1);
699 test_dumpLocale(test2);
700 test_dumpLocale(test3);
701 test_dumpLocale(test4);
702 test_dumpLocale(test5);
703 test_dumpLocale(test6);
704
705 test_assert(test1 == test1);
706
707 test_assert(test1 == test2);
708 test_assert(test2 == test3);
709 test_assert(test3 == test1);
710
711 test_assert(test4 == test5);
712 test_assert(test5 == test6);
713 test_assert(test6 == test4);
714
715 test_assert(test1 != test4);
716 test_assert(test5 != test3);
717 test_assert(test5 != test2);
718
719 int32_t hash1 = test1.hashCode();
720 int32_t hash2 = test2.hashCode();
721 int32_t hash3 = test3.hashCode();
722
723 test_assert(hash1 == hash2);
724 test_assert(hash2 == hash3);
725 test_assert(hash3 == hash1);
726 }
727
TestGetAvailableLocales()728 void LocaleTest::TestGetAvailableLocales()
729 {
730 int32_t locCount = 0;
731 const Locale* locList = Locale::getAvailableLocales(locCount);
732
733 if (locCount == 0)
734 dataerrln("getAvailableLocales() returned an empty list!");
735 else {
736 logln(UnicodeString("Number of locales returned = ") + locCount);
737 UnicodeString temp;
738 for(int32_t i = 0; i < locCount; ++i)
739 logln(locList[i].getName());
740 }
741 // I have no idea how to test this function...
742 }
743
744 // This test isn't applicable anymore - getISO3Language is
745 // independent of the data directory
TestDataDirectory()746 void LocaleTest::TestDataDirectory()
747 {
748 /*
749 char oldDirectory[80];
750 const char* temp;
751 UErrorCode err = U_ZERO_ERROR;
752 UnicodeString testValue;
753
754 temp = Locale::getDataDirectory();
755 strcpy(oldDirectory, temp);
756 logln(UnicodeString("oldDirectory = ") + oldDirectory);
757
758 Locale test(Locale::US);
759 test.getISO3Language(testValue);
760 logln("first fetch of language retrieved " + testValue);
761 if (testValue != "eng")
762 errln("Initial check of ISO3 language failed: expected \"eng\", got \"" + testValue + "\"");
763
764 {
765 char *path;
766 path=IntlTest::getTestDirectory();
767 Locale::setDataDirectory( path );
768 }
769
770 test.getISO3Language(testValue);
771 logln("second fetch of language retrieved " + testValue);
772 if (testValue != "xxx")
773 errln("setDataDirectory() failed: expected \"xxx\", got \"" + testValue + "\"");
774
775 Locale::setDataDirectory(oldDirectory);
776 test.getISO3Language(testValue);
777 logln("third fetch of language retrieved " + testValue);
778 if (testValue != "eng")
779 errln("get/setDataDirectory() failed: expected \"eng\", got \"" + testValue + "\"");
780 */
781 }
782
783 //===========================================================
784
doTestDisplayNames(Locale & displayLocale,int32_t compareIndex)785 void LocaleTest::doTestDisplayNames(Locale& displayLocale, int32_t compareIndex) {
786 UnicodeString temp;
787
788 for (int32_t i = 0; i <= MAX_LOCALES; i++) {
789 Locale testLocale("");
790 if (rawData[SCRIPT][i] && rawData[SCRIPT][i][0] != 0) {
791 testLocale = Locale(rawData[LANG][i], rawData[SCRIPT][i], rawData[CTRY][i], rawData[VAR][i]);
792 }
793 else {
794 testLocale = Locale(rawData[LANG][i], rawData[CTRY][i], rawData[VAR][i]);
795 }
796 logln(" Testing " + (temp=testLocale.getName()) + "...");
797
798 UnicodeString testLang;
799 UnicodeString testScript;
800 UnicodeString testCtry;
801 UnicodeString testVar;
802 UnicodeString testName;
803
804 testLocale.getDisplayLanguage(displayLocale, testLang);
805 testLocale.getDisplayScript(displayLocale, testScript);
806 testLocale.getDisplayCountry(displayLocale, testCtry);
807 testLocale.getDisplayVariant(displayLocale, testVar);
808 testLocale.getDisplayName(displayLocale, testName);
809
810 UnicodeString expectedLang;
811 UnicodeString expectedScript;
812 UnicodeString expectedCtry;
813 UnicodeString expectedVar;
814 UnicodeString expectedName;
815
816 expectedLang = dataTable[compareIndex][i];
817 if (expectedLang.length() == 0)
818 expectedLang = dataTable[DLANG_EN][i];
819
820 expectedScript = dataTable[compareIndex + 1][i];
821 if (expectedScript.length() == 0)
822 expectedScript = dataTable[DSCRIPT_EN][i];
823
824 expectedCtry = dataTable[compareIndex + 2][i];
825 if (expectedCtry.length() == 0)
826 expectedCtry = dataTable[DCTRY_EN][i];
827
828 expectedVar = dataTable[compareIndex + 3][i];
829 if (expectedVar.length() == 0)
830 expectedVar = dataTable[DVAR_EN][i];
831
832 expectedName = dataTable[compareIndex + 4][i];
833 if (expectedName.length() == 0)
834 expectedName = dataTable[DNAME_EN][i];
835
836 if (testLang != expectedLang)
837 dataerrln("Display language (" + UnicodeString(displayLocale.getName()) + ") of (" + UnicodeString(testLocale.getName()) + ") got " + testLang + " expected " + expectedLang);
838 if (testScript != expectedScript)
839 dataerrln("Display script (" + UnicodeString(displayLocale.getName()) + ") of (" + UnicodeString(testLocale.getName()) + ") got " + testScript + " expected " + expectedScript);
840 if (testCtry != expectedCtry)
841 dataerrln("Display country (" + UnicodeString(displayLocale.getName()) + ") of (" + UnicodeString(testLocale.getName()) + ") got " + testCtry + " expected " + expectedCtry);
842 if (testVar != expectedVar)
843 dataerrln("Display variant (" + UnicodeString(displayLocale.getName()) + ") of (" + UnicodeString(testLocale.getName()) + ") got " + testVar + " expected " + expectedVar);
844 if (testName != expectedName)
845 dataerrln("Display name (" + UnicodeString(displayLocale.getName()) + ") of (" + UnicodeString(testLocale.getName()) + ") got " + testName + " expected " + expectedName);
846 }
847 }
848
849 //---------------------------------------------------
850 // table of valid data
851 //---------------------------------------------------
852
853
854
setUpDataTable()855 void LocaleTest::setUpDataTable()
856 {
857 if (dataTable == 0) {
858 dataTable = new UnicodeString*[33];
859
860 for (int32_t i = 0; i < 33; i++) {
861 dataTable[i] = new UnicodeString[8];
862 for (int32_t j = 0; j < 8; j++) {
863 dataTable[i][j] = CharsToUnicodeString(rawData[i][j]);
864 }
865 }
866 }
867 }
868
869 // ====================
870
871
872 /**
873 * @bug 4011756 4011380
874 */
875 void
TestISO3Fallback()876 LocaleTest::TestISO3Fallback()
877 {
878 Locale test("xx", "YY");
879
880 const char * result;
881
882 result = test.getISO3Language();
883
884 // Conform to C API usage
885
886 if (!result || (result[0] != 0))
887 errln("getISO3Language() on xx_YY returned " + UnicodeString(result) + " instead of \"\"");
888
889 result = test.getISO3Country();
890
891 if (!result || (result[0] != 0))
892 errln("getISO3Country() on xx_YY returned " + UnicodeString(result) + " instead of \"\"");
893 }
894
895 /**
896 * @bug 4106155 4118587
897 */
898 void
TestGetLangsAndCountries()899 LocaleTest::TestGetLangsAndCountries()
900 {
901 // It didn't seem right to just do an exhaustive test of everything here, so I check
902 // for the following things:
903 // 1) Does each list have the right total number of entries?
904 // 2) Does each list contain certain language and country codes we think are important
905 // (the G7 countries, plus a couple others)?
906 // 3) Does each list have every entry formatted correctly? (i.e., two characters,
907 // all lower case for the language codes, all upper case for the country codes)
908 // 4) Is each list in sorted order?
909 int32_t testCount = 0;
910 const char * const * test = Locale::getISOLanguages();
911 const char spotCheck1[ ][4] = { "en", "es", "fr", "de", "it",
912 "ja", "ko", "zh", "th", "he",
913 "id", "iu", "ug", "yi", "za" };
914
915 int32_t i;
916
917 for(testCount = 0;test[testCount];testCount++)
918 ;
919
920 /* TODO: Change this test to be more like the cloctst version? */
921 if (testCount != 597)
922 errln("Expected getISOLanguages() to return 597 languages; it returned %d", testCount);
923 else {
924 for (i = 0; i < 15; i++) {
925 int32_t j;
926 for (j = 0; j < testCount; j++)
927 if (uprv_strcmp(test[j],spotCheck1[i])== 0)
928 break;
929 if (j == testCount || (uprv_strcmp(test[j],spotCheck1[i])!=0))
930 errln("Couldn't find " + (UnicodeString)spotCheck1[i] + " in language list.");
931 }
932 }
933 for (i = 0; i < testCount; i++) {
934 UnicodeString testee(test[i],"");
935 UnicodeString lc(test[i],"");
936 if (testee != lc.toLower())
937 errln(lc + " is not all lower case.");
938 if ( (testee.length() != 2) && (testee.length() != 3))
939 errln(testee + " is not two or three characters long.");
940 if (i > 0 && testee.compare(test[i - 1]) <= 0)
941 errln(testee + " appears in an out-of-order position in the list.");
942 }
943
944 test = Locale::getISOCountries();
945 UnicodeString spotCheck2 [] = { "US", "CA", "GB", "FR", "DE",
946 "IT", "JP", "KR", "CN", "TW",
947 "TH" };
948 int32_t spot2Len = 11;
949 for(testCount=0;test[testCount];testCount++)
950 ;
951
952 if (testCount != 249){
953 errln("Expected getISOCountries to return 249 countries; it returned %d", testCount);
954 }else {
955 for (i = 0; i < spot2Len; i++) {
956 int32_t j;
957 for (j = 0; j < testCount; j++)
958 {
959 UnicodeString testee(test[j],"");
960
961 if (testee == spotCheck2[i])
962 break;
963 }
964 UnicodeString testee(test[j],"");
965 if (j == testCount || testee != spotCheck2[i])
966 errln("Couldn't find " + spotCheck2[i] + " in country list.");
967 }
968 }
969 for (i = 0; i < testCount; i++) {
970 UnicodeString testee(test[i],"");
971 UnicodeString uc(test[i],"");
972 if (testee != uc.toUpper())
973 errln(testee + " is not all upper case.");
974 if (testee.length() != 2)
975 errln(testee + " is not two characters long.");
976 if (i > 0 && testee.compare(test[i - 1]) <= 0)
977 errln(testee + " appears in an out-of-order position in the list.");
978 }
979
980 // This getAvailableLocales and getISO3Language
981 {
982 int32_t numOfLocales;
983 Locale enLoc ("en");
984 const Locale *pLocales = Locale::getAvailableLocales(numOfLocales);
985
986 for (int i = 0; i < numOfLocales; i++) {
987 const Locale &loc(pLocales[i]);
988 UnicodeString name;
989 char szName[200];
990
991 loc.getDisplayName (enLoc, name);
992 name.extract (0, 200, szName, sizeof(szName));
993
994 if (strlen(loc.getISO3Language()) == 0) {
995 errln("getISO3Language() returned an empty string for: " + name);
996 }
997 }
998 }
999 }
1000
1001 /**
1002 * @bug 4118587
1003 */
1004 void
TestSimpleDisplayNames()1005 LocaleTest::TestSimpleDisplayNames()
1006 {
1007 // This test is different from TestDisplayNames because TestDisplayNames checks
1008 // fallback behavior, combination of language and country names to form locale
1009 // names, and other stuff like that. This test just checks specific language
1010 // and country codes to make sure we have the correct names for them.
1011 char languageCodes[] [4] = { "he", "id", "iu", "ug", "yi", "za" };
1012 UnicodeString languageNames [] = { "Hebrew", "Indonesian", "Inuktitut", "Uyghur", "Yiddish",
1013 "Zhuang" };
1014
1015 for (int32_t i = 0; i < 6; i++) {
1016 UnicodeString test;
1017 Locale l(languageCodes[i], "", "");
1018 l.getDisplayLanguage(Locale::getUS(), test);
1019 if (test != languageNames[i])
1020 dataerrln("Got wrong display name for " + UnicodeString(languageCodes[i]) + ": Expected \"" +
1021 languageNames[i] + "\", got \"" + test + "\".");
1022 }
1023 }
1024
1025 /**
1026 * @bug 4118595
1027 */
1028 void
TestUninstalledISO3Names()1029 LocaleTest::TestUninstalledISO3Names()
1030 {
1031 // This test checks to make sure getISO3Language and getISO3Country work right
1032 // even for locales that are not installed.
1033 const char iso2Languages [][4] = { "am", "ba", "fy", "mr", "rn",
1034 "ss", "tw", "zu" };
1035 const char iso3Languages [][5] = { "amh", "bak", "fry", "mar", "run",
1036 "ssw", "twi", "zul" };
1037
1038 int32_t i;
1039
1040 for (i = 0; i < 8; i++) {
1041 UErrorCode err = U_ZERO_ERROR;
1042
1043 UnicodeString test;
1044 Locale l(iso2Languages[i], "", "");
1045 test = l.getISO3Language();
1046 if((test != iso3Languages[i]) || U_FAILURE(err))
1047 errln("Got wrong ISO3 code for " + UnicodeString(iso2Languages[i]) + ": Expected \"" +
1048 iso3Languages[i] + "\", got \"" + test + "\"." + UnicodeString(u_errorName(err)));
1049 }
1050
1051 char iso2Countries [][4] = { "AF", "BW", "KZ", "MO", "MN",
1052 "SB", "TC", "ZW" };
1053 char iso3Countries [][4] = { "AFG", "BWA", "KAZ", "MAC", "MNG",
1054 "SLB", "TCA", "ZWE" };
1055
1056 for (i = 0; i < 8; i++) {
1057 UErrorCode err = U_ZERO_ERROR;
1058 Locale l("", iso2Countries[i], "");
1059 UnicodeString test(l.getISO3Country(), "");
1060 if (test != iso3Countries[i])
1061 errln("Got wrong ISO3 code for " + UnicodeString(iso2Countries[i]) + ": Expected \"" +
1062 UnicodeString(iso3Countries[i]) + "\", got \"" + test + "\"." + u_errorName(err));
1063 }
1064 }
1065
1066 /**
1067 * @bug 4092475
1068 * I could not reproduce this bug. I'm pretty convinced it was fixed with the
1069 * big locale-data reorg of 10/28/97. The lookup logic for language and country
1070 * display names was also changed at that time in that check-in. --rtg 3/20/98
1071 */
1072 void
TestAtypicalLocales()1073 LocaleTest::TestAtypicalLocales()
1074 {
1075 Locale localesToTest [] = { Locale("de", "CA"),
1076 Locale("ja", "ZA"),
1077 Locale("ru", "MX"),
1078 Locale("en", "FR"),
1079 Locale("es", "DE"),
1080 Locale("", "HR"),
1081 Locale("", "SE"),
1082 Locale("", "DO"),
1083 Locale("", "BE") };
1084
1085 UnicodeString englishDisplayNames [] = { "German (Canada)",
1086 "Japanese (South Africa)",
1087 "Russian (Mexico)",
1088 "English (France)",
1089 "Spanish (Germany)",
1090 "Unknown language (Croatia)",
1091 "Unknown language (Sweden)",
1092 "Unknown language (Dominican Republic)",
1093 "Unknown language (Belgium)" };
1094 UnicodeString frenchDisplayNames []= { "allemand (Canada)",
1095 "japonais (Afrique du Sud)",
1096 "russe (Mexique)",
1097 "anglais (France)",
1098 "espagnol (Allemagne)",
1099 u"langue indéterminée (Croatie)",
1100 u"langue indéterminée (Suède)",
1101 u"langue indéterminée (République dominicaine)",
1102 u"langue indéterminée (Belgique)" };
1103 UnicodeString spanishDisplayNames [] = {
1104 u"alemán (Canadá)",
1105 u"japonés (Sudáfrica)",
1106 u"ruso (México)",
1107 u"inglés (Francia)",
1108 u"español (Alemania)",
1109 "lengua desconocida (Croacia)",
1110 "lengua desconocida (Suecia)",
1111 u"lengua desconocida (República Dominicana)",
1112 u"lengua desconocida (Bélgica)" };
1113 // De-Anglicizing root required the change from
1114 // English display names to ISO Codes - ram 2003/09/26
1115 UnicodeString invDisplayNames [] = { "German (Canada)",
1116 "Japanese (South Africa)",
1117 "Russian (Mexico)",
1118 "English (France)",
1119 "Spanish (Germany)",
1120 "Unknown language (Croatia)",
1121 "Unknown language (Sweden)",
1122 "Unknown language (Dominican Republic)",
1123 "Unknown language (Belgium)" };
1124
1125 int32_t i;
1126 UErrorCode status = U_ZERO_ERROR;
1127 Locale saveLocale;
1128 Locale::setDefault(Locale::getUS(), status);
1129 for (i = 0; i < 9; ++i) {
1130 UnicodeString name;
1131 localesToTest[i].getDisplayName(Locale::getUS(), name);
1132 logln(name);
1133 if (name != englishDisplayNames[i])
1134 {
1135 dataerrln("Lookup in English failed: expected \"" + englishDisplayNames[i]
1136 + "\", got \"" + name + "\"");
1137 logln("Locale name was-> " + (name=localesToTest[i].getName()));
1138 }
1139 }
1140
1141 for (i = 0; i < 9; i++) {
1142 UnicodeString name;
1143 localesToTest[i].getDisplayName(Locale("es", "ES"), name);
1144 logln(name);
1145 if (name != spanishDisplayNames[i])
1146 dataerrln("Lookup in Spanish failed: expected \"" + spanishDisplayNames[i]
1147 + "\", got \"" + name + "\"");
1148 }
1149
1150 for (i = 0; i < 9; i++) {
1151 UnicodeString name;
1152 localesToTest[i].getDisplayName(Locale::getFrance(), name);
1153 logln(name);
1154 if (name != frenchDisplayNames[i])
1155 dataerrln("Lookup in French failed: expected \"" + frenchDisplayNames[i]
1156 + "\", got \"" + name + "\"");
1157 }
1158
1159 for (i = 0; i < 9; i++) {
1160 UnicodeString name;
1161 localesToTest[i].getDisplayName(Locale("inv", "IN"), name);
1162 logln(name + " Locale fallback to be, and data fallback to root");
1163 if (name != invDisplayNames[i])
1164 dataerrln("Lookup in INV failed: expected \"" + prettify(invDisplayNames[i])
1165 + "\", got \"" + prettify(name) + "\"");
1166 localesToTest[i].getDisplayName(Locale("inv", "BD"), name);
1167 logln(name + " Data fallback to root");
1168 if (name != invDisplayNames[i])
1169 dataerrln("Lookup in INV failed: expected \"" + prettify(invDisplayNames[i])
1170 + "\", got \"" + prettify(name )+ "\"");
1171 }
1172 Locale::setDefault(saveLocale, status);
1173 }
1174
1175 #if !UCONFIG_NO_FORMATTING
1176
1177 /**
1178 * @bug 4135752
1179 * This would be better tested by the LocaleDataTest. Will move it when I
1180 * get the LocaleDataTest working again.
1181 */
1182 void
TestThaiCurrencyFormat()1183 LocaleTest::TestThaiCurrencyFormat()
1184 {
1185 UErrorCode status = U_ZERO_ERROR;
1186 DecimalFormat *thaiCurrency = (DecimalFormat*)NumberFormat::createCurrencyInstance(
1187 Locale("th", "TH"), status);
1188 UnicodeString posPrefix(u"\u0E3F");
1189 UnicodeString temp;
1190
1191 if(U_FAILURE(status) || !thaiCurrency)
1192 {
1193 dataerrln("Couldn't get th_TH currency -> " + UnicodeString(u_errorName(status)));
1194 return;
1195 }
1196 if (thaiCurrency->getPositivePrefix(temp) != posPrefix)
1197 errln("Thai currency prefix wrong: expected Baht sign, got \"" +
1198 thaiCurrency->getPositivePrefix(temp) + "\"");
1199 if (thaiCurrency->getPositiveSuffix(temp) != "")
1200 errln("Thai currency suffix wrong: expected \"\", got \"" +
1201 thaiCurrency->getPositiveSuffix(temp) + "\"");
1202
1203 delete thaiCurrency;
1204 }
1205
1206 /**
1207 * @bug 4122371
1208 * Confirm that Euro support works. This test is pretty rudimentary; all it does
1209 * is check that any locales with the EURO variant format a number using the
1210 * Euro currency symbol.
1211 *
1212 * ASSUME: All locales encode the Euro character "\u20AC".
1213 * If this is changed to use the single-character Euro symbol, this
1214 * test must be updated.
1215 *
1216 */
1217 void
TestEuroSupport()1218 LocaleTest::TestEuroSupport()
1219 {
1220 UChar euro = 0x20ac;
1221 const UnicodeString EURO_CURRENCY(&euro, 1, 1); // Look for this UnicodeString in formatted Euro currency
1222 const char* localeArr[] = {
1223 "ca_ES",
1224 "de_AT",
1225 "de_DE",
1226 "de_LU",
1227 "el_GR",
1228 "en_BE",
1229 "en_IE",
1230 "en_GB@currency=EUR",
1231 "en_US@currency=EUR",
1232 "es_ES",
1233 "eu_ES",
1234 "fi_FI",
1235 "fr_BE",
1236 "fr_FR",
1237 "fr_LU",
1238 "ga_IE",
1239 "gl_ES",
1240 "it_IT",
1241 "nl_BE",
1242 "nl_NL",
1243 "pt_PT",
1244 NULL
1245 };
1246 const char** locales = localeArr;
1247
1248 UErrorCode status = U_ZERO_ERROR;
1249
1250 UnicodeString temp;
1251
1252 for (;*locales!=NULL;locales++) {
1253 Locale loc (*locales);
1254 UnicodeString temp;
1255 NumberFormat *nf = NumberFormat::createCurrencyInstance(loc, status);
1256 UnicodeString pos;
1257
1258 if (U_FAILURE(status)) {
1259 dataerrln("Error calling NumberFormat::createCurrencyInstance(%s)", *locales);
1260 continue;
1261 }
1262
1263 nf->format(271828.182845, pos);
1264 UnicodeString neg;
1265 nf->format(-271828.182845, neg);
1266 if (pos.indexOf(EURO_CURRENCY) >= 0 &&
1267 neg.indexOf(EURO_CURRENCY) >= 0) {
1268 logln("Ok: " + (temp=loc.getName()) +
1269 ": " + pos + " / " + neg);
1270 }
1271 else {
1272 errln("Fail: " + (temp=loc.getName()) +
1273 " formats without " + EURO_CURRENCY +
1274 ": " + pos + " / " + neg +
1275 "\n*** THIS FAILURE MAY ONLY MEAN THAT LOCALE DATA HAS CHANGED ***");
1276 }
1277
1278 delete nf;
1279 }
1280
1281 UnicodeString dollarStr("USD", ""), euroStr("EUR", ""), genericStr((UChar)0x00a4), resultStr;
1282 UChar tmp[4];
1283 status = U_ZERO_ERROR;
1284
1285 ucurr_forLocale("en_US", tmp, 4, &status);
1286 resultStr.setTo(tmp);
1287 if (dollarStr != resultStr) {
1288 errcheckln(status, "Fail: en_US didn't return USD - %s", u_errorName(status));
1289 }
1290 ucurr_forLocale("en_US@currency=EUR", tmp, 4, &status);
1291 resultStr.setTo(tmp);
1292 if (euroStr != resultStr) {
1293 errcheckln(status, "Fail: en_US@currency=EUR didn't return EUR - %s", u_errorName(status));
1294 }
1295 ucurr_forLocale("en_GB@currency=EUR", tmp, 4, &status);
1296 resultStr.setTo(tmp);
1297 if (euroStr != resultStr) {
1298 errcheckln(status, "Fail: en_GB@currency=EUR didn't return EUR - %s", u_errorName(status));
1299 }
1300 ucurr_forLocale("en_US_Q", tmp, 4, &status);
1301 resultStr.setTo(tmp);
1302 if (dollarStr != resultStr) {
1303 errcheckln(status, "Fail: en_US_Q didn't fallback to en_US - %s", u_errorName(status));
1304 }
1305 int32_t invalidLen = ucurr_forLocale("en_QQ", tmp, 4, &status);
1306 if (invalidLen || U_SUCCESS(status)) {
1307 errln("Fail: en_QQ didn't return NULL");
1308 }
1309
1310 // The currency keyword value is as long as the destination buffer.
1311 // It should detect the overflow internally, and default to the locale's currency.
1312 tmp[0] = u'¤';
1313 status = U_ZERO_ERROR;
1314 int32_t length = ucurr_forLocale("en_US@currency=euro", tmp, 4, &status);
1315 if (U_FAILURE(status) || dollarStr != UnicodeString(tmp, length)) {
1316 if (U_SUCCESS(status) && tmp[0] == u'¤') {
1317 errln("Fail: ucurr_forLocale(en_US@currency=euro) succeeded without writing output");
1318 } else {
1319 errln("Fail: ucurr_forLocale(en_US@currency=euro) != USD - %s", u_errorName(status));
1320 }
1321 }
1322 }
1323
1324 #endif
1325
1326 /**
1327 * @bug 4139504
1328 * toString() doesn't work with language_VARIANT.
1329 */
1330 void
TestToString()1331 LocaleTest::TestToString() {
1332 Locale DATA [] = {
1333 Locale("xx", "", ""),
1334 Locale("", "YY", ""),
1335 Locale("", "", "ZZ"),
1336 Locale("xx", "YY", ""),
1337 Locale("xx", "", "ZZ"),
1338 Locale("", "YY", "ZZ"),
1339 Locale("xx", "YY", "ZZ"),
1340 };
1341
1342 const char DATA_S [][20] = {
1343 "xx",
1344 "_YY",
1345 "__ZZ",
1346 "xx_YY",
1347 "xx__ZZ",
1348 "_YY_ZZ",
1349 "xx_YY_ZZ",
1350 };
1351
1352 for (int32_t i=0; i < 7; ++i) {
1353 const char *name;
1354 name = DATA[i].getName();
1355
1356 if (strcmp(name, DATA_S[i]) != 0)
1357 {
1358 errln("Fail: Locale.getName(), got:" + UnicodeString(name) + ", expected: " + DATA_S[i]);
1359 }
1360 else
1361 logln("Pass: Locale.getName(), got:" + UnicodeString(name) );
1362 }
1363 }
1364
1365 #if !UCONFIG_NO_FORMATTING
1366
1367 /**
1368 * @bug 4139940
1369 * Couldn't reproduce this bug -- probably was fixed earlier.
1370 *
1371 * ORIGINAL BUG REPORT:
1372 * -- basically, hungarian for monday shouldn't have an \u00f4
1373 * (o circumflex)in it instead it should be an o with 2 inclined
1374 * (right) lines over it..
1375 *
1376 * You may wonder -- why do all this -- why not just add a line to
1377 * LocaleData? Well, I could see by inspection that the locale file had the
1378 * right character in it, so I wanted to check the rest of the pipeline -- a
1379 * very remote possibility, but I wanted to be sure. The other possibility
1380 * is that something is wrong with the font mapping subsystem, but we can't
1381 * test that here.
1382 */
1383 void
Test4139940()1384 LocaleTest::Test4139940()
1385 {
1386 Locale mylocale("hu", "", "");
1387 UDate mydate = date(98,3,13); // A Monday
1388 UErrorCode status = U_ZERO_ERROR;
1389 SimpleDateFormat df_full("EEEE", mylocale, status);
1390 if(U_FAILURE(status)){
1391 dataerrln(UnicodeString("Could not create SimpleDateFormat object for locale hu. Error: ") + UnicodeString(u_errorName(status)));
1392 return;
1393 }
1394 UnicodeString str;
1395 FieldPosition pos(FieldPosition::DONT_CARE);
1396 df_full.format(mydate, str, pos);
1397 // Make sure that o circumflex (\u00F4) is NOT there, and
1398 // o double acute (\u0151) IS.
1399 UChar ocf = 0x00f4;
1400 UChar oda = 0x0151;
1401 if (str.indexOf(oda) < 0 || str.indexOf(ocf) >= 0) {
1402 /* If the default locale is "th" this test will fail because of the buddhist calendar. */
1403 if (strcmp(Locale::getDefault().getLanguage(), "th") != 0) {
1404 errln("Fail: Monday in Hungarian is wrong - oda's index is %d and ocf's is %d",
1405 str.indexOf(oda), str.indexOf(ocf));
1406 } else {
1407 logln(UnicodeString("An error is produce in buddhist calendar."));
1408 }
1409 logln(UnicodeString("String is: ") + str );
1410 }
1411 }
1412
1413 UDate
date(int32_t y,int32_t m,int32_t d,int32_t hr,int32_t min,int32_t sec)1414 LocaleTest::date(int32_t y, int32_t m, int32_t d, int32_t hr, int32_t min, int32_t sec)
1415 {
1416 UErrorCode status = U_ZERO_ERROR;
1417 Calendar *cal = Calendar::createInstance(status);
1418 if (cal == 0)
1419 return 0.0;
1420 cal->clear();
1421 cal->set(1900 + y, m, d, hr, min, sec); // Add 1900 to follow java.util.Date protocol
1422 UDate dt = cal->getTime(status);
1423 if (U_FAILURE(status))
1424 return 0.0;
1425
1426 delete cal;
1427 return dt;
1428 }
1429
1430 /**
1431 * @bug 4143951
1432 * Russian first day of week should be Monday. Confirmed.
1433 */
1434 void
Test4143951()1435 LocaleTest::Test4143951()
1436 {
1437 UErrorCode status = U_ZERO_ERROR;
1438 Calendar *cal = Calendar::createInstance(Locale("ru", "", ""), status);
1439 if(U_SUCCESS(status)) {
1440 if (cal->getFirstDayOfWeek(status) != UCAL_MONDAY) {
1441 dataerrln("Fail: First day of week in Russia should be Monday");
1442 }
1443 }
1444 delete cal;
1445 }
1446
1447 #endif
1448
1449 /**
1450 * @bug 4147315
1451 * java.util.Locale.getISO3Country() works wrong for non ISO-3166 codes.
1452 * Should throw an exception for unknown locales
1453 */
1454 void
Test4147315()1455 LocaleTest::Test4147315()
1456 {
1457 UnicodeString temp;
1458 // Try with codes that are the wrong length but happen to match text
1459 // at a valid offset in the mapping table
1460 Locale locale("xxx", "CCC");
1461
1462 const char *result = locale.getISO3Country();
1463
1464 // Change to conform to C api usage
1465 if((result==NULL)||(result[0] != 0))
1466 errln("ERROR: getISO3Country() returns: " + UnicodeString(result,"") +
1467 " for locale '" + (temp=locale.getName()) + "' rather than exception" );
1468 }
1469
1470 /**
1471 * @bug 4147317
1472 * java.util.Locale.getISO3Language() works wrong for non ISO-3166 codes.
1473 * Should throw an exception for unknown locales
1474 */
1475 void
Test4147317()1476 LocaleTest::Test4147317()
1477 {
1478 UnicodeString temp;
1479 // Try with codes that are the wrong length but happen to match text
1480 // at a valid offset in the mapping table
1481 Locale locale("xxx", "CCC");
1482
1483 const char *result = locale.getISO3Language();
1484
1485 // Change to conform to C api usage
1486 if((result==NULL)||(result[0] != 0))
1487 errln("ERROR: getISO3Language() returns: " + UnicodeString(result,"") +
1488 " for locale '" + (temp=locale.getName()) + "' rather than exception" );
1489 }
1490
1491 /*
1492 * @bug 4147552
1493 */
1494 void
Test4147552()1495 LocaleTest::Test4147552()
1496 {
1497 Locale locales [] = { Locale("no", "NO"),
1498 Locale("no", "NO", "B"),
1499 Locale("no", "NO", "NY")
1500 };
1501
1502 UnicodeString edn("Norwegian (Norway, B)");
1503 UnicodeString englishDisplayNames [] = {
1504 "Norwegian (Norway)",
1505 edn,
1506 // "Norwegian (Norway,B)",
1507 //"Norwegian (Norway,NY)"
1508 "Norwegian (Norway, NY)"
1509 };
1510 UnicodeString ndn("norsk (Norge, B");
1511 UnicodeString norwegianDisplayNames [] = {
1512 "norsk (Norge)",
1513 "norsk (Norge, B)",
1514 //ndn,
1515 "norsk (Noreg, NY)"
1516 //"Norsk (Noreg, Nynorsk)"
1517 };
1518 UErrorCode status = U_ZERO_ERROR;
1519
1520 Locale saveLocale;
1521 Locale::setDefault(Locale::getEnglish(), status);
1522 for (int32_t i = 0; i < 3; ++i) {
1523 Locale loc = locales[i];
1524 UnicodeString temp;
1525 if (loc.getDisplayName(temp) != englishDisplayNames[i])
1526 dataerrln("English display-name mismatch: expected " +
1527 englishDisplayNames[i] + ", got " + loc.getDisplayName(temp));
1528 if (loc.getDisplayName(loc, temp) != norwegianDisplayNames[i])
1529 dataerrln("Norwegian display-name mismatch: expected " +
1530 norwegianDisplayNames[i] + ", got " +
1531 loc.getDisplayName(loc, temp));
1532 }
1533 Locale::setDefault(saveLocale, status);
1534 }
1535
1536 void
TestVariantParsing()1537 LocaleTest::TestVariantParsing()
1538 {
1539 Locale en_US_custom("en", "US", "De Anza_Cupertino_California_United States_Earth");
1540
1541 UnicodeString dispName("English (United States, DE ANZA_CUPERTINO_CALIFORNIA_UNITED STATES_EARTH)");
1542 UnicodeString dispVar("DE ANZA_CUPERTINO_CALIFORNIA_UNITED STATES_EARTH");
1543
1544 UnicodeString got;
1545
1546 en_US_custom.getDisplayVariant(Locale::getUS(), got);
1547 if(got != dispVar) {
1548 errln("FAIL: getDisplayVariant()");
1549 errln("Wanted: " + dispVar);
1550 errln("Got : " + got);
1551 }
1552
1553 en_US_custom.getDisplayName(Locale::getUS(), got);
1554 if(got != dispName) {
1555 dataerrln("FAIL: getDisplayName()");
1556 dataerrln("Wanted: " + dispName);
1557 dataerrln("Got : " + got);
1558 }
1559
1560 Locale shortVariant("fr", "FR", "foo");
1561 shortVariant.getDisplayVariant(got);
1562
1563 if(got != "FOO") {
1564 errln("FAIL: getDisplayVariant()");
1565 errln("Wanted: foo");
1566 errln("Got : " + got);
1567 }
1568
1569 Locale bogusVariant("fr", "FR", "_foo");
1570 bogusVariant.getDisplayVariant(got);
1571
1572 if(got != "FOO") {
1573 errln("FAIL: getDisplayVariant()");
1574 errln("Wanted: foo");
1575 errln("Got : " + got);
1576 }
1577
1578 Locale bogusVariant2("fr", "FR", "foo_");
1579 bogusVariant2.getDisplayVariant(got);
1580
1581 if(got != "FOO") {
1582 errln("FAIL: getDisplayVariant()");
1583 errln("Wanted: foo");
1584 errln("Got : " + got);
1585 }
1586
1587 Locale bogusVariant3("fr", "FR", "_foo_");
1588 bogusVariant3.getDisplayVariant(got);
1589
1590 if(got != "FOO") {
1591 errln("FAIL: getDisplayVariant()");
1592 errln("Wanted: foo");
1593 errln("Got : " + got);
1594 }
1595 }
1596
Test20639_DeprecatesISO3Language()1597 void LocaleTest::Test20639_DeprecatesISO3Language() {
1598 IcuTestErrorCode status(*this, "Test20639_DeprecatesISO3Language");
1599
1600 const struct TestCase {
1601 const char* localeName;
1602 const char* expectedISO3Language;
1603 } cases[] = {
1604 {"nb", "nob"},
1605 {"no", "nor"}, // why not nob?
1606 {"he", "heb"},
1607 {"iw", "heb"},
1608 {"ro", "ron"},
1609 {"mo", "mol"},
1610 };
1611 for (auto& cas : cases) {
1612 Locale loc(cas.localeName);
1613 const char* actual = loc.getISO3Language();
1614 assertEquals(cas.localeName, cas.expectedISO3Language, actual);
1615 }
1616 }
1617
1618 #if !UCONFIG_NO_FORMATTING
1619
1620 /**
1621 * @bug 4105828
1622 * Currency symbol in zh is wrong. We will test this at the NumberFormat
1623 * end to test the whole pipe.
1624 */
1625 void
Test4105828()1626 LocaleTest::Test4105828()
1627 {
1628 Locale LOC [] = { Locale::getChinese(), Locale("zh", "CN", ""),
1629 Locale("zh", "TW", ""), Locale("zh", "HK", "") };
1630 UErrorCode status = U_ZERO_ERROR;
1631 for (int32_t i = 0; i < 4; ++i) {
1632 NumberFormat *fmt = NumberFormat::createPercentInstance(LOC[i], status);
1633 if(U_FAILURE(status)) {
1634 dataerrln("Couldn't create NumberFormat - %s", u_errorName(status));
1635 return;
1636 }
1637 UnicodeString result;
1638 FieldPosition pos(FieldPosition::DONT_CARE);
1639 fmt->format((int32_t)1, result, pos);
1640 UnicodeString temp;
1641 if(result != "100%") {
1642 errln(UnicodeString("Percent for ") + LOC[i].getDisplayName(temp) + " should be 100%, got " + result);
1643 }
1644 delete fmt;
1645 }
1646 }
1647
1648 #endif
1649
1650 // Tests setBogus and isBogus APIs for Locale
1651 // Jitterbug 1735
1652 void
TestSetIsBogus()1653 LocaleTest::TestSetIsBogus() {
1654 Locale l("en_US");
1655 l.setToBogus();
1656 if(l.isBogus() != TRUE) {
1657 errln("After setting bogus, didn't return TRUE");
1658 }
1659 l = "en_US"; // This should reset bogus
1660 if(l.isBogus() != FALSE) {
1661 errln("After resetting bogus, didn't return FALSE");
1662 }
1663 }
1664
1665
1666 void
TestAddLikelySubtags()1667 LocaleTest::TestAddLikelySubtags() {
1668 IcuTestErrorCode status(*this, "TestAddLikelySubtags()");
1669
1670 static const Locale min("sv");
1671 static const Locale max("sv_Latn_SE");
1672
1673 Locale result(min);
1674 result.addLikelySubtags(status);
1675 status.errIfFailureAndReset("\"%s\"", min.getName());
1676 assertEquals("addLikelySubtags", max.getName(), result.getName());
1677 }
1678
1679
1680 void
TestMinimizeSubtags()1681 LocaleTest::TestMinimizeSubtags() {
1682 IcuTestErrorCode status(*this, "TestMinimizeSubtags()");
1683
1684 static const Locale max("zh_Hant_TW");
1685 static const Locale min("zh_TW");
1686
1687 Locale result(max);
1688 result.minimizeSubtags(status);
1689 status.errIfFailureAndReset("\"%s\"", max.getName());
1690 assertEquals("minimizeSubtags", min.getName(), result.getName());
1691 }
1692
1693
1694 void
TestAddLikelyAndMinimizeSubtags()1695 LocaleTest::TestAddLikelyAndMinimizeSubtags() {
1696 IcuTestErrorCode status(*this, "TestAddLikelyAndMinimizeSubtags()");
1697
1698 static const struct {
1699 const char* const from;
1700 const char* const add;
1701 const char* const remove;
1702 } full_data[] = {
1703 {
1704 "und_AQ",
1705 "_Latn_AQ",
1706 "_AQ"
1707 }, {
1708 "und_Zzzz_AQ",
1709 "_Latn_AQ",
1710 "_AQ"
1711 }, {
1712 "und_Latn_AQ",
1713 "_Latn_AQ",
1714 "_AQ"
1715 }, {
1716 "und_Moon_AQ",
1717 "_Moon_AQ",
1718 "_Moon_AQ"
1719 }, {
1720 "aa",
1721 "aa_Latn_ET",
1722 "aa"
1723 }, {
1724 "af",
1725 "af_Latn_ZA",
1726 "af"
1727 }, {
1728 "ak",
1729 "ak_Latn_GH",
1730 "ak"
1731 }, {
1732 "am",
1733 "am_Ethi_ET",
1734 "am"
1735 }, {
1736 "ar",
1737 "ar_Arab_EG",
1738 "ar"
1739 }, {
1740 "as",
1741 "as_Beng_IN",
1742 "as"
1743 }, {
1744 "az",
1745 "az_Latn_AZ",
1746 "az"
1747 }, {
1748 "be",
1749 "be_Cyrl_BY",
1750 "be"
1751 }, {
1752 "bg",
1753 "bg_Cyrl_BG",
1754 "bg"
1755 }, {
1756 "bn",
1757 "bn_Beng_BD",
1758 "bn"
1759 }, {
1760 "bo",
1761 "bo_Tibt_CN",
1762 "bo"
1763 }, {
1764 "bs",
1765 "bs_Latn_BA",
1766 "bs"
1767 }, {
1768 "ca",
1769 "ca_Latn_ES",
1770 "ca"
1771 }, {
1772 "ch",
1773 "ch_Latn_GU",
1774 "ch"
1775 }, {
1776 "chk",
1777 "chk_Latn_FM",
1778 "chk"
1779 }, {
1780 "cs",
1781 "cs_Latn_CZ",
1782 "cs"
1783 }, {
1784 "cy",
1785 "cy_Latn_GB",
1786 "cy"
1787 }, {
1788 "da",
1789 "da_Latn_DK",
1790 "da"
1791 }, {
1792 "de",
1793 "de_Latn_DE",
1794 "de"
1795 }, {
1796 "dv",
1797 "dv_Thaa_MV",
1798 "dv"
1799 }, {
1800 "dz",
1801 "dz_Tibt_BT",
1802 "dz"
1803 }, {
1804 "ee",
1805 "ee_Latn_GH",
1806 "ee"
1807 }, {
1808 "el",
1809 "el_Grek_GR",
1810 "el"
1811 }, {
1812 "en",
1813 "en_Latn_US",
1814 "en"
1815 }, {
1816 "es",
1817 "es_Latn_ES",
1818 "es"
1819 }, {
1820 "et",
1821 "et_Latn_EE",
1822 "et"
1823 }, {
1824 "eu",
1825 "eu_Latn_ES",
1826 "eu"
1827 }, {
1828 "fa",
1829 "fa_Arab_IR",
1830 "fa"
1831 }, {
1832 "fi",
1833 "fi_Latn_FI",
1834 "fi"
1835 }, {
1836 "fil",
1837 "fil_Latn_PH",
1838 "fil"
1839 }, {
1840 "fj",
1841 "fj_Latn_FJ",
1842 "fj"
1843 }, {
1844 "fo",
1845 "fo_Latn_FO",
1846 "fo"
1847 }, {
1848 "fr",
1849 "fr_Latn_FR",
1850 "fr"
1851 }, {
1852 "fur",
1853 "fur_Latn_IT",
1854 "fur"
1855 }, {
1856 "ga",
1857 "ga_Latn_IE",
1858 "ga"
1859 }, {
1860 "gaa",
1861 "gaa_Latn_GH",
1862 "gaa"
1863 }, {
1864 "gl",
1865 "gl_Latn_ES",
1866 "gl"
1867 }, {
1868 "gn",
1869 "gn_Latn_PY",
1870 "gn"
1871 }, {
1872 "gu",
1873 "gu_Gujr_IN",
1874 "gu"
1875 }, {
1876 "ha",
1877 "ha_Latn_NG",
1878 "ha"
1879 }, {
1880 "haw",
1881 "haw_Latn_US",
1882 "haw"
1883 }, {
1884 "he",
1885 "he_Hebr_IL",
1886 "he"
1887 }, {
1888 "hi",
1889 "hi_Deva_IN",
1890 "hi"
1891 }, {
1892 "hr",
1893 "hr_Latn_HR",
1894 "hr"
1895 }, {
1896 "ht",
1897 "ht_Latn_HT",
1898 "ht"
1899 }, {
1900 "hu",
1901 "hu_Latn_HU",
1902 "hu"
1903 }, {
1904 "hy",
1905 "hy_Armn_AM",
1906 "hy"
1907 }, {
1908 "id",
1909 "id_Latn_ID",
1910 "id"
1911 }, {
1912 "ig",
1913 "ig_Latn_NG",
1914 "ig"
1915 }, {
1916 "ii",
1917 "ii_Yiii_CN",
1918 "ii"
1919 }, {
1920 "is",
1921 "is_Latn_IS",
1922 "is"
1923 }, {
1924 "it",
1925 "it_Latn_IT",
1926 "it"
1927 }, {
1928 "ja",
1929 "ja_Jpan_JP",
1930 "ja"
1931 }, {
1932 "ka",
1933 "ka_Geor_GE",
1934 "ka"
1935 }, {
1936 "kaj",
1937 "kaj_Latn_NG",
1938 "kaj"
1939 }, {
1940 "kam",
1941 "kam_Latn_KE",
1942 "kam"
1943 }, {
1944 "kk",
1945 "kk_Cyrl_KZ",
1946 "kk"
1947 }, {
1948 "kl",
1949 "kl_Latn_GL",
1950 "kl"
1951 }, {
1952 "km",
1953 "km_Khmr_KH",
1954 "km"
1955 }, {
1956 "kn",
1957 "kn_Knda_IN",
1958 "kn"
1959 }, {
1960 "ko",
1961 "ko_Kore_KR",
1962 "ko"
1963 }, {
1964 "kok",
1965 "kok_Deva_IN",
1966 "kok"
1967 }, {
1968 "kpe",
1969 "kpe_Latn_LR",
1970 "kpe"
1971 }, {
1972 "ku",
1973 "ku_Latn_TR",
1974 "ku"
1975 }, {
1976 "ky",
1977 "ky_Cyrl_KG",
1978 "ky"
1979 }, {
1980 "la",
1981 "la_Latn_VA",
1982 "la"
1983 }, {
1984 "ln",
1985 "ln_Latn_CD",
1986 "ln"
1987 }, {
1988 "lo",
1989 "lo_Laoo_LA",
1990 "lo"
1991 }, {
1992 "lt",
1993 "lt_Latn_LT",
1994 "lt"
1995 }, {
1996 "lv",
1997 "lv_Latn_LV",
1998 "lv"
1999 }, {
2000 "mg",
2001 "mg_Latn_MG",
2002 "mg"
2003 }, {
2004 "mh",
2005 "mh_Latn_MH",
2006 "mh"
2007 }, {
2008 "mk",
2009 "mk_Cyrl_MK",
2010 "mk"
2011 }, {
2012 "ml",
2013 "ml_Mlym_IN",
2014 "ml"
2015 }, {
2016 "mn",
2017 "mn_Cyrl_MN",
2018 "mn"
2019 }, {
2020 "mr",
2021 "mr_Deva_IN",
2022 "mr"
2023 }, {
2024 "ms",
2025 "ms_Latn_MY",
2026 "ms"
2027 }, {
2028 "mt",
2029 "mt_Latn_MT",
2030 "mt"
2031 }, {
2032 "my",
2033 "my_Mymr_MM",
2034 "my"
2035 }, {
2036 "na",
2037 "na_Latn_NR",
2038 "na"
2039 }, {
2040 "ne",
2041 "ne_Deva_NP",
2042 "ne"
2043 }, {
2044 "niu",
2045 "niu_Latn_NU",
2046 "niu"
2047 }, {
2048 "nl",
2049 "nl_Latn_NL",
2050 "nl"
2051 }, {
2052 "nn",
2053 "nn_Latn_NO",
2054 "nn"
2055 }, {
2056 "nr",
2057 "nr_Latn_ZA",
2058 "nr"
2059 }, {
2060 "nso",
2061 "nso_Latn_ZA",
2062 "nso"
2063 }, {
2064 "om",
2065 "om_Latn_ET",
2066 "om"
2067 }, {
2068 "or",
2069 "or_Orya_IN",
2070 "or"
2071 }, {
2072 "pa",
2073 "pa_Guru_IN",
2074 "pa"
2075 }, {
2076 "pa_Arab",
2077 "pa_Arab_PK",
2078 "pa_PK"
2079 }, {
2080 "pa_PK",
2081 "pa_Arab_PK",
2082 "pa_PK"
2083 }, {
2084 "pap",
2085 "pap_Latn_AW",
2086 "pap"
2087 }, {
2088 "pau",
2089 "pau_Latn_PW",
2090 "pau"
2091 }, {
2092 "pl",
2093 "pl_Latn_PL",
2094 "pl"
2095 }, {
2096 "ps",
2097 "ps_Arab_AF",
2098 "ps"
2099 }, {
2100 "pt",
2101 "pt_Latn_BR",
2102 "pt"
2103 }, {
2104 "rn",
2105 "rn_Latn_BI",
2106 "rn"
2107 }, {
2108 "ro",
2109 "ro_Latn_RO",
2110 "ro"
2111 }, {
2112 "ru",
2113 "ru_Cyrl_RU",
2114 "ru"
2115 }, {
2116 "rw",
2117 "rw_Latn_RW",
2118 "rw"
2119 }, {
2120 "sa",
2121 "sa_Deva_IN",
2122 "sa"
2123 }, {
2124 "se",
2125 "se_Latn_NO",
2126 "se"
2127 }, {
2128 "sg",
2129 "sg_Latn_CF",
2130 "sg"
2131 }, {
2132 "si",
2133 "si_Sinh_LK",
2134 "si"
2135 }, {
2136 "sid",
2137 "sid_Latn_ET",
2138 "sid"
2139 }, {
2140 "sk",
2141 "sk_Latn_SK",
2142 "sk"
2143 }, {
2144 "sl",
2145 "sl_Latn_SI",
2146 "sl"
2147 }, {
2148 "sm",
2149 "sm_Latn_WS",
2150 "sm"
2151 }, {
2152 "so",
2153 "so_Latn_SO",
2154 "so"
2155 }, {
2156 "sq",
2157 "sq_Latn_AL",
2158 "sq"
2159 }, {
2160 "sr",
2161 "sr_Cyrl_RS",
2162 "sr"
2163 }, {
2164 "ss",
2165 "ss_Latn_ZA",
2166 "ss"
2167 }, {
2168 "st",
2169 "st_Latn_ZA",
2170 "st"
2171 }, {
2172 "sv",
2173 "sv_Latn_SE",
2174 "sv"
2175 }, {
2176 "sw",
2177 "sw_Latn_TZ",
2178 "sw"
2179 }, {
2180 "ta",
2181 "ta_Taml_IN",
2182 "ta"
2183 }, {
2184 "te",
2185 "te_Telu_IN",
2186 "te"
2187 }, {
2188 "tet",
2189 "tet_Latn_TL",
2190 "tet"
2191 }, {
2192 "tg",
2193 "tg_Cyrl_TJ",
2194 "tg"
2195 }, {
2196 "th",
2197 "th_Thai_TH",
2198 "th"
2199 }, {
2200 "ti",
2201 "ti_Ethi_ET",
2202 "ti"
2203 }, {
2204 "tig",
2205 "tig_Ethi_ER",
2206 "tig"
2207 }, {
2208 "tk",
2209 "tk_Latn_TM",
2210 "tk"
2211 }, {
2212 "tkl",
2213 "tkl_Latn_TK",
2214 "tkl"
2215 }, {
2216 "tn",
2217 "tn_Latn_ZA",
2218 "tn"
2219 }, {
2220 "to",
2221 "to_Latn_TO",
2222 "to"
2223 }, {
2224 "tpi",
2225 "tpi_Latn_PG",
2226 "tpi"
2227 }, {
2228 "tr",
2229 "tr_Latn_TR",
2230 "tr"
2231 }, {
2232 "ts",
2233 "ts_Latn_ZA",
2234 "ts"
2235 }, {
2236 "tt",
2237 "tt_Cyrl_RU",
2238 "tt"
2239 }, {
2240 "tvl",
2241 "tvl_Latn_TV",
2242 "tvl"
2243 }, {
2244 "ty",
2245 "ty_Latn_PF",
2246 "ty"
2247 }, {
2248 "uk",
2249 "uk_Cyrl_UA",
2250 "uk"
2251 }, {
2252 "und",
2253 "en_Latn_US",
2254 "en"
2255 }, {
2256 "und_AD",
2257 "ca_Latn_AD",
2258 "ca_AD"
2259 }, {
2260 "und_AE",
2261 "ar_Arab_AE",
2262 "ar_AE"
2263 }, {
2264 "und_AF",
2265 "fa_Arab_AF",
2266 "fa_AF"
2267 }, {
2268 "und_AL",
2269 "sq_Latn_AL",
2270 "sq"
2271 }, {
2272 "und_AM",
2273 "hy_Armn_AM",
2274 "hy"
2275 }, {
2276 "und_AO",
2277 "pt_Latn_AO",
2278 "pt_AO"
2279 }, {
2280 "und_AR",
2281 "es_Latn_AR",
2282 "es_AR"
2283 }, {
2284 "und_AS",
2285 "sm_Latn_AS",
2286 "sm_AS"
2287 }, {
2288 "und_AT",
2289 "de_Latn_AT",
2290 "de_AT"
2291 }, {
2292 "und_AW",
2293 "nl_Latn_AW",
2294 "nl_AW"
2295 }, {
2296 "und_AX",
2297 "sv_Latn_AX",
2298 "sv_AX"
2299 }, {
2300 "und_AZ",
2301 "az_Latn_AZ",
2302 "az"
2303 }, {
2304 "und_Arab",
2305 "ar_Arab_EG",
2306 "ar"
2307 }, {
2308 "und_Arab_IN",
2309 "ur_Arab_IN",
2310 "ur_IN"
2311 }, {
2312 "und_Arab_PK",
2313 "ur_Arab_PK",
2314 "ur"
2315 }, {
2316 "und_Arab_SN",
2317 "ar_Arab_SN",
2318 "ar_SN"
2319 }, {
2320 "und_Armn",
2321 "hy_Armn_AM",
2322 "hy"
2323 }, {
2324 "und_BA",
2325 "bs_Latn_BA",
2326 "bs"
2327 }, {
2328 "und_BD",
2329 "bn_Beng_BD",
2330 "bn"
2331 }, {
2332 "und_BE",
2333 "nl_Latn_BE",
2334 "nl_BE"
2335 }, {
2336 "und_BF",
2337 "fr_Latn_BF",
2338 "fr_BF"
2339 }, {
2340 "und_BG",
2341 "bg_Cyrl_BG",
2342 "bg"
2343 }, {
2344 "und_BH",
2345 "ar_Arab_BH",
2346 "ar_BH"
2347 }, {
2348 "und_BI",
2349 "rn_Latn_BI",
2350 "rn"
2351 }, {
2352 "und_BJ",
2353 "fr_Latn_BJ",
2354 "fr_BJ"
2355 }, {
2356 "und_BN",
2357 "ms_Latn_BN",
2358 "ms_BN"
2359 }, {
2360 "und_BO",
2361 "es_Latn_BO",
2362 "es_BO"
2363 }, {
2364 "und_BR",
2365 "pt_Latn_BR",
2366 "pt"
2367 }, {
2368 "und_BT",
2369 "dz_Tibt_BT",
2370 "dz"
2371 }, {
2372 "und_BY",
2373 "be_Cyrl_BY",
2374 "be"
2375 }, {
2376 "und_Beng",
2377 "bn_Beng_BD",
2378 "bn"
2379 }, {
2380 "und_Beng_IN",
2381 "bn_Beng_IN",
2382 "bn_IN"
2383 }, {
2384 "und_CD",
2385 "sw_Latn_CD",
2386 "sw_CD"
2387 }, {
2388 "und_CF",
2389 "fr_Latn_CF",
2390 "fr_CF"
2391 }, {
2392 "und_CG",
2393 "fr_Latn_CG",
2394 "fr_CG"
2395 }, {
2396 "und_CH",
2397 "de_Latn_CH",
2398 "de_CH"
2399 }, {
2400 "und_CI",
2401 "fr_Latn_CI",
2402 "fr_CI"
2403 }, {
2404 "und_CL",
2405 "es_Latn_CL",
2406 "es_CL"
2407 }, {
2408 "und_CM",
2409 "fr_Latn_CM",
2410 "fr_CM"
2411 }, {
2412 "und_CN",
2413 "zh_Hans_CN",
2414 "zh"
2415 }, {
2416 "und_CO",
2417 "es_Latn_CO",
2418 "es_CO"
2419 }, {
2420 "und_CR",
2421 "es_Latn_CR",
2422 "es_CR"
2423 }, {
2424 "und_CU",
2425 "es_Latn_CU",
2426 "es_CU"
2427 }, {
2428 "und_CV",
2429 "pt_Latn_CV",
2430 "pt_CV"
2431 }, {
2432 "und_CY",
2433 "el_Grek_CY",
2434 "el_CY"
2435 }, {
2436 "und_CZ",
2437 "cs_Latn_CZ",
2438 "cs"
2439 }, {
2440 "und_Cyrl",
2441 "ru_Cyrl_RU",
2442 "ru"
2443 }, {
2444 "und_Cyrl_KZ",
2445 "ru_Cyrl_KZ",
2446 "ru_KZ"
2447 }, {
2448 "und_DE",
2449 "de_Latn_DE",
2450 "de"
2451 }, {
2452 "und_DJ",
2453 "aa_Latn_DJ",
2454 "aa_DJ"
2455 }, {
2456 "und_DK",
2457 "da_Latn_DK",
2458 "da"
2459 }, {
2460 "und_DO",
2461 "es_Latn_DO",
2462 "es_DO"
2463 }, {
2464 "und_DZ",
2465 "ar_Arab_DZ",
2466 "ar_DZ"
2467 }, {
2468 "und_Deva",
2469 "hi_Deva_IN",
2470 "hi"
2471 }, {
2472 "und_EC",
2473 "es_Latn_EC",
2474 "es_EC"
2475 }, {
2476 "und_EE",
2477 "et_Latn_EE",
2478 "et"
2479 }, {
2480 "und_EG",
2481 "ar_Arab_EG",
2482 "ar"
2483 }, {
2484 "und_EH",
2485 "ar_Arab_EH",
2486 "ar_EH"
2487 }, {
2488 "und_ER",
2489 "ti_Ethi_ER",
2490 "ti_ER"
2491 }, {
2492 "und_ES",
2493 "es_Latn_ES",
2494 "es"
2495 }, {
2496 "und_ET",
2497 "am_Ethi_ET",
2498 "am"
2499 }, {
2500 "und_Ethi",
2501 "am_Ethi_ET",
2502 "am"
2503 }, {
2504 "und_Ethi_ER",
2505 "am_Ethi_ER",
2506 "am_ER"
2507 }, {
2508 "und_FI",
2509 "fi_Latn_FI",
2510 "fi"
2511 }, {
2512 "und_FM",
2513 "en_Latn_FM",
2514 "en_FM"
2515 }, {
2516 "und_FO",
2517 "fo_Latn_FO",
2518 "fo"
2519 }, {
2520 "und_FR",
2521 "fr_Latn_FR",
2522 "fr"
2523 }, {
2524 "und_GA",
2525 "fr_Latn_GA",
2526 "fr_GA"
2527 }, {
2528 "und_GE",
2529 "ka_Geor_GE",
2530 "ka"
2531 }, {
2532 "und_GF",
2533 "fr_Latn_GF",
2534 "fr_GF"
2535 }, {
2536 "und_GL",
2537 "kl_Latn_GL",
2538 "kl"
2539 }, {
2540 "und_GN",
2541 "fr_Latn_GN",
2542 "fr_GN"
2543 }, {
2544 "und_GP",
2545 "fr_Latn_GP",
2546 "fr_GP"
2547 }, {
2548 "und_GQ",
2549 "es_Latn_GQ",
2550 "es_GQ"
2551 }, {
2552 "und_GR",
2553 "el_Grek_GR",
2554 "el"
2555 }, {
2556 "und_GT",
2557 "es_Latn_GT",
2558 "es_GT"
2559 }, {
2560 "und_GU",
2561 "en_Latn_GU",
2562 "en_GU"
2563 }, {
2564 "und_GW",
2565 "pt_Latn_GW",
2566 "pt_GW"
2567 }, {
2568 "und_Geor",
2569 "ka_Geor_GE",
2570 "ka"
2571 }, {
2572 "und_Grek",
2573 "el_Grek_GR",
2574 "el"
2575 }, {
2576 "und_Gujr",
2577 "gu_Gujr_IN",
2578 "gu"
2579 }, {
2580 "und_Guru",
2581 "pa_Guru_IN",
2582 "pa"
2583 }, {
2584 "und_HK",
2585 "zh_Hant_HK",
2586 "zh_HK"
2587 }, {
2588 "und_HN",
2589 "es_Latn_HN",
2590 "es_HN"
2591 }, {
2592 "und_HR",
2593 "hr_Latn_HR",
2594 "hr"
2595 }, {
2596 "und_HT",
2597 "ht_Latn_HT",
2598 "ht"
2599 }, {
2600 "und_HU",
2601 "hu_Latn_HU",
2602 "hu"
2603 }, {
2604 "und_Hani",
2605 "zh_Hani_CN",
2606 "zh_Hani"
2607 }, {
2608 "und_Hans",
2609 "zh_Hans_CN",
2610 "zh"
2611 }, {
2612 "und_Hant",
2613 "zh_Hant_TW",
2614 "zh_TW"
2615 }, {
2616 "und_Hebr",
2617 "he_Hebr_IL",
2618 "he"
2619 }, {
2620 "und_ID",
2621 "id_Latn_ID",
2622 "id"
2623 }, {
2624 "und_IL",
2625 "he_Hebr_IL",
2626 "he"
2627 }, {
2628 "und_IN",
2629 "hi_Deva_IN",
2630 "hi"
2631 }, {
2632 "und_IQ",
2633 "ar_Arab_IQ",
2634 "ar_IQ"
2635 }, {
2636 "und_IR",
2637 "fa_Arab_IR",
2638 "fa"
2639 }, {
2640 "und_IS",
2641 "is_Latn_IS",
2642 "is"
2643 }, {
2644 "und_IT",
2645 "it_Latn_IT",
2646 "it"
2647 }, {
2648 "und_JO",
2649 "ar_Arab_JO",
2650 "ar_JO"
2651 }, {
2652 "und_JP",
2653 "ja_Jpan_JP",
2654 "ja"
2655 }, {
2656 "und_Jpan",
2657 "ja_Jpan_JP",
2658 "ja"
2659 }, {
2660 "und_KG",
2661 "ky_Cyrl_KG",
2662 "ky"
2663 }, {
2664 "und_KH",
2665 "km_Khmr_KH",
2666 "km"
2667 }, {
2668 "und_KM",
2669 "ar_Arab_KM",
2670 "ar_KM"
2671 }, {
2672 "und_KP",
2673 "ko_Kore_KP",
2674 "ko_KP"
2675 }, {
2676 "und_KR",
2677 "ko_Kore_KR",
2678 "ko"
2679 }, {
2680 "und_KW",
2681 "ar_Arab_KW",
2682 "ar_KW"
2683 }, {
2684 "und_KZ",
2685 "ru_Cyrl_KZ",
2686 "ru_KZ"
2687 }, {
2688 "und_Khmr",
2689 "km_Khmr_KH",
2690 "km"
2691 }, {
2692 "und_Knda",
2693 "kn_Knda_IN",
2694 "kn"
2695 }, {
2696 "und_Kore",
2697 "ko_Kore_KR",
2698 "ko"
2699 }, {
2700 "und_LA",
2701 "lo_Laoo_LA",
2702 "lo"
2703 }, {
2704 "und_LB",
2705 "ar_Arab_LB",
2706 "ar_LB"
2707 }, {
2708 "und_LI",
2709 "de_Latn_LI",
2710 "de_LI"
2711 }, {
2712 "und_LK",
2713 "si_Sinh_LK",
2714 "si"
2715 }, {
2716 "und_LS",
2717 "st_Latn_LS",
2718 "st_LS"
2719 }, {
2720 "und_LT",
2721 "lt_Latn_LT",
2722 "lt"
2723 }, {
2724 "und_LU",
2725 "fr_Latn_LU",
2726 "fr_LU"
2727 }, {
2728 "und_LV",
2729 "lv_Latn_LV",
2730 "lv"
2731 }, {
2732 "und_LY",
2733 "ar_Arab_LY",
2734 "ar_LY"
2735 }, {
2736 "und_Laoo",
2737 "lo_Laoo_LA",
2738 "lo"
2739 }, {
2740 "und_Latn_ES",
2741 "es_Latn_ES",
2742 "es"
2743 }, {
2744 "und_Latn_ET",
2745 "en_Latn_ET",
2746 "en_ET"
2747 }, {
2748 "und_Latn_GB",
2749 "en_Latn_GB",
2750 "en_GB"
2751 }, {
2752 "und_Latn_GH",
2753 "ak_Latn_GH",
2754 "ak"
2755 }, {
2756 "und_Latn_ID",
2757 "id_Latn_ID",
2758 "id"
2759 }, {
2760 "und_Latn_IT",
2761 "it_Latn_IT",
2762 "it"
2763 }, {
2764 "und_Latn_NG",
2765 "en_Latn_NG",
2766 "en_NG"
2767 }, {
2768 "und_Latn_TR",
2769 "tr_Latn_TR",
2770 "tr"
2771 }, {
2772 "und_Latn_ZA",
2773 "en_Latn_ZA",
2774 "en_ZA"
2775 }, {
2776 "und_MA",
2777 "ar_Arab_MA",
2778 "ar_MA"
2779 }, {
2780 "und_MC",
2781 "fr_Latn_MC",
2782 "fr_MC"
2783 }, {
2784 "und_MD",
2785 "ro_Latn_MD",
2786 "ro_MD"
2787 }, {
2788 "und_ME",
2789 "sr_Latn_ME",
2790 "sr_ME"
2791 }, {
2792 "und_MG",
2793 "mg_Latn_MG",
2794 "mg"
2795 }, {
2796 "und_MK",
2797 "mk_Cyrl_MK",
2798 "mk"
2799 }, {
2800 "und_ML",
2801 "bm_Latn_ML",
2802 "bm"
2803 }, {
2804 "und_MM",
2805 "my_Mymr_MM",
2806 "my"
2807 }, {
2808 "und_MN",
2809 "mn_Cyrl_MN",
2810 "mn"
2811 }, {
2812 "und_MO",
2813 "zh_Hant_MO",
2814 "zh_MO"
2815 }, {
2816 "und_MQ",
2817 "fr_Latn_MQ",
2818 "fr_MQ"
2819 }, {
2820 "und_MR",
2821 "ar_Arab_MR",
2822 "ar_MR"
2823 }, {
2824 "und_MT",
2825 "mt_Latn_MT",
2826 "mt"
2827 }, {
2828 "und_MV",
2829 "dv_Thaa_MV",
2830 "dv"
2831 }, {
2832 "und_MX",
2833 "es_Latn_MX",
2834 "es_MX"
2835 }, {
2836 "und_MY",
2837 "ms_Latn_MY",
2838 "ms"
2839 }, {
2840 "und_MZ",
2841 "pt_Latn_MZ",
2842 "pt_MZ"
2843 }, {
2844 "und_Mlym",
2845 "ml_Mlym_IN",
2846 "ml"
2847 }, {
2848 "und_Mymr",
2849 "my_Mymr_MM",
2850 "my"
2851 }, {
2852 "und_NC",
2853 "fr_Latn_NC",
2854 "fr_NC"
2855 }, {
2856 "und_NE",
2857 "ha_Latn_NE",
2858 "ha_NE"
2859 }, {
2860 "und_NG",
2861 "en_Latn_NG",
2862 "en_NG"
2863 }, {
2864 "und_NI",
2865 "es_Latn_NI",
2866 "es_NI"
2867 }, {
2868 "und_NL",
2869 "nl_Latn_NL",
2870 "nl"
2871 }, {
2872 "und_NO",
2873 "no_Latn_NO",
2874 "no"
2875 }, {
2876 "und_NP",
2877 "ne_Deva_NP",
2878 "ne"
2879 }, {
2880 "und_NR",
2881 "en_Latn_NR",
2882 "en_NR"
2883 }, {
2884 "und_OM",
2885 "ar_Arab_OM",
2886 "ar_OM"
2887 }, {
2888 "und_Orya",
2889 "or_Orya_IN",
2890 "or"
2891 }, {
2892 "und_PA",
2893 "es_Latn_PA",
2894 "es_PA"
2895 }, {
2896 "und_PE",
2897 "es_Latn_PE",
2898 "es_PE"
2899 }, {
2900 "und_PF",
2901 "fr_Latn_PF",
2902 "fr_PF"
2903 }, {
2904 "und_PG",
2905 "tpi_Latn_PG",
2906 "tpi"
2907 }, {
2908 "und_PH",
2909 "fil_Latn_PH",
2910 "fil"
2911 }, {
2912 "und_PL",
2913 "pl_Latn_PL",
2914 "pl"
2915 }, {
2916 "und_PM",
2917 "fr_Latn_PM",
2918 "fr_PM"
2919 }, {
2920 "und_PR",
2921 "es_Latn_PR",
2922 "es_PR"
2923 }, {
2924 "und_PS",
2925 "ar_Arab_PS",
2926 "ar_PS"
2927 }, {
2928 "und_PT",
2929 "pt_Latn_PT",
2930 "pt_PT"
2931 }, {
2932 "und_PW",
2933 "pau_Latn_PW",
2934 "pau"
2935 }, {
2936 "und_PY",
2937 "gn_Latn_PY",
2938 "gn"
2939 }, {
2940 "und_QA",
2941 "ar_Arab_QA",
2942 "ar_QA"
2943 }, {
2944 "und_RE",
2945 "fr_Latn_RE",
2946 "fr_RE"
2947 }, {
2948 "und_RO",
2949 "ro_Latn_RO",
2950 "ro"
2951 }, {
2952 "und_RS",
2953 "sr_Cyrl_RS",
2954 "sr"
2955 }, {
2956 "und_RU",
2957 "ru_Cyrl_RU",
2958 "ru"
2959 }, {
2960 "und_RW",
2961 "rw_Latn_RW",
2962 "rw"
2963 }, {
2964 "und_SA",
2965 "ar_Arab_SA",
2966 "ar_SA"
2967 }, {
2968 "und_SD",
2969 "ar_Arab_SD",
2970 "ar_SD"
2971 }, {
2972 "und_SE",
2973 "sv_Latn_SE",
2974 "sv"
2975 }, {
2976 "und_SG",
2977 "en_Latn_SG",
2978 "en_SG"
2979 }, {
2980 "und_SI",
2981 "sl_Latn_SI",
2982 "sl"
2983 }, {
2984 "und_SJ",
2985 "no_Latn_SJ",
2986 "no_SJ"
2987 }, {
2988 "und_SK",
2989 "sk_Latn_SK",
2990 "sk"
2991 }, {
2992 "und_SM",
2993 "it_Latn_SM",
2994 "it_SM"
2995 }, {
2996 "und_SN",
2997 "fr_Latn_SN",
2998 "fr_SN"
2999 }, {
3000 "und_SO",
3001 "so_Latn_SO",
3002 "so"
3003 }, {
3004 "und_SR",
3005 "nl_Latn_SR",
3006 "nl_SR"
3007 }, {
3008 "und_ST",
3009 "pt_Latn_ST",
3010 "pt_ST"
3011 }, {
3012 "und_SV",
3013 "es_Latn_SV",
3014 "es_SV"
3015 }, {
3016 "und_SY",
3017 "ar_Arab_SY",
3018 "ar_SY"
3019 }, {
3020 "und_Sinh",
3021 "si_Sinh_LK",
3022 "si"
3023 }, {
3024 "und_Syrc",
3025 "syr_Syrc_IQ",
3026 "syr"
3027 }, {
3028 "und_TD",
3029 "fr_Latn_TD",
3030 "fr_TD"
3031 }, {
3032 "und_TG",
3033 "fr_Latn_TG",
3034 "fr_TG"
3035 }, {
3036 "und_TH",
3037 "th_Thai_TH",
3038 "th"
3039 }, {
3040 "und_TJ",
3041 "tg_Cyrl_TJ",
3042 "tg"
3043 }, {
3044 "und_TK",
3045 "tkl_Latn_TK",
3046 "tkl"
3047 }, {
3048 "und_TL",
3049 "pt_Latn_TL",
3050 "pt_TL"
3051 }, {
3052 "und_TM",
3053 "tk_Latn_TM",
3054 "tk"
3055 }, {
3056 "und_TN",
3057 "ar_Arab_TN",
3058 "ar_TN"
3059 }, {
3060 "und_TO",
3061 "to_Latn_TO",
3062 "to"
3063 }, {
3064 "und_TR",
3065 "tr_Latn_TR",
3066 "tr"
3067 }, {
3068 "und_TV",
3069 "tvl_Latn_TV",
3070 "tvl"
3071 }, {
3072 "und_TW",
3073 "zh_Hant_TW",
3074 "zh_TW"
3075 }, {
3076 "und_Taml",
3077 "ta_Taml_IN",
3078 "ta"
3079 }, {
3080 "und_Telu",
3081 "te_Telu_IN",
3082 "te"
3083 }, {
3084 "und_Thaa",
3085 "dv_Thaa_MV",
3086 "dv"
3087 }, {
3088 "und_Thai",
3089 "th_Thai_TH",
3090 "th"
3091 }, {
3092 "und_Tibt",
3093 "bo_Tibt_CN",
3094 "bo"
3095 }, {
3096 "und_UA",
3097 "uk_Cyrl_UA",
3098 "uk"
3099 }, {
3100 "und_UY",
3101 "es_Latn_UY",
3102 "es_UY"
3103 }, {
3104 "und_UZ",
3105 "uz_Latn_UZ",
3106 "uz"
3107 }, {
3108 "und_VA",
3109 "it_Latn_VA",
3110 "it_VA"
3111 }, {
3112 "und_VE",
3113 "es_Latn_VE",
3114 "es_VE"
3115 }, {
3116 "und_VN",
3117 "vi_Latn_VN",
3118 "vi"
3119 }, {
3120 "und_VU",
3121 "bi_Latn_VU",
3122 "bi"
3123 }, {
3124 "und_WF",
3125 "fr_Latn_WF",
3126 "fr_WF"
3127 }, {
3128 "und_WS",
3129 "sm_Latn_WS",
3130 "sm"
3131 }, {
3132 "und_YE",
3133 "ar_Arab_YE",
3134 "ar_YE"
3135 }, {
3136 "und_YT",
3137 "fr_Latn_YT",
3138 "fr_YT"
3139 }, {
3140 "und_Yiii",
3141 "ii_Yiii_CN",
3142 "ii"
3143 }, {
3144 "ur",
3145 "ur_Arab_PK",
3146 "ur"
3147 }, {
3148 "uz",
3149 "uz_Latn_UZ",
3150 "uz"
3151 }, {
3152 "uz_AF",
3153 "uz_Arab_AF",
3154 "uz_AF"
3155 }, {
3156 "uz_Arab",
3157 "uz_Arab_AF",
3158 "uz_AF"
3159 }, {
3160 "ve",
3161 "ve_Latn_ZA",
3162 "ve"
3163 }, {
3164 "vi",
3165 "vi_Latn_VN",
3166 "vi"
3167 }, {
3168 "wal",
3169 "wal_Ethi_ET",
3170 "wal"
3171 }, {
3172 "wo",
3173 "wo_Latn_SN",
3174 "wo"
3175 }, {
3176 "wo_SN",
3177 "wo_Latn_SN",
3178 "wo"
3179 }, {
3180 "xh",
3181 "xh_Latn_ZA",
3182 "xh"
3183 }, {
3184 "yo",
3185 "yo_Latn_NG",
3186 "yo"
3187 }, {
3188 "zh",
3189 "zh_Hans_CN",
3190 "zh"
3191 }, {
3192 "zh_HK",
3193 "zh_Hant_HK",
3194 "zh_HK"
3195 }, {
3196 "zh_Hani",
3197 "zh_Hani_CN",
3198 "zh_Hani"
3199 }, {
3200 "zh_Hant",
3201 "zh_Hant_TW",
3202 "zh_TW"
3203 }, {
3204 "zh_MO",
3205 "zh_Hant_MO",
3206 "zh_MO"
3207 }, {
3208 "zh_TW",
3209 "zh_Hant_TW",
3210 "zh_TW"
3211 }, {
3212 "zu",
3213 "zu_Latn_ZA",
3214 "zu"
3215 }, {
3216 "und",
3217 "en_Latn_US",
3218 "en"
3219 }, {
3220 "und_ZZ",
3221 "en_Latn_US",
3222 "en"
3223 }, {
3224 "und_CN",
3225 "zh_Hans_CN",
3226 "zh"
3227 }, {
3228 "und_TW",
3229 "zh_Hant_TW",
3230 "zh_TW"
3231 }, {
3232 "und_HK",
3233 "zh_Hant_HK",
3234 "zh_HK"
3235 }, {
3236 "und_AQ",
3237 "_Latn_AQ",
3238 "_AQ"
3239 }, {
3240 "und_Zzzz",
3241 "en_Latn_US",
3242 "en"
3243 }, {
3244 "und_Zzzz_ZZ",
3245 "en_Latn_US",
3246 "en"
3247 }, {
3248 "und_Zzzz_CN",
3249 "zh_Hans_CN",
3250 "zh"
3251 }, {
3252 "und_Zzzz_TW",
3253 "zh_Hant_TW",
3254 "zh_TW"
3255 }, {
3256 "und_Zzzz_HK",
3257 "zh_Hant_HK",
3258 "zh_HK"
3259 }, {
3260 "und_Zzzz_AQ",
3261 "_Latn_AQ",
3262 "_AQ"
3263 }, {
3264 "und_Latn",
3265 "en_Latn_US",
3266 "en"
3267 }, {
3268 "und_Latn_ZZ",
3269 "en_Latn_US",
3270 "en"
3271 }, {
3272 "und_Latn_CN",
3273 "za_Latn_CN",
3274 "za"
3275 }, {
3276 "und_Latn_TW",
3277 "trv_Latn_TW",
3278 "trv"
3279 }, {
3280 "und_Latn_HK",
3281 "zh_Latn_HK",
3282 "zh_Latn_HK"
3283 }, {
3284 "und_Latn_AQ",
3285 "_Latn_AQ",
3286 "_AQ"
3287 }, {
3288 "und_Hans",
3289 "zh_Hans_CN",
3290 "zh"
3291 }, {
3292 "und_Hans_ZZ",
3293 "zh_Hans_CN",
3294 "zh"
3295 }, {
3296 "und_Hans_CN",
3297 "zh_Hans_CN",
3298 "zh"
3299 }, {
3300 "und_Hans_TW",
3301 "zh_Hans_TW",
3302 "zh_Hans_TW"
3303 }, {
3304 "und_Hans_HK",
3305 "zh_Hans_HK",
3306 "zh_Hans_HK"
3307 }, {
3308 "und_Hans_AQ",
3309 "zh_Hans_AQ",
3310 "zh_AQ"
3311 }, {
3312 "und_Hant",
3313 "zh_Hant_TW",
3314 "zh_TW"
3315 }, {
3316 "und_Hant_ZZ",
3317 "zh_Hant_TW",
3318 "zh_TW"
3319 }, {
3320 "und_Hant_CN",
3321 "zh_Hant_CN",
3322 "zh_Hant_CN"
3323 }, {
3324 "und_Hant_TW",
3325 "zh_Hant_TW",
3326 "zh_TW"
3327 }, {
3328 "und_Hant_HK",
3329 "zh_Hant_HK",
3330 "zh_HK"
3331 }, {
3332 "und_Hant_AQ",
3333 "zh_Hant_AQ",
3334 "zh_Hant_AQ"
3335 }, {
3336 "und_Moon",
3337 "en_Moon_US",
3338 "en_Moon"
3339 }, {
3340 "und_Moon_ZZ",
3341 "en_Moon_US",
3342 "en_Moon"
3343 }, {
3344 "und_Moon_CN",
3345 "zh_Moon_CN",
3346 "zh_Moon"
3347 }, {
3348 "und_Moon_TW",
3349 "zh_Moon_TW",
3350 "zh_Moon_TW"
3351 }, {
3352 "und_Moon_HK",
3353 "zh_Moon_HK",
3354 "zh_Moon_HK"
3355 }, {
3356 "und_Moon_AQ",
3357 "_Moon_AQ",
3358 "_Moon_AQ"
3359 }, {
3360 "es",
3361 "es_Latn_ES",
3362 "es"
3363 }, {
3364 "es_ZZ",
3365 "es_Latn_ES",
3366 "es"
3367 }, {
3368 "es_CN",
3369 "es_Latn_CN",
3370 "es_CN"
3371 }, {
3372 "es_TW",
3373 "es_Latn_TW",
3374 "es_TW"
3375 }, {
3376 "es_HK",
3377 "es_Latn_HK",
3378 "es_HK"
3379 }, {
3380 "es_AQ",
3381 "es_Latn_AQ",
3382 "es_AQ"
3383 }, {
3384 "es_Zzzz",
3385 "es_Latn_ES",
3386 "es"
3387 }, {
3388 "es_Zzzz_ZZ",
3389 "es_Latn_ES",
3390 "es"
3391 }, {
3392 "es_Zzzz_CN",
3393 "es_Latn_CN",
3394 "es_CN"
3395 }, {
3396 "es_Zzzz_TW",
3397 "es_Latn_TW",
3398 "es_TW"
3399 }, {
3400 "es_Zzzz_HK",
3401 "es_Latn_HK",
3402 "es_HK"
3403 }, {
3404 "es_Zzzz_AQ",
3405 "es_Latn_AQ",
3406 "es_AQ"
3407 }, {
3408 "es_Latn",
3409 "es_Latn_ES",
3410 "es"
3411 }, {
3412 "es_Latn_ZZ",
3413 "es_Latn_ES",
3414 "es"
3415 }, {
3416 "es_Latn_CN",
3417 "es_Latn_CN",
3418 "es_CN"
3419 }, {
3420 "es_Latn_TW",
3421 "es_Latn_TW",
3422 "es_TW"
3423 }, {
3424 "es_Latn_HK",
3425 "es_Latn_HK",
3426 "es_HK"
3427 }, {
3428 "es_Latn_AQ",
3429 "es_Latn_AQ",
3430 "es_AQ"
3431 }, {
3432 "es_Hans",
3433 "es_Hans_ES",
3434 "es_Hans"
3435 }, {
3436 "es_Hans_ZZ",
3437 "es_Hans_ES",
3438 "es_Hans"
3439 }, {
3440 "es_Hans_CN",
3441 "es_Hans_CN",
3442 "es_Hans_CN"
3443 }, {
3444 "es_Hans_TW",
3445 "es_Hans_TW",
3446 "es_Hans_TW"
3447 }, {
3448 "es_Hans_HK",
3449 "es_Hans_HK",
3450 "es_Hans_HK"
3451 }, {
3452 "es_Hans_AQ",
3453 "es_Hans_AQ",
3454 "es_Hans_AQ"
3455 }, {
3456 "es_Hant",
3457 "es_Hant_ES",
3458 "es_Hant"
3459 }, {
3460 "es_Hant_ZZ",
3461 "es_Hant_ES",
3462 "es_Hant"
3463 }, {
3464 "es_Hant_CN",
3465 "es_Hant_CN",
3466 "es_Hant_CN"
3467 }, {
3468 "es_Hant_TW",
3469 "es_Hant_TW",
3470 "es_Hant_TW"
3471 }, {
3472 "es_Hant_HK",
3473 "es_Hant_HK",
3474 "es_Hant_HK"
3475 }, {
3476 "es_Hant_AQ",
3477 "es_Hant_AQ",
3478 "es_Hant_AQ"
3479 }, {
3480 "es_Moon",
3481 "es_Moon_ES",
3482 "es_Moon"
3483 }, {
3484 "es_Moon_ZZ",
3485 "es_Moon_ES",
3486 "es_Moon"
3487 }, {
3488 "es_Moon_CN",
3489 "es_Moon_CN",
3490 "es_Moon_CN"
3491 }, {
3492 "es_Moon_TW",
3493 "es_Moon_TW",
3494 "es_Moon_TW"
3495 }, {
3496 "es_Moon_HK",
3497 "es_Moon_HK",
3498 "es_Moon_HK"
3499 }, {
3500 "es_Moon_AQ",
3501 "es_Moon_AQ",
3502 "es_Moon_AQ"
3503 }, {
3504 "zh",
3505 "zh_Hans_CN",
3506 "zh"
3507 }, {
3508 "zh_ZZ",
3509 "zh_Hans_CN",
3510 "zh"
3511 }, {
3512 "zh_CN",
3513 "zh_Hans_CN",
3514 "zh"
3515 }, {
3516 "zh_TW",
3517 "zh_Hant_TW",
3518 "zh_TW"
3519 }, {
3520 "zh_HK",
3521 "zh_Hant_HK",
3522 "zh_HK"
3523 }, {
3524 "zh_AQ",
3525 "zh_Hans_AQ",
3526 "zh_AQ"
3527 }, {
3528 "zh_Zzzz",
3529 "zh_Hans_CN",
3530 "zh"
3531 }, {
3532 "zh_Zzzz_ZZ",
3533 "zh_Hans_CN",
3534 "zh"
3535 }, {
3536 "zh_Zzzz_CN",
3537 "zh_Hans_CN",
3538 "zh"
3539 }, {
3540 "zh_Zzzz_TW",
3541 "zh_Hant_TW",
3542 "zh_TW"
3543 }, {
3544 "zh_Zzzz_HK",
3545 "zh_Hant_HK",
3546 "zh_HK"
3547 }, {
3548 "zh_Zzzz_AQ",
3549 "zh_Hans_AQ",
3550 "zh_AQ"
3551 }, {
3552 "zh_Latn",
3553 "zh_Latn_CN",
3554 "zh_Latn"
3555 }, {
3556 "zh_Latn_ZZ",
3557 "zh_Latn_CN",
3558 "zh_Latn"
3559 }, {
3560 "zh_Latn_CN",
3561 "zh_Latn_CN",
3562 "zh_Latn"
3563 }, {
3564 "zh_Latn_TW",
3565 "zh_Latn_TW",
3566 "zh_Latn_TW"
3567 }, {
3568 "zh_Latn_HK",
3569 "zh_Latn_HK",
3570 "zh_Latn_HK"
3571 }, {
3572 "zh_Latn_AQ",
3573 "zh_Latn_AQ",
3574 "zh_Latn_AQ"
3575 }, {
3576 "zh_Hans",
3577 "zh_Hans_CN",
3578 "zh"
3579 }, {
3580 "zh_Hans_ZZ",
3581 "zh_Hans_CN",
3582 "zh"
3583 }, {
3584 "zh_Hans_TW",
3585 "zh_Hans_TW",
3586 "zh_Hans_TW"
3587 }, {
3588 "zh_Hans_HK",
3589 "zh_Hans_HK",
3590 "zh_Hans_HK"
3591 }, {
3592 "zh_Hans_AQ",
3593 "zh_Hans_AQ",
3594 "zh_AQ"
3595 }, {
3596 "zh_Hant",
3597 "zh_Hant_TW",
3598 "zh_TW"
3599 }, {
3600 "zh_Hant_ZZ",
3601 "zh_Hant_TW",
3602 "zh_TW"
3603 }, {
3604 "zh_Hant_CN",
3605 "zh_Hant_CN",
3606 "zh_Hant_CN"
3607 }, {
3608 "zh_Hant_AQ",
3609 "zh_Hant_AQ",
3610 "zh_Hant_AQ"
3611 }, {
3612 "zh_Moon",
3613 "zh_Moon_CN",
3614 "zh_Moon"
3615 }, {
3616 "zh_Moon_ZZ",
3617 "zh_Moon_CN",
3618 "zh_Moon"
3619 }, {
3620 "zh_Moon_CN",
3621 "zh_Moon_CN",
3622 "zh_Moon"
3623 }, {
3624 "zh_Moon_TW",
3625 "zh_Moon_TW",
3626 "zh_Moon_TW"
3627 }, {
3628 "zh_Moon_HK",
3629 "zh_Moon_HK",
3630 "zh_Moon_HK"
3631 }, {
3632 "zh_Moon_AQ",
3633 "zh_Moon_AQ",
3634 "zh_Moon_AQ"
3635 }, {
3636 "art",
3637 "",
3638 ""
3639 }, {
3640 "art_ZZ",
3641 "",
3642 ""
3643 }, {
3644 "art_CN",
3645 "",
3646 ""
3647 }, {
3648 "art_TW",
3649 "",
3650 ""
3651 }, {
3652 "art_HK",
3653 "",
3654 ""
3655 }, {
3656 "art_AQ",
3657 "",
3658 ""
3659 }, {
3660 "art_Zzzz",
3661 "",
3662 ""
3663 }, {
3664 "art_Zzzz_ZZ",
3665 "",
3666 ""
3667 }, {
3668 "art_Zzzz_CN",
3669 "",
3670 ""
3671 }, {
3672 "art_Zzzz_TW",
3673 "",
3674 ""
3675 }, {
3676 "art_Zzzz_HK",
3677 "",
3678 ""
3679 }, {
3680 "art_Zzzz_AQ",
3681 "",
3682 ""
3683 }, {
3684 "art_Latn",
3685 "",
3686 ""
3687 }, {
3688 "art_Latn_ZZ",
3689 "",
3690 ""
3691 }, {
3692 "art_Latn_CN",
3693 "",
3694 ""
3695 }, {
3696 "art_Latn_TW",
3697 "",
3698 ""
3699 }, {
3700 "art_Latn_HK",
3701 "",
3702 ""
3703 }, {
3704 "art_Latn_AQ",
3705 "",
3706 ""
3707 }, {
3708 "art_Hans",
3709 "",
3710 ""
3711 }, {
3712 "art_Hans_ZZ",
3713 "",
3714 ""
3715 }, {
3716 "art_Hans_CN",
3717 "",
3718 ""
3719 }, {
3720 "art_Hans_TW",
3721 "",
3722 ""
3723 }, {
3724 "art_Hans_HK",
3725 "",
3726 ""
3727 }, {
3728 "art_Hans_AQ",
3729 "",
3730 ""
3731 }, {
3732 "art_Hant",
3733 "",
3734 ""
3735 }, {
3736 "art_Hant_ZZ",
3737 "",
3738 ""
3739 }, {
3740 "art_Hant_CN",
3741 "",
3742 ""
3743 }, {
3744 "art_Hant_TW",
3745 "",
3746 ""
3747 }, {
3748 "art_Hant_HK",
3749 "",
3750 ""
3751 }, {
3752 "art_Hant_AQ",
3753 "",
3754 ""
3755 }, {
3756 "art_Moon",
3757 "",
3758 ""
3759 }, {
3760 "art_Moon_ZZ",
3761 "",
3762 ""
3763 }, {
3764 "art_Moon_CN",
3765 "",
3766 ""
3767 }, {
3768 "art_Moon_TW",
3769 "",
3770 ""
3771 }, {
3772 "art_Moon_HK",
3773 "",
3774 ""
3775 }, {
3776 "art_Moon_AQ",
3777 "",
3778 ""
3779 }, {
3780 "aae_Latn_IT",
3781 "aae_Latn_IT",
3782 "aae_Latn_IT"
3783 }, {
3784 "aae_Thai_CO",
3785 "aae_Thai_CO",
3786 "aae_Thai_CO"
3787 }, {
3788 "und_CW",
3789 "pap_Latn_CW",
3790 "pap_CW"
3791 }, {
3792 "zh_Hant",
3793 "zh_Hant_TW",
3794 "zh_TW"
3795 }, {
3796 "zh_Hani",
3797 "zh_Hani_CN",
3798 "zh_Hani"
3799 }, {
3800 "und",
3801 "en_Latn_US",
3802 "en"
3803 }, {
3804 "und_Thai",
3805 "th_Thai_TH",
3806 "th"
3807 }, {
3808 "und_419",
3809 "es_Latn_419",
3810 "es_419"
3811 }, {
3812 "und_150",
3813 "ru_Cyrl_RU",
3814 "ru"
3815 }, {
3816 "und_AT",
3817 "de_Latn_AT",
3818 "de_AT"
3819 }, {
3820 "und_US",
3821 "en_Latn_US",
3822 "en"
3823 }
3824 };
3825
3826 for (const auto& item : full_data) {
3827 const char* const org = item.from;
3828 const char* const exp = item.add;
3829 Locale res(org);
3830 res.addLikelySubtags(status);
3831 status.errIfFailureAndReset("\"%s\"", org);
3832 if (exp[0]) {
3833 assertEquals("addLikelySubtags", exp, res.getName());
3834 } else {
3835 assertEquals("addLikelySubtags", org, res.getName());
3836 }
3837 }
3838
3839 for (const auto& item : full_data) {
3840 const char* const org = item.from;
3841 const char* const exp = item.remove;
3842 Locale res(org);
3843 res.minimizeSubtags(status);
3844 status.errIfFailureAndReset("\"%s\"", org);
3845 if (exp[0]) {
3846 assertEquals("minimizeSubtags", exp, res.getName());
3847 } else {
3848 assertEquals("minimizeSubtags", org, res.getName());
3849 }
3850 }
3851 }
3852
3853
3854 void
TestKeywordVariants(void)3855 LocaleTest::TestKeywordVariants(void) {
3856 static const struct {
3857 const char *localeID;
3858 const char *expectedLocaleID;
3859 //const char *expectedLocaleIDNoKeywords;
3860 //const char *expectedCanonicalID;
3861 const char *expectedKeywords[10];
3862 int32_t numKeywords;
3863 UErrorCode expectedStatus;
3864 } testCases[] = {
3865 {
3866 "de_DE@ currency = euro; C o ll A t i o n = Phonebook ; C alen dar = buddhist ",
3867 "de_DE@calendar=buddhist;collation=Phonebook;currency=euro",
3868 //"de_DE",
3869 //"de_DE@calendar=buddhist;collation=Phonebook;currency=euro",
3870 {"calendar", "collation", "currency"},
3871 3,
3872 U_ZERO_ERROR
3873 },
3874 {
3875 "de_DE@euro",
3876 "de_DE@euro",
3877 //"de_DE",
3878 //"de_DE@currency=EUR",
3879 {"","","","","","",""},
3880 0,
3881 U_INVALID_FORMAT_ERROR /* must have '=' after '@' */
3882 }
3883 };
3884 UErrorCode status = U_ZERO_ERROR;
3885
3886 int32_t i = 0, j = 0;
3887 const char *result = NULL;
3888 StringEnumeration *keywords;
3889 int32_t keyCount = 0;
3890 const char *keyword = NULL;
3891 const UnicodeString *keywordString;
3892 int32_t keywordLen = 0;
3893
3894 for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
3895 status = U_ZERO_ERROR;
3896 Locale l(testCases[i].localeID);
3897 keywords = l.createKeywords(status);
3898
3899 if(status != testCases[i].expectedStatus) {
3900 err("Expected to get status %s. Got %s instead\n",
3901 u_errorName(testCases[i].expectedStatus), u_errorName(status));
3902 }
3903 status = U_ZERO_ERROR;
3904 if(keywords) {
3905 if((keyCount = keywords->count(status)) != testCases[i].numKeywords) {
3906 err("Expected to get %i keywords, got %i\n", testCases[i].numKeywords, keyCount);
3907 }
3908 if(keyCount) {
3909 for(j = 0;;) {
3910 if((j&1)==0) {
3911 if((keyword = keywords->next(&keywordLen, status)) == NULL) {
3912 break;
3913 }
3914 if(strcmp(keyword, testCases[i].expectedKeywords[j]) != 0) {
3915 err("Expected to get keyword value %s, got %s\n", testCases[i].expectedKeywords[j], keyword);
3916 }
3917 } else {
3918 if((keywordString = keywords->snext(status)) == NULL) {
3919 break;
3920 }
3921 if(*keywordString != UnicodeString(testCases[i].expectedKeywords[j], "")) {
3922 err("Expected to get keyword UnicodeString %s, got %s\n", testCases[i].expectedKeywords[j], keyword);
3923 }
3924 }
3925 j++;
3926
3927 if(j == keyCount / 2) {
3928 // replace keywords with a clone of itself
3929 StringEnumeration *k2 = keywords->clone();
3930 if(k2 == NULL || keyCount != k2->count(status)) {
3931 errln("KeywordEnumeration.clone() failed");
3932 } else {
3933 delete keywords;
3934 keywords = k2;
3935 }
3936 }
3937 }
3938 keywords->reset(status); // Make sure that reset works.
3939 for(j = 0;;) {
3940 if((keyword = keywords->next(&keywordLen, status)) == NULL) {
3941 break;
3942 }
3943 if(strcmp(keyword, testCases[i].expectedKeywords[j]) != 0) {
3944 err("Expected to get keyword value %s, got %s\n", testCases[i].expectedKeywords[j], keyword);
3945 }
3946 j++;
3947 }
3948 }
3949 delete keywords;
3950 }
3951 result = l.getName();
3952 if(uprv_strcmp(testCases[i].expectedLocaleID, result) != 0) {
3953 err("Expected to get \"%s\" from \"%s\". Got \"%s\" instead\n",
3954 testCases[i].expectedLocaleID, testCases[i].localeID, result);
3955 }
3956
3957 }
3958
3959 }
3960
3961
3962 void
TestCreateUnicodeKeywords(void)3963 LocaleTest::TestCreateUnicodeKeywords(void) {
3964 IcuTestErrorCode status(*this, "TestCreateUnicodeKeywords()");
3965
3966 static const Locale l("de@calendar=buddhist;collation=phonebook");
3967
3968 LocalPointer<StringEnumeration> keys(l.createUnicodeKeywords(status));
3969 status.errIfFailureAndReset("\"%s\"", l.getName());
3970
3971 const char* key;
3972 int32_t resultLength;
3973
3974 key = keys->next(&resultLength, status);
3975 status.errIfFailureAndReset("key #1");
3976 assertEquals("resultLength", 2, resultLength);
3977 assertTrue("key != nullptr", key != nullptr);
3978 if (key != nullptr) {
3979 assertEquals("calendar", "ca", key);
3980 }
3981
3982 key = keys->next(&resultLength, status);
3983 status.errIfFailureAndReset("key #2");
3984 assertEquals("resultLength", 2, resultLength);
3985 assertTrue("key != nullptr", key != nullptr);
3986 if (key != nullptr) {
3987 assertEquals("collation", "co", key);
3988 }
3989
3990 key = keys->next(&resultLength, status);
3991 status.errIfFailureAndReset("end of keys");
3992 assertEquals("resultLength", 0, resultLength);
3993 assertTrue("key == nullptr", key == nullptr);
3994
3995 const UnicodeString* skey;
3996 keys->reset(status); // KeywordEnumeration::reset() never touches status.
3997
3998 skey = keys->snext(status);
3999 status.errIfFailureAndReset("skey #1");
4000 assertTrue("skey != nullptr", skey != nullptr);
4001 if (skey != nullptr) {
4002 assertEquals("calendar", "ca", *skey);
4003 }
4004
4005 skey = keys->snext(status);
4006 status.errIfFailureAndReset("skey #2");
4007 assertTrue("skey != nullptr", skey != nullptr);
4008 if (skey != nullptr) {
4009 assertEquals("collation", "co", *skey);
4010 }
4011
4012 skey = keys->snext(status);
4013 status.errIfFailureAndReset("end of keys");
4014 assertTrue("skey == nullptr", skey == nullptr);
4015 }
4016
4017
4018 void
TestKeywordVariantParsing(void)4019 LocaleTest::TestKeywordVariantParsing(void) {
4020 static const struct {
4021 const char *localeID;
4022 const char *keyword;
4023 const char *expectedValue;
4024 } testCases[] = {
4025 { "de_DE@ C o ll A t i o n = Phonebook ", "collation", "Phonebook" },
4026 { "de_DE", "collation", ""},
4027 { "de_DE@collation= PHONEBOOK", "collation", "PHONEBOOK" },
4028 { "de_DE@ currency = euro ; CoLLaTion = PHONEBOOk ", "collation", "PHONEBOOk" },
4029 };
4030
4031 UErrorCode status = U_ZERO_ERROR;
4032
4033 int32_t i = 0;
4034 int32_t resultLen = 0;
4035 char buffer[256];
4036
4037 for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
4038 *buffer = 0;
4039 Locale l(testCases[i].localeID);
4040 resultLen = l.getKeywordValue(testCases[i].keyword, buffer, 256, status);
4041 (void)resultLen; // Suppress unused variable warning.
4042 if(uprv_strcmp(testCases[i].expectedValue, buffer) != 0) {
4043 err("Expected to extract \"%s\" from \"%s\" for keyword \"%s\". Got \"%s\" instead\n",
4044 testCases[i].expectedValue, testCases[i].localeID, testCases[i].keyword, buffer);
4045 }
4046 }
4047 }
4048
4049 void
TestCreateKeywordSet(void)4050 LocaleTest::TestCreateKeywordSet(void) {
4051 IcuTestErrorCode status(*this, "TestCreateKeywordSet()");
4052
4053 static const Locale l("de@calendar=buddhist;collation=phonebook");
4054
4055 std::set<std::string> result;
4056 l.getKeywords<std::string>(
4057 std::insert_iterator<decltype(result)>(result, result.begin()),
4058 status);
4059 status.errIfFailureAndReset("\"%s\"", l.getName());
4060
4061 assertEquals("set::size()", 2, static_cast<int32_t>(result.size()));
4062 assertTrue("set::find(\"calendar\")",
4063 result.find("calendar") != result.end());
4064 assertTrue("set::find(\"collation\")",
4065 result.find("collation") != result.end());
4066 }
4067
4068 void
TestCreateKeywordSetEmpty(void)4069 LocaleTest::TestCreateKeywordSetEmpty(void) {
4070 IcuTestErrorCode status(*this, "TestCreateKeywordSetEmpty()");
4071
4072 static const Locale l("de");
4073
4074 std::set<std::string> result;
4075 l.getKeywords<std::string>(
4076 std::insert_iterator<decltype(result)>(result, result.begin()),
4077 status);
4078 status.errIfFailureAndReset("\"%s\"", l.getName());
4079
4080 assertEquals("set::size()", 0, static_cast<int32_t>(result.size()));
4081 }
4082
4083 void
TestCreateUnicodeKeywordSet(void)4084 LocaleTest::TestCreateUnicodeKeywordSet(void) {
4085 IcuTestErrorCode status(*this, "TestCreateUnicodeKeywordSet()");
4086
4087 static const Locale l("de@calendar=buddhist;collation=phonebook");
4088
4089 std::set<std::string> result;
4090 l.getUnicodeKeywords<std::string>(
4091 std::insert_iterator<decltype(result)>(result, result.begin()),
4092 status);
4093 status.errIfFailureAndReset("\"%s\"", l.getName());
4094
4095 assertEquals("set::size()", 2, static_cast<int32_t>(result.size()));
4096 assertTrue("set::find(\"ca\")",
4097 result.find("ca") != result.end());
4098 assertTrue("set::find(\"co\")",
4099 result.find("co") != result.end());
4100 }
4101
4102 void
TestCreateUnicodeKeywordSetEmpty(void)4103 LocaleTest::TestCreateUnicodeKeywordSetEmpty(void) {
4104 IcuTestErrorCode status(*this, "TestCreateUnicodeKeywordSetEmpty()");
4105
4106 static const Locale l("de");
4107
4108 std::set<std::string> result;
4109 l.getUnicodeKeywords<std::string>(
4110 std::insert_iterator<decltype(result)>(result, result.begin()),
4111 status);
4112 status.errIfFailureAndReset("\"%s\"", l.getName());
4113
4114 assertEquals("set::size()", 0, static_cast<int32_t>(result.size()));
4115 }
4116
4117 void
TestGetKeywordValueStdString(void)4118 LocaleTest::TestGetKeywordValueStdString(void) {
4119 IcuTestErrorCode status(*this, "TestGetKeywordValueStdString()");
4120
4121 static const char tag[] = "fa-u-nu-latn";
4122 static const char keyword[] = "numbers";
4123 static const char expected[] = "latn";
4124
4125 Locale l = Locale::forLanguageTag(tag, status);
4126 status.errIfFailureAndReset("\"%s\"", tag);
4127
4128 std::string result = l.getKeywordValue<std::string>(keyword, status);
4129 status.errIfFailureAndReset("\"%s\"", keyword);
4130 assertEquals(keyword, expected, result.c_str());
4131 }
4132
4133 void
TestGetUnicodeKeywordValueStdString(void)4134 LocaleTest::TestGetUnicodeKeywordValueStdString(void) {
4135 IcuTestErrorCode status(*this, "TestGetUnicodeKeywordValueStdString()");
4136
4137 static const char keyword[] = "co";
4138 static const char expected[] = "phonebk";
4139
4140 static const Locale l("de@calendar=buddhist;collation=phonebook");
4141
4142 std::string result = l.getUnicodeKeywordValue<std::string>(keyword, status);
4143 status.errIfFailureAndReset("\"%s\"", keyword);
4144 assertEquals(keyword, expected, result.c_str());
4145 }
4146
4147 void
TestSetKeywordValue(void)4148 LocaleTest::TestSetKeywordValue(void) {
4149 static const struct {
4150 const char *keyword;
4151 const char *value;
4152 } testCases[] = {
4153 { "collation", "phonebook" },
4154 { "currency", "euro" },
4155 { "calendar", "buddhist" }
4156 };
4157
4158 IcuTestErrorCode status(*this, "TestSetKeywordValue()");
4159
4160 int32_t i = 0;
4161 int32_t resultLen = 0;
4162 char buffer[256];
4163
4164 Locale l(Locale::getGerman());
4165
4166 for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
4167 l.setKeywordValue(testCases[i].keyword, testCases[i].value, status);
4168 if(U_FAILURE(status)) {
4169 err("FAIL: Locale::setKeywordValue failed - %s\n", u_errorName(status));
4170 }
4171
4172 *buffer = 0;
4173 resultLen = l.getKeywordValue(testCases[i].keyword, buffer, 256, status);
4174 (void)resultLen; // Suppress unused variable warning.
4175 if(uprv_strcmp(testCases[i].value, buffer) != 0) {
4176 err("Expected to extract \"%s\" for keyword \"%s\". Got \"%s\" instead\n",
4177 testCases[i].value, testCases[i].keyword, buffer);
4178 }
4179 }
4180
4181 // Test long locale
4182 {
4183 status.errIfFailureAndReset();
4184 const char* input =
4185 "de__POSIX@colnormalization=no;colstrength=primary;currency=eur;"
4186 "em=default;kv=space;lb=strict;lw=normal;measure=metric;"
4187 "numbers=latn;rg=atzzzz;sd=atat1";
4188 const char* expected =
4189 "de__POSIX@colnormalization=no;colstrength=primary;currency=eur;"
4190 "em=default;kv=space;lb=strict;lw=normal;measure=metric;"
4191 "numbers=latn;rg=atzzzz;sd=atat1;ss=none";
4192 // Bug ICU-21385
4193 Locale l2(input);
4194 l2.setKeywordValue("ss", "none", status);
4195 assertEquals("", expected, l2.getName());
4196 status.errIfFailureAndReset();
4197 }
4198 }
4199
4200 void
TestSetKeywordValueStringPiece(void)4201 LocaleTest::TestSetKeywordValueStringPiece(void) {
4202 IcuTestErrorCode status(*this, "TestSetKeywordValueStringPiece()");
4203 Locale l(Locale::getGerman());
4204
4205 l.setKeywordValue(StringPiece("collation"), StringPiece("phonebook"), status);
4206 l.setKeywordValue(StringPiece("calendarxxx", 8), StringPiece("buddhistxxx", 8), status);
4207
4208 static const char expected[] = "de@calendar=buddhist;collation=phonebook";
4209 assertEquals("", expected, l.getName());
4210 }
4211
4212 void
TestSetUnicodeKeywordValueStringPiece(void)4213 LocaleTest::TestSetUnicodeKeywordValueStringPiece(void) {
4214 IcuTestErrorCode status(*this, "TestSetUnicodeKeywordValueStringPiece()");
4215 Locale l(Locale::getGerman());
4216
4217 l.setUnicodeKeywordValue(StringPiece("co"), StringPiece("phonebk"), status);
4218 status.errIfFailureAndReset();
4219
4220 l.setUnicodeKeywordValue(StringPiece("caxxx", 2), StringPiece("buddhistxxx", 8), status);
4221 status.errIfFailureAndReset();
4222
4223 static const char expected[] = "de@calendar=buddhist;collation=phonebook";
4224 assertEquals("", expected, l.getName());
4225
4226 l.setUnicodeKeywordValue("cu", nullptr, status);
4227 status.errIfFailureAndReset();
4228 assertEquals("", expected, l.getName());
4229
4230 l.setUnicodeKeywordValue("!!", nullptr, status);
4231 assertEquals("status", U_ILLEGAL_ARGUMENT_ERROR, status.reset());
4232 assertEquals("", expected, l.getName());
4233
4234 l.setUnicodeKeywordValue("co", "!!", status);
4235 assertEquals("status", U_ILLEGAL_ARGUMENT_ERROR, status.reset());
4236 assertEquals("", expected, l.getName());
4237
4238 l.setUnicodeKeywordValue("co", nullptr, status);
4239 status.errIfFailureAndReset();
4240
4241 l.setUnicodeKeywordValue("ca", "", status);
4242 status.errIfFailureAndReset();
4243
4244 assertEquals("", Locale::getGerman().getName(), l.getName());
4245 }
4246
4247 void
TestGetBaseName(void)4248 LocaleTest::TestGetBaseName(void) {
4249 static const struct {
4250 const char *localeID;
4251 const char *baseName;
4252 } testCases[] = {
4253 { "de_DE@ C o ll A t i o n = Phonebook ", "de_DE" },
4254 { "de@currency = euro; CoLLaTion = PHONEBOOk", "de" },
4255 { "ja@calendar = buddhist", "ja" },
4256 { "de-u-co-phonebk", "de"}
4257 };
4258
4259 int32_t i = 0;
4260
4261 for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
4262 Locale loc(testCases[i].localeID);
4263 if(strcmp(testCases[i].baseName, loc.getBaseName())) {
4264 errln("For locale \"%s\" expected baseName \"%s\", but got \"%s\"",
4265 testCases[i].localeID, testCases[i].baseName, loc.getBaseName());
4266 return;
4267 }
4268 }
4269
4270 // Verify that adding a keyword to an existing Locale doesn't change the base name.
4271 UErrorCode status = U_ZERO_ERROR;
4272 Locale loc2("en-US");
4273 if (strcmp("en_US", loc2.getBaseName())) {
4274 errln("%s:%d Expected \"en_US\", got \"%s\"", __FILE__, __LINE__, loc2.getBaseName());
4275 }
4276 loc2.setKeywordValue("key", "value", status);
4277 if (strcmp("en_US@key=value", loc2.getName())) {
4278 errln("%s:%d Expected \"en_US@key=value\", got \"%s\"", __FILE__, __LINE__, loc2.getName());
4279 }
4280 if (strcmp("en_US", loc2.getBaseName())) {
4281 errln("%s:%d Expected \"en_US\", got \"%s\"", __FILE__, __LINE__, loc2.getBaseName());
4282 }
4283 }
4284
4285 /**
4286 * Compare two locale IDs. If they are equal, return 0. If `string'
4287 * starts with `prefix' plus an additional element, that is, string ==
4288 * prefix + '_' + x, then return 1. Otherwise return a value < 0.
4289 */
_loccmp(const char * string,const char * prefix)4290 static UBool _loccmp(const char* string, const char* prefix) {
4291 int32_t slen = (int32_t)strlen(string),
4292 plen = (int32_t)strlen(prefix);
4293 int32_t c = uprv_strncmp(string, prefix, plen);
4294 /* 'root' is "less than" everything */
4295 if (prefix[0] == '\0') {
4296 return string[0] != '\0';
4297 }
4298 if (c) return -1; /* mismatch */
4299 if (slen == plen) return 0;
4300 if (string[plen] == '_') return 1;
4301 return -2; /* false match, e.g. "en_USX" cmp "en_US" */
4302 }
4303
4304 /**
4305 * Check the relationship between requested locales, and report problems.
4306 * The caller specifies the expected relationships between requested
4307 * and valid (expReqValid) and between valid and actual (expValidActual).
4308 * Possible values are:
4309 * "gt" strictly greater than, e.g., en_US > en
4310 * "ge" greater or equal, e.g., en >= en
4311 * "eq" equal, e.g., en == en
4312 */
_checklocs(const char * label,const char * req,const Locale & validLoc,const Locale & actualLoc,const char * expReqValid,const char * expValidActual)4313 void LocaleTest::_checklocs(const char* label,
4314 const char* req,
4315 const Locale& validLoc,
4316 const Locale& actualLoc,
4317 const char* expReqValid,
4318 const char* expValidActual) {
4319 const char* valid = validLoc.getName();
4320 const char* actual = actualLoc.getName();
4321 int32_t reqValid = _loccmp(req, valid);
4322 int32_t validActual = _loccmp(valid, actual);
4323 if (((0 == uprv_strcmp(expReqValid, "gt") && reqValid > 0) ||
4324 (0 == uprv_strcmp(expReqValid, "ge") && reqValid >= 0) ||
4325 (0 == uprv_strcmp(expReqValid, "eq") && reqValid == 0)) &&
4326 ((0 == uprv_strcmp(expValidActual, "gt") && validActual > 0) ||
4327 (0 == uprv_strcmp(expValidActual, "ge") && validActual >= 0) ||
4328 (0 == uprv_strcmp(expValidActual, "eq") && validActual == 0))) {
4329 logln("%s; req=%s, valid=%s, actual=%s",
4330 label, req, valid, actual);
4331 } else {
4332 dataerrln("FAIL: %s; req=%s, valid=%s, actual=%s. Require (R %s V) and (V %s A)",
4333 label, req, valid, actual,
4334 expReqValid, expValidActual);
4335 }
4336 }
4337
TestGetLocale(void)4338 void LocaleTest::TestGetLocale(void) {
4339 #if !UCONFIG_NO_SERVICE
4340 const char *req;
4341 Locale valid, actual, reqLoc;
4342
4343 // Calendar
4344 #if !UCONFIG_NO_FORMATTING
4345 {
4346 UErrorCode ec = U_ZERO_ERROR; // give each resource type its own error code
4347 req = "en_US_BROOKLYN";
4348 Calendar* cal = Calendar::createInstance(Locale::createFromName(req), ec);
4349 if (U_FAILURE(ec)) {
4350 dataerrln("FAIL: Calendar::createInstance failed - %s", u_errorName(ec));
4351 } else {
4352 valid = cal->getLocale(ULOC_VALID_LOCALE, ec);
4353 actual = cal->getLocale(ULOC_ACTUAL_LOCALE, ec);
4354 if (U_FAILURE(ec)) {
4355 errln("FAIL: Calendar::getLocale() failed");
4356 } else {
4357 _checklocs("Calendar", req, valid, actual);
4358 }
4359 /* Make sure that it fails correctly */
4360 ec = U_FILE_ACCESS_ERROR;
4361 if (cal->getLocale(ULOC_VALID_LOCALE, ec).getName()[0] != 0) {
4362 errln("FAIL: Calendar::getLocale() failed to fail correctly. It should have returned \"\"");
4363 }
4364 ec = U_ZERO_ERROR;
4365 }
4366 delete cal;
4367 }
4368 #endif
4369
4370 // DecimalFormat, DecimalFormatSymbols
4371 #if !UCONFIG_NO_FORMATTING
4372 {
4373 UErrorCode ec = U_ZERO_ERROR; // give each resource type its own error code
4374 req = "fr_FR_NICE";
4375 NumberFormat* nf = NumberFormat::createInstance(Locale::createFromName(req), ec);
4376 if (U_FAILURE(ec)) {
4377 dataerrln("FAIL: NumberFormat::createInstance failed - %s", u_errorName(ec));
4378 } else {
4379 DecimalFormat* dec = dynamic_cast<DecimalFormat*>(nf);
4380 if (dec == NULL) {
4381 errln("FAIL: NumberFormat::createInstance does not return a DecimalFormat");
4382 return;
4383 }
4384 valid = dec->getLocale(ULOC_VALID_LOCALE, ec);
4385 actual = dec->getLocale(ULOC_ACTUAL_LOCALE, ec);
4386 if (U_FAILURE(ec)) {
4387 errln("FAIL: DecimalFormat::getLocale() failed");
4388 } else {
4389 _checklocs("DecimalFormat", req, valid, actual);
4390 }
4391
4392 const DecimalFormatSymbols* sym = dec->getDecimalFormatSymbols();
4393 if (sym == NULL) {
4394 errln("FAIL: getDecimalFormatSymbols returned NULL");
4395 return;
4396 }
4397 valid = sym->getLocale(ULOC_VALID_LOCALE, ec);
4398 actual = sym->getLocale(ULOC_ACTUAL_LOCALE, ec);
4399 if (U_FAILURE(ec)) {
4400 errln("FAIL: DecimalFormatSymbols::getLocale() failed");
4401 } else {
4402 _checklocs("DecimalFormatSymbols", req, valid, actual);
4403 }
4404 }
4405 delete nf;
4406 }
4407 #endif
4408
4409 // DateFormat, DateFormatSymbols
4410 #if !UCONFIG_NO_FORMATTING
4411 {
4412 UErrorCode ec = U_ZERO_ERROR; // give each resource type its own error code
4413 req = "de_CH_LUCERNE";
4414 DateFormat* df =
4415 DateFormat::createDateInstance(DateFormat::kDefault,
4416 Locale::createFromName(req));
4417 if (df == 0){
4418 dataerrln("Error calling DateFormat::createDateInstance()");
4419 } else {
4420 SimpleDateFormat* dat = dynamic_cast<SimpleDateFormat*>(df);
4421 if (dat == NULL) {
4422 errln("FAIL: DateFormat::createInstance does not return a SimpleDateFormat");
4423 return;
4424 }
4425 valid = dat->getLocale(ULOC_VALID_LOCALE, ec);
4426 actual = dat->getLocale(ULOC_ACTUAL_LOCALE, ec);
4427 if (U_FAILURE(ec)) {
4428 errln("FAIL: SimpleDateFormat::getLocale() failed");
4429 } else {
4430 _checklocs("SimpleDateFormat", req, valid, actual);
4431 }
4432
4433 const DateFormatSymbols* sym = dat->getDateFormatSymbols();
4434 if (sym == NULL) {
4435 errln("FAIL: getDateFormatSymbols returned NULL");
4436 return;
4437 }
4438 valid = sym->getLocale(ULOC_VALID_LOCALE, ec);
4439 actual = sym->getLocale(ULOC_ACTUAL_LOCALE, ec);
4440 if (U_FAILURE(ec)) {
4441 errln("FAIL: DateFormatSymbols::getLocale() failed");
4442 } else {
4443 _checklocs("DateFormatSymbols", req, valid, actual);
4444 }
4445 }
4446 delete df;
4447 }
4448 #endif
4449
4450 // BreakIterator
4451 #if !UCONFIG_NO_BREAK_ITERATION
4452 {
4453 UErrorCode ec = U_ZERO_ERROR; // give each resource type its own error code
4454 req = "es_ES_BARCELONA";
4455 reqLoc = Locale::createFromName(req);
4456 BreakIterator* brk = BreakIterator::createWordInstance(reqLoc, ec);
4457 if (U_FAILURE(ec)) {
4458 dataerrln("FAIL: BreakIterator::createWordInstance failed - %s", u_errorName(ec));
4459 } else {
4460 valid = brk->getLocale(ULOC_VALID_LOCALE, ec);
4461 actual = brk->getLocale(ULOC_ACTUAL_LOCALE, ec);
4462 if (U_FAILURE(ec)) {
4463 errln("FAIL: BreakIterator::getLocale() failed");
4464 } else {
4465 _checklocs("BreakIterator", req, valid, actual);
4466 }
4467
4468 // After registering something, the behavior should be different
4469 URegistryKey key = BreakIterator::registerInstance(brk, reqLoc, UBRK_WORD, ec);
4470 brk = 0; // registerInstance adopts
4471 if (U_FAILURE(ec)) {
4472 errln("FAIL: BreakIterator::registerInstance() failed");
4473 } else {
4474 brk = BreakIterator::createWordInstance(reqLoc, ec);
4475 if (U_FAILURE(ec)) {
4476 errln("FAIL: BreakIterator::createWordInstance failed");
4477 } else {
4478 valid = brk->getLocale(ULOC_VALID_LOCALE, ec);
4479 actual = brk->getLocale(ULOC_ACTUAL_LOCALE, ec);
4480 if (U_FAILURE(ec)) {
4481 errln("FAIL: BreakIterator::getLocale() failed");
4482 } else {
4483 // N.B.: now expect valid==actual==req
4484 _checklocs("BreakIterator(registered)",
4485 req, valid, actual, "eq", "eq");
4486 }
4487 }
4488 // No matter what, unregister
4489 BreakIterator::unregister(key, ec);
4490 if (U_FAILURE(ec)) {
4491 errln("FAIL: BreakIterator::unregister() failed");
4492 }
4493 delete brk;
4494 brk = 0;
4495 }
4496
4497 // After unregistering, should behave normally again
4498 brk = BreakIterator::createWordInstance(reqLoc, ec);
4499 if (U_FAILURE(ec)) {
4500 errln("FAIL: BreakIterator::createWordInstance failed");
4501 } else {
4502 valid = brk->getLocale(ULOC_VALID_LOCALE, ec);
4503 actual = brk->getLocale(ULOC_ACTUAL_LOCALE, ec);
4504 if (U_FAILURE(ec)) {
4505 errln("FAIL: BreakIterator::getLocale() failed");
4506 } else {
4507 _checklocs("BreakIterator(unregistered)", req, valid, actual);
4508 }
4509 }
4510 }
4511 delete brk;
4512 }
4513 #endif
4514
4515 // Collator
4516 #if !UCONFIG_NO_COLLATION
4517 {
4518 UErrorCode ec = U_ZERO_ERROR; // give each resource type its own error code
4519
4520 checkRegisteredCollators(NULL); // Don't expect any extras
4521
4522 req = "hi_IN_BHOPAL";
4523 reqLoc = Locale::createFromName(req);
4524 Collator* coll = Collator::createInstance(reqLoc, ec);
4525 if (U_FAILURE(ec)) {
4526 dataerrln("FAIL: Collator::createInstance failed - %s", u_errorName(ec));
4527 } else {
4528 valid = coll->getLocale(ULOC_VALID_LOCALE, ec);
4529 actual = coll->getLocale(ULOC_ACTUAL_LOCALE, ec);
4530 if (U_FAILURE(ec)) {
4531 errln("FAIL: Collator::getLocale() failed");
4532 } else {
4533 _checklocs("Collator", req, valid, actual);
4534 }
4535
4536 // After registering something, the behavior should be different
4537 URegistryKey key = Collator::registerInstance(coll, reqLoc, ec);
4538 coll = 0; // registerInstance adopts
4539 if (U_FAILURE(ec)) {
4540 errln("FAIL: Collator::registerInstance() failed");
4541 } else {
4542 coll = Collator::createInstance(reqLoc, ec);
4543 if (U_FAILURE(ec)) {
4544 errln("FAIL: Collator::createWordInstance failed");
4545 } else {
4546 valid = coll->getLocale(ULOC_VALID_LOCALE, ec);
4547 actual = coll->getLocale(ULOC_ACTUAL_LOCALE, ec);
4548 if (U_FAILURE(ec)) {
4549 errln("FAIL: Collator::getLocale() failed");
4550 } else {
4551 // N.B.: now expect valid==actual==req
4552 _checklocs("Collator(registered)",
4553 req, valid, actual, "eq", "eq");
4554 }
4555 }
4556 checkRegisteredCollators(req); // include hi_IN_BHOPAL
4557
4558 // No matter what, unregister
4559 Collator::unregister(key, ec);
4560 if (U_FAILURE(ec)) {
4561 errln("FAIL: Collator::unregister() failed");
4562 }
4563 delete coll;
4564 coll = 0;
4565 }
4566
4567 // After unregistering, should behave normally again
4568 coll = Collator::createInstance(reqLoc, ec);
4569 if (U_FAILURE(ec)) {
4570 errln("FAIL: Collator::createInstance failed");
4571 } else {
4572 valid = coll->getLocale(ULOC_VALID_LOCALE, ec);
4573 actual = coll->getLocale(ULOC_ACTUAL_LOCALE, ec);
4574 if (U_FAILURE(ec)) {
4575 errln("FAIL: Collator::getLocale() failed");
4576 } else {
4577 _checklocs("Collator(unregistered)", req, valid, actual);
4578 }
4579 }
4580 }
4581 delete coll;
4582
4583 checkRegisteredCollators(NULL); // extra should be gone again
4584 }
4585 #endif
4586 #endif
4587 }
4588
4589 #if !UCONFIG_NO_COLLATION
4590 /**
4591 * Compare Collator::getAvailableLocales(int) [ "old", returning an array ]
4592 * with Collator::getAvailableLocales() [ "new", returning a StringEnumeration ]
4593 * These should be identical (check their API docs) EXCEPT that
4594 * if expectExtra is non-NULL, it will be in the "new" array but not "old".
4595 * Does not return any status but calls errln on error.
4596 * @param expectExtra an extra locale, will be in "new" but not "old". Or NULL.
4597 */
checkRegisteredCollators(const char * expectExtra)4598 void LocaleTest::checkRegisteredCollators(const char *expectExtra) {
4599 UErrorCode status = U_ZERO_ERROR;
4600 int32_t count1=0,count2=0;
4601 Hashtable oldHash(status);
4602 Hashtable newHash(status);
4603 assertSuccess(WHERE, status);
4604
4605 UnicodeString expectStr(expectExtra?expectExtra:"n/a", "");
4606
4607 // the 'old' list (non enumeration)
4608 const Locale* oldList = Collator::getAvailableLocales(count1);
4609 if(oldList == NULL) {
4610 dataerrln("Error: Collator::getAvailableLocales(count) returned NULL");
4611 return;
4612 }
4613
4614 // the 'new' list (enumeration)
4615 LocalPointer<StringEnumeration> newEnum(Collator::getAvailableLocales());
4616 if(newEnum.isNull()) {
4617 errln("Error: collator::getAvailableLocales() returned NULL");
4618 return;
4619 }
4620
4621 // OK. Let's add all of the OLD
4622 // then check for any in the NEW not in OLD
4623 // then check for any in OLD not in NEW.
4624
4625 // 1. add all of OLD
4626 for(int32_t i=0;i<count1;i++) {
4627 const UnicodeString key(oldList[i].getName(), "");
4628 int32_t oldI = oldHash.puti(key, 1, status);
4629 if( oldI == 1 ){
4630 errln("Error: duplicate key %s in Collator::getAvailableLocales(count) list.\n",
4631 oldList[i].getName());
4632 return;
4633 }
4634 if(expectExtra != NULL && !strcmp(expectExtra, oldList[i].getName())) {
4635 errln("Inexplicably, Collator::getAvailableCollators(count) had registered collator %s. This shouldn't happen, so I am going to consider it an error.\n", expectExtra);
4636 }
4637 }
4638
4639 // 2. add all of NEW
4640 const UnicodeString *locStr;
4641 UBool foundExpected = FALSE;
4642 while((locStr = newEnum->snext(status)) && U_SUCCESS(status)) {
4643 count2++;
4644
4645 if(expectExtra != NULL && expectStr == *locStr) {
4646 foundExpected = TRUE;
4647 logln(UnicodeString("Found expected registered collator: ","") + expectStr);
4648 }
4649 (void)foundExpected; // Hush unused variable compiler warning.
4650
4651 if( oldHash.geti(*locStr) == 0 ) {
4652 if(expectExtra != NULL && expectStr==*locStr) {
4653 logln(UnicodeString("As expected, Collator::getAvailableLocales(count) is missing registered collator ") + expectStr);
4654 } else {
4655 errln(UnicodeString("Error: Collator::getAvailableLocales(count) is missing: ","")
4656 + *locStr);
4657 }
4658 }
4659 newHash.puti(*locStr, 1, status);
4660 }
4661
4662 // 3. check all of OLD again
4663 for(int32_t i=0;i<count1;i++) {
4664 const UnicodeString key(oldList[i].getName(), "");
4665 int32_t newI = newHash.geti(key);
4666 if(newI == 0) {
4667 errln(UnicodeString("Error: Collator::getAvailableLocales() is missing: ","")
4668 + key);
4669 }
4670 }
4671
4672 int32_t expectCount2 = count1;
4673 if(expectExtra != NULL) {
4674 expectCount2 ++; // if an extra item registered, bump the expect count
4675 }
4676
4677 assertEquals("Collator::getAvail() count", expectCount2, count2);
4678 }
4679 #endif
4680
4681
4682
TestVariantWithOutCountry(void)4683 void LocaleTest::TestVariantWithOutCountry(void) {
4684 Locale loc("en","","POSIX");
4685 if (0 != strcmp(loc.getVariant(), "POSIX")) {
4686 errln("FAIL: en__POSIX didn't get parsed correctly - name is %s - expected %s got %s", loc.getName(), "POSIX", loc.getVariant());
4687 }
4688 Locale loc2("en","","FOUR");
4689 if (0 != strcmp(loc2.getVariant(), "FOUR")) {
4690 errln("FAIL: en__FOUR didn't get parsed correctly - name is %s - expected %s got %s", loc2.getName(), "FOUR", loc2.getVariant());
4691 }
4692 Locale loc3("en","Latn","","FOUR");
4693 if (0 != strcmp(loc3.getVariant(), "FOUR")) {
4694 errln("FAIL: en_Latn__FOUR didn't get parsed correctly - name is %s - expected %s got %s", loc3.getName(), "FOUR", loc3.getVariant());
4695 }
4696 Locale loc4("","Latn","","FOUR");
4697 if (0 != strcmp(loc4.getVariant(), "FOUR")) {
4698 errln("FAIL: _Latn__FOUR didn't get parsed correctly - name is %s - expected %s got %s", loc4.getName(), "FOUR", loc4.getVariant());
4699 }
4700 Locale loc5("","Latn","US","FOUR");
4701 if (0 != strcmp(loc5.getVariant(), "FOUR")) {
4702 errln("FAIL: _Latn_US_FOUR didn't get parsed correctly - name is %s - expected %s got %s", loc5.getName(), "FOUR", loc5.getVariant());
4703 }
4704 Locale loc6("de-1901");
4705 if (0 != strcmp(loc6.getVariant(), "1901")) {
4706 errln("FAIL: de-1901 didn't get parsed correctly - name is %s - expected %s got %s", loc6.getName(), "1901", loc6.getVariant());
4707 }
4708 }
4709
_canonicalize(int32_t selector,const char * localeID)4710 static Locale _canonicalize(int32_t selector, /* 0==createFromName, 1==createCanonical, 2==Locale ct */
4711 const char* localeID) {
4712 switch (selector) {
4713 case 0:
4714 return Locale::createFromName(localeID);
4715 case 1:
4716 return Locale::createCanonical(localeID);
4717 case 2:
4718 return Locale(localeID);
4719 default:
4720 return Locale("");
4721 }
4722 }
4723
TestCanonicalization(void)4724 void LocaleTest::TestCanonicalization(void)
4725 {
4726 static const struct {
4727 const char *localeID; /* input */
4728 const char *getNameID; /* expected getName() result */
4729 const char *canonicalID; /* expected canonicalize() result */
4730 } testCases[] = {
4731 { "ca_ES-with-extra-stuff-that really doesn't make any sense-unless-you're trying to increase code coverage",
4732 "ca_ES_WITH_EXTRA_STUFF_THAT REALLY DOESN'T MAKE ANY SENSE_UNLESS_YOU'RE TRYING TO INCREASE CODE COVERAGE",
4733 "ca_ES_EXTRA_STUFF_THAT REALLY DOESN'T MAKE ANY SENSE_UNLESS_WITH_YOU'RE TRYING TO INCREASE CODE COVERAGE"},
4734 { "zh@collation=pinyin", "zh@collation=pinyin", "zh@collation=pinyin" },
4735 { "zh_CN@collation=pinyin", "zh_CN@collation=pinyin", "zh_CN@collation=pinyin" },
4736 { "zh_CN_CA@collation=pinyin", "zh_CN_CA@collation=pinyin", "zh_CN_CA@collation=pinyin" },
4737 { "en_US_POSIX", "en_US_POSIX", "en_US_POSIX" },
4738 { "hy_AM_REVISED", "hy_AM_REVISED", "hy_AM_REVISED" },
4739 { "no_NO_NY", "no_NO_NY", "nb_NO_NY" /* not: "nn_NO" [alan ICU3.0] */ },
4740 { "no@ny", "no@ny", "nb__NY" /* not: "nn" [alan ICU3.0] */ }, /* POSIX ID */
4741 { "no-no.utf32@B", "no_NO.utf32@B", "nb_NO_B" /* not: "nb_NO_B" [alan ICU3.0] */ }, /* POSIX ID */
4742 { "qz-qz@Euro", "qz_QZ@Euro", "qz_QZ_EURO" }, /* qz-qz uses private use iso codes */
4743 // NOTE: uloc_getName() works on en-BOONT, but Locale() parser considers it BOGUS
4744 // TODO: unify this behavior
4745 { "en-BOONT", "en__BOONT", "en__BOONT" }, /* registered name */
4746 { "de-1901", "de__1901", "de__1901" }, /* registered name */
4747 { "de-1906", "de__1906", "de__1906" }, /* registered name */
4748
4749 /* posix behavior that used to be performed by getName */
4750 { "mr.utf8", "mr.utf8", "mr" },
4751 { "de-tv.koi8r", "de_TV.koi8r", "de_TV" },
4752 { "x-piglatin_ML.MBE", "x-piglatin_ML.MBE", "x-piglatin_ML" },
4753 { "i-cherokee_US.utf7", "i-cherokee_US.utf7", "i-cherokee_US" },
4754 { "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA" },
4755 { "no-no-ny.utf8@B", "no_NO_NY.utf8@B", "nb_NO_B_NY" /* not: "nn_NO" [alan ICU3.0] */ }, /* @ ignored unless variant is empty */
4756
4757 /* fleshing out canonicalization */
4758 /* trim space and sort keywords, ';' is separator so not present at end in canonical form */
4759 { "en_Hant_IL_VALLEY_GIRL@ currency = EUR; calendar = Japanese ;",
4760 "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR",
4761 "en_Hant_IL_GIRL_VALLEY@calendar=Japanese;currency=EUR" },
4762 /* already-canonical ids are not changed */
4763 { "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR",
4764 "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR",
4765 "en_Hant_IL_GIRL_VALLEY@calendar=Japanese;currency=EUR" },
4766 /* norwegian is just too weird, if we handle things in their full generality */
4767 { "no-Hant-GB_NY@currency=$$$", "no_Hant_GB_NY@currency=$$$", "nb_Hant_GB_NY@currency=$$$" /* not: "nn_Hant_GB@currency=$$$" [alan ICU3.0] */ },
4768
4769 /* test cases reflecting internal resource bundle usage */
4770 { "root@kw=foo", "root@kw=foo", "root@kw=foo" },
4771 { "@calendar=gregorian", "@calendar=gregorian", "@calendar=gregorian" },
4772 { "ja_JP@calendar=Japanese", "ja_JP@calendar=Japanese", "ja_JP@calendar=Japanese" },
4773
4774 // Before ICU 64, ICU locale canonicalization had some additional mappings.
4775 // They were removed for ICU-20187 "drop support for long-obsolete locale ID variants".
4776 // The following now use standard canonicalization.
4777 { "", "", "" },
4778 { "C", "c", "c" },
4779 { "POSIX", "posix", "posix" },
4780 { "ca_ES_PREEURO", "ca_ES_PREEURO", "ca_ES_PREEURO" },
4781 { "de_AT_PREEURO", "de_AT_PREEURO", "de_AT_PREEURO" },
4782 { "de_DE_PREEURO", "de_DE_PREEURO", "de_DE_PREEURO" },
4783 { "de_LU_PREEURO", "de_LU_PREEURO", "de_LU_PREEURO" },
4784 { "el_GR_PREEURO", "el_GR_PREEURO", "el_GR_PREEURO" },
4785 { "en_BE_PREEURO", "en_BE_PREEURO", "en_BE_PREEURO" },
4786 { "en_IE_PREEURO", "en_IE_PREEURO", "en_IE_PREEURO" },
4787 { "es_ES_PREEURO", "es_ES_PREEURO", "es_ES_PREEURO" },
4788 { "eu_ES_PREEURO", "eu_ES_PREEURO", "eu_ES_PREEURO" },
4789 { "fi_FI_PREEURO", "fi_FI_PREEURO", "fi_FI_PREEURO" },
4790 { "fr_BE_PREEURO", "fr_BE_PREEURO", "fr_BE_PREEURO" },
4791 { "fr_FR_PREEURO", "fr_FR_PREEURO", "fr_FR_PREEURO" },
4792 { "fr_LU_PREEURO", "fr_LU_PREEURO", "fr_LU_PREEURO" },
4793 { "ga_IE_PREEURO", "ga_IE_PREEURO", "ga_IE_PREEURO" },
4794 { "gl_ES_PREEURO", "gl_ES_PREEURO", "gl_ES_PREEURO" },
4795 { "it_IT_PREEURO", "it_IT_PREEURO", "it_IT_PREEURO" },
4796 { "nl_BE_PREEURO", "nl_BE_PREEURO", "nl_BE_PREEURO" },
4797 { "nl_NL_PREEURO", "nl_NL_PREEURO", "nl_NL_PREEURO" },
4798 { "pt_PT_PREEURO", "pt_PT_PREEURO", "pt_PT_PREEURO" },
4799 { "de__PHONEBOOK", "de__PHONEBOOK", "de__PHONEBOOK" },
4800 { "en_GB_EURO", "en_GB_EURO", "en_GB_EURO" },
4801 { "en_GB@EURO", "en_GB@EURO", "en_GB_EURO" }, /* POSIX ID */
4802 { "es__TRADITIONAL", "es__TRADITIONAL", "es__TRADITIONAL" },
4803 { "hi__DIRECT", "hi__DIRECT", "hi__DIRECT" },
4804 { "ja_JP_TRADITIONAL", "ja_JP_TRADITIONAL", "ja_JP_TRADITIONAL" },
4805 { "th_TH_TRADITIONAL", "th_TH_TRADITIONAL", "th_TH_TRADITIONAL" },
4806 { "zh_TW_STROKE", "zh_TW_STROKE", "zh_TW_STROKE" },
4807 { "zh__PINYIN", "zh__PINYIN", "zh__PINYIN" },
4808 { "sr-SP-Cyrl", "sr_SP_CYRL", "sr_SP_CYRL" }, /* .NET name */
4809 { "sr-SP-Latn", "sr_SP_LATN", "sr_SP_LATN" }, /* .NET name */
4810 { "sr_YU_CYRILLIC", "sr_YU_CYRILLIC", "sr_RS_CYRILLIC" }, /* Linux name */
4811 { "uz-UZ-Cyrl", "uz_UZ_CYRL", "uz_UZ_CYRL" }, /* .NET name */
4812 { "uz-UZ-Latn", "uz_UZ_LATN", "uz_UZ_LATN" }, /* .NET name */
4813 { "zh-CHS", "zh_CHS", "zh_CHS" }, /* .NET name */
4814 { "zh-CHT", "zh_CHT", "zh_CHT" }, /* .NET name This may change back to zh_Hant */
4815 /* PRE_EURO and EURO conversions don't affect other keywords */
4816 { "es_ES_PREEURO@CALendar=Japanese", "es_ES_PREEURO@calendar=Japanese", "es_ES_PREEURO@calendar=Japanese" },
4817 { "es_ES_EURO@SHOUT=zipeedeedoodah", "es_ES_EURO@shout=zipeedeedoodah", "es_ES_EURO@shout=zipeedeedoodah" },
4818 /* currency keyword overrides PRE_EURO and EURO currency */
4819 { "es_ES_PREEURO@currency=EUR", "es_ES_PREEURO@currency=EUR", "es_ES_PREEURO@currency=EUR" },
4820 { "es_ES_EURO@currency=ESP", "es_ES_EURO@currency=ESP", "es_ES_EURO@currency=ESP" },
4821 };
4822
4823 static const char* label[] = { "createFromName", "createCanonical", "Locale" };
4824
4825 int32_t i, j;
4826
4827 for (i=0; i < UPRV_LENGTHOF(testCases); i++) {
4828 for (j=0; j<3; ++j) {
4829 const char* expected = (j==1) ? testCases[i].canonicalID : testCases[i].getNameID;
4830 Locale loc = _canonicalize(j, testCases[i].localeID);
4831 const char* getName = loc.isBogus() ? "BOGUS" : loc.getName();
4832 if(uprv_strcmp(expected, getName) != 0) {
4833 errln("FAIL: %s(%s).getName() => \"%s\", expected \"%s\"",
4834 label[j], testCases[i].localeID, getName, expected);
4835 } else {
4836 logln("Ok: %s(%s) => \"%s\"",
4837 label[j], testCases[i].localeID, getName);
4838 }
4839 }
4840 }
4841 }
4842
TestCanonicalize(void)4843 void LocaleTest::TestCanonicalize(void)
4844 {
4845 static const struct {
4846 const char *localeID; /* input */
4847 const char *canonicalID; /* expected canonicalize() result */
4848 } testCases[] = {
4849 // language _ variant -> language
4850 { "no-BOKMAL", "nb" },
4851 // also test with script, country and extensions
4852 { "no-Cyrl-ID-BOKMAL-u-ca-japanese", "nb-Cyrl-ID-u-ca-japanese" },
4853 { "no-Cyrl-ID-1901-BOKMAL-xsistemo-u-ca-japanese", "nb-Cyrl-ID-1901-xsistemo-u-ca-japanese" },
4854 { "no-Cyrl-ID-1901-BOKMAL-u-ca-japanese", "nb-Cyrl-ID-1901-u-ca-japanese" },
4855 { "no-Cyrl-ID-BOKMAL-xsistemo-u-ca-japanese", "nb-Cyrl-ID-xsistemo-u-ca-japanese" },
4856 { "no-NYNORSK", "nn" },
4857 { "no-Cyrl-ID-NYNORSK-u-ca-japanese", "nn-Cyrl-ID-u-ca-japanese" },
4858 { "aa-SAAHO", "ssy" },
4859 // also test with script, country and extensions
4860 { "aa-Deva-IN-SAAHO-u-ca-japanese", "ssy-Deva-IN-u-ca-japanese" },
4861
4862 // language -> language
4863 { "aam", "aas" },
4864 // also test with script, country, variants and extensions
4865 { "aam-Cyrl-ID-3456-u-ca-japanese", "aas-Cyrl-ID-3456-u-ca-japanese" },
4866
4867 // language -> language _ Script
4868 { "sh", "sr-Latn" },
4869 // also test with script
4870 { "sh-Cyrl", "sr-Cyrl" },
4871 // also test with country, variants and extensions
4872 { "sh-ID-3456-u-ca-roc", "sr-Latn-ID-3456-u-ca-roc" },
4873
4874 // language -> language _ country
4875 { "prs", "fa-AF" },
4876 // also test with country
4877 { "prs-RU", "fa-RU" },
4878 // also test with script, variants and extensions
4879 { "prs-Cyrl-1009-u-ca-roc", "fa-Cyrl-AF-1009-u-ca-roc" },
4880
4881 { "pa-IN", "pa-IN" },
4882 // also test with script
4883 { "pa-Latn-IN", "pa-Latn-IN" },
4884 // also test with variants and extensions
4885 { "pa-IN-5678-u-ca-hindi", "pa-IN-5678-u-ca-hindi" },
4886
4887 { "ky-Cyrl-KG", "ky-Cyrl-KG" },
4888 // also test with variants and extensions
4889 { "ky-Cyrl-KG-3456-u-ca-roc", "ky-Cyrl-KG-3456-u-ca-roc" },
4890
4891 // Test replacement of scriptAlias
4892 { "en-Qaai", "en-Zinh" },
4893
4894 // Test replacement of territoryAlias
4895 // 554 has one replacement
4896 { "en-554", "en-NZ" },
4897 { "en-554-u-nu-arab", "en-NZ-u-nu-arab" },
4898 // 172 has multiple replacements
4899 // also test with variants
4900 { "ru-172-1234", "ru-RU-1234" },
4901 // also test with extensions
4902 { "ru-172-1234-u-nu-latn", "ru-RU-1234-u-nu-latn" },
4903 // also test with scripts
4904 { "uz-172", "uz-UZ" },
4905 { "uz-Cyrl-172", "uz-Cyrl-UZ" },
4906 { "uz-Bopo-172", "uz-Bopo-UZ" },
4907 // also test with variants and scripts
4908 { "uz-Cyrl-172-5678-u-nu-latn", "uz-Cyrl-UZ-5678-u-nu-latn" },
4909 // a language not used in this region
4910 { "fr-172", "fr-RU" },
4911
4912 // variant
4913 { "ja-Latn-hepburn-heploc", "ja-Latn-alalc97"},
4914
4915 { "aaa-Fooo-SU", "aaa-Fooo-RU"},
4916
4917 // ICU-21344
4918 { "ku-Arab-NT", "ku-Arab-IQ"},
4919 };
4920 int32_t i;
4921 for (i=0; i < UPRV_LENGTHOF(testCases); i++) {
4922 UErrorCode status = U_ZERO_ERROR;
4923 std::string otag = testCases[i].localeID;
4924 Locale loc = Locale::forLanguageTag(otag.c_str(), status);
4925 loc.canonicalize(status);
4926 std::string tag = loc.toLanguageTag<std::string>(status);
4927 if (tag != testCases[i].canonicalID) {
4928 errcheckln(status, "FAIL: %s should be canonicalized to %s but got %s - %s",
4929 otag.c_str(),
4930 testCases[i].canonicalID,
4931 tag.c_str(),
4932 u_errorName(status));
4933 }
4934 }
4935 }
4936
TestCurrencyByDate(void)4937 void LocaleTest::TestCurrencyByDate(void)
4938 {
4939 #if !UCONFIG_NO_FORMATTING
4940 UErrorCode status = U_ZERO_ERROR;
4941 UDate date = uprv_getUTCtime();
4942 UChar TMP[4] = {0, 0, 0, 0};
4943 int32_t index = 0;
4944 int32_t resLen = 0;
4945 UnicodeString tempStr, resultStr;
4946
4947 // Cycle through historical currencies
4948 date = (UDate)-630720000000.0; // pre 1961 - no currency defined
4949 index = ucurr_countCurrencies("eo_AM", date, &status);
4950 if (index != 0)
4951 {
4952 errcheckln(status, "FAIL: didn't return 0 for eo_AM - %s", u_errorName(status));
4953 }
4954 resLen = ucurr_forLocaleAndDate("eo_AM", date, index, TMP, 4, &status);
4955 if (resLen != 0) {
4956 errcheckln(status, "FAIL: eo_AM didn't return NULL - %s", u_errorName(status));
4957 }
4958 status = U_ZERO_ERROR;
4959
4960 date = (UDate)0.0; // 1970 - one currency defined
4961 index = ucurr_countCurrencies("eo_AM", date, &status);
4962 if (index != 1)
4963 {
4964 errcheckln(status, "FAIL: didn't return 1 for eo_AM - %s", u_errorName(status));
4965 }
4966 resLen = ucurr_forLocaleAndDate("eo_AM", date, index, TMP, 4, &status);
4967 tempStr.setTo(TMP);
4968 resultStr.setTo("SUR");
4969 if (resultStr != tempStr) {
4970 errcheckln(status, "FAIL: didn't return SUR for eo_AM - %s", u_errorName(status));
4971 }
4972
4973 date = (UDate)693792000000.0; // 1992 - one currency defined
4974 index = ucurr_countCurrencies("eo_AM", date, &status);
4975 if (index != 1)
4976 {
4977 errcheckln(status, "FAIL: didn't return 1 for eo_AM - %s", u_errorName(status));
4978 }
4979 resLen = ucurr_forLocaleAndDate("eo_AM", date, index, TMP, 4, &status);
4980 tempStr.setTo(TMP);
4981 resultStr.setTo("RUR");
4982 if (resultStr != tempStr) {
4983 errcheckln(status, "FAIL: didn't return RUR for eo_AM - %s", u_errorName(status));
4984 }
4985
4986 date = (UDate)977616000000.0; // post 1993 - one currency defined
4987 index = ucurr_countCurrencies("eo_AM", date, &status);
4988 if (index != 1)
4989 {
4990 errcheckln(status, "FAIL: didn't return 1 for eo_AM - %s", u_errorName(status));
4991 }
4992 resLen = ucurr_forLocaleAndDate("eo_AM", date, index, TMP, 4, &status);
4993 tempStr.setTo(TMP);
4994 resultStr.setTo("AMD");
4995 if (resultStr != tempStr) {
4996 errcheckln(status, "FAIL: didn't return AMD for eo_AM - %s", u_errorName(status));
4997 }
4998
4999 // Locale AD has multiple currencies at once
5000 date = (UDate)977616000000.0; // year 2001
5001 index = ucurr_countCurrencies("eo_AD", date, &status);
5002 if (index != 4)
5003 {
5004 errcheckln(status, "FAIL: didn't return 4 for eo_AD - %s", u_errorName(status));
5005 }
5006 resLen = ucurr_forLocaleAndDate("eo_AD", date, 1, TMP, 4, &status);
5007 tempStr.setTo(TMP);
5008 resultStr.setTo("EUR");
5009 if (resultStr != tempStr) {
5010 errcheckln(status, "FAIL: didn't return EUR for eo_AD - %s", u_errorName(status));
5011 }
5012 resLen = ucurr_forLocaleAndDate("eo_AD", date, 2, TMP, 4, &status);
5013 tempStr.setTo(TMP);
5014 resultStr.setTo("ESP");
5015 if (resultStr != tempStr) {
5016 errcheckln(status, "FAIL: didn't return ESP for eo_AD - %s", u_errorName(status));
5017 }
5018 resLen = ucurr_forLocaleAndDate("eo_AD", date, 3, TMP, 4, &status);
5019 tempStr.setTo(TMP);
5020 resultStr.setTo("FRF");
5021 if (resultStr != tempStr) {
5022 errcheckln(status, "FAIL: didn't return FRF for eo_AD - %s", u_errorName(status));
5023 }
5024 resLen = ucurr_forLocaleAndDate("eo_AD", date, 4, TMP, 4, &status);
5025 tempStr.setTo(TMP);
5026 resultStr.setTo("ADP");
5027 if (resultStr != tempStr) {
5028 errcheckln(status, "FAIL: didn't return ADP for eo_AD - %s", u_errorName(status));
5029 }
5030
5031 date = (UDate)0.0; // year 1970
5032 index = ucurr_countCurrencies("eo_AD", date, &status);
5033 if (index != 3)
5034 {
5035 errcheckln(status, "FAIL: didn't return 3 for eo_AD - %s", u_errorName(status));
5036 }
5037 resLen = ucurr_forLocaleAndDate("eo_AD", date, 1, TMP, 4, &status);
5038 tempStr.setTo(TMP);
5039 resultStr.setTo("ESP");
5040 if (resultStr != tempStr) {
5041 errcheckln(status, "FAIL: didn't return ESP for eo_AD - %s", u_errorName(status));
5042 }
5043 resLen = ucurr_forLocaleAndDate("eo_AD", date, 2, TMP, 4, &status);
5044 tempStr.setTo(TMP);
5045 resultStr.setTo("FRF");
5046 if (resultStr != tempStr) {
5047 errcheckln(status, "FAIL: didn't return FRF for eo_AD - %s", u_errorName(status));
5048 }
5049 resLen = ucurr_forLocaleAndDate("eo_AD", date, 3, TMP, 4, &status);
5050 tempStr.setTo(TMP);
5051 resultStr.setTo("ADP");
5052 if (resultStr != tempStr) {
5053 errcheckln(status, "FAIL: didn't return ADP for eo_AD - %s", u_errorName(status));
5054 }
5055
5056 date = (UDate)-630720000000.0; // year 1950
5057 index = ucurr_countCurrencies("eo_AD", date, &status);
5058 if (index != 2)
5059 {
5060 errcheckln(status, "FAIL: didn't return 2 for eo_AD - %s", u_errorName(status));
5061 }
5062 resLen = ucurr_forLocaleAndDate("eo_AD", date, 1, TMP, 4, &status);
5063 tempStr.setTo(TMP);
5064 resultStr.setTo("ESP");
5065 if (resultStr != tempStr) {
5066 errcheckln(status, "FAIL: didn't return ESP for eo_AD - %s", u_errorName(status));
5067 }
5068 resLen = ucurr_forLocaleAndDate("eo_AD", date, 2, TMP, 4, &status);
5069 tempStr.setTo(TMP);
5070 resultStr.setTo("ADP");
5071 if (resultStr != tempStr) {
5072 errcheckln(status, "FAIL: didn't return ADP for eo_AD - %s", u_errorName(status));
5073 }
5074
5075 date = (UDate)-2207520000000.0; // year 1900
5076 index = ucurr_countCurrencies("eo_AD", date, &status);
5077 if (index != 1)
5078 {
5079 errcheckln(status, "FAIL: didn't return 1 for eo_AD - %s", u_errorName(status));
5080 }
5081 resLen = ucurr_forLocaleAndDate("eo_AD", date, 1, TMP, 4, &status);
5082 tempStr.setTo(TMP);
5083 resultStr.setTo("ESP");
5084 if (resultStr != tempStr) {
5085 errcheckln(status, "FAIL: didn't return ESP for eo_AD - %s", u_errorName(status));
5086 }
5087
5088 // Locale UA has gap between years 1994 - 1996
5089 date = (UDate)788400000000.0;
5090 index = ucurr_countCurrencies("eo_UA", date, &status);
5091 if (index != 0)
5092 {
5093 errcheckln(status, "FAIL: didn't return 0 for eo_UA - %s", u_errorName(status));
5094 }
5095 resLen = ucurr_forLocaleAndDate("eo_UA", date, index, TMP, 4, &status);
5096 if (resLen != 0) {
5097 errcheckln(status, "FAIL: eo_UA didn't return NULL - %s", u_errorName(status));
5098 }
5099 status = U_ZERO_ERROR;
5100
5101 // Test index bounds
5102 resLen = ucurr_forLocaleAndDate("eo_UA", date, 100, TMP, 4, &status);
5103 if (resLen != 0) {
5104 errcheckln(status, "FAIL: eo_UA didn't return NULL - %s", u_errorName(status));
5105 }
5106 status = U_ZERO_ERROR;
5107
5108 resLen = ucurr_forLocaleAndDate("eo_UA", date, 0, TMP, 4, &status);
5109 if (resLen != 0) {
5110 errcheckln(status, "FAIL: eo_UA didn't return NULL - %s", u_errorName(status));
5111 }
5112 status = U_ZERO_ERROR;
5113
5114 // Test for bogus locale
5115 index = ucurr_countCurrencies("eo_QQ", date, &status);
5116 if (index != 0)
5117 {
5118 errcheckln(status, "FAIL: didn't return 0 for eo_QQ - %s", u_errorName(status));
5119 }
5120 status = U_ZERO_ERROR;
5121 resLen = ucurr_forLocaleAndDate("eo_QQ", date, 1, TMP, 4, &status);
5122 if (resLen != 0) {
5123 errcheckln(status, "FAIL: eo_QQ didn't return NULL - %s", u_errorName(status));
5124 }
5125 status = U_ZERO_ERROR;
5126 resLen = ucurr_forLocaleAndDate("eo_QQ", date, 0, TMP, 4, &status);
5127 if (resLen != 0) {
5128 errcheckln(status, "FAIL: eo_QQ didn't return NULL - %s", u_errorName(status));
5129 }
5130 status = U_ZERO_ERROR;
5131
5132 // Cycle through histrocial currencies
5133 date = (UDate)977616000000.0; // 2001 - one currency
5134 index = ucurr_countCurrencies("eo_AO", date, &status);
5135 if (index != 1)
5136 {
5137 errcheckln(status, "FAIL: didn't return 1 for eo_AO - %s", u_errorName(status));
5138 }
5139 resLen = ucurr_forLocaleAndDate("eo_AO", date, 1, TMP, 4, &status);
5140 tempStr.setTo(TMP);
5141 resultStr.setTo("AOA");
5142 if (resultStr != tempStr) {
5143 errcheckln(status, "FAIL: didn't return AOA for eo_AO - %s", u_errorName(status));
5144 }
5145
5146 date = (UDate)819936000000.0; // 1996 - 2 currencies
5147 index = ucurr_countCurrencies("eo_AO", date, &status);
5148 if (index != 2)
5149 {
5150 errcheckln(status, "FAIL: didn't return 1 for eo_AO - %s", u_errorName(status));
5151 }
5152 resLen = ucurr_forLocaleAndDate("eo_AO", date, 1, TMP, 4, &status);
5153 tempStr.setTo(TMP);
5154 resultStr.setTo("AOR");
5155 if (resultStr != tempStr) {
5156 errcheckln(status, "FAIL: didn't return AOR for eo_AO - %s", u_errorName(status));
5157 }
5158 resLen = ucurr_forLocaleAndDate("eo_AO", date, 2, TMP, 4, &status);
5159 tempStr.setTo(TMP);
5160 resultStr.setTo("AON");
5161 if (resultStr != tempStr) {
5162 errcheckln(status, "FAIL: didn't return AON for eo_AO - %s", u_errorName(status));
5163 }
5164
5165 date = (UDate)662256000000.0; // 1991 - 2 currencies
5166 index = ucurr_countCurrencies("eo_AO", date, &status);
5167 if (index != 2)
5168 {
5169 errcheckln(status, "FAIL: didn't return 1 for eo_AO - %s", u_errorName(status));
5170 }
5171 resLen = ucurr_forLocaleAndDate("eo_AO", date, 1, TMP, 4, &status);
5172 tempStr.setTo(TMP);
5173 resultStr.setTo("AON");
5174 if (resultStr != tempStr) {
5175 errcheckln(status, "FAIL: didn't return AON for eo_AO - %s", u_errorName(status));
5176 }
5177 resLen = ucurr_forLocaleAndDate("eo_AO", date, 2, TMP, 4, &status);
5178 tempStr.setTo(TMP);
5179 resultStr.setTo("AOK");
5180 if (resultStr != tempStr) {
5181 errcheckln(status, "FAIL: didn't return AOK for eo_AO - %s", u_errorName(status));
5182 }
5183
5184 date = (UDate)315360000000.0; // 1980 - one currency
5185 index = ucurr_countCurrencies("eo_AO", date, &status);
5186 if (index != 1)
5187 {
5188 errcheckln(status, "FAIL: didn't return 1 for eo_AO - %s", u_errorName(status));
5189 }
5190 resLen = ucurr_forLocaleAndDate("eo_AO", date, 1, TMP, 4, &status);
5191 tempStr.setTo(TMP);
5192 resultStr.setTo("AOK");
5193 if (resultStr != tempStr) {
5194 errcheckln(status, "FAIL: didn't return AOK for eo_AO - %s", u_errorName(status));
5195 }
5196
5197 date = (UDate)0.0; // 1970 - no currencies
5198 index = ucurr_countCurrencies("eo_AO", date, &status);
5199 if (index != 0)
5200 {
5201 errcheckln(status, "FAIL: didn't return 1 for eo_AO - %s", u_errorName(status));
5202 }
5203 resLen = ucurr_forLocaleAndDate("eo_AO", date, 1, TMP, 4, &status);
5204 if (resLen != 0) {
5205 errcheckln(status, "FAIL: eo_AO didn't return NULL - %s", u_errorName(status));
5206 }
5207 status = U_ZERO_ERROR;
5208
5209 // Test with currency keyword override
5210 date = (UDate)977616000000.0; // 2001 - two currencies
5211 index = ucurr_countCurrencies("eo_DE@currency=DEM", date, &status);
5212 if (index != 2)
5213 {
5214 errcheckln(status, "FAIL: didn't return 2 for eo_DE@currency=DEM - %s", u_errorName(status));
5215 }
5216 resLen = ucurr_forLocaleAndDate("eo_DE@currency=DEM", date, 1, TMP, 4, &status);
5217 tempStr.setTo(TMP);
5218 resultStr.setTo("EUR");
5219 if (resultStr != tempStr) {
5220 errcheckln(status, "FAIL: didn't return EUR for eo_DE@currency=DEM - %s", u_errorName(status));
5221 }
5222 resLen = ucurr_forLocaleAndDate("eo_DE@currency=DEM", date, 2, TMP, 4, &status);
5223 tempStr.setTo(TMP);
5224 resultStr.setTo("DEM");
5225 if (resultStr != tempStr) {
5226 errcheckln(status, "FAIL: didn't return DEM for eo_DE@currency=DEM - %s", u_errorName(status));
5227 }
5228
5229 // Test Euro Support
5230 status = U_ZERO_ERROR; // reset
5231 date = uprv_getUTCtime();
5232
5233 UChar USD[4];
5234 ucurr_forLocaleAndDate("en_US", date, 1, USD, 4, &status);
5235
5236 UChar YEN[4];
5237 ucurr_forLocaleAndDate("ja_JP", date, 1, YEN, 4, &status);
5238
5239 ucurr_forLocaleAndDate("en_US", date, 1, TMP, 4, &status);
5240 if (u_strcmp(USD, TMP) != 0) {
5241 errcheckln(status, "Fail: en_US didn't return USD - %s", u_errorName(status));
5242 }
5243 ucurr_forLocaleAndDate("en_US_Q", date, 1, TMP, 4, &status);
5244 if (u_strcmp(USD, TMP) != 0) {
5245 errcheckln(status, "Fail: en_US_Q didn't fallback to en_US - %s", u_errorName(status));
5246 }
5247 status = U_ZERO_ERROR; // reset
5248 #endif
5249 }
5250
TestGetVariantWithKeywords(void)5251 void LocaleTest::TestGetVariantWithKeywords(void)
5252 {
5253 Locale l("en_US_VALLEY@foo=value");
5254 const char *variant = l.getVariant();
5255 logln(variant);
5256 test_assert(strcmp("VALLEY", variant) == 0);
5257
5258 UErrorCode status = U_ZERO_ERROR;
5259 char buffer[50];
5260 int32_t len = l.getKeywordValue("foo", buffer, 50, status);
5261 buffer[len] = '\0';
5262 test_assert(strcmp("value", buffer) == 0);
5263 }
5264
TestIsRightToLeft()5265 void LocaleTest::TestIsRightToLeft() {
5266 assertFalse("root LTR", Locale::getRoot().isRightToLeft());
5267 assertFalse("zh LTR", Locale::getChinese().isRightToLeft());
5268 assertTrue("ar RTL", Locale("ar").isRightToLeft());
5269 assertTrue("und-EG RTL", Locale("und-EG").isRightToLeft(), FALSE, TRUE);
5270 assertFalse("fa-Cyrl LTR", Locale("fa-Cyrl").isRightToLeft());
5271 assertTrue("en-Hebr RTL", Locale("en-Hebr").isRightToLeft());
5272 assertTrue("ckb RTL", Locale("ckb").isRightToLeft(), FALSE, TRUE); // Sorani Kurdish
5273 assertFalse("fil LTR", Locale("fil").isRightToLeft());
5274 assertFalse("he-Zyxw LTR", Locale("he-Zyxw").isRightToLeft());
5275 }
5276
TestBug11421()5277 void LocaleTest::TestBug11421() {
5278 Locale::getDefault().getBaseName();
5279 int32_t numLocales;
5280 const Locale *localeList = Locale::getAvailableLocales(numLocales);
5281 for (int localeIndex = 0; localeIndex < numLocales; localeIndex++) {
5282 const Locale &loc = localeList[localeIndex];
5283 if (strncmp(loc.getName(), loc.getBaseName(), strlen(loc.getBaseName()))) {
5284 errln("%s:%d loc.getName=\"%s\"; loc.getBaseName=\"%s\"",
5285 __FILE__, __LINE__, loc.getName(), loc.getBaseName());
5286 break;
5287 }
5288 }
5289 }
5290
5291 // TestBug13277. The failure manifests as valgrind errors.
5292 // See the trac ticket for details.
5293 //
5294
TestBug13277()5295 void LocaleTest::TestBug13277() {
5296 UErrorCode status = U_ZERO_ERROR;
5297 CharString name("en-us-x-foo", -1, status);
5298 while (name.length() < 152) {
5299 name.append("-x-foo", -1, status);
5300 }
5301
5302 while (name.length() < 160) {
5303 name.append('z', status);
5304 Locale loc(name.data(), nullptr, nullptr, nullptr);
5305 }
5306 }
5307
5308 // TestBug13554 Check for read past end of array in getPosixID().
5309 // The bug shows as an Address Sanitizer failure.
5310
TestBug13554()5311 void LocaleTest::TestBug13554() {
5312 UErrorCode status = U_ZERO_ERROR;
5313 const int BUFFER_SIZE = 100;
5314 char posixID[BUFFER_SIZE];
5315
5316 for (uint32_t hostid = 0; hostid < 0x500; ++hostid) {
5317 status = U_ZERO_ERROR;
5318 uprv_convertToPosix(hostid, posixID, BUFFER_SIZE, &status);
5319 }
5320 }
5321
TestBug20410()5322 void LocaleTest::TestBug20410() {
5323 IcuTestErrorCode status(*this, "TestBug20410()");
5324
5325 static const char tag1[] = "art-lojban-x-0";
5326 static const Locale expected1("jbo@x=0");
5327 Locale result1 = Locale::forLanguageTag(tag1, status);
5328 status.errIfFailureAndReset("\"%s\"", tag1);
5329 assertEquals(tag1, expected1.getName(), result1.getName());
5330
5331 static const char tag2[] = "zh-xiang-u-nu-thai-x-0";
5332 static const Locale expected2("hsn@numbers=thai;x=0");
5333 Locale result2 = Locale::forLanguageTag(tag2, status);
5334 status.errIfFailureAndReset("\"%s\"", tag2);
5335 assertEquals(tag2, expected2.getName(), result2.getName());
5336
5337 static const char locid3[] = "art__lojban@x=0";
5338 Locale result3 = Locale::createCanonical(locid3);
5339 static const Locale expected3("jbo@x=0");
5340 assertEquals(locid3, expected3.getName(), result3.getName());
5341
5342 static const char locid4[] = "art-lojban-x-0";
5343 Locale result4 = Locale::createCanonical(locid4);
5344 static const Locale expected4("jbo@x=0");
5345 assertEquals(locid4, expected4.getName(), result4.getName());
5346 }
5347
TestBug20900()5348 void LocaleTest::TestBug20900() {
5349 static const struct {
5350 const char *localeID; /* input */
5351 const char *canonicalID; /* expected canonicalize() result */
5352 } testCases[] = {
5353 { "art-lojban", "jbo" },
5354 { "zh-guoyu", "zh" },
5355 { "zh-hakka", "hak" },
5356 { "zh-xiang", "hsn" },
5357 { "zh-min-nan", "nan" },
5358 { "zh-gan", "gan" },
5359 { "zh-wuu", "wuu" },
5360 { "zh-yue", "yue" },
5361 };
5362
5363 IcuTestErrorCode status(*this, "TestBug20900");
5364 for (int32_t i=0; i < UPRV_LENGTHOF(testCases); i++) {
5365 Locale loc = Locale::createCanonical(testCases[i].localeID);
5366 std::string result = loc.toLanguageTag<std::string>(status);
5367 const char* tag = loc.isBogus() ? "BOGUS" : result.c_str();
5368 status.errIfFailureAndReset("FAIL: createCanonical(%s).toLanguageTag() expected \"%s\"",
5369 testCases[i].localeID, tag);
5370 assertEquals("createCanonical", testCases[i].canonicalID, tag);
5371 }
5372 }
5373
5374 U_DEFINE_LOCAL_OPEN_POINTER(LocalStdioFilePointer, FILE, fclose);
TestLocaleCanonicalizationFromFile()5375 void LocaleTest::TestLocaleCanonicalizationFromFile()
5376 {
5377 IcuTestErrorCode status(*this, "TestLocaleCanonicalizationFromFile");
5378 const char *sourceTestDataPath=getSourceTestData(status);
5379 if(status.errIfFailureAndReset("unable to find the source/test/testdata "
5380 "folder (getSourceTestData())")) {
5381 return;
5382 }
5383 char testPath[400];
5384 char line[256];
5385 strcpy(testPath, sourceTestDataPath);
5386 strcat(testPath, "localeCanonicalization.txt");
5387 LocalStdioFilePointer testFile(fopen(testPath, "r"));
5388 if(testFile.isNull()) {
5389 errln("unable to open %s", testPath);
5390 return;
5391 }
5392 // Format:
5393 // <source locale identifier> ; <expected canonicalized locale identifier>
5394 while (fgets(line, (int)sizeof(line), testFile.getAlias())!=NULL) {
5395 if (line[0] == '#') {
5396 // ignore any lines start with #
5397 continue;
5398 }
5399 char *semi = strchr(line, ';');
5400 if (semi == nullptr) {
5401 // ignore any lines without ;
5402 continue;
5403 }
5404 *semi = '\0'; // null terminiate on the spot of semi
5405 const char* from = u_skipWhitespace((const char*)line);
5406 u_rtrim((char*)from);
5407 const char* to = u_skipWhitespace((const char*)semi + 1);
5408 u_rtrim((char*)to);
5409 std::string expect(to);
5410 // Change the _ to -
5411 std::transform(expect.begin(), expect.end(), expect.begin(),
5412 [](unsigned char c){ return c == '_' ? '-' : c; });
5413
5414 Locale loc = Locale::createCanonical(from);
5415 std::string result = loc.toLanguageTag<std::string>(status);
5416 const char* tag = loc.isBogus() ? "BOGUS" : result.c_str();
5417 status.errIfFailureAndReset(
5418 "FAIL: createCanonical(%s).toLanguageTag() expected \"%s\" locale is %s",
5419 from, tag, loc.getName());
5420 std::string msg("createCanonical(");
5421 msg += from;
5422 msg += ") locale = ";
5423 msg += loc.getName();
5424 assertEquals(msg.c_str(), expect.c_str(), tag);
5425 }
5426 }
5427
TestKnownCanonicalizedListCorrect()5428 void LocaleTest::TestKnownCanonicalizedListCorrect()
5429 {
5430 IcuTestErrorCode status(*this, "TestKnownCanonicalizedListCorrect");
5431 int32_t numOfKnownCanonicalized;
5432 const char* const* knownCanonicalized =
5433 ulocimp_getKnownCanonicalizedLocaleForTest(&numOfKnownCanonicalized);
5434 for (int32_t i = 0; i < numOfKnownCanonicalized; i++) {
5435 std::string msg("Known Canonicalized Locale is not canonicalized: ");
5436 assertTrue((msg + knownCanonicalized[i]).c_str(),
5437 ulocimp_isCanonicalizedLocaleForTest(knownCanonicalized[i]));
5438 }
5439 }
5440
TestConstructorAcceptsBCP47()5441 void LocaleTest::TestConstructorAcceptsBCP47() {
5442 IcuTestErrorCode status(*this, "TestConstructorAcceptsBCP47");
5443
5444 Locale loc1("ar-EG-u-nu-latn");
5445 Locale loc2("ar-EG@numbers=latn");
5446 Locale loc3("ar-EG");
5447 std::string val;
5448
5449 // Check getKeywordValue "numbers"
5450 val = loc1.getKeywordValue<std::string>("numbers", status);
5451 assertEquals("BCP47 syntax has ICU keyword value", "latn", val.c_str());
5452
5453 val = loc2.getKeywordValue<std::string>("numbers", status);
5454 assertEquals("ICU syntax has ICU keyword value", "latn", val.c_str());
5455
5456 val = loc3.getKeywordValue<std::string>("numbers", status);
5457 assertEquals("Default, ICU keyword", "", val.c_str());
5458
5459 // Check getUnicodeKeywordValue "nu"
5460 val = loc1.getUnicodeKeywordValue<std::string>("nu", status);
5461 assertEquals("BCP47 syntax has short unicode keyword value", "latn", val.c_str());
5462
5463 val = loc2.getUnicodeKeywordValue<std::string>("nu", status);
5464 assertEquals("ICU syntax has short unicode keyword value", "latn", val.c_str());
5465
5466 val = loc3.getUnicodeKeywordValue<std::string>("nu", status);
5467 status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR, "Default, short unicode keyword");
5468
5469 // Check getUnicodeKeywordValue "numbers"
5470 val = loc1.getUnicodeKeywordValue<std::string>("numbers", status);
5471 assertEquals("BCP47 syntax has long unicode keyword value", "latn", val.c_str());
5472
5473 val = loc2.getUnicodeKeywordValue<std::string>("numbers", status);
5474 assertEquals("ICU syntax has long unicode keyword value", "latn", val.c_str());
5475
5476 val = loc3.getUnicodeKeywordValue<std::string>("numbers", status);
5477 status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR, "Default, long unicode keyword");
5478 }
5479
TestForLanguageTag()5480 void LocaleTest::TestForLanguageTag() {
5481 IcuTestErrorCode status(*this, "TestForLanguageTag()");
5482
5483 static const char tag_en[] = "en-US";
5484 static const char tag_oed[] = "en-GB-oed";
5485 static const char tag_af[] = "af-t-ar-i0-handwrit-u-ca-coptic-x-foo";
5486 static const char tag_ill[] = "!";
5487 static const char tag_no_nul[] = { 'e', 'n', '-', 'G', 'B' };
5488 static const char tag_ext[] = "en-GB-1-abc-efg-a-xyz";
5489 static const char tag_var[] = "sl-rozaj-biske-1994";
5490
5491 static const Locale loc_en("en_US");
5492 static const Locale loc_oed("en_GB_OXENDICT");
5493 static const Locale loc_af("af@calendar=coptic;t=ar-i0-handwrit;x=foo");
5494 static const Locale loc_null("");
5495 static const Locale loc_gb("en_GB");
5496 static const Locale loc_ext("en_GB@1=abc-efg;a=xyz");
5497 static const Locale loc_var("sl__1994_BISKE_ROZAJ");
5498
5499 Locale result_en = Locale::forLanguageTag(tag_en, status);
5500 status.errIfFailureAndReset("\"%s\"", tag_en);
5501 assertEquals(tag_en, loc_en.getName(), result_en.getName());
5502
5503 Locale result_oed = Locale::forLanguageTag(tag_oed, status);
5504 status.errIfFailureAndReset("\"%s\"", tag_oed);
5505 assertEquals(tag_oed, loc_oed.getName(), result_oed.getName());
5506
5507 Locale result_af = Locale::forLanguageTag(tag_af, status);
5508 status.errIfFailureAndReset("\"%s\"", tag_af);
5509 assertEquals(tag_af, loc_af.getName(), result_af.getName());
5510
5511 Locale result_var = Locale::forLanguageTag(tag_var, status);
5512 status.errIfFailureAndReset("\"%s\"", tag_var);
5513 assertEquals(tag_var, loc_var.getName(), result_var.getName());
5514
5515 Locale result_ill = Locale::forLanguageTag(tag_ill, status);
5516 assertEquals(tag_ill, U_ILLEGAL_ARGUMENT_ERROR, status.reset());
5517 assertTrue(result_ill.getName(), result_ill.isBogus());
5518
5519 Locale result_null = Locale::forLanguageTag(nullptr, status);
5520 status.errIfFailureAndReset("nullptr");
5521 assertEquals("nullptr", loc_null.getName(), result_null.getName());
5522
5523 StringPiece sp_substr(tag_oed, 5); // "en-GB", no NUL.
5524 Locale result_substr = Locale::forLanguageTag(sp_substr, status);
5525 status.errIfFailureAndReset("\"%.*s\"", sp_substr.size(), sp_substr.data());
5526 assertEquals(CharString(sp_substr, status).data(),
5527 loc_gb.getName(), result_substr.getName());
5528
5529 StringPiece sp_no_nul(tag_no_nul, sizeof tag_no_nul); // "en-GB", no NUL.
5530 Locale result_no_nul = Locale::forLanguageTag(sp_no_nul, status);
5531 status.errIfFailureAndReset("\"%.*s\"", sp_no_nul.size(), sp_no_nul.data());
5532 assertEquals(CharString(sp_no_nul, status).data(),
5533 loc_gb.getName(), result_no_nul.getName());
5534
5535 Locale result_ext = Locale::forLanguageTag(tag_ext, status);
5536 status.errIfFailureAndReset("\"%s\"", tag_ext);
5537 assertEquals(tag_ext, loc_ext.getName(), result_ext.getName());
5538 }
5539
TestToLanguageTag()5540 void LocaleTest::TestToLanguageTag() {
5541 IcuTestErrorCode status(*this, "TestToLanguageTag()");
5542
5543 static const Locale loc_c("en_US_POSIX");
5544 static const Locale loc_en("en_US");
5545 static const Locale loc_af("af@calendar=coptic;t=ar-i0-handwrit;x=foo");
5546 static const Locale loc_ext("en@0=abc;a=xyz");
5547 static const Locale loc_empty("");
5548 static const Locale loc_ill("!");
5549 static const Locale loc_variant("sl__ROZAJ_BISKE_1994");
5550
5551 static const char tag_c[] = "en-US-u-va-posix";
5552 static const char tag_en[] = "en-US";
5553 static const char tag_af[] = "af-t-ar-i0-handwrit-u-ca-coptic-x-foo";
5554 static const char tag_ext[] = "en-0-abc-a-xyz";
5555 static const char tag_und[] = "und";
5556 static const char tag_variant[] = "sl-1994-biske-rozaj";
5557
5558 std::string result;
5559 StringByteSink<std::string> sink(&result);
5560 loc_c.toLanguageTag(sink, status);
5561 status.errIfFailureAndReset("\"%s\"", loc_c.getName());
5562 assertEquals(loc_c.getName(), tag_c, result.c_str());
5563
5564 std::string result_c = loc_c.toLanguageTag<std::string>(status);
5565 status.errIfFailureAndReset("\"%s\"", loc_c.getName());
5566 assertEquals(loc_c.getName(), tag_c, result_c.c_str());
5567
5568 std::string result_en = loc_en.toLanguageTag<std::string>(status);
5569 status.errIfFailureAndReset("\"%s\"", loc_en.getName());
5570 assertEquals(loc_en.getName(), tag_en, result_en.c_str());
5571
5572 std::string result_af = loc_af.toLanguageTag<std::string>(status);
5573 status.errIfFailureAndReset("\"%s\"", loc_af.getName());
5574 assertEquals(loc_af.getName(), tag_af, result_af.c_str());
5575
5576 std::string result_ext = loc_ext.toLanguageTag<std::string>(status);
5577 status.errIfFailureAndReset("\"%s\"", loc_ext.getName());
5578 assertEquals(loc_ext.getName(), tag_ext, result_ext.c_str());
5579
5580 std::string result_empty = loc_empty.toLanguageTag<std::string>(status);
5581 status.errIfFailureAndReset("\"%s\"", loc_empty.getName());
5582 assertEquals(loc_empty.getName(), tag_und, result_empty.c_str());
5583
5584 std::string result_ill = loc_ill.toLanguageTag<std::string>(status);
5585 status.errIfFailureAndReset("\"%s\"", loc_ill.getName());
5586 assertEquals(loc_ill.getName(), tag_und, result_ill.c_str());
5587
5588 std::string result_variant = loc_variant.toLanguageTag<std::string>(status);
5589 status.errIfFailureAndReset("\"%s\"", loc_variant.getName());
5590 assertEquals(loc_variant.getName(), tag_variant, result_variant.c_str());
5591
5592 Locale loc_bogus;
5593 loc_bogus.setToBogus();
5594 std::string result_bogus = loc_bogus.toLanguageTag<std::string>(status);
5595 assertEquals("bogus", U_ILLEGAL_ARGUMENT_ERROR, status.reset());
5596 assertTrue(result_bogus.c_str(), result_bogus.empty());
5597 }
5598
5599 /* ICU-20310 */
TestToLanguageTagOmitTrue()5600 void LocaleTest::TestToLanguageTagOmitTrue() {
5601 IcuTestErrorCode status(*this, "TestToLanguageTagOmitTrue()");
5602 assertEquals("en-u-kn should drop true",
5603 "en-u-kn", Locale("en-u-kn-true").toLanguageTag<std::string>(status).c_str());
5604 status.errIfFailureAndReset();
5605 assertEquals("en-u-kn should drop true",
5606 "en-u-kn", Locale("en-u-kn").toLanguageTag<std::string>(status).c_str());
5607 status.errIfFailureAndReset();
5608
5609 assertEquals("de-u-co should drop true",
5610 "de-u-co", Locale("de-u-co").toLanguageTag<std::string>(status).c_str());
5611 status.errIfFailureAndReset();
5612 assertEquals("de-u-co should drop true",
5613 "de-u-co", Locale("de-u-co-yes").toLanguageTag<std::string>(status).c_str());
5614 status.errIfFailureAndReset();
5615 assertEquals("de@collation=yes should drop true",
5616 "de-u-co", Locale("de@collation=yes").toLanguageTag<std::string>(status).c_str());
5617 status.errIfFailureAndReset();
5618
5619 assertEquals("cmn-Hans-CN-t-ca-u-ca-x-t-u should drop true",
5620 "cmn-Hans-CN-t-ca-u-ca-x-t-u",
5621 Locale("cmn-hans-cn-u-ca-t-ca-x-t-u").toLanguageTag<std::string>(status).c_str());
5622 status.errIfFailureAndReset();
5623 }
5624
TestMoveAssign()5625 void LocaleTest::TestMoveAssign() {
5626 // ULOC_FULLNAME_CAPACITY == 157 (uloc.h)
5627 Locale l1("de@collation=phonebook;x="
5628 "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
5629 "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
5630 "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
5631 "aaaaabbbbbzz");
5632
5633 Locale l2;
5634 {
5635 Locale l3(l1);
5636 assertTrue("l1 == l3", l1 == l3);
5637 l2 = std::move(l3);
5638 assertTrue("l1 == l2", l1 == l2);
5639 assertTrue("l2 != l3", l2.getName() != l3.getName());
5640 }
5641
5642 // This should remain true also after l3 has been destructed.
5643 assertTrue("l1 == l2, again", l1 == l2);
5644
5645 Locale l4("de@collation=phonebook");
5646
5647 Locale l5;
5648 {
5649 Locale l6(l4);
5650 assertTrue("l4 == l6", l4 == l6);
5651 l5 = std::move(l6);
5652 assertTrue("l4 == l5", l4 == l5);
5653 assertTrue("l5 != l6", l5.getName() != l6.getName());
5654 }
5655
5656 // This should remain true also after l6 has been destructed.
5657 assertTrue("l4 == l5, again", l4 == l5);
5658
5659 Locale l7("vo_Cyrl_AQ_EURO");
5660
5661 Locale l8;
5662 {
5663 Locale l9(l7);
5664 assertTrue("l7 == l9", l7 == l9);
5665 l8 = std::move(l9);
5666 assertTrue("l7 == l8", l7 == l8);
5667 assertTrue("l8 != l9", l8.getName() != l9.getName());
5668 }
5669
5670 // This should remain true also after l9 has been destructed.
5671 assertTrue("l7 == l8, again", l7 == l8);
5672
5673 assertEquals("language", l7.getLanguage(), l8.getLanguage());
5674 assertEquals("script", l7.getScript(), l8.getScript());
5675 assertEquals("country", l7.getCountry(), l8.getCountry());
5676 assertEquals("variant", l7.getVariant(), l8.getVariant());
5677 assertEquals("bogus", l7.isBogus(), l8.isBogus());
5678 }
5679
TestMoveCtor()5680 void LocaleTest::TestMoveCtor() {
5681 // ULOC_FULLNAME_CAPACITY == 157 (uloc.h)
5682 Locale l1("de@collation=phonebook;x="
5683 "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
5684 "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
5685 "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
5686 "aaaaabbbbbzz");
5687
5688 Locale l3(l1);
5689 assertTrue("l1 == l3", l1 == l3);
5690 Locale l2(std::move(l3));
5691 assertTrue("l1 == l2", l1 == l2);
5692 assertTrue("l2 != l3", l2.getName() != l3.getName());
5693
5694 Locale l4("de@collation=phonebook");
5695
5696 Locale l6(l4);
5697 assertTrue("l4 == l6", l4 == l6);
5698 Locale l5(std::move(l6));
5699 assertTrue("l4 == l5", l4 == l5);
5700 assertTrue("l5 != l6", l5.getName() != l6.getName());
5701
5702 Locale l7("vo_Cyrl_AQ_EURO");
5703
5704 Locale l9(l7);
5705 assertTrue("l7 == l9", l7 == l9);
5706 Locale l8(std::move(l9));
5707 assertTrue("l7 == l8", l7 == l8);
5708 assertTrue("l8 != l9", l8.getName() != l9.getName());
5709
5710 assertEquals("language", l7.getLanguage(), l8.getLanguage());
5711 assertEquals("script", l7.getScript(), l8.getScript());
5712 assertEquals("country", l7.getCountry(), l8.getCountry());
5713 assertEquals("variant", l7.getVariant(), l8.getVariant());
5714 assertEquals("bogus", l7.isBogus(), l8.isBogus());
5715 }
5716
TestBug20407iVariantPreferredValue()5717 void LocaleTest::TestBug20407iVariantPreferredValue() {
5718 IcuTestErrorCode status(*this, "TestBug20407iVariantPreferredValue()");
5719
5720 Locale l = Locale::forLanguageTag("hy-arevela", status);
5721 status.errIfFailureAndReset("hy-arevela fail");
5722 assertTrue("!l.isBogus()", !l.isBogus());
5723
5724 std::string result = l.toLanguageTag<std::string>(status);
5725 assertEquals(l.getName(), "hy", result.c_str());
5726
5727 l = Locale::forLanguageTag("hy-arevmda", status);
5728 status.errIfFailureAndReset("hy-arevmda");
5729 assertTrue("!l.isBogus()", !l.isBogus());
5730
5731 result = l.toLanguageTag<std::string>(status);
5732 assertEquals(l.getName(), "hyw", result.c_str());
5733 }
5734
TestBug13417VeryLongLanguageTag()5735 void LocaleTest::TestBug13417VeryLongLanguageTag() {
5736 IcuTestErrorCode status(*this, "TestBug13417VeryLongLanguageTag()");
5737
5738 static const char tag[] =
5739 "zh-x"
5740 "-foo-bar-baz-foo-bar-baz-foo-bar-baz-foo-bar-baz"
5741 "-foo-bar-baz-foo-bar-baz-foo-bar-baz-foo-bar-baz"
5742 "-foo-bar-baz-foo-bar-baz-foo-bar-baz-foo-bar-baz"
5743 "-foo-bar-baz-fxx"
5744 ;
5745
5746 Locale l = Locale::forLanguageTag(tag, status);
5747 status.errIfFailureAndReset("\"%s\"", tag);
5748 assertTrue("!l.isBogus()", !l.isBogus());
5749
5750 std::string result = l.toLanguageTag<std::string>(status);
5751 status.errIfFailureAndReset("\"%s\"", l.getName());
5752 assertEquals("equals", tag, result.c_str());
5753 }
5754
TestBug11053UnderlineTimeZone()5755 void LocaleTest::TestBug11053UnderlineTimeZone() {
5756 static const char* const tz_in_ext[] = {
5757 "etadd",
5758 "tzdar",
5759 "eheai",
5760 "sttms",
5761 "arirj",
5762 "arrgl",
5763 "aruaq",
5764 "arluq",
5765 "mxpvr",
5766 "brbvb",
5767 "arbue",
5768 "caycb",
5769 "brcgr",
5770 "cayzs",
5771 "crsjo",
5772 "caydq",
5773 "svsal",
5774 "cafne",
5775 "caglb",
5776 "cagoo",
5777 "tcgdt",
5778 "ustel",
5779 "bolpb",
5780 "uslax",
5781 "sxphi",
5782 "mxmex",
5783 "usnyc",
5784 "usxul",
5785 "usndcnt",
5786 "usndnsl",
5787 "ttpos",
5788 "brpvh",
5789 "prsju",
5790 "clpuq",
5791 "caffs",
5792 "cayek",
5793 "brrbr",
5794 "mxstis",
5795 "dosdq",
5796 "brsao",
5797 "gpsbh",
5798 "casjf",
5799 "knbas",
5800 "lccas",
5801 "vistt",
5802 "vcsvd",
5803 "cayyn",
5804 "cathu",
5805 "hkhkg",
5806 "mykul",
5807 "khpnh",
5808 "cvrai",
5809 "gsgrv",
5810 "shshn",
5811 "aubhq",
5812 "auldh",
5813 "imdgs",
5814 "smsai",
5815 "asppg",
5816 "pgpom",
5817 };
5818 static const char* const tzname_with_underline[] = {
5819 "America/Buenos_Aires",
5820 "America/Coral_Harbour",
5821 "America/Los_Angeles",
5822 "America/Mexico_City",
5823 "America/New_York",
5824 "America/Rio_Branco",
5825 "America/Sao_Paulo",
5826 "America/St_Johns",
5827 "America/St_Thomas",
5828 "Australia/Broken_Hill",
5829 "Australia/Lord_Howe",
5830 "Pacific/Pago_Pago",
5831 };
5832 std::string locale_str;
5833 for (int32_t i = 0; i < UPRV_LENGTHOF(tz_in_ext); i++) {
5834 locale_str = "en-u-tz-";
5835 locale_str += tz_in_ext[i];
5836 Locale l(locale_str.c_str());
5837 assertTrue((locale_str + " !l.isBogus()").c_str(), !l.isBogus());
5838 }
5839 for (int32_t i = 0; i < UPRV_LENGTHOF(tzname_with_underline); i++) {
5840 locale_str = "en@timezone=";
5841 locale_str += tzname_with_underline[i];
5842 Locale l(locale_str.c_str());
5843 assertTrue((locale_str + " !l.isBogus()").c_str(), !l.isBogus());
5844 }
5845 locale_str = "en_US@timezone=America/Coral_Harbour";
5846 Locale l2(locale_str.c_str());
5847 assertTrue((locale_str + " !l2.isBogus()").c_str(), !l2.isBogus());
5848 locale_str = "en_Latn@timezone=America/New_York";
5849 Locale l3(locale_str.c_str());
5850 assertTrue((locale_str + " !l3.isBogus()").c_str(), !l3.isBogus());
5851 locale_str = "en_Latn_US@timezone=Australia/Broken_Hill";
5852 Locale l4(locale_str.c_str());
5853 assertTrue((locale_str + " !l4.isBogus()").c_str(), !l4.isBogus());
5854 locale_str = "en-u-tz-ciabj";
5855 Locale l5(locale_str.c_str());
5856 assertTrue((locale_str + " !l5.isBogus()").c_str(), !l5.isBogus());
5857 locale_str = "en-US-u-tz-asppg";
5858 Locale l6(locale_str.c_str());
5859 assertTrue((locale_str + " !l6.isBogus()").c_str(), !l6.isBogus());
5860 locale_str = "fil-Latn-u-tz-cvrai";
5861 Locale l7(locale_str.c_str());
5862 assertTrue((locale_str + " !l7.isBogus()").c_str(), !l7.isBogus());
5863 locale_str = "fil-Latn-PH-u-tz-gsgrv";
5864 Locale l8(locale_str.c_str());
5865 assertTrue((locale_str + " !l8.isBogus()").c_str(), !l8.isBogus());
5866 }
5867
TestUnd()5868 void LocaleTest::TestUnd() {
5869 IcuTestErrorCode status(*this, "TestUnd()");
5870
5871 static const char empty[] = "";
5872 static const char root[] = "root";
5873 static const char und[] = "und";
5874
5875 Locale empty_ctor(empty);
5876 Locale empty_tag = Locale::forLanguageTag(empty, status);
5877 status.errIfFailureAndReset("\"%s\"", empty);
5878
5879 Locale root_ctor(root);
5880 Locale root_tag = Locale::forLanguageTag(root, status);
5881 Locale root_build = LocaleBuilder().setLanguageTag(root).build(status);
5882 status.errIfFailureAndReset("\"%s\"", root);
5883
5884 Locale und_ctor(und);
5885 Locale und_tag = Locale::forLanguageTag(und, status);
5886 Locale und_build = LocaleBuilder().setLanguageTag(und).build(status);
5887 status.errIfFailureAndReset("\"%s\"", und);
5888
5889 assertEquals("getName()", empty, empty_ctor.getName());
5890 assertEquals("getName()", empty, root_ctor.getName());
5891 assertEquals("getName()", empty, und_ctor.getName());
5892
5893 assertEquals("getName()", empty, empty_tag.getName());
5894 assertEquals("getName()", empty, root_tag.getName());
5895 assertEquals("getName()", empty, und_tag.getName());
5896
5897 assertEquals("getName()", empty, root_build.getName());
5898 assertEquals("getName()", empty, und_build.getName());
5899
5900 assertEquals("toLanguageTag()", und, empty_ctor.toLanguageTag<std::string>(status).c_str());
5901 assertEquals("toLanguageTag()", und, root_ctor.toLanguageTag<std::string>(status).c_str());
5902 assertEquals("toLanguageTag()", und, und_ctor.toLanguageTag<std::string>(status).c_str());
5903 status.errIfFailureAndReset();
5904
5905 assertEquals("toLanguageTag()", und, empty_tag.toLanguageTag<std::string>(status).c_str());
5906 assertEquals("toLanguageTag()", und, root_tag.toLanguageTag<std::string>(status).c_str());
5907 assertEquals("toLanguageTag()", und, und_tag.toLanguageTag<std::string>(status).c_str());
5908 status.errIfFailureAndReset();
5909
5910 assertEquals("toLanguageTag()", und, root_build.toLanguageTag<std::string>(status).c_str());
5911 assertEquals("toLanguageTag()", und, und_build.toLanguageTag<std::string>(status).c_str());
5912 status.errIfFailureAndReset();
5913
5914 assertTrue("empty_ctor == empty_tag", empty_ctor == empty_tag);
5915
5916 assertTrue("root_ctor == root_tag", root_ctor == root_tag);
5917 assertTrue("root_ctor == root_build", root_ctor == root_build);
5918 assertTrue("root_tag == root_build", root_tag == root_build);
5919
5920 assertTrue("und_ctor == und_tag", und_ctor == und_tag);
5921 assertTrue("und_ctor == und_build", und_ctor == und_build);
5922 assertTrue("und_tag == und_build", und_tag == und_build);
5923
5924 assertTrue("empty_ctor == root_ctor", empty_ctor == root_ctor);
5925 assertTrue("empty_ctor == und_ctor", empty_ctor == und_ctor);
5926 assertTrue("root_ctor == und_ctor", root_ctor == und_ctor);
5927
5928 assertTrue("empty_tag == root_tag", empty_tag == root_tag);
5929 assertTrue("empty_tag == und_tag", empty_tag == und_tag);
5930 assertTrue("root_tag == und_tag", root_tag == und_tag);
5931
5932 assertTrue("root_build == und_build", root_build == und_build);
5933
5934 static const Locale& displayLocale = Locale::getEnglish();
5935 static const UnicodeString displayName("Unknown language");
5936 UnicodeString tmp;
5937
5938 assertEquals("getDisplayName()", displayName, empty_ctor.getDisplayName(displayLocale, tmp));
5939 assertEquals("getDisplayName()", displayName, root_ctor.getDisplayName(displayLocale, tmp));
5940 assertEquals("getDisplayName()", displayName, und_ctor.getDisplayName(displayLocale, tmp));
5941
5942 assertEquals("getDisplayName()", displayName, empty_tag.getDisplayName(displayLocale, tmp));
5943 assertEquals("getDisplayName()", displayName, root_tag.getDisplayName(displayLocale, tmp));
5944 assertEquals("getDisplayName()", displayName, und_tag.getDisplayName(displayLocale, tmp));
5945
5946 assertEquals("getDisplayName()", displayName, root_build.getDisplayName(displayLocale, tmp));
5947 assertEquals("getDisplayName()", displayName, und_build.getDisplayName(displayLocale, tmp));
5948 }
5949
TestUndScript()5950 void LocaleTest::TestUndScript() {
5951 IcuTestErrorCode status(*this, "TestUndScript()");
5952
5953 static const char id[] = "_Cyrl";
5954 static const char tag[] = "und-Cyrl";
5955 static const char script[] = "Cyrl";
5956
5957 Locale locale_ctor(id);
5958 Locale locale_legacy(tag);
5959 Locale locale_tag = Locale::forLanguageTag(tag, status);
5960 Locale locale_build = LocaleBuilder().setScript(script).build(status);
5961 status.errIfFailureAndReset("\"%s\"", tag);
5962
5963 assertEquals("getName()", id, locale_ctor.getName());
5964 assertEquals("getName()", id, locale_legacy.getName());
5965 assertEquals("getName()", id, locale_tag.getName());
5966 assertEquals("getName()", id, locale_build.getName());
5967
5968 assertEquals("toLanguageTag()", tag, locale_ctor.toLanguageTag<std::string>(status).c_str());
5969 assertEquals("toLanguageTag()", tag, locale_legacy.toLanguageTag<std::string>(status).c_str());
5970 assertEquals("toLanguageTag()", tag, locale_tag.toLanguageTag<std::string>(status).c_str());
5971 assertEquals("toLanguageTag()", tag, locale_build.toLanguageTag<std::string>(status).c_str());
5972 status.errIfFailureAndReset();
5973
5974 static const Locale& displayLocale = Locale::getEnglish();
5975 static const UnicodeString displayName("Unknown language (Cyrillic)");
5976 UnicodeString tmp;
5977
5978 assertEquals("getDisplayName()", displayName, locale_ctor.getDisplayName(displayLocale, tmp));
5979 assertEquals("getDisplayName()", displayName, locale_legacy.getDisplayName(displayLocale, tmp));
5980 assertEquals("getDisplayName()", displayName, locale_tag.getDisplayName(displayLocale, tmp));
5981 assertEquals("getDisplayName()", displayName, locale_build.getDisplayName(displayLocale, tmp));
5982 }
5983
TestUndRegion()5984 void LocaleTest::TestUndRegion() {
5985 IcuTestErrorCode status(*this, "TestUndRegion()");
5986
5987 static const char id[] = "_AQ";
5988 static const char tag[] = "und-AQ";
5989 static const char region[] = "AQ";
5990
5991 Locale locale_ctor(id);
5992 Locale locale_legacy(tag);
5993 Locale locale_tag = Locale::forLanguageTag(tag, status);
5994 Locale locale_build = LocaleBuilder().setRegion(region).build(status);
5995 status.errIfFailureAndReset("\"%s\"", tag);
5996
5997 assertEquals("getName()", id, locale_ctor.getName());
5998 assertEquals("getName()", id, locale_legacy.getName());
5999 assertEquals("getName()", id, locale_tag.getName());
6000 assertEquals("getName()", id, locale_build.getName());
6001
6002 assertEquals("toLanguageTag()", tag, locale_ctor.toLanguageTag<std::string>(status).c_str());
6003 assertEquals("toLanguageTag()", tag, locale_legacy.toLanguageTag<std::string>(status).c_str());
6004 assertEquals("toLanguageTag()", tag, locale_tag.toLanguageTag<std::string>(status).c_str());
6005 assertEquals("toLanguageTag()", tag, locale_build.toLanguageTag<std::string>(status).c_str());
6006 status.errIfFailureAndReset();
6007
6008 static const Locale& displayLocale = Locale::getEnglish();
6009 static const UnicodeString displayName("Unknown language (Antarctica)");
6010 UnicodeString tmp;
6011
6012 assertEquals("getDisplayName()", displayName, locale_ctor.getDisplayName(displayLocale, tmp));
6013 assertEquals("getDisplayName()", displayName, locale_legacy.getDisplayName(displayLocale, tmp));
6014 assertEquals("getDisplayName()", displayName, locale_tag.getDisplayName(displayLocale, tmp));
6015 assertEquals("getDisplayName()", displayName, locale_build.getDisplayName(displayLocale, tmp));
6016 }
6017
TestUndCAPI()6018 void LocaleTest::TestUndCAPI() {
6019 IcuTestErrorCode status(*this, "TestUndCAPI()");
6020
6021 static const char empty[] = "";
6022 static const char root[] = "root";
6023 static const char und[] = "und";
6024
6025 static const char empty_script[] = "_Cyrl";
6026 static const char empty_region[] = "_AQ";
6027
6028 static const char und_script[] = "und_Cyrl";
6029 static const char und_region[] = "und_AQ";
6030
6031 char tmp[ULOC_FULLNAME_CAPACITY];
6032 int32_t reslen;
6033
6034 // uloc_getName()
6035
6036 uprv_memset(tmp, '!', sizeof tmp);
6037 reslen = uloc_getName(empty, tmp, sizeof tmp, status);
6038 status.errIfFailureAndReset("\"%s\"", empty);
6039 assertTrue("reslen >= 0", reslen >= 0);
6040 assertEquals("uloc_getName()", empty, tmp);
6041
6042 uprv_memset(tmp, '!', sizeof tmp);
6043 reslen = uloc_getName(root, tmp, sizeof tmp, status);
6044 status.errIfFailureAndReset("\"%s\"", root);
6045 assertTrue("reslen >= 0", reslen >= 0);
6046 assertEquals("uloc_getName()", empty, tmp);
6047
6048 uprv_memset(tmp, '!', sizeof tmp);
6049 reslen = uloc_getName(und, tmp, sizeof tmp, status);
6050 status.errIfFailureAndReset("\"%s\"", und);
6051 assertTrue("reslen >= 0", reslen >= 0);
6052 assertEquals("uloc_getName()", empty, tmp);
6053
6054 uprv_memset(tmp, '!', sizeof tmp);
6055 reslen = uloc_getName(empty_script, tmp, sizeof tmp, status);
6056 status.errIfFailureAndReset("\"%s\"", empty_script);
6057 assertTrue("reslen >= 0", reslen >= 0);
6058 assertEquals("uloc_getName()", empty_script, tmp);
6059
6060 uprv_memset(tmp, '!', sizeof tmp);
6061 reslen = uloc_getName(empty_region, tmp, sizeof tmp, status);
6062 status.errIfFailureAndReset("\"%s\"", empty_region);
6063 assertTrue("reslen >= 0", reslen >= 0);
6064 assertEquals("uloc_getName()", empty_region, tmp);
6065
6066 uprv_memset(tmp, '!', sizeof tmp);
6067 reslen = uloc_getName(und_script, tmp, sizeof tmp, status);
6068 status.errIfFailureAndReset("\"%s\"", und_script);
6069 assertTrue("reslen >= 0", reslen >= 0);
6070 assertEquals("uloc_getName()", empty_script, tmp);
6071
6072 uprv_memset(tmp, '!', sizeof tmp);
6073 reslen = uloc_getName(und_region, tmp, sizeof tmp, status);
6074 status.errIfFailureAndReset("\"%s\"", und_region);
6075 assertTrue("reslen >= 0", reslen >= 0);
6076 assertEquals("uloc_getName()", empty_region, tmp);
6077
6078 // uloc_getBaseName()
6079
6080 uprv_memset(tmp, '!', sizeof tmp);
6081 reslen = uloc_getBaseName(empty, tmp, sizeof tmp, status);
6082 status.errIfFailureAndReset("\"%s\"", empty);
6083 assertTrue("reslen >= 0", reslen >= 0);
6084 assertEquals("uloc_getBaseName()", empty, tmp);
6085
6086 uprv_memset(tmp, '!', sizeof tmp);
6087 reslen = uloc_getBaseName(root, tmp, sizeof tmp, status);
6088 status.errIfFailureAndReset("\"%s\"", root);
6089 assertTrue("reslen >= 0", reslen >= 0);
6090 assertEquals("uloc_getBaseName()", empty, tmp);
6091
6092 uprv_memset(tmp, '!', sizeof tmp);
6093 reslen = uloc_getBaseName(und, tmp, sizeof tmp, status);
6094 status.errIfFailureAndReset("\"%s\"", und);
6095 assertTrue("reslen >= 0", reslen >= 0);
6096 assertEquals("uloc_getBaseName()", empty, tmp);
6097
6098 uprv_memset(tmp, '!', sizeof tmp);
6099 reslen = uloc_getBaseName(empty_script, tmp, sizeof tmp, status);
6100 status.errIfFailureAndReset("\"%s\"", empty_script);
6101 assertTrue("reslen >= 0", reslen >= 0);
6102 assertEquals("uloc_getBaseName()", empty_script, tmp);
6103
6104 uprv_memset(tmp, '!', sizeof tmp);
6105 reslen = uloc_getBaseName(empty_region, tmp, sizeof tmp, status);
6106 status.errIfFailureAndReset("\"%s\"", empty_region);
6107 assertTrue("reslen >= 0", reslen >= 0);
6108 assertEquals("uloc_getBaseName()", empty_region, tmp);
6109
6110 uprv_memset(tmp, '!', sizeof tmp);
6111 reslen = uloc_getBaseName(und_script, tmp, sizeof tmp, status);
6112 status.errIfFailureAndReset("\"%s\"", und_script);
6113 assertTrue("reslen >= 0", reslen >= 0);
6114 assertEquals("uloc_getBaseName()", empty_script, tmp);
6115
6116 uprv_memset(tmp, '!', sizeof tmp);
6117 reslen = uloc_getBaseName(und_region, tmp, sizeof tmp, status);
6118 status.errIfFailureAndReset("\"%s\"", und_region);
6119 assertTrue("reslen >= 0", reslen >= 0);
6120 assertEquals("uloc_getBaseName()", empty_region, tmp);
6121
6122 // uloc_getParent()
6123
6124 uprv_memset(tmp, '!', sizeof tmp);
6125 reslen = uloc_getParent(empty, tmp, sizeof tmp, status);
6126 status.errIfFailureAndReset("\"%s\"", empty);
6127 assertTrue("reslen >= 0", reslen >= 0);
6128 assertEquals("uloc_getParent()", empty, tmp);
6129
6130 uprv_memset(tmp, '!', sizeof tmp);
6131 reslen = uloc_getParent(root, tmp, sizeof tmp, status);
6132 status.errIfFailureAndReset("\"%s\"", root);
6133 assertTrue("reslen >= 0", reslen >= 0);
6134 assertEquals("uloc_getParent()", empty, tmp);
6135
6136 uprv_memset(tmp, '!', sizeof tmp);
6137 reslen = uloc_getParent(und, tmp, sizeof tmp, status);
6138 status.errIfFailureAndReset("\"%s\"", und);
6139 assertTrue("reslen >= 0", reslen >= 0);
6140 assertEquals("uloc_getParent()", empty, tmp);
6141
6142 uprv_memset(tmp, '!', sizeof tmp);
6143 reslen = uloc_getParent(empty_script, tmp, sizeof tmp, status);
6144 status.errIfFailureAndReset("\"%s\"", empty_script);
6145 assertTrue("reslen >= 0", reslen >= 0);
6146 assertEquals("uloc_getParent()", empty, tmp);
6147
6148 uprv_memset(tmp, '!', sizeof tmp);
6149 reslen = uloc_getParent(empty_region, tmp, sizeof tmp, status);
6150 status.errIfFailureAndReset("\"%s\"", empty_region);
6151 assertTrue("reslen >= 0", reslen >= 0);
6152 assertEquals("uloc_getParent()", empty, tmp);
6153
6154 uprv_memset(tmp, '!', sizeof tmp);
6155 reslen = uloc_getParent(und_script, tmp, sizeof tmp, status);
6156 status.errIfFailureAndReset("\"%s\"", und_script);
6157 assertTrue("reslen >= 0", reslen >= 0);
6158 assertEquals("uloc_getParent()", empty, tmp);
6159
6160 uprv_memset(tmp, '!', sizeof tmp);
6161 reslen = uloc_getParent(und_region, tmp, sizeof tmp, status);
6162 status.errIfFailureAndReset("\"%s\"", und_region);
6163 assertTrue("reslen >= 0", reslen >= 0);
6164 assertEquals("uloc_getParent()", empty, tmp);
6165
6166 // uloc_getLanguage()
6167
6168 uprv_memset(tmp, '!', sizeof tmp);
6169 reslen = uloc_getLanguage(empty, tmp, sizeof tmp, status);
6170 status.errIfFailureAndReset("\"%s\"", empty);
6171 assertTrue("reslen >= 0", reslen >= 0);
6172 assertEquals("uloc_getLanguage()", empty, tmp);
6173
6174 uprv_memset(tmp, '!', sizeof tmp);
6175 reslen = uloc_getLanguage(root, tmp, sizeof tmp, status);
6176 status.errIfFailureAndReset("\"%s\"", root);
6177 assertTrue("reslen >= 0", reslen >= 0);
6178 assertEquals("uloc_getLanguage()", empty, tmp);
6179
6180 uprv_memset(tmp, '!', sizeof tmp);
6181 reslen = uloc_getLanguage(und, tmp, sizeof tmp, status);
6182 status.errIfFailureAndReset("\"%s\"", und);
6183 assertTrue("reslen >= 0", reslen >= 0);
6184 assertEquals("uloc_getLanguage()", empty, tmp);
6185
6186 uprv_memset(tmp, '!', sizeof tmp);
6187 reslen = uloc_getLanguage(empty_script, tmp, sizeof tmp, status);
6188 status.errIfFailureAndReset("\"%s\"", empty_script);
6189 assertTrue("reslen >= 0", reslen >= 0);
6190 assertEquals("uloc_getLanguage()", empty, tmp);
6191
6192 uprv_memset(tmp, '!', sizeof tmp);
6193 reslen = uloc_getLanguage(empty_region, tmp, sizeof tmp, status);
6194 status.errIfFailureAndReset("\"%s\"", empty_region);
6195 assertTrue("reslen >= 0", reslen >= 0);
6196 assertEquals("uloc_getLanguage()", empty, tmp);
6197
6198 uprv_memset(tmp, '!', sizeof tmp);
6199 reslen = uloc_getLanguage(und_script, tmp, sizeof tmp, status);
6200 status.errIfFailureAndReset("\"%s\"", und_script);
6201 assertTrue("reslen >= 0", reslen >= 0);
6202 assertEquals("uloc_getLanguage()", empty, tmp);
6203
6204 uprv_memset(tmp, '!', sizeof tmp);
6205 reslen = uloc_getLanguage(und_region, tmp, sizeof tmp, status);
6206 status.errIfFailureAndReset("\"%s\"", und_region);
6207 assertTrue("reslen >= 0", reslen >= 0);
6208 assertEquals("uloc_getLanguage()", empty, tmp);
6209 }
6210
6211 #define ARRAY_RANGE(array) (array), ((array) + UPRV_LENGTHOF(array))
6212
TestRangeIterator()6213 void LocaleTest::TestRangeIterator() {
6214 IcuTestErrorCode status(*this, "TestRangeIterator");
6215 Locale locales[] = { "fr", "en_GB", "en" };
6216 Locale::RangeIterator<Locale *> iter(ARRAY_RANGE(locales));
6217
6218 assertTrue("0.hasNext()", iter.hasNext());
6219 const Locale &l0 = iter.next();
6220 assertEquals("0.next()", "fr", l0.getName());
6221 assertTrue("&0.next()", &l0 == &locales[0]);
6222
6223 assertTrue("1.hasNext()", iter.hasNext());
6224 const Locale &l1 = iter.next();
6225 assertEquals("1.next()", "en_GB", l1.getName());
6226 assertTrue("&1.next()", &l1 == &locales[1]);
6227
6228 assertTrue("2.hasNext()", iter.hasNext());
6229 const Locale &l2 = iter.next();
6230 assertEquals("2.next()", "en", l2.getName());
6231 assertTrue("&2.next()", &l2 == &locales[2]);
6232
6233 assertFalse("3.hasNext()", iter.hasNext());
6234 }
6235
TestPointerConvertingIterator()6236 void LocaleTest::TestPointerConvertingIterator() {
6237 IcuTestErrorCode status(*this, "TestPointerConvertingIterator");
6238 Locale locales[] = { "fr", "en_GB", "en" };
6239 Locale *pointers[] = { locales, locales + 1, locales + 2 };
6240 // Lambda with explicit reference return type to prevent copy-constructing a temporary
6241 // which would be destructed right away.
6242 Locale::ConvertingIterator<Locale **, std::function<const Locale &(const Locale *)>> iter(
6243 ARRAY_RANGE(pointers), [](const Locale *p) -> const Locale & { return *p; });
6244
6245 assertTrue("0.hasNext()", iter.hasNext());
6246 const Locale &l0 = iter.next();
6247 assertEquals("0.next()", "fr", l0.getName());
6248 assertTrue("&0.next()", &l0 == pointers[0]);
6249
6250 assertTrue("1.hasNext()", iter.hasNext());
6251 const Locale &l1 = iter.next();
6252 assertEquals("1.next()", "en_GB", l1.getName());
6253 assertTrue("&1.next()", &l1 == pointers[1]);
6254
6255 assertTrue("2.hasNext()", iter.hasNext());
6256 const Locale &l2 = iter.next();
6257 assertEquals("2.next()", "en", l2.getName());
6258 assertTrue("&2.next()", &l2 == pointers[2]);
6259
6260 assertFalse("3.hasNext()", iter.hasNext());
6261 }
6262
6263 namespace {
6264
6265 class LocaleFromTag {
6266 public:
LocaleFromTag()6267 LocaleFromTag() : locale(Locale::getRoot()) {}
operator ()(const char * tag)6268 const Locale &operator()(const char *tag) { return locale = Locale(tag); }
6269
6270 private:
6271 // Store the locale in the converter, rather than return a reference to a temporary,
6272 // or a value which could go out of scope with the caller's reference to it.
6273 Locale locale;
6274 };
6275
6276 } // namespace
6277
TestTagConvertingIterator()6278 void LocaleTest::TestTagConvertingIterator() {
6279 IcuTestErrorCode status(*this, "TestTagConvertingIterator");
6280 const char *tags[] = { "fr", "en_GB", "en" };
6281 LocaleFromTag converter;
6282 Locale::ConvertingIterator<const char **, LocaleFromTag> iter(ARRAY_RANGE(tags), converter);
6283
6284 assertTrue("0.hasNext()", iter.hasNext());
6285 const Locale &l0 = iter.next();
6286 assertEquals("0.next()", "fr", l0.getName());
6287
6288 assertTrue("1.hasNext()", iter.hasNext());
6289 const Locale &l1 = iter.next();
6290 assertEquals("1.next()", "en_GB", l1.getName());
6291
6292 assertTrue("2.hasNext()", iter.hasNext());
6293 const Locale &l2 = iter.next();
6294 assertEquals("2.next()", "en", l2.getName());
6295
6296 assertFalse("3.hasNext()", iter.hasNext());
6297 }
6298
TestCapturingTagConvertingIterator()6299 void LocaleTest::TestCapturingTagConvertingIterator() {
6300 IcuTestErrorCode status(*this, "TestCapturingTagConvertingIterator");
6301 const char *tags[] = { "fr", "en_GB", "en" };
6302 // Store the converted locale in a locale variable,
6303 // rather than return a reference to a temporary,
6304 // or a value which could go out of scope with the caller's reference to it.
6305 Locale locale;
6306 // Lambda with explicit reference return type to prevent copy-constructing a temporary
6307 // which would be destructed right away.
6308 Locale::ConvertingIterator<const char **, std::function<const Locale &(const char *)>> iter(
6309 ARRAY_RANGE(tags), [&](const char *tag) -> const Locale & { return locale = Locale(tag); });
6310
6311 assertTrue("0.hasNext()", iter.hasNext());
6312 const Locale &l0 = iter.next();
6313 assertEquals("0.next()", "fr", l0.getName());
6314
6315 assertTrue("1.hasNext()", iter.hasNext());
6316 const Locale &l1 = iter.next();
6317 assertEquals("1.next()", "en_GB", l1.getName());
6318
6319 assertTrue("2.hasNext()", iter.hasNext());
6320 const Locale &l2 = iter.next();
6321 assertEquals("2.next()", "en", l2.getName());
6322
6323 assertFalse("3.hasNext()", iter.hasNext());
6324 }
6325
TestSetUnicodeKeywordValueInLongLocale()6326 void LocaleTest::TestSetUnicodeKeywordValueInLongLocale() {
6327 IcuTestErrorCode status(*this, "TestSetUnicodeKeywordValueInLongLocale");
6328 const char* value = "efghijkl";
6329 icu::Locale l("de");
6330 char keyword[3];
6331 CharString expected("de-u", status);
6332 keyword[2] = '\0';
6333 for (char i = 'a'; i < 's'; i++) {
6334 keyword[0] = keyword[1] = i;
6335 expected.append("-", status);
6336 expected.append(keyword, status);
6337 expected.append("-", status);
6338 expected.append(value, status);
6339 l.setUnicodeKeywordValue(keyword, value, status);
6340 if (status.errIfFailureAndReset(
6341 "setUnicodeKeywordValue(\"%s\", \"%s\") fail while locale is \"%s\"",
6342 keyword, value, l.getName())) {
6343 return;
6344 }
6345 std::string tag = l.toLanguageTag<std::string>(status);
6346 if (status.errIfFailureAndReset(
6347 "toLanguageTag fail on \"%s\"", l.getName())) {
6348 return;
6349 }
6350 if (tag != expected.data()) {
6351 errln("Expected to get \"%s\" bug got \"%s\"", tag.c_str(),
6352 expected.data());
6353 return;
6354 }
6355 }
6356 }
6357
TestSetUnicodeKeywordValueNullInLongLocale()6358 void LocaleTest::TestSetUnicodeKeywordValueNullInLongLocale() {
6359 IcuTestErrorCode status(*this, "TestSetUnicodeKeywordValueNullInLongLocale");
6360 const char *exts[] = {"cf", "cu", "em", "kk", "kr", "ks", "kv", "lb", "lw",
6361 "ms", "nu", "rg", "sd", "ss", "tz"};
6362 for (int32_t i = 0; i < UPRV_LENGTHOF(exts); i++) {
6363 CharString tag("de-u", status);
6364 for (int32_t j = 0; j <= i; j++) {
6365 tag.append("-", status).append(exts[j], status);
6366 }
6367 if (status.errIfFailureAndReset(
6368 "Cannot create tag \"%s\"", tag.data())) {
6369 continue;
6370 }
6371 Locale l = Locale::forLanguageTag(tag.data(), status);
6372 if (status.errIfFailureAndReset(
6373 "Locale::forLanguageTag(\"%s\") failed", tag.data())) {
6374 continue;
6375 }
6376 for (int32_t j = 0; j <= i; j++) {
6377 l.setUnicodeKeywordValue(exts[j], nullptr, status);
6378 if (status.errIfFailureAndReset(
6379 "Locale(\"%s\").setUnicodeKeywordValue(\"%s\", nullptr) failed",
6380 tag.data(), exts[j])) {
6381 continue;
6382 }
6383 }
6384 if (strcmp("de", l.getName()) != 0) {
6385 errln("setUnicodeKeywordValue should remove all extensions from "
6386 "\"%s\" and only have \"de\", but is \"%s\" instead.",
6387 tag.data(), l.getName());
6388 }
6389 }
6390 }
6391
TestLeak21419()6392 void LocaleTest::TestLeak21419() {
6393 IcuTestErrorCode status(*this, "TestLeak21419");
6394 Locale l = Locale("s-yU");
6395 l.canonicalize(status);
6396 status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR);
6397 }
6398