shell.js (70090B)
1 // GENERATED, DO NOT EDIT 2 // file: testIntl.js 3 // Copyright (C) 2011 2012 Norbert Lindenberg. All rights reserved. 4 // Copyright (C) 2012 2013 Mozilla Corporation. All rights reserved. 5 // Copyright (C) 2020 Apple Inc. All rights reserved. 6 // This code is governed by the BSD license found in the LICENSE file. 7 /*--- 8 description: | 9 This file contains shared functions for the tests in the conformance test 10 suite for the ECMAScript Internationalization API. 11 author: Norbert Lindenberg 12 defines: 13 - testWithIntlConstructors 14 - taintDataProperty 15 - taintMethod 16 - taintProperties 17 - taintArray 18 - getLocaleSupportInfo 19 - getInvalidLanguageTags 20 - isCanonicalizedStructurallyValidLanguageTag 21 - getInvalidLocaleArguments 22 - testOption 23 - testForUnwantedRegExpChanges 24 - allCalendars 25 - allCollations 26 - allNumberingSystems 27 - isValidNumberingSystem 28 - numberingSystemDigits 29 - allSimpleSanctionedUnits 30 - testNumberFormat 31 - getDateTimeComponents 32 - getDateTimeComponentValues 33 - isCanonicalizedStructurallyValidTimeZoneName 34 - partitionDurationFormatPattern 35 - formatDurationFormatPattern 36 ---*/ 37 /** 38 */ 39 40 41 /** 42 * @description Calls the provided function for every service constructor in 43 * the Intl object. 44 * @param {Function} f the function to call for each service constructor in 45 * the Intl object. 46 * @param {Function} Constructor the constructor object to test with. 47 */ 48 function testWithIntlConstructors(f) { 49 var constructors = ["Collator", "NumberFormat", "DateTimeFormat"]; 50 51 // Optionally supported Intl constructors. 52 // NB: Intl.Locale isn't an Intl service constructor! 53 // Intl.DisplayNames cannot be called without type in options. 54 ["PluralRules", "RelativeTimeFormat", "ListFormat"].forEach(function(constructor) { 55 if (typeof Intl[constructor] === "function") { 56 constructors[constructors.length] = constructor; 57 } 58 }); 59 60 constructors.forEach(function (constructor) { 61 var Constructor = Intl[constructor]; 62 try { 63 f(Constructor); 64 } catch (e) { 65 e.message += " (Testing with " + constructor + ".)"; 66 throw e; 67 } 68 }); 69 } 70 71 72 /** 73 * Taints a named data property of the given object by installing 74 * a setter that throws an exception. 75 * @param {object} obj the object whose data property to taint 76 * @param {string} property the property to taint 77 */ 78 function taintDataProperty(obj, property) { 79 Object.defineProperty(obj, property, { 80 set: function(value) { 81 throw new Test262Error("Client code can adversely affect behavior: setter for " + property + "."); 82 }, 83 enumerable: false, 84 configurable: true 85 }); 86 } 87 88 89 /** 90 * Taints a named method of the given object by replacing it with a function 91 * that throws an exception. 92 * @param {object} obj the object whose method to taint 93 * @param {string} property the name of the method to taint 94 */ 95 function taintMethod(obj, property) { 96 Object.defineProperty(obj, property, { 97 value: function() { 98 throw new Test262Error("Client code can adversely affect behavior: method " + property + "."); 99 }, 100 writable: true, 101 enumerable: false, 102 configurable: true 103 }); 104 } 105 106 107 /** 108 * Taints the given properties (and similarly named properties) by installing 109 * setters on Object.prototype that throw exceptions. 110 * @param {Array} properties an array of property names to taint 111 */ 112 function taintProperties(properties) { 113 properties.forEach(function (property) { 114 var adaptedProperties = [property, "__" + property, "_" + property, property + "_", property + "__"]; 115 adaptedProperties.forEach(function (property) { 116 taintDataProperty(Object.prototype, property); 117 }); 118 }); 119 } 120 121 122 /** 123 * Taints the Array object by creating a setter for the property "0" and 124 * replacing some key methods with functions that throw exceptions. 125 */ 126 function taintArray() { 127 taintDataProperty(Array.prototype, "0"); 128 taintMethod(Array.prototype, "indexOf"); 129 taintMethod(Array.prototype, "join"); 130 taintMethod(Array.prototype, "push"); 131 taintMethod(Array.prototype, "slice"); 132 taintMethod(Array.prototype, "sort"); 133 } 134 135 136 /** 137 * Gets locale support info for the given constructor object, which must be one 138 * of Intl constructors. 139 * @param {object} Constructor the constructor for which to get locale support info 140 * @param {object} options the options while calling the constructor 141 * @return {object} locale support info with the following properties: 142 * supported: array of fully supported language tags 143 * byFallback: array of language tags that are supported through fallbacks 144 * unsupported: array of unsupported language tags 145 */ 146 function getLocaleSupportInfo(Constructor, options) { 147 var languages = ["zh", "es", "en", "hi", "ur", "ar", "ja", "pa"]; 148 var scripts = ["Latn", "Hans", "Deva", "Arab", "Jpan", "Hant", "Guru"]; 149 var countries = ["CN", "IN", "US", "PK", "JP", "TW", "HK", "SG", "419"]; 150 151 var allTags = []; 152 var i, j, k; 153 var language, script, country; 154 for (i = 0; i < languages.length; i++) { 155 language = languages[i]; 156 allTags.push(language); 157 for (j = 0; j < scripts.length; j++) { 158 script = scripts[j]; 159 allTags.push(language + "-" + script); 160 for (k = 0; k < countries.length; k++) { 161 country = countries[k]; 162 allTags.push(language + "-" + script + "-" + country); 163 } 164 } 165 for (k = 0; k < countries.length; k++) { 166 country = countries[k]; 167 allTags.push(language + "-" + country); 168 } 169 } 170 171 var supported = []; 172 var byFallback = []; 173 var unsupported = []; 174 for (i = 0; i < allTags.length; i++) { 175 var request = allTags[i]; 176 var result = new Constructor([request], options).resolvedOptions().locale; 177 if (request === result) { 178 supported.push(request); 179 } else if (request.indexOf(result) === 0) { 180 byFallback.push(request); 181 } else { 182 unsupported.push(request); 183 } 184 } 185 186 return { 187 supported: supported, 188 byFallback: byFallback, 189 unsupported: unsupported 190 }; 191 } 192 193 194 /** 195 * Returns an array of strings for which IsStructurallyValidLanguageTag() returns false 196 */ 197 function getInvalidLanguageTags() { 198 var invalidLanguageTags = [ 199 "", // empty tag 200 "i", // singleton alone 201 "x", // private use without subtag 202 "u", // extension singleton in first place 203 "419", // region code in first place 204 "u-nu-latn-cu-bob", // extension sequence without language 205 "hans-cmn-cn", // "hans" could theoretically be a 4-letter language code, 206 // but those can't be followed by extlang codes. 207 "cmn-hans-cn-u-u", // duplicate singleton 208 "cmn-hans-cn-t-u-ca-u", // duplicate singleton 209 "de-gregory-gregory", // duplicate variant 210 "*", // language range 211 "de-*", // language range 212 "中文", // non-ASCII letters 213 "en-ß", // non-ASCII letters 214 "ıd", // non-ASCII letters 215 "es-Latn-latn", // two scripts 216 "pl-PL-pl", // two regions 217 "u-ca-gregory", // extension in first place 218 "de-1996-1996", // duplicate numeric variant 219 "pt-u-ca-gregory-u-nu-latn", // duplicate singleton subtag 220 221 // Invalid tags starting with: https://github.com/tc39/ecma402/pull/289 222 "no-nyn", // regular grandfathered in BCP47, but invalid in UTS35 223 "i-klingon", // irregular grandfathered in BCP47, but invalid in UTS35 224 "zh-hak-CN", // language with extlang in BCP47, but invalid in UTS35 225 "sgn-ils", // language with extlang in BCP47, but invalid in UTS35 226 "x-foo", // privateuse-only in BCP47, but invalid in UTS35 227 "x-en-US-12345", // more privateuse-only variants. 228 "x-12345-12345-en-US", 229 "x-en-US-12345-12345", 230 "x-en-u-foo", 231 "x-en-u-foo-u-bar", 232 "x-u-foo", 233 234 // underscores in different parts of the language tag 235 "de_DE", 236 "DE_de", 237 "cmn_Hans", 238 "cmn-hans_cn", 239 "es_419", 240 "es-419-u-nu-latn-cu_bob", 241 "i_klingon", 242 "cmn-hans-cn-t-ca-u-ca-x_t-u", 243 "enochian_enochian", 244 "de-gregory_u-ca-gregory", 245 246 "en\u0000", // null-terminator sequence 247 " en", // leading whitespace 248 "en ", // trailing whitespace 249 "it-IT-Latn", // country before script tag 250 "de-u", // incomplete Unicode extension sequences 251 "de-u-", 252 "de-u-ca-", 253 "de-u-ca-gregory-", 254 "si-x", // incomplete private-use tags 255 "x-", 256 "x-y-", 257 ]; 258 259 // make sure the data above is correct 260 for (var i = 0; i < invalidLanguageTags.length; ++i) { 261 var invalidTag = invalidLanguageTags[i]; 262 assert( 263 !isCanonicalizedStructurallyValidLanguageTag(invalidTag), 264 "Test data \"" + invalidTag + "\" is a canonicalized and structurally valid language tag." 265 ); 266 } 267 268 return invalidLanguageTags; 269 } 270 271 272 /** 273 * @description Tests whether locale is a String value representing a 274 * structurally valid and canonicalized BCP 47 language tag, as defined in 275 * sections 6.2.2 and 6.2.3 of the ECMAScript Internationalization API 276 * Specification. 277 * @param {String} locale the string to be tested. 278 * @result {Boolean} whether the test succeeded. 279 */ 280 function isCanonicalizedStructurallyValidLanguageTag(locale) { 281 282 /** 283 * Regular expression defining Unicode BCP 47 Locale Identifiers. 284 * 285 * Spec: https://unicode.org/reports/tr35/#Unicode_locale_identifier 286 */ 287 var alpha = "[a-z]", 288 digit = "[0-9]", 289 alphanum = "[a-z0-9]", 290 variant = "(" + alphanum + "{5,8}|(?:" + digit + alphanum + "{3}))", 291 region = "(" + alpha + "{2}|" + digit + "{3})", 292 script = "(" + alpha + "{4})", 293 language = "(" + alpha + "{2,3}|" + alpha + "{5,8})", 294 privateuse = "(x(-[a-z0-9]{1,8})+)", 295 singleton = "(" + digit + "|[a-wy-z])", 296 attribute= "(" + alphanum + "{3,8})", 297 keyword = "(" + alphanum + alpha + "(-" + alphanum + "{3,8})*)", 298 unicode_locale_extensions = "(u((-" + keyword + ")+|((-" + attribute + ")+(-" + keyword + ")*)))", 299 tlang = "(" + language + "(-" + script + ")?(-" + region + ")?(-" + variant + ")*)", 300 tfield = "(" + alpha + digit + "(-" + alphanum + "{3,8})+)", 301 transformed_extensions = "(t((-" + tlang + "(-" + tfield + ")*)|(-" + tfield + ")+))", 302 other_singleton = "(" + digit + "|[a-sv-wy-z])", 303 other_extensions = "(" + other_singleton + "(-" + alphanum + "{2,8})+)", 304 extension = "(" + unicode_locale_extensions + "|" + transformed_extensions + "|" + other_extensions + ")", 305 locale_id = language + "(-" + script + ")?(-" + region + ")?(-" + variant + ")*(-" + extension + ")*(-" + privateuse + ")?", 306 languageTag = "^(" + locale_id + ")$", 307 languageTagRE = new RegExp(languageTag, "i"); 308 309 var duplicateSingleton = "-" + singleton + "-(.*-)?\\1(?!" + alphanum + ")", 310 duplicateSingletonRE = new RegExp(duplicateSingleton, "i"), 311 duplicateVariant = "(" + alphanum + "{2,8}-)+" + variant + "-(" + alphanum + "{2,8}-)*\\2(?!" + alphanum + ")", 312 duplicateVariantRE = new RegExp(duplicateVariant, "i"); 313 314 var transformKeyRE = new RegExp("^" + alpha + digit + "$", "i"); 315 316 /** 317 * Verifies that the given string is a well-formed Unicode BCP 47 Locale Identifier 318 * with no duplicate variant or singleton subtags. 319 * 320 * Spec: ECMAScript Internationalization API Specification, draft, 6.2.2. 321 */ 322 function isStructurallyValidLanguageTag(locale) { 323 if (!languageTagRE.test(locale)) { 324 return false; 325 } 326 locale = locale.split(/-x-/)[0]; 327 return !duplicateSingletonRE.test(locale) && !duplicateVariantRE.test(locale); 328 } 329 330 331 /** 332 * Mappings from complete tags to preferred values. 333 * 334 * Spec: http://unicode.org/reports/tr35/#Identifiers 335 * Version: CLDR, version 36.1 336 */ 337 var __tagMappings = { 338 // property names must be in lower case; values in canonical form 339 340 "art-lojban": "jbo", 341 "cel-gaulish": "xtg", 342 "zh-guoyu": "zh", 343 "zh-hakka": "hak", 344 "zh-xiang": "hsn", 345 }; 346 347 348 /** 349 * Mappings from language subtags to preferred values. 350 * 351 * Spec: http://unicode.org/reports/tr35/#Identifiers 352 * Version: CLDR, version 36.1 353 */ 354 var __languageMappings = { 355 // property names and values must be in canonical case 356 357 "aam": "aas", 358 "aar": "aa", 359 "abk": "ab", 360 "adp": "dz", 361 "afr": "af", 362 "aju": "jrb", 363 "aka": "ak", 364 "alb": "sq", 365 "als": "sq", 366 "amh": "am", 367 "ara": "ar", 368 "arb": "ar", 369 "arg": "an", 370 "arm": "hy", 371 "asd": "snz", 372 "asm": "as", 373 "aue": "ktz", 374 "ava": "av", 375 "ave": "ae", 376 "aym": "ay", 377 "ayr": "ay", 378 "ayx": "nun", 379 "aze": "az", 380 "azj": "az", 381 "bak": "ba", 382 "bam": "bm", 383 "baq": "eu", 384 "bcc": "bal", 385 "bcl": "bik", 386 "bel": "be", 387 "ben": "bn", 388 "bgm": "bcg", 389 "bh": "bho", 390 "bih": "bho", 391 "bis": "bi", 392 "bjd": "drl", 393 "bod": "bo", 394 "bos": "bs", 395 "bre": "br", 396 "bul": "bg", 397 "bur": "my", 398 "bxk": "luy", 399 "bxr": "bua", 400 "cat": "ca", 401 "ccq": "rki", 402 "ces": "cs", 403 "cha": "ch", 404 "che": "ce", 405 "chi": "zh", 406 "chu": "cu", 407 "chv": "cv", 408 "cjr": "mom", 409 "cka": "cmr", 410 "cld": "syr", 411 "cmk": "xch", 412 "cmn": "zh", 413 "cor": "kw", 414 "cos": "co", 415 "coy": "pij", 416 "cqu": "quh", 417 "cre": "cr", 418 "cwd": "cr", 419 "cym": "cy", 420 "cze": "cs", 421 "dan": "da", 422 "deu": "de", 423 "dgo": "doi", 424 "dhd": "mwr", 425 "dik": "din", 426 "diq": "zza", 427 "dit": "dif", 428 "div": "dv", 429 "drh": "mn", 430 "dut": "nl", 431 "dzo": "dz", 432 "ekk": "et", 433 "ell": "el", 434 "emk": "man", 435 "eng": "en", 436 "epo": "eo", 437 "esk": "ik", 438 "est": "et", 439 "eus": "eu", 440 "ewe": "ee", 441 "fao": "fo", 442 "fas": "fa", 443 "fat": "ak", 444 "fij": "fj", 445 "fin": "fi", 446 "fra": "fr", 447 "fre": "fr", 448 "fry": "fy", 449 "fuc": "ff", 450 "ful": "ff", 451 "gav": "dev", 452 "gaz": "om", 453 "gbo": "grb", 454 "geo": "ka", 455 "ger": "de", 456 "gfx": "vaj", 457 "ggn": "gvr", 458 "gla": "gd", 459 "gle": "ga", 460 "glg": "gl", 461 "glv": "gv", 462 "gno": "gon", 463 "gre": "el", 464 "grn": "gn", 465 "gti": "nyc", 466 "gug": "gn", 467 "guj": "gu", 468 "guv": "duz", 469 "gya": "gba", 470 "hat": "ht", 471 "hau": "ha", 472 "hdn": "hai", 473 "hea": "hmn", 474 "heb": "he", 475 "her": "hz", 476 "him": "srx", 477 "hin": "hi", 478 "hmo": "ho", 479 "hrr": "jal", 480 "hrv": "hr", 481 "hun": "hu", 482 "hye": "hy", 483 "ibi": "opa", 484 "ibo": "ig", 485 "ice": "is", 486 "ido": "io", 487 "iii": "ii", 488 "ike": "iu", 489 "iku": "iu", 490 "ile": "ie", 491 "ilw": "gal", 492 "in": "id", 493 "ina": "ia", 494 "ind": "id", 495 "ipk": "ik", 496 "isl": "is", 497 "ita": "it", 498 "iw": "he", 499 "jav": "jv", 500 "jeg": "oyb", 501 "ji": "yi", 502 "jpn": "ja", 503 "jw": "jv", 504 "kal": "kl", 505 "kan": "kn", 506 "kas": "ks", 507 "kat": "ka", 508 "kau": "kr", 509 "kaz": "kk", 510 "kgc": "tdf", 511 "kgh": "kml", 512 "khk": "mn", 513 "khm": "km", 514 "kik": "ki", 515 "kin": "rw", 516 "kir": "ky", 517 "kmr": "ku", 518 "knc": "kr", 519 "kng": "kg", 520 "knn": "kok", 521 "koj": "kwv", 522 "kom": "kv", 523 "kon": "kg", 524 "kor": "ko", 525 "kpv": "kv", 526 "krm": "bmf", 527 "ktr": "dtp", 528 "kua": "kj", 529 "kur": "ku", 530 "kvs": "gdj", 531 "kwq": "yam", 532 "kxe": "tvd", 533 "kzj": "dtp", 534 "kzt": "dtp", 535 "lao": "lo", 536 "lat": "la", 537 "lav": "lv", 538 "lbk": "bnc", 539 "lii": "raq", 540 "lim": "li", 541 "lin": "ln", 542 "lit": "lt", 543 "llo": "ngt", 544 "lmm": "rmx", 545 "ltz": "lb", 546 "lub": "lu", 547 "lug": "lg", 548 "lvs": "lv", 549 "mac": "mk", 550 "mah": "mh", 551 "mal": "ml", 552 "mao": "mi", 553 "mar": "mr", 554 "may": "ms", 555 "meg": "cir", 556 "mhr": "chm", 557 "mkd": "mk", 558 "mlg": "mg", 559 "mlt": "mt", 560 "mnk": "man", 561 "mo": "ro", 562 "mol": "ro", 563 "mon": "mn", 564 "mri": "mi", 565 "msa": "ms", 566 "mst": "mry", 567 "mup": "raj", 568 "mwj": "vaj", 569 "mya": "my", 570 "myd": "aog", 571 "myt": "mry", 572 "nad": "xny", 573 "nau": "na", 574 "nav": "nv", 575 "nbl": "nr", 576 "ncp": "kdz", 577 "nde": "nd", 578 "ndo": "ng", 579 "nep": "ne", 580 "nld": "nl", 581 "nno": "nn", 582 "nns": "nbr", 583 "nnx": "ngv", 584 "no": "nb", 585 "nob": "nb", 586 "nor": "nb", 587 "npi": "ne", 588 "nts": "pij", 589 "nya": "ny", 590 "oci": "oc", 591 "ojg": "oj", 592 "oji": "oj", 593 "ori": "or", 594 "orm": "om", 595 "ory": "or", 596 "oss": "os", 597 "oun": "vaj", 598 "pan": "pa", 599 "pbu": "ps", 600 "pcr": "adx", 601 "per": "fa", 602 "pes": "fa", 603 "pli": "pi", 604 "plt": "mg", 605 "pmc": "huw", 606 "pmu": "phr", 607 "pnb": "lah", 608 "pol": "pl", 609 "por": "pt", 610 "ppa": "bfy", 611 "ppr": "lcq", 612 "pry": "prt", 613 "pus": "ps", 614 "puz": "pub", 615 "que": "qu", 616 "quz": "qu", 617 "rmy": "rom", 618 "roh": "rm", 619 "ron": "ro", 620 "rum": "ro", 621 "run": "rn", 622 "rus": "ru", 623 "sag": "sg", 624 "san": "sa", 625 "sca": "hle", 626 "scc": "sr", 627 "scr": "hr", 628 "sin": "si", 629 "skk": "oyb", 630 "slk": "sk", 631 "slo": "sk", 632 "slv": "sl", 633 "sme": "se", 634 "smo": "sm", 635 "sna": "sn", 636 "snd": "sd", 637 "som": "so", 638 "sot": "st", 639 "spa": "es", 640 "spy": "kln", 641 "sqi": "sq", 642 "src": "sc", 643 "srd": "sc", 644 "srp": "sr", 645 "ssw": "ss", 646 "sun": "su", 647 "swa": "sw", 648 "swe": "sv", 649 "swh": "sw", 650 "tah": "ty", 651 "tam": "ta", 652 "tat": "tt", 653 "tdu": "dtp", 654 "tel": "te", 655 "tgk": "tg", 656 "tgl": "fil", 657 "tha": "th", 658 "thc": "tpo", 659 "thx": "oyb", 660 "tib": "bo", 661 "tie": "ras", 662 "tir": "ti", 663 "tkk": "twm", 664 "tl": "fil", 665 "tlw": "weo", 666 "tmp": "tyj", 667 "tne": "kak", 668 "ton": "to", 669 "tsf": "taj", 670 "tsn": "tn", 671 "tso": "ts", 672 "ttq": "tmh", 673 "tuk": "tk", 674 "tur": "tr", 675 "tw": "ak", 676 "twi": "ak", 677 "uig": "ug", 678 "ukr": "uk", 679 "umu": "del", 680 "uok": "ema", 681 "urd": "ur", 682 "uzb": "uz", 683 "uzn": "uz", 684 "ven": "ve", 685 "vie": "vi", 686 "vol": "vo", 687 "wel": "cy", 688 "wln": "wa", 689 "wol": "wo", 690 "xba": "cax", 691 "xho": "xh", 692 "xia": "acn", 693 "xkh": "waw", 694 "xpe": "kpe", 695 "xsj": "suj", 696 "xsl": "den", 697 "ybd": "rki", 698 "ydd": "yi", 699 "yid": "yi", 700 "yma": "lrr", 701 "ymt": "mtm", 702 "yor": "yo", 703 "yos": "zom", 704 "yuu": "yug", 705 "zai": "zap", 706 "zha": "za", 707 "zho": "zh", 708 "zsm": "ms", 709 "zul": "zu", 710 "zyb": "za", 711 }; 712 713 714 /** 715 * Mappings from region subtags to preferred values. 716 * 717 * Spec: http://unicode.org/reports/tr35/#Identifiers 718 * Version: CLDR, version 36.1 719 */ 720 var __regionMappings = { 721 // property names and values must be in canonical case 722 723 "004": "AF", 724 "008": "AL", 725 "010": "AQ", 726 "012": "DZ", 727 "016": "AS", 728 "020": "AD", 729 "024": "AO", 730 "028": "AG", 731 "031": "AZ", 732 "032": "AR", 733 "036": "AU", 734 "040": "AT", 735 "044": "BS", 736 "048": "BH", 737 "050": "BD", 738 "051": "AM", 739 "052": "BB", 740 "056": "BE", 741 "060": "BM", 742 "062": "034", 743 "064": "BT", 744 "068": "BO", 745 "070": "BA", 746 "072": "BW", 747 "074": "BV", 748 "076": "BR", 749 "084": "BZ", 750 "086": "IO", 751 "090": "SB", 752 "092": "VG", 753 "096": "BN", 754 "100": "BG", 755 "104": "MM", 756 "108": "BI", 757 "112": "BY", 758 "116": "KH", 759 "120": "CM", 760 "124": "CA", 761 "132": "CV", 762 "136": "KY", 763 "140": "CF", 764 "144": "LK", 765 "148": "TD", 766 "152": "CL", 767 "156": "CN", 768 "158": "TW", 769 "162": "CX", 770 "166": "CC", 771 "170": "CO", 772 "174": "KM", 773 "175": "YT", 774 "178": "CG", 775 "180": "CD", 776 "184": "CK", 777 "188": "CR", 778 "191": "HR", 779 "192": "CU", 780 "196": "CY", 781 "203": "CZ", 782 "204": "BJ", 783 "208": "DK", 784 "212": "DM", 785 "214": "DO", 786 "218": "EC", 787 "222": "SV", 788 "226": "GQ", 789 "230": "ET", 790 "231": "ET", 791 "232": "ER", 792 "233": "EE", 793 "234": "FO", 794 "238": "FK", 795 "239": "GS", 796 "242": "FJ", 797 "246": "FI", 798 "248": "AX", 799 "249": "FR", 800 "250": "FR", 801 "254": "GF", 802 "258": "PF", 803 "260": "TF", 804 "262": "DJ", 805 "266": "GA", 806 "268": "GE", 807 "270": "GM", 808 "275": "PS", 809 "276": "DE", 810 "278": "DE", 811 "280": "DE", 812 "288": "GH", 813 "292": "GI", 814 "296": "KI", 815 "300": "GR", 816 "304": "GL", 817 "308": "GD", 818 "312": "GP", 819 "316": "GU", 820 "320": "GT", 821 "324": "GN", 822 "328": "GY", 823 "332": "HT", 824 "334": "HM", 825 "336": "VA", 826 "340": "HN", 827 "344": "HK", 828 "348": "HU", 829 "352": "IS", 830 "356": "IN", 831 "360": "ID", 832 "364": "IR", 833 "368": "IQ", 834 "372": "IE", 835 "376": "IL", 836 "380": "IT", 837 "384": "CI", 838 "388": "JM", 839 "392": "JP", 840 "398": "KZ", 841 "400": "JO", 842 "404": "KE", 843 "408": "KP", 844 "410": "KR", 845 "414": "KW", 846 "417": "KG", 847 "418": "LA", 848 "422": "LB", 849 "426": "LS", 850 "428": "LV", 851 "430": "LR", 852 "434": "LY", 853 "438": "LI", 854 "440": "LT", 855 "442": "LU", 856 "446": "MO", 857 "450": "MG", 858 "454": "MW", 859 "458": "MY", 860 "462": "MV", 861 "466": "ML", 862 "470": "MT", 863 "474": "MQ", 864 "478": "MR", 865 "480": "MU", 866 "484": "MX", 867 "492": "MC", 868 "496": "MN", 869 "498": "MD", 870 "499": "ME", 871 "500": "MS", 872 "504": "MA", 873 "508": "MZ", 874 "512": "OM", 875 "516": "NA", 876 "520": "NR", 877 "524": "NP", 878 "528": "NL", 879 "531": "CW", 880 "533": "AW", 881 "534": "SX", 882 "535": "BQ", 883 "540": "NC", 884 "548": "VU", 885 "554": "NZ", 886 "558": "NI", 887 "562": "NE", 888 "566": "NG", 889 "570": "NU", 890 "574": "NF", 891 "578": "NO", 892 "580": "MP", 893 "581": "UM", 894 "583": "FM", 895 "584": "MH", 896 "585": "PW", 897 "586": "PK", 898 "591": "PA", 899 "598": "PG", 900 "600": "PY", 901 "604": "PE", 902 "608": "PH", 903 "612": "PN", 904 "616": "PL", 905 "620": "PT", 906 "624": "GW", 907 "626": "TL", 908 "630": "PR", 909 "634": "QA", 910 "638": "RE", 911 "642": "RO", 912 "643": "RU", 913 "646": "RW", 914 "652": "BL", 915 "654": "SH", 916 "659": "KN", 917 "660": "AI", 918 "662": "LC", 919 "663": "MF", 920 "666": "PM", 921 "670": "VC", 922 "674": "SM", 923 "678": "ST", 924 "682": "SA", 925 "686": "SN", 926 "688": "RS", 927 "690": "SC", 928 "694": "SL", 929 "702": "SG", 930 "703": "SK", 931 "704": "VN", 932 "705": "SI", 933 "706": "SO", 934 "710": "ZA", 935 "716": "ZW", 936 "720": "YE", 937 "724": "ES", 938 "728": "SS", 939 "729": "SD", 940 "732": "EH", 941 "736": "SD", 942 "740": "SR", 943 "744": "SJ", 944 "748": "SZ", 945 "752": "SE", 946 "756": "CH", 947 "760": "SY", 948 "762": "TJ", 949 "764": "TH", 950 "768": "TG", 951 "772": "TK", 952 "776": "TO", 953 "780": "TT", 954 "784": "AE", 955 "788": "TN", 956 "792": "TR", 957 "795": "TM", 958 "796": "TC", 959 "798": "TV", 960 "800": "UG", 961 "804": "UA", 962 "807": "MK", 963 "818": "EG", 964 "826": "GB", 965 "830": "JE", 966 "831": "GG", 967 "832": "JE", 968 "833": "IM", 969 "834": "TZ", 970 "840": "US", 971 "850": "VI", 972 "854": "BF", 973 "858": "UY", 974 "860": "UZ", 975 "862": "VE", 976 "876": "WF", 977 "882": "WS", 978 "886": "YE", 979 "887": "YE", 980 "891": "RS", 981 "894": "ZM", 982 "958": "AA", 983 "959": "QM", 984 "960": "QN", 985 "962": "QP", 986 "963": "QQ", 987 "964": "QR", 988 "965": "QS", 989 "966": "QT", 990 "967": "EU", 991 "968": "QV", 992 "969": "QW", 993 "970": "QX", 994 "971": "QY", 995 "972": "QZ", 996 "973": "XA", 997 "974": "XB", 998 "975": "XC", 999 "976": "XD", 1000 "977": "XE", 1001 "978": "XF", 1002 "979": "XG", 1003 "980": "XH", 1004 "981": "XI", 1005 "982": "XJ", 1006 "983": "XK", 1007 "984": "XL", 1008 "985": "XM", 1009 "986": "XN", 1010 "987": "XO", 1011 "988": "XP", 1012 "989": "XQ", 1013 "990": "XR", 1014 "991": "XS", 1015 "992": "XT", 1016 "993": "XU", 1017 "994": "XV", 1018 "995": "XW", 1019 "996": "XX", 1020 "997": "XY", 1021 "998": "XZ", 1022 "999": "ZZ", 1023 "BU": "MM", 1024 "CS": "RS", 1025 "CT": "KI", 1026 "DD": "DE", 1027 "DY": "BJ", 1028 "FQ": "AQ", 1029 "FX": "FR", 1030 "HV": "BF", 1031 "JT": "UM", 1032 "MI": "UM", 1033 "NH": "VU", 1034 "NQ": "AQ", 1035 "PU": "UM", 1036 "PZ": "PA", 1037 "QU": "EU", 1038 "RH": "ZW", 1039 "TP": "TL", 1040 "UK": "GB", 1041 "VD": "VN", 1042 "WK": "UM", 1043 "YD": "YE", 1044 "YU": "RS", 1045 "ZR": "CD", 1046 }; 1047 1048 1049 /** 1050 * Complex mappings from language subtags to preferred values. 1051 * 1052 * Spec: http://unicode.org/reports/tr35/#Identifiers 1053 * Version: CLDR, version 36.1 1054 */ 1055 var __complexLanguageMappings = { 1056 // property names and values must be in canonical case 1057 1058 "cnr": {language: "sr", region: "ME"}, 1059 "drw": {language: "fa", region: "AF"}, 1060 "hbs": {language: "sr", script: "Latn"}, 1061 "prs": {language: "fa", region: "AF"}, 1062 "sh": {language: "sr", script: "Latn"}, 1063 "swc": {language: "sw", region: "CD"}, 1064 "tnf": {language: "fa", region: "AF"}, 1065 }; 1066 1067 1068 /** 1069 * Complex mappings from region subtags to preferred values. 1070 * 1071 * Spec: http://unicode.org/reports/tr35/#Identifiers 1072 * Version: CLDR, version 36.1 1073 */ 1074 var __complexRegionMappings = { 1075 // property names and values must be in canonical case 1076 1077 "172": { 1078 default: "RU", 1079 "ab": "GE", 1080 "az": "AZ", 1081 "be": "BY", 1082 "crh": "UA", 1083 "gag": "MD", 1084 "got": "UA", 1085 "hy": "AM", 1086 "ji": "UA", 1087 "ka": "GE", 1088 "kaa": "UZ", 1089 "kk": "KZ", 1090 "ku-Yezi": "GE", 1091 "ky": "KG", 1092 "os": "GE", 1093 "rue": "UA", 1094 "sog": "UZ", 1095 "tg": "TJ", 1096 "tk": "TM", 1097 "tkr": "AZ", 1098 "tly": "AZ", 1099 "ttt": "AZ", 1100 "ug-Cyrl": "KZ", 1101 "uk": "UA", 1102 "und-Armn": "AM", 1103 "und-Chrs": "UZ", 1104 "und-Geor": "GE", 1105 "und-Goth": "UA", 1106 "und-Sogd": "UZ", 1107 "und-Sogo": "UZ", 1108 "und-Yezi": "GE", 1109 "uz": "UZ", 1110 "xco": "UZ", 1111 "xmf": "GE", 1112 }, 1113 "200": { 1114 default: "CZ", 1115 "sk": "SK", 1116 }, 1117 "530": { 1118 default: "CW", 1119 "vic": "SX", 1120 }, 1121 "532": { 1122 default: "CW", 1123 "vic": "SX", 1124 }, 1125 "536": { 1126 default: "SA", 1127 "akk": "IQ", 1128 "ckb": "IQ", 1129 "ku-Arab": "IQ", 1130 "mis": "IQ", 1131 "syr": "IQ", 1132 "und-Hatr": "IQ", 1133 "und-Syrc": "IQ", 1134 "und-Xsux": "IQ", 1135 }, 1136 "582": { 1137 default: "FM", 1138 "mh": "MH", 1139 "pau": "PW", 1140 }, 1141 "810": { 1142 default: "RU", 1143 "ab": "GE", 1144 "az": "AZ", 1145 "be": "BY", 1146 "crh": "UA", 1147 "et": "EE", 1148 "gag": "MD", 1149 "got": "UA", 1150 "hy": "AM", 1151 "ji": "UA", 1152 "ka": "GE", 1153 "kaa": "UZ", 1154 "kk": "KZ", 1155 "ku-Yezi": "GE", 1156 "ky": "KG", 1157 "lt": "LT", 1158 "ltg": "LV", 1159 "lv": "LV", 1160 "os": "GE", 1161 "rue": "UA", 1162 "sgs": "LT", 1163 "sog": "UZ", 1164 "tg": "TJ", 1165 "tk": "TM", 1166 "tkr": "AZ", 1167 "tly": "AZ", 1168 "ttt": "AZ", 1169 "ug-Cyrl": "KZ", 1170 "uk": "UA", 1171 "und-Armn": "AM", 1172 "und-Chrs": "UZ", 1173 "und-Geor": "GE", 1174 "und-Goth": "UA", 1175 "und-Sogd": "UZ", 1176 "und-Sogo": "UZ", 1177 "und-Yezi": "GE", 1178 "uz": "UZ", 1179 "vro": "EE", 1180 "xco": "UZ", 1181 "xmf": "GE", 1182 }, 1183 "890": { 1184 default: "RS", 1185 "bs": "BA", 1186 "hr": "HR", 1187 "mk": "MK", 1188 "sl": "SI", 1189 }, 1190 "AN": { 1191 default: "CW", 1192 "vic": "SX", 1193 }, 1194 "NT": { 1195 default: "SA", 1196 "akk": "IQ", 1197 "ckb": "IQ", 1198 "ku-Arab": "IQ", 1199 "mis": "IQ", 1200 "syr": "IQ", 1201 "und-Hatr": "IQ", 1202 "und-Syrc": "IQ", 1203 "und-Xsux": "IQ", 1204 }, 1205 "PC": { 1206 default: "FM", 1207 "mh": "MH", 1208 "pau": "PW", 1209 }, 1210 "SU": { 1211 default: "RU", 1212 "ab": "GE", 1213 "az": "AZ", 1214 "be": "BY", 1215 "crh": "UA", 1216 "et": "EE", 1217 "gag": "MD", 1218 "got": "UA", 1219 "hy": "AM", 1220 "ji": "UA", 1221 "ka": "GE", 1222 "kaa": "UZ", 1223 "kk": "KZ", 1224 "ku-Yezi": "GE", 1225 "ky": "KG", 1226 "lt": "LT", 1227 "ltg": "LV", 1228 "lv": "LV", 1229 "os": "GE", 1230 "rue": "UA", 1231 "sgs": "LT", 1232 "sog": "UZ", 1233 "tg": "TJ", 1234 "tk": "TM", 1235 "tkr": "AZ", 1236 "tly": "AZ", 1237 "ttt": "AZ", 1238 "ug-Cyrl": "KZ", 1239 "uk": "UA", 1240 "und-Armn": "AM", 1241 "und-Chrs": "UZ", 1242 "und-Geor": "GE", 1243 "und-Goth": "UA", 1244 "und-Sogd": "UZ", 1245 "und-Sogo": "UZ", 1246 "und-Yezi": "GE", 1247 "uz": "UZ", 1248 "vro": "EE", 1249 "xco": "UZ", 1250 "xmf": "GE", 1251 }, 1252 }; 1253 1254 1255 /** 1256 * Mappings from variant subtags to preferred values. 1257 * 1258 * Spec: http://unicode.org/reports/tr35/#Identifiers 1259 * Version: CLDR, version 36.1 1260 */ 1261 var __variantMappings = { 1262 // property names and values must be in canonical case 1263 1264 "aaland": {type: "region", replacement: "AX"}, 1265 "arevela": {type: "language", replacement: "hy"}, 1266 "arevmda": {type: "language", replacement: "hyw"}, 1267 "heploc": {type: "variant", replacement: "alalc97"}, 1268 "polytoni": {type: "variant", replacement: "polyton"}, 1269 }; 1270 1271 1272 /** 1273 * Mappings from Unicode extension subtags to preferred values. 1274 * 1275 * Spec: http://unicode.org/reports/tr35/#Identifiers 1276 * Version: CLDR, version 36.1 1277 */ 1278 var __unicodeMappings = { 1279 // property names and values must be in canonical case 1280 1281 "ca": { 1282 "ethiopic-amete-alem": "ethioaa", 1283 "islamicc": "islamic-civil", 1284 }, 1285 "kb": { 1286 "yes": "true", 1287 }, 1288 "kc": { 1289 "yes": "true", 1290 }, 1291 "kh": { 1292 "yes": "true", 1293 }, 1294 "kk": { 1295 "yes": "true", 1296 }, 1297 "kn": { 1298 "yes": "true", 1299 }, 1300 "ks": { 1301 "primary": "level1", 1302 "tertiary": "level3", 1303 }, 1304 "ms": { 1305 "imperial": "uksystem", 1306 }, 1307 "rg": { 1308 "cn11": "cnbj", 1309 "cn12": "cntj", 1310 "cn13": "cnhe", 1311 "cn14": "cnsx", 1312 "cn15": "cnmn", 1313 "cn21": "cnln", 1314 "cn22": "cnjl", 1315 "cn23": "cnhl", 1316 "cn31": "cnsh", 1317 "cn32": "cnjs", 1318 "cn33": "cnzj", 1319 "cn34": "cnah", 1320 "cn35": "cnfj", 1321 "cn36": "cnjx", 1322 "cn37": "cnsd", 1323 "cn41": "cnha", 1324 "cn42": "cnhb", 1325 "cn43": "cnhn", 1326 "cn44": "cngd", 1327 "cn45": "cngx", 1328 "cn46": "cnhi", 1329 "cn50": "cncq", 1330 "cn51": "cnsc", 1331 "cn52": "cngz", 1332 "cn53": "cnyn", 1333 "cn54": "cnxz", 1334 "cn61": "cnsn", 1335 "cn62": "cngs", 1336 "cn63": "cnqh", 1337 "cn64": "cnnx", 1338 "cn65": "cnxj", 1339 "cz10a": "cz110", 1340 "cz10b": "cz111", 1341 "cz10c": "cz112", 1342 "cz10d": "cz113", 1343 "cz10e": "cz114", 1344 "cz10f": "cz115", 1345 "cz611": "cz663", 1346 "cz612": "cz632", 1347 "cz613": "cz633", 1348 "cz614": "cz634", 1349 "cz615": "cz635", 1350 "cz621": "cz641", 1351 "cz622": "cz642", 1352 "cz623": "cz643", 1353 "cz624": "cz644", 1354 "cz626": "cz646", 1355 "cz627": "cz647", 1356 "czjc": "cz31", 1357 "czjm": "cz64", 1358 "czka": "cz41", 1359 "czkr": "cz52", 1360 "czli": "cz51", 1361 "czmo": "cz80", 1362 "czol": "cz71", 1363 "czpa": "cz53", 1364 "czpl": "cz32", 1365 "czpr": "cz10", 1366 "czst": "cz20", 1367 "czus": "cz42", 1368 "czvy": "cz63", 1369 "czzl": "cz72", 1370 "fra": "frges", 1371 "frb": "frnaq", 1372 "frc": "frara", 1373 "frd": "frbfc", 1374 "fre": "frbre", 1375 "frf": "frcvl", 1376 "frg": "frges", 1377 "frh": "frcor", 1378 "fri": "frbfc", 1379 "frj": "fridf", 1380 "frk": "frocc", 1381 "frl": "frnaq", 1382 "frm": "frges", 1383 "frn": "frocc", 1384 "fro": "frhdf", 1385 "frp": "frnor", 1386 "frq": "frnor", 1387 "frr": "frpdl", 1388 "frs": "frhdf", 1389 "frt": "frnaq", 1390 "fru": "frpac", 1391 "frv": "frara", 1392 "laxn": "laxs", 1393 "lud": "lucl", 1394 "lug": "luec", 1395 "lul": "luca", 1396 "mrnkc": "mr13", 1397 "no23": "no50", 1398 "nzn": "nzauk", 1399 "nzs": "nzcan", 1400 "omba": "ombj", 1401 "omsh": "omsj", 1402 "plds": "pl02", 1403 "plkp": "pl04", 1404 "pllb": "pl08", 1405 "plld": "pl10", 1406 "pllu": "pl06", 1407 "plma": "pl12", 1408 "plmz": "pl14", 1409 "plop": "pl16", 1410 "plpd": "pl20", 1411 "plpk": "pl18", 1412 "plpm": "pl22", 1413 "plsk": "pl26", 1414 "plsl": "pl24", 1415 "plwn": "pl28", 1416 "plwp": "pl30", 1417 "plzp": "pl32", 1418 "tteto": "tttob", 1419 "ttrcm": "ttmrc", 1420 "ttwto": "tttob", 1421 "twkhq": "twkhh", 1422 "twtnq": "twtnn", 1423 "twtpq": "twnwt", 1424 "twtxq": "twtxg", 1425 }, 1426 "sd": { 1427 "cn11": "cnbj", 1428 "cn12": "cntj", 1429 "cn13": "cnhe", 1430 "cn14": "cnsx", 1431 "cn15": "cnmn", 1432 "cn21": "cnln", 1433 "cn22": "cnjl", 1434 "cn23": "cnhl", 1435 "cn31": "cnsh", 1436 "cn32": "cnjs", 1437 "cn33": "cnzj", 1438 "cn34": "cnah", 1439 "cn35": "cnfj", 1440 "cn36": "cnjx", 1441 "cn37": "cnsd", 1442 "cn41": "cnha", 1443 "cn42": "cnhb", 1444 "cn43": "cnhn", 1445 "cn44": "cngd", 1446 "cn45": "cngx", 1447 "cn46": "cnhi", 1448 "cn50": "cncq", 1449 "cn51": "cnsc", 1450 "cn52": "cngz", 1451 "cn53": "cnyn", 1452 "cn54": "cnxz", 1453 "cn61": "cnsn", 1454 "cn62": "cngs", 1455 "cn63": "cnqh", 1456 "cn64": "cnnx", 1457 "cn65": "cnxj", 1458 "cz10a": "cz110", 1459 "cz10b": "cz111", 1460 "cz10c": "cz112", 1461 "cz10d": "cz113", 1462 "cz10e": "cz114", 1463 "cz10f": "cz115", 1464 "cz611": "cz663", 1465 "cz612": "cz632", 1466 "cz613": "cz633", 1467 "cz614": "cz634", 1468 "cz615": "cz635", 1469 "cz621": "cz641", 1470 "cz622": "cz642", 1471 "cz623": "cz643", 1472 "cz624": "cz644", 1473 "cz626": "cz646", 1474 "cz627": "cz647", 1475 "czjc": "cz31", 1476 "czjm": "cz64", 1477 "czka": "cz41", 1478 "czkr": "cz52", 1479 "czli": "cz51", 1480 "czmo": "cz80", 1481 "czol": "cz71", 1482 "czpa": "cz53", 1483 "czpl": "cz32", 1484 "czpr": "cz10", 1485 "czst": "cz20", 1486 "czus": "cz42", 1487 "czvy": "cz63", 1488 "czzl": "cz72", 1489 "fra": "frges", 1490 "frb": "frnaq", 1491 "frc": "frara", 1492 "frd": "frbfc", 1493 "fre": "frbre", 1494 "frf": "frcvl", 1495 "frg": "frges", 1496 "frh": "frcor", 1497 "fri": "frbfc", 1498 "frj": "fridf", 1499 "frk": "frocc", 1500 "frl": "frnaq", 1501 "frm": "frges", 1502 "frn": "frocc", 1503 "fro": "frhdf", 1504 "frp": "frnor", 1505 "frq": "frnor", 1506 "frr": "frpdl", 1507 "frs": "frhdf", 1508 "frt": "frnaq", 1509 "fru": "frpac", 1510 "frv": "frara", 1511 "laxn": "laxs", 1512 "lud": "lucl", 1513 "lug": "luec", 1514 "lul": "luca", 1515 "mrnkc": "mr13", 1516 "no23": "no50", 1517 "nzn": "nzauk", 1518 "nzs": "nzcan", 1519 "omba": "ombj", 1520 "omsh": "omsj", 1521 "plds": "pl02", 1522 "plkp": "pl04", 1523 "pllb": "pl08", 1524 "plld": "pl10", 1525 "pllu": "pl06", 1526 "plma": "pl12", 1527 "plmz": "pl14", 1528 "plop": "pl16", 1529 "plpd": "pl20", 1530 "plpk": "pl18", 1531 "plpm": "pl22", 1532 "plsk": "pl26", 1533 "plsl": "pl24", 1534 "plwn": "pl28", 1535 "plwp": "pl30", 1536 "plzp": "pl32", 1537 "tteto": "tttob", 1538 "ttrcm": "ttmrc", 1539 "ttwto": "tttob", 1540 "twkhq": "twkhh", 1541 "twtnq": "twtnn", 1542 "twtpq": "twnwt", 1543 "twtxq": "twtxg", 1544 }, 1545 "tz": { 1546 "aqams": "nzakl", 1547 "cnckg": "cnsha", 1548 "cnhrb": "cnsha", 1549 "cnkhg": "cnurc", 1550 "cuba": "cuhav", 1551 "egypt": "egcai", 1552 "eire": "iedub", 1553 "est": "utcw05", 1554 "gmt0": "gmt", 1555 "hongkong": "hkhkg", 1556 "hst": "utcw10", 1557 "iceland": "isrey", 1558 "iran": "irthr", 1559 "israel": "jeruslm", 1560 "jamaica": "jmkin", 1561 "japan": "jptyo", 1562 "libya": "lytip", 1563 "mst": "utcw07", 1564 "navajo": "usden", 1565 "poland": "plwaw", 1566 "portugal": "ptlis", 1567 "prc": "cnsha", 1568 "roc": "twtpe", 1569 "rok": "krsel", 1570 "turkey": "trist", 1571 "uct": "utc", 1572 "usnavajo": "usden", 1573 "zulu": "utc", 1574 }, 1575 }; 1576 1577 1578 /** 1579 * Mappings from Unicode extension subtags to preferred values. 1580 * 1581 * Spec: http://unicode.org/reports/tr35/#Identifiers 1582 * Version: CLDR, version 36.1 1583 */ 1584 var __transformMappings = { 1585 // property names and values must be in canonical case 1586 1587 "d0": { 1588 "name": "charname", 1589 }, 1590 "m0": { 1591 "names": "prprname", 1592 }, 1593 }; 1594 1595 /** 1596 * Canonicalizes the given well-formed BCP 47 language tag, including regularized case of subtags. 1597 * 1598 * Spec: ECMAScript Internationalization API Specification, draft, 6.2.3. 1599 * Spec: RFC 5646, section 4.5. 1600 */ 1601 function canonicalizeLanguageTag(locale) { 1602 1603 // start with lower case for easier processing, and because most subtags will need to be lower case anyway 1604 locale = locale.toLowerCase(); 1605 1606 // handle mappings for complete tags 1607 if (__tagMappings.hasOwnProperty(locale)) { 1608 return __tagMappings[locale]; 1609 } 1610 1611 var subtags = locale.split("-"); 1612 var i = 0; 1613 1614 // handle standard part: all subtags before first variant or singleton subtag 1615 var language; 1616 var script; 1617 var region; 1618 while (i < subtags.length) { 1619 var subtag = subtags[i]; 1620 if (i === 0) { 1621 language = subtag; 1622 } else if (subtag.length === 2 || subtag.length === 3) { 1623 region = subtag.toUpperCase(); 1624 } else if (subtag.length === 4 && !("0" <= subtag[0] && subtag[0] <= "9")) { 1625 script = subtag[0].toUpperCase() + subtag.substring(1).toLowerCase(); 1626 } else { 1627 break; 1628 } 1629 i++; 1630 } 1631 1632 if (__languageMappings.hasOwnProperty(language)) { 1633 language = __languageMappings[language]; 1634 } else if (__complexLanguageMappings.hasOwnProperty(language)) { 1635 var mapping = __complexLanguageMappings[language]; 1636 1637 language = mapping.language; 1638 if (script === undefined && mapping.hasOwnProperty("script")) { 1639 script = mapping.script; 1640 } 1641 if (region === undefined && mapping.hasOwnProperty("region")) { 1642 region = mapping.region; 1643 } 1644 } 1645 1646 if (region !== undefined) { 1647 if (__regionMappings.hasOwnProperty(region)) { 1648 region = __regionMappings[region]; 1649 } else if (__complexRegionMappings.hasOwnProperty(region)) { 1650 var mapping = __complexRegionMappings[region]; 1651 1652 var mappingKey = language; 1653 if (script !== undefined) { 1654 mappingKey += "-" + script; 1655 } 1656 1657 if (mapping.hasOwnProperty(mappingKey)) { 1658 region = mapping[mappingKey]; 1659 } else { 1660 region = mapping.default; 1661 } 1662 } 1663 } 1664 1665 // handle variants 1666 var variants = []; 1667 while (i < subtags.length && subtags[i].length > 1) { 1668 var variant = subtags[i]; 1669 1670 if (__variantMappings.hasOwnProperty(variant)) { 1671 var mapping = __variantMappings[variant]; 1672 switch (mapping.type) { 1673 case "language": 1674 language = mapping.replacement; 1675 break; 1676 1677 case "region": 1678 region = mapping.replacement; 1679 break; 1680 1681 case "variant": 1682 variants.push(mapping.replacement); 1683 break; 1684 1685 default: 1686 throw new Error("illegal variant mapping type"); 1687 } 1688 } else { 1689 variants.push(variant); 1690 } 1691 1692 i += 1; 1693 } 1694 variants.sort(); 1695 1696 // handle extensions 1697 var extensions = []; 1698 while (i < subtags.length && subtags[i] !== "x") { 1699 var extensionStart = i; 1700 i++; 1701 while (i < subtags.length && subtags[i].length > 1) { 1702 i++; 1703 } 1704 1705 var extension; 1706 var extensionKey = subtags[extensionStart]; 1707 if (extensionKey === "u") { 1708 var j = extensionStart + 1; 1709 1710 // skip over leading attributes 1711 while (j < i && subtags[j].length > 2) { 1712 j++; 1713 } 1714 1715 extension = subtags.slice(extensionStart, j).join("-"); 1716 1717 while (j < i) { 1718 var keyStart = j; 1719 j++; 1720 1721 while (j < i && subtags[j].length > 2) { 1722 j++; 1723 } 1724 1725 var key = subtags[keyStart]; 1726 var value = subtags.slice(keyStart + 1, j).join("-"); 1727 1728 if (__unicodeMappings.hasOwnProperty(key)) { 1729 var mapping = __unicodeMappings[key]; 1730 if (mapping.hasOwnProperty(value)) { 1731 value = mapping[value]; 1732 } 1733 } 1734 1735 extension += "-" + key; 1736 if (value !== "" && value !== "true") { 1737 extension += "-" + value; 1738 } 1739 } 1740 } else if (extensionKey === "t") { 1741 var j = extensionStart + 1; 1742 1743 while (j < i && !transformKeyRE.test(subtags[j])) { 1744 j++; 1745 } 1746 1747 extension = "t"; 1748 1749 var transformLanguage = subtags.slice(extensionStart + 1, j).join("-"); 1750 if (transformLanguage !== "") { 1751 extension += "-" + canonicalizeLanguageTag(transformLanguage).toLowerCase(); 1752 } 1753 1754 while (j < i) { 1755 var keyStart = j; 1756 j++; 1757 1758 while (j < i && subtags[j].length > 2) { 1759 j++; 1760 } 1761 1762 var key = subtags[keyStart]; 1763 var value = subtags.slice(keyStart + 1, j).join("-"); 1764 1765 if (__transformMappings.hasOwnProperty(key)) { 1766 var mapping = __transformMappings[key]; 1767 if (mapping.hasOwnProperty(value)) { 1768 value = mapping[value]; 1769 } 1770 } 1771 1772 extension += "-" + key + "-" + value; 1773 } 1774 } else { 1775 extension = subtags.slice(extensionStart, i).join("-"); 1776 } 1777 1778 extensions.push(extension); 1779 } 1780 extensions.sort(); 1781 1782 // handle private use 1783 var privateUse; 1784 if (i < subtags.length) { 1785 privateUse = subtags.slice(i).join("-"); 1786 } 1787 1788 // put everything back together 1789 var canonical = language; 1790 if (script !== undefined) { 1791 canonical += "-" + script; 1792 } 1793 if (region !== undefined) { 1794 canonical += "-" + region; 1795 } 1796 if (variants.length > 0) { 1797 canonical += "-" + variants.join("-"); 1798 } 1799 if (extensions.length > 0) { 1800 canonical += "-" + extensions.join("-"); 1801 } 1802 if (privateUse !== undefined) { 1803 if (canonical.length > 0) { 1804 canonical += "-" + privateUse; 1805 } else { 1806 canonical = privateUse; 1807 } 1808 } 1809 1810 return canonical; 1811 } 1812 1813 return typeof locale === "string" && isStructurallyValidLanguageTag(locale) && 1814 canonicalizeLanguageTag(locale) === locale; 1815 } 1816 1817 1818 /** 1819 * Returns an array of error cases handled by CanonicalizeLocaleList(). 1820 */ 1821 function getInvalidLocaleArguments() { 1822 function CustomError() {} 1823 1824 var topLevelErrors = [ 1825 // fails ToObject 1826 [null, TypeError], 1827 1828 // fails Get 1829 [{ get length() { throw new CustomError(); } }, CustomError], 1830 1831 // fail ToLength 1832 [{ length: Symbol.toPrimitive }, TypeError], 1833 [{ length: { get [Symbol.toPrimitive]() { throw new CustomError(); } } }, CustomError], 1834 [{ length: { [Symbol.toPrimitive]() { throw new CustomError(); } } }, CustomError], 1835 [{ length: { get valueOf() { throw new CustomError(); } } }, CustomError], 1836 [{ length: { valueOf() { throw new CustomError(); } } }, CustomError], 1837 [{ length: { get toString() { throw new CustomError(); } } }, CustomError], 1838 [{ length: { toString() { throw new CustomError(); } } }, CustomError], 1839 1840 // fail type check 1841 [[undefined], TypeError], 1842 [[null], TypeError], 1843 [[true], TypeError], 1844 [[Symbol.toPrimitive], TypeError], 1845 [[1], TypeError], 1846 [[0.1], TypeError], 1847 [[NaN], TypeError], 1848 ]; 1849 1850 var invalidLanguageTags = [ 1851 "", // empty tag 1852 "i", // singleton alone 1853 "x", // private use without subtag 1854 "u", // extension singleton in first place 1855 "419", // region code in first place 1856 "u-nu-latn-cu-bob", // extension sequence without language 1857 "hans-cmn-cn", // "hans" could theoretically be a 4-letter language code, 1858 // but those can't be followed by extlang codes. 1859 "abcdefghi", // overlong language 1860 "cmn-hans-cn-u-u", // duplicate singleton 1861 "cmn-hans-cn-t-u-ca-u", // duplicate singleton 1862 "de-gregory-gregory", // duplicate variant 1863 "*", // language range 1864 "de-*", // language range 1865 "中文", // non-ASCII letters 1866 "en-ß", // non-ASCII letters 1867 "ıd" // non-ASCII letters 1868 ]; 1869 1870 return topLevelErrors.concat( 1871 invalidLanguageTags.map(tag => [tag, RangeError]), 1872 invalidLanguageTags.map(tag => [[tag], RangeError]), 1873 invalidLanguageTags.map(tag => [["en", tag], RangeError]), 1874 ) 1875 } 1876 1877 /** 1878 * Tests whether the named options property is correctly handled by the given constructor. 1879 * @param {object} Constructor the constructor to test. 1880 * @param {string} property the name of the options property to test. 1881 * @param {string} type the type that values of the property are expected to have 1882 * @param {Array} [values] an array of allowed values for the property. Not needed for boolean. 1883 * @param {any} fallback the fallback value that the property assumes if not provided. 1884 * @param {object} testOptions additional options: 1885 * @param {boolean} isOptional whether support for this property is optional for implementations. 1886 * @param {boolean} noReturn whether the resulting value of the property is not returned. 1887 * @param {boolean} isILD whether the resulting value of the property is implementation and locale dependent. 1888 * @param {object} extra additional option to pass along, properties are value -> {option: value}. 1889 */ 1890 function testOption(Constructor, property, type, values, fallback, testOptions) { 1891 var isOptional = testOptions !== undefined && testOptions.isOptional === true; 1892 var noReturn = testOptions !== undefined && testOptions.noReturn === true; 1893 var isILD = testOptions !== undefined && testOptions.isILD === true; 1894 1895 function addExtraOptions(options, value, testOptions) { 1896 if (testOptions !== undefined && testOptions.extra !== undefined) { 1897 var extra; 1898 if (value !== undefined && testOptions.extra[value] !== undefined) { 1899 extra = testOptions.extra[value]; 1900 } else if (testOptions.extra.any !== undefined) { 1901 extra = testOptions.extra.any; 1902 } 1903 if (extra !== undefined) { 1904 Object.getOwnPropertyNames(extra).forEach(function (prop) { 1905 options[prop] = extra[prop]; 1906 }); 1907 } 1908 } 1909 } 1910 1911 var testValues, options, obj, expected, actual, error; 1912 1913 // test that the specified values are accepted. Also add values that convert to specified values. 1914 if (type === "boolean") { 1915 if (values === undefined) { 1916 values = [true, false]; 1917 } 1918 testValues = values.slice(0); 1919 testValues.push(888); 1920 testValues.push(0); 1921 } else if (type === "string") { 1922 testValues = values.slice(0); 1923 testValues.push({toString: function () { return values[0]; }}); 1924 } 1925 testValues.forEach(function (value) { 1926 options = {}; 1927 options[property] = value; 1928 addExtraOptions(options, value, testOptions); 1929 obj = new Constructor(undefined, options); 1930 if (noReturn) { 1931 if (obj.resolvedOptions().hasOwnProperty(property)) { 1932 throw new Test262Error("Option property " + property + " is returned, but shouldn't be."); 1933 } 1934 } else { 1935 actual = obj.resolvedOptions()[property]; 1936 if (isILD) { 1937 if (actual !== undefined && values.indexOf(actual) === -1) { 1938 throw new Test262Error("Invalid value " + actual + " returned for property " + property + "."); 1939 } 1940 } else { 1941 if (type === "boolean") { 1942 expected = Boolean(value); 1943 } else if (type === "string") { 1944 expected = String(value); 1945 } 1946 if (actual !== expected && !(isOptional && actual === undefined)) { 1947 throw new Test262Error("Option value " + value + " for property " + property + 1948 " was not accepted; got " + actual + " instead."); 1949 } 1950 } 1951 } 1952 }); 1953 1954 // test that invalid values are rejected 1955 if (type === "string") { 1956 var invalidValues = ["invalidValue", -1, null]; 1957 // assume that we won't have values in caseless scripts 1958 if (values[0].toUpperCase() !== values[0]) { 1959 invalidValues.push(values[0].toUpperCase()); 1960 } else { 1961 invalidValues.push(values[0].toLowerCase()); 1962 } 1963 invalidValues.forEach(function (value) { 1964 options = {}; 1965 options[property] = value; 1966 addExtraOptions(options, value, testOptions); 1967 error = undefined; 1968 try { 1969 obj = new Constructor(undefined, options); 1970 } catch (e) { 1971 error = e; 1972 } 1973 if (error === undefined) { 1974 throw new Test262Error("Invalid option value " + value + " for property " + property + " was not rejected."); 1975 } else if (error.name !== "RangeError") { 1976 throw new Test262Error("Invalid option value " + value + " for property " + property + " was rejected with wrong error " + error.name + "."); 1977 } 1978 }); 1979 } 1980 1981 // test that fallback value or another valid value is used if no options value is provided 1982 if (!noReturn) { 1983 options = {}; 1984 addExtraOptions(options, undefined, testOptions); 1985 obj = new Constructor(undefined, options); 1986 actual = obj.resolvedOptions()[property]; 1987 if (!(isOptional && actual === undefined)) { 1988 if (fallback !== undefined) { 1989 if (actual !== fallback) { 1990 throw new Test262Error("Option fallback value " + fallback + " for property " + property + 1991 " was not used; got " + actual + " instead."); 1992 } 1993 } else { 1994 if (values.indexOf(actual) === -1 && !(isILD && actual === undefined)) { 1995 throw new Test262Error("Invalid value " + actual + " returned for property " + property + "."); 1996 } 1997 } 1998 } 1999 } 2000 } 2001 2002 2003 /** 2004 * Properties of the RegExp constructor that may be affected by use of regular 2005 * expressions, and the default values of these properties. Properties are from 2006 * https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Deprecated_and_obsolete_features#RegExp_Properties 2007 */ 2008 var regExpProperties = ["$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", 2009 "$_", "$*", "$&", "$+", "$`", "$'", 2010 "input", "lastMatch", "lastParen", "leftContext", "rightContext" 2011 ]; 2012 2013 var regExpPropertiesDefaultValues = (function () { 2014 var values = Object.create(null); 2015 (/(?:)/).test(""); 2016 regExpProperties.forEach(function (property) { 2017 values[property] = RegExp[property]; 2018 }); 2019 return values; 2020 }()); 2021 2022 2023 /** 2024 * Tests that executing the provided function (which may use regular expressions 2025 * in its implementation) does not create or modify unwanted properties on the 2026 * RegExp constructor. 2027 */ 2028 function testForUnwantedRegExpChanges(testFunc) { 2029 (/(?:)/).test(""); 2030 testFunc(); 2031 regExpProperties.forEach(function (property) { 2032 if (RegExp[property] !== regExpPropertiesDefaultValues[property]) { 2033 throw new Test262Error("RegExp has unexpected property " + property + " with value " + 2034 RegExp[property] + "."); 2035 } 2036 }); 2037 } 2038 2039 2040 /** 2041 * Returns an array of all known calendars. 2042 */ 2043 function allCalendars() { 2044 // source: CLDR file common/bcp47/number.xml; version CLDR 39. 2045 // https://github.com/unicode-org/cldr/blob/master/common/bcp47/calendar.xml 2046 return [ 2047 "buddhist", 2048 "chinese", 2049 "coptic", 2050 "dangi", 2051 "ethioaa", 2052 "ethiopic", 2053 "gregory", 2054 "hebrew", 2055 "indian", 2056 "islamic", 2057 "islamic-umalqura", 2058 "islamic-tbla", 2059 "islamic-civil", 2060 "islamic-rgsa", 2061 "iso8601", 2062 "japanese", 2063 "persian", 2064 "roc", 2065 ]; 2066 } 2067 2068 2069 /** 2070 * Returns an array of all known collations. 2071 */ 2072 function allCollations() { 2073 // source: CLDR file common/bcp47/collation.xml; version CLDR 39. 2074 // https://github.com/unicode-org/cldr/blob/master/common/bcp47/collation.xml 2075 return [ 2076 "big5han", 2077 "compat", 2078 "dict", 2079 "direct", 2080 "ducet", 2081 "emoji", 2082 "eor", 2083 "gb2312", 2084 "phonebk", 2085 "phonetic", 2086 "pinyin", 2087 "reformed", 2088 "search", 2089 "searchjl", 2090 "standard", 2091 "stroke", 2092 "trad", 2093 "unihan", 2094 "zhuyin", 2095 ]; 2096 } 2097 2098 2099 /** 2100 * Returns an array of all known numbering systems. 2101 */ 2102 function allNumberingSystems() { 2103 // source: CLDR file common/bcp47/number.xml; version CLDR 40 & new in Unicode 14.0 2104 // https://github.com/unicode-org/cldr/blob/master/common/bcp47/number.xml 2105 return [ 2106 "adlm", 2107 "ahom", 2108 "arab", 2109 "arabext", 2110 "armn", 2111 "armnlow", 2112 "bali", 2113 "beng", 2114 "bhks", 2115 "brah", 2116 "cakm", 2117 "cham", 2118 "cyrl", 2119 "deva", 2120 "diak", 2121 "ethi", 2122 "finance", 2123 "fullwide", 2124 "gara", 2125 "geor", 2126 "gong", 2127 "gonm", 2128 "grek", 2129 "greklow", 2130 "gujr", 2131 "gukh", 2132 "guru", 2133 "hanidays", 2134 "hanidec", 2135 "hans", 2136 "hansfin", 2137 "hant", 2138 "hantfin", 2139 "hebr", 2140 "hmng", 2141 "hmnp", 2142 "java", 2143 "jpan", 2144 "jpanfin", 2145 "jpanyear", 2146 "kali", 2147 "kawi", 2148 "khmr", 2149 "knda", 2150 "krai", 2151 "lana", 2152 "lanatham", 2153 "laoo", 2154 "latn", 2155 "lepc", 2156 "limb", 2157 "mathbold", 2158 "mathdbl", 2159 "mathmono", 2160 "mathsanb", 2161 "mathsans", 2162 "mlym", 2163 "modi", 2164 "mong", 2165 "mroo", 2166 "mtei", 2167 "mymr", 2168 "mymrepka", 2169 "mymrpao", 2170 "mymrshan", 2171 "mymrtlng", 2172 "nagm", 2173 "native", 2174 "newa", 2175 "nkoo", 2176 "olck", 2177 "onao", 2178 "orya", 2179 "osma", 2180 "outlined", 2181 "rohg", 2182 "roman", 2183 "romanlow", 2184 "saur", 2185 "shrd", 2186 "sind", 2187 "sinh", 2188 "sora", 2189 "sund", 2190 "sunu", 2191 "takr", 2192 "talu", 2193 "taml", 2194 "tamldec", 2195 "tnsa", 2196 "telu", 2197 "thai", 2198 "tirh", 2199 "tibt", 2200 "traditio", 2201 "vaii", 2202 "wara", 2203 "wcho", 2204 ]; 2205 } 2206 2207 2208 /** 2209 * Tests whether name is a valid BCP 47 numbering system name 2210 * and not excluded from use in the ECMAScript Internationalization API. 2211 * @param {string} name the name to be tested. 2212 * @return {boolean} whether name is a valid BCP 47 numbering system name and 2213 * allowed for use in the ECMAScript Internationalization API. 2214 */ 2215 2216 function isValidNumberingSystem(name) { 2217 2218 var numberingSystems = allNumberingSystems(); 2219 2220 var excluded = [ 2221 "finance", 2222 "native", 2223 "traditio" 2224 ]; 2225 2226 2227 return numberingSystems.indexOf(name) !== -1 && excluded.indexOf(name) === -1; 2228 } 2229 2230 2231 /** 2232 * Provides the digits of numbering systems with simple digit mappings, 2233 * as specified in 11.3.2. 2234 */ 2235 2236 var numberingSystemDigits = { 2237 adlm: "𞥐𞥑𞥒𞥓𞥔𞥕𞥖𞥗𞥘𞥙", 2238 ahom: "𑜰𑜱𑜲𑜳𑜴𑜵𑜶𑜷𑜸𑜹", 2239 arab: "٠١٢٣٤٥٦٧٨٩", 2240 arabext: "۰۱۲۳۴۵۶۷۸۹", 2241 bali: "\u1B50\u1B51\u1B52\u1B53\u1B54\u1B55\u1B56\u1B57\u1B58\u1B59", 2242 beng: "০১২৩৪৫৬৭৮৯", 2243 bhks: "𑱐𑱑𑱒𑱓𑱔𑱕𑱖𑱗𑱘𑱙", 2244 brah: "𑁦𑁧𑁨𑁩𑁪𑁫𑁬𑁭𑁮𑁯", 2245 cakm: "𑄶𑄷𑄸𑄹𑄺𑄻𑄼𑄽𑄾𑄿", 2246 cham: "꩐꩑꩒꩓꩔꩕꩖꩗꩘꩙", 2247 deva: "०१२३४५६७८९", 2248 diak: "𑥐𑥑𑥒𑥓𑥔𑥕𑥖𑥗𑥘𑥙", 2249 fullwide: "0123456789", 2250 gong: "𑶠𑶡𑶢𑶣𑶤𑶥𑶦𑶧𑶨𑶩", 2251 gonm: "𑵐𑵑𑵒𑵓𑵔𑵕𑵖𑵗𑵘𑵙", 2252 gujr: "૦૧૨૩૪૫૬૭૮૯", 2253 guru: "੦੧੨੩੪੫੬੭੮੯", 2254 hanidec: "〇一二三四五六七八九", 2255 hmng: "𖭐𖭑𖭒𖭓𖭔𖭕𖭖𖭗𖭘𖭙", 2256 hmnp: "𞅀𞅁𞅂𞅃𞅄𞅅𞅆𞅇𞅈𞅉", 2257 java: "꧐꧑꧒꧓꧔꧕꧖꧗꧘꧙", 2258 kali: "꤀꤁꤂꤃꤄꤅꤆꤇꤈꤉", 2259 kawi: "\u{11F50}\u{11F51}\u{11F52}\u{11F53}\u{11F54}\u{11F55}\u{11F56}\u{11F57}\u{11F58}\u{11F59}", 2260 khmr: "០១២៣៤៥៦៧៨៩", 2261 knda: "೦೧೨೩೪೫೬೭೮೯", 2262 lana: "᪀᪁᪂᪃᪄᪅᪆᪇᪈᪉", 2263 lanatham: "᪐᪑᪒᪓᪔᪕᪖᪗᪘᪙", 2264 laoo: "໐໑໒໓໔໕໖໗໘໙", 2265 latn: "0123456789", 2266 lepc: "᱀᱁᱂᱃᱄᱅᱆᱇᱈᱉", 2267 limb: "\u1946\u1947\u1948\u1949\u194A\u194B\u194C\u194D\u194E\u194F", 2268 nagm: "\u{1E4F0}\u{1E4F1}\u{1E4F2}\u{1E4F3}\u{1E4F4}\u{1E4F5}\u{1E4F6}\u{1E4F7}\u{1E4F8}\u{1E4F9}", 2269 mathbold: "𝟎𝟏𝟐𝟑𝟒𝟓𝟔𝟕𝟖𝟗", 2270 mathdbl: "𝟘𝟙𝟚𝟛𝟜𝟝𝟞𝟟𝟠𝟡", 2271 mathmono: "𝟶𝟷𝟸𝟹𝟺𝟻𝟼𝟽𝟾𝟿", 2272 mathsanb: "𝟬𝟭𝟮𝟯𝟰𝟱𝟲𝟳𝟴𝟵", 2273 mathsans: "𝟢𝟣𝟤𝟥𝟦𝟧𝟨𝟩𝟪𝟫", 2274 mlym: "൦൧൨൩൪൫൬൭൮൯", 2275 modi: "𑙐𑙑𑙒𑙓𑙔𑙕𑙖𑙗𑙘𑙙", 2276 mong: "᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙", 2277 mroo: "𖩠𖩡𖩢𖩣𖩤𖩥𖩦𖩧𖩨𖩩", 2278 mtei: "꯰꯱꯲꯳꯴꯵꯶꯷꯸꯹", 2279 mymr: "၀၁၂၃၄၅၆၇၈၉", 2280 mymrshan: "႐႑႒႓႔႕႖႗႘႙", 2281 mymrtlng: "꧰꧱꧲꧳꧴꧵꧶꧷꧸꧹", 2282 newa: "𑑐𑑑𑑒𑑓𑑔𑑕𑑖𑑗𑑘𑑙", 2283 nkoo: "߀߁߂߃߄߅߆߇߈߉", 2284 olck: "᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙", 2285 orya: "୦୧୨୩୪୫୬୭୮୯", 2286 osma: "𐒠𐒡𐒢𐒣𐒤𐒥𐒦𐒧𐒨𐒩", 2287 rohg: "𐴰𐴱𐴲𐴳𐴴𐴵𐴶𐴷𐴸𐴹", 2288 saur: "꣐꣑꣒꣓꣔꣕꣖꣗꣘꣙", 2289 segment: "🯰🯱🯲🯳🯴🯵🯶🯷🯸🯹", 2290 shrd: "𑇐𑇑𑇒𑇓𑇔𑇕𑇖𑇗𑇘𑇙", 2291 sind: "𑋰𑋱𑋲𑋳𑋴𑋵𑋶𑋷𑋸𑋹", 2292 sinh: "෦෧෨෩෪෫෬෭෮෯", 2293 sora: "𑃰𑃱𑃲𑃳𑃴𑃵𑃶𑃷𑃸𑃹", 2294 sund: "᮰᮱᮲᮳᮴᮵᮶᮷᮸᮹", 2295 takr: "𑛀𑛁𑛂𑛃𑛄𑛅𑛆𑛇𑛈𑛉", 2296 talu: "᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙", 2297 tamldec: "௦௧௨௩௪௫௬௭௮௯", 2298 tnsa: "\u{16AC0}\u{16AC1}\u{16AC2}\u{16AC3}\u{16AC4}\u{16AC5}\u{16AC6}\u{16AC7}\u{16AC8}\u{16AC9}", 2299 telu: "౦౧౨౩౪౫౬౭౮౯", 2300 thai: "๐๑๒๓๔๕๖๗๘๙", 2301 tibt: "༠༡༢༣༤༥༦༧༨༩", 2302 tirh: "𑓐𑓑𑓒𑓓𑓔𑓕𑓖𑓗𑓘𑓙", 2303 vaii: "꘠꘡꘢꘣꘤꘥꘦꘧꘨꘩", 2304 wara: "𑣠𑣡𑣢𑣣𑣤𑣥𑣦𑣧𑣨𑣩", 2305 wcho: "𞋰𞋱𞋲𞋳𞋴𞋵𞋶𞋷𞋸𞋹", 2306 }; 2307 2308 2309 /** 2310 * Returns an array of all simple, sanctioned unit identifiers. 2311 */ 2312 function allSimpleSanctionedUnits() { 2313 // https://tc39.es/ecma402/#table-sanctioned-simple-unit-identifiers 2314 return [ 2315 "acre", 2316 "bit", 2317 "byte", 2318 "celsius", 2319 "centimeter", 2320 "day", 2321 "degree", 2322 "fahrenheit", 2323 "fluid-ounce", 2324 "foot", 2325 "gallon", 2326 "gigabit", 2327 "gigabyte", 2328 "gram", 2329 "hectare", 2330 "hour", 2331 "inch", 2332 "kilobit", 2333 "kilobyte", 2334 "kilogram", 2335 "kilometer", 2336 "liter", 2337 "megabit", 2338 "megabyte", 2339 "meter", 2340 "microsecond", 2341 "mile", 2342 "mile-scandinavian", 2343 "milliliter", 2344 "millimeter", 2345 "millisecond", 2346 "minute", 2347 "month", 2348 "nanosecond", 2349 "ounce", 2350 "percent", 2351 "petabyte", 2352 "pound", 2353 "second", 2354 "stone", 2355 "terabit", 2356 "terabyte", 2357 "week", 2358 "yard", 2359 "year", 2360 ]; 2361 } 2362 2363 2364 /** 2365 * Tests that number formatting is handled correctly. The function checks that the 2366 * digit sequences in formatted output are as specified, converted to the 2367 * selected numbering system, and embedded in consistent localized patterns. 2368 * @param {Array} locales the locales to be tested. 2369 * @param {Array} numberingSystems the numbering systems to be tested. 2370 * @param {Object} options the options to pass to Intl.NumberFormat. Options 2371 * must include {useGrouping: false}, and must cause 1.1 to be formatted 2372 * pre- and post-decimal digits. 2373 * @param {Object} testData maps input data (in ES5 9.3.1 format) to expected output strings 2374 * in unlocalized format with Western digits. 2375 */ 2376 2377 function testNumberFormat(locales, numberingSystems, options, testData) { 2378 locales.forEach(function (locale) { 2379 numberingSystems.forEach(function (numbering) { 2380 var digits = numberingSystemDigits[numbering]; 2381 var format = new Intl.NumberFormat([locale + "-u-nu-" + numbering], options); 2382 2383 function getPatternParts(positive) { 2384 var n = positive ? 1.1 : -1.1; 2385 var formatted = format.format(n); 2386 var oneoneRE = "([^" + digits + "]*)[" + digits + "]+([^" + digits + "]+)[" + digits + "]+([^" + digits + "]*)"; 2387 var match = formatted.match(new RegExp(oneoneRE)); 2388 if (match === null) { 2389 throw new Test262Error("Unexpected formatted " + n + " for " + 2390 format.resolvedOptions().locale + " and options " + 2391 JSON.stringify(options) + ": " + formatted); 2392 } 2393 return match; 2394 } 2395 2396 function toNumbering(raw) { 2397 return raw.replace(/[0-9]/g, function (digit) { 2398 return digits[digit.charCodeAt(0) - "0".charCodeAt(0)]; 2399 }); 2400 } 2401 2402 function buildExpected(raw, patternParts) { 2403 var period = raw.indexOf("."); 2404 if (period === -1) { 2405 return patternParts[1] + toNumbering(raw) + patternParts[3]; 2406 } else { 2407 return patternParts[1] + 2408 toNumbering(raw.substring(0, period)) + 2409 patternParts[2] + 2410 toNumbering(raw.substring(period + 1)) + 2411 patternParts[3]; 2412 } 2413 } 2414 2415 if (format.resolvedOptions().numberingSystem === numbering) { 2416 // figure out prefixes, infixes, suffixes for positive and negative values 2417 var posPatternParts = getPatternParts(true); 2418 var negPatternParts = getPatternParts(false); 2419 2420 Object.getOwnPropertyNames(testData).forEach(function (input) { 2421 var rawExpected = testData[input]; 2422 var patternParts; 2423 if (rawExpected[0] === "-") { 2424 patternParts = negPatternParts; 2425 rawExpected = rawExpected.substring(1); 2426 } else { 2427 patternParts = posPatternParts; 2428 } 2429 var expected = buildExpected(rawExpected, patternParts); 2430 var actual = format.format(input); 2431 if (actual !== expected) { 2432 throw new Test262Error("Formatted value for " + input + ", " + 2433 format.resolvedOptions().locale + " and options " + 2434 JSON.stringify(options) + " is " + actual + "; expected " + expected + "."); 2435 } 2436 }); 2437 } 2438 }); 2439 }); 2440 } 2441 2442 2443 /** 2444 * Return the components of date-time formats. 2445 * @return {Array} an array with all date-time components. 2446 */ 2447 2448 function getDateTimeComponents() { 2449 return ["weekday", "era", "year", "month", "day", "hour", "minute", "second", "timeZoneName"]; 2450 } 2451 2452 2453 /** 2454 * Return the valid values for the given date-time component, as specified 2455 * by the table in section 12.1.1. 2456 * @param {string} component a date-time component. 2457 * @return {Array} an array with the valid values for the component. 2458 */ 2459 2460 function getDateTimeComponentValues(component) { 2461 2462 var components = { 2463 weekday: ["narrow", "short", "long"], 2464 era: ["narrow", "short", "long"], 2465 year: ["2-digit", "numeric"], 2466 month: ["2-digit", "numeric", "narrow", "short", "long"], 2467 day: ["2-digit", "numeric"], 2468 hour: ["2-digit", "numeric"], 2469 minute: ["2-digit", "numeric"], 2470 second: ["2-digit", "numeric"], 2471 timeZoneName: ["short", "long"] 2472 }; 2473 2474 var result = components[component]; 2475 if (result === undefined) { 2476 throw new Test262Error("Internal error: No values defined for date-time component " + component + "."); 2477 } 2478 return result; 2479 } 2480 2481 2482 /** 2483 * @description Tests whether timeZone is a String value representing a 2484 * structurally valid and canonicalized time zone name, as defined in 2485 * sections 6.4.1 and 6.4.2 of the ECMAScript Internationalization API 2486 * Specification. 2487 * @param {String} timeZone the string to be tested. 2488 * @result {Boolean} whether the test succeeded. 2489 */ 2490 2491 function isCanonicalizedStructurallyValidTimeZoneName(timeZone) { 2492 /** 2493 * Regular expression defining IANA Time Zone names. 2494 * 2495 * Spec: IANA Time Zone Database, Theory file 2496 */ 2497 var fileNameComponent = "(?:[A-Za-z_]|\\.(?!\\.?(?:/|$)))[A-Za-z.\\-_]{0,13}"; 2498 var fileName = fileNameComponent + "(?:/" + fileNameComponent + ")*"; 2499 var etcName = "(?:Etc/)?GMT[+-]\\d{1,2}"; 2500 var systemVName = "SystemV/[A-Z]{3}\\d{1,2}(?:[A-Z]{3})?"; 2501 var legacyName = etcName + "|" + systemVName + "|CST6CDT|EST5EDT|MST7MDT|PST8PDT|NZ"; 2502 var zoneNamePattern = new RegExp("^(?:" + fileName + "|" + legacyName + ")$"); 2503 2504 if (typeof timeZone !== "string") { 2505 return false; 2506 } 2507 // 6.4.2 CanonicalizeTimeZoneName (timeZone), step 3 2508 if (timeZone === "UTC") { 2509 return true; 2510 } 2511 // 6.4.2 CanonicalizeTimeZoneName (timeZone), step 3 2512 if (timeZone === "Etc/UTC" || timeZone === "Etc/GMT") { 2513 return false; 2514 } 2515 return zoneNamePattern.test(timeZone); 2516 } 2517 2518 2519 /** 2520 * @description Simplified PartitionDurationFormatPattern implementation which 2521 * only supports the "en" locale. 2522 * @param {Object} durationFormat the duration format object 2523 * @param {Object} duration the duration record 2524 * @result {Array} an array with formatted duration parts 2525 */ 2526 2527 function partitionDurationFormatPattern(durationFormat, duration) { 2528 function durationToFractional(duration, exponent) { 2529 let { 2530 seconds = 0, 2531 milliseconds = 0, 2532 microseconds = 0, 2533 nanoseconds = 0, 2534 } = duration; 2535 2536 // Directly return the duration amount when no sub-seconds are present. 2537 switch (exponent) { 2538 case 9: { 2539 if (milliseconds === 0 && microseconds === 0 && nanoseconds === 0) { 2540 return seconds; 2541 } 2542 break; 2543 } 2544 case 6: { 2545 if (microseconds === 0 && nanoseconds === 0) { 2546 return milliseconds; 2547 } 2548 break; 2549 } 2550 case 3: { 2551 if (nanoseconds === 0) { 2552 return microseconds; 2553 } 2554 break; 2555 } 2556 } 2557 2558 // Otherwise compute the overall amount of nanoseconds using BigInt to avoid 2559 // loss of precision. 2560 let ns = BigInt(nanoseconds); 2561 switch (exponent) { 2562 case 9: 2563 ns += BigInt(seconds) * 1_000_000_000n; 2564 // fallthrough 2565 case 6: 2566 ns += BigInt(milliseconds) * 1_000_000n; 2567 // fallthrough 2568 case 3: 2569 ns += BigInt(microseconds) * 1_000n; 2570 // fallthrough 2571 } 2572 2573 let e = BigInt(10 ** exponent); 2574 2575 // Split the nanoseconds amount into an integer and its fractional part. 2576 let q = ns / e; 2577 let r = ns % e; 2578 2579 // Pad fractional part, without any leading negative sign, to |exponent| digits. 2580 if (r < 0) { 2581 r = -r; 2582 } 2583 r = String(r).padStart(exponent, "0"); 2584 2585 // Return the result as a decimal string. 2586 return `${q}.${r}`; 2587 } 2588 2589 const units = [ 2590 "years", 2591 "months", 2592 "weeks", 2593 "days", 2594 "hours", 2595 "minutes", 2596 "seconds", 2597 "milliseconds", 2598 "microseconds", 2599 "nanoseconds", 2600 ]; 2601 2602 let options = durationFormat.resolvedOptions(); 2603 2604 // Only "en" is supported. 2605 const locale = "en"; 2606 const numberingSystem = "latn"; 2607 const timeSeparator = ":"; 2608 2609 let result = []; 2610 let needSeparator = false; 2611 let displayNegativeSign = true; 2612 2613 for (let unit of units) { 2614 // Absent units default to zero. 2615 let value = duration[unit] ?? 0; 2616 2617 let style = options[unit]; 2618 let display = options[unit + "Display"]; 2619 2620 // NumberFormat requires singular unit names. 2621 let numberFormatUnit = unit.slice(0, -1); 2622 2623 // Compute the matching NumberFormat options. 2624 let nfOpts = Object.create(null); 2625 2626 // Numeric seconds and sub-seconds are combined into a single value. 2627 let done = false; 2628 if (unit === "seconds" || unit === "milliseconds" || unit === "microseconds") { 2629 let nextStyle = options[units[units.indexOf(unit) + 1]]; 2630 if (nextStyle === "numeric") { 2631 if (unit === "seconds") { 2632 value = durationToFractional(duration, 9); 2633 } else if (unit === "milliseconds") { 2634 value = durationToFractional(duration, 6); 2635 } else { 2636 value = durationToFractional(duration, 3); 2637 } 2638 2639 nfOpts.maximumFractionDigits = options.fractionalDigits ?? 9; 2640 nfOpts.minimumFractionDigits = options.fractionalDigits ?? 0; 2641 nfOpts.roundingMode = "trunc"; 2642 2643 done = true; 2644 } 2645 } 2646 2647 // Display zero numeric minutes when seconds will be displayed. 2648 let displayRequired = false; 2649 if (unit === "minutes" && needSeparator) { 2650 displayRequired = options.secondsDisplay === "always" || 2651 (duration.seconds ?? 0) !== 0 || 2652 (duration.milliseconds ?? 0) !== 0 || 2653 (duration.microseconds ?? 0) !== 0 || 2654 (duration.nanoseconds ?? 0) !== 0; 2655 } 2656 2657 // "auto" display omits zero units. 2658 if (value !== 0 || display !== "auto" || displayRequired) { 2659 // Display only the first negative value. 2660 if (displayNegativeSign) { 2661 displayNegativeSign = false; 2662 2663 // Set to negative zero to ensure the sign is displayed. 2664 if (value === 0) { 2665 let negative = units.some(unit => (duration[unit] ?? 0) < 0); 2666 if (negative) { 2667 value = -0; 2668 } 2669 } 2670 } else { 2671 nfOpts.signDisplay = "never"; 2672 } 2673 2674 nfOpts.numberingSystem = options.numberingSystem; 2675 2676 // If the value is formatted as a 2-digit numeric value. 2677 if (style === "2-digit") { 2678 nfOpts.minimumIntegerDigits = 2; 2679 } 2680 2681 // If the value is formatted as a standalone unit. 2682 if (style !== "numeric" && style !== "2-digit") { 2683 nfOpts.style = "unit"; 2684 nfOpts.unit = numberFormatUnit; 2685 nfOpts.unitDisplay = style; 2686 } else { 2687 nfOpts.useGrouping = false; 2688 } 2689 2690 let nf = new Intl.NumberFormat(locale, nfOpts); 2691 2692 let list; 2693 if (!needSeparator) { 2694 list = []; 2695 } else { 2696 list = result[result.length - 1]; 2697 2698 // Prepend the time separator before the formatted number. 2699 list.push({ 2700 type: "literal", 2701 value: timeSeparator, 2702 }); 2703 } 2704 2705 // Format the numeric value. 2706 let parts = nf.formatToParts(value); 2707 2708 // Add |numberFormatUnit| to the formatted number. 2709 for (let {value, type} of parts) { 2710 list.push({type, value, unit: numberFormatUnit}); 2711 } 2712 2713 if (!needSeparator) { 2714 // Prepend the separator before the next numeric unit. 2715 if (style === "2-digit" || style === "numeric") { 2716 needSeparator = true; 2717 } 2718 2719 // Append the formatted number to |result|. 2720 result.push(list); 2721 } 2722 } 2723 2724 if (done) { 2725 break; 2726 } 2727 } 2728 2729 let listStyle = options.style; 2730 if (listStyle === "digital") { 2731 listStyle = "short"; 2732 } 2733 2734 let lf = new Intl.ListFormat(locale, { 2735 type: "unit", 2736 style: listStyle, 2737 }); 2738 2739 // Collect all formatted units into a list of strings. 2740 let strings = []; 2741 for (let parts of result) { 2742 let string = ""; 2743 for (let {value} of parts) { 2744 string += value; 2745 } 2746 strings.push(string); 2747 } 2748 2749 // Format the list of strings and compute the overall result. 2750 let flattened = []; 2751 for (let {type, value} of lf.formatToParts(strings)) { 2752 if (type === "element") { 2753 flattened.push(...result.shift()); 2754 } else { 2755 flattened.push({type, value}); 2756 } 2757 } 2758 return flattened; 2759 } 2760 2761 2762 /** 2763 * @description Return the formatted string from partitionDurationFormatPattern. 2764 * @param {Object} durationFormat the duration format object 2765 * @param {Object} duration the duration record 2766 * @result {String} a string containing the formatted duration 2767 */ 2768 2769 function formatDurationFormatPattern(durationFormat, duration) { 2770 let parts = partitionDurationFormatPattern(durationFormat, duration); 2771 return parts.reduce((acc, e) => acc + e.value, ""); 2772 }