From 98455821a766bba12a0a20b04fccb38beca31512 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Sat, 26 Oct 2024 15:34:51 -0700 Subject: [PATCH 01/19] Implement `:currency` function in the default registry Initial implementation of the `:currency` function. This function will be `optional` in 2.0. Not behavior differences from `:number` and `:integer`. `:unit` to follow. --- spec/registry.md | 197 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 135 insertions(+), 62 deletions(-) diff --git a/spec/registry.md b/spec/registry.md index eb8fb62972..d34f9c2ed9 100644 --- a/spec/registry.md +++ b/spec/registry.md @@ -171,37 +171,6 @@ with _options_ on the _expression_ taking priority over any option values of the > would be formatted with the resolved options > `{ notation: 'scientific', minimumFractionDigits: '1' }`. -> [!NOTE] -> The following options and option values are being developed during the Technical Preview -> period. - -The following values for the option `style` are _not_ part of the default registry. -Implementations SHOULD avoid creating options that conflict with these, but -are encouraged to track development of these options during Tech Preview: -- `currency` -- `unit` - -The following options are _not_ part of the default registry. -Implementations SHOULD avoid creating options that conflict with these, but -are encouraged to track development of these options during Tech Preview: -- `currency` - - valid [Unicode Currency Identifier](https://cldr-smoke.unicode.org/spec/main/ldml/tr35.html#UnicodeCurrencyIdentifier) - (no default) -- `currencyDisplay` - - `symbol` (default) - - `narrowSymbol` - - `code` - - `name` -- `currencySign` - - `accounting` - - `standard` (default) -- `unit` - - (anything not empty) -- `unitDisplay` - - `long` - - `short` (default) - - `narrow` - ##### Default Value of `select` Option The value `plural` is the default for the option `select` @@ -308,37 +277,6 @@ Option values with the following names are however discarded if included in the - `maximumFractionDigits` - `minimumSignificantDigits` -> [!NOTE] -> The following options and option values are being developed during the Technical Preview -> period. - -The following values for the option `style` are _not_ part of the default registry. -Implementations SHOULD avoid creating options that conflict with these, but -are encouraged to track development of these options during Tech Preview: -- `currency` -- `unit` - -The following options are _not_ part of the default registry. -Implementations SHOULD avoid creating options that conflict with these, but -are encouraged to track development of these options during Tech Preview: -- `currency` - - valid [Unicode Currency Identifier](https://cldr-smoke.unicode.org/spec/main/ldml/tr35.html#UnicodeCurrencyIdentifier) - (no default) -- `currencyDisplay` - - `symbol` (default) - - `narrowSymbol` - - `code` - - `name` -- `currencySign` - - `accounting` - - `standard` (default) -- `unit` - - (anything not empty) -- `unitDisplay` - - `long` - - `short` (default) - - `narrow` - ##### Default Value of `select` Option The value `plural` is the default for the option `select` @@ -384,6 +322,128 @@ its _resolved value_ contains the implementation-defined integer value of the _operand_ of the annotated _expression_, together with the resolved options' values. +## The `:currency` function + +The function `:currency` is a selector and formatter for currency values, +which are a specialized form of numeric selection and formatting. + +#### Operands + +The function `:currency` requires a [Currency Operand](#currency-operands) as its _operand_ +or a [Number Operand](#number-operands), if used with the _option_ `currency`. + +#### Options + +Some options do not have default values defined in this specification. +The defaults for these options are implementation-dependent. +In general, the default values for such options depend on the locale, +the currency, +the value of other options, or all of these. + +Fraction digits for currency values behave differently than for other numeric formatters. +The number of fraction digits displayed is usually set by the currency used. +For example, USD uses 2 fraction digits, while JPY uses none. +Setting `fractionDigits` to `none` makes the display and selection work similar to `:integer`. +Setting some other number of `fractionDigits` allows greater precision display +(such as when performing currency conversions or other specialized operations) + +> [!NOTE] +> The names of _options_ and their _values_ were derived from the +> [options](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#options) +> in JavaScript's `Intl.NumberFormat`. + +The following options and their values are required to be available on the function `:number`: +- `select` + - `plural` (default; see [Default Value of `select` Option](#default-value-of-select-option) below) + - `ordinal` + - `exact` +- `currency` + - valid [Unicode Currency Identifier](https://cldr-smoke.unicode.org/spec/main/ldml/tr35.html#UnicodeCurrencyIdentifier) + (no default) +- `compactDisplay` (this option only has meaning when combined with the option `notation=compact`) + - `short` (default) + - `long` +- `notation` + - `standard` (default) + - `compact` +- `numberingSystem` + - valid [Unicode Number System Identifier](https://cldr-smoke.unicode.org/spec/main/ldml/tr35.html#UnicodeNumberSystemIdentifier) + (default is locale-specific) +- `currencySign` + - `accounting` + - `standard` (default) +- `currencyDisplay` (this option's values are derived from those in ICU NumberFormatter) + - `auto` (default) + - `narrow` + - `short` + - `iso` + - `full` + - `formal` + - `variant` +- `useGrouping` + - `auto` (default) + - `always` + - `never` + - `min2` +- `minimumIntegerDigits` + - ([digit size option](#digit-size-options), default: `1`) +- `fractionDigits` (unlike number/integer formats, the fraction digits for currency formatting are fixed) + - `auto` (default) (the number of digits used by the currency) + - `none` + - ([digit size option](#digit-size-options)) +- `minimumSignificantDigits` + - ([digit size option](#digit-size-options)) +- `maximumSignificantDigits` + - ([digit size option](#digit-size-options)) + +If the _operand_ of the _expression_ is an implementation-defined type, +such as the _resolved value_ of an _expression_ with a `:currency` _annotation_, +it can include option values. +These are included in the resolved option values of the _expression_, +with _options_ on the _expression_ taking priority over any option values of the _operand_. + +> For example, the _placeholder_ in this _message_: +> ``` +> .input {$n :currency currency=USD fractionDigits=none} +> {{{$n :currency currencySign=accounting}}} +> ``` +> would be formatted with the resolved options +> `{ currencySign: 'accounting', fractionDigits: 'none', currency: 'USD' }`. + +##### Default Value of `select` Option + +The value `plural` is the default for the option `select` +because it is the most common use case for numeric selection. +It can be used for exact value matches but also allows for the grammatical needs of +languages using CLDR's plural rules. +This might not be noticeable in the source language (particularly English), +but can cause problems in target locales that the original developer is not considering. + +> For example, a naive developer might use a special message for the value `1` without +> considering a locale's need for a `one` plural: +> ``` +> .input {$var :currency} +> .match $var +> 1 {{You have one last chance}} +> one {{You have {$var} chance remaining}} +> * {{You have {$var} chances remaining}} +> ``` +> +> The `one` variant is needed by languages such as Polish or Russian. +> Such locales typically also require other keywords such as `two`, `few`, and `many`. + +#### Selection + +The _function_ `:currency` performs selection as described in [Number Selection](#number-selection) below. + +#### Composition + +When an _operand_ or an _option_ value uses a _variable_ annotated, +directly or indirectly, by a `:number` _annotation_, +its _resolved value_ contains an implementation-defined numerical value +of the _operand_ of the annotated _expression_, +together with the resolved options' values. + ### Number Operands The _operand_ of a number function is either an implementation-defined type or @@ -417,6 +477,19 @@ All other values produce a _Bad Operand_ error. > or the type `com.ibm.icu.util.CurrencyAmount` can be used to set the currency and related > options (such as the number of fraction digits). +### Currency Operands + +The _operand_ of the `:currency` function is an implementation-defined type that +contains a number and a currency code +or a map whose keys are `value` and `currency`. + +> [!NOTE] +> For example, in ICU4J, the type `com.ibm.icu.util.CurrencyAmount` can be used +> to set the currency. + +The _operand_ MAY be a [Number Operand](#number-operands), as long as the option `currency` +is provided. + ### Digit Size Options Some _options_ of number _functions_ are defined to take a "digit size option". From 81ded2a9c4679408a850bf983b67824c69cb8acd Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Sat, 26 Oct 2024 15:38:42 -0700 Subject: [PATCH 02/19] Fix some details --- spec/registry.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/registry.md b/spec/registry.md index d34f9c2ed9..371116f44e 100644 --- a/spec/registry.md +++ b/spec/registry.md @@ -324,10 +324,10 @@ together with the resolved options' values. ## The `:currency` function -The function `:currency` is a selector and formatter for currency values, +The function `:currency` is an OPTIONAL selector and formatter for currency values, which are a specialized form of numeric selection and formatting. -#### Operands +#### `:currency` Operands The function `:currency` requires a [Currency Operand](#currency-operands) as its _operand_ or a [Number Operand](#number-operands), if used with the _option_ `currency`. @@ -348,11 +348,11 @@ Setting some other number of `fractionDigits` allows greater precision display (such as when performing currency conversions or other specialized operations) > [!NOTE] -> The names of _options_ and their _values_ were derived from the +> Except where noted otherwise, the names of _options_ and their _values_ were derived from the > [options](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#options) > in JavaScript's `Intl.NumberFormat`. -The following options and their values are required to be available on the function `:number`: +The following options and their values are required to be available on the function `:currency`: - `select` - `plural` (default; see [Default Value of `select` Option](#default-value-of-select-option) below) - `ordinal` From ebd86789ee5b142d6c26cddaf0462c6aceeba8a5 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Sat, 26 Oct 2024 15:50:22 -0700 Subject: [PATCH 03/19] Clean up operand --- spec/registry.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/spec/registry.md b/spec/registry.md index 371116f44e..90314596e6 100644 --- a/spec/registry.md +++ b/spec/registry.md @@ -322,7 +322,7 @@ its _resolved value_ contains the implementation-defined integer value of the _operand_ of the annotated _expression_, together with the resolved options' values. -## The `:currency` function +### The `:currency` function The function `:currency` is an OPTIONAL selector and formatter for currency values, which are a specialized form of numeric selection and formatting. @@ -439,8 +439,8 @@ The _function_ `:currency` performs selection as described in [Number Selection] #### Composition When an _operand_ or an _option_ value uses a _variable_ annotated, -directly or indirectly, by a `:number` _annotation_, -its _resolved value_ contains an implementation-defined numerical value +directly or indirectly, by a `:currency` _annotation_, +its _resolved value_ contains an implementation-defined currency value of the _operand_ of the annotated _expression_, together with the resolved options' values. @@ -482,13 +482,20 @@ All other values produce a _Bad Operand_ error. The _operand_ of the `:currency` function is an implementation-defined type that contains a number and a currency code or a map whose keys are `value` and `currency`. +When the _operand_ is a map, the value of `value` MUST be a [Number Operand](#number-operands). +When the _operand_ is a map, the value of `currency` MUST be either a +valid [Unicode Currency Identifier](https://cldr-smoke.unicode.org/spec/main/ldml/tr35.html#UnicodeCurrencyIdentifier) +or an implementation-defined currency type. > [!NOTE] > For example, in ICU4J, the type `com.ibm.icu.util.CurrencyAmount` can be used -> to set the currency. +> to set the amount and currency. The _operand_ MAY be a [Number Operand](#number-operands), as long as the option `currency` is provided. +The option `currency` MUST NOT be used to override the currency of an implementation-defined type +or of a map containing a `currency` field. +Using this option in such a case results in a _Bad Option_ error. ### Digit Size Options From cec72a3795ed8162589dbae0dc4a4c1696e0def8 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Sun, 27 Oct 2024 10:13:08 -0700 Subject: [PATCH 04/19] Apply suggestions from code review Co-authored-by: Eemeli Aro --- spec/registry.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/spec/registry.md b/spec/registry.md index 90314596e6..745a3ae437 100644 --- a/spec/registry.md +++ b/spec/registry.md @@ -480,10 +480,8 @@ All other values produce a _Bad Operand_ error. ### Currency Operands The _operand_ of the `:currency` function is an implementation-defined type that -contains a number and a currency code -or a map whose keys are `value` and `currency`. -When the _operand_ is a map, the value of `value` MUST be a [Number Operand](#number-operands). -When the _operand_ is a map, the value of `currency` MUST be either a +contains a numerical `value` and a `currency` code. +The value of `currency` MUST be either a valid [Unicode Currency Identifier](https://cldr-smoke.unicode.org/spec/main/ldml/tr35.html#UnicodeCurrencyIdentifier) or an implementation-defined currency type. @@ -493,8 +491,7 @@ or an implementation-defined currency type. The _operand_ MAY be a [Number Operand](#number-operands), as long as the option `currency` is provided. -The option `currency` MUST NOT be used to override the currency of an implementation-defined type -or of a map containing a `currency` field. +The option `currency` MUST NOT be used to override the currency of an implementation-defined type. Using this option in such a case results in a _Bad Option_ error. ### Digit Size Options From 447bf1c42b8bc5882f3c365b4f9857ee6f502464 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Sun, 27 Oct 2024 10:21:36 -0700 Subject: [PATCH 05/19] Improve operand, remove excess repeated content --- spec/registry.md | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/spec/registry.md b/spec/registry.md index 745a3ae437..02b544f837 100644 --- a/spec/registry.md +++ b/spec/registry.md @@ -410,28 +410,6 @@ with _options_ on the _expression_ taking priority over any option values of the > would be formatted with the resolved options > `{ currencySign: 'accounting', fractionDigits: 'none', currency: 'USD' }`. -##### Default Value of `select` Option - -The value `plural` is the default for the option `select` -because it is the most common use case for numeric selection. -It can be used for exact value matches but also allows for the grammatical needs of -languages using CLDR's plural rules. -This might not be noticeable in the source language (particularly English), -but can cause problems in target locales that the original developer is not considering. - -> For example, a naive developer might use a special message for the value `1` without -> considering a locale's need for a `one` plural: -> ``` -> .input {$var :currency} -> .match $var -> 1 {{You have one last chance}} -> one {{You have {$var} chance remaining}} -> * {{You have {$var} chances remaining}} -> ``` -> -> The `one` variant is needed by languages such as Polish or Russian. -> Such locales typically also require other keywords such as `two`, `few`, and `many`. - #### Selection The _function_ `:currency` performs selection as described in [Number Selection](#number-selection) below. @@ -479,9 +457,10 @@ All other values produce a _Bad Operand_ error. ### Currency Operands -The _operand_ of the `:currency` function is an implementation-defined type that -contains a numerical `value` and a `currency` code. -The value of `currency` MUST be either a +The _operand_ of the `:currency` function is one or more implementation-defined types +each of which contains a numerical `value` and a `currency` +or a [Number Operand](#number-operands), if used with the _option_ `currency`. +The value of `currency` MUST be either a string containing a valid [Unicode Currency Identifier](https://cldr-smoke.unicode.org/spec/main/ldml/tr35.html#UnicodeCurrencyIdentifier) or an implementation-defined currency type. From c6ba0fd96ccb5f5d69dcf8fd74994621dae18d9b Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Sun, 27 Oct 2024 11:38:41 -0700 Subject: [PATCH 06/19] Eliminate unnecessary extra operand section --- spec/registry.md | 54 +++++++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/spec/registry.md b/spec/registry.md index 02b544f837..e3d72e7b54 100644 --- a/spec/registry.md +++ b/spec/registry.md @@ -327,10 +327,40 @@ together with the resolved options' values. The function `:currency` is an OPTIONAL selector and formatter for currency values, which are a specialized form of numeric selection and formatting. -#### `:currency` Operands +#### Operands + +The _operand_ of the `:currency` function can be one of any number of +implementation-defined types, +each of which contains a numerical `value` and a `currency`; +or it can be a [Number Operand](#number-operands), as long as the option +`currency` is provided. +The option `currency` MUST NOT be used to override the currency of an implementation-defined type. +Using this option in such a case results in a _Bad Option_ error. + +The value of the _operand_'s `currency` MUST be either a string containing a +valid [Unicode Currency Identifier](https://cldr-smoke.unicode.org/spec/main/ldml/tr35.html#UnicodeCurrencyIdentifier) +or an implementation-defined currency type. -The function `:currency` requires a [Currency Operand](#currency-operands) as its _operand_ -or a [Number Operand](#number-operands), if used with the _option_ `currency`. +A [Number Operand](#number-operands) without a `currency` _option_ results in a _Bad Operand_ error. + +> [!NOTE] +> For example, in ICU4J, the type `com.ibm.icu.util.CurrencyAmount` can be used +> to set the amount and currency. + +> [!NOTE] +> For runtime environments that do not provide a ready-made data structure, +> class, or type for currency values, the implementation ought to provide +> a data structure, convenience function, or documentation on how to encode +> the value and currency code for formatting. +> For example, such an implementation might define a "currency operand" +> to include a key-value structure with specific keys to be the +> local currency operand, which might look like the following: +> ```json +> "operandName": { +> "value": 123.45, +> "currency": "EUR" +> } +> ``` #### Options @@ -455,24 +485,6 @@ All other values produce a _Bad Operand_ error. > or the type `com.ibm.icu.util.CurrencyAmount` can be used to set the currency and related > options (such as the number of fraction digits). -### Currency Operands - -The _operand_ of the `:currency` function is one or more implementation-defined types -each of which contains a numerical `value` and a `currency` -or a [Number Operand](#number-operands), if used with the _option_ `currency`. -The value of `currency` MUST be either a string containing a -valid [Unicode Currency Identifier](https://cldr-smoke.unicode.org/spec/main/ldml/tr35.html#UnicodeCurrencyIdentifier) -or an implementation-defined currency type. - -> [!NOTE] -> For example, in ICU4J, the type `com.ibm.icu.util.CurrencyAmount` can be used -> to set the amount and currency. - -The _operand_ MAY be a [Number Operand](#number-operands), as long as the option `currency` -is provided. -The option `currency` MUST NOT be used to override the currency of an implementation-defined type. -Using this option in such a case results in a _Bad Option_ error. - ### Digit Size Options Some _options_ of number _functions_ are defined to take a "digit size option". From 221738738d0649ea7b4b2cb4f6f8d651a4bec15b Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Sun, 27 Oct 2024 11:45:01 -0700 Subject: [PATCH 07/19] Update spec/registry.md Co-authored-by: Eemeli Aro --- spec/registry.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/registry.md b/spec/registry.md index e3d72e7b54..5cd9557346 100644 --- a/spec/registry.md +++ b/spec/registry.md @@ -384,7 +384,7 @@ Setting some other number of `fractionDigits` allows greater precision display The following options and their values are required to be available on the function `:currency`: - `select` - - `plural` (default; see [Default Value of `select` Option](#default-value-of-select-option) below) + - `plural` (default) - `ordinal` - `exact` - `currency` From 241d44202bcb1f6fca97fff59b1ce9ef221f1e22 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Mon, 28 Oct 2024 09:51:06 -0700 Subject: [PATCH 08/19] Update spec/registry.md Co-authored-by: Eemeli Aro --- spec/registry.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/registry.md b/spec/registry.md index 5cd9557346..ad294d09a9 100644 --- a/spec/registry.md +++ b/spec/registry.md @@ -356,7 +356,7 @@ A [Number Operand](#number-operands) without a `currency` _option_ results in a > to include a key-value structure with specific keys to be the > local currency operand, which might look like the following: > ```json -> "operandName": { +> { > "value": 123.45, > "currency": "EUR" > } From 3f855fccc55a699fc27d13c1e156b0aabec388b0 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Mon, 28 Oct 2024 14:42:29 -0700 Subject: [PATCH 09/19] Changes from 2024-10-28 call --- spec/registry.md | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/spec/registry.md b/spec/registry.md index ad294d09a9..793076d9db 100644 --- a/spec/registry.md +++ b/spec/registry.md @@ -324,7 +324,7 @@ together with the resolved options' values. ### The `:currency` function -The function `:currency` is an OPTIONAL selector and formatter for currency values, +The function `:currency` is a selector and formatter for currency values, which are a specialized form of numeric selection and formatting. #### Operands @@ -373,9 +373,24 @@ the value of other options, or all of these. Fraction digits for currency values behave differently than for other numeric formatters. The number of fraction digits displayed is usually set by the currency used. For example, USD uses 2 fraction digits, while JPY uses none. -Setting `fractionDigits` to `none` makes the display and selection work similar to `:integer`. Setting some other number of `fractionDigits` allows greater precision display (such as when performing currency conversions or other specialized operations) +or disabling fraction digits if set to `0`. +The special _option_ _value_ `hideIfWhole` is used to display values without +fraction digits when the number of fraction digits is zero, +or based on the currency when the number of fraction digits for the currency is non-zero. +> For example, this _message_: +> ``` +> The special price is {$price :currency fractionDigits=hideIfWhole}. +> ``` +> When used with the value `5.00 USD` in the `en-US` locale displays as: +> ``` +> The special price is $5. +> ``` +> But like this when when value is `5.01 USD`: +> ``` +> The special price is $5.01. +> ``` > [!NOTE] > Except where noted otherwise, the names of _options_ and their _values_ were derived from the @@ -419,7 +434,7 @@ The following options and their values are required to be available on the funct - ([digit size option](#digit-size-options), default: `1`) - `fractionDigits` (unlike number/integer formats, the fraction digits for currency formatting are fixed) - `auto` (default) (the number of digits used by the currency) - - `none` + - `hideIfWhole` (see note above) - ([digit size option](#digit-size-options)) - `minimumSignificantDigits` - ([digit size option](#digit-size-options)) From 5b8176891f8ff9be31433955a4492b01505a83bf Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Mon, 4 Nov 2024 14:10:00 -0800 Subject: [PATCH 10/19] Changes due to 2024-11-04 call - Remove `ordinal` selector - Remove `currencyDisplay=auto` - Add `currencyDisplay=none` - Add documentation links for `currencyDisplay` - Add a note about implementation aliasing - Fix example to use `hideIfWhole` instead of invalid `none` option value --- spec/registry.md | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/spec/registry.md b/spec/registry.md index 793076d9db..03b4ad4cf2 100644 --- a/spec/registry.md +++ b/spec/registry.md @@ -392,15 +392,22 @@ or based on the currency when the number of fraction digits for the currency is > The special price is $5.01. > ``` +Implementations MAY internally alias option values that they do not have data or a backing implementation for. +Notably, the `currencyDisplay` option has a rich set of values that mirrors developments in CLDR data. +Some implementations might not be able to produce all of these formats for every currency. + > [!NOTE] > Except where noted otherwise, the names of _options_ and their _values_ were derived from the > [options](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#options) > in JavaScript's `Intl.NumberFormat`. +> [!NOTE] +> The option `select` does not accept the value `ordinal` because selecting +> currency values using ordinal rules makes no sense. + The following options and their values are required to be available on the function `:currency`: - `select` - `plural` (default) - - `ordinal` - `exact` - `currency` - valid [Unicode Currency Identifier](https://cldr-smoke.unicode.org/spec/main/ldml/tr35.html#UnicodeCurrencyIdentifier) @@ -417,14 +424,14 @@ The following options and their values are required to be available on the funct - `currencySign` - `accounting` - `standard` (default) -- `currencyDisplay` (this option's values are derived from those in ICU NumberFormatter) - - `auto` (default) +- `currencyDisplay` (this option's values are derived from those in ICU [NumberFormatter.UnitWidth](https://unicode-org.github.io/icu-docs/apidoc/released/icu4j/com/ibm/icu/number/NumberFormatter.UnitWidth.html)) - `narrow` - - `short` - - `iso` + - `short` (default) - `full` + - `iso` - `formal` - `variant` + - `none` (this is called `hidden` in ICU) - `useGrouping` - `auto` (default) - `always` @@ -449,11 +456,11 @@ with _options_ on the _expression_ taking priority over any option values of the > For example, the _placeholder_ in this _message_: > ``` -> .input {$n :currency currency=USD fractionDigits=none} +> .input {$n :currency currency=USD fractionDigits=hideIfWhole} > {{{$n :currency currencySign=accounting}}} > ``` > would be formatted with the resolved options -> `{ currencySign: 'accounting', fractionDigits: 'none', currency: 'USD' }`. +> `{ currencySign: 'accounting', fractionDigits: 'hideIfWhole', currency: 'USD' }`. #### Selection From d0c37ebf571a26b02cfde096e37b4c82e22a0002 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Tue, 5 Nov 2024 07:39:06 -0800 Subject: [PATCH 11/19] Make `currency` be well-formed Includes a note explaining this. --- spec/registry.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/spec/registry.md b/spec/registry.md index 03b4ad4cf2..25904f9a10 100644 --- a/spec/registry.md +++ b/spec/registry.md @@ -338,7 +338,7 @@ The option `currency` MUST NOT be used to override the currency of an implementa Using this option in such a case results in a _Bad Option_ error. The value of the _operand_'s `currency` MUST be either a string containing a -valid [Unicode Currency Identifier](https://cldr-smoke.unicode.org/spec/main/ldml/tr35.html#UnicodeCurrencyIdentifier) +well-formed [Unicode Currency Identifier](https://cldr-smoke.unicode.org/spec/main/ldml/tr35.html#UnicodeCurrencyIdentifier) or an implementation-defined currency type. A [Number Operand](#number-operands) without a `currency` _option_ results in a _Bad Operand_ error. @@ -347,6 +347,14 @@ A [Number Operand](#number-operands) without a `currency` _option_ results in a > For example, in ICU4J, the type `com.ibm.icu.util.CurrencyAmount` can be used > to set the amount and currency. +> [!NOTE] +> The `currency` is only required to be well-formed rather than checked for validity. +> This allows new currency codes to be defined +> (there are many recent examples of this occuring). +> It also avoids requiring implementations to check currency codes for validity, +> although implementations are permitted to emit _Bad Option_ or _Bad Operand_ for invalid codes. +> A well-formed currency code matches the regular expression `^[A-Z]{3}$`. + > [!NOTE] > For runtime environments that do not provide a ready-made data structure, > class, or type for currency values, the implementation ought to provide @@ -410,7 +418,7 @@ The following options and their values are required to be available on the funct - `plural` (default) - `exact` - `currency` - - valid [Unicode Currency Identifier](https://cldr-smoke.unicode.org/spec/main/ldml/tr35.html#UnicodeCurrencyIdentifier) + - well-formed [Unicode Currency Identifier](https://cldr-smoke.unicode.org/spec/main/ldml/tr35.html#UnicodeCurrencyIdentifier) (no default) - `compactDisplay` (this option only has meaning when combined with the option `notation=compact`) - `short` (default) From bbc7091bba3ccd355b8550535cd4b8b326990854 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Tue, 5 Nov 2024 12:34:47 -0800 Subject: [PATCH 12/19] Rename `currencyDisplay` values --- spec/registry.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/registry.md b/spec/registry.md index 25904f9a10..c555a5c5db 100644 --- a/spec/registry.md +++ b/spec/registry.md @@ -434,9 +434,9 @@ The following options and their values are required to be available on the funct - `standard` (default) - `currencyDisplay` (this option's values are derived from those in ICU [NumberFormatter.UnitWidth](https://unicode-org.github.io/icu-docs/apidoc/released/icu4j/com/ibm/icu/number/NumberFormatter.UnitWidth.html)) - `narrow` - - `short` (default) - - `full` - - `iso` + - `symbol` (default) + - `name` + - `code` - `formal` - `variant` - `none` (this is called `hidden` in ICU) From 8a9b63fad2b3b92a8625a10bfefb770df1a883bb Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Wed, 6 Nov 2024 07:19:04 -0800 Subject: [PATCH 13/19] Update spec/registry.md Co-authored-by: Eemeli Aro --- spec/registry.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/registry.md b/spec/registry.md index c555a5c5db..1493234530 100644 --- a/spec/registry.md +++ b/spec/registry.md @@ -433,7 +433,7 @@ The following options and their values are required to be available on the funct - `accounting` - `standard` (default) - `currencyDisplay` (this option's values are derived from those in ICU [NumberFormatter.UnitWidth](https://unicode-org.github.io/icu-docs/apidoc/released/icu4j/com/ibm/icu/number/NumberFormatter.UnitWidth.html)) - - `narrow` + - `narrowSymbol` - `symbol` (default) - `name` - `code` From b27e95f8973be06eb0ce463e366edae8f324f5e7 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Wed, 6 Nov 2024 07:28:28 -0800 Subject: [PATCH 14/19] Define "well-formed" currency code --- spec/registry.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/spec/registry.md b/spec/registry.md index 1493234530..c2e5be7c24 100644 --- a/spec/registry.md +++ b/spec/registry.md @@ -340,6 +340,12 @@ Using this option in such a case results in a _Bad Option_ error. The value of the _operand_'s `currency` MUST be either a string containing a well-formed [Unicode Currency Identifier](https://cldr-smoke.unicode.org/spec/main/ldml/tr35.html#UnicodeCurrencyIdentifier) or an implementation-defined currency type. +Although currency codes are expected to be uppercase, +implementations SHOULD treat them in a case-insensitive manner. +A well-formed Unicode Currency Identifier matches the production `currency_code` in this ABNF: +```abnf +currency_code = 3ALPHA +``` A [Number Operand](#number-operands) without a `currency` _option_ results in a _Bad Operand_ error. @@ -353,7 +359,6 @@ A [Number Operand](#number-operands) without a `currency` _option_ results in a > (there are many recent examples of this occuring). > It also avoids requiring implementations to check currency codes for validity, > although implementations are permitted to emit _Bad Option_ or _Bad Operand_ for invalid codes. -> A well-formed currency code matches the regular expression `^[A-Z]{3}$`. > [!NOTE] > For runtime environments that do not provide a ready-made data structure, @@ -363,7 +368,7 @@ A [Number Operand](#number-operands) without a `currency` _option_ results in a > For example, such an implementation might define a "currency operand" > to include a key-value structure with specific keys to be the > local currency operand, which might look like the following: -> ```json +> ``` > { > "value": 123.45, > "currency": "EUR" From 236b781f2a5958aeb93538f06674f83ed40b80ae Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Wed, 6 Nov 2024 11:06:30 -0800 Subject: [PATCH 15/19] Update spec/registry.md Co-authored-by: Eemeli Aro --- spec/registry.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/registry.md b/spec/registry.md index c2e5be7c24..8bfbe7d426 100644 --- a/spec/registry.md +++ b/spec/registry.md @@ -454,12 +454,14 @@ The following options and their values are required to be available on the funct - ([digit size option](#digit-size-options), default: `1`) - `fractionDigits` (unlike number/integer formats, the fraction digits for currency formatting are fixed) - `auto` (default) (the number of digits used by the currency) - - `hideIfWhole` (see note above) - ([digit size option](#digit-size-options)) - `minimumSignificantDigits` - ([digit size option](#digit-size-options)) - `maximumSignificantDigits` - ([digit size option](#digit-size-options)) +- `trailingZeroDisplay` + - `auto` (default) + - `stripIfInteger` If the _operand_ of the _expression_ is an implementation-defined type, such as the _resolved value_ of an _expression_ with a `:currency` _annotation_, From f3b2872387963a1076a9326e3f118dc46b0e7121 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Wed, 6 Nov 2024 11:15:32 -0800 Subject: [PATCH 16/19] Add `trailingZeroDisplay` option to :number and :currency --- spec/registry.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/spec/registry.md b/spec/registry.md index 8bfbe7d426..10579b8e6a 100644 --- a/spec/registry.md +++ b/spec/registry.md @@ -156,6 +156,9 @@ The following options and their values are required to be available on the funct - ([digit size option](#digit-size-options)) - `maximumSignificantDigits` - ([digit size option](#digit-size-options)) +- `trailingZeroDisplay` + - `auto` (default) + - `stripIfInteger` If the _operand_ of the _expression_ is an implementation-defined type, such as the _resolved value_ of an _expression_ with a `:number` or `:integer` _annotation_, @@ -389,12 +392,15 @@ For example, USD uses 2 fraction digits, while JPY uses none. Setting some other number of `fractionDigits` allows greater precision display (such as when performing currency conversions or other specialized operations) or disabling fraction digits if set to `0`. -The special _option_ _value_ `hideIfWhole` is used to display values without -fraction digits when the number of fraction digits is zero, -or based on the currency when the number of fraction digits for the currency is non-zero. + +The _option_ `trailingZeroDisplay` has a value `stripIfInteger` that is useful +for displaying currencies with their fraction digits removed when the fraction +part of the _operand_ is zero. +This is sometimes used in _messages_ to make the displayed value omit the fraction part +automatically. > For example, this _message_: > ``` -> The special price is {$price :currency fractionDigits=hideIfWhole}. +> The special price is {$price :currency trailingZeroDisplay=stripIfInteger}. > ``` > When used with the value `5.00 USD` in the `en-US` locale displays as: > ``` @@ -471,11 +477,11 @@ with _options_ on the _expression_ taking priority over any option values of the > For example, the _placeholder_ in this _message_: > ``` -> .input {$n :currency currency=USD fractionDigits=hideIfWhole} +> .input {$n :currency currency=USD trailingZeroDisplay=stripIfInteger} > {{{$n :currency currencySign=accounting}}} > ``` > would be formatted with the resolved options -> `{ currencySign: 'accounting', fractionDigits: 'hideIfWhole', currency: 'USD' }`. +> `{ currencySign: 'accounting', trailingZeroDisplay: 'stripIfInteger', currency: 'USD' }`. #### Selection From e1a1f454ca570de9fbd9f698b019cefd4a54fc9c Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Wed, 6 Nov 2024 12:26:00 -0800 Subject: [PATCH 17/19] Update spec/registry.md Co-authored-by: Eemeli Aro --- spec/registry.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/registry.md b/spec/registry.md index 10579b8e6a..8eb839996e 100644 --- a/spec/registry.md +++ b/spec/registry.md @@ -443,7 +443,7 @@ The following options and their values are required to be available on the funct - `currencySign` - `accounting` - `standard` (default) -- `currencyDisplay` (this option's values are derived from those in ICU [NumberFormatter.UnitWidth](https://unicode-org.github.io/icu-docs/apidoc/released/icu4j/com/ibm/icu/number/NumberFormatter.UnitWidth.html)) +- `currencyDisplay` - `narrowSymbol` - `symbol` (default) - `name` From ef98226151edcbd619831e2859d3b5d9187c8f46 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Wed, 6 Nov 2024 16:14:29 -0800 Subject: [PATCH 18/19] Add rounding options to :number and :currency --- spec/registry.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/spec/registry.md b/spec/registry.md index 8eb839996e..c496c51124 100644 --- a/spec/registry.md +++ b/spec/registry.md @@ -159,6 +159,22 @@ The following options and their values are required to be available on the funct - `trailingZeroDisplay` - `auto` (default) - `stripIfInteger` +- `roundingPriority` + - `auto` (default) + - `morePrecision` + - `lessPrecision` +- `roundingIncrement` + - 1 (default), 2, 5, 10, 20, 25, 50, 100, 200, 250, 500, 1000, 2000, 2500, and 5000 +- `roundingMode` + - `ceil` + - `floor` + - `expand` + - `trunc` + - `halfCeil` + - `halfFloor` + - `halfExpand` (default) + - `halfTrunc` + - `halfEven` If the _operand_ of the _expression_ is an implementation-defined type, such as the _resolved value_ of an _expression_ with a `:number` or `:integer` _annotation_, @@ -468,6 +484,22 @@ The following options and their values are required to be available on the funct - `trailingZeroDisplay` - `auto` (default) - `stripIfInteger` +- `roundingPriority` + - `auto` (default) + - `morePrecision` + - `lessPrecision` +- `roundingIncrement` + - 1 (default), 2, 5, 10, 20, 25, 50, 100, 200, 250, 500, 1000, 2000, 2500, and 5000 +- `roundingMode` + - `ceil` + - `floor` + - `expand` + - `trunc` + - `halfCeil` + - `halfFloor` + - `halfExpand` (default) + - `halfTrunc` + - `halfEven` If the _operand_ of the _expression_ is an implementation-defined type, such as the _resolved value_ of an _expression_ with a `:currency` _annotation_, From a80c0e24f0d8e05e30ede138c2dd26c18d8eafe8 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Tue, 12 Nov 2024 14:53:51 -0800 Subject: [PATCH 19/19] Implement 2024-11-11 changes - change `none` to `never` - remove `variant` --- spec/registry.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/spec/registry.md b/spec/registry.md index c496c51124..913fdacf85 100644 --- a/spec/registry.md +++ b/spec/registry.md @@ -464,9 +464,8 @@ The following options and their values are required to be available on the funct - `symbol` (default) - `name` - `code` - - `formal` - - `variant` - - `none` (this is called `hidden` in ICU) + - `formalSymbol` + - `never` (this is called `hidden` in ICU) - `useGrouping` - `auto` (default) - `always`