summaryrefslogtreecommitdiffstats
path: root/js/src/builtin/intl/PluralRules.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--js/src/builtin/intl/PluralRules.js390
1 files changed, 390 insertions, 0 deletions
diff --git a/js/src/builtin/intl/PluralRules.js b/js/src/builtin/intl/PluralRules.js
new file mode 100644
index 0000000000..a90fc32d0b
--- /dev/null
+++ b/js/src/builtin/intl/PluralRules.js
@@ -0,0 +1,390 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * PluralRules internal properties.
+ *
+ * Spec: ECMAScript 402 API, PluralRules, 13.3.3.
+ */
+var pluralRulesInternalProperties = {
+ localeData: pluralRulesLocaleData,
+ relevantExtensionKeys: [],
+};
+
+function pluralRulesLocaleData() {
+ // PluralRules don't support any extension keys.
+ return {};
+}
+
+/**
+ * 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 PluralRules = pluralRulesInternalProperties;
+
+ // Compute effective locale.
+
+ // Step 10.
+ var localeData = PluralRules.localeData;
+
+ // Step 11.
+ const r = ResolveLocale(
+ "PluralRules",
+ lazyPluralRulesData.requestedLocales,
+ lazyPluralRulesData.opt,
+ PluralRules.relevantExtensionKeys,
+ localeData
+ );
+
+ // Step 12.
+ internalProps.locale = r.locale;
+
+ // Step 8.
+ internalProps.type = lazyPluralRulesData.type;
+
+ // Step 9.
+ internalProps.minimumIntegerDigits = lazyPluralRulesData.minimumIntegerDigits;
+
+ if ("minimumFractionDigits" in lazyPluralRulesData) {
+ assert(
+ "maximumFractionDigits" in lazyPluralRulesData,
+ "min/max frac digits mismatch"
+ );
+ 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;
+ }
+
+ // Intl.NumberFormat v3 Proposal
+ internalProps.roundingPriority = lazyPluralRulesData.roundingPriority;
+
+ // Step 13 (lazily computed on first access).
+ internalProps.pluralCategories = null;
+
+ return internalProps;
+}
+
+/**
+ * Returns an object containing the PluralRules internal properties of |obj|.
+ */
+function getPluralRulesInternals(obj) {
+ assert(IsObject(obj), "getPluralRulesInternals called with non-object");
+ assert(
+ intl_GuardToPluralRules(obj) !== null,
+ "getPluralRulesInternals called with non-PluralRules"
+ );
+
+ var internals = getIntlObjectInternals(obj);
+ 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, 13.1.1.
+ */
+function InitializePluralRules(pluralRules, locales, options) {
+ assert(IsObject(pluralRules), "InitializePluralRules called with non-object");
+ assert(
+ intl_GuardToPluralRules(pluralRules) !== null,
+ "InitializePluralRules called with non-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],
+ //
+ // // optional, mutually exclusive with the significant-digits option
+ // minimumFractionDigits: integer ∈ [0, 20],
+ // maximumFractionDigits: integer ∈ [0, 20],
+ //
+ // // optional, mutually exclusive with the fraction-digits option
+ // minimumSignificantDigits: integer ∈ [1, 21],
+ // maximumSignificantDigits: integer ∈ [1, 21],
+ //
+ // roundingPriority: "auto" / "lessPrecision" / "morePrecision",
+ // }
+ //
+ // 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 1.
+ let requestedLocales = CanonicalizeLocaleList(locales);
+ lazyPluralRulesData.requestedLocales = requestedLocales;
+
+ // Steps 2-3.
+ if (options === undefined) {
+ options = std_Object_create(null);
+ } else {
+ options = ToObject(options);
+ }
+
+ // Step 4.
+ let opt = new_Record();
+ lazyPluralRulesData.opt = opt;
+
+ // Steps 5-6.
+ let matcher = GetOption(
+ options,
+ "localeMatcher",
+ "string",
+ ["lookup", "best fit"],
+ "best fit"
+ );
+ opt.localeMatcher = matcher;
+
+ // Step 7.
+ const type = GetOption(
+ options,
+ "type",
+ "string",
+ ["cardinal", "ordinal"],
+ "cardinal"
+ );
+ lazyPluralRulesData.type = type;
+
+ // Step 9.
+ SetNumberFormatDigitOptions(lazyPluralRulesData, options, 0, 3, "standard");
+
+ // Step 15.
+ //
+ // We've done everything that must be done now: mark the lazy data as fully
+ // computed and install it.
+ initializeIntlObject(pluralRules, "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, 13.3.2.
+ */
+function Intl_PluralRules_supportedLocalesOf(locales /*, options*/) {
+ var options = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
+
+ // Step 1.
+ var availableLocales = "PluralRules";
+
+ // 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, 13.4.3.
+ */
+function Intl_PluralRules_select(value) {
+ // Step 1.
+ let pluralRules = this;
+
+ // Steps 2-3.
+ if (
+ !IsObject(pluralRules) ||
+ (pluralRules = intl_GuardToPluralRules(pluralRules)) === null
+ ) {
+ return callFunction(
+ intl_CallPluralRulesMethodIfWrapped,
+ this,
+ value,
+ "Intl_PluralRules_select"
+ );
+ }
+
+ // Step 4.
+ let n = ToNumber(value);
+
+ // Ensure the PluralRules internals are resolved.
+ getPluralRulesInternals(pluralRules);
+
+ // Step 5.
+ return intl_SelectPluralRule(pluralRules, n);
+}
+
+/**
+ * Returns a String value representing the plural category matching the input
+ * number range according to the effective locale and the formatting options
+ * of this PluralRules.
+ */
+function Intl_PluralRules_selectRange(start, end) {
+ // Step 1.
+ var pluralRules = this;
+
+ // Step 2.
+ if (
+ !IsObject(pluralRules) ||
+ (pluralRules = intl_GuardToPluralRules(pluralRules)) === null
+ ) {
+ return callFunction(
+ intl_CallPluralRulesMethodIfWrapped,
+ this,
+ start,
+ end,
+ "Intl_PluralRules_selectRange"
+ );
+ }
+
+ // Step 3.
+ if (start === undefined || end === undefined) {
+ ThrowTypeError(
+ JSMSG_UNDEFINED_NUMBER,
+ start === undefined ? "start" : "end",
+ "PluralRules",
+ "selectRange"
+ );
+ }
+
+ // Step 4.
+ var x = ToNumber(start);
+
+ // Step 5.
+ var y = ToNumber(end);
+
+ // Step 6.
+ return intl_SelectPluralRuleRange(pluralRules, x, y);
+}
+
+/**
+ * Returns the resolved options for a PluralRules object.
+ *
+ * Spec: ECMAScript 402 API, PluralRules, 13.4.4.
+ */
+function Intl_PluralRules_resolvedOptions() {
+ // Step 1.
+ var pluralRules = this;
+
+ // Steps 2-3.
+ if (
+ !IsObject(pluralRules) ||
+ (pluralRules = intl_GuardToPluralRules(pluralRules)) === null
+ ) {
+ return callFunction(
+ intl_CallPluralRulesMethodIfWrapped,
+ this,
+ "Intl_PluralRules_resolvedOptions"
+ );
+ }
+
+ var internals = getPluralRulesInternals(pluralRules);
+
+ // Steps 4-5.
+ var result = {
+ locale: internals.locale,
+ type: internals.type,
+ minimumIntegerDigits: internals.minimumIntegerDigits,
+ };
+
+ // Min/Max fraction digits are either both present or not present at all.
+ assert(
+ hasOwn("minimumFractionDigits", internals) ===
+ hasOwn("maximumFractionDigits", internals),
+ "minimumFractionDigits is present iff maximumFractionDigits is present"
+ );
+
+ if (hasOwn("minimumFractionDigits", internals)) {
+ DefineDataProperty(
+ result,
+ "minimumFractionDigits",
+ internals.minimumFractionDigits
+ );
+ DefineDataProperty(
+ result,
+ "maximumFractionDigits",
+ internals.maximumFractionDigits
+ );
+ }
+
+ // Min/Max significant digits are either both present or not present at all.
+ assert(
+ hasOwn("minimumSignificantDigits", internals) ===
+ hasOwn("maximumSignificantDigits", internals),
+ "minimumSignificantDigits is present iff maximumSignificantDigits is present"
+ );
+
+ if (hasOwn("minimumSignificantDigits", internals)) {
+ DefineDataProperty(
+ result,
+ "minimumSignificantDigits",
+ internals.minimumSignificantDigits
+ );
+ DefineDataProperty(
+ result,
+ "maximumSignificantDigits",
+ internals.maximumSignificantDigits
+ );
+ }
+
+ // Step 6.
+ var internalsPluralCategories = internals.pluralCategories;
+ if (internalsPluralCategories === null) {
+ internalsPluralCategories = intl_GetPluralCategories(pluralRules);
+ internals.pluralCategories = internalsPluralCategories;
+ }
+
+ var pluralCategories = [];
+ for (var i = 0; i < internalsPluralCategories.length; i++) {
+ DefineDataProperty(pluralCategories, i, internalsPluralCategories[i]);
+ }
+
+ // Step 7.
+ DefineDataProperty(result, "pluralCategories", pluralCategories);
+
+#ifdef NIGHTLY_BUILD
+ DefineDataProperty(result, "roundingPriority", internals.roundingPriority);
+#endif
+
+ // Step 8.
+ return result;
+}