Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FF116 Intl.PluralRules - NumFormat v3 #28097

Merged
merged 10 commits into from
Jul 28, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,25 @@ browser-compat: javascript.builtins.Intl.PluralRules

The **`Intl.PluralRules`** object enables plural-sensitive formatting and plural-related language rules.

## Concepts and usage
hamishwillee marked this conversation as resolved.
Show resolved Hide resolved
hamishwillee marked this conversation as resolved.
Show resolved Hide resolved

Languages use different patterns for expressing both plural numbers of items (cardinal numbers) and for expressing the order of items (ordinal numbers).
English has two forms for expressing cardinal numbers: one for the singular "item" (1 hour, 1 dog, 1 fish) and the other for zero or any other number of "items" (0 hours, 2 lemmings, 100000.5 fish), while Chinese has only one form, and Arabic has six!
Similarly, English has four forms for ordinal numbers: "th", "st", "nd", "rd", giving the sequence: 0th, 1st, 2nd, 3rd, 4th, 5th, ..., 21st, 22nd, 23rd, 24th, 25th, and so on, while both Chinese and Arabic only have one form for ordinal numbers.
hamishwillee marked this conversation as resolved.
Show resolved Hide resolved

The plural rules methods [`PluralRules.select()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/PluralRules/select) and [`PluralRules.selectRange()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/PluralRules/selectRange) return a _tag_ that represents the plural form of a particular cardinal or ordinal number, or range, for a particular language and set of formatting options.
hamishwillee marked this conversation as resolved.
Show resolved Hide resolved
Code can use the returned tags to format strings appropriately for the given language and number/range.
hamishwillee marked this conversation as resolved.
Show resolved Hide resolved

The full set of tags that might be returned are: `zero`, `one`, `two`, `few`, `many`, `other` (the "general" plural form, used if the language only has one form).
hamishwillee marked this conversation as resolved.
Show resolved Hide resolved
As English only has two forms for cardinal numbers, the `PluralRules.select()` method return only two tags: `"one"` for the singular case, and `"other"` for all other cardinal numbers.
hamishwillee marked this conversation as resolved.
Show resolved Hide resolved
This allows constructions of sentences that make sense in English: "1 dog _is_ happy" and "10 dogs _are_ happy", or "1 fish _is_ golden" and "10 fish _are_ golden".
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very interesting, because when people think of "plural" they usually think of changing the noun itself. I think you would want to point out that there are three kinds of variation in pluralization:

  1. Inflection of the noun itself: dog–dogs
  2. Inflection of the verb (if there's agreement in pluralization): is–are
  3. Inflection of the referent: it–them

And even if the noun itself never changes, the other two variations would also be accounted as a different pluralization. The CLDR spec also talks about this.


`PluralRules.select()` can return any of four tags for ordinal numbers in English, representing each of the allowed forms: `one` for "st" numbers (1, 21, 31, ...), `two` for "nd" numbers (2, 22, 32, ...), `few` for "rd" numbers (3, 33, 43, ...), and `other` for "th" numbers (0, 4-20, etc.).
hamishwillee marked this conversation as resolved.
Show resolved Hide resolved
Again, the returned tags allow appropriate formatting of strings describing an ordinal number.

For more information about the rules and how they are used see [Plural Rules](https://cldr.unicode.org/index/cldr-spec/plural-rules).
For a list of the rules and how they apply for different languages see the [LDML Language Plural Rules](https://www.unicode.org/cldr/charts/43/supplemental/language_plural_rules.html).
hamishwillee marked this conversation as resolved.
Show resolved Hide resolved

## Constructor

- {{jsxref("Intl/PluralRules/PluralRules", "Intl.PluralRules()")}}
Expand Down Expand Up @@ -41,21 +60,72 @@ These properties are defined on `Intl.PluralRules.prototype` and shared by all `

### Using locales

This example shows some of the variations in localized plural rules. In order to get the format of the language used in the user interface of your application, make sure to specify that language (and possibly some fallback languages) using the `locales` argument:
This example shows some of the variations in localized plural rules for cardinal numbers.

In order to get the format for the language used in the user interface of your application, make sure to specify that language (and possibly some fallback languages) using the [constructor `locales`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/PluralRules/PluralRules#locales) argument:

```js
// US English
const enCardinalRules = new Intl.PluralRules("en-US");
console.log(enCardinalRules.select(0)); // > "other"
console.log(enCardinalRules.select(1)); // > "one"
console.log(enCardinalRules.select(2)); // > "other"
console.log(enCardinalRules.select(3)); // > "other"

// Arabic
const arCardinalRules = new Intl.PluralRules("ar-EG");
console.log(arCardinalRules.select(0)); // > "zero"
console.log(arCardinalRules.select(1)); // > "one"
console.log(arCardinalRules.select(2)); // > "two"
console.log(arCardinalRules.select(6)); // > "few"
console.log(arCardinalRules.select(18)); // > "many"
hamishwillee marked this conversation as resolved.
Show resolved Hide resolved
```

### Using options

The plural form of the specified number may also depend on [constructor `options`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/PluralRules/PluralRules#locales), such as how the number is rounded, and whether it is cardinal or ordinal.
Josh-Cena marked this conversation as resolved.
Show resolved Hide resolved

This example shows how you can set the type of rules to "ordinal", and how this affects the form for some numbers in US English.

```js
// US English - ordinal
const enOrdinalRules = new Intl.PluralRules("en-US", { type: "ordinal" });
console.log(enOrdinalRules.select(0)); // > "other" (0th)
console.log(enOrdinalRules.select(1)); // > "one" (1st)
console.log(enOrdinalRules.select(2)); // > "two" (2nd)
console.log(enOrdinalRules.select(3)); // > "few" (3rd)
console.log(enOrdinalRules.select(4)); // > "other" (4th)
console.log(enOrdinalRules.select(21)); // > "one" (21st)
hamishwillee marked this conversation as resolved.
Show resolved Hide resolved
```

### Formatting text using the returned tag

The code below extends the previous example, showing how you might use the returned tag for an ordinal number to format text in English.

```js
// Arabic has different plural rules

new Intl.PluralRules("ar-EG").select(0);
// → 'zero'
new Intl.PluralRules("ar-EG").select(1);
// → 'one'
new Intl.PluralRules("ar-EG").select(2);
// → 'two'
new Intl.PluralRules("ar-EG").select(6);
// → 'few'
new Intl.PluralRules("ar-EG").select(18);
// → 'many'
const enOrdinalRules = new Intl.PluralRules("en-US", { type: "ordinal" });

const suffixes = new Map([
["one", "st"],
["two", "nd"],
["few", "rd"],
["other", "th"],
]);
const formatOrdinals = (n) => {
const rule = enOrdinalRules.select(n);
const suffix = suffixes.get(rule);
return `${n}${suffix}`;
};

formatOrdinals(0); // '0th'
formatOrdinals(1); // '1st'
formatOrdinals(2); // '2nd'
formatOrdinals(3); // '3rd'
formatOrdinals(4); // '4th'
formatOrdinals(11); // '11th'
formatOrdinals(21); // '21st'
formatOrdinals(42); // '42nd'
formatOrdinals(103); // '103rd'
```

## Specifications
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,58 +28,72 @@ new Intl.PluralRules(locales, options)
- : An object with some or all of the following properties:

- `localeMatcher`
- : The locale matching algorithm to use. Possible values are
`"lookup"` and `"best fit"`; the default is
`"best fit"`. For information about this option, see the
{{jsxref("Global_Objects/Intl", "Intl", "#locale_identification_and_negotiation", 1)}} page.
- : The locale matching algorithm to use. Possible values are `"lookup"` and `"best fit"`; the default is
`"best fit"`. For information about this option, see the {{jsxref("Global_Objects/Intl", "Intl", "#locale_identification_and_negotiation", 1)}} page.
- `type`

- : The type to use. Possible values are:

- `"cardinal"` for cardinal numbers (referring to the
quantity of things). This is the default value.
- `"ordinal"` for ordinal number (referring to the
ordering or ranking of things, e.g. "1st", "2nd", "3rd" in
English).
- `"cardinal"` for cardinal numbers (referring to the quantity of things). This is the default value.
- `"ordinal"` for ordinal number (referring to the ordering or ranking of things, e.g. "1st", "2nd", "3rd" in English).

- `roundingMode` {{experimental_inline}}

- : Specifies how fractional values are rounded.
hamishwillee marked this conversation as resolved.
Show resolved Hide resolved
The options are are: `"ceil"`, `"floor"`, `"expand"`, `"trunc"`, `"halfCeil"`, `"halfFloor"`, `"halfExpand"` (default), `"halfTrunc"`, `"halfEven"`.
The meanings of the values are documented in more detail in the corresponding [`Intl.NumberFormat` constructor](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#roundingmode) option.

- `roundingPriority` {{experimental_inline}}

- : Specify how rounding conflicts will be resolved if both "FractionDigits" ([`minimumFractionDigits`](#minimumfractiondigits)/[`maximumFractionDigits`](#maximumfractiondigits)) and "SignificantDigits" ([`minimumSignificantDigits`](#minimumsignificantdigits)/[`maximumSignificantDigits`](#maximumsignificantdigits)) are specified:

- `"auto"`: the result from the significant digits property is used (default).
- `"morePrecision"`: the result from the property that results in more precision is used.
- `"lessPrecision"`: the result from the property that results in less precision is used.

Note that for values other than `auto` the result with more precision is calculated from the [`maximumSignificantDigits`](#minimumsignificantdigits) and [`maximumFractionDigits`](#maximumfractiondigits) (minimum fractional and significant digit settings are ignored).

- `roundingIncrement` {{experimental_inline}}

- : Specifies the rounding-increment precision.
Must be one of the following integers:
`1`, `2`, `5`, `10`, `20`, `25`, `50`, `100`, `200`, `250`, `500`, `1000`, `2000`, `2500`, `5000`.
The behavior is described in more detail in the corresponding [`Intl.NumberFormat` constructor](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#roundingincrement) option.

- `trailingZeroDisplay` {{experimental_inline}}

- : A string expressing the strategy for displaying trailing zeros on whole numbers.
The default is `"auto"`.

- `"auto"`: keep trailing zeros according to `minimumFractionDigits` and `minimumSignificantDigits`.
- `"stripIfInteger"`: remove the fraction digits _if_ they are all zero.
This is the same as `auto` if any of the fraction digits is non-zero.

The following properties fall into two groups:
`minimumIntegerDigits`, `minimumFractionDigits`, and
`maximumFractionDigits` in one group,
`minimumSignificantDigits` and
`maximumSignificantDigits` in the other. If at least one property
from the second group is defined, then the first group is ignored.
`minimumIntegerDigits`, `minimumFractionDigits`, and `maximumFractionDigits` in one group, and `minimumSignificantDigits` and `maximumSignificantDigits` in the other. If at least one property from the second group is defined, then the first group is ignored.

- `minimumIntegerDigits`
- : The minimum number of integer digits to use. Possible values are from 1 to
21; the default is 1.
- : The minimum number of integer digits to use. Possible values are from 1 to 21; the default is 1.
- `minimumFractionDigits`
- : The minimum number of fraction digits to use. Possible values are from 0
to 20; the default for plain number and percent formatting is 0; the
default for currency formatting is the number of minor unit digits
provided by the [ISO 4217 currency code list](https://www.six-group.com/dam/download/financial-information/data-center/iso-currrency/lists/list-one.xml)
(2 if the list doesn't provide that information).
- : The minimum number of fraction digits to use. Possible values are from 0 to 20;
the default for plain number and percent formatting is 0;
the default for currency formatting is the number of minor unit digits provided by the [ISO 4217 currency code list](https://www.six-group.com/dam/download/financial-information/data-center/iso-currrency/lists/list-one.xml) (2 if the list doesn't provide that information).
- `maximumFractionDigits`
- : The maximum number of fraction digits to use. Possible values are from 0
to 20; the default for plain number formatting is the larger of
`minimumFractionDigits` and 3; the default for currency
formatting is the larger of `minimumFractionDigits` and the
number of minor unit digits provided by the [ISO 4217 currency code list](https://www.six-group.com/dam/download/financial-information/data-center/iso-currrency/lists/list-one.xml)
(2 if the list doesn't provide that information); the default for percent formatting is the larger of
`minimumFractionDigits` and 0.
- : The maximum number of fraction digits to use.
Possible values are from 0 to 20; the default for plain number formatting is the larger of `minimumFractionDigits` and 3; the default for currency formatting is the larger of `minimumFractionDigits` and the number of minor unit digits provided by the [ISO 4217 currency code list](https://www.six-group.com/dam/download/financial-information/data-center/iso-currrency/lists/list-one.xml) (2 if the list doesn't provide that information); the default for percent formatting is the larger of `minimumFractionDigits` and 0.
- `minimumSignificantDigits`
- : The minimum number of significant digits to use. Possible values are from
1 to 21; the default is 1.
- : The minimum number of significant digits to use.
Possible values are from 1 to 21; the default is 1.
- `maximumSignificantDigits`
- : The maximum number of significant digits to use. Possible values are from
1 to 21; the default is 21.
- : The maximum number of significant digits to use.
Possible values are from 1 to 21; the default is 21.

## Examples

### Basic usage

In basic use without specifying a locale, a formatted string in the default locale and
with default options is returned. This is useful to distinguish between singular and
plural forms, e.g. "dog" and "dogs".
In basic use without specifying a locale, a formatted string in the default locale and with default options is returned.
This is useful to distinguish between singular and plural forms, e.g. "dog" and "dogs".

```js
const pr = new Intl.PluralRules();
Expand All @@ -93,9 +107,7 @@ pr.select(2); // 'other' if in US English locale

### Using options

The results can be customized using the `options` argument, which has one
property called `type` which you can set to `ordinal`. This is
useful to figure out the ordinal indicator, e.g. "1st", "2nd", "3rd", "4th", "42nd"
The results can be customized using the `options` argument, which has one property called `type` which you can set to `ordinal`. This is useful to figure out the ordinal indicator, e.g. "1st", "2nd", "3rd", "4th", "42nd"
Josh-Cena marked this conversation as resolved.
Show resolved Hide resolved
and so forth.

```js
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,51 +17,73 @@ The **`resolvedOptions()`** method of {{jsxref("Intl.PluralRules")}} instances r
resolvedOptions()
```

### Return value
### Parameters

None.

A new object with properties reflecting the locale and plural formatting options
computed during the initialization of the given {{jsxref("Intl.PluralRules")}} object.
### Return value

## Description
A new object with properties reflecting the locale and plural formatting options computed during the initialization of the given {{jsxref("Intl.PluralRules")}} object.

The resulting object has the following properties:
The object has the following properties:

- `locale`
- : The BCP 47 language tag for the locale actually used. If any Unicode extension
values were requested in the input BCP 47 language tag that led to this locale,
the key-value pairs that were requested and are supported for this locale are
included in `locale`.
- : The BCP 47 language tag for the locale actually used. If any Unicode extension values were requested in the input BCP 47 language tag that led to this locale, the key-value pairs that were requested and are supported for this locale are included in `locale`.
- `pluralCategories`
- : An {{jsxref("Array")}} of plural categories used by the given locale, selected from the list `"zero"`, `"one"`, `"two"`, `"few"`, `"many"` and `"other"`.
- `type`

- : The type used (`cardinal` or `ordinal`).

- `roundingMode` {{experimental_inline}}
- : The rounding mode.
This is the value provided for the [`options.roundingMode`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/PluralRules/PluralRules#roundingmode) argument in the constructor, or the default value: `halfExpand`.
- `roundingPriority` {{experimental_inline}}
- : The priority for resolving rounding conflicts if both "FractionDigits" and "SignificantDigits" are specified.
This is the value provided for the [`options.roundingPriority`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/PluralRules/PluralRules#roundingpriority) argument in the constructor, or the default value: `auto`.
- `roundingIncrement` {{experimental_inline}}
- : The rounding-increment precision (the increment used when rounding numbers).
This is the value specified in the [`options.roundingIncrement`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/PluralRules/PluralRules#roundingincrement) argument in the constructor.
- `trailingZeroDisplay` {{experimental_inline}}
- : The strategy for displaying trailing zeros on whole numbers.
This is the value specified in the [`options.trailingZeroDisplay`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/PluralRules/PluralRules#trailingzerodisplay) argument in the constructor, or the default value: `"auto"`.

Only one of the following two groups of properties is included:

- `minimumIntegerDigits`, `minimumFractionDigits`, `maximumFractionDigits`
- : The values provided for these properties in the `options` argument or
filled in as defaults. These properties are present only if neither
`minimumSignificantDigits` nor `maximumSignificantDigits`
was provided in the `options` argument.
- : The values provided for these properties in the `options` argument or filled in as defaults.
These properties are present only if neither `minimumSignificantDigits` nor `maximumSignificantDigits` was provided in the `options` argument.
- `minimumSignificantDigits`, `maximumSignificantDigits`
- : The values provided for these properties in the `options` argument or
filled in as defaults. These properties are present only if at least one of them
was provided in the `options` argument.
- : The values provided for these properties in the `options` argument or filled in as defaults.
These properties are present only if at least one of them was provided in the `options` argument.

## Examples

### Using the resolvedOptions() method

The code below shows the construction of a `PluralRules` object, followed by logging of each of the resolved options.

```js
const de = new Intl.PluralRules("de-DE");
const usedOptions = de.resolvedOptions();
// Create a PluralRules instance
const de = new Intl.PluralRules("de-DE", {
maximumSignificantDigits: 2,
trailingZeroDisplay: "auto",
});

usedOptions.locale; // "de-DE"
usedOptions.maximumFractionDigits; // 3
usedOptions.minimumFractionDigits; // 0
usedOptions.minimumIntegerDigits; // 1
usedOptions.pluralCategories; // [ "one", "other" ]
usedOptions.type; // "cardinal"
// Resolve the options
const usedOptions = de.resolvedOptions();
console.log(usedOptions.locale); // "de-DE"
console.log(usedOptions.pluralCategories); // Array ["one", "other"]
console.log(usedOptions.type); // "cardinal"
console.log(usedOptions.minimumIntegerDigits); // 1
console.log(usedOptions.minimumFractionDigits); // undefined (maximumSignificantDigits is set)
console.log(usedOptions.maximumFractionDigits); //undefined (maximumSignificantDigits is set)
console.log(usedOptions.minimumSignificantDigits); // 1
console.log(usedOptions.maximumSignificantDigits); //2
console.log(usedOptions.roundingIncrement); // 1
console.log(usedOptions.roundingMode); // "halfExpand"
console.log(usedOptions.roundingPriority); // "auto"
console.log(usedOptions.trailingZeroDisplay); // "auto"
```

## Specifications
Expand Down
Loading