summaryrefslogtreecommitdiffstats
path: root/js/src/builtin/intl/PluralRules.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/builtin/intl/PluralRules.js')
-rw-r--r--js/src/builtin/intl/PluralRules.js440
1 files changed, 440 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..1dbf6656df
--- /dev/null
+++ b/js/src/builtin/intl/PluralRules.js
@@ -0,0 +1,440 @@
+/* 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.
+ *
+ * 9.1 Internal slots of Service Constructors
+ * 16.2.3 Properties of the Intl.PluralRules Constructor, Internal slots
+ *
+ * ES2024 Intl draft rev 74ca7099f103d143431b2ea422ae640c6f43e3e6
+ */
+var pluralRulesInternalProperties = {
+ localeData: pluralRulesLocaleData,
+ relevantExtensionKeys: [],
+};
+
+function pluralRulesLocaleData() {
+ // PluralRules don't support any extension keys.
+ return {};
+}
+
+/**
+ * 16.1.2 InitializePluralRules ( pluralRules, locales, options )
+ *
+ * Compute an internal properties object from |lazyPluralRulesData|.
+ *
+ * ES2024 Intl draft rev 74ca7099f103d143431b2ea422ae640c6f43e3e6
+ */
+function resolvePluralRulesInternals(lazyPluralRulesData) {
+ assert(IsObject(lazyPluralRulesData), "lazy data not an object?");
+
+ var internalProps = std_Object_create(null);
+
+ var PluralRules = pluralRulesInternalProperties;
+
+ // Compute effective locale.
+
+ // Step 9.
+ var localeData = PluralRules.localeData;
+
+ // Step 10.
+ var r = ResolveLocale(
+ "PluralRules",
+ lazyPluralRulesData.requestedLocales,
+ lazyPluralRulesData.opt,
+ PluralRules.relevantExtensionKeys,
+ localeData
+ );
+
+ // Step 11.
+ internalProps.locale = r.locale;
+
+ // Step 7.
+ internalProps.type = lazyPluralRulesData.type;
+
+ // Step 8. SetNumberFormatDigitOptions, step 6.
+ internalProps.minimumIntegerDigits = lazyPluralRulesData.minimumIntegerDigits;
+
+ // Step 8. SetNumberFormatDigitOptions, step 14.
+ internalProps.roundingIncrement = lazyPluralRulesData.roundingIncrement;
+
+ // Step 8. SetNumberFormatDigitOptions, step 15.
+ internalProps.roundingMode = lazyPluralRulesData.roundingMode;
+
+ // Step 8. SetNumberFormatDigitOptions, step 16.
+ internalProps.trailingZeroDisplay = lazyPluralRulesData.trailingZeroDisplay;
+
+ // Step 8. SetNumberFormatDigitOptions, steps 25-26.
+ if ("minimumFractionDigits" in lazyPluralRulesData) {
+ assert(
+ "maximumFractionDigits" in lazyPluralRulesData,
+ "min/max frac digits mismatch"
+ );
+ internalProps.minimumFractionDigits =
+ lazyPluralRulesData.minimumFractionDigits;
+ internalProps.maximumFractionDigits =
+ lazyPluralRulesData.maximumFractionDigits;
+ }
+
+ // Step 8. SetNumberFormatDigitOptions, steps 24 and 26.
+ if ("minimumSignificantDigits" in lazyPluralRulesData) {
+ assert(
+ "maximumSignificantDigits" in lazyPluralRulesData,
+ "min/max sig digits mismatch"
+ );
+ internalProps.minimumSignificantDigits =
+ lazyPluralRulesData.minimumSignificantDigits;
+ internalProps.maximumSignificantDigits =
+ lazyPluralRulesData.maximumSignificantDigits;
+ }
+
+ // Step 8. SetNumberFormatDigitOptions, steps 26-30.
+ internalProps.roundingPriority = lazyPluralRulesData.roundingPriority;
+
+ // `pluralCategories` is 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;
+}
+
+/**
+ * 16.1.2 InitializePluralRules ( pluralRules, locales, options )
+ *
+ * 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.
+ *
+ * ES2024 Intl draft rev 74ca7099f103d143431b2ea422ae640c6f43e3e6
+ */
+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, 100],
+ // maximumFractionDigits: integer ∈ [0, 100],
+ //
+ // // optional, mutually exclusive with the fraction-digits option
+ // minimumSignificantDigits: integer ∈ [1, 21],
+ // maximumSignificantDigits: integer ∈ [1, 21],
+ //
+ // roundingPriority: "auto" / "lessPrecision" / "morePrecision",
+ //
+ // trailingZeroDisplay: "auto" / "stripIfInteger",
+ //
+ // roundingIncrement: integer ∈ (1, 2, 5,
+ // 10, 20, 25, 50,
+ // 100, 200, 250, 500,
+ // 1000, 2000, 2500, 5000),
+ //
+ // roundingMode: "ceil" / "floor" / "expand" / "trunc" /
+ // "halfCeil" / "halfFloor" / "halfExpand" / "halfTrunc" / "halfEven",
+ // }
+ //
+ // 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.
+ var lazyPluralRulesData = std_Object_create(null);
+
+ // Step 1.
+ var requestedLocales = CanonicalizeLocaleList(locales);
+ lazyPluralRulesData.requestedLocales = requestedLocales;
+
+ // Step 2. (Inlined call to CoerceOptionsToObject.)
+ if (options === undefined) {
+ options = std_Object_create(null);
+ } else {
+ options = ToObject(options);
+ }
+
+ // Step 3.
+ var opt = new_Record();
+ lazyPluralRulesData.opt = opt;
+
+ // Steps 4-5.
+ var matcher = GetOption(
+ options,
+ "localeMatcher",
+ "string",
+ ["lookup", "best fit"],
+ "best fit"
+ );
+ opt.localeMatcher = matcher;
+
+ // Steps 6-7.
+ var type = GetOption(
+ options,
+ "type",
+ "string",
+ ["cardinal", "ordinal"],
+ "cardinal"
+ );
+ lazyPluralRulesData.type = type;
+
+ // Step 8.
+ SetNumberFormatDigitOptions(lazyPluralRulesData, options, 0, 3, "standard");
+
+ // Step 12.
+ //
+ // We've done everything that must be done now: mark the lazy data as fully
+ // computed and install it.
+ initializeIntlObject(pluralRules, "PluralRules", lazyPluralRulesData);
+}
+
+/**
+ * 16.2.2 Intl.PluralRules.supportedLocalesOf ( locales [ , options ] )
+ *
+ * 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.
+ *
+ * ES2024 Intl draft rev 74ca7099f103d143431b2ea422ae640c6f43e3e6
+ */
+function Intl_PluralRules_supportedLocalesOf(locales /*, options*/) {
+ var options = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
+
+ // Step 1.
+ var availableLocales = "PluralRules";
+
+ // Step 2.
+ var requestedLocales = CanonicalizeLocaleList(locales);
+
+ // Step 3.
+ return SupportedLocales(availableLocales, requestedLocales, options);
+}
+
+/**
+ * 16.3.3 Intl.PluralRules.prototype.select ( value )
+ *
+ * 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.
+ *
+ * ES2024 Intl draft rev 74ca7099f103d143431b2ea422ae640c6f43e3e6
+ */
+function Intl_PluralRules_select(value) {
+ // Step 1.
+ var pluralRules = this;
+
+ // Step 2.
+ if (
+ !IsObject(pluralRules) ||
+ (pluralRules = intl_GuardToPluralRules(pluralRules)) === null
+ ) {
+ return callFunction(
+ intl_CallPluralRulesMethodIfWrapped,
+ this,
+ value,
+ "Intl_PluralRules_select"
+ );
+ }
+
+ // Step 3.
+ var n = ToNumber(value);
+
+ // Ensure the PluralRules internals are resolved.
+ getPluralRulesInternals(pluralRules);
+
+ // Step 4.
+ return intl_SelectPluralRule(pluralRules, n);
+}
+
+/**
+ * 16.3.4 Intl.PluralRules.prototype.selectRange ( start, end )
+ *
+ * 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.
+ *
+ * ES2024 Intl draft rev 74ca7099f103d143431b2ea422ae640c6f43e3e6
+ */
+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);
+}
+
+/**
+ * 16.3.5 Intl.PluralRules.prototype.resolvedOptions ( )
+ *
+ * Returns the resolved options for a PluralRules object.
+ *
+ * ES2024 Intl draft rev 74ca7099f103d143431b2ea422ae640c6f43e3e6
+ */
+function Intl_PluralRules_resolvedOptions() {
+ // Step 1.
+ var pluralRules = this;
+
+ // Step 2.
+ if (
+ !IsObject(pluralRules) ||
+ (pluralRules = intl_GuardToPluralRules(pluralRules)) === null
+ ) {
+ return callFunction(
+ intl_CallPluralRulesMethodIfWrapped,
+ this,
+ "Intl_PluralRules_resolvedOptions"
+ );
+ }
+
+ var internals = getPluralRulesInternals(pluralRules);
+
+ // Steps 3-4.
+ 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
+ );
+ }
+
+ DefineDataProperty(result, "roundingMode", internals.roundingMode);
+ DefineDataProperty(result, "roundingIncrement", internals.roundingIncrement);
+ DefineDataProperty(
+ result,
+ "trailingZeroDisplay",
+ internals.trailingZeroDisplay
+ );
+
+ // Step 5.
+ 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 6.
+ DefineDataProperty(result, "pluralCategories", pluralCategories);
+
+ // Steps 7-9.
+ //
+ // Our implementation doesn't use [[RoundingType]], but instead directly
+ // stores the computed `roundingPriority` value.
+ DefineDataProperty(result, "roundingPriority", internals.roundingPriority);
+
+ // Step 10.
+ return result;
+}