Source code

Revision control

Other Tools

1
// Generated by make_intl_data.py. DO NOT EDIT.
2
// Version: CLDR-36
4
5
#include "mozilla/Assertions.h"
6
#include "mozilla/Span.h"
7
#include "mozilla/TextUtils.h"
8
9
#include <algorithm>
10
#include <cstdint>
11
#include <cstring>
12
#include <iterator>
13
#include <type_traits>
14
15
#include "builtin/intl/LanguageTag.h"
16
#include "util/Text.h"
17
#include "vm/JSContext.h"
18
19
using namespace js::intl::LanguageTagLimits;
20
21
template <size_t Length, size_t TagLength, size_t SubtagLength>
22
static inline bool HasReplacement(
23
const char (&subtags)[Length][TagLength],
24
const js::intl::LanguageTagSubtag<SubtagLength>& subtag) {
25
MOZ_ASSERT(subtag.length() == TagLength - 1,
26
"subtag must have the same length as the list of subtags");
27
28
const char* ptr = subtag.span().data();
29
return std::binary_search(std::begin(subtags), std::end(subtags), ptr,
30
[](const char* a, const char* b) {
31
return memcmp(a, b, TagLength - 1) < 0;
32
});
33
}
34
35
template <size_t Length, size_t TagLength, size_t SubtagLength>
36
static inline const char* SearchReplacement(
37
const char (&subtags)[Length][TagLength],
38
const char* (&aliases)[Length],
39
const js::intl::LanguageTagSubtag<SubtagLength>& subtag) {
40
MOZ_ASSERT(subtag.length() == TagLength - 1,
41
"subtag must have the same length as the list of subtags");
42
43
const char* ptr = subtag.span().data();
44
auto p = std::lower_bound(std::begin(subtags), std::end(subtags), ptr,
45
[](const char* a, const char* b) {
46
return memcmp(a, b, TagLength - 1) < 0;
47
});
48
if (p != std::end(subtags) && memcmp(*p, ptr, TagLength - 1) == 0) {
49
return aliases[std::distance(std::begin(subtags), p)];
50
}
51
return nullptr;
52
}
53
54
#ifdef DEBUG
55
static bool IsCanonicallyCasedLanguageTag(mozilla::Span<const char> span) {
56
// Tell the analysis the |std::all_of| function can't GC.
57
JS::AutoSuppressGCAnalysis nogc;
58
59
return std::all_of(span.begin(), span.end(), mozilla::IsAsciiLowercaseAlpha<char>);
60
}
61
62
static bool IsCanonicallyCasedRegionTag(mozilla::Span<const char> span) {
63
// Tell the analysis the |std::all_of| function can't GC.
64
JS::AutoSuppressGCAnalysis nogc;
65
66
return std::all_of(span.begin(), span.end(), mozilla::IsAsciiUppercaseAlpha<char>) ||
67
std::all_of(span.begin(), span.end(), mozilla::IsAsciiDigit<char>);
68
}
69
70
static bool IsCanonicallyCasedVariantTag(mozilla::Span<const char> span) {
71
auto isAsciiLowercaseAlphaOrDigit = [](char c) {
72
return mozilla::IsAsciiLowercaseAlpha(c) || mozilla::IsAsciiDigit(c);
73
};
74
75
// Tell the analysis the |std::all_of| function can't GC.
76
JS::AutoSuppressGCAnalysis nogc;
77
78
return std::all_of(span.begin(), span.end(), isAsciiLowercaseAlphaOrDigit);
79
}
80
#endif
81
82
// Mappings from language subtags to preferred values.
83
// Derived from CLDR Supplemental Data, version 36.
85
bool js::intl::LanguageTag::languageMapping(LanguageSubtag& language) {
86
MOZ_ASSERT(IsStructurallyValidLanguageTag(language.span()));
87
MOZ_ASSERT(IsCanonicallyCasedLanguageTag(language.span()));
88
89
if (language.length() == 2) {
90
static const char languages[9][3] = {
91
"bh", "in", "iw", "ji", "jw", "mo", "no", "tl", "tw",
92
};
93
static const char* aliases[9] = {
94
"bho", "id", "he", "yi", "jv", "ro", "nb", "fil", "ak",
95
};
96
97
if (const char* replacement = SearchReplacement(languages, aliases, language)) {
98
language.set(mozilla::MakeStringSpan(replacement));
99
return true;
100
}
101
return false;
102
}
103
104
if (language.length() == 3) {
105
static const char languages[345][4] = {
106
"aam", "aar", "abk", "adp", "afr", "aju", "aka", "alb", "als", "amh",
107
"ara", "arb", "arg", "arm", "asd", "asm", "aue", "ava", "ave", "aym",
108
"ayr", "ayx", "aze", "azj", "bak", "bam", "baq", "bcc", "bcl", "bel",
109
"ben", "bgm", "bih", "bis", "bjd", "bod", "bos", "bre", "bul", "bur",
110
"bxk", "bxr", "cat", "ccq", "ces", "cha", "che", "chi", "chu", "chv",
111
"cjr", "cka", "cld", "cmk", "cmn", "cor", "cos", "coy", "cqu", "cre",
112
"cwd", "cym", "cze", "dan", "deu", "dgo", "dhd", "dik", "diq", "dit",
113
"div", "drh", "dut", "dzo", "ekk", "ell", "emk", "eng", "epo", "esk",
114
"est", "eus", "ewe", "fao", "fas", "fat", "fij", "fin", "fra", "fre",
115
"fry", "fuc", "ful", "gav", "gaz", "gbo", "geo", "ger", "gfx", "ggn",
116
"gla", "gle", "glg", "glv", "gno", "gre", "grn", "gti", "gug", "guj",
117
"guv", "gya", "hat", "hau", "hdn", "hea", "heb", "her", "him", "hin",
118
"hmo", "hrr", "hrv", "hun", "hye", "ibi", "ibo", "ice", "ido", "iii",
119
"ike", "iku", "ile", "ilw", "ina", "ind", "ipk", "isl", "ita", "jav",
120
"jeg", "jpn", "kal", "kan", "kas", "kat", "kau", "kaz", "kgc", "kgh",
121
"khk", "khm", "kik", "kin", "kir", "kmr", "knc", "kng", "knn", "koj",
122
"kom", "kon", "kor", "kpv", "krm", "ktr", "kua", "kur", "kvs", "kwq",
123
"kxe", "kzj", "kzt", "lao", "lat", "lav", "lbk", "lii", "lim", "lin",
124
"lit", "llo", "lmm", "ltz", "lub", "lug", "lvs", "mac", "mah", "mal",
125
"mao", "mar", "may", "meg", "mhr", "mkd", "mlg", "mlt", "mnk", "mol",
126
"mon", "mri", "msa", "mst", "mup", "mwj", "mya", "myd", "myt", "nad",
127
"nau", "nav", "nbl", "ncp", "nde", "ndo", "nep", "nld", "nno", "nns",
128
"nnx", "nob", "nor", "npi", "nts", "nya", "oci", "ojg", "oji", "ori",
129
"orm", "ory", "oss", "oun", "pan", "pbu", "pcr", "per", "pes", "pli",
130
"plt", "pmc", "pmu", "pnb", "pol", "por", "ppa", "ppr", "pry", "pus",
131
"puz", "que", "quz", "rmy", "roh", "ron", "rum", "run", "rus", "sag",
132
"san", "sca", "scc", "scr", "sin", "skk", "slk", "slo", "slv", "sme",
133
"smo", "sna", "snd", "som", "sot", "spa", "spy", "sqi", "src", "srd",
134
"srp", "ssw", "sun", "swa", "swe", "swh", "tah", "tam", "tat", "tdu",
135
"tel", "tgk", "tgl", "tha", "thc", "thx", "tib", "tie", "tir", "tkk",
136
"tlw", "tmp", "tne", "ton", "tsf", "tsn", "tso", "ttq", "tuk", "tur",
137
"twi", "uig", "ukr", "umu", "uok", "urd", "uzb", "uzn", "ven", "vie",
138
"vol", "wel", "wln", "wol", "xba", "xho", "xia", "xkh", "xpe", "xsj",
139
"xsl", "ybd", "ydd", "yid", "yma", "ymt", "yor", "yos", "yuu", "zai",
140
"zha", "zho", "zsm", "zul", "zyb",
141
};
142
static const char* aliases[345] = {
143
"aas", "aa", "ab", "dz", "af", "jrb", "ak", "sq", "sq", "am",
144
"ar", "ar", "an", "hy", "snz", "as", "ktz", "av", "ae", "ay",
145
"ay", "nun", "az", "az", "ba", "bm", "eu", "bal", "bik", "be",
146
"bn", "bcg", "bho", "bi", "drl", "bo", "bs", "br", "bg", "my",
147
"luy", "bua", "ca", "rki", "cs", "ch", "ce", "zh", "cu", "cv",
148
"mom", "cmr", "syr", "xch", "zh", "kw", "co", "pij", "quh", "cr",
149
"cr", "cy", "cs", "da", "de", "doi", "mwr", "din", "zza", "dif",
150
"dv", "mn", "nl", "dz", "et", "el", "man", "en", "eo", "ik",
151
"et", "eu", "ee", "fo", "fa", "ak", "fj", "fi", "fr", "fr",
152
"fy", "ff", "ff", "dev", "om", "grb", "ka", "de", "vaj", "gvr",
153
"gd", "ga", "gl", "gv", "gon", "el", "gn", "nyc", "gn", "gu",
154
"duz", "gba", "ht", "ha", "hai", "hmn", "he", "hz", "srx", "hi",
155
"ho", "jal", "hr", "hu", "hy", "opa", "ig", "is", "io", "ii",
156
"iu", "iu", "ie", "gal", "ia", "id", "ik", "is", "it", "jv",
157
"oyb", "ja", "kl", "kn", "ks", "ka", "kr", "kk", "tdf", "kml",
158
"mn", "km", "ki", "rw", "ky", "ku", "kr", "kg", "kok", "kwv",
159
"kv", "kg", "ko", "kv", "bmf", "dtp", "kj", "ku", "gdj", "yam",
160
"tvd", "dtp", "dtp", "lo", "la", "lv", "bnc", "raq", "li", "ln",
161
"lt", "ngt", "rmx", "lb", "lu", "lg", "lv", "mk", "mh", "ml",
162
"mi", "mr", "ms", "cir", "chm", "mk", "mg", "mt", "man", "ro",
163
"mn", "mi", "ms", "mry", "raj", "vaj", "my", "aog", "mry", "xny",
164
"na", "nv", "nr", "kdz", "nd", "ng", "ne", "nl", "nn", "nbr",
165
"ngv", "nb", "nb", "ne", "pij", "ny", "oc", "oj", "oj", "or",
166
"om", "or", "os", "vaj", "pa", "ps", "adx", "fa", "fa", "pi",
167
"mg", "huw", "phr", "lah", "pl", "pt", "bfy", "lcq", "prt", "ps",
168
"pub", "qu", "qu", "rom", "rm", "ro", "ro", "rn", "ru", "sg",
169
"sa", "hle", "sr", "hr", "si", "oyb", "sk", "sk", "sl", "se",
170
"sm", "sn", "sd", "so", "st", "es", "kln", "sq", "sc", "sc",
171
"sr", "ss", "su", "sw", "sv", "sw", "ty", "ta", "tt", "dtp",
172
"te", "tg", "fil", "th", "tpo", "oyb", "bo", "ras", "ti", "twm",
173
"weo", "tyj", "kak", "to", "taj", "tn", "ts", "tmh", "tk", "tr",
174
"ak", "ug", "uk", "del", "ema", "ur", "uz", "uz", "ve", "vi",
175
"vo", "cy", "wa", "wo", "cax", "xh", "acn", "waw", "kpe", "suj",
176
"den", "rki", "yi", "yi", "lrr", "mtm", "yo", "zom", "yug", "zap",
177
"za", "zh", "ms", "zu", "za",
178
};
179
180
if (const char* replacement = SearchReplacement(languages, aliases, language)) {
181
language.set(mozilla::MakeStringSpan(replacement));
182
return true;
183
}
184
return false;
185
}
186
187
return false;
188
}
189
190
// Language subtags with complex mappings.
191
// Derived from CLDR Supplemental Data, version 36.
193
bool js::intl::LanguageTag::complexLanguageMapping(const LanguageSubtag& language) {
194
MOZ_ASSERT(IsStructurallyValidLanguageTag(language.span()));
195
MOZ_ASSERT(IsCanonicallyCasedLanguageTag(language.span()));
196
197
if (language.length() == 2) {
198
return language.equalTo("sh");
199
}
200
201
if (language.length() == 3) {
202
static const char languages[6][4] = {
203
"cnr", "drw", "hbs", "prs", "swc", "tnf",
204
};
205
206
return HasReplacement(languages, language);
207
}
208
209
return false;
210
}
211
212
// Mappings from region subtags to preferred values.
213
// Derived from CLDR Supplemental Data, version 36.
215
bool js::intl::LanguageTag::regionMapping(RegionSubtag& region) {
216
MOZ_ASSERT(IsStructurallyValidRegionTag(region.span()));
217
MOZ_ASSERT(IsCanonicallyCasedRegionTag(region.span()));
218
219
if (region.length() == 2) {
220
static const char regions[23][3] = {
221
"BU", "CS", "CT", "DD", "DY", "FQ", "FX", "HV", "JT", "MI",
222
"NH", "NQ", "PU", "PZ", "QU", "RH", "TP", "UK", "VD", "WK",
223
"YD", "YU", "ZR",
224
};
225
static const char* aliases[23] = {
226
"MM", "RS", "KI", "DE", "BJ", "AQ", "FR", "BF", "UM", "UM",
227
"VU", "AQ", "UM", "PA", "EU", "ZW", "TL", "GB", "VN", "UM",
228
"YE", "RS", "CD",
229
};
230
231
if (const char* replacement = SearchReplacement(regions, aliases, region)) {
232
region.set(mozilla::MakeStringSpan(replacement));
233
return true;
234
}
235
return false;
236
}
237
238
{
239
static const char regions[300][4] = {
240
"004", "008", "010", "012", "016", "020", "024", "028", "031", "032",
241
"036", "040", "044", "048", "050", "051", "052", "056", "060", "062",
242
"064", "068", "070", "072", "074", "076", "084", "086", "090", "092",
243
"096", "100", "104", "108", "112", "116", "120", "124", "132", "136",
244
"140", "144", "148", "152", "156", "158", "162", "166", "170", "174",
245
"175", "178", "180", "184", "188", "191", "192", "196", "203", "204",
246
"208", "212", "214", "218", "222", "226", "230", "231", "232", "233",
247
"234", "238", "239", "242", "246", "248", "249", "250", "254", "258",
248
"260", "262", "266", "268", "270", "275", "276", "278", "280", "288",
249
"292", "296", "300", "304", "308", "312", "316", "320", "324", "328",
250
"332", "334", "336", "340", "344", "348", "352", "356", "360", "364",
251
"368", "372", "376", "380", "384", "388", "392", "398", "400", "404",
252
"408", "410", "414", "417", "418", "422", "426", "428", "430", "434",
253
"438", "440", "442", "446", "450", "454", "458", "462", "466", "470",
254
"474", "478", "480", "484", "492", "496", "498", "499", "500", "504",
255
"508", "512", "516", "520", "524", "528", "531", "533", "534", "535",
256
"540", "548", "554", "558", "562", "566", "570", "574", "578", "580",
257
"581", "583", "584", "585", "586", "591", "598", "600", "604", "608",
258
"612", "616", "620", "624", "626", "630", "634", "638", "642", "643",
259
"646", "652", "654", "659", "660", "662", "663", "666", "670", "674",
260
"678", "682", "686", "688", "690", "694", "702", "703", "704", "705",
261
"706", "710", "716", "720", "724", "728", "729", "732", "736", "740",
262
"744", "748", "752", "756", "760", "762", "764", "768", "772", "776",
263
"780", "784", "788", "792", "795", "796", "798", "800", "804", "807",
264
"818", "826", "830", "831", "832", "833", "834", "840", "850", "854",
265
"858", "860", "862", "876", "882", "886", "887", "891", "894", "958",
266
"959", "960", "962", "963", "964", "965", "966", "967", "968", "969",
267
"970", "971", "972", "973", "974", "975", "976", "977", "978", "979",
268
"980", "981", "982", "983", "984", "985", "986", "987", "988", "989",
269
"990", "991", "992", "993", "994", "995", "996", "997", "998", "999",
270
};
271
static const char* aliases[300] = {
272
"AF", "AL", "AQ", "DZ", "AS", "AD", "AO", "AG", "AZ", "AR",
273
"AU", "AT", "BS", "BH", "BD", "AM", "BB", "BE", "BM", "034",
274
"BT", "BO", "BA", "BW", "BV", "BR", "BZ", "IO", "SB", "VG",
275
"BN", "BG", "MM", "BI", "BY", "KH", "CM", "CA", "CV", "KY",
276
"CF", "LK", "TD", "CL", "CN", "TW", "CX", "CC", "CO", "KM",
277
"YT", "CG", "CD", "CK", "CR", "HR", "CU", "CY", "CZ", "BJ",
278
"DK", "DM", "DO", "EC", "SV", "GQ", "ET", "ET", "ER", "EE",
279
"FO", "FK", "GS", "FJ", "FI", "AX", "FR", "FR", "GF", "PF",
280
"TF", "DJ", "GA", "GE", "GM", "PS", "DE", "DE", "DE", "GH",
281
"GI", "KI", "GR", "GL", "GD", "GP", "GU", "GT", "GN", "GY",
282
"HT", "HM", "VA", "HN", "HK", "HU", "IS", "IN", "ID", "IR",
283
"IQ", "IE", "IL", "IT", "CI", "JM", "JP", "KZ", "JO", "KE",
284
"KP", "KR", "KW", "KG", "LA", "LB", "LS", "LV", "LR", "LY",
285
"LI", "LT", "LU", "MO", "MG", "MW", "MY", "MV", "ML", "MT",
286
"MQ", "MR", "MU", "MX", "MC", "MN", "MD", "ME", "MS", "MA",
287
"MZ", "OM", "NA", "NR", "NP", "NL", "CW", "AW", "SX", "BQ",
288
"NC", "VU", "NZ", "NI", "NE", "NG", "NU", "NF", "NO", "MP",
289
"UM", "FM", "MH", "PW", "PK", "PA", "PG", "PY", "PE", "PH",
290
"PN", "PL", "PT", "GW", "TL", "PR", "QA", "RE", "RO", "RU",
291
"RW", "BL", "SH", "KN", "AI", "LC", "MF", "PM", "VC", "SM",
292
"ST", "SA", "SN", "RS", "SC", "SL", "SG", "SK", "VN", "SI",
293
"SO", "ZA", "ZW", "YE", "ES", "SS", "SD", "EH", "SD", "SR",
294
"SJ", "SZ", "SE", "CH", "SY", "TJ", "TH", "TG", "TK", "TO",
295
"TT", "AE", "TN", "TR", "TM", "TC", "TV", "UG", "UA", "MK",
296
"EG", "GB", "JE", "GG", "JE", "IM", "TZ", "US", "VI", "BF",
297
"UY", "UZ", "VE", "WF", "WS", "YE", "YE", "RS", "ZM", "AA",
298
"QM", "QN", "QP", "QQ", "QR", "QS", "QT", "EU", "QV", "QW",
299
"QX", "QY", "QZ", "XA", "XB", "XC", "XD", "XE", "XF", "XG",
300
"XH", "XI", "XJ", "XK", "XL", "XM", "XN", "XO", "XP", "XQ",
301
"XR", "XS", "XT", "XU", "XV", "XW", "XX", "XY", "XZ", "ZZ",
302
};
303
304
if (const char* replacement = SearchReplacement(regions, aliases, region)) {
305
region.set(mozilla::MakeStringSpan(replacement));
306
return true;
307
}
308
return false;
309
}
310
}
311
312
// Region subtags with complex mappings.
313
// Derived from CLDR Supplemental Data, version 36.
315
bool js::intl::LanguageTag::complexRegionMapping(const RegionSubtag& region) {
316
MOZ_ASSERT(IsStructurallyValidRegionTag(region.span()));
317
MOZ_ASSERT(IsCanonicallyCasedRegionTag(region.span()));
318
319
if (region.length() == 2) {
320
return region.equalTo("AN") ||
321
region.equalTo("NT") ||
322
region.equalTo("PC") ||
323
region.equalTo("SU");
324
}
325
326
{
327
static const char regions[8][4] = {
328
"172", "200", "530", "532", "536", "582", "810", "890",
329
};
330
331
return HasReplacement(regions, region);
332
}
333
}
334
335
// Language subtags with complex mappings.
336
// Derived from CLDR Supplemental Data, version 36.
338
void js::intl::LanguageTag::performComplexLanguageMappings() {
339
MOZ_ASSERT(IsStructurallyValidLanguageTag(language().span()));
340
MOZ_ASSERT(IsCanonicallyCasedLanguageTag(language().span()));
341
342
if (language().equalTo("cnr")) {
343
setLanguage("sr");
344
if (region().missing()) {
345
setRegion("ME");
346
}
347
}
348
else if (language().equalTo("drw") ||
349
language().equalTo("prs") ||
350
language().equalTo("tnf")) {
351
setLanguage("fa");
352
if (region().missing()) {
353
setRegion("AF");
354
}
355
}
356
else if (language().equalTo("hbs") ||
357
language().equalTo("sh")) {
358
setLanguage("sr");
359
if (script().missing()) {
360
setScript("Latn");
361
}
362
}
363
else if (language().equalTo("swc")) {
364
setLanguage("sw");
365
if (region().missing()) {
366
setRegion("CD");
367
}
368
}
369
}
370
371
// Region subtags with complex mappings.
372
// Derived from CLDR Supplemental Data, version 36.
374
void js::intl::LanguageTag::performComplexRegionMappings() {
375
MOZ_ASSERT(IsStructurallyValidLanguageTag(language().span()));
376
MOZ_ASSERT(IsCanonicallyCasedLanguageTag(language().span()));
377
MOZ_ASSERT(IsStructurallyValidRegionTag(region().span()));
378
MOZ_ASSERT(IsCanonicallyCasedRegionTag(region().span()));
379
380
if (region().equalTo("172")) {
381
if (language().equalTo("hy") ||
382
(language().equalTo("und") && script().equalTo("Armn"))) {
383
setRegion("AM");
384
}
385
else if (language().equalTo("az") ||
386
language().equalTo("tkr") ||
387
language().equalTo("tly") ||
388
language().equalTo("ttt")) {
389
setRegion("AZ");
390
}
391
else if (language().equalTo("be")) {
392
setRegion("BY");
393
}
394
else if (language().equalTo("ab") ||
395
language().equalTo("ka") ||
396
language().equalTo("os") ||
397
(language().equalTo("und") && script().equalTo("Geor")) ||
398
language().equalTo("xmf")) {
399
setRegion("GE");
400
}
401
else if (language().equalTo("ky")) {
402
setRegion("KG");
403
}
404
else if (language().equalTo("kk") ||
405
(language().equalTo("ug") && script().equalTo("Cyrl"))) {
406
setRegion("KZ");
407
}
408
else if (language().equalTo("gag")) {
409
setRegion("MD");
410
}
411
else if (language().equalTo("tg")) {
412
setRegion("TJ");
413
}
414
else if (language().equalTo("tk")) {
415
setRegion("TM");
416
}
417
else if (language().equalTo("crh") ||
418
language().equalTo("got") ||
419
language().equalTo("ji") ||
420
language().equalTo("rue") ||
421
language().equalTo("uk") ||
422
(language().equalTo("und") && script().equalTo("Goth"))) {
423
setRegion("UA");
424
}
425
else if (language().equalTo("kaa") ||
426
language().equalTo("sog") ||
427
(language().equalTo("und") && script().equalTo("Sogd")) ||
428
(language().equalTo("und") && script().equalTo("Sogo")) ||
429
language().equalTo("uz")) {
430
setRegion("UZ");
431
}
432
else {
433
setRegion("RU");
434
}
435
}
436
else if (region().equalTo("200")) {
437
if (language().equalTo("sk")) {
438
setRegion("SK");
439
}
440
else {
441
setRegion("CZ");
442
}
443
}
444
else if (region().equalTo("530") ||
445
region().equalTo("532") ||
446
region().equalTo("AN")) {
447
if (language().equalTo("vic")) {
448
setRegion("SX");
449
}
450
else {
451
setRegion("CW");
452
}
453
}
454
else if (region().equalTo("536") ||
455
region().equalTo("NT")) {
456
if (language().equalTo("akk") ||
457
language().equalTo("ckb") ||
458
(language().equalTo("ku") && script().equalTo("Arab")) ||
459
language().equalTo("mis") ||
460
language().equalTo("syr") ||
461
(language().equalTo("und") && script().equalTo("Xsux")) ||
462
(language().equalTo("und") && script().equalTo("Hatr")) ||
463
(language().equalTo("und") && script().equalTo("Syrc"))) {
464
setRegion("IQ");
465
}
466
else {
467
setRegion("SA");
468
}
469
}
470
else if (region().equalTo("582") ||
471
region().equalTo("PC")) {
472
if (language().equalTo("mh")) {
473
setRegion("MH");
474
}
475
else if (language().equalTo("pau")) {
476
setRegion("PW");
477
}
478
else {
479
setRegion("FM");
480
}
481
}
482
else if (region().equalTo("810") ||
483
region().equalTo("SU")) {
484
if (language().equalTo("hy") ||
485
(language().equalTo("und") && script().equalTo("Armn"))) {
486
setRegion("AM");
487
}
488
else if (language().equalTo("az") ||
489
language().equalTo("tkr") ||
490
language().equalTo("tly") ||
491
language().equalTo("ttt")) {
492
setRegion("AZ");
493
}
494
else if (language().equalTo("be")) {
495
setRegion("BY");
496
}
497
else if (language().equalTo("et") ||
498
language().equalTo("vro")) {
499
setRegion("EE");
500
}
501
else if (language().equalTo("ab") ||
502
language().equalTo("ka") ||
503
language().equalTo("os") ||
504
(language().equalTo("und") && script().equalTo("Geor")) ||
505
language().equalTo("xmf")) {
506
setRegion("GE");
507
}
508
else if (language().equalTo("ky")) {
509
setRegion("KG");
510
}
511
else if (language().equalTo("kk") ||
512
(language().equalTo("ug") && script().equalTo("Cyrl"))) {
513
setRegion("KZ");
514
}
515
else if (language().equalTo("lt") ||
516
language().equalTo("sgs")) {
517
setRegion("LT");
518
}
519
else if (language().equalTo("ltg") ||
520
language().equalTo("lv")) {
521
setRegion("LV");
522
}
523
else if (language().equalTo("gag")) {
524
setRegion("MD");
525
}
526
else if (language().equalTo("tg")) {
527
setRegion("TJ");
528
}
529
else if (language().equalTo("tk")) {
530
setRegion("TM");
531
}
532
else if (language().equalTo("crh") ||
533
language().equalTo("got") ||
534
language().equalTo("ji") ||
535
language().equalTo("rue") ||
536
language().equalTo("uk") ||
537
(language().equalTo("und") && script().equalTo("Goth"))) {
538
setRegion("UA");
539
}
540
else if (language().equalTo("kaa") ||
541
language().equalTo("sog") ||
542
(language().equalTo("und") && script().equalTo("Sogd")) ||
543
(language().equalTo("und") && script().equalTo("Sogo")) ||
544
language().equalTo("uz")) {
545
setRegion("UZ");
546
}
547
else {
548
setRegion("RU");
549
}
550
}
551
else if (region().equalTo("890")) {
552
if (language().equalTo("bs")) {
553
setRegion("BA");
554
}
555
else if (language().equalTo("hr")) {
556
setRegion("HR");
557
}
558
else if (language().equalTo("mk")) {
559
setRegion("MK");
560
}
561
else if (language().equalTo("sl")) {
562
setRegion("SI");
563
}
564
else {
565
setRegion("RS");
566
}
567
}
568
}
569
570
// Canonicalize grandfathered locale identifiers.
571
// Derived from CLDR Supplemental Data, version 36.
573
bool js::intl::LanguageTag::updateGrandfatheredMappings(JSContext* cx) {
574
// We're mapping regular grandfathered tags to non-grandfathered form here.
575
// Other tags remain unchanged.
576
//
577
// regular = "art-lojban"
578
// / "cel-gaulish"
579
// / "no-bok"
580
// / "no-nyn"
581
// / "zh-guoyu"
582
// / "zh-hakka"
583
// / "zh-min"
584
// / "zh-min-nan"
585
// / "zh-xiang"
586
//
587
// Therefore we can quickly exclude most tags by checking every
588
// |unicode_locale_id| subcomponent for characteristics not shared by any of
589
// the regular grandfathered (RG) tags:
590
//
591
// * Real-world |unicode_language_subtag|s are all two or three letters,
592
// so don't waste time running a useless |language.length > 3| fast-path.
593
// * No RG tag has a "script"-looking component.
594
// * No RG tag has a "region"-looking component.
595
// * The RG tags that match |unicode_locale_id| (art-lojban, cel-gaulish,
596
// zh-guoyu, zh-hakka, zh-xiang) have exactly one "variant". (no-bok,
597
// no-nyn, zh-min, and zh-min-nan require BCP47's extlang subtag
598
// that |unicode_locale_id| doesn't support.)
599
// * No RG tag contains |extensions| or |pu_extensions|.
600
if (script().present() ||
601
region().present() ||
602
variants().length() != 1 ||
603
extensions().length() != 0 ||
604
privateuse()) {
605
return true;
606
}
607
608
MOZ_ASSERT(IsCanonicallyCasedLanguageTag(language().span()));
609
MOZ_ASSERT(IsCanonicallyCasedVariantTag(mozilla::MakeStringSpan(variants()[0].get())));
610
611
auto variantEqualTo = [this](const char* variant) {
612
return strcmp(variants()[0].get(), variant) == 0;
613
};
614
615
// art-lojban -> jbo
616
if (language().equalTo("art") && variantEqualTo("lojban")) {
617
setLanguage("jbo");
618
clearVariants();
619
return true;
620
}
621
622
// cel-gaulish -> xtg-x-cel-gaulish
623
else if (language().equalTo("cel") && variantEqualTo("gaulish")) {
624
setLanguage("xtg");
625
clearVariants();
626
627
auto privateuse = DuplicateString(cx, "x-cel-gaulish");
628
if (!privateuse) {
629
return false;
630
}
631
setPrivateuse(std::move(privateuse));
632
return true;
633
}
634
635
// zh-guoyu -> zh
636
else if (language().equalTo("zh") && variantEqualTo("guoyu")) {
637
setLanguage("zh");
638
clearVariants();
639
return true;
640
}
641
642
// zh-hakka -> hak
643
else if (language().equalTo("zh") && variantEqualTo("hakka")) {
644
setLanguage("hak");
645
clearVariants();
646
return true;
647
}
648
649
// zh-xiang -> hsn
650
else if (language().equalTo("zh") && variantEqualTo("xiang")) {
651
setLanguage("hsn");
652
clearVariants();
653
return true;
654
}
655
656
return true;
657
}
658
659
template <size_t Length>
660
static inline bool IsUnicodeKey(mozilla::Span<const char> key,
661
const char (&str)[Length]) {
662
static_assert(Length == UnicodeKeyLength + 1,
663
"Unicode extension key is two characters long");
664
return memcmp(key.data(), str, Length - 1) == 0;
665
}
666
667
template <size_t Length>
668
static inline bool IsUnicodeType(mozilla::Span<const char> type,
669
const char (&str)[Length]) {
670
static_assert(Length > UnicodeKeyLength + 1,
671
"Unicode extension type contains more than two characters");
672
return type.size() == (Length - 1) &&
673
memcmp(type.data(), str, Length - 1) == 0;
674
}
675
676
static int32_t CompareUnicodeType(const char* a, mozilla::Span<const char> b) {
677
#ifdef DEBUG
678
auto isNull = [](char c) {
679
return c == '\0';
680
};
681
#endif
682
683
MOZ_ASSERT(std::none_of(b.begin(), b.end(), isNull),
684
"unexpected null-character in string");
685
686
using UnsignedChar = unsigned char;
687
for (size_t i = 0; i < b.size(); i++) {
688
// |a| is zero-terminated and |b| doesn't contain a null-terminator. So if
689
// we've reached the end of |a|, the below if-statement will always be true.
690
// That ensures we don't read past the end of |a|.
691
if (int32_t r = UnsignedChar(a[i]) - UnsignedChar(b[i])) {
692
return r;
693
}
694
}
695
696
// Return zero if both strings are equal or a negative number if |b| is a
697
// prefix of |a|.
698
return -int32_t(UnsignedChar(a[b.size()]));
699
};
700
701
template <size_t Length>
702
static inline const char* SearchReplacement(const char* (&types)[Length],
703
const char* (&aliases)[Length],
704
mozilla::Span<const char> type) {
705
706
auto p = std::lower_bound(std::begin(types), std::end(types), type,
707
[](const auto& a, const auto& b) {
708
return CompareUnicodeType(a, b) < 0;
709
});
710
if (p != std::end(types) && CompareUnicodeType(*p, type) == 0) {
711
return aliases[std::distance(std::begin(types), p)];
712
}
713
return nullptr;
714
}
715
716
/**
717
* Mapping from deprecated BCP 47 Unicode extension types to their preferred
718
* values.
719
*
721
*/
722
const char* js::intl::LanguageTag::replaceUnicodeExtensionType(
723
mozilla::Span<const char> key, mozilla::Span<const char> type) {
724
#ifdef DEBUG
725
static auto isAsciiLowercaseAlphanumeric = [](char c) {
726
return mozilla::IsAsciiLowercaseAlpha(c) || mozilla::IsAsciiDigit(c);
727
};
728
729
static auto isAsciiLowercaseAlphanumericOrDash = [](char c) {
730
return isAsciiLowercaseAlphanumeric(c) || c == '-';
731
};
732
#endif
733
734
MOZ_ASSERT(key.size() == UnicodeKeyLength);
735
MOZ_ASSERT(std::all_of(key.begin(), key.end(),
736
isAsciiLowercaseAlphanumeric));
737
738
MOZ_ASSERT(type.size() > UnicodeKeyLength);
739
MOZ_ASSERT(std::all_of(type.begin(), type.end(),
740
isAsciiLowercaseAlphanumericOrDash));
741
742
if (IsUnicodeKey(key, "ca")) {
743
if (IsUnicodeType(type, "ethiopic-amete-alem")) {
744
return "ethioaa";
745
}
746
if (IsUnicodeType(type, "islamicc")) {
747
return "islamic-civil";
748
}
749
}
750
else if (IsUnicodeKey(key, "kb") ||
751
IsUnicodeKey(key, "kc") ||
752
IsUnicodeKey(key, "kh") ||
753
IsUnicodeKey(key, "kk") ||
754
IsUnicodeKey(key, "kn")) {
755
if (IsUnicodeType(type, "yes")) {
756
return "true";
757
}
758
}
759
else if (IsUnicodeKey(key, "ks")) {
760
if (IsUnicodeType(type, "primary")) {
761
return "level1";
762
}
763
if (IsUnicodeType(type, "tertiary")) {
764
return "level3";
765
}
766
}
767
else if (IsUnicodeKey(key, "ms")) {
768
if (IsUnicodeType(type, "imperial")) {
769
return "uksystem";
770
}
771
}
772
else if (IsUnicodeKey(key, "rg") ||
773
IsUnicodeKey(key, "sd")) {
774
static const char* types[117] = {
775
"cn11", "cn12", "cn13", "cn14", "cn15", "cn21", "cn22", "cn23",
776
"cn31", "cn32", "cn33", "cn34", "cn35", "cn36", "cn37", "cn41",
777
"cn42", "cn43", "cn44", "cn45", "cn46", "cn50", "cn51", "cn52",
778
"cn53", "cn54", "cn61", "cn62", "cn63", "cn64", "cn65", "cz10a",
779
"cz10b", "cz10c", "cz10d", "cz10e", "cz10f", "cz611", "cz612", "cz613",
780
"cz614", "cz615", "cz621", "cz622", "cz623", "cz624", "cz626", "cz627",
781
"czjc", "czjm", "czka", "czkr", "czli", "czmo", "czol", "czpa",
782
"czpl", "czpr", "czst", "czus", "czvy", "czzl", "fra", "frb",
783
"frc", "frd", "fre", "frf", "frg", "frh", "fri", "frj",
784
"frk", "frl", "frm", "frn", "fro", "frp", "frq", "frr",
785
"frs", "frt", "fru", "frv", "laxn", "lud", "lug", "lul",
786
"mrnkc", "no23", "nzn", "nzs", "omba", "omsh", "plds", "plkp",
787
"pllb", "plld", "pllu", "plma", "plmz", "plop", "plpd", "plpk",
788
"plpm", "plsk", "plsl", "plwn", "plwp", "plzp", "tteto", "ttrcm",
789
"ttwto", "twkhq", "twtnq", "twtpq", "twtxq",
790
};
791
static const char* aliases[117] = {
792
"cnbj", "cntj", "cnhe", "cnsx", "cnmn", "cnln", "cnjl", "cnhl",
793
"cnsh", "cnjs", "cnzj", "cnah", "cnfj", "cnjx", "cnsd", "cnha",
794
"cnhb", "cnhn", "cngd", "cngx", "cnhi", "cncq", "cnsc", "cngz",
795
"cnyn", "cnxz", "cnsn", "cngs", "cnqh", "cnnx", "cnxj", "cz110",
796
"cz111", "cz112", "cz113", "cz114", "cz115", "cz663", "cz632", "cz633",
797
"cz634", "cz635", "cz641", "cz642", "cz643", "cz644", "cz646", "cz647",
798
"cz31", "cz64", "cz41", "cz52", "cz51", "cz80", "cz71", "cz53",
799
"cz32", "cz10", "cz20", "cz42", "cz63", "cz72", "frges", "frnaq",
800
"frara", "frbfc", "frbre", "frcvl", "frges", "frcor", "frbfc", "fridf",
801
"frocc", "frnaq", "frges", "frocc", "frhdf", "frnor", "frnor", "frpdl",
802
"frhdf", "frnaq", "frpac", "frara", "laxs", "lucl", "luec", "luca",
803
"mr13", "no50", "nzauk", "nzcan", "ombj", "omsj", "pl02", "pl04",
804
"pl08", "pl10", "pl06", "pl12", "pl14", "pl16", "pl20", "pl18",
805
"pl22", "pl26", "pl24", "pl28", "pl30", "pl32", "tttob", "ttmrc",
806
"tttob", "twkhh", "twtnn", "twnwt", "twtxg",
807
};
808
return SearchReplacement(types, aliases, type);
809
}
810
else if (IsUnicodeKey(key, "tz")) {
811
static const char* types[28] = {
812
"aqams", "cnckg", "cnhrb", "cnkhg", "cuba", "egypt",
813
"eire", "est", "gmt0", "hongkong", "hst", "iceland",
814
"iran", "israel", "jamaica", "japan", "libya", "mst",
815
"navajo", "poland", "portugal", "prc", "roc", "rok",
816
"turkey", "uct", "usnavajo", "zulu",
817
};
818
static const char* aliases[28] = {
819
"nzakl", "cnsha", "cnsha", "cnurc", "cuhav", "egcai",
820
"iedub", "utcw05", "gmt", "hkhkg", "utcw10", "isrey",
821
"irthr", "jeruslm", "jmkin", "jptyo", "lytip", "utcw07",
822
"usden", "plwaw", "ptlis", "cnsha", "twtpe", "krsel",
823
"trist", "utc", "usden", "utc",
824
};
825
return SearchReplacement(types, aliases, type);
826
}
827
return nullptr;
828
}