mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-20 22:27:31 +09:00
Add pluralrules to JS Intl
This commit is contained in:
parent
49676c9254
commit
ea1e157289
3 changed files with 542 additions and 134 deletions
|
|
@ -9,7 +9,8 @@
|
||||||
JSMSG_INVALID_OPTION_VALUE: false, JSMSG_INVALID_DIGITS_VALUE: false,
|
JSMSG_INVALID_OPTION_VALUE: false, JSMSG_INVALID_DIGITS_VALUE: false,
|
||||||
JSMSG_INTL_OBJECT_REINITED: false, JSMSG_INVALID_CURRENCY_CODE: false,
|
JSMSG_INTL_OBJECT_REINITED: false, JSMSG_INVALID_CURRENCY_CODE: false,
|
||||||
JSMSG_UNDEFINED_CURRENCY: false, JSMSG_INVALID_TIME_ZONE: false,
|
JSMSG_UNDEFINED_CURRENCY: false, JSMSG_INVALID_TIME_ZONE: false,
|
||||||
JSMSG_DATE_NOT_FINITE: false,
|
JSMSG_DATE_NOT_FINITE: false, JSMSG_INVALID_KEYS_TYPE: false,
|
||||||
|
JSMSG_INVALID_KEY: false,
|
||||||
intl_Collator_availableLocales: false,
|
intl_Collator_availableLocales: false,
|
||||||
intl_availableCollations: false,
|
intl_availableCollations: false,
|
||||||
intl_CompareStrings: false,
|
intl_CompareStrings: false,
|
||||||
|
|
@ -20,6 +21,9 @@
|
||||||
intl_availableCalendars: false,
|
intl_availableCalendars: false,
|
||||||
intl_patternForSkeleton: false,
|
intl_patternForSkeleton: false,
|
||||||
intl_FormatDateTime: false,
|
intl_FormatDateTime: false,
|
||||||
|
intl_SelectPluralRule: false,
|
||||||
|
intl_GetPluralCategories: false,
|
||||||
|
intl_GetCalendarInfo: false,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -432,7 +436,7 @@ function CanonicalizeLanguageTag(locale) {
|
||||||
subtags[i] = subtag;
|
subtags[i] = subtag;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
var normal = callFunction(std_Array_join, callFunction(std_Array_slice, subtags, 0, i), "-");
|
var normal = ArrayJoinRange(subtags, "-", 0, i);
|
||||||
|
|
||||||
// Extension sequences are sorted by their singleton characters.
|
// Extension sequences are sorted by their singleton characters.
|
||||||
// "u-ca-chinese-t-zh-latn" -> "t-zh-latn-u-ca-chinese"
|
// "u-ca-chinese-t-zh-latn" -> "t-zh-latn-u-ca-chinese"
|
||||||
|
|
@ -442,7 +446,7 @@ function CanonicalizeLanguageTag(locale) {
|
||||||
i++;
|
i++;
|
||||||
while (i < subtags.length && subtags[i].length > 1)
|
while (i < subtags.length && subtags[i].length > 1)
|
||||||
i++;
|
i++;
|
||||||
var extension = callFunction(std_Array_join, callFunction(std_Array_slice, subtags, extensionStart, i), "-");
|
var extension = ArrayJoinRange(subtags, "-", extensionStart, i);
|
||||||
callFunction(std_Array_push, extensions, extension);
|
callFunction(std_Array_push, extensions, extension);
|
||||||
}
|
}
|
||||||
callFunction(std_Array_sort, extensions);
|
callFunction(std_Array_sort, extensions);
|
||||||
|
|
@ -450,7 +454,7 @@ function CanonicalizeLanguageTag(locale) {
|
||||||
// Private use sequences are left as is. "x-private"
|
// Private use sequences are left as is. "x-private"
|
||||||
var privateUse = "";
|
var privateUse = "";
|
||||||
if (i < subtags.length)
|
if (i < subtags.length)
|
||||||
privateUse = callFunction(std_Array_join, callFunction(std_Array_slice, subtags, i), "-");
|
privateUse = ArrayJoinRange(subtags, "-", i);
|
||||||
|
|
||||||
// Put everything back together.
|
// Put everything back together.
|
||||||
var canonical = normal;
|
var canonical = normal;
|
||||||
|
|
@ -467,6 +471,24 @@ function CanonicalizeLanguageTag(locale) {
|
||||||
return canonical;
|
return canonical;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Joins the array elements in the given range with the supplied separator.
|
||||||
|
*/
|
||||||
|
function ArrayJoinRange(array, separator, from, to = array.length) {
|
||||||
|
assert(typeof separator === "string", "|separator| is a string value");
|
||||||
|
assert(typeof from === "number", "|from| is a number value");
|
||||||
|
assert(typeof to === "number", "|to| is a number value");
|
||||||
|
assert(0 <= from && from <= to && to <= array.length, "|from| and |to| form a valid range");
|
||||||
|
|
||||||
|
if (from === to)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
var result = array[from];
|
||||||
|
for (var i = from + 1; i < to; i++) {
|
||||||
|
result += separator + array[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
function localeContainsNoUnicodeExtensions(locale) {
|
function localeContainsNoUnicodeExtensions(locale) {
|
||||||
// No "-u-", no possible Unicode extension.
|
// No "-u-", no possible Unicode extension.
|
||||||
|
|
@ -838,6 +860,7 @@ function BestAvailableLocaleIgnoringDefault(availableLocales, locale) {
|
||||||
return BestAvailableLocaleHelper(availableLocales, locale, false);
|
return BestAvailableLocaleHelper(availableLocales, locale, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var noRelevantExtensionKeys = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares a BCP 47 language priority list against the set of locales in
|
* Compares a BCP 47 language priority list against the set of locales in
|
||||||
|
|
@ -1165,9 +1188,10 @@ function GetOption(options, property, type, values, fallback) {
|
||||||
* Spec: ECMAScript Internationalization API Specification, 9.2.10.
|
* Spec: ECMAScript Internationalization API Specification, 9.2.10.
|
||||||
*/
|
*/
|
||||||
function GetNumberOption(options, property, minimum, maximum, fallback) {
|
function GetNumberOption(options, property, minimum, maximum, fallback) {
|
||||||
assert(typeof minimum === "number", "GetNumberOption");
|
assert(typeof minimum === "number" && (minimum | 0) === minimum, "GetNumberOption");
|
||||||
assert(typeof maximum === "number", "GetNumberOption");
|
assert(typeof maximum === "number" && (maximum | 0) === maximum, "GetNumberOption");
|
||||||
assert(fallback === undefined || (fallback >= minimum && fallback <= maximum), "GetNumberOption");
|
assert(typeof fallback === "number" && (fallback | 0) === fallback, "GetNumberOption");
|
||||||
|
assert(minimum <= fallback && fallback <= maximum, "GetNumberOption");
|
||||||
|
|
||||||
// Step 1.
|
// Step 1.
|
||||||
var value = options[property];
|
var value = options[property];
|
||||||
|
|
@ -1177,7 +1201,10 @@ function GetNumberOption(options, property, minimum, maximum, fallback) {
|
||||||
value = ToNumber(value);
|
value = ToNumber(value);
|
||||||
if (Number_isNaN(value) || value < minimum || value > maximum)
|
if (Number_isNaN(value) || value < minimum || value > maximum)
|
||||||
ThrowRangeError(JSMSG_INVALID_DIGITS_VALUE, value);
|
ThrowRangeError(JSMSG_INVALID_DIGITS_VALUE, value);
|
||||||
return std_Math_floor(value);
|
|
||||||
|
// Apply bitwise-or to convert -0 to +0 per ES2017, 5.2 and to ensure
|
||||||
|
// the result is an int32 value.
|
||||||
|
return std_Math_floor(value) | 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3.
|
// Step 3.
|
||||||
|
|
@ -1251,7 +1278,9 @@ function initializeIntlObject(obj) {
|
||||||
function setLazyData(internals, type, lazyData)
|
function setLazyData(internals, type, lazyData)
|
||||||
{
|
{
|
||||||
assert(internals.type === "partial", "can't set lazy data for anything but a newborn");
|
assert(internals.type === "partial", "can't set lazy data for anything but a newborn");
|
||||||
assert(type === "Collator" || type === "DateTimeFormat" || type == "NumberFormat", "bad type");
|
assert(type === "Collator" || type === "DateTimeFormat" ||
|
||||||
|
type == "NumberFormat" || type === "PluralRules",
|
||||||
|
"bad type");
|
||||||
assert(IsObject(lazyData), "non-object lazy data");
|
assert(IsObject(lazyData), "non-object lazy data");
|
||||||
|
|
||||||
// Set in reverse order so that the .type change is a barrier.
|
// Set in reverse order so that the .type change is a barrier.
|
||||||
|
|
@ -1301,7 +1330,9 @@ function isInitializedIntlObject(obj) {
|
||||||
if (IsObject(internals)) {
|
if (IsObject(internals)) {
|
||||||
assert(callFunction(std_Object_hasOwnProperty, internals, "type"), "missing type");
|
assert(callFunction(std_Object_hasOwnProperty, internals, "type"), "missing type");
|
||||||
var type = internals.type;
|
var type = internals.type;
|
||||||
assert(type === "partial" || type === "Collator" || type === "DateTimeFormat" || type === "NumberFormat", "unexpected type");
|
assert(type === "partial" || type === "Collator" ||
|
||||||
|
type === "DateTimeFormat" || type === "NumberFormat" || type === "PluralRules",
|
||||||
|
"unexpected type");
|
||||||
assert(callFunction(std_Object_hasOwnProperty, internals, "lazyData"), "missing lazyData");
|
assert(callFunction(std_Object_hasOwnProperty, internals, "lazyData"), "missing lazyData");
|
||||||
assert(callFunction(std_Object_hasOwnProperty, internals, "internalProps"), "missing internalProps");
|
assert(callFunction(std_Object_hasOwnProperty, internals, "internalProps"), "missing internalProps");
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1358,6 +1389,8 @@ function getInternals(obj)
|
||||||
internalProps = resolveCollatorInternals(lazyData)
|
internalProps = resolveCollatorInternals(lazyData)
|
||||||
else if (type === "DateTimeFormat")
|
else if (type === "DateTimeFormat")
|
||||||
internalProps = resolveDateTimeFormatInternals(lazyData)
|
internalProps = resolveDateTimeFormatInternals(lazyData)
|
||||||
|
else if (type === "PluralRules")
|
||||||
|
internalProps = resolvePluralRulesInternals(lazyData)
|
||||||
else
|
else
|
||||||
internalProps = resolveNumberFormatInternals(lazyData);
|
internalProps = resolveNumberFormatInternals(lazyData);
|
||||||
setInternalProperties(internals, internalProps);
|
setInternalProperties(internals, internalProps);
|
||||||
|
|
@ -1689,6 +1722,7 @@ function Intl_Collator_compare_get() {
|
||||||
// Step 2.
|
// Step 2.
|
||||||
return internals.boundCompare;
|
return internals.boundCompare;
|
||||||
}
|
}
|
||||||
|
_SetCanonicalName(Intl_Collator_compare_get, "get compare");
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1757,45 +1791,37 @@ function resolveNumberFormatInternals(lazyNumberFormatData) {
|
||||||
// Step 6.
|
// Step 6.
|
||||||
var opt = lazyNumberFormatData.opt;
|
var opt = lazyNumberFormatData.opt;
|
||||||
|
|
||||||
// Compute effective locale.
|
|
||||||
// Step 9.
|
|
||||||
var NumberFormat = numberFormatInternalProperties;
|
var NumberFormat = numberFormatInternalProperties;
|
||||||
|
|
||||||
// Step 10.
|
// Step 9.
|
||||||
var localeData = NumberFormat.localeData;
|
var localeData = NumberFormat.localeData;
|
||||||
|
|
||||||
// Step 11.
|
// Step 10.
|
||||||
var r = ResolveLocale(callFunction(NumberFormat.availableLocales, NumberFormat),
|
var r = ResolveLocale(callFunction(NumberFormat.availableLocales, NumberFormat),
|
||||||
lazyNumberFormatData.requestedLocales,
|
lazyNumberFormatData.requestedLocales,
|
||||||
lazyNumberFormatData.opt,
|
lazyNumberFormatData.opt,
|
||||||
NumberFormat.relevantExtensionKeys,
|
NumberFormat.relevantExtensionKeys,
|
||||||
localeData);
|
localeData);
|
||||||
|
|
||||||
// Steps 12-13. (Step 14 is not relevant to our implementation.)
|
// Steps 11-12. (Step 13 is not relevant to our implementation.)
|
||||||
internalProps.locale = r.locale;
|
internalProps.locale = r.locale;
|
||||||
internalProps.numberingSystem = r.nu;
|
internalProps.numberingSystem = r.nu;
|
||||||
|
|
||||||
// Compute formatting options.
|
// Compute formatting options.
|
||||||
// Step 16.
|
// Step 15.
|
||||||
var s = lazyNumberFormatData.style;
|
var style = lazyNumberFormatData.style;
|
||||||
internalProps.style = s;
|
internalProps.style = style;
|
||||||
|
|
||||||
// Steps 20, 22.
|
// Steps 19, 21.
|
||||||
if (s === "currency") {
|
if (style === "currency") {
|
||||||
internalProps.currency = lazyNumberFormatData.currency;
|
internalProps.currency = lazyNumberFormatData.currency;
|
||||||
internalProps.currencyDisplay = lazyNumberFormatData.currencyDisplay;
|
internalProps.currencyDisplay = lazyNumberFormatData.currencyDisplay;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 24.
|
|
||||||
internalProps.minimumIntegerDigits = lazyNumberFormatData.minimumIntegerDigits;
|
internalProps.minimumIntegerDigits = lazyNumberFormatData.minimumIntegerDigits;
|
||||||
|
|
||||||
// Steps 27.
|
|
||||||
internalProps.minimumFractionDigits = lazyNumberFormatData.minimumFractionDigits;
|
internalProps.minimumFractionDigits = lazyNumberFormatData.minimumFractionDigits;
|
||||||
|
|
||||||
// Step 30.
|
|
||||||
internalProps.maximumFractionDigits = lazyNumberFormatData.maximumFractionDigits;
|
internalProps.maximumFractionDigits = lazyNumberFormatData.maximumFractionDigits;
|
||||||
|
|
||||||
// Step 33.
|
|
||||||
if ("minimumSignificantDigits" in lazyNumberFormatData) {
|
if ("minimumSignificantDigits" in lazyNumberFormatData) {
|
||||||
// Note: Intl.NumberFormat.prototype.resolvedOptions() exposes the
|
// Note: Intl.NumberFormat.prototype.resolvedOptions() exposes the
|
||||||
// actual presence (versus undefined-ness) of these properties.
|
// actual presence (versus undefined-ness) of these properties.
|
||||||
|
|
@ -1804,10 +1830,10 @@ function resolveNumberFormatInternals(lazyNumberFormatData) {
|
||||||
internalProps.maximumSignificantDigits = lazyNumberFormatData.maximumSignificantDigits;
|
internalProps.maximumSignificantDigits = lazyNumberFormatData.maximumSignificantDigits;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 35.
|
// Step 27.
|
||||||
internalProps.useGrouping = lazyNumberFormatData.useGrouping;
|
internalProps.useGrouping = lazyNumberFormatData.useGrouping;
|
||||||
|
|
||||||
// Step 42.
|
// Step 34.
|
||||||
internalProps.boundFormat = undefined;
|
internalProps.boundFormat = undefined;
|
||||||
|
|
||||||
// The caller is responsible for associating |internalProps| with the right
|
// The caller is responsible for associating |internalProps| with the right
|
||||||
|
|
@ -1835,6 +1861,44 @@ function getNumberFormatInternals(obj, methodName) {
|
||||||
return internalProps;
|
return internalProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies digit options used for number formatting onto the intl object.
|
||||||
|
*
|
||||||
|
* Spec: ECMAScript Internationalization API Specification, 11.1.1.
|
||||||
|
*/
|
||||||
|
function SetNumberFormatDigitOptions(lazyData, options, mnfdDefault, mxfdDefault) {
|
||||||
|
// We skip Step 1 because we set the properties on a lazyData object.
|
||||||
|
|
||||||
|
// Step 2-3.
|
||||||
|
assert(IsObject(options), "SetNumberFormatDigitOptions");
|
||||||
|
assert(typeof mnfdDefault === "number", "SetNumberFormatDigitOptions");
|
||||||
|
assert(typeof mxfdDefault === "number", "SetNumberFormatDigitOptions");
|
||||||
|
assert(mnfdDefault <= mxfdDefault, "SetNumberFormatDigitOptions");
|
||||||
|
|
||||||
|
// Steps 4-6.
|
||||||
|
const mnid = GetNumberOption(options, "minimumIntegerDigits", 1, 21, 1);
|
||||||
|
const mnfd = GetNumberOption(options, "minimumFractionDigits", 0, 20, mnfdDefault);
|
||||||
|
const mxfdActualDefault = std_Math_max(mnfd, mxfdDefault);
|
||||||
|
const mxfd = GetNumberOption(options, "maximumFractionDigits", mnfd, 20, mxfdActualDefault);
|
||||||
|
|
||||||
|
// Steps 7-8.
|
||||||
|
let mnsd = options.minimumSignificantDigits;
|
||||||
|
let mxsd = options.maximumSignificantDigits;
|
||||||
|
|
||||||
|
// Steps 9-11.
|
||||||
|
lazyData.minimumIntegerDigits = mnid;
|
||||||
|
lazyData.minimumFractionDigits = mnfd;
|
||||||
|
lazyData.maximumFractionDigits = mxfd;
|
||||||
|
|
||||||
|
// Step 12.
|
||||||
|
if (mnsd !== undefined || mxsd !== undefined) {
|
||||||
|
mnsd = GetNumberOption(options, "minimumSignificantDigits", 1, 21, 1);
|
||||||
|
mxsd = GetNumberOption(options, "maximumSignificantDigits", mnsd, 21, 21);
|
||||||
|
lazyData.minimumSignificantDigits = mnsd;
|
||||||
|
lazyData.maximumSignificantDigits = mxsd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes an object as a NumberFormat.
|
* Initializes an object as a NumberFormat.
|
||||||
|
|
@ -1884,7 +1948,7 @@ function InitializeNumberFormat(numberFormat, locales, options) {
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// Note that lazy data is only installed as a final step of initialization,
|
// Note that lazy data is only installed as a final step of initialization,
|
||||||
// so every Collator lazy data object has *all* these properties, never a
|
// so every NumberFormat lazy data object has *all* these properties, never a
|
||||||
// subset of them.
|
// subset of them.
|
||||||
var lazyNumberFormatData = std_Object_create(null);
|
var lazyNumberFormatData = std_Object_create(null);
|
||||||
|
|
||||||
|
|
@ -1914,67 +1978,46 @@ function InitializeNumberFormat(numberFormat, locales, options) {
|
||||||
opt.localeMatcher = matcher;
|
opt.localeMatcher = matcher;
|
||||||
|
|
||||||
// Compute formatting options.
|
// Compute formatting options.
|
||||||
// Step 15.
|
// Step 14.
|
||||||
var s = GetOption(options, "style", "string", ["decimal", "percent", "currency"], "decimal");
|
var style = GetOption(options, "style", "string", ["decimal", "percent", "currency"], "decimal");
|
||||||
lazyNumberFormatData.style = s;
|
lazyNumberFormatData.style = style;
|
||||||
|
|
||||||
// Steps 17-20.
|
// Steps 16-19.
|
||||||
var c = GetOption(options, "currency", "string", undefined, undefined);
|
var c = GetOption(options, "currency", "string", undefined, undefined);
|
||||||
if (c !== undefined && !IsWellFormedCurrencyCode(c))
|
if (c !== undefined && !IsWellFormedCurrencyCode(c))
|
||||||
ThrowRangeError(JSMSG_INVALID_CURRENCY_CODE, c);
|
ThrowRangeError(JSMSG_INVALID_CURRENCY_CODE, c);
|
||||||
var cDigits;
|
var cDigits;
|
||||||
if (s === "currency") {
|
if (style === "currency") {
|
||||||
if (c === undefined)
|
if (c === undefined)
|
||||||
ThrowTypeError(JSMSG_UNDEFINED_CURRENCY);
|
ThrowTypeError(JSMSG_UNDEFINED_CURRENCY);
|
||||||
|
|
||||||
// Steps 20.a-c.
|
// Steps 19.a-c.
|
||||||
c = toASCIIUpperCase(c);
|
c = toASCIIUpperCase(c);
|
||||||
lazyNumberFormatData.currency = c;
|
lazyNumberFormatData.currency = c;
|
||||||
cDigits = CurrencyDigits(c);
|
cDigits = CurrencyDigits(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 21.
|
// Step 20.
|
||||||
var cd = GetOption(options, "currencyDisplay", "string", ["code", "symbol", "name"], "symbol");
|
var cd = GetOption(options, "currencyDisplay", "string", ["code", "symbol", "name"], "symbol");
|
||||||
if (s === "currency")
|
if (style === "currency")
|
||||||
lazyNumberFormatData.currencyDisplay = cd;
|
lazyNumberFormatData.currencyDisplay = cd;
|
||||||
|
|
||||||
// Step 23.
|
// Steps 22-25.
|
||||||
var mnid = GetNumberOption(options, "minimumIntegerDigits", 1, 21, 1);
|
var mnfdDefault, mxfdDefault;
|
||||||
lazyNumberFormatData.minimumIntegerDigits = mnid;
|
if (style === "currency") {
|
||||||
|
mnfdDefault = cDigits;
|
||||||
// Steps 25-26.
|
mxfdDefault = cDigits;
|
||||||
var mnfdDefault = (s === "currency") ? cDigits : 0;
|
} else {
|
||||||
var mnfd = GetNumberOption(options, "minimumFractionDigits", 0, 20, mnfdDefault);
|
mnfdDefault = 0;
|
||||||
lazyNumberFormatData.minimumFractionDigits = mnfd;
|
mxfdDefault = style === "percent" ? 0 : 3;
|
||||||
|
|
||||||
// Steps 28-29.
|
|
||||||
var mxfdDefault;
|
|
||||||
if (s === "currency")
|
|
||||||
mxfdDefault = std_Math_max(mnfd, cDigits);
|
|
||||||
else if (s === "percent")
|
|
||||||
mxfdDefault = std_Math_max(mnfd, 0);
|
|
||||||
else
|
|
||||||
mxfdDefault = std_Math_max(mnfd, 3);
|
|
||||||
var mxfd = GetNumberOption(options, "maximumFractionDigits", mnfd, 20, mxfdDefault);
|
|
||||||
lazyNumberFormatData.maximumFractionDigits = mxfd;
|
|
||||||
|
|
||||||
// Steps 31-32.
|
|
||||||
var mnsd = options.minimumSignificantDigits;
|
|
||||||
var mxsd = options.maximumSignificantDigits;
|
|
||||||
|
|
||||||
// Step 33.
|
|
||||||
if (mnsd !== undefined || mxsd !== undefined) {
|
|
||||||
mnsd = GetNumberOption(options, "minimumSignificantDigits", 1, 21, 1);
|
|
||||||
mxsd = GetNumberOption(options, "maximumSignificantDigits", mnsd, 21, 21);
|
|
||||||
lazyNumberFormatData.minimumSignificantDigits = mnsd;
|
|
||||||
lazyNumberFormatData.maximumSignificantDigits = mxsd;
|
|
||||||
}
|
}
|
||||||
|
SetNumberFormatDigitOptions(lazyNumberFormatData, options, mnfdDefault, mxfdDefault);
|
||||||
|
|
||||||
// Step 34.
|
// Steps 26.
|
||||||
var g = GetOption(options, "useGrouping", "boolean", undefined, true);
|
var g = GetOption(options, "useGrouping", "boolean", undefined, true);
|
||||||
lazyNumberFormatData.useGrouping = g;
|
lazyNumberFormatData.useGrouping = g;
|
||||||
|
|
||||||
// Step 43.
|
// Steps 35-36.
|
||||||
//
|
//
|
||||||
// We've done everything that must be done now: mark the lazy data as fully
|
// We've done everything that must be done now: mark the lazy data as fully
|
||||||
// computed and install it.
|
// computed and install it.
|
||||||
|
|
@ -1982,43 +2025,6 @@ function InitializeNumberFormat(numberFormat, locales, options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mapping from currency codes to the number of decimal digits used for them.
|
|
||||||
* Default is 2 digits.
|
|
||||||
*
|
|
||||||
* Spec: ISO 4217 Currency and Funds Code List.
|
|
||||||
* http://www.currency-iso.org/en/home/tables/table-a1.html
|
|
||||||
*/
|
|
||||||
var currencyDigits = {
|
|
||||||
BHD: 3,
|
|
||||||
BIF: 0,
|
|
||||||
BYR: 0,
|
|
||||||
CLF: 4,
|
|
||||||
CLP: 0,
|
|
||||||
DJF: 0,
|
|
||||||
GNF: 0,
|
|
||||||
IQD: 3,
|
|
||||||
ISK: 0,
|
|
||||||
JOD: 3,
|
|
||||||
JPY: 0,
|
|
||||||
KMF: 0,
|
|
||||||
KRW: 0,
|
|
||||||
KWD: 3,
|
|
||||||
LYD: 3,
|
|
||||||
OMR: 3,
|
|
||||||
PYG: 0,
|
|
||||||
RWF: 0,
|
|
||||||
TND: 3,
|
|
||||||
UGX: 0,
|
|
||||||
UYI: 0,
|
|
||||||
VND: 0,
|
|
||||||
VUV: 0,
|
|
||||||
XAF: 0,
|
|
||||||
XOF: 0,
|
|
||||||
XPF: 0
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of decimal digits to be used for the given currency.
|
* Returns the number of decimal digits to be used for the given currency.
|
||||||
*
|
*
|
||||||
|
|
@ -2100,7 +2106,7 @@ function numberFormatFormatToBind(value) {
|
||||||
|
|
||||||
// Step 1.a.ii-iii.
|
// Step 1.a.ii-iii.
|
||||||
var x = ToNumber(value);
|
var x = ToNumber(value);
|
||||||
return intl_FormatNumber(this, x);
|
return intl_FormatNumber(this, x, /* formatToParts = */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2127,6 +2133,22 @@ function Intl_NumberFormat_format_get() {
|
||||||
// Step 2.
|
// Step 2.
|
||||||
return internals.boundFormat;
|
return internals.boundFormat;
|
||||||
}
|
}
|
||||||
|
_SetCanonicalName(Intl_NumberFormat_format_get, "get format");
|
||||||
|
|
||||||
|
|
||||||
|
function Intl_NumberFormat_formatToParts(value) {
|
||||||
|
// Step 1.
|
||||||
|
var nf = this;
|
||||||
|
|
||||||
|
// Steps 2-3.
|
||||||
|
getNumberFormatInternals(nf, "formatToParts");
|
||||||
|
|
||||||
|
// Step 4.
|
||||||
|
var x = ToNumber(value);
|
||||||
|
|
||||||
|
// Step 5.
|
||||||
|
return intl_FormatNumber(nf, x, /* formatToParts = */ true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -2268,26 +2290,6 @@ function getDateTimeFormatInternals(obj, methodName) {
|
||||||
return internalProps;
|
return internalProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Components of date and time formats and their values.
|
|
||||||
*
|
|
||||||
* Spec: ECMAScript Internationalization API Specification, 12.1.1.
|
|
||||||
*/
|
|
||||||
var dateTimeComponentValues = {
|
|
||||||
weekday: ["narrow", "short", "long"],
|
|
||||||
era: ["narrow", "short", "long"],
|
|
||||||
year: ["2-digit", "numeric"],
|
|
||||||
month: ["2-digit", "numeric", "narrow", "short", "long"],
|
|
||||||
day: ["2-digit", "numeric"],
|
|
||||||
hour: ["2-digit", "numeric"],
|
|
||||||
minute: ["2-digit", "numeric"],
|
|
||||||
second: ["2-digit", "numeric"],
|
|
||||||
timeZoneName: ["short", "long"]
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
var dateTimeComponents = std_Object_getOwnPropertyNames(dateTimeComponentValues);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes an object as a DateTimeFormat.
|
* Initializes an object as a DateTimeFormat.
|
||||||
|
|
@ -2377,12 +2379,19 @@ function InitializeDateTimeFormat(dateTimeFormat, locales, options) {
|
||||||
lazyDateTimeFormatData.formatOpt = formatOpt;
|
lazyDateTimeFormatData.formatOpt = formatOpt;
|
||||||
|
|
||||||
// Step 19.
|
// Step 19.
|
||||||
var i, prop;
|
// 12.1, Table 4: Components of date and time formats.
|
||||||
for (i = 0; i < dateTimeComponents.length; i++) {
|
formatOpt.weekday = GetOption(options, "weekday", "string", ["narrow", "short", "long"],
|
||||||
prop = dateTimeComponents[i];
|
undefined);
|
||||||
var value = GetOption(options, prop, "string", dateTimeComponentValues[prop], undefined);
|
formatOpt.era = GetOption(options, "era", "string", ["narrow", "short", "long"], undefined);
|
||||||
formatOpt[prop] = value;
|
formatOpt.year = GetOption(options, "year", "string", ["2-digit", "numeric"], undefined);
|
||||||
}
|
formatOpt.month = GetOption(options, "month", "string",
|
||||||
|
["2-digit", "numeric", "narrow", "short", "long"], undefined);
|
||||||
|
formatOpt.day = GetOption(options, "day", "string", ["2-digit", "numeric"], undefined);
|
||||||
|
formatOpt.hour = GetOption(options, "hour", "string", ["2-digit", "numeric"], undefined);
|
||||||
|
formatOpt.minute = GetOption(options, "minute", "string", ["2-digit", "numeric"], undefined);
|
||||||
|
formatOpt.second = GetOption(options, "second", "string", ["2-digit", "numeric"], undefined);
|
||||||
|
formatOpt.timeZoneName = GetOption(options, "timeZoneName", "string", ["short", "long"],
|
||||||
|
undefined);
|
||||||
|
|
||||||
// Steps 20-21 provided by ICU - see comment after this function.
|
// Steps 20-21 provided by ICU - see comment after this function.
|
||||||
|
|
||||||
|
|
@ -2650,7 +2659,6 @@ function ToDateTimeOptions(options, required, defaults) {
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares the date and time components requested by options with the available
|
* Compares the date and time components requested by options with the available
|
||||||
* date and time formats in formats, and selects the best match according
|
* date and time formats in formats, and selects the best match according
|
||||||
|
|
@ -2836,6 +2844,7 @@ function Intl_DateTimeFormat_format_get() {
|
||||||
// Step 2.
|
// Step 2.
|
||||||
return internals.boundFormat;
|
return internals.boundFormat;
|
||||||
}
|
}
|
||||||
|
_SetCanonicalName(Intl_DateTimeFormat_format_get, "get format");
|
||||||
|
|
||||||
|
|
||||||
function Intl_DateTimeFormat_formatToParts() {
|
function Intl_DateTimeFormat_formatToParts() {
|
||||||
|
|
@ -2971,6 +2980,232 @@ function resolveICUPattern(pattern, result) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/********** Intl.PluralRules **********/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PluralRules internal properties.
|
||||||
|
*
|
||||||
|
* Spec: ECMAScript 402 API, PluralRules, 1.3.3.
|
||||||
|
*/
|
||||||
|
var pluralRulesInternalProperties = {
|
||||||
|
_availableLocales: null,
|
||||||
|
availableLocales: function()
|
||||||
|
{
|
||||||
|
var locales = this._availableLocales;
|
||||||
|
if (locales)
|
||||||
|
return locales;
|
||||||
|
|
||||||
|
locales = intl_PluralRules_availableLocales();
|
||||||
|
addSpecialMissingLanguageTags(locales);
|
||||||
|
return (this._availableLocales = locales);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute an internal properties object from |lazyPluralRulesData|.
|
||||||
|
*/
|
||||||
|
function resolvePluralRulesInternals(lazyPluralRulesData) {
|
||||||
|
assert(IsObject(lazyPluralRulesData), "lazy data not an object?");
|
||||||
|
|
||||||
|
var internalProps = std_Object_create(null);
|
||||||
|
|
||||||
|
var requestedLocales = lazyPluralRulesData.requestedLocales;
|
||||||
|
|
||||||
|
var PluralRules = pluralRulesInternalProperties;
|
||||||
|
|
||||||
|
// Step 13.
|
||||||
|
const r = ResolveLocale(callFunction(PluralRules.availableLocales, PluralRules),
|
||||||
|
lazyPluralRulesData.requestedLocales,
|
||||||
|
lazyPluralRulesData.opt,
|
||||||
|
noRelevantExtensionKeys, undefined);
|
||||||
|
|
||||||
|
// Step 14.
|
||||||
|
internalProps.locale = r.locale;
|
||||||
|
internalProps.type = lazyPluralRulesData.type;
|
||||||
|
|
||||||
|
internalProps.pluralCategories = intl_GetPluralCategories(
|
||||||
|
internalProps.locale,
|
||||||
|
internalProps.type);
|
||||||
|
|
||||||
|
internalProps.minimumIntegerDigits = lazyPluralRulesData.minimumIntegerDigits;
|
||||||
|
internalProps.minimumFractionDigits = lazyPluralRulesData.minimumFractionDigits;
|
||||||
|
internalProps.maximumFractionDigits = lazyPluralRulesData.maximumFractionDigits;
|
||||||
|
|
||||||
|
if ("minimumSignificantDigits" in lazyPluralRulesData) {
|
||||||
|
assert("maximumSignificantDigits" in lazyPluralRulesData, "min/max sig digits mismatch");
|
||||||
|
internalProps.minimumSignificantDigits = lazyPluralRulesData.minimumSignificantDigits;
|
||||||
|
internalProps.maximumSignificantDigits = lazyPluralRulesData.maximumSignificantDigits;
|
||||||
|
}
|
||||||
|
|
||||||
|
return internalProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an object containing the PluralRules internal properties of |obj|,
|
||||||
|
* or throws a TypeError if |obj| isn't PluralRules-initialized.
|
||||||
|
*/
|
||||||
|
function getPluralRulesInternals(obj, methodName) {
|
||||||
|
var internals = getIntlObjectInternals(obj, "PluralRules", methodName);
|
||||||
|
assert(internals.type === "PluralRules", "bad type escaped getIntlObjectInternals");
|
||||||
|
|
||||||
|
var internalProps = maybeInternalProperties(internals);
|
||||||
|
if (internalProps)
|
||||||
|
return internalProps;
|
||||||
|
|
||||||
|
internalProps = resolvePluralRulesInternals(internals.lazyData);
|
||||||
|
setInternalProperties(internals, internalProps);
|
||||||
|
return internalProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes an object as a PluralRules.
|
||||||
|
*
|
||||||
|
* This method is complicated a moderate bit by its implementing initialization
|
||||||
|
* as a *lazy* concept. Everything that must happen now, does -- but we defer
|
||||||
|
* all the work we can until the object is actually used as a PluralRules.
|
||||||
|
* This later work occurs in |resolvePluralRulesInternals|; steps not noted
|
||||||
|
* here occur there.
|
||||||
|
*
|
||||||
|
* Spec: ECMAScript 402 API, PluralRules, 1.1.1.
|
||||||
|
*/
|
||||||
|
function InitializePluralRules(pluralRules, locales, options) {
|
||||||
|
assert(IsObject(pluralRules), "InitializePluralRules");
|
||||||
|
|
||||||
|
// Step 1.
|
||||||
|
if (isInitializedIntlObject(pluralRules))
|
||||||
|
ThrowTypeError(JSMSG_INTL_OBJECT_REINITED);
|
||||||
|
|
||||||
|
let internals = initializeIntlObject(pluralRules);
|
||||||
|
|
||||||
|
// Lazy PluralRules data has the following structure:
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// requestedLocales: List of locales,
|
||||||
|
// type: "cardinal" / "ordinal",
|
||||||
|
//
|
||||||
|
// opt: // opt object computer in InitializePluralRules
|
||||||
|
// {
|
||||||
|
// localeMatcher: "lookup" / "best fit",
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// minimumIntegerDigits: integer ∈ [1, 21],
|
||||||
|
// minimumFractionDigits: integer ∈ [0, 20],
|
||||||
|
// maximumFractionDigits: integer ∈ [0, 20],
|
||||||
|
//
|
||||||
|
// // optional
|
||||||
|
// minimumSignificantDigits: integer ∈ [1, 21],
|
||||||
|
// maximumSignificantDigits: integer ∈ [1, 21],
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Note that lazy data is only installed as a final step of initialization,
|
||||||
|
// so every PluralRules lazy data object has *all* these properties, never a
|
||||||
|
// subset of them.
|
||||||
|
const lazyPluralRulesData = std_Object_create(null);
|
||||||
|
|
||||||
|
// Step 3.
|
||||||
|
let requestedLocales = CanonicalizeLocaleList(locales);
|
||||||
|
lazyPluralRulesData.requestedLocales = requestedLocales;
|
||||||
|
|
||||||
|
// Steps 4-5.
|
||||||
|
if (options === undefined)
|
||||||
|
options = {};
|
||||||
|
else
|
||||||
|
options = ToObject(options);
|
||||||
|
|
||||||
|
// Step 6.
|
||||||
|
const type = GetOption(options, "type", "string", ["cardinal", "ordinal"], "cardinal");
|
||||||
|
lazyPluralRulesData.type = type;
|
||||||
|
|
||||||
|
// Step 8.
|
||||||
|
let opt = new Record();
|
||||||
|
lazyPluralRulesData.opt = opt;
|
||||||
|
|
||||||
|
// Steps 9-10.
|
||||||
|
let matcher = GetOption(options, "localeMatcher", "string", ["lookup", "best fit"], "best fit");
|
||||||
|
opt.localeMatcher = matcher;
|
||||||
|
|
||||||
|
// Steps 11-12.
|
||||||
|
SetNumberFormatDigitOptions(lazyPluralRulesData, options, 0, 3);
|
||||||
|
|
||||||
|
setLazyData(internals, "PluralRules", lazyPluralRulesData)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the subset of the given locale list for which this locale list has a
|
||||||
|
* matching (possibly fallback) locale. Locales appear in the same order in the
|
||||||
|
* returned list as in the input list.
|
||||||
|
*
|
||||||
|
* Spec: ECMAScript 402 API, PluralRules, 1.3.2.
|
||||||
|
*/
|
||||||
|
function Intl_PluralRules_supportedLocalesOf(locales /*, options*/) {
|
||||||
|
var options = arguments.length > 1 ? arguments[1] : undefined;
|
||||||
|
|
||||||
|
// Step 1.
|
||||||
|
var availableLocales = callFunction(pluralRulesInternalProperties.availableLocales,
|
||||||
|
pluralRulesInternalProperties);
|
||||||
|
// Step 2.
|
||||||
|
let requestedLocales = CanonicalizeLocaleList(locales);
|
||||||
|
|
||||||
|
// Step 3.
|
||||||
|
return SupportedLocales(availableLocales, requestedLocales, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a String value representing the plural category matching
|
||||||
|
* the number passed as value according to the
|
||||||
|
* effective locale and the formatting options of this PluralRules.
|
||||||
|
*
|
||||||
|
* Spec: ECMAScript 402 API, PluralRules, 1.4.3.
|
||||||
|
*/
|
||||||
|
function Intl_PluralRules_select(value) {
|
||||||
|
// Step 1.
|
||||||
|
let pluralRules = this;
|
||||||
|
// Step 2.
|
||||||
|
let internals = getPluralRulesInternals(pluralRules, "select");
|
||||||
|
|
||||||
|
// Steps 3-4.
|
||||||
|
let n = ToNumber(value);
|
||||||
|
|
||||||
|
// Step 5.
|
||||||
|
return intl_SelectPluralRule(pluralRules, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the resolved options for a PluralRules object.
|
||||||
|
*
|
||||||
|
* Spec: ECMAScript 402 API, PluralRules, 1.4.4.
|
||||||
|
*/
|
||||||
|
function Intl_PluralRules_resolvedOptions() {
|
||||||
|
var internals = getPluralRulesInternals(this, "resolvedOptions");
|
||||||
|
|
||||||
|
var internalsPluralCategories = internals.pluralCategories;
|
||||||
|
var pluralCategories = [];
|
||||||
|
for (var i = 0; i < internalsPluralCategories.length; i++)
|
||||||
|
_DefineDataProperty(pluralCategories, i, internalsPluralCategories[i]);
|
||||||
|
|
||||||
|
var result = {
|
||||||
|
locale: internals.locale,
|
||||||
|
type: internals.type,
|
||||||
|
pluralCategories,
|
||||||
|
minimumIntegerDigits: internals.minimumIntegerDigits,
|
||||||
|
minimumFractionDigits: internals.minimumFractionDigits,
|
||||||
|
maximumFractionDigits: internals.maximumFractionDigits,
|
||||||
|
};
|
||||||
|
|
||||||
|
var optionalProperties = [
|
||||||
|
"minimumSignificantDigits",
|
||||||
|
"maximumSignificantDigits"
|
||||||
|
];
|
||||||
|
|
||||||
|
for (var i = 0; i < optionalProperties.length; i++) {
|
||||||
|
var p = optionalProperties[i];
|
||||||
|
if (callFunction(std_Object_hasOwnProperty, internals, p))
|
||||||
|
_DefineDataProperty(result, p, internals[p]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function Intl_getCanonicalLocales(locales) {
|
function Intl_getCanonicalLocales(locales) {
|
||||||
let codes = CanonicalizeLocaleList(locales);
|
let codes = CanonicalizeLocaleList(locales);
|
||||||
let result = [];
|
let result = [];
|
||||||
|
|
@ -3006,3 +3241,126 @@ function Intl_getCalendarInfo(locales) {
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is a custom method designed after Intl API, but currently
|
||||||
|
* not part of the spec or spec proposal.
|
||||||
|
* We want to use it internally to retrieve translated values from CLDR in
|
||||||
|
* order to ensure they're aligned with what Intl API returns.
|
||||||
|
*
|
||||||
|
* This API may one day be a foundation for an ECMA402 API spec proposal.
|
||||||
|
*
|
||||||
|
* The function takes two arguments - locales which is a list of locale strings
|
||||||
|
* and options which is an object with two optional properties:
|
||||||
|
*
|
||||||
|
* keys:
|
||||||
|
* an Array of string values that are paths to individual terms
|
||||||
|
*
|
||||||
|
* style:
|
||||||
|
* a String with a value "long", "short" or "narrow"
|
||||||
|
*
|
||||||
|
* It returns an object with properties:
|
||||||
|
*
|
||||||
|
* locale:
|
||||||
|
* a negotiated locale string
|
||||||
|
*
|
||||||
|
* style:
|
||||||
|
* negotiated style
|
||||||
|
*
|
||||||
|
* values:
|
||||||
|
* A key-value pair list of requested keys and corresponding
|
||||||
|
* translated values
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function Intl_getDisplayNames(locales, options) {
|
||||||
|
// 1. Let requestLocales be ? CanonicalizeLocaleList(locales).
|
||||||
|
const requestedLocales = CanonicalizeLocaleList(locales);
|
||||||
|
|
||||||
|
// 2. If options is undefined, then
|
||||||
|
if (options === undefined)
|
||||||
|
// a. Let options be ObjectCreate(%ObjectPrototype%).
|
||||||
|
options = {};
|
||||||
|
// 3. Else,
|
||||||
|
else
|
||||||
|
// a. Let options be ? ToObject(options).
|
||||||
|
options = ToObject(options);
|
||||||
|
|
||||||
|
const DateTimeFormat = dateTimeFormatInternalProperties;
|
||||||
|
|
||||||
|
// 4. Let localeData be %DateTimeFormat%.[[localeData]].
|
||||||
|
const localeData = DateTimeFormat.localeData;
|
||||||
|
|
||||||
|
// 5. Let opt be a new Record.
|
||||||
|
const localeOpt = new Record();
|
||||||
|
// 6. Set localeOpt.[[localeMatcher]] to "best fit".
|
||||||
|
localeOpt.localeMatcher = "best fit";
|
||||||
|
|
||||||
|
// 7. Let r be ResolveLocale(%DateTimeFormat%.[[availableLocales]], requestedLocales, localeOpt,
|
||||||
|
// %DateTimeFormat%.[[relevantExtensionKeys]], localeData).
|
||||||
|
const r = ResolveLocale(callFunction(DateTimeFormat.availableLocales, DateTimeFormat),
|
||||||
|
requestedLocales,
|
||||||
|
localeOpt,
|
||||||
|
DateTimeFormat.relevantExtensionKeys,
|
||||||
|
localeData);
|
||||||
|
|
||||||
|
// 8. Let style be ? GetOption(options, "style", "string", « "long", "short", "narrow" », "long").
|
||||||
|
const style = GetOption(options, "style", "string", ["long", "short", "narrow"], "long");
|
||||||
|
// 9. Let keys be ? Get(options, "keys").
|
||||||
|
let keys = options.keys;
|
||||||
|
|
||||||
|
// 10. If keys is undefined,
|
||||||
|
if (keys === undefined) {
|
||||||
|
// a. Let keys be ArrayCreate(0).
|
||||||
|
keys = [];
|
||||||
|
} else if (!IsObject(keys)) {
|
||||||
|
// 11. Else,
|
||||||
|
// a. If Type(keys) is not Object, throw a TypeError exception.
|
||||||
|
ThrowTypeError(JSMSG_INVALID_KEYS_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 12. Let processedKeys be ArrayCreate(0).
|
||||||
|
// (This really should be a List, but we use an Array here in order that
|
||||||
|
// |intl_ComputeDisplayNames| may infallibly access the list's length via
|
||||||
|
// |ArrayObject::length|.)
|
||||||
|
let processedKeys = [];
|
||||||
|
// 13. Let len be ? ToLength(? Get(keys, "length")).
|
||||||
|
let len = ToLength(keys.length);
|
||||||
|
// 14. Let i be 0.
|
||||||
|
// 15. Repeat, while i < len
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
// a. Let processedKey be ? ToString(? Get(keys, i)).
|
||||||
|
// b. Perform ? CreateDataPropertyOrThrow(processedKeys, i, processedKey).
|
||||||
|
callFunction(std_Array_push, processedKeys, ToString(keys[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 16. Let names be ? ComputeDisplayNames(r.[[locale]], style, processedKeys).
|
||||||
|
const names = intl_ComputeDisplayNames(r.locale, style, processedKeys);
|
||||||
|
|
||||||
|
// 17. Let values be ObjectCreate(%ObjectPrototype%).
|
||||||
|
const values = {};
|
||||||
|
|
||||||
|
// 18. Set i to 0.
|
||||||
|
// 19. Repeat, while i < len
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
// a. Let key be ? Get(processedKeys, i).
|
||||||
|
const key = processedKeys[i];
|
||||||
|
// b. Let name be ? Get(names, i).
|
||||||
|
const name = names[i];
|
||||||
|
// c. Assert: Type(name) is string.
|
||||||
|
assert(typeof name === "string", "unexpected non-string value");
|
||||||
|
// d. Assert: the length of name is greater than zero.
|
||||||
|
assert(name.length > 0, "empty string value");
|
||||||
|
// e. Perform ? DefinePropertyOrThrow(values, key, name).
|
||||||
|
_DefineDataProperty(values, key, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 20. Let options be ObjectCreate(%ObjectPrototype%).
|
||||||
|
// 21. Perform ! DefinePropertyOrThrow(result, "locale", r.[[locale]]).
|
||||||
|
// 22. Perform ! DefinePropertyOrThrow(result, "style", style).
|
||||||
|
// 23. Perform ! DefinePropertyOrThrow(result, "values", values).
|
||||||
|
const result = { locale: r.locale, style, values };
|
||||||
|
|
||||||
|
// 24. Return result.
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
// |reftest| skip-if(!this.hasOwnProperty("Intl")||!this.hasOwnProperty("addIntlExtras"))
|
||||||
|
|
||||||
|
// Tests the PluralRules.resolvedOptions function for overriden Array[Symbol.species].
|
||||||
|
|
||||||
|
addIntlExtras(Intl);
|
||||||
|
|
||||||
|
var pl = new Intl.PluralRules("de");
|
||||||
|
|
||||||
|
Object.defineProperty(Array, Symbol.species, {
|
||||||
|
value: function() {
|
||||||
|
return new Proxy(["?"], {
|
||||||
|
get(t, pk, r) {
|
||||||
|
return Reflect.get(t, pk, r);
|
||||||
|
},
|
||||||
|
defineProperty(t, pk) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var pluralCategories = pl.resolvedOptions().pluralCategories;
|
||||||
|
|
||||||
|
assertEqArray(pluralCategories, ["one", "other"]);
|
||||||
|
|
||||||
|
if (typeof reportCompare === "function")
|
||||||
|
reportCompare(0, 0);
|
||||||
23
js/src/tests/Intl/getCanonicalLocales-overridden-species.js
Normal file
23
js/src/tests/Intl/getCanonicalLocales-overridden-species.js
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
// |reftest| skip-if(!this.hasOwnProperty("Intl"))
|
||||||
|
|
||||||
|
// Tests the getCanonicalLocales function for overriden Array[Symbol.species].
|
||||||
|
|
||||||
|
Object.defineProperty(Array, Symbol.species, {
|
||||||
|
value: function() {
|
||||||
|
return new Proxy(["?"], {
|
||||||
|
get(t, pk, r) {
|
||||||
|
return Reflect.get(t, pk, r);
|
||||||
|
},
|
||||||
|
defineProperty(t, pk) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var arr = Intl.getCanonicalLocales("de-x-private");
|
||||||
|
|
||||||
|
assertEqArray(arr, ["de-x-private"]);
|
||||||
|
|
||||||
|
if (typeof reportCompare === "function")
|
||||||
|
reportCompare(0, 0);
|
||||||
Loading…
Add table
Add a link
Reference in a new issue