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 != 594)
922 errln("Expected getISOLanguages() to return 594 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 != 253){
953 errln("Expected getISOCountries to return 253 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 "no",
2057 "no_Latn_NO",
2058 "no"
2059 }, {
2060 "nr",
2061 "nr_Latn_ZA",
2062 "nr"
2063 }, {
2064 "nso",
2065 "nso_Latn_ZA",
2066 "nso"
2067 }, {
2068 "om",
2069 "om_Latn_ET",
2070 "om"
2071 }, {
2072 "or",
2073 "or_Orya_IN",
2074 "or"
2075 }, {
2076 "pa",
2077 "pa_Guru_IN",
2078 "pa"
2079 }, {
2080 "pa_Arab",
2081 "pa_Arab_PK",
2082 "pa_PK"
2083 }, {
2084 "pa_PK",
2085 "pa_Arab_PK",
2086 "pa_PK"
2087 }, {
2088 "pap",
2089 "pap_Latn_AW",
2090 "pap"
2091 }, {
2092 "pau",
2093 "pau_Latn_PW",
2094 "pau"
2095 }, {
2096 "pl",
2097 "pl_Latn_PL",
2098 "pl"
2099 }, {
2100 "ps",
2101 "ps_Arab_AF",
2102 "ps"
2103 }, {
2104 "pt",
2105 "pt_Latn_BR",
2106 "pt"
2107 }, {
2108 "rn",
2109 "rn_Latn_BI",
2110 "rn"
2111 }, {
2112 "ro",
2113 "ro_Latn_RO",
2114 "ro"
2115 }, {
2116 "ru",
2117 "ru_Cyrl_RU",
2118 "ru"
2119 }, {
2120 "rw",
2121 "rw_Latn_RW",
2122 "rw"
2123 }, {
2124 "sa",
2125 "sa_Deva_IN",
2126 "sa"
2127 }, {
2128 "se",
2129 "se_Latn_NO",
2130 "se"
2131 }, {
2132 "sg",
2133 "sg_Latn_CF",
2134 "sg"
2135 }, {
2136 "si",
2137 "si_Sinh_LK",
2138 "si"
2139 }, {
2140 "sid",
2141 "sid_Latn_ET",
2142 "sid"
2143 }, {
2144 "sk",
2145 "sk_Latn_SK",
2146 "sk"
2147 }, {
2148 "sl",
2149 "sl_Latn_SI",
2150 "sl"
2151 }, {
2152 "sm",
2153 "sm_Latn_WS",
2154 "sm"
2155 }, {
2156 "so",
2157 "so_Latn_SO",
2158 "so"
2159 }, {
2160 "sq",
2161 "sq_Latn_AL",
2162 "sq"
2163 }, {
2164 "sr",
2165 "sr_Cyrl_RS",
2166 "sr"
2167 }, {
2168 "ss",
2169 "ss_Latn_ZA",
2170 "ss"
2171 }, {
2172 "st",
2173 "st_Latn_ZA",
2174 "st"
2175 }, {
2176 "sv",
2177 "sv_Latn_SE",
2178 "sv"
2179 }, {
2180 "sw",
2181 "sw_Latn_TZ",
2182 "sw"
2183 }, {
2184 "ta",
2185 "ta_Taml_IN",
2186 "ta"
2187 }, {
2188 "te",
2189 "te_Telu_IN",
2190 "te"
2191 }, {
2192 "tet",
2193 "tet_Latn_TL",
2194 "tet"
2195 }, {
2196 "tg",
2197 "tg_Cyrl_TJ",
2198 "tg"
2199 }, {
2200 "th",
2201 "th_Thai_TH",
2202 "th"
2203 }, {
2204 "ti",
2205 "ti_Ethi_ET",
2206 "ti"
2207 }, {
2208 "tig",
2209 "tig_Ethi_ER",
2210 "tig"
2211 }, {
2212 "tk",
2213 "tk_Latn_TM",
2214 "tk"
2215 }, {
2216 "tkl",
2217 "tkl_Latn_TK",
2218 "tkl"
2219 }, {
2220 "tn",
2221 "tn_Latn_ZA",
2222 "tn"
2223 }, {
2224 "to",
2225 "to_Latn_TO",
2226 "to"
2227 }, {
2228 "tpi",
2229 "tpi_Latn_PG",
2230 "tpi"
2231 }, {
2232 "tr",
2233 "tr_Latn_TR",
2234 "tr"
2235 }, {
2236 "ts",
2237 "ts_Latn_ZA",
2238 "ts"
2239 }, {
2240 "tt",
2241 "tt_Cyrl_RU",
2242 "tt"
2243 }, {
2244 "tvl",
2245 "tvl_Latn_TV",
2246 "tvl"
2247 }, {
2248 "ty",
2249 "ty_Latn_PF",
2250 "ty"
2251 }, {
2252 "uk",
2253 "uk_Cyrl_UA",
2254 "uk"
2255 }, {
2256 "und",
2257 "en_Latn_US",
2258 "en"
2259 }, {
2260 "und_AD",
2261 "ca_Latn_AD",
2262 "ca_AD"
2263 }, {
2264 "und_AE",
2265 "ar_Arab_AE",
2266 "ar_AE"
2267 }, {
2268 "und_AF",
2269 "fa_Arab_AF",
2270 "fa_AF"
2271 }, {
2272 "und_AL",
2273 "sq_Latn_AL",
2274 "sq"
2275 }, {
2276 "und_AM",
2277 "hy_Armn_AM",
2278 "hy"
2279 }, {
2280 "und_AO",
2281 "pt_Latn_AO",
2282 "pt_AO"
2283 }, {
2284 "und_AR",
2285 "es_Latn_AR",
2286 "es_AR"
2287 }, {
2288 "und_AS",
2289 "sm_Latn_AS",
2290 "sm_AS"
2291 }, {
2292 "und_AT",
2293 "de_Latn_AT",
2294 "de_AT"
2295 }, {
2296 "und_AW",
2297 "nl_Latn_AW",
2298 "nl_AW"
2299 }, {
2300 "und_AX",
2301 "sv_Latn_AX",
2302 "sv_AX"
2303 }, {
2304 "und_AZ",
2305 "az_Latn_AZ",
2306 "az"
2307 }, {
2308 "und_Arab",
2309 "ar_Arab_EG",
2310 "ar"
2311 }, {
2312 "und_Arab_IN",
2313 "ur_Arab_IN",
2314 "ur_IN"
2315 }, {
2316 "und_Arab_PK",
2317 "ur_Arab_PK",
2318 "ur"
2319 }, {
2320 "und_Arab_SN",
2321 "ar_Arab_SN",
2322 "ar_SN"
2323 }, {
2324 "und_Armn",
2325 "hy_Armn_AM",
2326 "hy"
2327 }, {
2328 "und_BA",
2329 "bs_Latn_BA",
2330 "bs"
2331 }, {
2332 "und_BD",
2333 "bn_Beng_BD",
2334 "bn"
2335 }, {
2336 "und_BE",
2337 "nl_Latn_BE",
2338 "nl_BE"
2339 }, {
2340 "und_BF",
2341 "fr_Latn_BF",
2342 "fr_BF"
2343 }, {
2344 "und_BG",
2345 "bg_Cyrl_BG",
2346 "bg"
2347 }, {
2348 "und_BH",
2349 "ar_Arab_BH",
2350 "ar_BH"
2351 }, {
2352 "und_BI",
2353 "rn_Latn_BI",
2354 "rn"
2355 }, {
2356 "und_BJ",
2357 "fr_Latn_BJ",
2358 "fr_BJ"
2359 }, {
2360 "und_BN",
2361 "ms_Latn_BN",
2362 "ms_BN"
2363 }, {
2364 "und_BO",
2365 "es_Latn_BO",
2366 "es_BO"
2367 }, {
2368 "und_BR",
2369 "pt_Latn_BR",
2370 "pt"
2371 }, {
2372 "und_BT",
2373 "dz_Tibt_BT",
2374 "dz"
2375 }, {
2376 "und_BY",
2377 "be_Cyrl_BY",
2378 "be"
2379 }, {
2380 "und_Beng",
2381 "bn_Beng_BD",
2382 "bn"
2383 }, {
2384 "und_Beng_IN",
2385 "bn_Beng_IN",
2386 "bn_IN"
2387 }, {
2388 "und_CD",
2389 "sw_Latn_CD",
2390 "sw_CD"
2391 }, {
2392 "und_CF",
2393 "fr_Latn_CF",
2394 "fr_CF"
2395 }, {
2396 "und_CG",
2397 "fr_Latn_CG",
2398 "fr_CG"
2399 }, {
2400 "und_CH",
2401 "de_Latn_CH",
2402 "de_CH"
2403 }, {
2404 "und_CI",
2405 "fr_Latn_CI",
2406 "fr_CI"
2407 }, {
2408 "und_CL",
2409 "es_Latn_CL",
2410 "es_CL"
2411 }, {
2412 "und_CM",
2413 "fr_Latn_CM",
2414 "fr_CM"
2415 }, {
2416 "und_CN",
2417 "zh_Hans_CN",
2418 "zh"
2419 }, {
2420 "und_CO",
2421 "es_Latn_CO",
2422 "es_CO"
2423 }, {
2424 "und_CR",
2425 "es_Latn_CR",
2426 "es_CR"
2427 }, {
2428 "und_CU",
2429 "es_Latn_CU",
2430 "es_CU"
2431 }, {
2432 "und_CV",
2433 "pt_Latn_CV",
2434 "pt_CV"
2435 }, {
2436 "und_CY",
2437 "el_Grek_CY",
2438 "el_CY"
2439 }, {
2440 "und_CZ",
2441 "cs_Latn_CZ",
2442 "cs"
2443 }, {
2444 "und_Cyrl",
2445 "ru_Cyrl_RU",
2446 "ru"
2447 }, {
2448 "und_Cyrl_KZ",
2449 "ru_Cyrl_KZ",
2450 "ru_KZ"
2451 }, {
2452 "und_DE",
2453 "de_Latn_DE",
2454 "de"
2455 }, {
2456 "und_DJ",
2457 "aa_Latn_DJ",
2458 "aa_DJ"
2459 }, {
2460 "und_DK",
2461 "da_Latn_DK",
2462 "da"
2463 }, {
2464 "und_DO",
2465 "es_Latn_DO",
2466 "es_DO"
2467 }, {
2468 "und_DZ",
2469 "ar_Arab_DZ",
2470 "ar_DZ"
2471 }, {
2472 "und_Deva",
2473 "hi_Deva_IN",
2474 "hi"
2475 }, {
2476 "und_EC",
2477 "es_Latn_EC",
2478 "es_EC"
2479 }, {
2480 "und_EE",
2481 "et_Latn_EE",
2482 "et"
2483 }, {
2484 "und_EG",
2485 "ar_Arab_EG",
2486 "ar"
2487 }, {
2488 "und_EH",
2489 "ar_Arab_EH",
2490 "ar_EH"
2491 }, {
2492 "und_ER",
2493 "ti_Ethi_ER",
2494 "ti_ER"
2495 }, {
2496 "und_ES",
2497 "es_Latn_ES",
2498 "es"
2499 }, {
2500 "und_ET",
2501 "am_Ethi_ET",
2502 "am"
2503 }, {
2504 "und_Ethi",
2505 "am_Ethi_ET",
2506 "am"
2507 }, {
2508 "und_Ethi_ER",
2509 "am_Ethi_ER",
2510 "am_ER"
2511 }, {
2512 "und_FI",
2513 "fi_Latn_FI",
2514 "fi"
2515 }, {
2516 "und_FM",
2517 "en_Latn_FM",
2518 "en_FM"
2519 }, {
2520 "und_FO",
2521 "fo_Latn_FO",
2522 "fo"
2523 }, {
2524 "und_FR",
2525 "fr_Latn_FR",
2526 "fr"
2527 }, {
2528 "und_GA",
2529 "fr_Latn_GA",
2530 "fr_GA"
2531 }, {
2532 "und_GE",
2533 "ka_Geor_GE",
2534 "ka"
2535 }, {
2536 "und_GF",
2537 "fr_Latn_GF",
2538 "fr_GF"
2539 }, {
2540 "und_GL",
2541 "kl_Latn_GL",
2542 "kl"
2543 }, {
2544 "und_GN",
2545 "fr_Latn_GN",
2546 "fr_GN"
2547 }, {
2548 "und_GP",
2549 "fr_Latn_GP",
2550 "fr_GP"
2551 }, {
2552 "und_GQ",
2553 "es_Latn_GQ",
2554 "es_GQ"
2555 }, {
2556 "und_GR",
2557 "el_Grek_GR",
2558 "el"
2559 }, {
2560 "und_GT",
2561 "es_Latn_GT",
2562 "es_GT"
2563 }, {
2564 "und_GU",
2565 "en_Latn_GU",
2566 "en_GU"
2567 }, {
2568 "und_GW",
2569 "pt_Latn_GW",
2570 "pt_GW"
2571 }, {
2572 "und_Geor",
2573 "ka_Geor_GE",
2574 "ka"
2575 }, {
2576 "und_Grek",
2577 "el_Grek_GR",
2578 "el"
2579 }, {
2580 "und_Gujr",
2581 "gu_Gujr_IN",
2582 "gu"
2583 }, {
2584 "und_Guru",
2585 "pa_Guru_IN",
2586 "pa"
2587 }, {
2588 "und_HK",
2589 "zh_Hant_HK",
2590 "zh_HK"
2591 }, {
2592 "und_HN",
2593 "es_Latn_HN",
2594 "es_HN"
2595 }, {
2596 "und_HR",
2597 "hr_Latn_HR",
2598 "hr"
2599 }, {
2600 "und_HT",
2601 "ht_Latn_HT",
2602 "ht"
2603 }, {
2604 "und_HU",
2605 "hu_Latn_HU",
2606 "hu"
2607 }, {
2608 "und_Hani",
2609 "zh_Hani_CN",
2610 "zh_Hani"
2611 }, {
2612 "und_Hans",
2613 "zh_Hans_CN",
2614 "zh"
2615 }, {
2616 "und_Hant",
2617 "zh_Hant_TW",
2618 "zh_TW"
2619 }, {
2620 "und_Hebr",
2621 "he_Hebr_IL",
2622 "he"
2623 }, {
2624 "und_ID",
2625 "id_Latn_ID",
2626 "id"
2627 }, {
2628 "und_IL",
2629 "he_Hebr_IL",
2630 "he"
2631 }, {
2632 "und_IN",
2633 "hi_Deva_IN",
2634 "hi"
2635 }, {
2636 "und_IQ",
2637 "ar_Arab_IQ",
2638 "ar_IQ"
2639 }, {
2640 "und_IR",
2641 "fa_Arab_IR",
2642 "fa"
2643 }, {
2644 "und_IS",
2645 "is_Latn_IS",
2646 "is"
2647 }, {
2648 "und_IT",
2649 "it_Latn_IT",
2650 "it"
2651 }, {
2652 "und_JO",
2653 "ar_Arab_JO",
2654 "ar_JO"
2655 }, {
2656 "und_JP",
2657 "ja_Jpan_JP",
2658 "ja"
2659 }, {
2660 "und_Jpan",
2661 "ja_Jpan_JP",
2662 "ja"
2663 }, {
2664 "und_KG",
2665 "ky_Cyrl_KG",
2666 "ky"
2667 }, {
2668 "und_KH",
2669 "km_Khmr_KH",
2670 "km"
2671 }, {
2672 "und_KM",
2673 "ar_Arab_KM",
2674 "ar_KM"
2675 }, {
2676 "und_KP",
2677 "ko_Kore_KP",
2678 "ko_KP"
2679 }, {
2680 "und_KR",
2681 "ko_Kore_KR",
2682 "ko"
2683 }, {
2684 "und_KW",
2685 "ar_Arab_KW",
2686 "ar_KW"
2687 }, {
2688 "und_KZ",
2689 "ru_Cyrl_KZ",
2690 "ru_KZ"
2691 }, {
2692 "und_Khmr",
2693 "km_Khmr_KH",
2694 "km"
2695 }, {
2696 "und_Knda",
2697 "kn_Knda_IN",
2698 "kn"
2699 }, {
2700 "und_Kore",
2701 "ko_Kore_KR",
2702 "ko"
2703 }, {
2704 "und_LA",
2705 "lo_Laoo_LA",
2706 "lo"
2707 }, {
2708 "und_LB",
2709 "ar_Arab_LB",
2710 "ar_LB"
2711 }, {
2712 "und_LI",
2713 "de_Latn_LI",
2714 "de_LI"
2715 }, {
2716 "und_LK",
2717 "si_Sinh_LK",
2718 "si"
2719 }, {
2720 "und_LS",
2721 "st_Latn_LS",
2722 "st_LS"
2723 }, {
2724 "und_LT",
2725 "lt_Latn_LT",
2726 "lt"
2727 }, {
2728 "und_LU",
2729 "fr_Latn_LU",
2730 "fr_LU"
2731 }, {
2732 "und_LV",
2733 "lv_Latn_LV",
2734 "lv"
2735 }, {
2736 "und_LY",
2737 "ar_Arab_LY",
2738 "ar_LY"
2739 }, {
2740 "und_Laoo",
2741 "lo_Laoo_LA",
2742 "lo"
2743 }, {
2744 "und_Latn_ES",
2745 "es_Latn_ES",
2746 "es"
2747 }, {
2748 "und_Latn_ET",
2749 "en_Latn_ET",
2750 "en_ET"
2751 }, {
2752 "und_Latn_GB",
2753 "en_Latn_GB",
2754 "en_GB"
2755 }, {
2756 "und_Latn_GH",
2757 "ak_Latn_GH",
2758 "ak"
2759 }, {
2760 "und_Latn_ID",
2761 "id_Latn_ID",
2762 "id"
2763 }, {
2764 "und_Latn_IT",
2765 "it_Latn_IT",
2766 "it"
2767 }, {
2768 "und_Latn_NG",
2769 "en_Latn_NG",
2770 "en_NG"
2771 }, {
2772 "und_Latn_TR",
2773 "tr_Latn_TR",
2774 "tr"
2775 }, {
2776 "und_Latn_ZA",
2777 "en_Latn_ZA",
2778 "en_ZA"
2779 }, {
2780 "und_MA",
2781 "ar_Arab_MA",
2782 "ar_MA"
2783 }, {
2784 "und_MC",
2785 "fr_Latn_MC",
2786 "fr_MC"
2787 }, {
2788 "und_MD",
2789 "ro_Latn_MD",
2790 "ro_MD"
2791 }, {
2792 "und_ME",
2793 "sr_Latn_ME",
2794 "sr_ME"
2795 }, {
2796 "und_MG",
2797 "mg_Latn_MG",
2798 "mg"
2799 }, {
2800 "und_MK",
2801 "mk_Cyrl_MK",
2802 "mk"
2803 }, {
2804 "und_ML",
2805 "bm_Latn_ML",
2806 "bm"
2807 }, {
2808 "und_MM",
2809 "my_Mymr_MM",
2810 "my"
2811 }, {
2812 "und_MN",
2813 "mn_Cyrl_MN",
2814 "mn"
2815 }, {
2816 "und_MO",
2817 "zh_Hant_MO",
2818 "zh_MO"
2819 }, {
2820 "und_MQ",
2821 "fr_Latn_MQ",
2822 "fr_MQ"
2823 }, {
2824 "und_MR",
2825 "ar_Arab_MR",
2826 "ar_MR"
2827 }, {
2828 "und_MT",
2829 "mt_Latn_MT",
2830 "mt"
2831 }, {
2832 "und_MV",
2833 "dv_Thaa_MV",
2834 "dv"
2835 }, {
2836 "und_MX",
2837 "es_Latn_MX",
2838 "es_MX"
2839 }, {
2840 "und_MY",
2841 "ms_Latn_MY",
2842 "ms"
2843 }, {
2844 "und_MZ",
2845 "pt_Latn_MZ",
2846 "pt_MZ"
2847 }, {
2848 "und_Mlym",
2849 "ml_Mlym_IN",
2850 "ml"
2851 }, {
2852 "und_Mymr",
2853 "my_Mymr_MM",
2854 "my"
2855 }, {
2856 "und_NC",
2857 "fr_Latn_NC",
2858 "fr_NC"
2859 }, {
2860 "und_NE",
2861 "ha_Latn_NE",
2862 "ha_NE"
2863 }, {
2864 "und_NG",
2865 "en_Latn_NG",
2866 "en_NG"
2867 }, {
2868 "und_NI",
2869 "es_Latn_NI",
2870 "es_NI"
2871 }, {
2872 "und_NL",
2873 "nl_Latn_NL",
2874 "nl"
2875 }, {
2876 "und_NO",
2877 "nb_Latn_NO",
2878 "nb"
2879 }, {
2880 "und_NP",
2881 "ne_Deva_NP",
2882 "ne"
2883 }, {
2884 "und_NR",
2885 "en_Latn_NR",
2886 "en_NR"
2887 }, {
2888 "und_OM",
2889 "ar_Arab_OM",
2890 "ar_OM"
2891 }, {
2892 "und_Orya",
2893 "or_Orya_IN",
2894 "or"
2895 }, {
2896 "und_PA",
2897 "es_Latn_PA",
2898 "es_PA"
2899 }, {
2900 "und_PE",
2901 "es_Latn_PE",
2902 "es_PE"
2903 }, {
2904 "und_PF",
2905 "fr_Latn_PF",
2906 "fr_PF"
2907 }, {
2908 "und_PG",
2909 "tpi_Latn_PG",
2910 "tpi"
2911 }, {
2912 "und_PH",
2913 "fil_Latn_PH",
2914 "fil"
2915 }, {
2916 "und_PL",
2917 "pl_Latn_PL",
2918 "pl"
2919 }, {
2920 "und_PM",
2921 "fr_Latn_PM",
2922 "fr_PM"
2923 }, {
2924 "und_PR",
2925 "es_Latn_PR",
2926 "es_PR"
2927 }, {
2928 "und_PS",
2929 "ar_Arab_PS",
2930 "ar_PS"
2931 }, {
2932 "und_PT",
2933 "pt_Latn_PT",
2934 "pt_PT"
2935 }, {
2936 "und_PW",
2937 "pau_Latn_PW",
2938 "pau"
2939 }, {
2940 "und_PY",
2941 "gn_Latn_PY",
2942 "gn"
2943 }, {
2944 "und_QA",
2945 "ar_Arab_QA",
2946 "ar_QA"
2947 }, {
2948 "und_RE",
2949 "fr_Latn_RE",
2950 "fr_RE"
2951 }, {
2952 "und_RO",
2953 "ro_Latn_RO",
2954 "ro"
2955 }, {
2956 "und_RS",
2957 "sr_Cyrl_RS",
2958 "sr"
2959 }, {
2960 "und_RU",
2961 "ru_Cyrl_RU",
2962 "ru"
2963 }, {
2964 "und_RW",
2965 "rw_Latn_RW",
2966 "rw"
2967 }, {
2968 "und_SA",
2969 "ar_Arab_SA",
2970 "ar_SA"
2971 }, {
2972 "und_SD",
2973 "ar_Arab_SD",
2974 "ar_SD"
2975 }, {
2976 "und_SE",
2977 "sv_Latn_SE",
2978 "sv"
2979 }, {
2980 "und_SG",
2981 "en_Latn_SG",
2982 "en_SG"
2983 }, {
2984 "und_SI",
2985 "sl_Latn_SI",
2986 "sl"
2987 }, {
2988 "und_SJ",
2989 "nb_Latn_SJ",
2990 "nb_SJ"
2991 }, {
2992 "und_SK",
2993 "sk_Latn_SK",
2994 "sk"
2995 }, {
2996 "und_SM",
2997 "it_Latn_SM",
2998 "it_SM"
2999 }, {
3000 "und_SN",
3001 "fr_Latn_SN",
3002 "fr_SN"
3003 }, {
3004 "und_SO",
3005 "so_Latn_SO",
3006 "so"
3007 }, {
3008 "und_SR",
3009 "nl_Latn_SR",
3010 "nl_SR"
3011 }, {
3012 "und_ST",
3013 "pt_Latn_ST",
3014 "pt_ST"
3015 }, {
3016 "und_SV",
3017 "es_Latn_SV",
3018 "es_SV"
3019 }, {
3020 "und_SY",
3021 "ar_Arab_SY",
3022 "ar_SY"
3023 }, {
3024 "und_Sinh",
3025 "si_Sinh_LK",
3026 "si"
3027 }, {
3028 "und_Syrc",
3029 "syr_Syrc_IQ",
3030 "syr"
3031 }, {
3032 "und_TD",
3033 "fr_Latn_TD",
3034 "fr_TD"
3035 }, {
3036 "und_TG",
3037 "fr_Latn_TG",
3038 "fr_TG"
3039 }, {
3040 "und_TH",
3041 "th_Thai_TH",
3042 "th"
3043 }, {
3044 "und_TJ",
3045 "tg_Cyrl_TJ",
3046 "tg"
3047 }, {
3048 "und_TK",
3049 "tkl_Latn_TK",
3050 "tkl"
3051 }, {
3052 "und_TL",
3053 "pt_Latn_TL",
3054 "pt_TL"
3055 }, {
3056 "und_TM",
3057 "tk_Latn_TM",
3058 "tk"
3059 }, {
3060 "und_TN",
3061 "ar_Arab_TN",
3062 "ar_TN"
3063 }, {
3064 "und_TO",
3065 "to_Latn_TO",
3066 "to"
3067 }, {
3068 "und_TR",
3069 "tr_Latn_TR",
3070 "tr"
3071 }, {
3072 "und_TV",
3073 "tvl_Latn_TV",
3074 "tvl"
3075 }, {
3076 "und_TW",
3077 "zh_Hant_TW",
3078 "zh_TW"
3079 }, {
3080 "und_Taml",
3081 "ta_Taml_IN",
3082 "ta"
3083 }, {
3084 "und_Telu",
3085 "te_Telu_IN",
3086 "te"
3087 }, {
3088 "und_Thaa",
3089 "dv_Thaa_MV",
3090 "dv"
3091 }, {
3092 "und_Thai",
3093 "th_Thai_TH",
3094 "th"
3095 }, {
3096 "und_Tibt",
3097 "bo_Tibt_CN",
3098 "bo"
3099 }, {
3100 "und_UA",
3101 "uk_Cyrl_UA",
3102 "uk"
3103 }, {
3104 "und_UY",
3105 "es_Latn_UY",
3106 "es_UY"
3107 }, {
3108 "und_UZ",
3109 "uz_Latn_UZ",
3110 "uz"
3111 }, {
3112 "und_VA",
3113 "it_Latn_VA",
3114 "it_VA"
3115 }, {
3116 "und_VE",
3117 "es_Latn_VE",
3118 "es_VE"
3119 }, {
3120 "und_VN",
3121 "vi_Latn_VN",
3122 "vi"
3123 }, {
3124 "und_VU",
3125 "bi_Latn_VU",
3126 "bi"
3127 }, {
3128 "und_WF",
3129 "fr_Latn_WF",
3130 "fr_WF"
3131 }, {
3132 "und_WS",
3133 "sm_Latn_WS",
3134 "sm"
3135 }, {
3136 "und_YE",
3137 "ar_Arab_YE",
3138 "ar_YE"
3139 }, {
3140 "und_YT",
3141 "fr_Latn_YT",
3142 "fr_YT"
3143 }, {
3144 "und_Yiii",
3145 "ii_Yiii_CN",
3146 "ii"
3147 }, {
3148 "ur",
3149 "ur_Arab_PK",
3150 "ur"
3151 }, {
3152 "uz",
3153 "uz_Latn_UZ",
3154 "uz"
3155 }, {
3156 "uz_AF",
3157 "uz_Arab_AF",
3158 "uz_AF"
3159 }, {
3160 "uz_Arab",
3161 "uz_Arab_AF",
3162 "uz_AF"
3163 }, {
3164 "ve",
3165 "ve_Latn_ZA",
3166 "ve"
3167 }, {
3168 "vi",
3169 "vi_Latn_VN",
3170 "vi"
3171 }, {
3172 "wal",
3173 "wal_Ethi_ET",
3174 "wal"
3175 }, {
3176 "wo",
3177 "wo_Latn_SN",
3178 "wo"
3179 }, {
3180 "wo_SN",
3181 "wo_Latn_SN",
3182 "wo"
3183 }, {
3184 "xh",
3185 "xh_Latn_ZA",
3186 "xh"
3187 }, {
3188 "yo",
3189 "yo_Latn_NG",
3190 "yo"
3191 }, {
3192 "zh",
3193 "zh_Hans_CN",
3194 "zh"
3195 }, {
3196 "zh_HK",
3197 "zh_Hant_HK",
3198 "zh_HK"
3199 }, {
3200 "zh_Hani",
3201 "zh_Hani_CN",
3202 "zh_Hani"
3203 }, {
3204 "zh_Hant",
3205 "zh_Hant_TW",
3206 "zh_TW"
3207 }, {
3208 "zh_MO",
3209 "zh_Hant_MO",
3210 "zh_MO"
3211 }, {
3212 "zh_TW",
3213 "zh_Hant_TW",
3214 "zh_TW"
3215 }, {
3216 "zu",
3217 "zu_Latn_ZA",
3218 "zu"
3219 }, {
3220 "und",
3221 "en_Latn_US",
3222 "en"
3223 }, {
3224 "und_ZZ",
3225 "en_Latn_US",
3226 "en"
3227 }, {
3228 "und_CN",
3229 "zh_Hans_CN",
3230 "zh"
3231 }, {
3232 "und_TW",
3233 "zh_Hant_TW",
3234 "zh_TW"
3235 }, {
3236 "und_HK",
3237 "zh_Hant_HK",
3238 "zh_HK"
3239 }, {
3240 "und_AQ",
3241 "_Latn_AQ",
3242 "_AQ"
3243 }, {
3244 "und_Zzzz",
3245 "en_Latn_US",
3246 "en"
3247 }, {
3248 "und_Zzzz_ZZ",
3249 "en_Latn_US",
3250 "en"
3251 }, {
3252 "und_Zzzz_CN",
3253 "zh_Hans_CN",
3254 "zh"
3255 }, {
3256 "und_Zzzz_TW",
3257 "zh_Hant_TW",
3258 "zh_TW"
3259 }, {
3260 "und_Zzzz_HK",
3261 "zh_Hant_HK",
3262 "zh_HK"
3263 }, {
3264 "und_Zzzz_AQ",
3265 "_Latn_AQ",
3266 "_AQ"
3267 }, {
3268 "und_Latn",
3269 "en_Latn_US",
3270 "en"
3271 }, {
3272 "und_Latn_ZZ",
3273 "en_Latn_US",
3274 "en"
3275 }, {
3276 "und_Latn_CN",
3277 "za_Latn_CN",
3278 "za"
3279 }, {
3280 "und_Latn_TW",
3281 "trv_Latn_TW",
3282 "trv"
3283 }, {
3284 "und_Latn_HK",
3285 "zh_Latn_HK",
3286 "zh_Latn_HK"
3287 }, {
3288 "und_Latn_AQ",
3289 "_Latn_AQ",
3290 "_AQ"
3291 }, {
3292 "und_Hans",
3293 "zh_Hans_CN",
3294 "zh"
3295 }, {
3296 "und_Hans_ZZ",
3297 "zh_Hans_CN",
3298 "zh"
3299 }, {
3300 "und_Hans_CN",
3301 "zh_Hans_CN",
3302 "zh"
3303 }, {
3304 "und_Hans_TW",
3305 "zh_Hans_TW",
3306 "zh_Hans_TW"
3307 }, {
3308 "und_Hans_HK",
3309 "zh_Hans_HK",
3310 "zh_Hans_HK"
3311 }, {
3312 "und_Hans_AQ",
3313 "zh_Hans_AQ",
3314 "zh_AQ"
3315 }, {
3316 "und_Hant",
3317 "zh_Hant_TW",
3318 "zh_TW"
3319 }, {
3320 "und_Hant_ZZ",
3321 "zh_Hant_TW",
3322 "zh_TW"
3323 }, {
3324 "und_Hant_CN",
3325 "zh_Hant_CN",
3326 "zh_Hant_CN"
3327 }, {
3328 "und_Hant_TW",
3329 "zh_Hant_TW",
3330 "zh_TW"
3331 }, {
3332 "und_Hant_HK",
3333 "zh_Hant_HK",
3334 "zh_HK"
3335 }, {
3336 "und_Hant_AQ",
3337 "zh_Hant_AQ",
3338 "zh_Hant_AQ"
3339 }, {
3340 "und_Moon",
3341 "en_Moon_US",
3342 "en_Moon"
3343 }, {
3344 "und_Moon_ZZ",
3345 "en_Moon_US",
3346 "en_Moon"
3347 }, {
3348 "und_Moon_CN",
3349 "zh_Moon_CN",
3350 "zh_Moon"
3351 }, {
3352 "und_Moon_TW",
3353 "zh_Moon_TW",
3354 "zh_Moon_TW"
3355 }, {
3356 "und_Moon_HK",
3357 "zh_Moon_HK",
3358 "zh_Moon_HK"
3359 }, {
3360 "und_Moon_AQ",
3361 "_Moon_AQ",
3362 "_Moon_AQ"
3363 }, {
3364 "es",
3365 "es_Latn_ES",
3366 "es"
3367 }, {
3368 "es_ZZ",
3369 "es_Latn_ES",
3370 "es"
3371 }, {
3372 "es_CN",
3373 "es_Latn_CN",
3374 "es_CN"
3375 }, {
3376 "es_TW",
3377 "es_Latn_TW",
3378 "es_TW"
3379 }, {
3380 "es_HK",
3381 "es_Latn_HK",
3382 "es_HK"
3383 }, {
3384 "es_AQ",
3385 "es_Latn_AQ",
3386 "es_AQ"
3387 }, {
3388 "es_Zzzz",
3389 "es_Latn_ES",
3390 "es"
3391 }, {
3392 "es_Zzzz_ZZ",
3393 "es_Latn_ES",
3394 "es"
3395 }, {
3396 "es_Zzzz_CN",
3397 "es_Latn_CN",
3398 "es_CN"
3399 }, {
3400 "es_Zzzz_TW",
3401 "es_Latn_TW",
3402 "es_TW"
3403 }, {
3404 "es_Zzzz_HK",
3405 "es_Latn_HK",
3406 "es_HK"
3407 }, {
3408 "es_Zzzz_AQ",
3409 "es_Latn_AQ",
3410 "es_AQ"
3411 }, {
3412 "es_Latn",
3413 "es_Latn_ES",
3414 "es"
3415 }, {
3416 "es_Latn_ZZ",
3417 "es_Latn_ES",
3418 "es"
3419 }, {
3420 "es_Latn_CN",
3421 "es_Latn_CN",
3422 "es_CN"
3423 }, {
3424 "es_Latn_TW",
3425 "es_Latn_TW",
3426 "es_TW"
3427 }, {
3428 "es_Latn_HK",
3429 "es_Latn_HK",
3430 "es_HK"
3431 }, {
3432 "es_Latn_AQ",
3433 "es_Latn_AQ",
3434 "es_AQ"
3435 }, {
3436 "es_Hans",
3437 "es_Hans_ES",
3438 "es_Hans"
3439 }, {
3440 "es_Hans_ZZ",
3441 "es_Hans_ES",
3442 "es_Hans"
3443 }, {
3444 "es_Hans_CN",
3445 "es_Hans_CN",
3446 "es_Hans_CN"
3447 }, {
3448 "es_Hans_TW",
3449 "es_Hans_TW",
3450 "es_Hans_TW"
3451 }, {
3452 "es_Hans_HK",
3453 "es_Hans_HK",
3454 "es_Hans_HK"
3455 }, {
3456 "es_Hans_AQ",
3457 "es_Hans_AQ",
3458 "es_Hans_AQ"
3459 }, {
3460 "es_Hant",
3461 "es_Hant_ES",
3462 "es_Hant"
3463 }, {
3464 "es_Hant_ZZ",
3465 "es_Hant_ES",
3466 "es_Hant"
3467 }, {
3468 "es_Hant_CN",
3469 "es_Hant_CN",
3470 "es_Hant_CN"
3471 }, {
3472 "es_Hant_TW",
3473 "es_Hant_TW",
3474 "es_Hant_TW"
3475 }, {
3476 "es_Hant_HK",
3477 "es_Hant_HK",
3478 "es_Hant_HK"
3479 }, {
3480 "es_Hant_AQ",
3481 "es_Hant_AQ",
3482 "es_Hant_AQ"
3483 }, {
3484 "es_Moon",
3485 "es_Moon_ES",
3486 "es_Moon"
3487 }, {
3488 "es_Moon_ZZ",
3489 "es_Moon_ES",
3490 "es_Moon"
3491 }, {
3492 "es_Moon_CN",
3493 "es_Moon_CN",
3494 "es_Moon_CN"
3495 }, {
3496 "es_Moon_TW",
3497 "es_Moon_TW",
3498 "es_Moon_TW"
3499 }, {
3500 "es_Moon_HK",
3501 "es_Moon_HK",
3502 "es_Moon_HK"
3503 }, {
3504 "es_Moon_AQ",
3505 "es_Moon_AQ",
3506 "es_Moon_AQ"
3507 }, {
3508 "zh",
3509 "zh_Hans_CN",
3510 "zh"
3511 }, {
3512 "zh_ZZ",
3513 "zh_Hans_CN",
3514 "zh"
3515 }, {
3516 "zh_CN",
3517 "zh_Hans_CN",
3518 "zh"
3519 }, {
3520 "zh_TW",
3521 "zh_Hant_TW",
3522 "zh_TW"
3523 }, {
3524 "zh_HK",
3525 "zh_Hant_HK",
3526 "zh_HK"
3527 }, {
3528 "zh_AQ",
3529 "zh_Hans_AQ",
3530 "zh_AQ"
3531 }, {
3532 "zh_Zzzz",
3533 "zh_Hans_CN",
3534 "zh"
3535 }, {
3536 "zh_Zzzz_ZZ",
3537 "zh_Hans_CN",
3538 "zh"
3539 }, {
3540 "zh_Zzzz_CN",
3541 "zh_Hans_CN",
3542 "zh"
3543 }, {
3544 "zh_Zzzz_TW",
3545 "zh_Hant_TW",
3546 "zh_TW"
3547 }, {
3548 "zh_Zzzz_HK",
3549 "zh_Hant_HK",
3550 "zh_HK"
3551 }, {
3552 "zh_Zzzz_AQ",
3553 "zh_Hans_AQ",
3554 "zh_AQ"
3555 }, {
3556 "zh_Latn",
3557 "zh_Latn_CN",
3558 "zh_Latn"
3559 }, {
3560 "zh_Latn_ZZ",
3561 "zh_Latn_CN",
3562 "zh_Latn"
3563 }, {
3564 "zh_Latn_CN",
3565 "zh_Latn_CN",
3566 "zh_Latn"
3567 }, {
3568 "zh_Latn_TW",
3569 "zh_Latn_TW",
3570 "zh_Latn_TW"
3571 }, {
3572 "zh_Latn_HK",
3573 "zh_Latn_HK",
3574 "zh_Latn_HK"
3575 }, {
3576 "zh_Latn_AQ",
3577 "zh_Latn_AQ",
3578 "zh_Latn_AQ"
3579 }, {
3580 "zh_Hans",
3581 "zh_Hans_CN",
3582 "zh"
3583 }, {
3584 "zh_Hans_ZZ",
3585 "zh_Hans_CN",
3586 "zh"
3587 }, {
3588 "zh_Hans_TW",
3589 "zh_Hans_TW",
3590 "zh_Hans_TW"
3591 }, {
3592 "zh_Hans_HK",
3593 "zh_Hans_HK",
3594 "zh_Hans_HK"
3595 }, {
3596 "zh_Hans_AQ",
3597 "zh_Hans_AQ",
3598 "zh_AQ"
3599 }, {
3600 "zh_Hant",
3601 "zh_Hant_TW",
3602 "zh_TW"
3603 }, {
3604 "zh_Hant_ZZ",
3605 "zh_Hant_TW",
3606 "zh_TW"
3607 }, {
3608 "zh_Hant_CN",
3609 "zh_Hant_CN",
3610 "zh_Hant_CN"
3611 }, {
3612 "zh_Hant_AQ",
3613 "zh_Hant_AQ",
3614 "zh_Hant_AQ"
3615 }, {
3616 "zh_Moon",
3617 "zh_Moon_CN",
3618 "zh_Moon"
3619 }, {
3620 "zh_Moon_ZZ",
3621 "zh_Moon_CN",
3622 "zh_Moon"
3623 }, {
3624 "zh_Moon_CN",
3625 "zh_Moon_CN",
3626 "zh_Moon"
3627 }, {
3628 "zh_Moon_TW",
3629 "zh_Moon_TW",
3630 "zh_Moon_TW"
3631 }, {
3632 "zh_Moon_HK",
3633 "zh_Moon_HK",
3634 "zh_Moon_HK"
3635 }, {
3636 "zh_Moon_AQ",
3637 "zh_Moon_AQ",
3638 "zh_Moon_AQ"
3639 }, {
3640 "art",
3641 "",
3642 ""
3643 }, {
3644 "art_ZZ",
3645 "",
3646 ""
3647 }, {
3648 "art_CN",
3649 "",
3650 ""
3651 }, {
3652 "art_TW",
3653 "",
3654 ""
3655 }, {
3656 "art_HK",
3657 "",
3658 ""
3659 }, {
3660 "art_AQ",
3661 "",
3662 ""
3663 }, {
3664 "art_Zzzz",
3665 "",
3666 ""
3667 }, {
3668 "art_Zzzz_ZZ",
3669 "",
3670 ""
3671 }, {
3672 "art_Zzzz_CN",
3673 "",
3674 ""
3675 }, {
3676 "art_Zzzz_TW",
3677 "",
3678 ""
3679 }, {
3680 "art_Zzzz_HK",
3681 "",
3682 ""
3683 }, {
3684 "art_Zzzz_AQ",
3685 "",
3686 ""
3687 }, {
3688 "art_Latn",
3689 "",
3690 ""
3691 }, {
3692 "art_Latn_ZZ",
3693 "",
3694 ""
3695 }, {
3696 "art_Latn_CN",
3697 "",
3698 ""
3699 }, {
3700 "art_Latn_TW",
3701 "",
3702 ""
3703 }, {
3704 "art_Latn_HK",
3705 "",
3706 ""
3707 }, {
3708 "art_Latn_AQ",
3709 "",
3710 ""
3711 }, {
3712 "art_Hans",
3713 "",
3714 ""
3715 }, {
3716 "art_Hans_ZZ",
3717 "",
3718 ""
3719 }, {
3720 "art_Hans_CN",
3721 "",
3722 ""
3723 }, {
3724 "art_Hans_TW",
3725 "",
3726 ""
3727 }, {
3728 "art_Hans_HK",
3729 "",
3730 ""
3731 }, {
3732 "art_Hans_AQ",
3733 "",
3734 ""
3735 }, {
3736 "art_Hant",
3737 "",
3738 ""
3739 }, {
3740 "art_Hant_ZZ",
3741 "",
3742 ""
3743 }, {
3744 "art_Hant_CN",
3745 "",
3746 ""
3747 }, {
3748 "art_Hant_TW",
3749 "",
3750 ""
3751 }, {
3752 "art_Hant_HK",
3753 "",
3754 ""
3755 }, {
3756 "art_Hant_AQ",
3757 "",
3758 ""
3759 }, {
3760 "art_Moon",
3761 "",
3762 ""
3763 }, {
3764 "art_Moon_ZZ",
3765 "",
3766 ""
3767 }, {
3768 "art_Moon_CN",
3769 "",
3770 ""
3771 }, {
3772 "art_Moon_TW",
3773 "",
3774 ""
3775 }, {
3776 "art_Moon_HK",
3777 "",
3778 ""
3779 }, {
3780 "art_Moon_AQ",
3781 "",
3782 ""
3783 }, {
3784 "aae_Latn_IT",
3785 "aae_Latn_IT",
3786 "aae_Latn_IT"
3787 }, {
3788 "aae_Thai_CO",
3789 "aae_Thai_CO",
3790 "aae_Thai_CO"
3791 }, {
3792 "und_CW",
3793 "pap_Latn_CW",
3794 "pap_CW"
3795 }, {
3796 "zh_Hant",
3797 "zh_Hant_TW",
3798 "zh_TW"
3799 }, {
3800 "zh_Hani",
3801 "zh_Hani_CN",
3802 "zh_Hani"
3803 }, {
3804 "und",
3805 "en_Latn_US",
3806 "en"
3807 }, {
3808 "und_Thai",
3809 "th_Thai_TH",
3810 "th"
3811 }, {
3812 "und_419",
3813 "es_Latn_419",
3814 "es_419"
3815 }, {
3816 "und_150",
3817 "ru_Cyrl_RU",
3818 "ru"
3819 }, {
3820 "und_AT",
3821 "de_Latn_AT",
3822 "de_AT"
3823 }, {
3824 "und_US",
3825 "en_Latn_US",
3826 "en"
3827 }
3828 };
3829
3830 for (const auto& item : full_data) {
3831 const char* const org = item.from;
3832 const char* const exp = item.add;
3833 Locale res(org);
3834 res.addLikelySubtags(status);
3835 status.errIfFailureAndReset("\"%s\"", org);
3836 if (exp[0]) {
3837 assertEquals("addLikelySubtags", exp, res.getName());
3838 } else {
3839 assertEquals("addLikelySubtags", org, res.getName());
3840 }
3841 }
3842
3843 for (const auto& item : full_data) {
3844 const char* const org = item.from;
3845 const char* const exp = item.remove;
3846 Locale res(org);
3847 res.minimizeSubtags(status);
3848 status.errIfFailureAndReset("\"%s\"", org);
3849 if (exp[0]) {
3850 assertEquals("minimizeSubtags", exp, res.getName());
3851 } else {
3852 assertEquals("minimizeSubtags", org, res.getName());
3853 }
3854 }
3855 }
3856
3857
3858 void
TestKeywordVariants(void)3859 LocaleTest::TestKeywordVariants(void) {
3860 static const struct {
3861 const char *localeID;
3862 const char *expectedLocaleID;
3863 //const char *expectedLocaleIDNoKeywords;
3864 //const char *expectedCanonicalID;
3865 const char *expectedKeywords[10];
3866 int32_t numKeywords;
3867 UErrorCode expectedStatus;
3868 } testCases[] = {
3869 {
3870 "de_DE@ currency = euro; C o ll A t i o n = Phonebook ; C alen dar = buddhist ",
3871 "de_DE@calendar=buddhist;collation=Phonebook;currency=euro",
3872 //"de_DE",
3873 //"de_DE@calendar=buddhist;collation=Phonebook;currency=euro",
3874 {"calendar", "collation", "currency"},
3875 3,
3876 U_ZERO_ERROR
3877 },
3878 {
3879 "de_DE@euro",
3880 "de_DE@euro",
3881 //"de_DE",
3882 //"de_DE@currency=EUR",
3883 {"","","","","","",""},
3884 0,
3885 U_INVALID_FORMAT_ERROR /* must have '=' after '@' */
3886 }
3887 };
3888 UErrorCode status = U_ZERO_ERROR;
3889
3890 int32_t i = 0, j = 0;
3891 const char *result = NULL;
3892 StringEnumeration *keywords;
3893 int32_t keyCount = 0;
3894 const char *keyword = NULL;
3895 const UnicodeString *keywordString;
3896 int32_t keywordLen = 0;
3897
3898 for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
3899 status = U_ZERO_ERROR;
3900 Locale l(testCases[i].localeID);
3901 keywords = l.createKeywords(status);
3902
3903 if(status != testCases[i].expectedStatus) {
3904 err("Expected to get status %s. Got %s instead\n",
3905 u_errorName(testCases[i].expectedStatus), u_errorName(status));
3906 }
3907 status = U_ZERO_ERROR;
3908 if(keywords) {
3909 if((keyCount = keywords->count(status)) != testCases[i].numKeywords) {
3910 err("Expected to get %i keywords, got %i\n", testCases[i].numKeywords, keyCount);
3911 }
3912 if(keyCount) {
3913 for(j = 0;;) {
3914 if((j&1)==0) {
3915 if((keyword = keywords->next(&keywordLen, status)) == NULL) {
3916 break;
3917 }
3918 if(strcmp(keyword, testCases[i].expectedKeywords[j]) != 0) {
3919 err("Expected to get keyword value %s, got %s\n", testCases[i].expectedKeywords[j], keyword);
3920 }
3921 } else {
3922 if((keywordString = keywords->snext(status)) == NULL) {
3923 break;
3924 }
3925 if(*keywordString != UnicodeString(testCases[i].expectedKeywords[j], "")) {
3926 err("Expected to get keyword UnicodeString %s, got %s\n", testCases[i].expectedKeywords[j], keyword);
3927 }
3928 }
3929 j++;
3930
3931 if(j == keyCount / 2) {
3932 // replace keywords with a clone of itself
3933 StringEnumeration *k2 = keywords->clone();
3934 if(k2 == NULL || keyCount != k2->count(status)) {
3935 errln("KeywordEnumeration.clone() failed");
3936 } else {
3937 delete keywords;
3938 keywords = k2;
3939 }
3940 }
3941 }
3942 keywords->reset(status); // Make sure that reset works.
3943 for(j = 0;;) {
3944 if((keyword = keywords->next(&keywordLen, status)) == NULL) {
3945 break;
3946 }
3947 if(strcmp(keyword, testCases[i].expectedKeywords[j]) != 0) {
3948 err("Expected to get keyword value %s, got %s\n", testCases[i].expectedKeywords[j], keyword);
3949 }
3950 j++;
3951 }
3952 }
3953 delete keywords;
3954 }
3955 result = l.getName();
3956 if(uprv_strcmp(testCases[i].expectedLocaleID, result) != 0) {
3957 err("Expected to get \"%s\" from \"%s\". Got \"%s\" instead\n",
3958 testCases[i].expectedLocaleID, testCases[i].localeID, result);
3959 }
3960
3961 }
3962
3963 }
3964
3965
3966 void
TestCreateUnicodeKeywords(void)3967 LocaleTest::TestCreateUnicodeKeywords(void) {
3968 IcuTestErrorCode status(*this, "TestCreateUnicodeKeywords()");
3969
3970 static const Locale l("de@calendar=buddhist;collation=phonebook");
3971
3972 LocalPointer<StringEnumeration> keys(l.createUnicodeKeywords(status));
3973 status.errIfFailureAndReset("\"%s\"", l.getName());
3974
3975 const char* key;
3976 int32_t resultLength;
3977
3978 key = keys->next(&resultLength, status);
3979 status.errIfFailureAndReset("key #1");
3980 assertEquals("resultLength", 2, resultLength);
3981 assertTrue("key != nullptr", key != nullptr);
3982 if (key != nullptr) {
3983 assertEquals("calendar", "ca", key);
3984 }
3985
3986 key = keys->next(&resultLength, status);
3987 status.errIfFailureAndReset("key #2");
3988 assertEquals("resultLength", 2, resultLength);
3989 assertTrue("key != nullptr", key != nullptr);
3990 if (key != nullptr) {
3991 assertEquals("collation", "co", key);
3992 }
3993
3994 key = keys->next(&resultLength, status);
3995 status.errIfFailureAndReset("end of keys");
3996 assertEquals("resultLength", 0, resultLength);
3997 assertTrue("key == nullptr", key == nullptr);
3998
3999 const UnicodeString* skey;
4000 keys->reset(status); // KeywordEnumeration::reset() never touches status.
4001
4002 skey = keys->snext(status);
4003 status.errIfFailureAndReset("skey #1");
4004 assertTrue("skey != nullptr", skey != nullptr);
4005 if (skey != nullptr) {
4006 assertEquals("calendar", "ca", *skey);
4007 }
4008
4009 skey = keys->snext(status);
4010 status.errIfFailureAndReset("skey #2");
4011 assertTrue("skey != nullptr", skey != nullptr);
4012 if (skey != nullptr) {
4013 assertEquals("collation", "co", *skey);
4014 }
4015
4016 skey = keys->snext(status);
4017 status.errIfFailureAndReset("end of keys");
4018 assertTrue("skey == nullptr", skey == nullptr);
4019 }
4020
4021
4022 void
TestKeywordVariantParsing(void)4023 LocaleTest::TestKeywordVariantParsing(void) {
4024 static const struct {
4025 const char *localeID;
4026 const char *keyword;
4027 const char *expectedValue;
4028 } testCases[] = {
4029 { "de_DE@ C o ll A t i o n = Phonebook ", "collation", "Phonebook" },
4030 { "de_DE", "collation", ""},
4031 { "de_DE@collation= PHONEBOOK", "collation", "PHONEBOOK" },
4032 { "de_DE@ currency = euro ; CoLLaTion = PHONEBOOk ", "collation", "PHONEBOOk" },
4033 };
4034
4035 UErrorCode status = U_ZERO_ERROR;
4036
4037 int32_t i = 0;
4038 int32_t resultLen = 0;
4039 char buffer[256];
4040
4041 for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
4042 *buffer = 0;
4043 Locale l(testCases[i].localeID);
4044 resultLen = l.getKeywordValue(testCases[i].keyword, buffer, 256, status);
4045 (void)resultLen; // Suppress unused variable warning.
4046 if(uprv_strcmp(testCases[i].expectedValue, buffer) != 0) {
4047 err("Expected to extract \"%s\" from \"%s\" for keyword \"%s\". Got \"%s\" instead\n",
4048 testCases[i].expectedValue, testCases[i].localeID, testCases[i].keyword, buffer);
4049 }
4050 }
4051 }
4052
4053 void
TestCreateKeywordSet(void)4054 LocaleTest::TestCreateKeywordSet(void) {
4055 IcuTestErrorCode status(*this, "TestCreateKeywordSet()");
4056
4057 static const Locale l("de@calendar=buddhist;collation=phonebook");
4058
4059 std::set<std::string> result;
4060 l.getKeywords<std::string>(
4061 std::insert_iterator<decltype(result)>(result, result.begin()),
4062 status);
4063 status.errIfFailureAndReset("\"%s\"", l.getName());
4064
4065 assertEquals("set::size()", 2, static_cast<int32_t>(result.size()));
4066 assertTrue("set::find(\"calendar\")",
4067 result.find("calendar") != result.end());
4068 assertTrue("set::find(\"collation\")",
4069 result.find("collation") != result.end());
4070 }
4071
4072 void
TestCreateKeywordSetEmpty(void)4073 LocaleTest::TestCreateKeywordSetEmpty(void) {
4074 IcuTestErrorCode status(*this, "TestCreateKeywordSetEmpty()");
4075
4076 static const Locale l("de");
4077
4078 std::set<std::string> result;
4079 l.getKeywords<std::string>(
4080 std::insert_iterator<decltype(result)>(result, result.begin()),
4081 status);
4082 status.errIfFailureAndReset("\"%s\"", l.getName());
4083
4084 assertEquals("set::size()", 0, static_cast<int32_t>(result.size()));
4085 }
4086
4087 void
TestCreateUnicodeKeywordSet(void)4088 LocaleTest::TestCreateUnicodeKeywordSet(void) {
4089 IcuTestErrorCode status(*this, "TestCreateUnicodeKeywordSet()");
4090
4091 static const Locale l("de@calendar=buddhist;collation=phonebook");
4092
4093 std::set<std::string> result;
4094 l.getUnicodeKeywords<std::string>(
4095 std::insert_iterator<decltype(result)>(result, result.begin()),
4096 status);
4097 status.errIfFailureAndReset("\"%s\"", l.getName());
4098
4099 assertEquals("set::size()", 2, static_cast<int32_t>(result.size()));
4100 assertTrue("set::find(\"ca\")",
4101 result.find("ca") != result.end());
4102 assertTrue("set::find(\"co\")",
4103 result.find("co") != result.end());
4104 }
4105
4106 void
TestCreateUnicodeKeywordSetEmpty(void)4107 LocaleTest::TestCreateUnicodeKeywordSetEmpty(void) {
4108 IcuTestErrorCode status(*this, "TestCreateUnicodeKeywordSetEmpty()");
4109
4110 static const Locale l("de");
4111
4112 std::set<std::string> result;
4113 l.getUnicodeKeywords<std::string>(
4114 std::insert_iterator<decltype(result)>(result, result.begin()),
4115 status);
4116 status.errIfFailureAndReset("\"%s\"", l.getName());
4117
4118 assertEquals("set::size()", 0, static_cast<int32_t>(result.size()));
4119 }
4120
4121 void
TestGetKeywordValueStdString(void)4122 LocaleTest::TestGetKeywordValueStdString(void) {
4123 IcuTestErrorCode status(*this, "TestGetKeywordValueStdString()");
4124
4125 static const char tag[] = "fa-u-nu-latn";
4126 static const char keyword[] = "numbers";
4127 static const char expected[] = "latn";
4128
4129 Locale l = Locale::forLanguageTag(tag, status);
4130 status.errIfFailureAndReset("\"%s\"", tag);
4131
4132 std::string result = l.getKeywordValue<std::string>(keyword, status);
4133 status.errIfFailureAndReset("\"%s\"", keyword);
4134 assertEquals(keyword, expected, result.c_str());
4135 }
4136
4137 void
TestGetUnicodeKeywordValueStdString(void)4138 LocaleTest::TestGetUnicodeKeywordValueStdString(void) {
4139 IcuTestErrorCode status(*this, "TestGetUnicodeKeywordValueStdString()");
4140
4141 static const char keyword[] = "co";
4142 static const char expected[] = "phonebk";
4143
4144 static const Locale l("de@calendar=buddhist;collation=phonebook");
4145
4146 std::string result = l.getUnicodeKeywordValue<std::string>(keyword, status);
4147 status.errIfFailureAndReset("\"%s\"", keyword);
4148 assertEquals(keyword, expected, result.c_str());
4149 }
4150
4151 void
TestSetKeywordValue(void)4152 LocaleTest::TestSetKeywordValue(void) {
4153 static const struct {
4154 const char *keyword;
4155 const char *value;
4156 } testCases[] = {
4157 { "collation", "phonebook" },
4158 { "currency", "euro" },
4159 { "calendar", "buddhist" }
4160 };
4161
4162 IcuTestErrorCode status(*this, "TestSetKeywordValue()");
4163
4164 int32_t i = 0;
4165 int32_t resultLen = 0;
4166 char buffer[256];
4167
4168 Locale l(Locale::getGerman());
4169
4170 for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
4171 l.setKeywordValue(testCases[i].keyword, testCases[i].value, status);
4172 if(U_FAILURE(status)) {
4173 err("FAIL: Locale::setKeywordValue failed - %s\n", u_errorName(status));
4174 }
4175
4176 *buffer = 0;
4177 resultLen = l.getKeywordValue(testCases[i].keyword, buffer, 256, status);
4178 (void)resultLen; // Suppress unused variable warning.
4179 if(uprv_strcmp(testCases[i].value, buffer) != 0) {
4180 err("Expected to extract \"%s\" for keyword \"%s\". Got \"%s\" instead\n",
4181 testCases[i].value, testCases[i].keyword, buffer);
4182 }
4183 }
4184
4185 // Test long locale
4186 {
4187 status.errIfFailureAndReset();
4188 const char* input =
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";
4192 const char* expected =
4193 "de__POSIX@colnormalization=no;colstrength=primary;currency=eur;"
4194 "em=default;kv=space;lb=strict;lw=normal;measure=metric;"
4195 "numbers=latn;rg=atzzzz;sd=atat1;ss=none";
4196 // Bug ICU-21385
4197 Locale l2(input);
4198 l2.setKeywordValue("ss", "none", status);
4199 assertEquals("", expected, l2.getName());
4200 status.errIfFailureAndReset();
4201 }
4202 }
4203
4204 void
TestSetKeywordValueStringPiece(void)4205 LocaleTest::TestSetKeywordValueStringPiece(void) {
4206 IcuTestErrorCode status(*this, "TestSetKeywordValueStringPiece()");
4207 Locale l(Locale::getGerman());
4208
4209 l.setKeywordValue(StringPiece("collation"), StringPiece("phonebook"), status);
4210 l.setKeywordValue(StringPiece("calendarxxx", 8), StringPiece("buddhistxxx", 8), status);
4211
4212 static const char expected[] = "de@calendar=buddhist;collation=phonebook";
4213 assertEquals("", expected, l.getName());
4214 }
4215
4216 void
TestSetUnicodeKeywordValueStringPiece(void)4217 LocaleTest::TestSetUnicodeKeywordValueStringPiece(void) {
4218 IcuTestErrorCode status(*this, "TestSetUnicodeKeywordValueStringPiece()");
4219 Locale l(Locale::getGerman());
4220
4221 l.setUnicodeKeywordValue(StringPiece("co"), StringPiece("phonebk"), status);
4222 status.errIfFailureAndReset();
4223
4224 l.setUnicodeKeywordValue(StringPiece("caxxx", 2), StringPiece("buddhistxxx", 8), status);
4225 status.errIfFailureAndReset();
4226
4227 static const char expected[] = "de@calendar=buddhist;collation=phonebook";
4228 assertEquals("", expected, l.getName());
4229
4230 l.setUnicodeKeywordValue("cu", nullptr, status);
4231 status.errIfFailureAndReset();
4232 assertEquals("", expected, l.getName());
4233
4234 l.setUnicodeKeywordValue("!!", nullptr, status);
4235 assertEquals("status", U_ILLEGAL_ARGUMENT_ERROR, status.reset());
4236 assertEquals("", expected, l.getName());
4237
4238 l.setUnicodeKeywordValue("co", "!!", status);
4239 assertEquals("status", U_ILLEGAL_ARGUMENT_ERROR, status.reset());
4240 assertEquals("", expected, l.getName());
4241
4242 l.setUnicodeKeywordValue("co", nullptr, status);
4243 status.errIfFailureAndReset();
4244
4245 l.setUnicodeKeywordValue("ca", "", status);
4246 status.errIfFailureAndReset();
4247
4248 assertEquals("", Locale::getGerman().getName(), l.getName());
4249 }
4250
4251 void
TestGetBaseName(void)4252 LocaleTest::TestGetBaseName(void) {
4253 static const struct {
4254 const char *localeID;
4255 const char *baseName;
4256 } testCases[] = {
4257 { "de_DE@ C o ll A t i o n = Phonebook ", "de_DE" },
4258 { "de@currency = euro; CoLLaTion = PHONEBOOk", "de" },
4259 { "ja@calendar = buddhist", "ja" },
4260 { "de-u-co-phonebk", "de"}
4261 };
4262
4263 int32_t i = 0;
4264
4265 for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
4266 Locale loc(testCases[i].localeID);
4267 if(strcmp(testCases[i].baseName, loc.getBaseName())) {
4268 errln("For locale \"%s\" expected baseName \"%s\", but got \"%s\"",
4269 testCases[i].localeID, testCases[i].baseName, loc.getBaseName());
4270 return;
4271 }
4272 }
4273
4274 // Verify that adding a keyword to an existing Locale doesn't change the base name.
4275 UErrorCode status = U_ZERO_ERROR;
4276 Locale loc2("en-US");
4277 if (strcmp("en_US", loc2.getBaseName())) {
4278 errln("%s:%d Expected \"en_US\", got \"%s\"", __FILE__, __LINE__, loc2.getBaseName());
4279 }
4280 loc2.setKeywordValue("key", "value", status);
4281 if (strcmp("en_US@key=value", loc2.getName())) {
4282 errln("%s:%d Expected \"en_US@key=value\", got \"%s\"", __FILE__, __LINE__, loc2.getName());
4283 }
4284 if (strcmp("en_US", loc2.getBaseName())) {
4285 errln("%s:%d Expected \"en_US\", got \"%s\"", __FILE__, __LINE__, loc2.getBaseName());
4286 }
4287 }
4288
4289 /**
4290 * Compare two locale IDs. If they are equal, return 0. If `string'
4291 * starts with `prefix' plus an additional element, that is, string ==
4292 * prefix + '_' + x, then return 1. Otherwise return a value < 0.
4293 */
_loccmp(const char * string,const char * prefix)4294 static UBool _loccmp(const char* string, const char* prefix) {
4295 int32_t slen = (int32_t)strlen(string),
4296 plen = (int32_t)strlen(prefix);
4297 int32_t c = uprv_strncmp(string, prefix, plen);
4298 /* 'root' is "less than" everything */
4299 if (prefix[0] == '\0') {
4300 return string[0] != '\0';
4301 }
4302 if (c) return -1; /* mismatch */
4303 if (slen == plen) return 0;
4304 if (string[plen] == '_') return 1;
4305 return -2; /* false match, e.g. "en_USX" cmp "en_US" */
4306 }
4307
4308 /**
4309 * Check the relationship between requested locales, and report problems.
4310 * The caller specifies the expected relationships between requested
4311 * and valid (expReqValid) and between valid and actual (expValidActual).
4312 * Possible values are:
4313 * "gt" strictly greater than, e.g., en_US > en
4314 * "ge" greater or equal, e.g., en >= en
4315 * "eq" equal, e.g., en == en
4316 */
_checklocs(const char * label,const char * req,const Locale & validLoc,const Locale & actualLoc,const char * expReqValid,const char * expValidActual)4317 void LocaleTest::_checklocs(const char* label,
4318 const char* req,
4319 const Locale& validLoc,
4320 const Locale& actualLoc,
4321 const char* expReqValid,
4322 const char* expValidActual) {
4323 const char* valid = validLoc.getName();
4324 const char* actual = actualLoc.getName();
4325 int32_t reqValid = _loccmp(req, valid);
4326 int32_t validActual = _loccmp(valid, actual);
4327 if (((0 == uprv_strcmp(expReqValid, "gt") && reqValid > 0) ||
4328 (0 == uprv_strcmp(expReqValid, "ge") && reqValid >= 0) ||
4329 (0 == uprv_strcmp(expReqValid, "eq") && reqValid == 0)) &&
4330 ((0 == uprv_strcmp(expValidActual, "gt") && validActual > 0) ||
4331 (0 == uprv_strcmp(expValidActual, "ge") && validActual >= 0) ||
4332 (0 == uprv_strcmp(expValidActual, "eq") && validActual == 0))) {
4333 logln("%s; req=%s, valid=%s, actual=%s",
4334 label, req, valid, actual);
4335 } else {
4336 dataerrln("FAIL: %s; req=%s, valid=%s, actual=%s. Require (R %s V) and (V %s A)",
4337 label, req, valid, actual,
4338 expReqValid, expValidActual);
4339 }
4340 }
4341
TestGetLocale(void)4342 void LocaleTest::TestGetLocale(void) {
4343 #if !UCONFIG_NO_SERVICE
4344 const char *req;
4345 Locale valid, actual, reqLoc;
4346
4347 // Calendar
4348 #if !UCONFIG_NO_FORMATTING
4349 {
4350 UErrorCode ec = U_ZERO_ERROR; // give each resource type its own error code
4351 req = "en_US_BROOKLYN";
4352 Calendar* cal = Calendar::createInstance(Locale::createFromName(req), ec);
4353 if (U_FAILURE(ec)) {
4354 dataerrln("FAIL: Calendar::createInstance failed - %s", u_errorName(ec));
4355 } else {
4356 valid = cal->getLocale(ULOC_VALID_LOCALE, ec);
4357 actual = cal->getLocale(ULOC_ACTUAL_LOCALE, ec);
4358 if (U_FAILURE(ec)) {
4359 errln("FAIL: Calendar::getLocale() failed");
4360 } else {
4361 _checklocs("Calendar", req, valid, actual);
4362 }
4363 /* Make sure that it fails correctly */
4364 ec = U_FILE_ACCESS_ERROR;
4365 if (cal->getLocale(ULOC_VALID_LOCALE, ec).getName()[0] != 0) {
4366 errln("FAIL: Calendar::getLocale() failed to fail correctly. It should have returned \"\"");
4367 }
4368 ec = U_ZERO_ERROR;
4369 }
4370 delete cal;
4371 }
4372 #endif
4373
4374 // DecimalFormat, DecimalFormatSymbols
4375 #if !UCONFIG_NO_FORMATTING
4376 {
4377 UErrorCode ec = U_ZERO_ERROR; // give each resource type its own error code
4378 req = "fr_FR_NICE";
4379 NumberFormat* nf = NumberFormat::createInstance(Locale::createFromName(req), ec);
4380 if (U_FAILURE(ec)) {
4381 dataerrln("FAIL: NumberFormat::createInstance failed - %s", u_errorName(ec));
4382 } else {
4383 DecimalFormat* dec = dynamic_cast<DecimalFormat*>(nf);
4384 if (dec == NULL) {
4385 errln("FAIL: NumberFormat::createInstance does not return a DecimalFormat");
4386 return;
4387 }
4388 valid = dec->getLocale(ULOC_VALID_LOCALE, ec);
4389 actual = dec->getLocale(ULOC_ACTUAL_LOCALE, ec);
4390 if (U_FAILURE(ec)) {
4391 errln("FAIL: DecimalFormat::getLocale() failed");
4392 } else {
4393 _checklocs("DecimalFormat", req, valid, actual);
4394 }
4395
4396 const DecimalFormatSymbols* sym = dec->getDecimalFormatSymbols();
4397 if (sym == NULL) {
4398 errln("FAIL: getDecimalFormatSymbols returned NULL");
4399 return;
4400 }
4401 valid = sym->getLocale(ULOC_VALID_LOCALE, ec);
4402 actual = sym->getLocale(ULOC_ACTUAL_LOCALE, ec);
4403 if (U_FAILURE(ec)) {
4404 errln("FAIL: DecimalFormatSymbols::getLocale() failed");
4405 } else {
4406 _checklocs("DecimalFormatSymbols", req, valid, actual);
4407 }
4408 }
4409 delete nf;
4410 }
4411 #endif
4412
4413 // DateFormat, DateFormatSymbols
4414 #if !UCONFIG_NO_FORMATTING
4415 {
4416 UErrorCode ec = U_ZERO_ERROR; // give each resource type its own error code
4417 req = "de_CH_LUCERNE";
4418 DateFormat* df =
4419 DateFormat::createDateInstance(DateFormat::kDefault,
4420 Locale::createFromName(req));
4421 if (df == 0){
4422 dataerrln("Error calling DateFormat::createDateInstance()");
4423 } else {
4424 SimpleDateFormat* dat = dynamic_cast<SimpleDateFormat*>(df);
4425 if (dat == NULL) {
4426 errln("FAIL: DateFormat::createInstance does not return a SimpleDateFormat");
4427 return;
4428 }
4429 valid = dat->getLocale(ULOC_VALID_LOCALE, ec);
4430 actual = dat->getLocale(ULOC_ACTUAL_LOCALE, ec);
4431 if (U_FAILURE(ec)) {
4432 errln("FAIL: SimpleDateFormat::getLocale() failed");
4433 } else {
4434 _checklocs("SimpleDateFormat", req, valid, actual);
4435 }
4436
4437 const DateFormatSymbols* sym = dat->getDateFormatSymbols();
4438 if (sym == NULL) {
4439 errln("FAIL: getDateFormatSymbols returned NULL");
4440 return;
4441 }
4442 valid = sym->getLocale(ULOC_VALID_LOCALE, ec);
4443 actual = sym->getLocale(ULOC_ACTUAL_LOCALE, ec);
4444 if (U_FAILURE(ec)) {
4445 errln("FAIL: DateFormatSymbols::getLocale() failed");
4446 } else {
4447 _checklocs("DateFormatSymbols", req, valid, actual);
4448 }
4449 }
4450 delete df;
4451 }
4452 #endif
4453
4454 // BreakIterator
4455 #if !UCONFIG_NO_BREAK_ITERATION
4456 {
4457 UErrorCode ec = U_ZERO_ERROR; // give each resource type its own error code
4458 req = "es_ES_BARCELONA";
4459 reqLoc = Locale::createFromName(req);
4460 BreakIterator* brk = BreakIterator::createWordInstance(reqLoc, ec);
4461 if (U_FAILURE(ec)) {
4462 dataerrln("FAIL: BreakIterator::createWordInstance failed - %s", u_errorName(ec));
4463 } else {
4464 valid = brk->getLocale(ULOC_VALID_LOCALE, ec);
4465 actual = brk->getLocale(ULOC_ACTUAL_LOCALE, ec);
4466 if (U_FAILURE(ec)) {
4467 errln("FAIL: BreakIterator::getLocale() failed");
4468 } else {
4469 _checklocs("BreakIterator", req, valid, actual);
4470 }
4471
4472 // After registering something, the behavior should be different
4473 URegistryKey key = BreakIterator::registerInstance(brk, reqLoc, UBRK_WORD, ec);
4474 brk = 0; // registerInstance adopts
4475 if (U_FAILURE(ec)) {
4476 errln("FAIL: BreakIterator::registerInstance() failed");
4477 } else {
4478 brk = BreakIterator::createWordInstance(reqLoc, ec);
4479 if (U_FAILURE(ec)) {
4480 errln("FAIL: BreakIterator::createWordInstance failed");
4481 } else {
4482 valid = brk->getLocale(ULOC_VALID_LOCALE, ec);
4483 actual = brk->getLocale(ULOC_ACTUAL_LOCALE, ec);
4484 if (U_FAILURE(ec)) {
4485 errln("FAIL: BreakIterator::getLocale() failed");
4486 } else {
4487 // N.B.: now expect valid==actual==req
4488 _checklocs("BreakIterator(registered)",
4489 req, valid, actual, "eq", "eq");
4490 }
4491 }
4492 // No matter what, unregister
4493 BreakIterator::unregister(key, ec);
4494 if (U_FAILURE(ec)) {
4495 errln("FAIL: BreakIterator::unregister() failed");
4496 }
4497 delete brk;
4498 brk = 0;
4499 }
4500
4501 // After unregistering, should behave normally again
4502 brk = BreakIterator::createWordInstance(reqLoc, ec);
4503 if (U_FAILURE(ec)) {
4504 errln("FAIL: BreakIterator::createWordInstance failed");
4505 } else {
4506 valid = brk->getLocale(ULOC_VALID_LOCALE, ec);
4507 actual = brk->getLocale(ULOC_ACTUAL_LOCALE, ec);
4508 if (U_FAILURE(ec)) {
4509 errln("FAIL: BreakIterator::getLocale() failed");
4510 } else {
4511 _checklocs("BreakIterator(unregistered)", req, valid, actual);
4512 }
4513 }
4514 }
4515 delete brk;
4516 }
4517 #endif
4518
4519 // Collator
4520 #if !UCONFIG_NO_COLLATION
4521 {
4522 UErrorCode ec = U_ZERO_ERROR; // give each resource type its own error code
4523
4524 checkRegisteredCollators(NULL); // Don't expect any extras
4525
4526 req = "hi_IN_BHOPAL";
4527 reqLoc = Locale::createFromName(req);
4528 Collator* coll = Collator::createInstance(reqLoc, ec);
4529 if (U_FAILURE(ec)) {
4530 dataerrln("FAIL: Collator::createInstance failed - %s", u_errorName(ec));
4531 } else {
4532 valid = coll->getLocale(ULOC_VALID_LOCALE, ec);
4533 actual = coll->getLocale(ULOC_ACTUAL_LOCALE, ec);
4534 if (U_FAILURE(ec)) {
4535 errln("FAIL: Collator::getLocale() failed");
4536 } else {
4537 _checklocs("Collator", req, valid, actual);
4538 }
4539
4540 // After registering something, the behavior should be different
4541 URegistryKey key = Collator::registerInstance(coll, reqLoc, ec);
4542 coll = 0; // registerInstance adopts
4543 if (U_FAILURE(ec)) {
4544 errln("FAIL: Collator::registerInstance() failed");
4545 } else {
4546 coll = Collator::createInstance(reqLoc, ec);
4547 if (U_FAILURE(ec)) {
4548 errln("FAIL: Collator::createWordInstance failed");
4549 } else {
4550 valid = coll->getLocale(ULOC_VALID_LOCALE, ec);
4551 actual = coll->getLocale(ULOC_ACTUAL_LOCALE, ec);
4552 if (U_FAILURE(ec)) {
4553 errln("FAIL: Collator::getLocale() failed");
4554 } else {
4555 // N.B.: now expect valid==actual==req
4556 _checklocs("Collator(registered)",
4557 req, valid, actual, "eq", "eq");
4558 }
4559 }
4560 checkRegisteredCollators(req); // include hi_IN_BHOPAL
4561
4562 // No matter what, unregister
4563 Collator::unregister(key, ec);
4564 if (U_FAILURE(ec)) {
4565 errln("FAIL: Collator::unregister() failed");
4566 }
4567 delete coll;
4568 coll = 0;
4569 }
4570
4571 // After unregistering, should behave normally again
4572 coll = Collator::createInstance(reqLoc, ec);
4573 if (U_FAILURE(ec)) {
4574 errln("FAIL: Collator::createInstance failed");
4575 } else {
4576 valid = coll->getLocale(ULOC_VALID_LOCALE, ec);
4577 actual = coll->getLocale(ULOC_ACTUAL_LOCALE, ec);
4578 if (U_FAILURE(ec)) {
4579 errln("FAIL: Collator::getLocale() failed");
4580 } else {
4581 _checklocs("Collator(unregistered)", req, valid, actual);
4582 }
4583 }
4584 }
4585 delete coll;
4586
4587 checkRegisteredCollators(NULL); // extra should be gone again
4588 }
4589 #endif
4590 #endif
4591 }
4592
4593 #if !UCONFIG_NO_COLLATION
4594 /**
4595 * Compare Collator::getAvailableLocales(int) [ "old", returning an array ]
4596 * with Collator::getAvailableLocales() [ "new", returning a StringEnumeration ]
4597 * These should be identical (check their API docs) EXCEPT that
4598 * if expectExtra is non-NULL, it will be in the "new" array but not "old".
4599 * Does not return any status but calls errln on error.
4600 * @param expectExtra an extra locale, will be in "new" but not "old". Or NULL.
4601 */
checkRegisteredCollators(const char * expectExtra)4602 void LocaleTest::checkRegisteredCollators(const char *expectExtra) {
4603 UErrorCode status = U_ZERO_ERROR;
4604 int32_t count1=0,count2=0;
4605 Hashtable oldHash(status);
4606 Hashtable newHash(status);
4607 assertSuccess(WHERE, status);
4608
4609 UnicodeString expectStr(expectExtra?expectExtra:"n/a", "");
4610
4611 // the 'old' list (non enumeration)
4612 const Locale* oldList = Collator::getAvailableLocales(count1);
4613 if(oldList == NULL) {
4614 dataerrln("Error: Collator::getAvailableLocales(count) returned NULL");
4615 return;
4616 }
4617
4618 // the 'new' list (enumeration)
4619 LocalPointer<StringEnumeration> newEnum(Collator::getAvailableLocales());
4620 if(newEnum.isNull()) {
4621 errln("Error: collator::getAvailableLocales() returned NULL");
4622 return;
4623 }
4624
4625 // OK. Let's add all of the OLD
4626 // then check for any in the NEW not in OLD
4627 // then check for any in OLD not in NEW.
4628
4629 // 1. add all of OLD
4630 for(int32_t i=0;i<count1;i++) {
4631 const UnicodeString key(oldList[i].getName(), "");
4632 int32_t oldI = oldHash.puti(key, 1, status);
4633 if( oldI == 1 ){
4634 errln("Error: duplicate key %s in Collator::getAvailableLocales(count) list.\n",
4635 oldList[i].getName());
4636 return;
4637 }
4638 if(expectExtra != NULL && !strcmp(expectExtra, oldList[i].getName())) {
4639 errln("Inexplicably, Collator::getAvailableCollators(count) had registered collator %s. This shouldn't happen, so I am going to consider it an error.\n", expectExtra);
4640 }
4641 }
4642
4643 // 2. add all of NEW
4644 const UnicodeString *locStr;
4645 UBool foundExpected = FALSE;
4646 while((locStr = newEnum->snext(status)) && U_SUCCESS(status)) {
4647 count2++;
4648
4649 if(expectExtra != NULL && expectStr == *locStr) {
4650 foundExpected = TRUE;
4651 logln(UnicodeString("Found expected registered collator: ","") + expectStr);
4652 }
4653 (void)foundExpected; // Hush unused variable compiler warning.
4654
4655 if( oldHash.geti(*locStr) == 0 ) {
4656 if(expectExtra != NULL && expectStr==*locStr) {
4657 logln(UnicodeString("As expected, Collator::getAvailableLocales(count) is missing registered collator ") + expectStr);
4658 } else {
4659 errln(UnicodeString("Error: Collator::getAvailableLocales(count) is missing: ","")
4660 + *locStr);
4661 }
4662 }
4663 newHash.puti(*locStr, 1, status);
4664 }
4665
4666 // 3. check all of OLD again
4667 for(int32_t i=0;i<count1;i++) {
4668 const UnicodeString key(oldList[i].getName(), "");
4669 int32_t newI = newHash.geti(key);
4670 if(newI == 0) {
4671 errln(UnicodeString("Error: Collator::getAvailableLocales() is missing: ","")
4672 + key);
4673 }
4674 }
4675
4676 int32_t expectCount2 = count1;
4677 if(expectExtra != NULL) {
4678 expectCount2 ++; // if an extra item registered, bump the expect count
4679 }
4680
4681 assertEquals("Collator::getAvail() count", expectCount2, count2);
4682 }
4683 #endif
4684
4685
4686
TestVariantWithOutCountry(void)4687 void LocaleTest::TestVariantWithOutCountry(void) {
4688 Locale loc("en","","POSIX");
4689 if (0 != strcmp(loc.getVariant(), "POSIX")) {
4690 errln("FAIL: en__POSIX didn't get parsed correctly - name is %s - expected %s got %s", loc.getName(), "POSIX", loc.getVariant());
4691 }
4692 Locale loc2("en","","FOUR");
4693 if (0 != strcmp(loc2.getVariant(), "FOUR")) {
4694 errln("FAIL: en__FOUR didn't get parsed correctly - name is %s - expected %s got %s", loc2.getName(), "FOUR", loc2.getVariant());
4695 }
4696 Locale loc3("en","Latn","","FOUR");
4697 if (0 != strcmp(loc3.getVariant(), "FOUR")) {
4698 errln("FAIL: en_Latn__FOUR didn't get parsed correctly - name is %s - expected %s got %s", loc3.getName(), "FOUR", loc3.getVariant());
4699 }
4700 Locale loc4("","Latn","","FOUR");
4701 if (0 != strcmp(loc4.getVariant(), "FOUR")) {
4702 errln("FAIL: _Latn__FOUR didn't get parsed correctly - name is %s - expected %s got %s", loc4.getName(), "FOUR", loc4.getVariant());
4703 }
4704 Locale loc5("","Latn","US","FOUR");
4705 if (0 != strcmp(loc5.getVariant(), "FOUR")) {
4706 errln("FAIL: _Latn_US_FOUR didn't get parsed correctly - name is %s - expected %s got %s", loc5.getName(), "FOUR", loc5.getVariant());
4707 }
4708 Locale loc6("de-1901");
4709 if (0 != strcmp(loc6.getVariant(), "1901")) {
4710 errln("FAIL: de-1901 didn't get parsed correctly - name is %s - expected %s got %s", loc6.getName(), "1901", loc6.getVariant());
4711 }
4712 }
4713
_canonicalize(int32_t selector,const char * localeID)4714 static Locale _canonicalize(int32_t selector, /* 0==createFromName, 1==createCanonical, 2==Locale ct */
4715 const char* localeID) {
4716 switch (selector) {
4717 case 0:
4718 return Locale::createFromName(localeID);
4719 case 1:
4720 return Locale::createCanonical(localeID);
4721 case 2:
4722 return Locale(localeID);
4723 default:
4724 return Locale("");
4725 }
4726 }
4727
TestCanonicalization(void)4728 void LocaleTest::TestCanonicalization(void)
4729 {
4730 static const struct {
4731 const char *localeID; /* input */
4732 const char *getNameID; /* expected getName() result */
4733 const char *canonicalID; /* expected canonicalize() result */
4734 } testCases[] = {
4735 { "ca_ES-with-extra-stuff-that really doesn't make any sense-unless-you're trying to increase code coverage",
4736 "ca_ES_WITH_EXTRA_STUFF_THAT REALLY DOESN'T MAKE ANY SENSE_UNLESS_YOU'RE TRYING TO INCREASE CODE COVERAGE",
4737 "ca_ES_EXTRA_STUFF_THAT REALLY DOESN'T MAKE ANY SENSE_UNLESS_WITH_YOU'RE TRYING TO INCREASE CODE COVERAGE"},
4738 { "zh@collation=pinyin", "zh@collation=pinyin", "zh@collation=pinyin" },
4739 { "zh_CN@collation=pinyin", "zh_CN@collation=pinyin", "zh_CN@collation=pinyin" },
4740 { "zh_CN_CA@collation=pinyin", "zh_CN_CA@collation=pinyin", "zh_CN_CA@collation=pinyin" },
4741 { "en_US_POSIX", "en_US_POSIX", "en_US_POSIX" },
4742 { "hy_AM_REVISED", "hy_AM_REVISED", "hy_AM_REVISED" },
4743 { "no_NO_NY", "no_NO_NY", "no_NO_NY" /* not: "nn_NO" [alan ICU3.0] */ },
4744 { "no@ny", "no@ny", "no__NY" /* not: "nn" [alan ICU3.0] */ }, /* POSIX ID */
4745 { "no-no.utf32@B", "no_NO.utf32@B", "no_NO_B" }, /* POSIX ID */
4746 { "qz-qz@Euro", "qz_QZ@Euro", "qz_QZ_EURO" }, /* qz-qz uses private use iso codes */
4747 // NOTE: uloc_getName() works on en-BOONT, but Locale() parser considers it BOGUS
4748 // TODO: unify this behavior
4749 { "en-BOONT", "en__BOONT", "en__BOONT" }, /* registered name */
4750 { "de-1901", "de__1901", "de__1901" }, /* registered name */
4751 { "de-1906", "de__1906", "de__1906" }, /* registered name */
4752 // New in CLDR 39 / ICU 69
4753 { "nb", "nb", "nb" },
4754
4755 /* posix behavior that used to be performed by getName */
4756 { "mr.utf8", "mr.utf8", "mr" },
4757 { "de-tv.koi8r", "de_TV.koi8r", "de_TV" },
4758 { "x-piglatin_ML.MBE", "x-piglatin_ML.MBE", "x-piglatin_ML" },
4759 { "i-cherokee_US.utf7", "i-cherokee_US.utf7", "i-cherokee_US" },
4760 { "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA" },
4761 { "no-no-ny.utf8@B", "no_NO_NY.utf8@B", "no_NO_B_NY" /* not: "nn_NO" [alan ICU3.0] */ }, /* @ ignored unless variant is empty */
4762
4763 /* fleshing out canonicalization */
4764 /* trim space and sort keywords, ';' is separator so not present at end in canonical form */
4765 { "en_Hant_IL_VALLEY_GIRL@ currency = EUR; calendar = Japanese ;",
4766 "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR",
4767 "en_Hant_IL_GIRL_VALLEY@calendar=Japanese;currency=EUR" },
4768 /* already-canonical ids are not changed */
4769 { "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR",
4770 "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR",
4771 "en_Hant_IL_GIRL_VALLEY@calendar=Japanese;currency=EUR" },
4772 /* norwegian is just too weird, if we handle things in their full generality */
4773 { "no-Hant-GB_NY@currency=$$$", "no_Hant_GB_NY@currency=$$$", "no_Hant_GB_NY@currency=$$$" /* not: "nn_Hant_GB@currency=$$$" [alan ICU3.0] */ },
4774
4775 /* test cases reflecting internal resource bundle usage */
4776 { "root@kw=foo", "root@kw=foo", "root@kw=foo" },
4777 { "@calendar=gregorian", "@calendar=gregorian", "@calendar=gregorian" },
4778 { "ja_JP@calendar=Japanese", "ja_JP@calendar=Japanese", "ja_JP@calendar=Japanese" },
4779
4780 // Before ICU 64, ICU locale canonicalization had some additional mappings.
4781 // They were removed for ICU-20187 "drop support for long-obsolete locale ID variants".
4782 // The following now use standard canonicalization.
4783 { "", "", "" },
4784 { "C", "c", "c" },
4785 { "POSIX", "posix", "posix" },
4786 { "ca_ES_PREEURO", "ca_ES_PREEURO", "ca_ES_PREEURO" },
4787 { "de_AT_PREEURO", "de_AT_PREEURO", "de_AT_PREEURO" },
4788 { "de_DE_PREEURO", "de_DE_PREEURO", "de_DE_PREEURO" },
4789 { "de_LU_PREEURO", "de_LU_PREEURO", "de_LU_PREEURO" },
4790 { "el_GR_PREEURO", "el_GR_PREEURO", "el_GR_PREEURO" },
4791 { "en_BE_PREEURO", "en_BE_PREEURO", "en_BE_PREEURO" },
4792 { "en_IE_PREEURO", "en_IE_PREEURO", "en_IE_PREEURO" },
4793 { "es_ES_PREEURO", "es_ES_PREEURO", "es_ES_PREEURO" },
4794 { "eu_ES_PREEURO", "eu_ES_PREEURO", "eu_ES_PREEURO" },
4795 { "fi_FI_PREEURO", "fi_FI_PREEURO", "fi_FI_PREEURO" },
4796 { "fr_BE_PREEURO", "fr_BE_PREEURO", "fr_BE_PREEURO" },
4797 { "fr_FR_PREEURO", "fr_FR_PREEURO", "fr_FR_PREEURO" },
4798 { "fr_LU_PREEURO", "fr_LU_PREEURO", "fr_LU_PREEURO" },
4799 { "ga_IE_PREEURO", "ga_IE_PREEURO", "ga_IE_PREEURO" },
4800 { "gl_ES_PREEURO", "gl_ES_PREEURO", "gl_ES_PREEURO" },
4801 { "it_IT_PREEURO", "it_IT_PREEURO", "it_IT_PREEURO" },
4802 { "nl_BE_PREEURO", "nl_BE_PREEURO", "nl_BE_PREEURO" },
4803 { "nl_NL_PREEURO", "nl_NL_PREEURO", "nl_NL_PREEURO" },
4804 { "pt_PT_PREEURO", "pt_PT_PREEURO", "pt_PT_PREEURO" },
4805 { "de__PHONEBOOK", "de__PHONEBOOK", "de__PHONEBOOK" },
4806 { "en_GB_EURO", "en_GB_EURO", "en_GB_EURO" },
4807 { "en_GB@EURO", "en_GB@EURO", "en_GB_EURO" }, /* POSIX ID */
4808 { "es__TRADITIONAL", "es__TRADITIONAL", "es__TRADITIONAL" },
4809 { "hi__DIRECT", "hi__DIRECT", "hi__DIRECT" },
4810 { "ja_JP_TRADITIONAL", "ja_JP_TRADITIONAL", "ja_JP_TRADITIONAL" },
4811 { "th_TH_TRADITIONAL", "th_TH_TRADITIONAL", "th_TH_TRADITIONAL" },
4812 { "zh_TW_STROKE", "zh_TW_STROKE", "zh_TW_STROKE" },
4813 { "zh__PINYIN", "zh__PINYIN", "zh__PINYIN" },
4814 { "sr-SP-Cyrl", "sr_SP_CYRL", "sr_SP_CYRL" }, /* .NET name */
4815 { "sr-SP-Latn", "sr_SP_LATN", "sr_SP_LATN" }, /* .NET name */
4816 { "sr_YU_CYRILLIC", "sr_YU_CYRILLIC", "sr_RS_CYRILLIC" }, /* Linux name */
4817 { "uz-UZ-Cyrl", "uz_UZ_CYRL", "uz_UZ_CYRL" }, /* .NET name */
4818 { "uz-UZ-Latn", "uz_UZ_LATN", "uz_UZ_LATN" }, /* .NET name */
4819 { "zh-CHS", "zh_CHS", "zh_CHS" }, /* .NET name */
4820 { "zh-CHT", "zh_CHT", "zh_CHT" }, /* .NET name This may change back to zh_Hant */
4821 /* PRE_EURO and EURO conversions don't affect other keywords */
4822 { "es_ES_PREEURO@CALendar=Japanese", "es_ES_PREEURO@calendar=Japanese", "es_ES_PREEURO@calendar=Japanese" },
4823 { "es_ES_EURO@SHOUT=zipeedeedoodah", "es_ES_EURO@shout=zipeedeedoodah", "es_ES_EURO@shout=zipeedeedoodah" },
4824 /* currency keyword overrides PRE_EURO and EURO currency */
4825 { "es_ES_PREEURO@currency=EUR", "es_ES_PREEURO@currency=EUR", "es_ES_PREEURO@currency=EUR" },
4826 { "es_ES_EURO@currency=ESP", "es_ES_EURO@currency=ESP", "es_ES_EURO@currency=ESP" },
4827 };
4828
4829 static const char* label[] = { "createFromName", "createCanonical", "Locale" };
4830
4831 int32_t i, j;
4832
4833 for (i=0; i < UPRV_LENGTHOF(testCases); i++) {
4834 for (j=0; j<3; ++j) {
4835 const char* expected = (j==1) ? testCases[i].canonicalID : testCases[i].getNameID;
4836 Locale loc = _canonicalize(j, testCases[i].localeID);
4837 const char* getName = loc.isBogus() ? "BOGUS" : loc.getName();
4838 if(uprv_strcmp(expected, getName) != 0) {
4839 errln("FAIL: %s(%s).getName() => \"%s\", expected \"%s\"",
4840 label[j], testCases[i].localeID, getName, expected);
4841 } else {
4842 logln("Ok: %s(%s) => \"%s\"",
4843 label[j], testCases[i].localeID, getName);
4844 }
4845 }
4846 }
4847 }
4848
TestCanonicalize(void)4849 void LocaleTest::TestCanonicalize(void)
4850 {
4851 static const struct {
4852 const char *localeID; /* input */
4853 const char *canonicalID; /* expected canonicalize() result */
4854 } testCases[] = {
4855 // language _ variant -> language
4856 { "no-BOKMAL", "nb" },
4857 // also test with script, country and extensions
4858 { "no-Cyrl-ID-BOKMAL-u-ca-japanese", "nb-Cyrl-ID-u-ca-japanese" },
4859 { "no-Cyrl-ID-1901-BOKMAL-xsistemo-u-ca-japanese", "nb-Cyrl-ID-1901-xsistemo-u-ca-japanese" },
4860 { "no-Cyrl-ID-1901-BOKMAL-u-ca-japanese", "nb-Cyrl-ID-1901-u-ca-japanese" },
4861 { "no-Cyrl-ID-BOKMAL-xsistemo-u-ca-japanese", "nb-Cyrl-ID-xsistemo-u-ca-japanese" },
4862 { "no-NYNORSK", "nn" },
4863 { "no-Cyrl-ID-NYNORSK-u-ca-japanese", "nn-Cyrl-ID-u-ca-japanese" },
4864 { "aa-SAAHO", "ssy" },
4865 // also test with script, country and extensions
4866 { "aa-Deva-IN-SAAHO-u-ca-japanese", "ssy-Deva-IN-u-ca-japanese" },
4867
4868 // language -> language
4869 { "aam", "aas" },
4870 // also test with script, country, variants and extensions
4871 { "aam-Cyrl-ID-3456-u-ca-japanese", "aas-Cyrl-ID-3456-u-ca-japanese" },
4872
4873 // language -> language _ Script
4874 { "sh", "sr-Latn" },
4875 // also test with script
4876 { "sh-Cyrl", "sr-Cyrl" },
4877 // also test with country, variants and extensions
4878 { "sh-ID-3456-u-ca-roc", "sr-Latn-ID-3456-u-ca-roc" },
4879
4880 // language -> language _ country
4881 { "prs", "fa-AF" },
4882 // also test with country
4883 { "prs-RU", "fa-RU" },
4884 // also test with script, variants and extensions
4885 { "prs-Cyrl-1009-u-ca-roc", "fa-Cyrl-AF-1009-u-ca-roc" },
4886
4887 { "pa-IN", "pa-IN" },
4888 // also test with script
4889 { "pa-Latn-IN", "pa-Latn-IN" },
4890 // also test with variants and extensions
4891 { "pa-IN-5678-u-ca-hindi", "pa-IN-5678-u-ca-hindi" },
4892
4893 { "ky-Cyrl-KG", "ky-Cyrl-KG" },
4894 // also test with variants and extensions
4895 { "ky-Cyrl-KG-3456-u-ca-roc", "ky-Cyrl-KG-3456-u-ca-roc" },
4896
4897 // Test replacement of scriptAlias
4898 { "en-Qaai", "en-Zinh" },
4899
4900 // Test replacement of territoryAlias
4901 // 554 has one replacement
4902 { "en-554", "en-NZ" },
4903 { "en-554-u-nu-arab", "en-NZ-u-nu-arab" },
4904 // 172 has multiple replacements
4905 // also test with variants
4906 { "ru-172-1234", "ru-RU-1234" },
4907 // also test with extensions
4908 { "ru-172-1234-u-nu-latn", "ru-RU-1234-u-nu-latn" },
4909 // also test with scripts
4910 { "uz-172", "uz-UZ" },
4911 { "uz-Cyrl-172", "uz-Cyrl-UZ" },
4912 { "uz-Bopo-172", "uz-Bopo-UZ" },
4913 // also test with variants and scripts
4914 { "uz-Cyrl-172-5678-u-nu-latn", "uz-Cyrl-UZ-5678-u-nu-latn" },
4915 // a language not used in this region
4916 { "fr-172", "fr-RU" },
4917
4918 // variant
4919 { "ja-Latn-hepburn-heploc", "ja-Latn-alalc97"},
4920
4921 { "aaa-Fooo-SU", "aaa-Fooo-RU"},
4922
4923 // ICU-21344
4924 { "ku-Arab-NT", "ku-Arab-IQ"},
4925
4926 // ICU-21402
4927 { "und-u-rg-no23", "und-u-rg-no50"},
4928 { "und-u-rg-cn11", "und-u-rg-cnbj"},
4929 { "und-u-rg-cz10a", "und-u-rg-cz110"},
4930 { "und-u-rg-fra", "und-u-rg-frges"},
4931 { "und-u-rg-frg", "und-u-rg-frges"},
4932 { "und-u-rg-lud", "und-u-rg-lucl"},
4933
4934 { "und-NO-u-sd-no23", "und-NO-u-sd-no50"},
4935 { "und-CN-u-sd-cn11", "und-CN-u-sd-cnbj"},
4936 { "und-CZ-u-sd-cz10a", "und-CZ-u-sd-cz110"},
4937 { "und-FR-u-sd-fra", "und-FR-u-sd-frges"},
4938 { "und-FR-u-sd-frg", "und-FR-u-sd-frges"},
4939 { "und-LU-u-sd-lud", "und-LU-u-sd-lucl"},
4940
4941 // ICU-21550
4942 { "und-u-rg-fi01", "und-u-rg-axzzzz"},
4943 { "und-u-rg-frcp", "und-u-rg-cpzzzz"},
4944 { "und-u-rg-frpm", "und-u-rg-pmzzzz"},
4945 { "und-u-rg-usvi", "und-u-rg-vizzzz"},
4946 { "und-u-rg-cn91", "und-u-rg-hkzzzz"},
4947 { "und-u-rg-nlaw", "und-u-rg-awzzzz"},
4948
4949 { "und-NO-u-sd-frre", "und-NO-u-sd-rezzzz"},
4950 { "und-CN-u-sd-nlcw", "und-CN-u-sd-cwzzzz"},
4951 { "und-CZ-u-sd-usgu", "und-CZ-u-sd-guzzzz"},
4952 { "und-FR-u-sd-shta", "und-FR-u-sd-tazzzz"},
4953 { "und-FR-u-sd-cn71", "und-FR-u-sd-twzzzz"},
4954
4955
4956 // ICU-21401
4957 { "cel-gaulish", "xtg"},
4958
4959 // ICU-21406
4960 // Inside T extension
4961 // Case of Script and Region
4962 { "ja-kana-jp-t-it-latn-it", "ja-Kana-JP-t-it-latn-it"},
4963 { "und-t-zh-hani-tw", "und-t-zh-hani-tw"},
4964 { "und-cyrl-t-und-Latn", "und-Cyrl-t-und-latn"},
4965 // Order of singleton
4966 { "und-u-ca-roc-t-zh", "und-t-zh-u-ca-roc"},
4967 // Variant subtags are alphabetically ordered.
4968 { "sl-t-sl-rozaj-biske-1994", "sl-t-sl-1994-biske-rozaj"},
4969 // tfield subtags are alphabetically ordered.
4970 // (Also tests subtag case normalisation.)
4971 { "DE-T-lv-M0-DIN", "de-t-lv-m0-din"},
4972 { "DE-T-M0-DIN-K0-QWERTZ", "de-t-k0-qwertz-m0-din"},
4973 { "DE-T-lv-M0-DIN-K0-QWERTZ", "de-t-lv-k0-qwertz-m0-din"},
4974 // "true" tvalue subtags aren't removed.
4975 // (UTS 35 version 36, §3.2.1 claims otherwise, but tkey must be followed by
4976 // tvalue, so that's likely a spec bug in UTS 35.)
4977 { "en-t-m0-true", "en-t-m0-true"},
4978 // tlang subtags are canonicalised.
4979 { "en-t-iw", "en-t-he"},
4980 { "en-t-hy-latn-SU", "en-t-hy-latn-am"},
4981 { "ru-t-ru-cyrl-SU", "ru-t-ru-cyrl-ru"},
4982 { "fr-t-fr-172", "fr-t-fr-ru"},
4983 { "und-t-no-latn-BOKMAL", "und-t-nb-latn" },
4984 { "und-t-sgn-qAAi-NL", "und-t-dse-zinh" },
4985 // alias of tvalue should be replaced
4986 { "en-t-m0-NaMeS", "en-t-m0-prprname" },
4987 { "en-t-s0-ascii-d0-NaMe", "en-t-d0-charname-s0-ascii" },
4988
4989 };
4990 int32_t i;
4991 for (i=0; i < UPRV_LENGTHOF(testCases); i++) {
4992 UErrorCode status = U_ZERO_ERROR;
4993 std::string otag = testCases[i].localeID;
4994 Locale loc = Locale::forLanguageTag(otag.c_str(), status);
4995 loc.canonicalize(status);
4996 std::string tag = loc.toLanguageTag<std::string>(status);
4997 if (tag != testCases[i].canonicalID) {
4998 errcheckln(status, "FAIL: %s should be canonicalized to %s but got %s - %s",
4999 otag.c_str(),
5000 testCases[i].canonicalID,
5001 tag.c_str(),
5002 u_errorName(status));
5003 }
5004 }
5005 }
5006
TestCurrencyByDate(void)5007 void LocaleTest::TestCurrencyByDate(void)
5008 {
5009 #if !UCONFIG_NO_FORMATTING
5010 UErrorCode status = U_ZERO_ERROR;
5011 UDate date = uprv_getUTCtime();
5012 UChar TMP[4] = {0, 0, 0, 0};
5013 int32_t index = 0;
5014 int32_t resLen = 0;
5015 UnicodeString tempStr, resultStr;
5016
5017 // Cycle through historical currencies
5018 date = (UDate)-630720000000.0; // pre 1961 - no currency defined
5019 index = ucurr_countCurrencies("eo_AM", date, &status);
5020 if (index != 0)
5021 {
5022 errcheckln(status, "FAIL: didn't return 0 for eo_AM - %s", u_errorName(status));
5023 }
5024 resLen = ucurr_forLocaleAndDate("eo_AM", date, index, TMP, 4, &status);
5025 if (resLen != 0) {
5026 errcheckln(status, "FAIL: eo_AM didn't return NULL - %s", u_errorName(status));
5027 }
5028 status = U_ZERO_ERROR;
5029
5030 date = (UDate)0.0; // 1970 - one currency defined
5031 index = ucurr_countCurrencies("eo_AM", date, &status);
5032 if (index != 1)
5033 {
5034 errcheckln(status, "FAIL: didn't return 1 for eo_AM - %s", u_errorName(status));
5035 }
5036 resLen = ucurr_forLocaleAndDate("eo_AM", date, index, TMP, 4, &status);
5037 tempStr.setTo(TMP);
5038 resultStr.setTo("SUR");
5039 if (resultStr != tempStr) {
5040 errcheckln(status, "FAIL: didn't return SUR for eo_AM - %s", u_errorName(status));
5041 }
5042
5043 date = (UDate)693792000000.0; // 1992 - one currency defined
5044 index = ucurr_countCurrencies("eo_AM", date, &status);
5045 if (index != 1)
5046 {
5047 errcheckln(status, "FAIL: didn't return 1 for eo_AM - %s", u_errorName(status));
5048 }
5049 resLen = ucurr_forLocaleAndDate("eo_AM", date, index, TMP, 4, &status);
5050 tempStr.setTo(TMP);
5051 resultStr.setTo("RUR");
5052 if (resultStr != tempStr) {
5053 errcheckln(status, "FAIL: didn't return RUR for eo_AM - %s", u_errorName(status));
5054 }
5055
5056 date = (UDate)977616000000.0; // post 1993 - one currency defined
5057 index = ucurr_countCurrencies("eo_AM", date, &status);
5058 if (index != 1)
5059 {
5060 errcheckln(status, "FAIL: didn't return 1 for eo_AM - %s", u_errorName(status));
5061 }
5062 resLen = ucurr_forLocaleAndDate("eo_AM", date, index, TMP, 4, &status);
5063 tempStr.setTo(TMP);
5064 resultStr.setTo("AMD");
5065 if (resultStr != tempStr) {
5066 errcheckln(status, "FAIL: didn't return AMD for eo_AM - %s", u_errorName(status));
5067 }
5068
5069 // Locale AD has multiple currencies at once
5070 date = (UDate)977616000000.0; // year 2001
5071 index = ucurr_countCurrencies("eo_AD", date, &status);
5072 if (index != 4)
5073 {
5074 errcheckln(status, "FAIL: didn't return 4 for eo_AD - %s", u_errorName(status));
5075 }
5076 resLen = ucurr_forLocaleAndDate("eo_AD", date, 1, TMP, 4, &status);
5077 tempStr.setTo(TMP);
5078 resultStr.setTo("EUR");
5079 if (resultStr != tempStr) {
5080 errcheckln(status, "FAIL: didn't return EUR for eo_AD - %s", u_errorName(status));
5081 }
5082 resLen = ucurr_forLocaleAndDate("eo_AD", date, 2, TMP, 4, &status);
5083 tempStr.setTo(TMP);
5084 resultStr.setTo("ESP");
5085 if (resultStr != tempStr) {
5086 errcheckln(status, "FAIL: didn't return ESP for eo_AD - %s", u_errorName(status));
5087 }
5088 resLen = ucurr_forLocaleAndDate("eo_AD", date, 3, TMP, 4, &status);
5089 tempStr.setTo(TMP);
5090 resultStr.setTo("FRF");
5091 if (resultStr != tempStr) {
5092 errcheckln(status, "FAIL: didn't return FRF for eo_AD - %s", u_errorName(status));
5093 }
5094 resLen = ucurr_forLocaleAndDate("eo_AD", date, 4, TMP, 4, &status);
5095 tempStr.setTo(TMP);
5096 resultStr.setTo("ADP");
5097 if (resultStr != tempStr) {
5098 errcheckln(status, "FAIL: didn't return ADP for eo_AD - %s", u_errorName(status));
5099 }
5100
5101 date = (UDate)0.0; // year 1970
5102 index = ucurr_countCurrencies("eo_AD", date, &status);
5103 if (index != 3)
5104 {
5105 errcheckln(status, "FAIL: didn't return 3 for eo_AD - %s", u_errorName(status));
5106 }
5107 resLen = ucurr_forLocaleAndDate("eo_AD", date, 1, TMP, 4, &status);
5108 tempStr.setTo(TMP);
5109 resultStr.setTo("ESP");
5110 if (resultStr != tempStr) {
5111 errcheckln(status, "FAIL: didn't return ESP for eo_AD - %s", u_errorName(status));
5112 }
5113 resLen = ucurr_forLocaleAndDate("eo_AD", date, 2, TMP, 4, &status);
5114 tempStr.setTo(TMP);
5115 resultStr.setTo("FRF");
5116 if (resultStr != tempStr) {
5117 errcheckln(status, "FAIL: didn't return FRF for eo_AD - %s", u_errorName(status));
5118 }
5119 resLen = ucurr_forLocaleAndDate("eo_AD", date, 3, TMP, 4, &status);
5120 tempStr.setTo(TMP);
5121 resultStr.setTo("ADP");
5122 if (resultStr != tempStr) {
5123 errcheckln(status, "FAIL: didn't return ADP for eo_AD - %s", u_errorName(status));
5124 }
5125
5126 date = (UDate)-630720000000.0; // year 1950
5127 index = ucurr_countCurrencies("eo_AD", date, &status);
5128 if (index != 2)
5129 {
5130 errcheckln(status, "FAIL: didn't return 2 for eo_AD - %s", u_errorName(status));
5131 }
5132 resLen = ucurr_forLocaleAndDate("eo_AD", date, 1, TMP, 4, &status);
5133 tempStr.setTo(TMP);
5134 resultStr.setTo("ESP");
5135 if (resultStr != tempStr) {
5136 errcheckln(status, "FAIL: didn't return ESP for eo_AD - %s", u_errorName(status));
5137 }
5138 resLen = ucurr_forLocaleAndDate("eo_AD", date, 2, TMP, 4, &status);
5139 tempStr.setTo(TMP);
5140 resultStr.setTo("ADP");
5141 if (resultStr != tempStr) {
5142 errcheckln(status, "FAIL: didn't return ADP for eo_AD - %s", u_errorName(status));
5143 }
5144
5145 date = (UDate)-2207520000000.0; // year 1900
5146 index = ucurr_countCurrencies("eo_AD", date, &status);
5147 if (index != 1)
5148 {
5149 errcheckln(status, "FAIL: didn't return 1 for eo_AD - %s", u_errorName(status));
5150 }
5151 resLen = ucurr_forLocaleAndDate("eo_AD", date, 1, TMP, 4, &status);
5152 tempStr.setTo(TMP);
5153 resultStr.setTo("ESP");
5154 if (resultStr != tempStr) {
5155 errcheckln(status, "FAIL: didn't return ESP for eo_AD - %s", u_errorName(status));
5156 }
5157
5158 // Locale UA has gap between years 1994 - 1996
5159 date = (UDate)788400000000.0;
5160 index = ucurr_countCurrencies("eo_UA", date, &status);
5161 if (index != 0)
5162 {
5163 errcheckln(status, "FAIL: didn't return 0 for eo_UA - %s", u_errorName(status));
5164 }
5165 resLen = ucurr_forLocaleAndDate("eo_UA", date, index, TMP, 4, &status);
5166 if (resLen != 0) {
5167 errcheckln(status, "FAIL: eo_UA didn't return NULL - %s", u_errorName(status));
5168 }
5169 status = U_ZERO_ERROR;
5170
5171 // Test index bounds
5172 resLen = ucurr_forLocaleAndDate("eo_UA", date, 100, TMP, 4, &status);
5173 if (resLen != 0) {
5174 errcheckln(status, "FAIL: eo_UA didn't return NULL - %s", u_errorName(status));
5175 }
5176 status = U_ZERO_ERROR;
5177
5178 resLen = ucurr_forLocaleAndDate("eo_UA", date, 0, TMP, 4, &status);
5179 if (resLen != 0) {
5180 errcheckln(status, "FAIL: eo_UA didn't return NULL - %s", u_errorName(status));
5181 }
5182 status = U_ZERO_ERROR;
5183
5184 // Test for bogus locale
5185 index = ucurr_countCurrencies("eo_QQ", date, &status);
5186 if (index != 0)
5187 {
5188 errcheckln(status, "FAIL: didn't return 0 for eo_QQ - %s", u_errorName(status));
5189 }
5190 status = U_ZERO_ERROR;
5191 resLen = ucurr_forLocaleAndDate("eo_QQ", date, 1, TMP, 4, &status);
5192 if (resLen != 0) {
5193 errcheckln(status, "FAIL: eo_QQ didn't return NULL - %s", u_errorName(status));
5194 }
5195 status = U_ZERO_ERROR;
5196 resLen = ucurr_forLocaleAndDate("eo_QQ", date, 0, TMP, 4, &status);
5197 if (resLen != 0) {
5198 errcheckln(status, "FAIL: eo_QQ didn't return NULL - %s", u_errorName(status));
5199 }
5200 status = U_ZERO_ERROR;
5201
5202 // Cycle through histrocial currencies
5203 date = (UDate)977616000000.0; // 2001 - one currency
5204 index = ucurr_countCurrencies("eo_AO", date, &status);
5205 if (index != 1)
5206 {
5207 errcheckln(status, "FAIL: didn't return 1 for eo_AO - %s", u_errorName(status));
5208 }
5209 resLen = ucurr_forLocaleAndDate("eo_AO", date, 1, TMP, 4, &status);
5210 tempStr.setTo(TMP);
5211 resultStr.setTo("AOA");
5212 if (resultStr != tempStr) {
5213 errcheckln(status, "FAIL: didn't return AOA for eo_AO - %s", u_errorName(status));
5214 }
5215
5216 date = (UDate)819936000000.0; // 1996 - 2 currencies
5217 index = ucurr_countCurrencies("eo_AO", date, &status);
5218 if (index != 2)
5219 {
5220 errcheckln(status, "FAIL: didn't return 1 for eo_AO - %s", u_errorName(status));
5221 }
5222 resLen = ucurr_forLocaleAndDate("eo_AO", date, 1, TMP, 4, &status);
5223 tempStr.setTo(TMP);
5224 resultStr.setTo("AOR");
5225 if (resultStr != tempStr) {
5226 errcheckln(status, "FAIL: didn't return AOR for eo_AO - %s", u_errorName(status));
5227 }
5228 resLen = ucurr_forLocaleAndDate("eo_AO", date, 2, TMP, 4, &status);
5229 tempStr.setTo(TMP);
5230 resultStr.setTo("AON");
5231 if (resultStr != tempStr) {
5232 errcheckln(status, "FAIL: didn't return AON for eo_AO - %s", u_errorName(status));
5233 }
5234
5235 date = (UDate)662256000000.0; // 1991 - 2 currencies
5236 index = ucurr_countCurrencies("eo_AO", date, &status);
5237 if (index != 2)
5238 {
5239 errcheckln(status, "FAIL: didn't return 1 for eo_AO - %s", u_errorName(status));
5240 }
5241 resLen = ucurr_forLocaleAndDate("eo_AO", date, 1, TMP, 4, &status);
5242 tempStr.setTo(TMP);
5243 resultStr.setTo("AON");
5244 if (resultStr != tempStr) {
5245 errcheckln(status, "FAIL: didn't return AON for eo_AO - %s", u_errorName(status));
5246 }
5247 resLen = ucurr_forLocaleAndDate("eo_AO", date, 2, TMP, 4, &status);
5248 tempStr.setTo(TMP);
5249 resultStr.setTo("AOK");
5250 if (resultStr != tempStr) {
5251 errcheckln(status, "FAIL: didn't return AOK for eo_AO - %s", u_errorName(status));
5252 }
5253
5254 date = (UDate)315360000000.0; // 1980 - one currency
5255 index = ucurr_countCurrencies("eo_AO", date, &status);
5256 if (index != 1)
5257 {
5258 errcheckln(status, "FAIL: didn't return 1 for eo_AO - %s", u_errorName(status));
5259 }
5260 resLen = ucurr_forLocaleAndDate("eo_AO", date, 1, TMP, 4, &status);
5261 tempStr.setTo(TMP);
5262 resultStr.setTo("AOK");
5263 if (resultStr != tempStr) {
5264 errcheckln(status, "FAIL: didn't return AOK for eo_AO - %s", u_errorName(status));
5265 }
5266
5267 date = (UDate)0.0; // 1970 - no currencies
5268 index = ucurr_countCurrencies("eo_AO", date, &status);
5269 if (index != 0)
5270 {
5271 errcheckln(status, "FAIL: didn't return 1 for eo_AO - %s", u_errorName(status));
5272 }
5273 resLen = ucurr_forLocaleAndDate("eo_AO", date, 1, TMP, 4, &status);
5274 if (resLen != 0) {
5275 errcheckln(status, "FAIL: eo_AO didn't return NULL - %s", u_errorName(status));
5276 }
5277 status = U_ZERO_ERROR;
5278
5279 // Test with currency keyword override
5280 date = (UDate)977616000000.0; // 2001 - two currencies
5281 index = ucurr_countCurrencies("eo_DE@currency=DEM", date, &status);
5282 if (index != 2)
5283 {
5284 errcheckln(status, "FAIL: didn't return 2 for eo_DE@currency=DEM - %s", u_errorName(status));
5285 }
5286 resLen = ucurr_forLocaleAndDate("eo_DE@currency=DEM", date, 1, TMP, 4, &status);
5287 tempStr.setTo(TMP);
5288 resultStr.setTo("EUR");
5289 if (resultStr != tempStr) {
5290 errcheckln(status, "FAIL: didn't return EUR for eo_DE@currency=DEM - %s", u_errorName(status));
5291 }
5292 resLen = ucurr_forLocaleAndDate("eo_DE@currency=DEM", date, 2, TMP, 4, &status);
5293 tempStr.setTo(TMP);
5294 resultStr.setTo("DEM");
5295 if (resultStr != tempStr) {
5296 errcheckln(status, "FAIL: didn't return DEM for eo_DE@currency=DEM - %s", u_errorName(status));
5297 }
5298
5299 // Test Euro Support
5300 status = U_ZERO_ERROR; // reset
5301 date = uprv_getUTCtime();
5302
5303 UChar USD[4];
5304 ucurr_forLocaleAndDate("en_US", date, 1, USD, 4, &status);
5305
5306 UChar YEN[4];
5307 ucurr_forLocaleAndDate("ja_JP", date, 1, YEN, 4, &status);
5308
5309 ucurr_forLocaleAndDate("en_US", date, 1, TMP, 4, &status);
5310 if (u_strcmp(USD, TMP) != 0) {
5311 errcheckln(status, "Fail: en_US didn't return USD - %s", u_errorName(status));
5312 }
5313 ucurr_forLocaleAndDate("en_US_Q", date, 1, TMP, 4, &status);
5314 if (u_strcmp(USD, TMP) != 0) {
5315 errcheckln(status, "Fail: en_US_Q didn't fallback to en_US - %s", u_errorName(status));
5316 }
5317 status = U_ZERO_ERROR; // reset
5318 #endif
5319 }
5320
TestGetVariantWithKeywords(void)5321 void LocaleTest::TestGetVariantWithKeywords(void)
5322 {
5323 Locale l("en_US_VALLEY@foo=value");
5324 const char *variant = l.getVariant();
5325 logln(variant);
5326 test_assert(strcmp("VALLEY", variant) == 0);
5327
5328 UErrorCode status = U_ZERO_ERROR;
5329 char buffer[50];
5330 int32_t len = l.getKeywordValue("foo", buffer, 50, status);
5331 buffer[len] = '\0';
5332 test_assert(strcmp("value", buffer) == 0);
5333 }
5334
TestIsRightToLeft()5335 void LocaleTest::TestIsRightToLeft() {
5336 assertFalse("root LTR", Locale::getRoot().isRightToLeft());
5337 assertFalse("zh LTR", Locale::getChinese().isRightToLeft());
5338 assertTrue("ar RTL", Locale("ar").isRightToLeft());
5339 assertTrue("und-EG RTL", Locale("und-EG").isRightToLeft(), FALSE, TRUE);
5340 assertFalse("fa-Cyrl LTR", Locale("fa-Cyrl").isRightToLeft());
5341 assertTrue("en-Hebr RTL", Locale("en-Hebr").isRightToLeft());
5342 assertTrue("ckb RTL", Locale("ckb").isRightToLeft(), FALSE, TRUE); // Sorani Kurdish
5343 assertFalse("fil LTR", Locale("fil").isRightToLeft());
5344 assertFalse("he-Zyxw LTR", Locale("he-Zyxw").isRightToLeft());
5345 }
5346
TestBug11421()5347 void LocaleTest::TestBug11421() {
5348 Locale::getDefault().getBaseName();
5349 int32_t numLocales;
5350 const Locale *localeList = Locale::getAvailableLocales(numLocales);
5351 for (int localeIndex = 0; localeIndex < numLocales; localeIndex++) {
5352 const Locale &loc = localeList[localeIndex];
5353 if (strncmp(loc.getName(), loc.getBaseName(), strlen(loc.getBaseName()))) {
5354 errln("%s:%d loc.getName=\"%s\"; loc.getBaseName=\"%s\"",
5355 __FILE__, __LINE__, loc.getName(), loc.getBaseName());
5356 break;
5357 }
5358 }
5359 }
5360
5361 // TestBug13277. The failure manifests as valgrind errors.
5362 // See the trac ticket for details.
5363 //
5364
TestBug13277()5365 void LocaleTest::TestBug13277() {
5366 UErrorCode status = U_ZERO_ERROR;
5367 CharString name("en-us-x-foo", -1, status);
5368 while (name.length() < 152) {
5369 name.append("-x-foo", -1, status);
5370 }
5371
5372 while (name.length() < 160) {
5373 name.append('z', status);
5374 Locale loc(name.data(), nullptr, nullptr, nullptr);
5375 }
5376 }
5377
5378 // TestBug13554 Check for read past end of array in getPosixID().
5379 // The bug shows as an Address Sanitizer failure.
5380
TestBug13554()5381 void LocaleTest::TestBug13554() {
5382 UErrorCode status = U_ZERO_ERROR;
5383 const int BUFFER_SIZE = 100;
5384 char posixID[BUFFER_SIZE];
5385
5386 for (uint32_t hostid = 0; hostid < 0x500; ++hostid) {
5387 status = U_ZERO_ERROR;
5388 uprv_convertToPosix(hostid, posixID, BUFFER_SIZE, &status);
5389 }
5390 }
5391
TestBug20410()5392 void LocaleTest::TestBug20410() {
5393 IcuTestErrorCode status(*this, "TestBug20410()");
5394
5395 static const char tag1[] = "art-lojban-x-0";
5396 static const Locale expected1("jbo@x=0");
5397 Locale result1 = Locale::forLanguageTag(tag1, status);
5398 status.errIfFailureAndReset("\"%s\"", tag1);
5399 assertEquals(tag1, expected1.getName(), result1.getName());
5400
5401 static const char tag2[] = "zh-xiang-u-nu-thai-x-0";
5402 static const Locale expected2("hsn@numbers=thai;x=0");
5403 Locale result2 = Locale::forLanguageTag(tag2, status);
5404 status.errIfFailureAndReset("\"%s\"", tag2);
5405 assertEquals(tag2, expected2.getName(), result2.getName());
5406
5407 static const char locid3[] = "art__lojban@x=0";
5408 Locale result3 = Locale::createCanonical(locid3);
5409 static const Locale expected3("jbo@x=0");
5410 assertEquals(locid3, expected3.getName(), result3.getName());
5411
5412 static const char locid4[] = "art-lojban-x-0";
5413 Locale result4 = Locale::createCanonical(locid4);
5414 static const Locale expected4("jbo@x=0");
5415 assertEquals(locid4, expected4.getName(), result4.getName());
5416 }
5417
TestBug20900()5418 void LocaleTest::TestBug20900() {
5419 static const struct {
5420 const char *localeID; /* input */
5421 const char *canonicalID; /* expected canonicalize() result */
5422 } testCases[] = {
5423 { "art-lojban", "jbo" },
5424 { "zh-guoyu", "zh" },
5425 { "zh-hakka", "hak" },
5426 { "zh-xiang", "hsn" },
5427 { "zh-min-nan", "nan" },
5428 { "zh-gan", "gan" },
5429 { "zh-wuu", "wuu" },
5430 { "zh-yue", "yue" },
5431 };
5432
5433 IcuTestErrorCode status(*this, "TestBug20900");
5434 for (int32_t i=0; i < UPRV_LENGTHOF(testCases); i++) {
5435 Locale loc = Locale::createCanonical(testCases[i].localeID);
5436 std::string result = loc.toLanguageTag<std::string>(status);
5437 const char* tag = loc.isBogus() ? "BOGUS" : result.c_str();
5438 status.errIfFailureAndReset("FAIL: createCanonical(%s).toLanguageTag() expected \"%s\"",
5439 testCases[i].localeID, tag);
5440 assertEquals("createCanonical", testCases[i].canonicalID, tag);
5441 }
5442 }
5443
5444 U_DEFINE_LOCAL_OPEN_POINTER(LocalStdioFilePointer, FILE, fclose);
TestLocaleCanonicalizationFromFile()5445 void LocaleTest::TestLocaleCanonicalizationFromFile()
5446 {
5447 IcuTestErrorCode status(*this, "TestLocaleCanonicalizationFromFile");
5448 const char *sourceTestDataPath=getSourceTestData(status);
5449 if(status.errIfFailureAndReset("unable to find the source/test/testdata "
5450 "folder (getSourceTestData())")) {
5451 return;
5452 }
5453 char testPath[400];
5454 char line[256];
5455 strcpy(testPath, sourceTestDataPath);
5456 strcat(testPath, "localeCanonicalization.txt");
5457 LocalStdioFilePointer testFile(fopen(testPath, "r"));
5458 if(testFile.isNull()) {
5459 errln("unable to open %s", testPath);
5460 return;
5461 }
5462 // Format:
5463 // <source locale identifier> ; <expected canonicalized locale identifier>
5464 while (fgets(line, (int)sizeof(line), testFile.getAlias())!=NULL) {
5465 if (line[0] == '#') {
5466 // ignore any lines start with #
5467 continue;
5468 }
5469 char *semi = strchr(line, ';');
5470 if (semi == nullptr) {
5471 // ignore any lines without ;
5472 continue;
5473 }
5474 *semi = '\0'; // null terminiate on the spot of semi
5475 const char* from = u_skipWhitespace((const char*)line);
5476 u_rtrim((char*)from);
5477 const char* to = u_skipWhitespace((const char*)semi + 1);
5478 u_rtrim((char*)to);
5479 std::string expect(to);
5480 // Change the _ to -
5481 std::transform(expect.begin(), expect.end(), expect.begin(),
5482 [](unsigned char c){ return c == '_' ? '-' : c; });
5483
5484 Locale loc = Locale::createCanonical(from);
5485 std::string result = loc.toLanguageTag<std::string>(status);
5486 const char* tag = loc.isBogus() ? "BOGUS" : result.c_str();
5487 status.errIfFailureAndReset(
5488 "FAIL: createCanonical(%s).toLanguageTag() expected \"%s\" locale is %s",
5489 from, tag, loc.getName());
5490 std::string msg("createCanonical(");
5491 msg += from;
5492 msg += ") locale = ";
5493 msg += loc.getName();
5494 assertEquals(msg.c_str(), expect.c_str(), tag);
5495 }
5496 }
5497
TestKnownCanonicalizedListCorrect()5498 void LocaleTest::TestKnownCanonicalizedListCorrect()
5499 {
5500 IcuTestErrorCode status(*this, "TestKnownCanonicalizedListCorrect");
5501 int32_t numOfKnownCanonicalized;
5502 const char* const* knownCanonicalized =
5503 ulocimp_getKnownCanonicalizedLocaleForTest(&numOfKnownCanonicalized);
5504 for (int32_t i = 0; i < numOfKnownCanonicalized; i++) {
5505 std::string msg("Known Canonicalized Locale is not canonicalized: ");
5506 assertTrue((msg + knownCanonicalized[i]).c_str(),
5507 ulocimp_isCanonicalizedLocaleForTest(knownCanonicalized[i]));
5508 }
5509 }
5510
TestConstructorAcceptsBCP47()5511 void LocaleTest::TestConstructorAcceptsBCP47() {
5512 IcuTestErrorCode status(*this, "TestConstructorAcceptsBCP47");
5513
5514 Locale loc1("ar-EG-u-nu-latn");
5515 Locale loc2("ar-EG@numbers=latn");
5516 Locale loc3("ar-EG");
5517 std::string val;
5518
5519 // Check getKeywordValue "numbers"
5520 val = loc1.getKeywordValue<std::string>("numbers", status);
5521 assertEquals("BCP47 syntax has ICU keyword value", "latn", val.c_str());
5522
5523 val = loc2.getKeywordValue<std::string>("numbers", status);
5524 assertEquals("ICU syntax has ICU keyword value", "latn", val.c_str());
5525
5526 val = loc3.getKeywordValue<std::string>("numbers", status);
5527 assertEquals("Default, ICU keyword", "", val.c_str());
5528
5529 // Check getUnicodeKeywordValue "nu"
5530 val = loc1.getUnicodeKeywordValue<std::string>("nu", status);
5531 assertEquals("BCP47 syntax has short unicode keyword value", "latn", val.c_str());
5532
5533 val = loc2.getUnicodeKeywordValue<std::string>("nu", status);
5534 assertEquals("ICU syntax has short unicode keyword value", "latn", val.c_str());
5535
5536 val = loc3.getUnicodeKeywordValue<std::string>("nu", status);
5537 status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR, "Default, short unicode keyword");
5538
5539 // Check getUnicodeKeywordValue "numbers"
5540 val = loc1.getUnicodeKeywordValue<std::string>("numbers", status);
5541 assertEquals("BCP47 syntax has long unicode keyword value", "latn", val.c_str());
5542
5543 val = loc2.getUnicodeKeywordValue<std::string>("numbers", status);
5544 assertEquals("ICU syntax has long unicode keyword value", "latn", val.c_str());
5545
5546 val = loc3.getUnicodeKeywordValue<std::string>("numbers", status);
5547 status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR, "Default, long unicode keyword");
5548 }
5549
TestForLanguageTag()5550 void LocaleTest::TestForLanguageTag() {
5551 IcuTestErrorCode status(*this, "TestForLanguageTag()");
5552
5553 static const char tag_en[] = "en-US";
5554 static const char tag_oed[] = "en-GB-oed";
5555 static const char tag_af[] = "af-t-ar-i0-handwrit-u-ca-coptic-x-foo";
5556 static const char tag_ill[] = "!";
5557 static const char tag_no_nul[] = { 'e', 'n', '-', 'G', 'B' };
5558 static const char tag_ext[] = "en-GB-1-abc-efg-a-xyz";
5559 static const char tag_var[] = "sl-rozaj-biske-1994";
5560
5561 static const Locale loc_en("en_US");
5562 static const Locale loc_oed("en_GB_OXENDICT");
5563 static const Locale loc_af("af@calendar=coptic;t=ar-i0-handwrit;x=foo");
5564 static const Locale loc_null("");
5565 static const Locale loc_gb("en_GB");
5566 static const Locale loc_ext("en_GB@1=abc-efg;a=xyz");
5567 static const Locale loc_var("sl__1994_BISKE_ROZAJ");
5568
5569 Locale result_en = Locale::forLanguageTag(tag_en, status);
5570 status.errIfFailureAndReset("\"%s\"", tag_en);
5571 assertEquals(tag_en, loc_en.getName(), result_en.getName());
5572
5573 Locale result_oed = Locale::forLanguageTag(tag_oed, status);
5574 status.errIfFailureAndReset("\"%s\"", tag_oed);
5575 assertEquals(tag_oed, loc_oed.getName(), result_oed.getName());
5576
5577 Locale result_af = Locale::forLanguageTag(tag_af, status);
5578 status.errIfFailureAndReset("\"%s\"", tag_af);
5579 assertEquals(tag_af, loc_af.getName(), result_af.getName());
5580
5581 Locale result_var = Locale::forLanguageTag(tag_var, status);
5582 status.errIfFailureAndReset("\"%s\"", tag_var);
5583 assertEquals(tag_var, loc_var.getName(), result_var.getName());
5584
5585 Locale result_ill = Locale::forLanguageTag(tag_ill, status);
5586 assertEquals(tag_ill, U_ILLEGAL_ARGUMENT_ERROR, status.reset());
5587 assertTrue(result_ill.getName(), result_ill.isBogus());
5588
5589 Locale result_null = Locale::forLanguageTag(nullptr, status);
5590 status.errIfFailureAndReset("nullptr");
5591 assertEquals("nullptr", loc_null.getName(), result_null.getName());
5592
5593 StringPiece sp_substr(tag_oed, 5); // "en-GB", no NUL.
5594 Locale result_substr = Locale::forLanguageTag(sp_substr, status);
5595 status.errIfFailureAndReset("\"%.*s\"", sp_substr.size(), sp_substr.data());
5596 assertEquals(CharString(sp_substr, status).data(),
5597 loc_gb.getName(), result_substr.getName());
5598
5599 StringPiece sp_no_nul(tag_no_nul, sizeof tag_no_nul); // "en-GB", no NUL.
5600 Locale result_no_nul = Locale::forLanguageTag(sp_no_nul, status);
5601 status.errIfFailureAndReset("\"%.*s\"", sp_no_nul.size(), sp_no_nul.data());
5602 assertEquals(CharString(sp_no_nul, status).data(),
5603 loc_gb.getName(), result_no_nul.getName());
5604
5605 Locale result_ext = Locale::forLanguageTag(tag_ext, status);
5606 status.errIfFailureAndReset("\"%s\"", tag_ext);
5607 assertEquals(tag_ext, loc_ext.getName(), result_ext.getName());
5608
5609 static const struct {
5610 const char *inputTag; /* input */
5611 const char *expectedID; /* expected forLanguageTag().getName() result */
5612 } testCases[] = {
5613 // ICU-21433
5614 {"und-1994-biske-rozaj", "__1994_BISKE_ROZAJ"},
5615 {"de-1994-biske-rozaj", "de__1994_BISKE_ROZAJ"},
5616 {"und-x-private", "@x=private"},
5617 {"de-1994-biske-rozaj-x-private", "de__1994_BISKE_ROZAJ@x=private"},
5618 {"und-1994-biske-rozaj-x-private", "__1994_BISKE_ROZAJ@x=private"},
5619 };
5620 int32_t i;
5621 for (i=0; i < UPRV_LENGTHOF(testCases); i++) {
5622 UErrorCode status = U_ZERO_ERROR;
5623 std::string otag = testCases[i].inputTag;
5624 std::string tag = Locale::forLanguageTag(otag.c_str(), status).getName();
5625 if (tag != testCases[i].expectedID) {
5626 errcheckln(status, "FAIL: %s should be toLanguageTag to %s but got %s - %s",
5627 otag.c_str(),
5628 testCases[i].expectedID,
5629 tag.c_str(),
5630 u_errorName(status));
5631 }
5632 }
5633 }
5634
TestToLanguageTag()5635 void LocaleTest::TestToLanguageTag() {
5636 IcuTestErrorCode status(*this, "TestToLanguageTag()");
5637
5638 static const Locale loc_c("en_US_POSIX");
5639 static const Locale loc_en("en_US");
5640 static const Locale loc_af("af@calendar=coptic;t=ar-i0-handwrit;x=foo");
5641 static const Locale loc_ext("en@0=abc;a=xyz");
5642 static const Locale loc_empty("");
5643 static const Locale loc_ill("!");
5644 static const Locale loc_variant("sl__ROZAJ_BISKE_1994");
5645
5646 static const char tag_c[] = "en-US-u-va-posix";
5647 static const char tag_en[] = "en-US";
5648 static const char tag_af[] = "af-t-ar-i0-handwrit-u-ca-coptic-x-foo";
5649 static const char tag_ext[] = "en-0-abc-a-xyz";
5650 static const char tag_und[] = "und";
5651 static const char tag_variant[] = "sl-1994-biske-rozaj";
5652
5653 std::string result;
5654 StringByteSink<std::string> sink(&result);
5655 loc_c.toLanguageTag(sink, status);
5656 status.errIfFailureAndReset("\"%s\"", loc_c.getName());
5657 assertEquals(loc_c.getName(), tag_c, result.c_str());
5658
5659 std::string result_c = loc_c.toLanguageTag<std::string>(status);
5660 status.errIfFailureAndReset("\"%s\"", loc_c.getName());
5661 assertEquals(loc_c.getName(), tag_c, result_c.c_str());
5662
5663 std::string result_en = loc_en.toLanguageTag<std::string>(status);
5664 status.errIfFailureAndReset("\"%s\"", loc_en.getName());
5665 assertEquals(loc_en.getName(), tag_en, result_en.c_str());
5666
5667 std::string result_af = loc_af.toLanguageTag<std::string>(status);
5668 status.errIfFailureAndReset("\"%s\"", loc_af.getName());
5669 assertEquals(loc_af.getName(), tag_af, result_af.c_str());
5670
5671 std::string result_ext = loc_ext.toLanguageTag<std::string>(status);
5672 status.errIfFailureAndReset("\"%s\"", loc_ext.getName());
5673 assertEquals(loc_ext.getName(), tag_ext, result_ext.c_str());
5674
5675 std::string result_empty = loc_empty.toLanguageTag<std::string>(status);
5676 status.errIfFailureAndReset("\"%s\"", loc_empty.getName());
5677 assertEquals(loc_empty.getName(), tag_und, result_empty.c_str());
5678
5679 std::string result_ill = loc_ill.toLanguageTag<std::string>(status);
5680 status.errIfFailureAndReset("\"%s\"", loc_ill.getName());
5681 assertEquals(loc_ill.getName(), tag_und, result_ill.c_str());
5682
5683 std::string result_variant = loc_variant.toLanguageTag<std::string>(status);
5684 status.errIfFailureAndReset("\"%s\"", loc_variant.getName());
5685 assertEquals(loc_variant.getName(), tag_variant, result_variant.c_str());
5686
5687 Locale loc_bogus;
5688 loc_bogus.setToBogus();
5689 std::string result_bogus = loc_bogus.toLanguageTag<std::string>(status);
5690 assertEquals("bogus", U_ILLEGAL_ARGUMENT_ERROR, status.reset());
5691 assertTrue(result_bogus.c_str(), result_bogus.empty());
5692
5693 static const struct {
5694 const char *localeID; /* input */
5695 const char *expectedID; /* expected toLanguageTag() result */
5696 } testCases[] = {
5697 /* ICU-21414 */
5698 {"und-x-abc-private", "und-x-abc-private"},
5699 {"und-x-private", "und-x-private"},
5700 {"und-u-ca-roc-x-private", "und-u-ca-roc-x-private"},
5701 {"und-US-x-private", "und-US-x-private"},
5702 {"und-Latn-x-private", "und-Latn-x-private"},
5703 {"und-1994-biske-rozaj", "und-1994-biske-rozaj"},
5704 {"und-1994-biske-rozaj-x-private", "und-1994-biske-rozaj-x-private"},
5705 };
5706 int32_t i;
5707 for (i=0; i < UPRV_LENGTHOF(testCases); i++) {
5708 UErrorCode status = U_ZERO_ERROR;
5709 std::string otag = testCases[i].localeID;
5710 std::string tag = Locale::forLanguageTag(otag.c_str(), status).toLanguageTag<std::string>(status);
5711 if (tag != testCases[i].expectedID) {
5712 errcheckln(status, "FAIL: %s should be toLanguageTag to %s but got %s - %s",
5713 otag.c_str(),
5714 testCases[i].expectedID,
5715 tag.c_str(),
5716 u_errorName(status));
5717 }
5718 }
5719 }
5720
5721 /* ICU-20310 */
TestToLanguageTagOmitTrue()5722 void LocaleTest::TestToLanguageTagOmitTrue() {
5723 IcuTestErrorCode status(*this, "TestToLanguageTagOmitTrue()");
5724 assertEquals("en-u-kn should drop true",
5725 "en-u-kn", Locale("en-u-kn-true").toLanguageTag<std::string>(status).c_str());
5726 status.errIfFailureAndReset();
5727 assertEquals("en-u-kn should drop true",
5728 "en-u-kn", Locale("en-u-kn").toLanguageTag<std::string>(status).c_str());
5729 status.errIfFailureAndReset();
5730
5731 assertEquals("de-u-co should drop true",
5732 "de-u-co", Locale("de-u-co").toLanguageTag<std::string>(status).c_str());
5733 status.errIfFailureAndReset();
5734 assertEquals("de-u-co should drop true",
5735 "de-u-co", Locale("de-u-co-yes").toLanguageTag<std::string>(status).c_str());
5736 status.errIfFailureAndReset();
5737 assertEquals("de@collation=yes should drop true",
5738 "de-u-co", Locale("de@collation=yes").toLanguageTag<std::string>(status).c_str());
5739 status.errIfFailureAndReset();
5740
5741 assertEquals("cmn-Hans-CN-t-ca-u-ca-x-t-u should drop true",
5742 "cmn-Hans-CN-t-ca-u-ca-x-t-u",
5743 Locale("cmn-hans-cn-u-ca-t-ca-x-t-u").toLanguageTag<std::string>(status).c_str());
5744 status.errIfFailureAndReset();
5745 }
5746
TestMoveAssign()5747 void LocaleTest::TestMoveAssign() {
5748 // ULOC_FULLNAME_CAPACITY == 157 (uloc.h)
5749 Locale l1("de@collation=phonebook;x="
5750 "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
5751 "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
5752 "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
5753 "aaaaabbbbbzz");
5754
5755 Locale l2;
5756 {
5757 Locale l3(l1);
5758 assertTrue("l1 == l3", l1 == l3);
5759 l2 = std::move(l3);
5760 assertTrue("l1 == l2", l1 == l2);
5761 assertTrue("l2 != l3", l2.getName() != l3.getName());
5762 }
5763
5764 // This should remain true also after l3 has been destructed.
5765 assertTrue("l1 == l2, again", l1 == l2);
5766
5767 Locale l4("de@collation=phonebook");
5768
5769 Locale l5;
5770 {
5771 Locale l6(l4);
5772 assertTrue("l4 == l6", l4 == l6);
5773 l5 = std::move(l6);
5774 assertTrue("l4 == l5", l4 == l5);
5775 assertTrue("l5 != l6", l5.getName() != l6.getName());
5776 }
5777
5778 // This should remain true also after l6 has been destructed.
5779 assertTrue("l4 == l5, again", l4 == l5);
5780
5781 Locale l7("vo_Cyrl_AQ_EURO");
5782
5783 Locale l8;
5784 {
5785 Locale l9(l7);
5786 assertTrue("l7 == l9", l7 == l9);
5787 l8 = std::move(l9);
5788 assertTrue("l7 == l8", l7 == l8);
5789 assertTrue("l8 != l9", l8.getName() != l9.getName());
5790 }
5791
5792 // This should remain true also after l9 has been destructed.
5793 assertTrue("l7 == l8, again", l7 == l8);
5794
5795 assertEquals("language", l7.getLanguage(), l8.getLanguage());
5796 assertEquals("script", l7.getScript(), l8.getScript());
5797 assertEquals("country", l7.getCountry(), l8.getCountry());
5798 assertEquals("variant", l7.getVariant(), l8.getVariant());
5799 assertEquals("bogus", l7.isBogus(), l8.isBogus());
5800 }
5801
TestMoveCtor()5802 void LocaleTest::TestMoveCtor() {
5803 // ULOC_FULLNAME_CAPACITY == 157 (uloc.h)
5804 Locale l1("de@collation=phonebook;x="
5805 "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
5806 "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
5807 "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
5808 "aaaaabbbbbzz");
5809
5810 Locale l3(l1);
5811 assertTrue("l1 == l3", l1 == l3);
5812 Locale l2(std::move(l3));
5813 assertTrue("l1 == l2", l1 == l2);
5814 assertTrue("l2 != l3", l2.getName() != l3.getName());
5815
5816 Locale l4("de@collation=phonebook");
5817
5818 Locale l6(l4);
5819 assertTrue("l4 == l6", l4 == l6);
5820 Locale l5(std::move(l6));
5821 assertTrue("l4 == l5", l4 == l5);
5822 assertTrue("l5 != l6", l5.getName() != l6.getName());
5823
5824 Locale l7("vo_Cyrl_AQ_EURO");
5825
5826 Locale l9(l7);
5827 assertTrue("l7 == l9", l7 == l9);
5828 Locale l8(std::move(l9));
5829 assertTrue("l7 == l8", l7 == l8);
5830 assertTrue("l8 != l9", l8.getName() != l9.getName());
5831
5832 assertEquals("language", l7.getLanguage(), l8.getLanguage());
5833 assertEquals("script", l7.getScript(), l8.getScript());
5834 assertEquals("country", l7.getCountry(), l8.getCountry());
5835 assertEquals("variant", l7.getVariant(), l8.getVariant());
5836 assertEquals("bogus", l7.isBogus(), l8.isBogus());
5837 }
5838
TestBug20407iVariantPreferredValue()5839 void LocaleTest::TestBug20407iVariantPreferredValue() {
5840 IcuTestErrorCode status(*this, "TestBug20407iVariantPreferredValue()");
5841
5842 Locale l = Locale::forLanguageTag("hy-arevela", status);
5843 status.errIfFailureAndReset("hy-arevela fail");
5844 assertTrue("!l.isBogus()", !l.isBogus());
5845
5846 std::string result = l.toLanguageTag<std::string>(status);
5847 assertEquals(l.getName(), "hy", result.c_str());
5848
5849 l = Locale::forLanguageTag("hy-arevmda", status);
5850 status.errIfFailureAndReset("hy-arevmda");
5851 assertTrue("!l.isBogus()", !l.isBogus());
5852
5853 result = l.toLanguageTag<std::string>(status);
5854 assertEquals(l.getName(), "hyw", result.c_str());
5855 }
5856
TestBug13417VeryLongLanguageTag()5857 void LocaleTest::TestBug13417VeryLongLanguageTag() {
5858 IcuTestErrorCode status(*this, "TestBug13417VeryLongLanguageTag()");
5859
5860 static const char tag[] =
5861 "zh-x"
5862 "-foo-bar-baz-foo-bar-baz-foo-bar-baz-foo-bar-baz"
5863 "-foo-bar-baz-foo-bar-baz-foo-bar-baz-foo-bar-baz"
5864 "-foo-bar-baz-foo-bar-baz-foo-bar-baz-foo-bar-baz"
5865 "-foo-bar-baz-fxx"
5866 ;
5867
5868 Locale l = Locale::forLanguageTag(tag, status);
5869 status.errIfFailureAndReset("\"%s\"", tag);
5870 assertTrue("!l.isBogus()", !l.isBogus());
5871
5872 std::string result = l.toLanguageTag<std::string>(status);
5873 status.errIfFailureAndReset("\"%s\"", l.getName());
5874 assertEquals("equals", tag, result.c_str());
5875 }
5876
TestBug11053UnderlineTimeZone()5877 void LocaleTest::TestBug11053UnderlineTimeZone() {
5878 static const char* const tz_in_ext[] = {
5879 "etadd",
5880 "tzdar",
5881 "eheai",
5882 "sttms",
5883 "arirj",
5884 "arrgl",
5885 "aruaq",
5886 "arluq",
5887 "mxpvr",
5888 "brbvb",
5889 "arbue",
5890 "caycb",
5891 "brcgr",
5892 "cayzs",
5893 "crsjo",
5894 "caydq",
5895 "svsal",
5896 "cafne",
5897 "caglb",
5898 "cagoo",
5899 "tcgdt",
5900 "ustel",
5901 "bolpb",
5902 "uslax",
5903 "sxphi",
5904 "mxmex",
5905 "usnyc",
5906 "usxul",
5907 "usndcnt",
5908 "usndnsl",
5909 "ttpos",
5910 "brpvh",
5911 "prsju",
5912 "clpuq",
5913 "caffs",
5914 "cayek",
5915 "brrbr",
5916 "mxstis",
5917 "dosdq",
5918 "brsao",
5919 "gpsbh",
5920 "casjf",
5921 "knbas",
5922 "lccas",
5923 "vistt",
5924 "vcsvd",
5925 "cayyn",
5926 "cathu",
5927 "hkhkg",
5928 "mykul",
5929 "khpnh",
5930 "cvrai",
5931 "gsgrv",
5932 "shshn",
5933 "aubhq",
5934 "auldh",
5935 "imdgs",
5936 "smsai",
5937 "asppg",
5938 "pgpom",
5939 };
5940 static const char* const tzname_with_underline[] = {
5941 "America/Buenos_Aires",
5942 "America/Coral_Harbour",
5943 "America/Los_Angeles",
5944 "America/Mexico_City",
5945 "America/New_York",
5946 "America/Rio_Branco",
5947 "America/Sao_Paulo",
5948 "America/St_Johns",
5949 "America/St_Thomas",
5950 "Australia/Broken_Hill",
5951 "Australia/Lord_Howe",
5952 "Pacific/Pago_Pago",
5953 };
5954 std::string locale_str;
5955 for (int32_t i = 0; i < UPRV_LENGTHOF(tz_in_ext); i++) {
5956 locale_str = "en-u-tz-";
5957 locale_str += tz_in_ext[i];
5958 Locale l(locale_str.c_str());
5959 assertTrue((locale_str + " !l.isBogus()").c_str(), !l.isBogus());
5960 }
5961 for (int32_t i = 0; i < UPRV_LENGTHOF(tzname_with_underline); i++) {
5962 locale_str = "en@timezone=";
5963 locale_str += tzname_with_underline[i];
5964 Locale l(locale_str.c_str());
5965 assertTrue((locale_str + " !l.isBogus()").c_str(), !l.isBogus());
5966 }
5967 locale_str = "en_US@timezone=America/Coral_Harbour";
5968 Locale l2(locale_str.c_str());
5969 assertTrue((locale_str + " !l2.isBogus()").c_str(), !l2.isBogus());
5970 locale_str = "en_Latn@timezone=America/New_York";
5971 Locale l3(locale_str.c_str());
5972 assertTrue((locale_str + " !l3.isBogus()").c_str(), !l3.isBogus());
5973 locale_str = "en_Latn_US@timezone=Australia/Broken_Hill";
5974 Locale l4(locale_str.c_str());
5975 assertTrue((locale_str + " !l4.isBogus()").c_str(), !l4.isBogus());
5976 locale_str = "en-u-tz-ciabj";
5977 Locale l5(locale_str.c_str());
5978 assertTrue((locale_str + " !l5.isBogus()").c_str(), !l5.isBogus());
5979 locale_str = "en-US-u-tz-asppg";
5980 Locale l6(locale_str.c_str());
5981 assertTrue((locale_str + " !l6.isBogus()").c_str(), !l6.isBogus());
5982 locale_str = "fil-Latn-u-tz-cvrai";
5983 Locale l7(locale_str.c_str());
5984 assertTrue((locale_str + " !l7.isBogus()").c_str(), !l7.isBogus());
5985 locale_str = "fil-Latn-PH-u-tz-gsgrv";
5986 Locale l8(locale_str.c_str());
5987 assertTrue((locale_str + " !l8.isBogus()").c_str(), !l8.isBogus());
5988 }
5989
TestUnd()5990 void LocaleTest::TestUnd() {
5991 IcuTestErrorCode status(*this, "TestUnd()");
5992
5993 static const char empty[] = "";
5994 static const char root[] = "root";
5995 static const char und[] = "und";
5996
5997 Locale empty_ctor(empty);
5998 Locale empty_tag = Locale::forLanguageTag(empty, status);
5999 status.errIfFailureAndReset("\"%s\"", empty);
6000
6001 Locale root_ctor(root);
6002 Locale root_tag = Locale::forLanguageTag(root, status);
6003 Locale root_build = LocaleBuilder().setLanguageTag(root).build(status);
6004 status.errIfFailureAndReset("\"%s\"", root);
6005
6006 Locale und_ctor(und);
6007 Locale und_tag = Locale::forLanguageTag(und, status);
6008 Locale und_build = LocaleBuilder().setLanguageTag(und).build(status);
6009 status.errIfFailureAndReset("\"%s\"", und);
6010
6011 assertEquals("getName()", empty, empty_ctor.getName());
6012 assertEquals("getName()", empty, root_ctor.getName());
6013 assertEquals("getName()", empty, und_ctor.getName());
6014
6015 assertEquals("getName()", empty, empty_tag.getName());
6016 assertEquals("getName()", empty, root_tag.getName());
6017 assertEquals("getName()", empty, und_tag.getName());
6018
6019 assertEquals("getName()", empty, root_build.getName());
6020 assertEquals("getName()", empty, und_build.getName());
6021
6022 assertEquals("toLanguageTag()", und, empty_ctor.toLanguageTag<std::string>(status).c_str());
6023 assertEquals("toLanguageTag()", und, root_ctor.toLanguageTag<std::string>(status).c_str());
6024 assertEquals("toLanguageTag()", und, und_ctor.toLanguageTag<std::string>(status).c_str());
6025 status.errIfFailureAndReset();
6026
6027 assertEquals("toLanguageTag()", und, empty_tag.toLanguageTag<std::string>(status).c_str());
6028 assertEquals("toLanguageTag()", und, root_tag.toLanguageTag<std::string>(status).c_str());
6029 assertEquals("toLanguageTag()", und, und_tag.toLanguageTag<std::string>(status).c_str());
6030 status.errIfFailureAndReset();
6031
6032 assertEquals("toLanguageTag()", und, root_build.toLanguageTag<std::string>(status).c_str());
6033 assertEquals("toLanguageTag()", und, und_build.toLanguageTag<std::string>(status).c_str());
6034 status.errIfFailureAndReset();
6035
6036 assertTrue("empty_ctor == empty_tag", empty_ctor == empty_tag);
6037
6038 assertTrue("root_ctor == root_tag", root_ctor == root_tag);
6039 assertTrue("root_ctor == root_build", root_ctor == root_build);
6040 assertTrue("root_tag == root_build", root_tag == root_build);
6041
6042 assertTrue("und_ctor == und_tag", und_ctor == und_tag);
6043 assertTrue("und_ctor == und_build", und_ctor == und_build);
6044 assertTrue("und_tag == und_build", und_tag == und_build);
6045
6046 assertTrue("empty_ctor == root_ctor", empty_ctor == root_ctor);
6047 assertTrue("empty_ctor == und_ctor", empty_ctor == und_ctor);
6048 assertTrue("root_ctor == und_ctor", root_ctor == und_ctor);
6049
6050 assertTrue("empty_tag == root_tag", empty_tag == root_tag);
6051 assertTrue("empty_tag == und_tag", empty_tag == und_tag);
6052 assertTrue("root_tag == und_tag", root_tag == und_tag);
6053
6054 assertTrue("root_build == und_build", root_build == und_build);
6055
6056 static const Locale& displayLocale = Locale::getEnglish();
6057 static const UnicodeString displayName("Unknown language");
6058 UnicodeString tmp;
6059
6060 assertEquals("getDisplayName()", displayName, empty_ctor.getDisplayName(displayLocale, tmp));
6061 assertEquals("getDisplayName()", displayName, root_ctor.getDisplayName(displayLocale, tmp));
6062 assertEquals("getDisplayName()", displayName, und_ctor.getDisplayName(displayLocale, tmp));
6063
6064 assertEquals("getDisplayName()", displayName, empty_tag.getDisplayName(displayLocale, tmp));
6065 assertEquals("getDisplayName()", displayName, root_tag.getDisplayName(displayLocale, tmp));
6066 assertEquals("getDisplayName()", displayName, und_tag.getDisplayName(displayLocale, tmp));
6067
6068 assertEquals("getDisplayName()", displayName, root_build.getDisplayName(displayLocale, tmp));
6069 assertEquals("getDisplayName()", displayName, und_build.getDisplayName(displayLocale, tmp));
6070 }
6071
TestUndScript()6072 void LocaleTest::TestUndScript() {
6073 IcuTestErrorCode status(*this, "TestUndScript()");
6074
6075 static const char id[] = "_Cyrl";
6076 static const char tag[] = "und-Cyrl";
6077 static const char script[] = "Cyrl";
6078
6079 Locale locale_ctor(id);
6080 Locale locale_legacy(tag);
6081 Locale locale_tag = Locale::forLanguageTag(tag, status);
6082 Locale locale_build = LocaleBuilder().setScript(script).build(status);
6083 status.errIfFailureAndReset("\"%s\"", tag);
6084
6085 assertEquals("getName()", id, locale_ctor.getName());
6086 assertEquals("getName()", id, locale_legacy.getName());
6087 assertEquals("getName()", id, locale_tag.getName());
6088 assertEquals("getName()", id, locale_build.getName());
6089
6090 assertEquals("toLanguageTag()", tag, locale_ctor.toLanguageTag<std::string>(status).c_str());
6091 assertEquals("toLanguageTag()", tag, locale_legacy.toLanguageTag<std::string>(status).c_str());
6092 assertEquals("toLanguageTag()", tag, locale_tag.toLanguageTag<std::string>(status).c_str());
6093 assertEquals("toLanguageTag()", tag, locale_build.toLanguageTag<std::string>(status).c_str());
6094 status.errIfFailureAndReset();
6095
6096 static const Locale& displayLocale = Locale::getEnglish();
6097 static const UnicodeString displayName("Unknown language (Cyrillic)");
6098 UnicodeString tmp;
6099
6100 assertEquals("getDisplayName()", displayName, locale_ctor.getDisplayName(displayLocale, tmp));
6101 assertEquals("getDisplayName()", displayName, locale_legacy.getDisplayName(displayLocale, tmp));
6102 assertEquals("getDisplayName()", displayName, locale_tag.getDisplayName(displayLocale, tmp));
6103 assertEquals("getDisplayName()", displayName, locale_build.getDisplayName(displayLocale, tmp));
6104 }
6105
TestUndRegion()6106 void LocaleTest::TestUndRegion() {
6107 IcuTestErrorCode status(*this, "TestUndRegion()");
6108
6109 static const char id[] = "_AQ";
6110 static const char tag[] = "und-AQ";
6111 static const char region[] = "AQ";
6112
6113 Locale locale_ctor(id);
6114 Locale locale_legacy(tag);
6115 Locale locale_tag = Locale::forLanguageTag(tag, status);
6116 Locale locale_build = LocaleBuilder().setRegion(region).build(status);
6117 status.errIfFailureAndReset("\"%s\"", tag);
6118
6119 assertEquals("getName()", id, locale_ctor.getName());
6120 assertEquals("getName()", id, locale_legacy.getName());
6121 assertEquals("getName()", id, locale_tag.getName());
6122 assertEquals("getName()", id, locale_build.getName());
6123
6124 assertEquals("toLanguageTag()", tag, locale_ctor.toLanguageTag<std::string>(status).c_str());
6125 assertEquals("toLanguageTag()", tag, locale_legacy.toLanguageTag<std::string>(status).c_str());
6126 assertEquals("toLanguageTag()", tag, locale_tag.toLanguageTag<std::string>(status).c_str());
6127 assertEquals("toLanguageTag()", tag, locale_build.toLanguageTag<std::string>(status).c_str());
6128 status.errIfFailureAndReset();
6129
6130 static const Locale& displayLocale = Locale::getEnglish();
6131 static const UnicodeString displayName("Unknown language (Antarctica)");
6132 UnicodeString tmp;
6133
6134 assertEquals("getDisplayName()", displayName, locale_ctor.getDisplayName(displayLocale, tmp));
6135 assertEquals("getDisplayName()", displayName, locale_legacy.getDisplayName(displayLocale, tmp));
6136 assertEquals("getDisplayName()", displayName, locale_tag.getDisplayName(displayLocale, tmp));
6137 assertEquals("getDisplayName()", displayName, locale_build.getDisplayName(displayLocale, tmp));
6138 }
6139
TestUndCAPI()6140 void LocaleTest::TestUndCAPI() {
6141 IcuTestErrorCode status(*this, "TestUndCAPI()");
6142
6143 static const char empty[] = "";
6144 static const char root[] = "root";
6145 static const char und[] = "und";
6146
6147 static const char empty_script[] = "_Cyrl";
6148 static const char empty_region[] = "_AQ";
6149
6150 static const char und_script[] = "und_Cyrl";
6151 static const char und_region[] = "und_AQ";
6152
6153 char tmp[ULOC_FULLNAME_CAPACITY];
6154 int32_t reslen;
6155
6156 // uloc_getName()
6157
6158 uprv_memset(tmp, '!', sizeof tmp);
6159 reslen = uloc_getName(empty, tmp, sizeof tmp, status);
6160 status.errIfFailureAndReset("\"%s\"", empty);
6161 assertTrue("reslen >= 0", reslen >= 0);
6162 assertEquals("uloc_getName()", empty, tmp);
6163
6164 uprv_memset(tmp, '!', sizeof tmp);
6165 reslen = uloc_getName(root, tmp, sizeof tmp, status);
6166 status.errIfFailureAndReset("\"%s\"", root);
6167 assertTrue("reslen >= 0", reslen >= 0);
6168 assertEquals("uloc_getName()", empty, tmp);
6169
6170 uprv_memset(tmp, '!', sizeof tmp);
6171 reslen = uloc_getName(und, tmp, sizeof tmp, status);
6172 status.errIfFailureAndReset("\"%s\"", und);
6173 assertTrue("reslen >= 0", reslen >= 0);
6174 assertEquals("uloc_getName()", empty, tmp);
6175
6176 uprv_memset(tmp, '!', sizeof tmp);
6177 reslen = uloc_getName(empty_script, tmp, sizeof tmp, status);
6178 status.errIfFailureAndReset("\"%s\"", empty_script);
6179 assertTrue("reslen >= 0", reslen >= 0);
6180 assertEquals("uloc_getName()", empty_script, tmp);
6181
6182 uprv_memset(tmp, '!', sizeof tmp);
6183 reslen = uloc_getName(empty_region, tmp, sizeof tmp, status);
6184 status.errIfFailureAndReset("\"%s\"", empty_region);
6185 assertTrue("reslen >= 0", reslen >= 0);
6186 assertEquals("uloc_getName()", empty_region, tmp);
6187
6188 uprv_memset(tmp, '!', sizeof tmp);
6189 reslen = uloc_getName(und_script, tmp, sizeof tmp, status);
6190 status.errIfFailureAndReset("\"%s\"", und_script);
6191 assertTrue("reslen >= 0", reslen >= 0);
6192 assertEquals("uloc_getName()", empty_script, tmp);
6193
6194 uprv_memset(tmp, '!', sizeof tmp);
6195 reslen = uloc_getName(und_region, tmp, sizeof tmp, status);
6196 status.errIfFailureAndReset("\"%s\"", und_region);
6197 assertTrue("reslen >= 0", reslen >= 0);
6198 assertEquals("uloc_getName()", empty_region, tmp);
6199
6200 // uloc_getBaseName()
6201
6202 uprv_memset(tmp, '!', sizeof tmp);
6203 reslen = uloc_getBaseName(empty, tmp, sizeof tmp, status);
6204 status.errIfFailureAndReset("\"%s\"", empty);
6205 assertTrue("reslen >= 0", reslen >= 0);
6206 assertEquals("uloc_getBaseName()", empty, tmp);
6207
6208 uprv_memset(tmp, '!', sizeof tmp);
6209 reslen = uloc_getBaseName(root, tmp, sizeof tmp, status);
6210 status.errIfFailureAndReset("\"%s\"", root);
6211 assertTrue("reslen >= 0", reslen >= 0);
6212 assertEquals("uloc_getBaseName()", empty, tmp);
6213
6214 uprv_memset(tmp, '!', sizeof tmp);
6215 reslen = uloc_getBaseName(und, tmp, sizeof tmp, status);
6216 status.errIfFailureAndReset("\"%s\"", und);
6217 assertTrue("reslen >= 0", reslen >= 0);
6218 assertEquals("uloc_getBaseName()", empty, tmp);
6219
6220 uprv_memset(tmp, '!', sizeof tmp);
6221 reslen = uloc_getBaseName(empty_script, tmp, sizeof tmp, status);
6222 status.errIfFailureAndReset("\"%s\"", empty_script);
6223 assertTrue("reslen >= 0", reslen >= 0);
6224 assertEquals("uloc_getBaseName()", empty_script, tmp);
6225
6226 uprv_memset(tmp, '!', sizeof tmp);
6227 reslen = uloc_getBaseName(empty_region, tmp, sizeof tmp, status);
6228 status.errIfFailureAndReset("\"%s\"", empty_region);
6229 assertTrue("reslen >= 0", reslen >= 0);
6230 assertEquals("uloc_getBaseName()", empty_region, tmp);
6231
6232 uprv_memset(tmp, '!', sizeof tmp);
6233 reslen = uloc_getBaseName(und_script, tmp, sizeof tmp, status);
6234 status.errIfFailureAndReset("\"%s\"", und_script);
6235 assertTrue("reslen >= 0", reslen >= 0);
6236 assertEquals("uloc_getBaseName()", empty_script, tmp);
6237
6238 uprv_memset(tmp, '!', sizeof tmp);
6239 reslen = uloc_getBaseName(und_region, tmp, sizeof tmp, status);
6240 status.errIfFailureAndReset("\"%s\"", und_region);
6241 assertTrue("reslen >= 0", reslen >= 0);
6242 assertEquals("uloc_getBaseName()", empty_region, tmp);
6243
6244 // uloc_getParent()
6245
6246 uprv_memset(tmp, '!', sizeof tmp);
6247 reslen = uloc_getParent(empty, tmp, sizeof tmp, status);
6248 status.errIfFailureAndReset("\"%s\"", empty);
6249 assertTrue("reslen >= 0", reslen >= 0);
6250 assertEquals("uloc_getParent()", empty, tmp);
6251
6252 uprv_memset(tmp, '!', sizeof tmp);
6253 reslen = uloc_getParent(root, tmp, sizeof tmp, status);
6254 status.errIfFailureAndReset("\"%s\"", root);
6255 assertTrue("reslen >= 0", reslen >= 0);
6256 assertEquals("uloc_getParent()", empty, tmp);
6257
6258 uprv_memset(tmp, '!', sizeof tmp);
6259 reslen = uloc_getParent(und, tmp, sizeof tmp, status);
6260 status.errIfFailureAndReset("\"%s\"", und);
6261 assertTrue("reslen >= 0", reslen >= 0);
6262 assertEquals("uloc_getParent()", empty, tmp);
6263
6264 uprv_memset(tmp, '!', sizeof tmp);
6265 reslen = uloc_getParent(empty_script, tmp, sizeof tmp, status);
6266 status.errIfFailureAndReset("\"%s\"", empty_script);
6267 assertTrue("reslen >= 0", reslen >= 0);
6268 assertEquals("uloc_getParent()", empty, tmp);
6269
6270 uprv_memset(tmp, '!', sizeof tmp);
6271 reslen = uloc_getParent(empty_region, tmp, sizeof tmp, status);
6272 status.errIfFailureAndReset("\"%s\"", empty_region);
6273 assertTrue("reslen >= 0", reslen >= 0);
6274 assertEquals("uloc_getParent()", empty, tmp);
6275
6276 uprv_memset(tmp, '!', sizeof tmp);
6277 reslen = uloc_getParent(und_script, tmp, sizeof tmp, status);
6278 status.errIfFailureAndReset("\"%s\"", und_script);
6279 assertTrue("reslen >= 0", reslen >= 0);
6280 assertEquals("uloc_getParent()", empty, tmp);
6281
6282 uprv_memset(tmp, '!', sizeof tmp);
6283 reslen = uloc_getParent(und_region, tmp, sizeof tmp, status);
6284 status.errIfFailureAndReset("\"%s\"", und_region);
6285 assertTrue("reslen >= 0", reslen >= 0);
6286 assertEquals("uloc_getParent()", empty, tmp);
6287
6288 // uloc_getLanguage()
6289
6290 uprv_memset(tmp, '!', sizeof tmp);
6291 reslen = uloc_getLanguage(empty, tmp, sizeof tmp, status);
6292 status.errIfFailureAndReset("\"%s\"", empty);
6293 assertTrue("reslen >= 0", reslen >= 0);
6294 assertEquals("uloc_getLanguage()", empty, tmp);
6295
6296 uprv_memset(tmp, '!', sizeof tmp);
6297 reslen = uloc_getLanguage(root, tmp, sizeof tmp, status);
6298 status.errIfFailureAndReset("\"%s\"", root);
6299 assertTrue("reslen >= 0", reslen >= 0);
6300 assertEquals("uloc_getLanguage()", empty, tmp);
6301
6302 uprv_memset(tmp, '!', sizeof tmp);
6303 reslen = uloc_getLanguage(und, tmp, sizeof tmp, status);
6304 status.errIfFailureAndReset("\"%s\"", und);
6305 assertTrue("reslen >= 0", reslen >= 0);
6306 assertEquals("uloc_getLanguage()", empty, tmp);
6307
6308 uprv_memset(tmp, '!', sizeof tmp);
6309 reslen = uloc_getLanguage(empty_script, tmp, sizeof tmp, status);
6310 status.errIfFailureAndReset("\"%s\"", empty_script);
6311 assertTrue("reslen >= 0", reslen >= 0);
6312 assertEquals("uloc_getLanguage()", empty, tmp);
6313
6314 uprv_memset(tmp, '!', sizeof tmp);
6315 reslen = uloc_getLanguage(empty_region, tmp, sizeof tmp, status);
6316 status.errIfFailureAndReset("\"%s\"", empty_region);
6317 assertTrue("reslen >= 0", reslen >= 0);
6318 assertEquals("uloc_getLanguage()", empty, tmp);
6319
6320 uprv_memset(tmp, '!', sizeof tmp);
6321 reslen = uloc_getLanguage(und_script, tmp, sizeof tmp, status);
6322 status.errIfFailureAndReset("\"%s\"", und_script);
6323 assertTrue("reslen >= 0", reslen >= 0);
6324 assertEquals("uloc_getLanguage()", empty, tmp);
6325
6326 uprv_memset(tmp, '!', sizeof tmp);
6327 reslen = uloc_getLanguage(und_region, tmp, sizeof tmp, status);
6328 status.errIfFailureAndReset("\"%s\"", und_region);
6329 assertTrue("reslen >= 0", reslen >= 0);
6330 assertEquals("uloc_getLanguage()", empty, tmp);
6331 }
6332
6333 #define ARRAY_RANGE(array) (array), ((array) + UPRV_LENGTHOF(array))
6334
TestRangeIterator()6335 void LocaleTest::TestRangeIterator() {
6336 IcuTestErrorCode status(*this, "TestRangeIterator");
6337 Locale locales[] = { "fr", "en_GB", "en" };
6338 Locale::RangeIterator<Locale *> iter(ARRAY_RANGE(locales));
6339
6340 assertTrue("0.hasNext()", iter.hasNext());
6341 const Locale &l0 = iter.next();
6342 assertEquals("0.next()", "fr", l0.getName());
6343 assertTrue("&0.next()", &l0 == &locales[0]);
6344
6345 assertTrue("1.hasNext()", iter.hasNext());
6346 const Locale &l1 = iter.next();
6347 assertEquals("1.next()", "en_GB", l1.getName());
6348 assertTrue("&1.next()", &l1 == &locales[1]);
6349
6350 assertTrue("2.hasNext()", iter.hasNext());
6351 const Locale &l2 = iter.next();
6352 assertEquals("2.next()", "en", l2.getName());
6353 assertTrue("&2.next()", &l2 == &locales[2]);
6354
6355 assertFalse("3.hasNext()", iter.hasNext());
6356 }
6357
TestPointerConvertingIterator()6358 void LocaleTest::TestPointerConvertingIterator() {
6359 IcuTestErrorCode status(*this, "TestPointerConvertingIterator");
6360 Locale locales[] = { "fr", "en_GB", "en" };
6361 Locale *pointers[] = { locales, locales + 1, locales + 2 };
6362 // Lambda with explicit reference return type to prevent copy-constructing a temporary
6363 // which would be destructed right away.
6364 Locale::ConvertingIterator<Locale **, std::function<const Locale &(const Locale *)>> iter(
6365 ARRAY_RANGE(pointers), [](const Locale *p) -> const Locale & { return *p; });
6366
6367 assertTrue("0.hasNext()", iter.hasNext());
6368 const Locale &l0 = iter.next();
6369 assertEquals("0.next()", "fr", l0.getName());
6370 assertTrue("&0.next()", &l0 == pointers[0]);
6371
6372 assertTrue("1.hasNext()", iter.hasNext());
6373 const Locale &l1 = iter.next();
6374 assertEquals("1.next()", "en_GB", l1.getName());
6375 assertTrue("&1.next()", &l1 == pointers[1]);
6376
6377 assertTrue("2.hasNext()", iter.hasNext());
6378 const Locale &l2 = iter.next();
6379 assertEquals("2.next()", "en", l2.getName());
6380 assertTrue("&2.next()", &l2 == pointers[2]);
6381
6382 assertFalse("3.hasNext()", iter.hasNext());
6383 }
6384
6385 namespace {
6386
6387 class LocaleFromTag {
6388 public:
LocaleFromTag()6389 LocaleFromTag() : locale(Locale::getRoot()) {}
operator ()(const char * tag)6390 const Locale &operator()(const char *tag) { return locale = Locale(tag); }
6391
6392 private:
6393 // Store the locale in the converter, rather than return a reference to a temporary,
6394 // or a value which could go out of scope with the caller's reference to it.
6395 Locale locale;
6396 };
6397
6398 } // namespace
6399
TestTagConvertingIterator()6400 void LocaleTest::TestTagConvertingIterator() {
6401 IcuTestErrorCode status(*this, "TestTagConvertingIterator");
6402 const char *tags[] = { "fr", "en_GB", "en" };
6403 LocaleFromTag converter;
6404 Locale::ConvertingIterator<const char **, LocaleFromTag> iter(ARRAY_RANGE(tags), converter);
6405
6406 assertTrue("0.hasNext()", iter.hasNext());
6407 const Locale &l0 = iter.next();
6408 assertEquals("0.next()", "fr", l0.getName());
6409
6410 assertTrue("1.hasNext()", iter.hasNext());
6411 const Locale &l1 = iter.next();
6412 assertEquals("1.next()", "en_GB", l1.getName());
6413
6414 assertTrue("2.hasNext()", iter.hasNext());
6415 const Locale &l2 = iter.next();
6416 assertEquals("2.next()", "en", l2.getName());
6417
6418 assertFalse("3.hasNext()", iter.hasNext());
6419 }
6420
TestCapturingTagConvertingIterator()6421 void LocaleTest::TestCapturingTagConvertingIterator() {
6422 IcuTestErrorCode status(*this, "TestCapturingTagConvertingIterator");
6423 const char *tags[] = { "fr", "en_GB", "en" };
6424 // Store the converted locale in a locale variable,
6425 // rather than return a reference to a temporary,
6426 // or a value which could go out of scope with the caller's reference to it.
6427 Locale locale;
6428 // Lambda with explicit reference return type to prevent copy-constructing a temporary
6429 // which would be destructed right away.
6430 Locale::ConvertingIterator<const char **, std::function<const Locale &(const char *)>> iter(
6431 ARRAY_RANGE(tags), [&](const char *tag) -> const Locale & { return locale = Locale(tag); });
6432
6433 assertTrue("0.hasNext()", iter.hasNext());
6434 const Locale &l0 = iter.next();
6435 assertEquals("0.next()", "fr", l0.getName());
6436
6437 assertTrue("1.hasNext()", iter.hasNext());
6438 const Locale &l1 = iter.next();
6439 assertEquals("1.next()", "en_GB", l1.getName());
6440
6441 assertTrue("2.hasNext()", iter.hasNext());
6442 const Locale &l2 = iter.next();
6443 assertEquals("2.next()", "en", l2.getName());
6444
6445 assertFalse("3.hasNext()", iter.hasNext());
6446 }
6447
TestSetUnicodeKeywordValueInLongLocale()6448 void LocaleTest::TestSetUnicodeKeywordValueInLongLocale() {
6449 IcuTestErrorCode status(*this, "TestSetUnicodeKeywordValueInLongLocale");
6450 const char* value = "efghijkl";
6451 icu::Locale l("de");
6452 char keyword[3];
6453 CharString expected("de-u", status);
6454 keyword[2] = '\0';
6455 for (char i = 'a'; i < 's'; i++) {
6456 keyword[0] = keyword[1] = i;
6457 expected.append("-", status);
6458 expected.append(keyword, status);
6459 expected.append("-", status);
6460 expected.append(value, status);
6461 l.setUnicodeKeywordValue(keyword, value, status);
6462 if (status.errIfFailureAndReset(
6463 "setUnicodeKeywordValue(\"%s\", \"%s\") fail while locale is \"%s\"",
6464 keyword, value, l.getName())) {
6465 return;
6466 }
6467 std::string tag = l.toLanguageTag<std::string>(status);
6468 if (status.errIfFailureAndReset(
6469 "toLanguageTag fail on \"%s\"", l.getName())) {
6470 return;
6471 }
6472 if (tag != expected.data()) {
6473 errln("Expected to get \"%s\" bug got \"%s\"", tag.c_str(),
6474 expected.data());
6475 return;
6476 }
6477 }
6478 }
6479
TestSetUnicodeKeywordValueNullInLongLocale()6480 void LocaleTest::TestSetUnicodeKeywordValueNullInLongLocale() {
6481 IcuTestErrorCode status(*this, "TestSetUnicodeKeywordValueNullInLongLocale");
6482 const char *exts[] = {"cf", "cu", "em", "kk", "kr", "ks", "kv", "lb", "lw",
6483 "ms", "nu", "rg", "sd", "ss", "tz"};
6484 for (int32_t i = 0; i < UPRV_LENGTHOF(exts); i++) {
6485 CharString tag("de-u", status);
6486 for (int32_t j = 0; j <= i; j++) {
6487 tag.append("-", status).append(exts[j], status);
6488 }
6489 if (status.errIfFailureAndReset(
6490 "Cannot create tag \"%s\"", tag.data())) {
6491 continue;
6492 }
6493 Locale l = Locale::forLanguageTag(tag.data(), status);
6494 if (status.errIfFailureAndReset(
6495 "Locale::forLanguageTag(\"%s\") failed", tag.data())) {
6496 continue;
6497 }
6498 for (int32_t j = 0; j <= i; j++) {
6499 l.setUnicodeKeywordValue(exts[j], nullptr, status);
6500 if (status.errIfFailureAndReset(
6501 "Locale(\"%s\").setUnicodeKeywordValue(\"%s\", nullptr) failed",
6502 tag.data(), exts[j])) {
6503 continue;
6504 }
6505 }
6506 if (strcmp("de", l.getName()) != 0) {
6507 errln("setUnicodeKeywordValue should remove all extensions from "
6508 "\"%s\" and only have \"de\", but is \"%s\" instead.",
6509 tag.data(), l.getName());
6510 }
6511 }
6512 }
6513
TestLeak21419()6514 void LocaleTest::TestLeak21419() {
6515 IcuTestErrorCode status(*this, "TestLeak21419");
6516 Locale l = Locale("s-yU");
6517 l.canonicalize(status);
6518 status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR);
6519 }
6520