mirror of https://github.com/tc39/test262.git
Added new tests for chapters 6 and 9 of ECMAScript Internationalization API Specification.
- Removed a few old test cases that were redundant with new, more comprehensive ones. - Added testIntl.js as standard include for all console tests in test262.py – see related bug 574. - Added .jshintrc file for settings for the JSHint tool.
This commit is contained in:
parent
8cad7d03ce
commit
1af2425075
|
@ -0,0 +1,658 @@
|
|||
// Copyright 2011-2012 Norbert Lindenberg. All rights reserved.
|
||||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* This file contains shared functions for the tests in the conformance test
|
||||
* suite for the ECMAScript Internationalization API.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @description Calls the provided function for every service constructor in
|
||||
* the Intl object, until f returns a falsy value. It returns the result of the
|
||||
* last call to f, mapped to a boolean.
|
||||
* @param {Function} f the function to call for each service constructor in
|
||||
* the Intl object.
|
||||
* @param {Function} Constructor the constructor object to test with.
|
||||
* @result {Boolean} whether the test succeeded.
|
||||
*/
|
||||
function testWithIntlConstructors(f) {
|
||||
var constructors = ["Collator", "NumberFormat", "DateTimeFormat"];
|
||||
return constructors.every(function (constructor) {
|
||||
var Constructor = Intl[constructor];
|
||||
var result;
|
||||
try {
|
||||
result = f(Constructor);
|
||||
} catch (e) {
|
||||
e.message += " (Testing with " + constructor + ".)";
|
||||
throw e;
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the name of the given constructor object, which must be one of
|
||||
* Intl.Collator, Intl.NumberFormat, or Intl.DateTimeFormat.
|
||||
* @param {object} Constructor a constructor
|
||||
* @return {string} the name of the constructor
|
||||
*/
|
||||
function getConstructorName(Constructor) {
|
||||
switch (Constructor) {
|
||||
case Intl.Collator:
|
||||
return "Collator";
|
||||
case Intl.NumberFormat:
|
||||
return "NumberFormat";
|
||||
case Intl.DateTimeFormat:
|
||||
return "DateTimeFormat";
|
||||
default:
|
||||
$ERROR("test internal error: unknown Constructor");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Taints a named data property of the given object by installing
|
||||
* a setter that throws an exception.
|
||||
* @param {object} obj the object whose data property to taint
|
||||
* @param {string} property the property to taint
|
||||
*/
|
||||
function taintDataProperty(obj, property) {
|
||||
Object.defineProperty(obj, property, {
|
||||
set: function(value) {
|
||||
$ERROR("Client code can adversely affect behavior: setter for " + property + ".");
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Taints a named method of the given object by replacing it with a function
|
||||
* that throws an exception.
|
||||
* @param {object} obj the object whose method to taint
|
||||
* @param {string} property the name of the method to taint
|
||||
*/
|
||||
function taintMethod(obj, property) {
|
||||
Object.defineProperty(obj, property, {
|
||||
value: function() {
|
||||
$ERROR("Client code can adversely affect behavior: method " + property + ".");
|
||||
},
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Taints the given properties (and similarly named properties) by installing
|
||||
* setters on Object.prototype that throw exceptions.
|
||||
* @param {Array} properties an array of property names to taint
|
||||
*/
|
||||
function taintProperties(properties) {
|
||||
properties.forEach(function (property) {
|
||||
var adaptedProperties = [property, "__" + property, "_" + property, property + "_", property + "__"];
|
||||
adaptedProperties.forEach(function (property) {
|
||||
taintDataProperty(Object.prototype, property);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Taints the Array object by creating a setter for the property "0" and
|
||||
* replacing some key methods with functions that throw exceptions.
|
||||
*/
|
||||
function taintArray() {
|
||||
taintDataProperty(Array.prototype, "0");
|
||||
taintMethod(Array.prototype, "indexOf");
|
||||
taintMethod(Array.prototype, "join");
|
||||
taintMethod(Array.prototype, "push");
|
||||
taintMethod(Array.prototype, "slice");
|
||||
taintMethod(Array.prototype, "sort");
|
||||
}
|
||||
|
||||
|
||||
// auxiliary data for getLocaleSupportInfo
|
||||
var languages = ["zh", "es", "en", "hi", "ur", "ar", "ja", "pa"];
|
||||
var scripts = ["Latn", "Hans", "Deva", "Arab", "Jpan", "Hant"];
|
||||
var countries = ["CN", "IN", "US", "PK", "JP", "TW", "HK", "SG"];
|
||||
var localeSupportInfo = {};
|
||||
|
||||
|
||||
/**
|
||||
* Gets locale support info for the given constructor object, which must be one
|
||||
* of Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat.
|
||||
* @param {object} Constructor the constructor for which to get locale support info
|
||||
* @return {object} locale support info with the following properties:
|
||||
* supported: array of fully supported language tags
|
||||
* byFallback: array of language tags that are supported through fallbacks
|
||||
* unsupported: array of unsupported language tags
|
||||
*/
|
||||
function getLocaleSupportInfo(Constructor) {
|
||||
var constructorName = getConstructorName(Constructor);
|
||||
if (localeSupportInfo[constructorName] !== undefined) {
|
||||
return localeSupportInfo[constructorName];
|
||||
}
|
||||
|
||||
var allTags = [];
|
||||
var i, j, k;
|
||||
var language, script, country;
|
||||
for (i = 0; i < languages.length; i++) {
|
||||
language = languages[i];
|
||||
allTags.push(language);
|
||||
for (j = 0; j < scripts.length; j++) {
|
||||
script = scripts[j];
|
||||
allTags.push(language + "-" + script);
|
||||
for (k = 0; k < countries.length; k++) {
|
||||
country = countries[k];
|
||||
allTags.push(language + "-" + script + "-" + country);
|
||||
}
|
||||
}
|
||||
for (k = 0; k < countries.length; k++) {
|
||||
country = countries[k];
|
||||
allTags.push(language + "-" + country);
|
||||
}
|
||||
}
|
||||
|
||||
var supported = [];
|
||||
var byFallback = [];
|
||||
var unsupported = [];
|
||||
for (i = 0; i < allTags.length; i++) {
|
||||
var request = allTags[i];
|
||||
var result = new Constructor([request], {localeMatcher: "lookup"}).resolvedOptions().locale;
|
||||
if (request === result) {
|
||||
supported.push(request);
|
||||
} else if (request.indexOf(result) === 0) {
|
||||
byFallback.push(request);
|
||||
} else {
|
||||
unsupported.push(request);
|
||||
}
|
||||
}
|
||||
|
||||
localeSupportInfo[constructorName] = {
|
||||
supported: supported,
|
||||
byFallback: byFallback,
|
||||
unsupported: unsupported
|
||||
};
|
||||
|
||||
return localeSupportInfo[constructorName];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description Tests whether locale is a String value representing a
|
||||
* structurally valid and canonicalized BCP 47 language tag, as defined in
|
||||
* sections 6.2.2 and 6.2.3 of the ECMAScript Internationalization API
|
||||
* Specification.
|
||||
* @param {String} locale the string to be tested.
|
||||
* @result {Boolean} whether the test succeeded.
|
||||
*/
|
||||
function isCanonicalizedStructurallyValidLanguageTag(locale) {
|
||||
|
||||
/**
|
||||
* Regular expression defining BCP 47 language tags.
|
||||
*
|
||||
* Spec: RFC 5646 section 2.1.
|
||||
*/
|
||||
var alpha = "[a-zA-Z]",
|
||||
digit = "[0-9]",
|
||||
alphanum = "(" + alpha + "|" + digit + ")",
|
||||
regular = "(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang)",
|
||||
irregular = "(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)",
|
||||
grandfathered = "(" + irregular + "|" + regular + ")",
|
||||
privateuse = "(x(-[a-z0-9]{1,8})+)",
|
||||
singleton = "(" + digit + "|[A-WY-Za-wy-z])",
|
||||
extension = "(" + singleton + "(-" + alphanum + "{2,8})+)",
|
||||
variant = "(" + alphanum + "{5,8}|(" + digit + alphanum + "{3}))",
|
||||
region = "(" + alpha + "{2}|" + digit + "{3})",
|
||||
script = "(" + alpha + "{4})",
|
||||
extlang = "(" + alpha + "{3}(-" + alpha + "{3}){0,2})",
|
||||
language = "(" + alpha + "{2,3}(-" + extlang + ")?|" + alpha + "{4}|" + alpha + "{5,8})",
|
||||
langtag = language + "(-" + script + ")?(-" + region + ")?(-" + variant + ")*(-" + extension + ")*(-" + privateuse + ")?",
|
||||
languageTag = "^(" + langtag + "|" + privateuse + "|" + grandfathered + ")$",
|
||||
languageTagRE = new RegExp(languageTag, "i");
|
||||
var duplicateSingleton = "-" + singleton + "-(.*-)?\\1(?!" + alphanum + ")",
|
||||
duplicateSingletonRE = new RegExp(duplicateSingleton, "i"),
|
||||
duplicateVariant = "(" + alphanum + "{2,8}-)+" + variant + "-(" + alphanum + "{2,8}-)*\\3(?!" + alphanum + ")",
|
||||
duplicateVariantRE = new RegExp(duplicateVariant, "i");
|
||||
|
||||
|
||||
/**
|
||||
* Verifies that the given string is a well-formed BCP 47 language tag
|
||||
* with no duplicate variant or singleton subtags.
|
||||
*
|
||||
* Spec: ECMAScript Internationalization API Specification, draft, 6.2.2.
|
||||
*/
|
||||
function isStructurallyValidLanguageTag(locale) {
|
||||
if (!languageTagRE.test(locale)) {
|
||||
return false;
|
||||
}
|
||||
locale = locale.split(/-x-/)[0];
|
||||
return !duplicateSingletonRE.test(locale) && !duplicateVariantRE.test(locale);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Mappings from complete tags to preferred values.
|
||||
*
|
||||
* Spec: IANA Language Subtag Registry.
|
||||
*/
|
||||
var __tagMappings = {
|
||||
// property names must be in lower case; values in canonical form
|
||||
|
||||
// grandfathered tags from IANA language subtag registry, file date 2011-08-25
|
||||
"art-lojban": "jbo",
|
||||
"cel-gaulish": "cel-gaulish",
|
||||
"en-gb-oed": "en-GB-oed",
|
||||
"i-ami": "ami",
|
||||
"i-bnn": "bnn",
|
||||
"i-default": "i-default",
|
||||
"i-enochian": "i-enochian",
|
||||
"i-hak": "hak",
|
||||
"i-klingon": "tlh",
|
||||
"i-lux": "lb",
|
||||
"i-mingo": "i-mingo",
|
||||
"i-navajo": "nv",
|
||||
"i-pwn": "pwn",
|
||||
"i-tao": "tao",
|
||||
"i-tay": "tay",
|
||||
"i-tsu": "tsu",
|
||||
"no-bok": "nb",
|
||||
"no-nyn": "nn",
|
||||
"sgn-be-fr": "sfb",
|
||||
"sgn-be-nl": "vgt",
|
||||
"sgn-ch-de": "sgg",
|
||||
"zh-guoyu": "cmn",
|
||||
"zh-hakka": "hak",
|
||||
"zh-min": "zh-min",
|
||||
"zh-min-nan": "nan",
|
||||
"zh-xiang": "hsn",
|
||||
// deprecated redundant tags from IANA language subtag registry, file date 2011-08-25
|
||||
"sgn-br": "bzs",
|
||||
"sgn-co": "csn",
|
||||
"sgn-de": "gsg",
|
||||
"sgn-dk": "dsl",
|
||||
"sgn-es": "ssp",
|
||||
"sgn-fr": "fsl",
|
||||
"sgn-gb": "bfi",
|
||||
"sgn-gr": "gss",
|
||||
"sgn-ie": "isg",
|
||||
"sgn-it": "ise",
|
||||
"sgn-jp": "jsl",
|
||||
"sgn-mx": "mfs",
|
||||
"sgn-ni": "ncs",
|
||||
"sgn-nl": "dse",
|
||||
"sgn-no": "nsl",
|
||||
"sgn-pt": "psr",
|
||||
"sgn-se": "swl",
|
||||
"sgn-us": "ase",
|
||||
"sgn-za": "sfs",
|
||||
"zh-cmn": "cmn",
|
||||
"zh-cmn-hans": "cmn-Hans",
|
||||
"zh-cmn-hant": "cmn-Hant",
|
||||
"zh-gan": "gan",
|
||||
"zh-wuu": "wuu",
|
||||
"zh-yue": "yue",
|
||||
// deprecated variant with prefix from IANA language subtag registry, file date 2011-08-25
|
||||
"ja-latn-hepburn-heploc": "ja-Latn-alalc97"
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Mappings from non-extlang subtags to preferred values.
|
||||
*
|
||||
* Spec: IANA Language Subtag Registry.
|
||||
*/
|
||||
var __subtagMappings = {
|
||||
// property names and values must be in canonical case
|
||||
// language subtags with Preferred-Value mappings from IANA language subtag registry, file date 2011-08-25
|
||||
"in": "id",
|
||||
"iw": "he",
|
||||
"ji": "yi",
|
||||
"jw": "jv",
|
||||
"mo": "ro",
|
||||
"ayx": "nun",
|
||||
"cjr": "mom",
|
||||
"cmk": "xch",
|
||||
"drh": "khk",
|
||||
"drw": "prs",
|
||||
"gav": "dev",
|
||||
"mst": "mry",
|
||||
"myt": "mry",
|
||||
"tie": "ras",
|
||||
"tkk": "twm",
|
||||
"tnf": "prs",
|
||||
// region subtags with Preferred-Value mappings from IANA language subtag registry, file date 2011-08-25
|
||||
"BU": "MM",
|
||||
"DD": "DE",
|
||||
"FX": "FR",
|
||||
"TP": "TL",
|
||||
"YD": "YE",
|
||||
"ZR": "CD"
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Mappings from extlang subtags to preferred values.
|
||||
*
|
||||
* Spec: IANA Language Subtag Registry.
|
||||
*/
|
||||
var __extlangMappings = {
|
||||
// extlang subtags with Preferred-Value mappings from IANA language subtag registry, file date 2011-08-25
|
||||
// values are arrays with [0] the replacement value, [1] (if present) the prefix to be removed
|
||||
"aao": ["aao", "ar"],
|
||||
"abh": ["abh", "ar"],
|
||||
"abv": ["abv", "ar"],
|
||||
"acm": ["acm", "ar"],
|
||||
"acq": ["acq", "ar"],
|
||||
"acw": ["acw", "ar"],
|
||||
"acx": ["acx", "ar"],
|
||||
"acy": ["acy", "ar"],
|
||||
"adf": ["adf", "ar"],
|
||||
"ads": ["ads", "sgn"],
|
||||
"aeb": ["aeb", "ar"],
|
||||
"aec": ["aec", "ar"],
|
||||
"aed": ["aed", "sgn"],
|
||||
"aen": ["aen", "sgn"],
|
||||
"afb": ["afb", "ar"],
|
||||
"afg": ["afg", "sgn"],
|
||||
"ajp": ["ajp", "ar"],
|
||||
"apc": ["apc", "ar"],
|
||||
"apd": ["apd", "ar"],
|
||||
"arb": ["arb", "ar"],
|
||||
"arq": ["arq", "ar"],
|
||||
"ars": ["ars", "ar"],
|
||||
"ary": ["ary", "ar"],
|
||||
"arz": ["arz", "ar"],
|
||||
"ase": ["ase", "sgn"],
|
||||
"asf": ["asf", "sgn"],
|
||||
"asp": ["asp", "sgn"],
|
||||
"asq": ["asq", "sgn"],
|
||||
"asw": ["asw", "sgn"],
|
||||
"auz": ["auz", "ar"],
|
||||
"avl": ["avl", "ar"],
|
||||
"ayh": ["ayh", "ar"],
|
||||
"ayl": ["ayl", "ar"],
|
||||
"ayn": ["ayn", "ar"],
|
||||
"ayp": ["ayp", "ar"],
|
||||
"bbz": ["bbz", "ar"],
|
||||
"bfi": ["bfi", "sgn"],
|
||||
"bfk": ["bfk", "sgn"],
|
||||
"bjn": ["bjn", "ms"],
|
||||
"bog": ["bog", "sgn"],
|
||||
"bqn": ["bqn", "sgn"],
|
||||
"bqy": ["bqy", "sgn"],
|
||||
"btj": ["btj", "ms"],
|
||||
"bve": ["bve", "ms"],
|
||||
"bvl": ["bvl", "sgn"],
|
||||
"bvu": ["bvu", "ms"],
|
||||
"bzs": ["bzs", "sgn"],
|
||||
"cdo": ["cdo", "zh"],
|
||||
"cds": ["cds", "sgn"],
|
||||
"cjy": ["cjy", "zh"],
|
||||
"cmn": ["cmn", "zh"],
|
||||
"coa": ["coa", "ms"],
|
||||
"cpx": ["cpx", "zh"],
|
||||
"csc": ["csc", "sgn"],
|
||||
"csd": ["csd", "sgn"],
|
||||
"cse": ["cse", "sgn"],
|
||||
"csf": ["csf", "sgn"],
|
||||
"csg": ["csg", "sgn"],
|
||||
"csl": ["csl", "sgn"],
|
||||
"csn": ["csn", "sgn"],
|
||||
"csq": ["csq", "sgn"],
|
||||
"csr": ["csr", "sgn"],
|
||||
"czh": ["czh", "zh"],
|
||||
"czo": ["czo", "zh"],
|
||||
"doq": ["doq", "sgn"],
|
||||
"dse": ["dse", "sgn"],
|
||||
"dsl": ["dsl", "sgn"],
|
||||
"dup": ["dup", "ms"],
|
||||
"ecs": ["ecs", "sgn"],
|
||||
"esl": ["esl", "sgn"],
|
||||
"esn": ["esn", "sgn"],
|
||||
"eso": ["eso", "sgn"],
|
||||
"eth": ["eth", "sgn"],
|
||||
"fcs": ["fcs", "sgn"],
|
||||
"fse": ["fse", "sgn"],
|
||||
"fsl": ["fsl", "sgn"],
|
||||
"fss": ["fss", "sgn"],
|
||||
"gan": ["gan", "zh"],
|
||||
"gom": ["gom", "kok"],
|
||||
"gse": ["gse", "sgn"],
|
||||
"gsg": ["gsg", "sgn"],
|
||||
"gsm": ["gsm", "sgn"],
|
||||
"gss": ["gss", "sgn"],
|
||||
"gus": ["gus", "sgn"],
|
||||
"hab": ["hab", "sgn"],
|
||||
"haf": ["haf", "sgn"],
|
||||
"hak": ["hak", "zh"],
|
||||
"hds": ["hds", "sgn"],
|
||||
"hji": ["hji", "ms"],
|
||||
"hks": ["hks", "sgn"],
|
||||
"hos": ["hos", "sgn"],
|
||||
"hps": ["hps", "sgn"],
|
||||
"hsh": ["hsh", "sgn"],
|
||||
"hsl": ["hsl", "sgn"],
|
||||
"hsn": ["hsn", "zh"],
|
||||
"icl": ["icl", "sgn"],
|
||||
"ils": ["ils", "sgn"],
|
||||
"inl": ["inl", "sgn"],
|
||||
"ins": ["ins", "sgn"],
|
||||
"ise": ["ise", "sgn"],
|
||||
"isg": ["isg", "sgn"],
|
||||
"isr": ["isr", "sgn"],
|
||||
"jak": ["jak", "ms"],
|
||||
"jax": ["jax", "ms"],
|
||||
"jcs": ["jcs", "sgn"],
|
||||
"jhs": ["jhs", "sgn"],
|
||||
"jls": ["jls", "sgn"],
|
||||
"jos": ["jos", "sgn"],
|
||||
"jsl": ["jsl", "sgn"],
|
||||
"jus": ["jus", "sgn"],
|
||||
"kgi": ["kgi", "sgn"],
|
||||
"knn": ["knn", "kok"],
|
||||
"kvb": ["kvb", "ms"],
|
||||
"kvk": ["kvk", "sgn"],
|
||||
"kvr": ["kvr", "ms"],
|
||||
"kxd": ["kxd", "ms"],
|
||||
"lbs": ["lbs", "sgn"],
|
||||
"lce": ["lce", "ms"],
|
||||
"lcf": ["lcf", "ms"],
|
||||
"liw": ["liw", "ms"],
|
||||
"lls": ["lls", "sgn"],
|
||||
"lsg": ["lsg", "sgn"],
|
||||
"lsl": ["lsl", "sgn"],
|
||||
"lso": ["lso", "sgn"],
|
||||
"lsp": ["lsp", "sgn"],
|
||||
"lst": ["lst", "sgn"],
|
||||
"lsy": ["lsy", "sgn"],
|
||||
"ltg": ["ltg", "lv"],
|
||||
"lvs": ["lvs", "lv"],
|
||||
"lzh": ["lzh", "zh"],
|
||||
"max": ["max", "ms"],
|
||||
"mdl": ["mdl", "sgn"],
|
||||
"meo": ["meo", "ms"],
|
||||
"mfa": ["mfa", "ms"],
|
||||
"mfb": ["mfb", "ms"],
|
||||
"mfs": ["mfs", "sgn"],
|
||||
"min": ["min", "ms"],
|
||||
"mnp": ["mnp", "zh"],
|
||||
"mqg": ["mqg", "ms"],
|
||||
"mre": ["mre", "sgn"],
|
||||
"msd": ["msd", "sgn"],
|
||||
"msi": ["msi", "ms"],
|
||||
"msr": ["msr", "sgn"],
|
||||
"mui": ["mui", "ms"],
|
||||
"mzc": ["mzc", "sgn"],
|
||||
"mzg": ["mzg", "sgn"],
|
||||
"mzy": ["mzy", "sgn"],
|
||||
"nan": ["nan", "zh"],
|
||||
"nbs": ["nbs", "sgn"],
|
||||
"ncs": ["ncs", "sgn"],
|
||||
"nsi": ["nsi", "sgn"],
|
||||
"nsl": ["nsl", "sgn"],
|
||||
"nsp": ["nsp", "sgn"],
|
||||
"nsr": ["nsr", "sgn"],
|
||||
"nzs": ["nzs", "sgn"],
|
||||
"okl": ["okl", "sgn"],
|
||||
"orn": ["orn", "ms"],
|
||||
"ors": ["ors", "ms"],
|
||||
"pel": ["pel", "ms"],
|
||||
"pga": ["pga", "ar"],
|
||||
"pks": ["pks", "sgn"],
|
||||
"prl": ["prl", "sgn"],
|
||||
"prz": ["prz", "sgn"],
|
||||
"psc": ["psc", "sgn"],
|
||||
"psd": ["psd", "sgn"],
|
||||
"pse": ["pse", "ms"],
|
||||
"psg": ["psg", "sgn"],
|
||||
"psl": ["psl", "sgn"],
|
||||
"pso": ["pso", "sgn"],
|
||||
"psp": ["psp", "sgn"],
|
||||
"psr": ["psr", "sgn"],
|
||||
"pys": ["pys", "sgn"],
|
||||
"rms": ["rms", "sgn"],
|
||||
"rsi": ["rsi", "sgn"],
|
||||
"rsl": ["rsl", "sgn"],
|
||||
"sdl": ["sdl", "sgn"],
|
||||
"sfb": ["sfb", "sgn"],
|
||||
"sfs": ["sfs", "sgn"],
|
||||
"sgg": ["sgg", "sgn"],
|
||||
"sgx": ["sgx", "sgn"],
|
||||
"shu": ["shu", "ar"],
|
||||
"slf": ["slf", "sgn"],
|
||||
"sls": ["sls", "sgn"],
|
||||
"sqs": ["sqs", "sgn"],
|
||||
"ssh": ["ssh", "ar"],
|
||||
"ssp": ["ssp", "sgn"],
|
||||
"ssr": ["ssr", "sgn"],
|
||||
"svk": ["svk", "sgn"],
|
||||
"swc": ["swc", "sw"],
|
||||
"swh": ["swh", "sw"],
|
||||
"swl": ["swl", "sgn"],
|
||||
"syy": ["syy", "sgn"],
|
||||
"tmw": ["tmw", "ms"],
|
||||
"tse": ["tse", "sgn"],
|
||||
"tsm": ["tsm", "sgn"],
|
||||
"tsq": ["tsq", "sgn"],
|
||||
"tss": ["tss", "sgn"],
|
||||
"tsy": ["tsy", "sgn"],
|
||||
"tza": ["tza", "sgn"],
|
||||
"ugn": ["ugn", "sgn"],
|
||||
"ugy": ["ugy", "sgn"],
|
||||
"ukl": ["ukl", "sgn"],
|
||||
"uks": ["uks", "sgn"],
|
||||
"urk": ["urk", "ms"],
|
||||
"uzn": ["uzn", "uz"],
|
||||
"uzs": ["uzs", "uz"],
|
||||
"vgt": ["vgt", "sgn"],
|
||||
"vkk": ["vkk", "ms"],
|
||||
"vkt": ["vkt", "ms"],
|
||||
"vsi": ["vsi", "sgn"],
|
||||
"vsl": ["vsl", "sgn"],
|
||||
"vsv": ["vsv", "sgn"],
|
||||
"wuu": ["wuu", "zh"],
|
||||
"xki": ["xki", "sgn"],
|
||||
"xml": ["xml", "sgn"],
|
||||
"xmm": ["xmm", "ms"],
|
||||
"xms": ["xms", "sgn"],
|
||||
"yds": ["yds", "sgn"],
|
||||
"ysl": ["ysl", "sgn"],
|
||||
"yue": ["yue", "zh"],
|
||||
"zib": ["zib", "sgn"],
|
||||
"zlm": ["zlm", "ms"],
|
||||
"zmi": ["zmi", "ms"],
|
||||
"zsl": ["zsl", "sgn"],
|
||||
"zsm": ["zsm", "ms"]
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Canonicalizes the given well-formed BCP 47 language tag, including regularized case of subtags.
|
||||
*
|
||||
* Spec: ECMAScript Internationalization API Specification, draft, 6.2.3.
|
||||
* Spec: RFC 5646, section 4.5.
|
||||
*/
|
||||
function canonicalizeLanguageTag(locale) {
|
||||
|
||||
// start with lower case for easier processing, and because most subtags will need to be lower case anyway
|
||||
locale = locale.toLowerCase();
|
||||
|
||||
// handle mappings for complete tags
|
||||
if (__tagMappings.hasOwnProperty(locale)) {
|
||||
return __tagMappings[locale];
|
||||
}
|
||||
|
||||
var subtags = locale.split("-");
|
||||
var i = 0;
|
||||
|
||||
// handle standard part: all subtags before first singleton or "x"
|
||||
while (i < subtags.length) {
|
||||
var subtag = subtags[i];
|
||||
if (subtag.length === 1 && (i > 0 || subtag === "x")) {
|
||||
break;
|
||||
} else if (i !== 0 && subtag.length === 2) {
|
||||
subtag = subtag.toUpperCase();
|
||||
} else if (subtag.length === 4) {
|
||||
subtag = subtag[0].toUpperCase() + subtag.substring(1).toLowerCase();
|
||||
}
|
||||
if (__subtagMappings.hasOwnProperty(subtag)) {
|
||||
subtag = __subtagMappings[subtag];
|
||||
} else if (__extlangMappings.hasOwnProperty(subtag)) {
|
||||
subtag = __extlangMappings[subtag][0];
|
||||
if (i === 1 && __extlangMappings[subtag][1] === subtags[0]) {
|
||||
subtags.shift();
|
||||
i--;
|
||||
}
|
||||
}
|
||||
subtags[i] = subtag;
|
||||
i++;
|
||||
}
|
||||
var normal = subtags.slice(0, i).join("-");
|
||||
|
||||
// handle extensions
|
||||
var extensions = [];
|
||||
while (i < subtags.length && subtags[i] !== "x") {
|
||||
var extensionStart = i;
|
||||
i++;
|
||||
while (i < subtags.length && subtags[i].length > 1) {
|
||||
i++;
|
||||
}
|
||||
var extension = subtags.slice(extensionStart, i).join("-");
|
||||
extensions.push(extension);
|
||||
}
|
||||
extensions.sort();
|
||||
|
||||
// handle private use
|
||||
var privateUse;
|
||||
if (i < subtags.length) {
|
||||
privateUse = subtags.slice(i).join("-");
|
||||
}
|
||||
|
||||
// put everything back together
|
||||
var canonical = normal;
|
||||
if (extensions.length > 0) {
|
||||
canonical += "-" + extensions.join("-");
|
||||
}
|
||||
if (privateUse !== undefined) {
|
||||
if (canonical.length > 0) {
|
||||
canonical += "-" + privateUse;
|
||||
} else {
|
||||
canonical = privateUse;
|
||||
}
|
||||
}
|
||||
|
||||
return canonical;
|
||||
}
|
||||
|
||||
return typeof locale === "string" && isStructurallyValidLanguageTag(locale) &&
|
||||
canonicalizeLanguageTag(locale) === locale;
|
||||
}
|
||||
|
|
@ -0,0 +1,658 @@
|
|||
// Copyright 2011-2012 Norbert Lindenberg. All rights reserved.
|
||||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* This file contains shared functions for the tests in the conformance test
|
||||
* suite for the ECMAScript Internationalization API.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @description Calls the provided function for every service constructor in
|
||||
* the Intl object, until f returns a falsy value. It returns the result of the
|
||||
* last call to f, mapped to a boolean.
|
||||
* @param {Function} f the function to call for each service constructor in
|
||||
* the Intl object.
|
||||
* @param {Function} Constructor the constructor object to test with.
|
||||
* @result {Boolean} whether the test succeeded.
|
||||
*/
|
||||
function testWithIntlConstructors(f) {
|
||||
var constructors = ["Collator", "NumberFormat", "DateTimeFormat"];
|
||||
return constructors.every(function (constructor) {
|
||||
var Constructor = Intl[constructor];
|
||||
var result;
|
||||
try {
|
||||
result = f(Constructor);
|
||||
} catch (e) {
|
||||
e.message += " (Testing with " + constructor + ".)";
|
||||
throw e;
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the name of the given constructor object, which must be one of
|
||||
* Intl.Collator, Intl.NumberFormat, or Intl.DateTimeFormat.
|
||||
* @param {object} Constructor a constructor
|
||||
* @return {string} the name of the constructor
|
||||
*/
|
||||
function getConstructorName(Constructor) {
|
||||
switch (Constructor) {
|
||||
case Intl.Collator:
|
||||
return "Collator";
|
||||
case Intl.NumberFormat:
|
||||
return "NumberFormat";
|
||||
case Intl.DateTimeFormat:
|
||||
return "DateTimeFormat";
|
||||
default:
|
||||
$ERROR("test internal error: unknown Constructor");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Taints a named data property of the given object by installing
|
||||
* a setter that throws an exception.
|
||||
* @param {object} obj the object whose data property to taint
|
||||
* @param {string} property the property to taint
|
||||
*/
|
||||
function taintDataProperty(obj, property) {
|
||||
Object.defineProperty(obj, property, {
|
||||
set: function(value) {
|
||||
$ERROR("Client code can adversely affect behavior: setter for " + property + ".");
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Taints a named method of the given object by replacing it with a function
|
||||
* that throws an exception.
|
||||
* @param {object} obj the object whose method to taint
|
||||
* @param {string} property the name of the method to taint
|
||||
*/
|
||||
function taintMethod(obj, property) {
|
||||
Object.defineProperty(obj, property, {
|
||||
value: function() {
|
||||
$ERROR("Client code can adversely affect behavior: method " + property + ".");
|
||||
},
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Taints the given properties (and similarly named properties) by installing
|
||||
* setters on Object.prototype that throw exceptions.
|
||||
* @param {Array} properties an array of property names to taint
|
||||
*/
|
||||
function taintProperties(properties) {
|
||||
properties.forEach(function (property) {
|
||||
var adaptedProperties = [property, "__" + property, "_" + property, property + "_", property + "__"];
|
||||
adaptedProperties.forEach(function (property) {
|
||||
taintDataProperty(Object.prototype, property);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Taints the Array object by creating a setter for the property "0" and
|
||||
* replacing some key methods with functions that throw exceptions.
|
||||
*/
|
||||
function taintArray() {
|
||||
taintDataProperty(Array.prototype, "0");
|
||||
taintMethod(Array.prototype, "indexOf");
|
||||
taintMethod(Array.prototype, "join");
|
||||
taintMethod(Array.prototype, "push");
|
||||
taintMethod(Array.prototype, "slice");
|
||||
taintMethod(Array.prototype, "sort");
|
||||
}
|
||||
|
||||
|
||||
// auxiliary data for getLocaleSupportInfo
|
||||
var languages = ["zh", "es", "en", "hi", "ur", "ar", "ja", "pa"];
|
||||
var scripts = ["Latn", "Hans", "Deva", "Arab", "Jpan", "Hant"];
|
||||
var countries = ["CN", "IN", "US", "PK", "JP", "TW", "HK", "SG"];
|
||||
var localeSupportInfo = {};
|
||||
|
||||
|
||||
/**
|
||||
* Gets locale support info for the given constructor object, which must be one
|
||||
* of Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat.
|
||||
* @param {object} Constructor the constructor for which to get locale support info
|
||||
* @return {object} locale support info with the following properties:
|
||||
* supported: array of fully supported language tags
|
||||
* byFallback: array of language tags that are supported through fallbacks
|
||||
* unsupported: array of unsupported language tags
|
||||
*/
|
||||
function getLocaleSupportInfo(Constructor) {
|
||||
var constructorName = getConstructorName(Constructor);
|
||||
if (localeSupportInfo[constructorName] !== undefined) {
|
||||
return localeSupportInfo[constructorName];
|
||||
}
|
||||
|
||||
var allTags = [];
|
||||
var i, j, k;
|
||||
var language, script, country;
|
||||
for (i = 0; i < languages.length; i++) {
|
||||
language = languages[i];
|
||||
allTags.push(language);
|
||||
for (j = 0; j < scripts.length; j++) {
|
||||
script = scripts[j];
|
||||
allTags.push(language + "-" + script);
|
||||
for (k = 0; k < countries.length; k++) {
|
||||
country = countries[k];
|
||||
allTags.push(language + "-" + script + "-" + country);
|
||||
}
|
||||
}
|
||||
for (k = 0; k < countries.length; k++) {
|
||||
country = countries[k];
|
||||
allTags.push(language + "-" + country);
|
||||
}
|
||||
}
|
||||
|
||||
var supported = [];
|
||||
var byFallback = [];
|
||||
var unsupported = [];
|
||||
for (i = 0; i < allTags.length; i++) {
|
||||
var request = allTags[i];
|
||||
var result = new Constructor([request], {localeMatcher: "lookup"}).resolvedOptions().locale;
|
||||
if (request === result) {
|
||||
supported.push(request);
|
||||
} else if (request.indexOf(result) === 0) {
|
||||
byFallback.push(request);
|
||||
} else {
|
||||
unsupported.push(request);
|
||||
}
|
||||
}
|
||||
|
||||
localeSupportInfo[constructorName] = {
|
||||
supported: supported,
|
||||
byFallback: byFallback,
|
||||
unsupported: unsupported
|
||||
};
|
||||
|
||||
return localeSupportInfo[constructorName];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description Tests whether locale is a String value representing a
|
||||
* structurally valid and canonicalized BCP 47 language tag, as defined in
|
||||
* sections 6.2.2 and 6.2.3 of the ECMAScript Internationalization API
|
||||
* Specification.
|
||||
* @param {String} locale the string to be tested.
|
||||
* @result {Boolean} whether the test succeeded.
|
||||
*/
|
||||
function isCanonicalizedStructurallyValidLanguageTag(locale) {
|
||||
|
||||
/**
|
||||
* Regular expression defining BCP 47 language tags.
|
||||
*
|
||||
* Spec: RFC 5646 section 2.1.
|
||||
*/
|
||||
var alpha = "[a-zA-Z]",
|
||||
digit = "[0-9]",
|
||||
alphanum = "(" + alpha + "|" + digit + ")",
|
||||
regular = "(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang)",
|
||||
irregular = "(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)",
|
||||
grandfathered = "(" + irregular + "|" + regular + ")",
|
||||
privateuse = "(x(-[a-z0-9]{1,8})+)",
|
||||
singleton = "(" + digit + "|[A-WY-Za-wy-z])",
|
||||
extension = "(" + singleton + "(-" + alphanum + "{2,8})+)",
|
||||
variant = "(" + alphanum + "{5,8}|(" + digit + alphanum + "{3}))",
|
||||
region = "(" + alpha + "{2}|" + digit + "{3})",
|
||||
script = "(" + alpha + "{4})",
|
||||
extlang = "(" + alpha + "{3}(-" + alpha + "{3}){0,2})",
|
||||
language = "(" + alpha + "{2,3}(-" + extlang + ")?|" + alpha + "{4}|" + alpha + "{5,8})",
|
||||
langtag = language + "(-" + script + ")?(-" + region + ")?(-" + variant + ")*(-" + extension + ")*(-" + privateuse + ")?",
|
||||
languageTag = "^(" + langtag + "|" + privateuse + "|" + grandfathered + ")$",
|
||||
languageTagRE = new RegExp(languageTag, "i");
|
||||
var duplicateSingleton = "-" + singleton + "-(.*-)?\\1(?!" + alphanum + ")",
|
||||
duplicateSingletonRE = new RegExp(duplicateSingleton, "i"),
|
||||
duplicateVariant = "(" + alphanum + "{2,8}-)+" + variant + "-(" + alphanum + "{2,8}-)*\\3(?!" + alphanum + ")",
|
||||
duplicateVariantRE = new RegExp(duplicateVariant, "i");
|
||||
|
||||
|
||||
/**
|
||||
* Verifies that the given string is a well-formed BCP 47 language tag
|
||||
* with no duplicate variant or singleton subtags.
|
||||
*
|
||||
* Spec: ECMAScript Internationalization API Specification, draft, 6.2.2.
|
||||
*/
|
||||
function isStructurallyValidLanguageTag(locale) {
|
||||
if (!languageTagRE.test(locale)) {
|
||||
return false;
|
||||
}
|
||||
locale = locale.split(/-x-/)[0];
|
||||
return !duplicateSingletonRE.test(locale) && !duplicateVariantRE.test(locale);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Mappings from complete tags to preferred values.
|
||||
*
|
||||
* Spec: IANA Language Subtag Registry.
|
||||
*/
|
||||
var __tagMappings = {
|
||||
// property names must be in lower case; values in canonical form
|
||||
|
||||
// grandfathered tags from IANA language subtag registry, file date 2011-08-25
|
||||
"art-lojban": "jbo",
|
||||
"cel-gaulish": "cel-gaulish",
|
||||
"en-gb-oed": "en-GB-oed",
|
||||
"i-ami": "ami",
|
||||
"i-bnn": "bnn",
|
||||
"i-default": "i-default",
|
||||
"i-enochian": "i-enochian",
|
||||
"i-hak": "hak",
|
||||
"i-klingon": "tlh",
|
||||
"i-lux": "lb",
|
||||
"i-mingo": "i-mingo",
|
||||
"i-navajo": "nv",
|
||||
"i-pwn": "pwn",
|
||||
"i-tao": "tao",
|
||||
"i-tay": "tay",
|
||||
"i-tsu": "tsu",
|
||||
"no-bok": "nb",
|
||||
"no-nyn": "nn",
|
||||
"sgn-be-fr": "sfb",
|
||||
"sgn-be-nl": "vgt",
|
||||
"sgn-ch-de": "sgg",
|
||||
"zh-guoyu": "cmn",
|
||||
"zh-hakka": "hak",
|
||||
"zh-min": "zh-min",
|
||||
"zh-min-nan": "nan",
|
||||
"zh-xiang": "hsn",
|
||||
// deprecated redundant tags from IANA language subtag registry, file date 2011-08-25
|
||||
"sgn-br": "bzs",
|
||||
"sgn-co": "csn",
|
||||
"sgn-de": "gsg",
|
||||
"sgn-dk": "dsl",
|
||||
"sgn-es": "ssp",
|
||||
"sgn-fr": "fsl",
|
||||
"sgn-gb": "bfi",
|
||||
"sgn-gr": "gss",
|
||||
"sgn-ie": "isg",
|
||||
"sgn-it": "ise",
|
||||
"sgn-jp": "jsl",
|
||||
"sgn-mx": "mfs",
|
||||
"sgn-ni": "ncs",
|
||||
"sgn-nl": "dse",
|
||||
"sgn-no": "nsl",
|
||||
"sgn-pt": "psr",
|
||||
"sgn-se": "swl",
|
||||
"sgn-us": "ase",
|
||||
"sgn-za": "sfs",
|
||||
"zh-cmn": "cmn",
|
||||
"zh-cmn-hans": "cmn-Hans",
|
||||
"zh-cmn-hant": "cmn-Hant",
|
||||
"zh-gan": "gan",
|
||||
"zh-wuu": "wuu",
|
||||
"zh-yue": "yue",
|
||||
// deprecated variant with prefix from IANA language subtag registry, file date 2011-08-25
|
||||
"ja-latn-hepburn-heploc": "ja-Latn-alalc97"
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Mappings from non-extlang subtags to preferred values.
|
||||
*
|
||||
* Spec: IANA Language Subtag Registry.
|
||||
*/
|
||||
var __subtagMappings = {
|
||||
// property names and values must be in canonical case
|
||||
// language subtags with Preferred-Value mappings from IANA language subtag registry, file date 2011-08-25
|
||||
"in": "id",
|
||||
"iw": "he",
|
||||
"ji": "yi",
|
||||
"jw": "jv",
|
||||
"mo": "ro",
|
||||
"ayx": "nun",
|
||||
"cjr": "mom",
|
||||
"cmk": "xch",
|
||||
"drh": "khk",
|
||||
"drw": "prs",
|
||||
"gav": "dev",
|
||||
"mst": "mry",
|
||||
"myt": "mry",
|
||||
"tie": "ras",
|
||||
"tkk": "twm",
|
||||
"tnf": "prs",
|
||||
// region subtags with Preferred-Value mappings from IANA language subtag registry, file date 2011-08-25
|
||||
"BU": "MM",
|
||||
"DD": "DE",
|
||||
"FX": "FR",
|
||||
"TP": "TL",
|
||||
"YD": "YE",
|
||||
"ZR": "CD"
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Mappings from extlang subtags to preferred values.
|
||||
*
|
||||
* Spec: IANA Language Subtag Registry.
|
||||
*/
|
||||
var __extlangMappings = {
|
||||
// extlang subtags with Preferred-Value mappings from IANA language subtag registry, file date 2011-08-25
|
||||
// values are arrays with [0] the replacement value, [1] (if present) the prefix to be removed
|
||||
"aao": ["aao", "ar"],
|
||||
"abh": ["abh", "ar"],
|
||||
"abv": ["abv", "ar"],
|
||||
"acm": ["acm", "ar"],
|
||||
"acq": ["acq", "ar"],
|
||||
"acw": ["acw", "ar"],
|
||||
"acx": ["acx", "ar"],
|
||||
"acy": ["acy", "ar"],
|
||||
"adf": ["adf", "ar"],
|
||||
"ads": ["ads", "sgn"],
|
||||
"aeb": ["aeb", "ar"],
|
||||
"aec": ["aec", "ar"],
|
||||
"aed": ["aed", "sgn"],
|
||||
"aen": ["aen", "sgn"],
|
||||
"afb": ["afb", "ar"],
|
||||
"afg": ["afg", "sgn"],
|
||||
"ajp": ["ajp", "ar"],
|
||||
"apc": ["apc", "ar"],
|
||||
"apd": ["apd", "ar"],
|
||||
"arb": ["arb", "ar"],
|
||||
"arq": ["arq", "ar"],
|
||||
"ars": ["ars", "ar"],
|
||||
"ary": ["ary", "ar"],
|
||||
"arz": ["arz", "ar"],
|
||||
"ase": ["ase", "sgn"],
|
||||
"asf": ["asf", "sgn"],
|
||||
"asp": ["asp", "sgn"],
|
||||
"asq": ["asq", "sgn"],
|
||||
"asw": ["asw", "sgn"],
|
||||
"auz": ["auz", "ar"],
|
||||
"avl": ["avl", "ar"],
|
||||
"ayh": ["ayh", "ar"],
|
||||
"ayl": ["ayl", "ar"],
|
||||
"ayn": ["ayn", "ar"],
|
||||
"ayp": ["ayp", "ar"],
|
||||
"bbz": ["bbz", "ar"],
|
||||
"bfi": ["bfi", "sgn"],
|
||||
"bfk": ["bfk", "sgn"],
|
||||
"bjn": ["bjn", "ms"],
|
||||
"bog": ["bog", "sgn"],
|
||||
"bqn": ["bqn", "sgn"],
|
||||
"bqy": ["bqy", "sgn"],
|
||||
"btj": ["btj", "ms"],
|
||||
"bve": ["bve", "ms"],
|
||||
"bvl": ["bvl", "sgn"],
|
||||
"bvu": ["bvu", "ms"],
|
||||
"bzs": ["bzs", "sgn"],
|
||||
"cdo": ["cdo", "zh"],
|
||||
"cds": ["cds", "sgn"],
|
||||
"cjy": ["cjy", "zh"],
|
||||
"cmn": ["cmn", "zh"],
|
||||
"coa": ["coa", "ms"],
|
||||
"cpx": ["cpx", "zh"],
|
||||
"csc": ["csc", "sgn"],
|
||||
"csd": ["csd", "sgn"],
|
||||
"cse": ["cse", "sgn"],
|
||||
"csf": ["csf", "sgn"],
|
||||
"csg": ["csg", "sgn"],
|
||||
"csl": ["csl", "sgn"],
|
||||
"csn": ["csn", "sgn"],
|
||||
"csq": ["csq", "sgn"],
|
||||
"csr": ["csr", "sgn"],
|
||||
"czh": ["czh", "zh"],
|
||||
"czo": ["czo", "zh"],
|
||||
"doq": ["doq", "sgn"],
|
||||
"dse": ["dse", "sgn"],
|
||||
"dsl": ["dsl", "sgn"],
|
||||
"dup": ["dup", "ms"],
|
||||
"ecs": ["ecs", "sgn"],
|
||||
"esl": ["esl", "sgn"],
|
||||
"esn": ["esn", "sgn"],
|
||||
"eso": ["eso", "sgn"],
|
||||
"eth": ["eth", "sgn"],
|
||||
"fcs": ["fcs", "sgn"],
|
||||
"fse": ["fse", "sgn"],
|
||||
"fsl": ["fsl", "sgn"],
|
||||
"fss": ["fss", "sgn"],
|
||||
"gan": ["gan", "zh"],
|
||||
"gom": ["gom", "kok"],
|
||||
"gse": ["gse", "sgn"],
|
||||
"gsg": ["gsg", "sgn"],
|
||||
"gsm": ["gsm", "sgn"],
|
||||
"gss": ["gss", "sgn"],
|
||||
"gus": ["gus", "sgn"],
|
||||
"hab": ["hab", "sgn"],
|
||||
"haf": ["haf", "sgn"],
|
||||
"hak": ["hak", "zh"],
|
||||
"hds": ["hds", "sgn"],
|
||||
"hji": ["hji", "ms"],
|
||||
"hks": ["hks", "sgn"],
|
||||
"hos": ["hos", "sgn"],
|
||||
"hps": ["hps", "sgn"],
|
||||
"hsh": ["hsh", "sgn"],
|
||||
"hsl": ["hsl", "sgn"],
|
||||
"hsn": ["hsn", "zh"],
|
||||
"icl": ["icl", "sgn"],
|
||||
"ils": ["ils", "sgn"],
|
||||
"inl": ["inl", "sgn"],
|
||||
"ins": ["ins", "sgn"],
|
||||
"ise": ["ise", "sgn"],
|
||||
"isg": ["isg", "sgn"],
|
||||
"isr": ["isr", "sgn"],
|
||||
"jak": ["jak", "ms"],
|
||||
"jax": ["jax", "ms"],
|
||||
"jcs": ["jcs", "sgn"],
|
||||
"jhs": ["jhs", "sgn"],
|
||||
"jls": ["jls", "sgn"],
|
||||
"jos": ["jos", "sgn"],
|
||||
"jsl": ["jsl", "sgn"],
|
||||
"jus": ["jus", "sgn"],
|
||||
"kgi": ["kgi", "sgn"],
|
||||
"knn": ["knn", "kok"],
|
||||
"kvb": ["kvb", "ms"],
|
||||
"kvk": ["kvk", "sgn"],
|
||||
"kvr": ["kvr", "ms"],
|
||||
"kxd": ["kxd", "ms"],
|
||||
"lbs": ["lbs", "sgn"],
|
||||
"lce": ["lce", "ms"],
|
||||
"lcf": ["lcf", "ms"],
|
||||
"liw": ["liw", "ms"],
|
||||
"lls": ["lls", "sgn"],
|
||||
"lsg": ["lsg", "sgn"],
|
||||
"lsl": ["lsl", "sgn"],
|
||||
"lso": ["lso", "sgn"],
|
||||
"lsp": ["lsp", "sgn"],
|
||||
"lst": ["lst", "sgn"],
|
||||
"lsy": ["lsy", "sgn"],
|
||||
"ltg": ["ltg", "lv"],
|
||||
"lvs": ["lvs", "lv"],
|
||||
"lzh": ["lzh", "zh"],
|
||||
"max": ["max", "ms"],
|
||||
"mdl": ["mdl", "sgn"],
|
||||
"meo": ["meo", "ms"],
|
||||
"mfa": ["mfa", "ms"],
|
||||
"mfb": ["mfb", "ms"],
|
||||
"mfs": ["mfs", "sgn"],
|
||||
"min": ["min", "ms"],
|
||||
"mnp": ["mnp", "zh"],
|
||||
"mqg": ["mqg", "ms"],
|
||||
"mre": ["mre", "sgn"],
|
||||
"msd": ["msd", "sgn"],
|
||||
"msi": ["msi", "ms"],
|
||||
"msr": ["msr", "sgn"],
|
||||
"mui": ["mui", "ms"],
|
||||
"mzc": ["mzc", "sgn"],
|
||||
"mzg": ["mzg", "sgn"],
|
||||
"mzy": ["mzy", "sgn"],
|
||||
"nan": ["nan", "zh"],
|
||||
"nbs": ["nbs", "sgn"],
|
||||
"ncs": ["ncs", "sgn"],
|
||||
"nsi": ["nsi", "sgn"],
|
||||
"nsl": ["nsl", "sgn"],
|
||||
"nsp": ["nsp", "sgn"],
|
||||
"nsr": ["nsr", "sgn"],
|
||||
"nzs": ["nzs", "sgn"],
|
||||
"okl": ["okl", "sgn"],
|
||||
"orn": ["orn", "ms"],
|
||||
"ors": ["ors", "ms"],
|
||||
"pel": ["pel", "ms"],
|
||||
"pga": ["pga", "ar"],
|
||||
"pks": ["pks", "sgn"],
|
||||
"prl": ["prl", "sgn"],
|
||||
"prz": ["prz", "sgn"],
|
||||
"psc": ["psc", "sgn"],
|
||||
"psd": ["psd", "sgn"],
|
||||
"pse": ["pse", "ms"],
|
||||
"psg": ["psg", "sgn"],
|
||||
"psl": ["psl", "sgn"],
|
||||
"pso": ["pso", "sgn"],
|
||||
"psp": ["psp", "sgn"],
|
||||
"psr": ["psr", "sgn"],
|
||||
"pys": ["pys", "sgn"],
|
||||
"rms": ["rms", "sgn"],
|
||||
"rsi": ["rsi", "sgn"],
|
||||
"rsl": ["rsl", "sgn"],
|
||||
"sdl": ["sdl", "sgn"],
|
||||
"sfb": ["sfb", "sgn"],
|
||||
"sfs": ["sfs", "sgn"],
|
||||
"sgg": ["sgg", "sgn"],
|
||||
"sgx": ["sgx", "sgn"],
|
||||
"shu": ["shu", "ar"],
|
||||
"slf": ["slf", "sgn"],
|
||||
"sls": ["sls", "sgn"],
|
||||
"sqs": ["sqs", "sgn"],
|
||||
"ssh": ["ssh", "ar"],
|
||||
"ssp": ["ssp", "sgn"],
|
||||
"ssr": ["ssr", "sgn"],
|
||||
"svk": ["svk", "sgn"],
|
||||
"swc": ["swc", "sw"],
|
||||
"swh": ["swh", "sw"],
|
||||
"swl": ["swl", "sgn"],
|
||||
"syy": ["syy", "sgn"],
|
||||
"tmw": ["tmw", "ms"],
|
||||
"tse": ["tse", "sgn"],
|
||||
"tsm": ["tsm", "sgn"],
|
||||
"tsq": ["tsq", "sgn"],
|
||||
"tss": ["tss", "sgn"],
|
||||
"tsy": ["tsy", "sgn"],
|
||||
"tza": ["tza", "sgn"],
|
||||
"ugn": ["ugn", "sgn"],
|
||||
"ugy": ["ugy", "sgn"],
|
||||
"ukl": ["ukl", "sgn"],
|
||||
"uks": ["uks", "sgn"],
|
||||
"urk": ["urk", "ms"],
|
||||
"uzn": ["uzn", "uz"],
|
||||
"uzs": ["uzs", "uz"],
|
||||
"vgt": ["vgt", "sgn"],
|
||||
"vkk": ["vkk", "ms"],
|
||||
"vkt": ["vkt", "ms"],
|
||||
"vsi": ["vsi", "sgn"],
|
||||
"vsl": ["vsl", "sgn"],
|
||||
"vsv": ["vsv", "sgn"],
|
||||
"wuu": ["wuu", "zh"],
|
||||
"xki": ["xki", "sgn"],
|
||||
"xml": ["xml", "sgn"],
|
||||
"xmm": ["xmm", "ms"],
|
||||
"xms": ["xms", "sgn"],
|
||||
"yds": ["yds", "sgn"],
|
||||
"ysl": ["ysl", "sgn"],
|
||||
"yue": ["yue", "zh"],
|
||||
"zib": ["zib", "sgn"],
|
||||
"zlm": ["zlm", "ms"],
|
||||
"zmi": ["zmi", "ms"],
|
||||
"zsl": ["zsl", "sgn"],
|
||||
"zsm": ["zsm", "ms"]
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Canonicalizes the given well-formed BCP 47 language tag, including regularized case of subtags.
|
||||
*
|
||||
* Spec: ECMAScript Internationalization API Specification, draft, 6.2.3.
|
||||
* Spec: RFC 5646, section 4.5.
|
||||
*/
|
||||
function canonicalizeLanguageTag(locale) {
|
||||
|
||||
// start with lower case for easier processing, and because most subtags will need to be lower case anyway
|
||||
locale = locale.toLowerCase();
|
||||
|
||||
// handle mappings for complete tags
|
||||
if (__tagMappings.hasOwnProperty(locale)) {
|
||||
return __tagMappings[locale];
|
||||
}
|
||||
|
||||
var subtags = locale.split("-");
|
||||
var i = 0;
|
||||
|
||||
// handle standard part: all subtags before first singleton or "x"
|
||||
while (i < subtags.length) {
|
||||
var subtag = subtags[i];
|
||||
if (subtag.length === 1 && (i > 0 || subtag === "x")) {
|
||||
break;
|
||||
} else if (i !== 0 && subtag.length === 2) {
|
||||
subtag = subtag.toUpperCase();
|
||||
} else if (subtag.length === 4) {
|
||||
subtag = subtag[0].toUpperCase() + subtag.substring(1).toLowerCase();
|
||||
}
|
||||
if (__subtagMappings.hasOwnProperty(subtag)) {
|
||||
subtag = __subtagMappings[subtag];
|
||||
} else if (__extlangMappings.hasOwnProperty(subtag)) {
|
||||
subtag = __extlangMappings[subtag][0];
|
||||
if (i === 1 && __extlangMappings[subtag][1] === subtags[0]) {
|
||||
subtags.shift();
|
||||
i--;
|
||||
}
|
||||
}
|
||||
subtags[i] = subtag;
|
||||
i++;
|
||||
}
|
||||
var normal = subtags.slice(0, i).join("-");
|
||||
|
||||
// handle extensions
|
||||
var extensions = [];
|
||||
while (i < subtags.length && subtags[i] !== "x") {
|
||||
var extensionStart = i;
|
||||
i++;
|
||||
while (i < subtags.length && subtags[i].length > 1) {
|
||||
i++;
|
||||
}
|
||||
var extension = subtags.slice(extensionStart, i).join("-");
|
||||
extensions.push(extension);
|
||||
}
|
||||
extensions.sort();
|
||||
|
||||
// handle private use
|
||||
var privateUse;
|
||||
if (i < subtags.length) {
|
||||
privateUse = subtags.slice(i).join("-");
|
||||
}
|
||||
|
||||
// put everything back together
|
||||
var canonical = normal;
|
||||
if (extensions.length > 0) {
|
||||
canonical += "-" + extensions.join("-");
|
||||
}
|
||||
if (privateUse !== undefined) {
|
||||
if (canonical.length > 0) {
|
||||
canonical += "-" + privateUse;
|
||||
} else {
|
||||
canonical = privateUse;
|
||||
}
|
||||
}
|
||||
|
||||
return canonical;
|
||||
}
|
||||
|
||||
return typeof locale === "string" && isStructurallyValidLanguageTag(locale) &&
|
||||
canonicalizeLanguageTag(locale) === locale;
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that structurally valid language tags are accepted.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
$INCLUDE("testIntl.js");
|
||||
|
||||
var validLanguageTags = [
|
||||
"de", // ISO 639 language code
|
||||
"de-DE", // + ISO 3166-1 country code
|
||||
"DE-de", // tags are case-insensitive
|
||||
"cmn", // ISO 639 language code
|
||||
"cmn-Hans", // + script code
|
||||
"CMN-hANS", // tags are case-insensitive
|
||||
"cmn-hans-cn", // + ISO 3166-1 country code
|
||||
"es-419", // + UN M.49 region code
|
||||
"es-419-u-nu-latn-cu-bob", // + Unicode locale extension sequence
|
||||
"i-klingon", // grandfathered tag
|
||||
"cmn-hans-cn-t-ca-u-ca-x-t-u", // singleton subtags can also be used as private use subtags
|
||||
"enochian-enochian", // language and variant subtags may be the same
|
||||
"de-gregory-u-ca-gregory" // variant and extension subtags may be the same
|
||||
];
|
||||
|
||||
testWithIntlConstructors(function (Constructor) {
|
||||
validLanguageTags.forEach(function (tag) {
|
||||
// this must not throw an exception for a valid language tag
|
||||
var obj = new Constructor([tag]);
|
||||
});
|
||||
return true;
|
||||
});
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that language tags with "_" are not accepted.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
$INCLUDE("testIntl.js");
|
||||
|
||||
var invalidLanguageTags = [
|
||||
"de_DE",
|
||||
"DE_de",
|
||||
"cmn_Hans",
|
||||
"cmn-hans_cn",
|
||||
"es_419",
|
||||
"es-419-u-nu-latn-cu_bob",
|
||||
"i_klingon",
|
||||
"cmn-hans-cn-t-ca-u-ca-x_t-u",
|
||||
"enochian_enochian",
|
||||
"de-gregory_u-ca-gregory"
|
||||
];
|
||||
|
||||
testWithIntlConstructors(function (Constructor) {
|
||||
invalidLanguageTags.forEach(function (tag) {
|
||||
var error;
|
||||
try {
|
||||
// this must throw an exception for an invalid language tag
|
||||
var obj = new Constructor([tag]);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
if (error === undefined) {
|
||||
$ERROR("Invalid language tag " + tag + " was not rejected.");
|
||||
} else if (error.name !== "RangeError") {
|
||||
$ERROR("Invalid language tag " + tag + " was rejected with wrong error " + error.name + ".");
|
||||
}
|
||||
});
|
||||
return true;
|
||||
});
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that language tags with invalid subtag sequences are not accepted.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
$INCLUDE("testIntl.js");
|
||||
|
||||
var invalidLanguageTags = [
|
||||
"", // empty tag
|
||||
"i", // singleton alone
|
||||
"x", // private use without subtag
|
||||
"u", // extension singleton in first place
|
||||
"419", // region code in first place
|
||||
"u-nu-latn-cu-bob", // extension sequence without language
|
||||
"hans-cmn-cn", // "hans" could theoretically be a 4-letter language code,
|
||||
// but those can't be followed by extlang codes.
|
||||
"cmn-hans-cn-u-u", // duplicate singleton
|
||||
"cmn-hans-cn-t-u-ca-u", // duplicate singleton
|
||||
"de-gregory-gregory", // duplicate variant
|
||||
"中文", // non-ASCII letters
|
||||
"en-ß", // non-ASCII letters
|
||||
"ıd" // non-ASCII letters
|
||||
];
|
||||
|
||||
testWithIntlConstructors(function (Constructor) {
|
||||
invalidLanguageTags.forEach(function (tag) {
|
||||
var error;
|
||||
try {
|
||||
// this must throw an exception for an invalid language tag
|
||||
var obj = new Constructor([tag]);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
if (error === undefined) {
|
||||
$ERROR("Invalid language tag " + tag + " was not rejected.");
|
||||
} else if (error.name !== "RangeError") {
|
||||
$ERROR("Invalid language tag " + tag + " was rejected with wrong error " + error.name + ".");
|
||||
}
|
||||
});
|
||||
return true;
|
||||
});
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright 2011-2012 Norbert Lindenberg. All rights reserved.
|
||||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that language tags are canonicalized in return values.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
$INCLUDE("testIntl.js");
|
||||
|
||||
var canonicalizedTags = {
|
||||
"de": ["de"],
|
||||
"de-DE": ["de-DE", "de"],
|
||||
"DE-de": ["de-DE", "de"],
|
||||
"cmn": ["cmn"],
|
||||
"CMN-hANS": ["cmn-Hans", "cmn"],
|
||||
"cmn-hans-cn": ["cmn-Hans-CN", "cmn-Hans", "cmn"],
|
||||
"es-419": ["es-419", "es"],
|
||||
"es-419-u-nu-latn": ["es-419-u-nu-latn", "es-419", "es", "es-u-nu-latn"],
|
||||
// -u-ca is incomplete, so it will not show up in resolvedOptions().locale
|
||||
"cmn-hans-cn-u-ca-t-ca-x-t-u": ["cmn-Hans-CN-t-ca-u-ca-x-t-u", "cmn-Hans-CN-t-ca-x-t-u", "cmn-Hans-CN-t-ca-x-t", "cmn-Hans-CN-t-ca", "cmn-Hans-CN", "cmn-Hans", "cmn"],
|
||||
"enochian-enochian": ["enochian-enochian", "enochian"],
|
||||
"de-gregory-u-ca-gregory": ["de-gregory-u-ca-gregory", "de-gregory", "de-u-ca-gregory", "de"],
|
||||
"no-nyn": ["nn"],
|
||||
"i-klingon": ["tlh"],
|
||||
"sgn-GR": ["gss"],
|
||||
"ji": ["yi"],
|
||||
"de-DD": ["de-DE", "de"],
|
||||
"zh-hak-CN": ["hak-CN", "hak"],
|
||||
"sgn-ils": ["ils"],
|
||||
"in": ["id"]
|
||||
};
|
||||
|
||||
// make sure the data above is correct
|
||||
Object.getOwnPropertyNames(canonicalizedTags).forEach(function (tag) {
|
||||
canonicalizedTags[tag].forEach(function (canonicalTag) {
|
||||
if (!isCanonicalizedStructurallyValidLanguageTag(canonicalTag)) {
|
||||
$ERROR("Test data \"" + canonicalTag + "\" is not canonicalized and structurally valid language tag.");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// now the actual test
|
||||
testWithIntlConstructors(function (Constructor) {
|
||||
var defaultLocale = new Constructor().resolvedOptions().locale;
|
||||
Object.getOwnPropertyNames(canonicalizedTags).forEach(function (tag) {
|
||||
// use lookup locale matcher to keep the set of possible return values predictable
|
||||
|
||||
// Variant 1: construct an object and see whether its locale is canonicalized.
|
||||
// In this variant, shortened forms or the default locale may be returned
|
||||
var object = new Constructor([tag], {localeMatcher: "lookup"});
|
||||
var locale = object.resolvedOptions().locale;
|
||||
if (canonicalizedTags[tag].indexOf(locale) === -1 && locale !== defaultLocale) {
|
||||
$ERROR("For " + tag + " got " + locale + "; expected one of " +
|
||||
canonicalizedTags[tag].join(", ") + ".");
|
||||
}
|
||||
|
||||
// Variant 2: get the supported locales. If the tag is supported, it should be returned canonicalized but unshortened
|
||||
var supported = Constructor.supportedLocalesOf([tag]);
|
||||
if (supported.length > 0 && supported[0] !== canonicalizedTags[tag][0]) {
|
||||
$ERROR("For " + tag + " got " + supported[0] + "; expected " +
|
||||
canonicalizedTags[tag][0] + ".");
|
||||
}
|
||||
});
|
||||
return true;
|
||||
});
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that the default locale is a String value representing the
|
||||
* structurally valid and canonicalized BCP 47 language tag.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
$INCLUDE("testIntl.js");
|
||||
|
||||
testWithIntlConstructors(function (Constructor) {
|
||||
var defaultLocale = new Constructor().resolvedOptions().locale;
|
||||
if (!isCanonicalizedStructurallyValidLanguageTag(defaultLocale)) {
|
||||
$ERROR("Default locale \"" + defaultLocale + "\" is not canonicalized and structurally valid language tag.");
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that well-formed currency codes are accepted.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
var wellFormedCurrencyCodes = [
|
||||
"BOB",
|
||||
"EUR",
|
||||
"usd", // currency codes are case-insensitive
|
||||
"XdR",
|
||||
"xTs"
|
||||
];
|
||||
|
||||
wellFormedCurrencyCodes.forEach(function (code) {
|
||||
// this must not throw an exception for a valid currency code
|
||||
var format = new Intl.NumberFormat(["de-de"], {style: "currency", currency: code});
|
||||
if (format.resolvedOptions().currency !== code.toUpperCase()) {
|
||||
$ERROR("Currency " + code + " was not correctly accepted; turned into " +
|
||||
format.resolvedOptions().currency + ".");
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that invalid currency codes are not accepted.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
var invalidCurrencyCodes = [
|
||||
"€",
|
||||
"$",
|
||||
"SFr.",
|
||||
"DM",
|
||||
"KR₩",
|
||||
"702",
|
||||
"ßP",
|
||||
"ınr"
|
||||
];
|
||||
|
||||
invalidCurrencyCodes.forEach(function (code) {
|
||||
var error;
|
||||
try {
|
||||
// this must throw an exception for an invalid currency code
|
||||
var format = new Intl.NumberFormat(["de-de"], {style: "currency", currency: code});
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
if (error === undefined) {
|
||||
$ERROR("Invalid currency code " + code + " was not rejected.");
|
||||
} else if (error.name !== "RangeError") {
|
||||
$ERROR("Invalid currency code " + code + " was rejected with wrong error " + error.name + ".");
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that valid time zone names are accepted.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
var validTimeZoneNames = [
|
||||
"UTC",
|
||||
"utc" // time zone names are case-insensitive
|
||||
];
|
||||
|
||||
validTimeZoneNames.forEach(function (name) {
|
||||
// this must not throw an exception for a valid time zone name
|
||||
var format = new Intl.DateTimeFormat(["de-de"], {timeZone: name});
|
||||
if (format.resolvedOptions().timeZone !== name.toUpperCase()) {
|
||||
$ERROR("Time zone name " + name + " was not correctly accepted; turned into " +
|
||||
format.resolvedOptions().timeZone + ".");
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that invalid time zone names are not accepted.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
var invalidTimeZoneNames = [
|
||||
"",
|
||||
"MEZ", // localized abbreviation
|
||||
"Pacific Time", // localized long form
|
||||
"cnsha", // BCP 47 time zone code
|
||||
"invalid", // as the name says
|
||||
"Europe/İstanbul", // non-ASCII letter
|
||||
"asıa/baku", // non-ASCII letter
|
||||
"europe/brußels" // non-ASCII letter
|
||||
];
|
||||
|
||||
invalidTimeZoneNames.forEach(function (name) {
|
||||
var error;
|
||||
try {
|
||||
// this must throw an exception for an invalid time zone name
|
||||
var format = new Intl.DateTimeFormat(["de-de"], {timeZone: name});
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
if (error === undefined) {
|
||||
$ERROR("Invalid time zone name " + name + " was not rejected.");
|
||||
} else if (error.name !== "RangeError") {
|
||||
$ERROR("Invalid time zone name " + name + " was rejected with wrong error " + error.name + ".");
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that additional time zone names, if accepted, are handled correctly.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
// canonicalization specified in conformance clause
|
||||
var additionalTimeZoneNames = {
|
||||
"Etc/GMT": "UTC",
|
||||
"Greenwich": "UTC",
|
||||
"PRC": "Asia/Shanghai",
|
||||
"AmErIcA/LoS_aNgElEs": "America/Los_Angeles",
|
||||
"etc/gmt+7": "Etc/GMT+7"
|
||||
};
|
||||
|
||||
Object.getOwnPropertyNames(additionalTimeZoneNames).forEach(function (name) {
|
||||
var format, error;
|
||||
try {
|
||||
format = new Intl.DateTimeFormat([], {timeZone: name});
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
if (error === undefined) {
|
||||
var actual = format.resolvedOptions().timeZone;
|
||||
var expected = additionalTimeZoneNames.name;
|
||||
if (actual !== expected) {
|
||||
$ERROR("Time zone name " + name + " was accepted, but incorrectly canonicalized to " +
|
||||
actual + "; expected " + expected + ".");
|
||||
}
|
||||
} else if (error.name !== "RangeError") {
|
||||
$ERROR("Time zone name " + name + " was rejected with wrong error " + error.name + ".");
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that default locale is available.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
$INCLUDE("testIntl.js");
|
||||
|
||||
testWithIntlConstructors(function (Constructor) {
|
||||
var defaultLocale = new Constructor().resolvedOptions().locale;
|
||||
var supportedLocales = Constructor.supportedLocalesOf([defaultLocale]);
|
||||
if (supportedLocales.indexOf(defaultLocale) === -1) {
|
||||
$ERROR("Default locale is not reported as available.");
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that appropriate fallback locales are provided for
|
||||
* supported locales.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
$INCLUDE("testIntl.js");
|
||||
|
||||
testWithIntlConstructors(function (Constructor) {
|
||||
var info = getLocaleSupportInfo(Constructor);
|
||||
var fallback;
|
||||
info.supported.forEach(function (locale) {
|
||||
var pos = locale.lastIndexOf("-");
|
||||
if (pos !== -1) {
|
||||
fallback = locale.substring(0, pos);
|
||||
if (info.supported.indexOf(fallback) === -1) {
|
||||
$ERROR("Locale " + locale + " is supported, but fallback " + fallback + " isn't.");
|
||||
}
|
||||
}
|
||||
var match = /([a-z]{2,3})(-[A-Z][a-z]{3})(-[A-Z]{2})/.exec(locale);
|
||||
if (match !== null) {
|
||||
fallback = match[1] + match[3];
|
||||
if (info.supported.indexOf(fallback) === -1) {
|
||||
$ERROR("Locale " + locale + " is supported, but fallback " + fallback + " isn't.");
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that canonicalization of locale lists treats undefined and empty lists the same.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
$INCLUDE("testIntl.js");
|
||||
|
||||
testWithIntlConstructors(function (Constructor) {
|
||||
var supportedForUndefined = Constructor.supportedLocalesOf(undefined);
|
||||
var supportedForEmptyList = Constructor.supportedLocalesOf([]);
|
||||
if (supportedForUndefined.length !== supportedForEmptyList.length) {
|
||||
$ERROR("Supported locales differ between undefined and empty list input.");
|
||||
}
|
||||
// we don't compare the elements because length should be 0 - let's just verify that
|
||||
if (supportedForUndefined.length !== 0) {
|
||||
$ERROR("Internal test error: Assumption about length being 0 is invalid.");
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that the behavior of a List is not affected by adversarial
|
||||
* changes to Array.prototype.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
$INCLUDE("testIntl.js");
|
||||
|
||||
taintArray();
|
||||
|
||||
testWithIntlConstructors(function (Constructor) {
|
||||
var defaultLocale = new Constructor().resolvedOptions().locale;
|
||||
var canonicalized = Constructor.supportedLocalesOf([defaultLocale, defaultLocale]);
|
||||
if (canonicalized.length > 1) {
|
||||
$ERROR("Canonicalization didn't remove duplicate language tags from locale list.");
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that a single string instead of a locale list is treated
|
||||
* as the locale list containing that string.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
$INCLUDE("testIntl.js");
|
||||
|
||||
var validAndInvalidLanguageTags = [
|
||||
"de", // ISO 639 language code
|
||||
"de-DE", // + ISO 3166-1 country code
|
||||
"DE-de", // tags are case-insensitive
|
||||
"cmn", // ISO 639 language code
|
||||
"cmn-Hans", // + script code
|
||||
"CMN-hANS", // tags are case-insensitive
|
||||
"cmn-hans-cn", // + ISO 3166-1 country code
|
||||
"es-419", // + UN M.49 region code
|
||||
"es-419-u-nu-latn-cu-bob", // + Unicode locale extension sequence
|
||||
"i-klingon", // grandfathered tag
|
||||
"cmn-hans-cn-t-ca-u-ca-x-t-u", // singleton subtags can also be used as private use subtags
|
||||
"enochian-enochian", // language and variant subtags may be the same
|
||||
"de-gregory-u-ca-gregory", // variant and extension subtags may be the same
|
||||
"de_DE",
|
||||
"DE_de",
|
||||
"cmn_Hans",
|
||||
"cmn-hans_cn",
|
||||
"es_419",
|
||||
"es-419-u-nu-latn-cu_bob",
|
||||
"i_klingon",
|
||||
"cmn-hans-cn-t-ca-u-ca-x_t-u",
|
||||
"enochian_enochian",
|
||||
"de-gregory_u-ca-gregory",
|
||||
"i", // singleton alone
|
||||
"x", // private use without subtag
|
||||
"u", // extension singleton in first place
|
||||
"419", // region code in first place
|
||||
"u-nu-latn-cu-bob", // extension sequence without language
|
||||
"hans-cmn-cn", // "hans" could theoretically be a 4-letter language code,
|
||||
// but those can't be followed by extlang codes.
|
||||
"cmn-hans-cn-u-u", // duplicate singleton
|
||||
"cmn-hans-cn-t-u-ca-u", // duplicate singleton
|
||||
"de-gregory-gregory" // duplicate variant
|
||||
];
|
||||
|
||||
testWithIntlConstructors(function (Constructor) {
|
||||
validAndInvalidLanguageTags.forEach(function (locale) {
|
||||
var obj1, obj2, locale1, locale2, error1, error2;
|
||||
try {
|
||||
obj1 = new Constructor(locale);
|
||||
locale1 = obj1.resolvedOptions().locale;
|
||||
} catch (e) {
|
||||
error1 = e;
|
||||
}
|
||||
try {
|
||||
obj2 = new Constructor([locale]);
|
||||
locale2 = obj2.resolvedOptions().locale;
|
||||
} catch (e) {
|
||||
error2 = e;
|
||||
}
|
||||
|
||||
if ((error1 === undefined) !== (error2 === undefined)) {
|
||||
if (error1 === undefined) {
|
||||
$ERROR("Single locale string " + locale +
|
||||
" was accepted, but locale list containing that string wasn't.");
|
||||
} else {
|
||||
$ERROR("Single locale string " + locale +
|
||||
" was rejected, but locale list containing that string wasn't.");
|
||||
}
|
||||
} else if (error1 === undefined) {
|
||||
if (locale1 !== locale2) {
|
||||
$ERROR("Single locale string " + locale + " results in " + locale1 +
|
||||
", but locale list [" + locale + "] results in " + locale2 + ".");
|
||||
}
|
||||
} else {
|
||||
if (error1.name !== error2.name) {
|
||||
$ERROR("Single locale string " + locale + " results in error " + error1.name +
|
||||
", but locale list [" + locale + "] results in error " + error2.name + ".");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
});
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that non-objects are converted to objects before canonicalization.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
$INCLUDE("testIntl.js");
|
||||
|
||||
testWithIntlConstructors(function (Constructor) {
|
||||
// undefined is handled separately
|
||||
|
||||
// null should result in a TypeError
|
||||
var error;
|
||||
try {
|
||||
var supportedForNull = Constructor.supportedLocalesOf(null);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
if (error === undefined) {
|
||||
$ERROR("Null as locale list was not rejected.");
|
||||
} else if (error.name !== "TypeError") {
|
||||
$ERROR("Null as locale list was rejected with wrong error " + error.name + ".");
|
||||
}
|
||||
|
||||
// let's use an empty list for comparison
|
||||
var supportedForEmptyList = Constructor.supportedLocalesOf([]);
|
||||
// we don't compare the elements because length should be 0 - let's just verify that
|
||||
if (supportedForEmptyList.length !== 0) {
|
||||
$ERROR("Internal test error: Assumption about length being 0 is invalid.");
|
||||
}
|
||||
|
||||
// most non-objects will be interpreted as empty lists because a missing length property is interpreted as 0
|
||||
var supportedForNumber = Constructor.supportedLocalesOf(5);
|
||||
if (supportedForNumber.length !== supportedForEmptyList.length) {
|
||||
$ERROR("Supported locales differ between numeric and empty list input.");
|
||||
}
|
||||
var supportedForBoolean = Constructor.supportedLocalesOf(true);
|
||||
if (supportedForBoolean.length !== supportedForEmptyList.length) {
|
||||
$ERROR("Supported locales differ between boolean and empty list input.");
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that values other than strings are not accepted as locales.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
$INCLUDE("testIntl.js");
|
||||
|
||||
var notStringOrObject = [undefined, null, true, false, 0, 5, -5, NaN];
|
||||
|
||||
testWithIntlConstructors(function (Constructor) {
|
||||
notStringOrObject.forEach(function (value) {
|
||||
var error;
|
||||
try {
|
||||
var supported = Constructor.supportedLocalesOf([value]);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
if (error === undefined) {
|
||||
$ERROR("" + value + " as locale was not rejected.");
|
||||
} else if (error.name !== "TypeError") {
|
||||
$ERROR("" + value + " as locale was rejected with wrong error " + error.name + ".");
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
});
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that canonicalization of locale lists removes duplicate language tags.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
$INCLUDE("testIntl.js");
|
||||
|
||||
testWithIntlConstructors(function (Constructor) {
|
||||
var defaultLocale = new Constructor().resolvedOptions().locale;
|
||||
var canonicalized = Constructor.supportedLocalesOf([defaultLocale, defaultLocale]);
|
||||
if (canonicalized.length > 1) {
|
||||
$ERROR("Canonicalization didn't remove duplicate language tags from locale list.");
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that locales that are reported by resolvedOptions
|
||||
* are also reported by supportedLocalesOf.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
$INCLUDE("testIntl.js");
|
||||
|
||||
testWithIntlConstructors(function (Constructor) {
|
||||
var info = getLocaleSupportInfo(Constructor);
|
||||
// this test should work equally for both matching algorithms
|
||||
["lookup", "best fit"].forEach(function (matcher) {
|
||||
var supportedByConstructor = info.supported.concat(info.byFallback);
|
||||
var supported = Constructor.supportedLocalesOf(supportedByConstructor,
|
||||
{localeMatcher: matcher});
|
||||
// we could check the length first, but it's probably more interesting which locales are missing
|
||||
var i = 0;
|
||||
var limit = Math.min(supportedByConstructor.length, supported.length);
|
||||
while (i < limit && supportedByConstructor[i] === supported[i]) {
|
||||
i++;
|
||||
}
|
||||
if (i < supportedByConstructor.length) {
|
||||
$ERROR("Locale " + supportedByConstructor[i] +
|
||||
" is returned by resolvedOptions but not by supportedLocalesOf.");
|
||||
} else if (i < supported.length) {
|
||||
$ERROR("Locale " + supported[i] +
|
||||
" is returned by supportedLocalesOf but not by resolvedOptions.");
|
||||
}
|
||||
});
|
||||
|
||||
// this test is only valid for lookup - best fit may find additional locales supported
|
||||
var unsupportedByConstructor = info.unsupported;
|
||||
var supported = Constructor.supportedLocalesOf(unsupportedByConstructor,
|
||||
{localeMatcher: "lookup"});
|
||||
if (supported.length > 0) {
|
||||
$ERROR("Locale " + supported[0] +
|
||||
" is returned by supportedLocalesOf but not by resolvedOptions.");
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that the behavior of a Record is not affected by adversarial
|
||||
* changes to Object.prototype.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
$INCLUDE("testIntl.js");
|
||||
|
||||
taintProperties(["locale", "extension", "extensionIndex"]);
|
||||
|
||||
testWithIntlConstructors(function (Constructor) {
|
||||
var locale = new Constructor(undefined, {localeMatcher: "lookup"}).resolvedOptions().locale;
|
||||
if (!isCanonicalizedStructurallyValidLanguageTag(locale)) {
|
||||
$ERROR("Constructor returns invalid locale " + locale + ".");
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2011-2012 Norbert Lindenberg. All rights reserved.
|
||||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that missing Unicode extension values default to true for
|
||||
* boolean keys.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
var extensions = ["-u-co-phonebk-kn", "-u-kn-co-phonebk"];
|
||||
extensions.forEach(function (extension) {
|
||||
var defaultLocale = new Intl.Collator().resolvedOptions().locale;
|
||||
var collator = new Intl.Collator([defaultLocale + extension], {usage: "sort"});
|
||||
var locale = collator.resolvedOptions().locale;
|
||||
var numeric = collator.resolvedOptions().numeric;
|
||||
if (numeric !== undefined) {
|
||||
if (numeric !== true) {
|
||||
$ERROR("Default value for \"kn\" should be true, but is " + numeric + ".");
|
||||
}
|
||||
if (locale.indexOf("-kn") !== -1) {
|
||||
$ERROR("\"kn\" is returned in locale, but shouldn't be.");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that the behavior of a Record is not affected by adversarial
|
||||
* changes to Object.prototype.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
$INCLUDE("testIntl.js");
|
||||
|
||||
taintProperties(["dataLocale", "nu", "ca", "co", "locale"]);
|
||||
|
||||
testWithIntlConstructors(function (Constructor) {
|
||||
var locale = new Constructor(undefined, {localeMatcher: "lookup"}).resolvedOptions().locale;
|
||||
if (!isCanonicalizedStructurallyValidLanguageTag(locale)) {
|
||||
$ERROR("Constructor returns invalid locale " + locale + ".");
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that the behavior of a List is not affected by adversarial
|
||||
* changes to Array.prototype.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
$INCLUDE("testIntl.js");
|
||||
|
||||
taintArray();
|
||||
|
||||
testWithIntlConstructors(function (Constructor) {
|
||||
// this test should work equally for both matching algorithms
|
||||
["lookup", "best fit"].forEach(function (matcher) {
|
||||
var defaultLocale = new Constructor().resolvedOptions().locale;
|
||||
var canonicalized = Constructor.supportedLocalesOf([defaultLocale, defaultLocale],
|
||||
{localeMatcher: matcher});
|
||||
if (canonicalized.length > 1) {
|
||||
$ERROR("Canonicalization with matcher " + matcher + " didn't remove duplicate language tags from locale list.");
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
});
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that LookupSupportedLocales returns an empty list when
|
||||
* given an empty list.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
$INCLUDE("testIntl.js");
|
||||
|
||||
testWithIntlConstructors(function (Constructor) {
|
||||
// this test should work equally for both matching algorithms
|
||||
["lookup", "best fit"].forEach(function (matcher) {
|
||||
var supported = Constructor.supportedLocalesOf([], {localeMatcher: matcher});
|
||||
if (supported.length !== 0) {
|
||||
$ERROR("SupportedLocales with matcher " + matcher + " returned a non-empty list for an empty list.");
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
});
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that Unicode locale extension sequences do not affect
|
||||
* whether a locale is considered supported, but are reported back.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
$INCLUDE("testIntl.js");
|
||||
|
||||
testWithIntlConstructors(function (Constructor) {
|
||||
// this test should work equally for both matching algorithms
|
||||
["lookup", "best fit"].forEach(function (matcher) {
|
||||
var info = getLocaleSupportInfo(Constructor);
|
||||
var allLocales = info.supported.concat(info.byFallback, info.unsupported);
|
||||
allLocales.forEach(function (locale) {
|
||||
var validExtension = "-u-co-phonebk-nu-latn";
|
||||
var invalidExtension = "-u-nu-invalid";
|
||||
var supported1 = Constructor.supportedLocalesOf([locale],
|
||||
{localeMatcher: matcher});
|
||||
var supported2 = Constructor.supportedLocalesOf([locale + validExtension],
|
||||
{localeMatcher: matcher});
|
||||
var supported3 = Constructor.supportedLocalesOf([locale + invalidExtension],
|
||||
{localeMatcher: matcher});
|
||||
if (supported1.length === 1) {
|
||||
if (supported2.length !== 1 || supported3.length !== 1) {
|
||||
$ERROR("Presence of Unicode locale extension sequence affects whether locale " +
|
||||
locale + " is considered supported with matcher " + matcher + ".");
|
||||
}
|
||||
if (supported2[0] !== locale + validExtension || supported3[0] !== locale + invalidExtension) {
|
||||
alert(locale + "; " + supported2[0] + "; " + supported3[0]);
|
||||
$ERROR("Unicode locale extension sequence is not correctly returned for locale " +
|
||||
locale + " with matcher " + matcher + ".");
|
||||
}
|
||||
} else {
|
||||
if (supported2.length !== 0 || supported3.length !== 0) {
|
||||
$ERROR("Presence of Unicode locale extension sequence affects whether locale " +
|
||||
locale + " is considered supported with matcher " + matcher + ".");
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return true;
|
||||
});
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that LookupSupportedLocales includes the default locale
|
||||
* and doesn't include the "no linguistic content" locale.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
$INCLUDE("testIntl.js");
|
||||
|
||||
testWithIntlConstructors(function (Constructor) {
|
||||
// this test should work equally for both matching algorithms
|
||||
["lookup", "best fit"].forEach(function (matcher) {
|
||||
var defaultLocale = new Constructor().resolvedOptions().locale;
|
||||
var noLinguisticContent = "zxx";
|
||||
var supported = Constructor.supportedLocalesOf([defaultLocale, noLinguisticContent],
|
||||
{localeMatcher: matcher});
|
||||
if (supported.indexOf(defaultLocale) === -1) {
|
||||
$ERROR("SupportedLocales didn't return default locale with matcher " + matcher + ".");
|
||||
}
|
||||
if (supported.indexOf(noLinguisticContent) !== -1) {
|
||||
$ERROR("SupportedLocales returned the \"no linguistic content\" locale with matcher " + matcher + ".");
|
||||
}
|
||||
if (supported.length > 1) {
|
||||
$ERROR("SupportedLocales returned stray locales: " + supported.join(", ") + " with matcher " + matcher + ".");
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
});
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that the option localeMatcher is processed correctly.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
$INCLUDE("testIntl.js");
|
||||
|
||||
testWithIntlConstructors(function (Constructor) {
|
||||
var defaultLocale = new Constructor().resolvedOptions().locale;
|
||||
|
||||
var validValues = [undefined, "lookup", "best fit", {toString: function () { return "lookup"; }}];
|
||||
validValues.forEach(function (value) {
|
||||
var supported = Constructor.supportedLocalesOf([defaultLocale], {localeMatcher: value});
|
||||
});
|
||||
|
||||
var invalidValues = [null, 0, 5, NaN, true, false, "invalid"];
|
||||
invalidValues.forEach(function (value) {
|
||||
var error;
|
||||
try {
|
||||
var supported = Constructor.supportedLocalesOf([defaultLocale], {localeMatcher: value});
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
if (error === undefined) {
|
||||
$ERROR("Invalid localeMatcher value " + value + " was not rejected.");
|
||||
} else if (error.name !== "RangeError") {
|
||||
$ERROR("Invalid localeMatcher value " + value + " was rejected with wrong error " + error.name + ".");
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
});
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests that the array returned by SupportedLocales is extensible,
|
||||
* but its properties are non-writable/non-configurable.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
$INCLUDE("testIntl.js");
|
||||
|
||||
function testFrozenProperty(obj, property) {
|
||||
var desc = Object.getOwnPropertyDescriptor(obj, property);
|
||||
if (desc.writable) {
|
||||
$ERROR("Property " + property + " of object returned by SupportedLocales is writable.");
|
||||
}
|
||||
if (desc.configurable) {
|
||||
$ERROR("Property " + property + " of object returned by SupportedLocales is configurable.");
|
||||
}
|
||||
}
|
||||
|
||||
testWithIntlConstructors(function (Constructor) {
|
||||
var defaultLocale = new Constructor().resolvedOptions().locale;
|
||||
var supported = Constructor.supportedLocalesOf([defaultLocale]);
|
||||
if (!Object.isExtensible(supported)) {
|
||||
$ERROR("Object returned by SupportedLocales is not extensible.");
|
||||
}
|
||||
for (var i = 0; i < supported.length; i++) {
|
||||
testFrozenProperty(supported, i);
|
||||
}
|
||||
testFrozenProperty(supported, "length");
|
||||
|
||||
return true;
|
||||
});
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
// Copyright 2012 Google Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests the internal properties of Intl.Collator.
|
||||
*/
|
||||
|
||||
var defaultLocale = new Intl.Collator([]).resolvedOptions().locale;
|
||||
var supportedLocales = Intl.Collator.supportedLocalesOf([defaultLocale]);
|
||||
|
||||
if (supportedLocales.length < 1 || supportedLocales[0] !== defaultLocale) {
|
||||
$ERROR('The default locale is not supported by Intl.Collator');
|
||||
}
|
||||
|
||||
// FIXME: Find a way to check [[relevantExtensionKeys]]
|
||||
|
||||
// FIXME: Find a way to check specified properties of [[localeData]]
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
// Copyright 2012 Google Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests the internal properties of Intl.NumberFormat.
|
||||
* @author: Roozbeh Pournader
|
||||
*/
|
||||
|
||||
var defaultLocale = new Intl.NumberFormat([]).resolvedOptions().locale;
|
||||
var supportedLocales = Intl.NumberFormat.supportedLocalesOf([defaultLocale]);
|
||||
|
||||
if (supportedLocales.length < 1 || supportedLocales[0] !== defaultLocale) {
|
||||
$ERROR('The default locale is not supported by Intl.NumberFormat');
|
||||
}
|
||||
|
||||
// FIXME: Find a way to check that [[relevantExtensionKeys]] === ['nu']
|
||||
|
||||
// FIXME: Find a way to check specified properties of [[localeData]]
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
// Copyright 2012 Google Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @description Tests the internal properties of Intl.DateTimeFormat.
|
||||
* @author: Roozbeh Pournader
|
||||
*/
|
||||
|
||||
var defaultLocale = new Intl.DateTimeFormat([]).resolvedOptions().locale;
|
||||
var supportedLocales = Intl.DateTimeFormat.supportedLocalesOf([defaultLocale]);
|
||||
|
||||
if (supportedLocales.length < 1 || supportedLocales[0] !== defaultLocale) {
|
||||
$ERROR('The default locale is not supported by Intl.DateTimeFormat');
|
||||
}
|
||||
|
||||
// FIXME: Find a way to check that [[relevantExtensionKeys]] === ['ca', 'nu']
|
||||
|
||||
// FIXME: Find a way to check specified properties of [[localeData]]
|
||||
|
|
@ -212,6 +212,7 @@ class TestCase(object):
|
|||
self.suite.GetInclude("sta.js") + \
|
||||
self.suite.GetInclude("ed.js") + \
|
||||
self.suite.GetInclude("testBuiltInObject.js") + \
|
||||
self.suite.GetInclude("testIntl.js") + \
|
||||
self.test + '\n'
|
||||
|
||||
if self.strict_mode:
|
||||
|
|
|
@ -0,0 +1,658 @@
|
|||
// Copyright 2011-2012 Norbert Lindenberg. All rights reserved.
|
||||
// Copyright 2012 Mozilla Corporation. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* This file contains shared functions for the tests in the conformance test
|
||||
* suite for the ECMAScript Internationalization API.
|
||||
* @author Norbert Lindenberg
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @description Calls the provided function for every service constructor in
|
||||
* the Intl object, until f returns a falsy value. It returns the result of the
|
||||
* last call to f, mapped to a boolean.
|
||||
* @param {Function} f the function to call for each service constructor in
|
||||
* the Intl object.
|
||||
* @param {Function} Constructor the constructor object to test with.
|
||||
* @result {Boolean} whether the test succeeded.
|
||||
*/
|
||||
function testWithIntlConstructors(f) {
|
||||
var constructors = ["Collator", "NumberFormat", "DateTimeFormat"];
|
||||
return constructors.every(function (constructor) {
|
||||
var Constructor = Intl[constructor];
|
||||
var result;
|
||||
try {
|
||||
result = f(Constructor);
|
||||
} catch (e) {
|
||||
e.message += " (Testing with " + constructor + ".)";
|
||||
throw e;
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the name of the given constructor object, which must be one of
|
||||
* Intl.Collator, Intl.NumberFormat, or Intl.DateTimeFormat.
|
||||
* @param {object} Constructor a constructor
|
||||
* @return {string} the name of the constructor
|
||||
*/
|
||||
function getConstructorName(Constructor) {
|
||||
switch (Constructor) {
|
||||
case Intl.Collator:
|
||||
return "Collator";
|
||||
case Intl.NumberFormat:
|
||||
return "NumberFormat";
|
||||
case Intl.DateTimeFormat:
|
||||
return "DateTimeFormat";
|
||||
default:
|
||||
$ERROR("test internal error: unknown Constructor");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Taints a named data property of the given object by installing
|
||||
* a setter that throws an exception.
|
||||
* @param {object} obj the object whose data property to taint
|
||||
* @param {string} property the property to taint
|
||||
*/
|
||||
function taintDataProperty(obj, property) {
|
||||
Object.defineProperty(obj, property, {
|
||||
set: function(value) {
|
||||
$ERROR("Client code can adversely affect behavior: setter for " + property + ".");
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Taints a named method of the given object by replacing it with a function
|
||||
* that throws an exception.
|
||||
* @param {object} obj the object whose method to taint
|
||||
* @param {string} property the name of the method to taint
|
||||
*/
|
||||
function taintMethod(obj, property) {
|
||||
Object.defineProperty(obj, property, {
|
||||
value: function() {
|
||||
$ERROR("Client code can adversely affect behavior: method " + property + ".");
|
||||
},
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Taints the given properties (and similarly named properties) by installing
|
||||
* setters on Object.prototype that throw exceptions.
|
||||
* @param {Array} properties an array of property names to taint
|
||||
*/
|
||||
function taintProperties(properties) {
|
||||
properties.forEach(function (property) {
|
||||
var adaptedProperties = [property, "__" + property, "_" + property, property + "_", property + "__"];
|
||||
adaptedProperties.forEach(function (property) {
|
||||
taintDataProperty(Object.prototype, property);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Taints the Array object by creating a setter for the property "0" and
|
||||
* replacing some key methods with functions that throw exceptions.
|
||||
*/
|
||||
function taintArray() {
|
||||
taintDataProperty(Array.prototype, "0");
|
||||
taintMethod(Array.prototype, "indexOf");
|
||||
taintMethod(Array.prototype, "join");
|
||||
taintMethod(Array.prototype, "push");
|
||||
taintMethod(Array.prototype, "slice");
|
||||
taintMethod(Array.prototype, "sort");
|
||||
}
|
||||
|
||||
|
||||
// auxiliary data for getLocaleSupportInfo
|
||||
var languages = ["zh", "es", "en", "hi", "ur", "ar", "ja", "pa"];
|
||||
var scripts = ["Latn", "Hans", "Deva", "Arab", "Jpan", "Hant"];
|
||||
var countries = ["CN", "IN", "US", "PK", "JP", "TW", "HK", "SG"];
|
||||
var localeSupportInfo = {};
|
||||
|
||||
|
||||
/**
|
||||
* Gets locale support info for the given constructor object, which must be one
|
||||
* of Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat.
|
||||
* @param {object} Constructor the constructor for which to get locale support info
|
||||
* @return {object} locale support info with the following properties:
|
||||
* supported: array of fully supported language tags
|
||||
* byFallback: array of language tags that are supported through fallbacks
|
||||
* unsupported: array of unsupported language tags
|
||||
*/
|
||||
function getLocaleSupportInfo(Constructor) {
|
||||
var constructorName = getConstructorName(Constructor);
|
||||
if (localeSupportInfo[constructorName] !== undefined) {
|
||||
return localeSupportInfo[constructorName];
|
||||
}
|
||||
|
||||
var allTags = [];
|
||||
var i, j, k;
|
||||
var language, script, country;
|
||||
for (i = 0; i < languages.length; i++) {
|
||||
language = languages[i];
|
||||
allTags.push(language);
|
||||
for (j = 0; j < scripts.length; j++) {
|
||||
script = scripts[j];
|
||||
allTags.push(language + "-" + script);
|
||||
for (k = 0; k < countries.length; k++) {
|
||||
country = countries[k];
|
||||
allTags.push(language + "-" + script + "-" + country);
|
||||
}
|
||||
}
|
||||
for (k = 0; k < countries.length; k++) {
|
||||
country = countries[k];
|
||||
allTags.push(language + "-" + country);
|
||||
}
|
||||
}
|
||||
|
||||
var supported = [];
|
||||
var byFallback = [];
|
||||
var unsupported = [];
|
||||
for (i = 0; i < allTags.length; i++) {
|
||||
var request = allTags[i];
|
||||
var result = new Constructor([request], {localeMatcher: "lookup"}).resolvedOptions().locale;
|
||||
if (request === result) {
|
||||
supported.push(request);
|
||||
} else if (request.indexOf(result) === 0) {
|
||||
byFallback.push(request);
|
||||
} else {
|
||||
unsupported.push(request);
|
||||
}
|
||||
}
|
||||
|
||||
localeSupportInfo[constructorName] = {
|
||||
supported: supported,
|
||||
byFallback: byFallback,
|
||||
unsupported: unsupported
|
||||
};
|
||||
|
||||
return localeSupportInfo[constructorName];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description Tests whether locale is a String value representing a
|
||||
* structurally valid and canonicalized BCP 47 language tag, as defined in
|
||||
* sections 6.2.2 and 6.2.3 of the ECMAScript Internationalization API
|
||||
* Specification.
|
||||
* @param {String} locale the string to be tested.
|
||||
* @result {Boolean} whether the test succeeded.
|
||||
*/
|
||||
function isCanonicalizedStructurallyValidLanguageTag(locale) {
|
||||
|
||||
/**
|
||||
* Regular expression defining BCP 47 language tags.
|
||||
*
|
||||
* Spec: RFC 5646 section 2.1.
|
||||
*/
|
||||
var alpha = "[a-zA-Z]",
|
||||
digit = "[0-9]",
|
||||
alphanum = "(" + alpha + "|" + digit + ")",
|
||||
regular = "(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang)",
|
||||
irregular = "(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)",
|
||||
grandfathered = "(" + irregular + "|" + regular + ")",
|
||||
privateuse = "(x(-[a-z0-9]{1,8})+)",
|
||||
singleton = "(" + digit + "|[A-WY-Za-wy-z])",
|
||||
extension = "(" + singleton + "(-" + alphanum + "{2,8})+)",
|
||||
variant = "(" + alphanum + "{5,8}|(" + digit + alphanum + "{3}))",
|
||||
region = "(" + alpha + "{2}|" + digit + "{3})",
|
||||
script = "(" + alpha + "{4})",
|
||||
extlang = "(" + alpha + "{3}(-" + alpha + "{3}){0,2})",
|
||||
language = "(" + alpha + "{2,3}(-" + extlang + ")?|" + alpha + "{4}|" + alpha + "{5,8})",
|
||||
langtag = language + "(-" + script + ")?(-" + region + ")?(-" + variant + ")*(-" + extension + ")*(-" + privateuse + ")?",
|
||||
languageTag = "^(" + langtag + "|" + privateuse + "|" + grandfathered + ")$",
|
||||
languageTagRE = new RegExp(languageTag, "i");
|
||||
var duplicateSingleton = "-" + singleton + "-(.*-)?\\1(?!" + alphanum + ")",
|
||||
duplicateSingletonRE = new RegExp(duplicateSingleton, "i"),
|
||||
duplicateVariant = "(" + alphanum + "{2,8}-)+" + variant + "-(" + alphanum + "{2,8}-)*\\3(?!" + alphanum + ")",
|
||||
duplicateVariantRE = new RegExp(duplicateVariant, "i");
|
||||
|
||||
|
||||
/**
|
||||
* Verifies that the given string is a well-formed BCP 47 language tag
|
||||
* with no duplicate variant or singleton subtags.
|
||||
*
|
||||
* Spec: ECMAScript Internationalization API Specification, draft, 6.2.2.
|
||||
*/
|
||||
function isStructurallyValidLanguageTag(locale) {
|
||||
if (!languageTagRE.test(locale)) {
|
||||
return false;
|
||||
}
|
||||
locale = locale.split(/-x-/)[0];
|
||||
return !duplicateSingletonRE.test(locale) && !duplicateVariantRE.test(locale);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Mappings from complete tags to preferred values.
|
||||
*
|
||||
* Spec: IANA Language Subtag Registry.
|
||||
*/
|
||||
var __tagMappings = {
|
||||
// property names must be in lower case; values in canonical form
|
||||
|
||||
// grandfathered tags from IANA language subtag registry, file date 2011-08-25
|
||||
"art-lojban": "jbo",
|
||||
"cel-gaulish": "cel-gaulish",
|
||||
"en-gb-oed": "en-GB-oed",
|
||||
"i-ami": "ami",
|
||||
"i-bnn": "bnn",
|
||||
"i-default": "i-default",
|
||||
"i-enochian": "i-enochian",
|
||||
"i-hak": "hak",
|
||||
"i-klingon": "tlh",
|
||||
"i-lux": "lb",
|
||||
"i-mingo": "i-mingo",
|
||||
"i-navajo": "nv",
|
||||
"i-pwn": "pwn",
|
||||
"i-tao": "tao",
|
||||
"i-tay": "tay",
|
||||
"i-tsu": "tsu",
|
||||
"no-bok": "nb",
|
||||
"no-nyn": "nn",
|
||||
"sgn-be-fr": "sfb",
|
||||
"sgn-be-nl": "vgt",
|
||||
"sgn-ch-de": "sgg",
|
||||
"zh-guoyu": "cmn",
|
||||
"zh-hakka": "hak",
|
||||
"zh-min": "zh-min",
|
||||
"zh-min-nan": "nan",
|
||||
"zh-xiang": "hsn",
|
||||
// deprecated redundant tags from IANA language subtag registry, file date 2011-08-25
|
||||
"sgn-br": "bzs",
|
||||
"sgn-co": "csn",
|
||||
"sgn-de": "gsg",
|
||||
"sgn-dk": "dsl",
|
||||
"sgn-es": "ssp",
|
||||
"sgn-fr": "fsl",
|
||||
"sgn-gb": "bfi",
|
||||
"sgn-gr": "gss",
|
||||
"sgn-ie": "isg",
|
||||
"sgn-it": "ise",
|
||||
"sgn-jp": "jsl",
|
||||
"sgn-mx": "mfs",
|
||||
"sgn-ni": "ncs",
|
||||
"sgn-nl": "dse",
|
||||
"sgn-no": "nsl",
|
||||
"sgn-pt": "psr",
|
||||
"sgn-se": "swl",
|
||||
"sgn-us": "ase",
|
||||
"sgn-za": "sfs",
|
||||
"zh-cmn": "cmn",
|
||||
"zh-cmn-hans": "cmn-Hans",
|
||||
"zh-cmn-hant": "cmn-Hant",
|
||||
"zh-gan": "gan",
|
||||
"zh-wuu": "wuu",
|
||||
"zh-yue": "yue",
|
||||
// deprecated variant with prefix from IANA language subtag registry, file date 2011-08-25
|
||||
"ja-latn-hepburn-heploc": "ja-Latn-alalc97"
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Mappings from non-extlang subtags to preferred values.
|
||||
*
|
||||
* Spec: IANA Language Subtag Registry.
|
||||
*/
|
||||
var __subtagMappings = {
|
||||
// property names and values must be in canonical case
|
||||
// language subtags with Preferred-Value mappings from IANA language subtag registry, file date 2011-08-25
|
||||
"in": "id",
|
||||
"iw": "he",
|
||||
"ji": "yi",
|
||||
"jw": "jv",
|
||||
"mo": "ro",
|
||||
"ayx": "nun",
|
||||
"cjr": "mom",
|
||||
"cmk": "xch",
|
||||
"drh": "khk",
|
||||
"drw": "prs",
|
||||
"gav": "dev",
|
||||
"mst": "mry",
|
||||
"myt": "mry",
|
||||
"tie": "ras",
|
||||
"tkk": "twm",
|
||||
"tnf": "prs",
|
||||
// region subtags with Preferred-Value mappings from IANA language subtag registry, file date 2011-08-25
|
||||
"BU": "MM",
|
||||
"DD": "DE",
|
||||
"FX": "FR",
|
||||
"TP": "TL",
|
||||
"YD": "YE",
|
||||
"ZR": "CD"
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Mappings from extlang subtags to preferred values.
|
||||
*
|
||||
* Spec: IANA Language Subtag Registry.
|
||||
*/
|
||||
var __extlangMappings = {
|
||||
// extlang subtags with Preferred-Value mappings from IANA language subtag registry, file date 2011-08-25
|
||||
// values are arrays with [0] the replacement value, [1] (if present) the prefix to be removed
|
||||
"aao": ["aao", "ar"],
|
||||
"abh": ["abh", "ar"],
|
||||
"abv": ["abv", "ar"],
|
||||
"acm": ["acm", "ar"],
|
||||
"acq": ["acq", "ar"],
|
||||
"acw": ["acw", "ar"],
|
||||
"acx": ["acx", "ar"],
|
||||
"acy": ["acy", "ar"],
|
||||
"adf": ["adf", "ar"],
|
||||
"ads": ["ads", "sgn"],
|
||||
"aeb": ["aeb", "ar"],
|
||||
"aec": ["aec", "ar"],
|
||||
"aed": ["aed", "sgn"],
|
||||
"aen": ["aen", "sgn"],
|
||||
"afb": ["afb", "ar"],
|
||||
"afg": ["afg", "sgn"],
|
||||
"ajp": ["ajp", "ar"],
|
||||
"apc": ["apc", "ar"],
|
||||
"apd": ["apd", "ar"],
|
||||
"arb": ["arb", "ar"],
|
||||
"arq": ["arq", "ar"],
|
||||
"ars": ["ars", "ar"],
|
||||
"ary": ["ary", "ar"],
|
||||
"arz": ["arz", "ar"],
|
||||
"ase": ["ase", "sgn"],
|
||||
"asf": ["asf", "sgn"],
|
||||
"asp": ["asp", "sgn"],
|
||||
"asq": ["asq", "sgn"],
|
||||
"asw": ["asw", "sgn"],
|
||||
"auz": ["auz", "ar"],
|
||||
"avl": ["avl", "ar"],
|
||||
"ayh": ["ayh", "ar"],
|
||||
"ayl": ["ayl", "ar"],
|
||||
"ayn": ["ayn", "ar"],
|
||||
"ayp": ["ayp", "ar"],
|
||||
"bbz": ["bbz", "ar"],
|
||||
"bfi": ["bfi", "sgn"],
|
||||
"bfk": ["bfk", "sgn"],
|
||||
"bjn": ["bjn", "ms"],
|
||||
"bog": ["bog", "sgn"],
|
||||
"bqn": ["bqn", "sgn"],
|
||||
"bqy": ["bqy", "sgn"],
|
||||
"btj": ["btj", "ms"],
|
||||
"bve": ["bve", "ms"],
|
||||
"bvl": ["bvl", "sgn"],
|
||||
"bvu": ["bvu", "ms"],
|
||||
"bzs": ["bzs", "sgn"],
|
||||
"cdo": ["cdo", "zh"],
|
||||
"cds": ["cds", "sgn"],
|
||||
"cjy": ["cjy", "zh"],
|
||||
"cmn": ["cmn", "zh"],
|
||||
"coa": ["coa", "ms"],
|
||||
"cpx": ["cpx", "zh"],
|
||||
"csc": ["csc", "sgn"],
|
||||
"csd": ["csd", "sgn"],
|
||||
"cse": ["cse", "sgn"],
|
||||
"csf": ["csf", "sgn"],
|
||||
"csg": ["csg", "sgn"],
|
||||
"csl": ["csl", "sgn"],
|
||||
"csn": ["csn", "sgn"],
|
||||
"csq": ["csq", "sgn"],
|
||||
"csr": ["csr", "sgn"],
|
||||
"czh": ["czh", "zh"],
|
||||
"czo": ["czo", "zh"],
|
||||
"doq": ["doq", "sgn"],
|
||||
"dse": ["dse", "sgn"],
|
||||
"dsl": ["dsl", "sgn"],
|
||||
"dup": ["dup", "ms"],
|
||||
"ecs": ["ecs", "sgn"],
|
||||
"esl": ["esl", "sgn"],
|
||||
"esn": ["esn", "sgn"],
|
||||
"eso": ["eso", "sgn"],
|
||||
"eth": ["eth", "sgn"],
|
||||
"fcs": ["fcs", "sgn"],
|
||||
"fse": ["fse", "sgn"],
|
||||
"fsl": ["fsl", "sgn"],
|
||||
"fss": ["fss", "sgn"],
|
||||
"gan": ["gan", "zh"],
|
||||
"gom": ["gom", "kok"],
|
||||
"gse": ["gse", "sgn"],
|
||||
"gsg": ["gsg", "sgn"],
|
||||
"gsm": ["gsm", "sgn"],
|
||||
"gss": ["gss", "sgn"],
|
||||
"gus": ["gus", "sgn"],
|
||||
"hab": ["hab", "sgn"],
|
||||
"haf": ["haf", "sgn"],
|
||||
"hak": ["hak", "zh"],
|
||||
"hds": ["hds", "sgn"],
|
||||
"hji": ["hji", "ms"],
|
||||
"hks": ["hks", "sgn"],
|
||||
"hos": ["hos", "sgn"],
|
||||
"hps": ["hps", "sgn"],
|
||||
"hsh": ["hsh", "sgn"],
|
||||
"hsl": ["hsl", "sgn"],
|
||||
"hsn": ["hsn", "zh"],
|
||||
"icl": ["icl", "sgn"],
|
||||
"ils": ["ils", "sgn"],
|
||||
"inl": ["inl", "sgn"],
|
||||
"ins": ["ins", "sgn"],
|
||||
"ise": ["ise", "sgn"],
|
||||
"isg": ["isg", "sgn"],
|
||||
"isr": ["isr", "sgn"],
|
||||
"jak": ["jak", "ms"],
|
||||
"jax": ["jax", "ms"],
|
||||
"jcs": ["jcs", "sgn"],
|
||||
"jhs": ["jhs", "sgn"],
|
||||
"jls": ["jls", "sgn"],
|
||||
"jos": ["jos", "sgn"],
|
||||
"jsl": ["jsl", "sgn"],
|
||||
"jus": ["jus", "sgn"],
|
||||
"kgi": ["kgi", "sgn"],
|
||||
"knn": ["knn", "kok"],
|
||||
"kvb": ["kvb", "ms"],
|
||||
"kvk": ["kvk", "sgn"],
|
||||
"kvr": ["kvr", "ms"],
|
||||
"kxd": ["kxd", "ms"],
|
||||
"lbs": ["lbs", "sgn"],
|
||||
"lce": ["lce", "ms"],
|
||||
"lcf": ["lcf", "ms"],
|
||||
"liw": ["liw", "ms"],
|
||||
"lls": ["lls", "sgn"],
|
||||
"lsg": ["lsg", "sgn"],
|
||||
"lsl": ["lsl", "sgn"],
|
||||
"lso": ["lso", "sgn"],
|
||||
"lsp": ["lsp", "sgn"],
|
||||
"lst": ["lst", "sgn"],
|
||||
"lsy": ["lsy", "sgn"],
|
||||
"ltg": ["ltg", "lv"],
|
||||
"lvs": ["lvs", "lv"],
|
||||
"lzh": ["lzh", "zh"],
|
||||
"max": ["max", "ms"],
|
||||
"mdl": ["mdl", "sgn"],
|
||||
"meo": ["meo", "ms"],
|
||||
"mfa": ["mfa", "ms"],
|
||||
"mfb": ["mfb", "ms"],
|
||||
"mfs": ["mfs", "sgn"],
|
||||
"min": ["min", "ms"],
|
||||
"mnp": ["mnp", "zh"],
|
||||
"mqg": ["mqg", "ms"],
|
||||
"mre": ["mre", "sgn"],
|
||||
"msd": ["msd", "sgn"],
|
||||
"msi": ["msi", "ms"],
|
||||
"msr": ["msr", "sgn"],
|
||||
"mui": ["mui", "ms"],
|
||||
"mzc": ["mzc", "sgn"],
|
||||
"mzg": ["mzg", "sgn"],
|
||||
"mzy": ["mzy", "sgn"],
|
||||
"nan": ["nan", "zh"],
|
||||
"nbs": ["nbs", "sgn"],
|
||||
"ncs": ["ncs", "sgn"],
|
||||
"nsi": ["nsi", "sgn"],
|
||||
"nsl": ["nsl", "sgn"],
|
||||
"nsp": ["nsp", "sgn"],
|
||||
"nsr": ["nsr", "sgn"],
|
||||
"nzs": ["nzs", "sgn"],
|
||||
"okl": ["okl", "sgn"],
|
||||
"orn": ["orn", "ms"],
|
||||
"ors": ["ors", "ms"],
|
||||
"pel": ["pel", "ms"],
|
||||
"pga": ["pga", "ar"],
|
||||
"pks": ["pks", "sgn"],
|
||||
"prl": ["prl", "sgn"],
|
||||
"prz": ["prz", "sgn"],
|
||||
"psc": ["psc", "sgn"],
|
||||
"psd": ["psd", "sgn"],
|
||||
"pse": ["pse", "ms"],
|
||||
"psg": ["psg", "sgn"],
|
||||
"psl": ["psl", "sgn"],
|
||||
"pso": ["pso", "sgn"],
|
||||
"psp": ["psp", "sgn"],
|
||||
"psr": ["psr", "sgn"],
|
||||
"pys": ["pys", "sgn"],
|
||||
"rms": ["rms", "sgn"],
|
||||
"rsi": ["rsi", "sgn"],
|
||||
"rsl": ["rsl", "sgn"],
|
||||
"sdl": ["sdl", "sgn"],
|
||||
"sfb": ["sfb", "sgn"],
|
||||
"sfs": ["sfs", "sgn"],
|
||||
"sgg": ["sgg", "sgn"],
|
||||
"sgx": ["sgx", "sgn"],
|
||||
"shu": ["shu", "ar"],
|
||||
"slf": ["slf", "sgn"],
|
||||
"sls": ["sls", "sgn"],
|
||||
"sqs": ["sqs", "sgn"],
|
||||
"ssh": ["ssh", "ar"],
|
||||
"ssp": ["ssp", "sgn"],
|
||||
"ssr": ["ssr", "sgn"],
|
||||
"svk": ["svk", "sgn"],
|
||||
"swc": ["swc", "sw"],
|
||||
"swh": ["swh", "sw"],
|
||||
"swl": ["swl", "sgn"],
|
||||
"syy": ["syy", "sgn"],
|
||||
"tmw": ["tmw", "ms"],
|
||||
"tse": ["tse", "sgn"],
|
||||
"tsm": ["tsm", "sgn"],
|
||||
"tsq": ["tsq", "sgn"],
|
||||
"tss": ["tss", "sgn"],
|
||||
"tsy": ["tsy", "sgn"],
|
||||
"tza": ["tza", "sgn"],
|
||||
"ugn": ["ugn", "sgn"],
|
||||
"ugy": ["ugy", "sgn"],
|
||||
"ukl": ["ukl", "sgn"],
|
||||
"uks": ["uks", "sgn"],
|
||||
"urk": ["urk", "ms"],
|
||||
"uzn": ["uzn", "uz"],
|
||||
"uzs": ["uzs", "uz"],
|
||||
"vgt": ["vgt", "sgn"],
|
||||
"vkk": ["vkk", "ms"],
|
||||
"vkt": ["vkt", "ms"],
|
||||
"vsi": ["vsi", "sgn"],
|
||||
"vsl": ["vsl", "sgn"],
|
||||
"vsv": ["vsv", "sgn"],
|
||||
"wuu": ["wuu", "zh"],
|
||||
"xki": ["xki", "sgn"],
|
||||
"xml": ["xml", "sgn"],
|
||||
"xmm": ["xmm", "ms"],
|
||||
"xms": ["xms", "sgn"],
|
||||
"yds": ["yds", "sgn"],
|
||||
"ysl": ["ysl", "sgn"],
|
||||
"yue": ["yue", "zh"],
|
||||
"zib": ["zib", "sgn"],
|
||||
"zlm": ["zlm", "ms"],
|
||||
"zmi": ["zmi", "ms"],
|
||||
"zsl": ["zsl", "sgn"],
|
||||
"zsm": ["zsm", "ms"]
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Canonicalizes the given well-formed BCP 47 language tag, including regularized case of subtags.
|
||||
*
|
||||
* Spec: ECMAScript Internationalization API Specification, draft, 6.2.3.
|
||||
* Spec: RFC 5646, section 4.5.
|
||||
*/
|
||||
function canonicalizeLanguageTag(locale) {
|
||||
|
||||
// start with lower case for easier processing, and because most subtags will need to be lower case anyway
|
||||
locale = locale.toLowerCase();
|
||||
|
||||
// handle mappings for complete tags
|
||||
if (__tagMappings.hasOwnProperty(locale)) {
|
||||
return __tagMappings[locale];
|
||||
}
|
||||
|
||||
var subtags = locale.split("-");
|
||||
var i = 0;
|
||||
|
||||
// handle standard part: all subtags before first singleton or "x"
|
||||
while (i < subtags.length) {
|
||||
var subtag = subtags[i];
|
||||
if (subtag.length === 1 && (i > 0 || subtag === "x")) {
|
||||
break;
|
||||
} else if (i !== 0 && subtag.length === 2) {
|
||||
subtag = subtag.toUpperCase();
|
||||
} else if (subtag.length === 4) {
|
||||
subtag = subtag[0].toUpperCase() + subtag.substring(1).toLowerCase();
|
||||
}
|
||||
if (__subtagMappings.hasOwnProperty(subtag)) {
|
||||
subtag = __subtagMappings[subtag];
|
||||
} else if (__extlangMappings.hasOwnProperty(subtag)) {
|
||||
subtag = __extlangMappings[subtag][0];
|
||||
if (i === 1 && __extlangMappings[subtag][1] === subtags[0]) {
|
||||
subtags.shift();
|
||||
i--;
|
||||
}
|
||||
}
|
||||
subtags[i] = subtag;
|
||||
i++;
|
||||
}
|
||||
var normal = subtags.slice(0, i).join("-");
|
||||
|
||||
// handle extensions
|
||||
var extensions = [];
|
||||
while (i < subtags.length && subtags[i] !== "x") {
|
||||
var extensionStart = i;
|
||||
i++;
|
||||
while (i < subtags.length && subtags[i].length > 1) {
|
||||
i++;
|
||||
}
|
||||
var extension = subtags.slice(extensionStart, i).join("-");
|
||||
extensions.push(extension);
|
||||
}
|
||||
extensions.sort();
|
||||
|
||||
// handle private use
|
||||
var privateUse;
|
||||
if (i < subtags.length) {
|
||||
privateUse = subtags.slice(i).join("-");
|
||||
}
|
||||
|
||||
// put everything back together
|
||||
var canonical = normal;
|
||||
if (extensions.length > 0) {
|
||||
canonical += "-" + extensions.join("-");
|
||||
}
|
||||
if (privateUse !== undefined) {
|
||||
if (canonical.length > 0) {
|
||||
canonical += "-" + privateUse;
|
||||
} else {
|
||||
canonical = privateUse;
|
||||
}
|
||||
}
|
||||
|
||||
return canonical;
|
||||
}
|
||||
|
||||
return typeof locale === "string" && isStructurallyValidLanguageTag(locale) &&
|
||||
canonicalizeLanguageTag(locale) === locale;
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
|
@ -1 +1 @@
|
|||
{"numTests":41,"testSuite":["json/intl402.json"]}
|
||||
{"numTests":66,"testSuite":["json/intl402.json"]}
|
Loading…
Reference in New Issue