Skip to content
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
204 changes: 142 additions & 62 deletions spec/registry.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down Expand Up @@ -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`
Expand Down Expand Up @@ -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 an OPTIONAL selector and formatter for currency values,
which are a specialized form of numeric selection and formatting.

#### `: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`.

#### 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]
> 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 `:currency`:
- `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' }`.

Copy link
Member

Choose a reason for hiding this comment

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

Question.

It appears reasonable to allow composition of currency with numeric values, eg:

.input {$n :number }
{{{$n :currency currencySign=accounting}}}

or

.input {$n :integer }
{{{$n :currency currencySign=accounting}}}

whereby any options on the numeric functions are ignored for the currency formatting.

Not a blocker, since this can be done later.

Copy link
Member Author

Choose a reason for hiding this comment

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

It is reasonable, but not using the messages in your examples, since $n (if just a number) doesn't have a currency code associated with it. Note that Measure and CurrencyAmount in ICU4J are not subclasses of Number. ICU might choose to treat either as numbers, of course. I'm just pointing out that tuple-types might not work out-of-the-box. In addition, the implementation might resolve the value to a non-currency type:

.input {$c :currency}
.local $discounted = {$c :math subtract=2}
{{{$discounted} might only be a Number...}}

The reverse is also potentially true as well: one could use the :number or :integer formatter or selector against a :currency annotated value, although I can't fathom why you'd want to. Bad Operand might be a blessing in this case.

Note that the options would not be ignored in cases where they overlap (which they do quite significantly and on purpose). The primary differences are the handling of fractional digits, display of the currency symbol, and the handling of sign/currencySign (which might want to be harmonized??).

Mainly, this behavior is up to the implementation, since currency types or tuples might not be on the number/integer menu of types.


.input {$n :number useGrouping=never numberingSystem=Latn}
.local $c = {$n :currency currencyCode=INR}
{{This prints in rupees without lakhs (or other groupings) and with Latin digits: {$c}}}

Copy link
Member

Choose a reason for hiding this comment

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

Sorry, I fat-fingered. I had copied the example, and meant to delete the currencySign option, and instead deleted the currencyCode option!

I had also meant just composition one way, from a number to a currency amount, as you have it:

.input {$n :number useGrouping=never numberingSystem=Latn}
.local $c = {$n :currency currencyCode=INR}
{{This prints in rupees without lakhs (or other groupings) and with Latin digits: {$c}}}

I hadn't meant from a currency amount to a number.

.input {$c :currency}
.local $n = {$c :number useGrouping=never numberingSystem=Latn}
{{This prints just the number part of a currency amount: {$n}}}

##### 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.
Copy link
Collaborator

Choose a reason for hiding this comment

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

While considering #933, I realised that plural selection on currency values depends on being able to introspect the fraction digits which are by default locale-dependent. The ICU FormattedNumber might do that automatically, but in other APIs the operation can get a bit trickier.

Copy link
Member Author

Choose a reason for hiding this comment

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

It's not locale-dependent. It's currency dependent. This is why fraction digits are different in this function!

Copy link
Member

Choose a reason for hiding this comment

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

+1


#### Composition

When an _operand_ or an _option_ value uses a _variable_ annotated,
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.

### Number Operands

The _operand_ of a number function is either an implementation-defined type or
Expand Down Expand Up @@ -417,6 +477,26 @@ 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`.
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 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

Some _options_ of number _functions_ are defined to take a "digit size option".
Expand Down