Skip to content

Commit 528109e

Browse files
aphillipseemeli
andauthored
Implement :currency function in the default registry (#915)
* 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. * Fix some details * Clean up operand * Apply suggestions from code review Co-authored-by: Eemeli Aro <[email protected]> * Improve operand, remove excess repeated content * Eliminate unnecessary extra operand section * Update spec/registry.md Co-authored-by: Eemeli Aro <[email protected]> * Update spec/registry.md Co-authored-by: Eemeli Aro <[email protected]> * Changes from 2024-10-28 call * 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 * Make `currency` be well-formed Includes a note explaining this. * Rename `currencyDisplay` values * Update spec/registry.md Co-authored-by: Eemeli Aro <[email protected]> * Define "well-formed" currency code * Update spec/registry.md Co-authored-by: Eemeli Aro <[email protected]> * Add `trailingZeroDisplay` option to :number and :currency * Update spec/registry.md Co-authored-by: Eemeli Aro <[email protected]> * Add rounding options to :number and :currency * Implement 2024-11-11 changes - change `none` to `never` - remove `variant` --------- Co-authored-by: Eemeli Aro <[email protected]>
1 parent 4181354 commit 528109e

File tree

1 file changed

+203
-62
lines changed

1 file changed

+203
-62
lines changed

spec/registry.md

Lines changed: 203 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,25 @@ The following options and their values are required to be available on the funct
192192
- ([digit size option](#digit-size-options))
193193
- `maximumSignificantDigits`
194194
- ([digit size option](#digit-size-options))
195+
- `trailingZeroDisplay`
196+
- `auto` (default)
197+
- `stripIfInteger`
198+
- `roundingPriority`
199+
- `auto` (default)
200+
- `morePrecision`
201+
- `lessPrecision`
202+
- `roundingIncrement`
203+
- 1 (default), 2, 5, 10, 20, 25, 50, 100, 200, 250, 500, 1000, 2000, 2500, and 5000
204+
- `roundingMode`
205+
- `ceil`
206+
- `floor`
207+
- `expand`
208+
- `trunc`
209+
- `halfCeil`
210+
- `halfFloor`
211+
- `halfExpand` (default)
212+
- `halfTrunc`
213+
- `halfEven`
195214
196215
If the _operand_ of the _expression_ is an implementation-defined type,
197216
such as the _resolved value_ of an _expression_ with a `:number` or `:integer` _annotation_,
@@ -207,37 +226,6 @@ with _options_ on the _expression_ taking priority over any option values of the
207226
> would be formatted with the resolved options
208227
> `{ notation: 'scientific', minimumFractionDigits: '1' }`.
209228
210-
> [!NOTE]
211-
> The following options and option values are being developed during the Technical Preview
212-
> period.
213-
214-
The following values for the option `style` are _not_ part of the default registry.
215-
Implementations SHOULD avoid creating options that conflict with these, but
216-
are encouraged to track development of these options during Tech Preview:
217-
- `currency`
218-
- `unit`
219-
220-
The following options are _not_ part of the default registry.
221-
Implementations SHOULD avoid creating options that conflict with these, but
222-
are encouraged to track development of these options during Tech Preview:
223-
- `currency`
224-
- valid [Unicode Currency Identifier](https://cldr-smoke.unicode.org/spec/main/ldml/tr35.html#UnicodeCurrencyIdentifier)
225-
(no default)
226-
- `currencyDisplay`
227-
- `symbol` (default)
228-
- `narrowSymbol`
229-
- `code`
230-
- `name`
231-
- `currencySign`
232-
- `accounting`
233-
- `standard` (default)
234-
- `unit`
235-
- (anything not empty)
236-
- `unitDisplay`
237-
- `long`
238-
- `short` (default)
239-
- `narrow`
240-
241229
##### Default Value of `select` Option
242230
243231
The value `plural` is the default for the option `select`
@@ -343,37 +331,6 @@ Option values with the following names are however discarded if included in the
343331
- `maximumFractionDigits`
344332
- `minimumSignificantDigits`
345333
346-
> [!NOTE]
347-
> The following options and option values are being developed during the Technical Preview
348-
> period.
349-
350-
The following values for the option `style` are _not_ part of the default registry.
351-
Implementations SHOULD avoid creating options that conflict with these, but
352-
are encouraged to track development of these options during Tech Preview:
353-
- `currency`
354-
- `unit`
355-
356-
The following options are _not_ part of the default registry.
357-
Implementations SHOULD avoid creating options that conflict with these, but
358-
are encouraged to track development of these options during Tech Preview:
359-
- `currency`
360-
- valid [Unicode Currency Identifier](https://cldr-smoke.unicode.org/spec/main/ldml/tr35.html#UnicodeCurrencyIdentifier)
361-
(no default)
362-
- `currencyDisplay`
363-
- `symbol` (default)
364-
- `narrowSymbol`
365-
- `code`
366-
- `name`
367-
- `currencySign`
368-
- `accounting`
369-
- `standard` (default)
370-
- `unit`
371-
- (anything not empty)
372-
- `unitDisplay`
373-
- `long`
374-
- `short` (default)
375-
- `narrow`
376-
377334
##### Default Value of `select` Option
378335
379336
The value `plural` is the default for the option `select`
@@ -418,6 +375,190 @@ together with the resolved options' values.
418375
419376
The _function_ `:integer` performs selection as described in [Number Selection](#number-selection) below.
420377
378+
### The `:currency` function
379+
380+
The function `:currency` is a selector and formatter for currency values,
381+
which are a specialized form of numeric selection and formatting.
382+
383+
#### Operands
384+
385+
The _operand_ of the `:currency` function can be one of any number of
386+
implementation-defined types,
387+
each of which contains a numerical `value` and a `currency`;
388+
or it can be a [Number Operand](#number-operands), as long as the option
389+
`currency` is provided.
390+
The option `currency` MUST NOT be used to override the currency of an implementation-defined type.
391+
Using this option in such a case results in a _Bad Option_ error.
392+
393+
The value of the _operand_'s `currency` MUST be either a string containing a
394+
well-formed [Unicode Currency Identifier](https://cldr-smoke.unicode.org/spec/main/ldml/tr35.html#UnicodeCurrencyIdentifier)
395+
or an implementation-defined currency type.
396+
Although currency codes are expected to be uppercase,
397+
implementations SHOULD treat them in a case-insensitive manner.
398+
A well-formed Unicode Currency Identifier matches the production `currency_code` in this ABNF:
399+
```abnf
400+
currency_code = 3ALPHA
401+
```
402+
403+
A [Number Operand](#number-operands) without a `currency` _option_ results in a _Bad Operand_ error.
404+
405+
> [!NOTE]
406+
> For example, in ICU4J, the type `com.ibm.icu.util.CurrencyAmount` can be used
407+
> to set the amount and currency.
408+
409+
> [!NOTE]
410+
> The `currency` is only required to be well-formed rather than checked for validity.
411+
> This allows new currency codes to be defined
412+
> (there are many recent examples of this occuring).
413+
> It also avoids requiring implementations to check currency codes for validity,
414+
> although implementations are permitted to emit _Bad Option_ or _Bad Operand_ for invalid codes.
415+
416+
> [!NOTE]
417+
> For runtime environments that do not provide a ready-made data structure,
418+
> class, or type for currency values, the implementation ought to provide
419+
> a data structure, convenience function, or documentation on how to encode
420+
> the value and currency code for formatting.
421+
> For example, such an implementation might define a "currency operand"
422+
> to include a key-value structure with specific keys to be the
423+
> local currency operand, which might look like the following:
424+
> ```
425+
> {
426+
> "value": 123.45,
427+
> "currency": "EUR"
428+
> }
429+
> ```
430+
431+
#### Options
432+
433+
Some options do not have default values defined in this specification.
434+
The defaults for these options are implementation-dependent.
435+
In general, the default values for such options depend on the locale,
436+
the currency,
437+
the value of other options, or all of these.
438+
439+
Fraction digits for currency values behave differently than for other numeric formatters.
440+
The number of fraction digits displayed is usually set by the currency used.
441+
For example, USD uses 2 fraction digits, while JPY uses none.
442+
Setting some other number of `fractionDigits` allows greater precision display
443+
(such as when performing currency conversions or other specialized operations)
444+
or disabling fraction digits if set to `0`.
445+
446+
The _option_ `trailingZeroDisplay` has a value `stripIfInteger` that is useful
447+
for displaying currencies with their fraction digits removed when the fraction
448+
part of the _operand_ is zero.
449+
This is sometimes used in _messages_ to make the displayed value omit the fraction part
450+
automatically.
451+
> For example, this _message_:
452+
> ```
453+
> The special price is {$price :currency trailingZeroDisplay=stripIfInteger}.
454+
> ```
455+
> When used with the value `5.00 USD` in the `en-US` locale displays as:
456+
> ```
457+
> The special price is $5.
458+
> ```
459+
> But like this when when value is `5.01 USD`:
460+
> ```
461+
> The special price is $5.01.
462+
> ```
463+
464+
Implementations MAY internally alias option values that they do not have data or a backing implementation for.
465+
Notably, the `currencyDisplay` option has a rich set of values that mirrors developments in CLDR data.
466+
Some implementations might not be able to produce all of these formats for every currency.
467+
468+
> [!NOTE]
469+
> Except where noted otherwise, the names of _options_ and their _values_ were derived from the
470+
> [options](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#options)
471+
> in JavaScript's `Intl.NumberFormat`.
472+
473+
> [!NOTE]
474+
> The option `select` does not accept the value `ordinal` because selecting
475+
> currency values using ordinal rules makes no sense.
476+
477+
The following options and their values are required to be available on the function `:currency`:
478+
- `select`
479+
- `plural` (default)
480+
- `exact`
481+
- `currency`
482+
- well-formed [Unicode Currency Identifier](https://cldr-smoke.unicode.org/spec/main/ldml/tr35.html#UnicodeCurrencyIdentifier)
483+
(no default)
484+
- `compactDisplay` (this option only has meaning when combined with the option `notation=compact`)
485+
- `short` (default)
486+
- `long`
487+
- `notation`
488+
- `standard` (default)
489+
- `compact`
490+
- `numberingSystem`
491+
- valid [Unicode Number System Identifier](https://cldr-smoke.unicode.org/spec/main/ldml/tr35.html#UnicodeNumberSystemIdentifier)
492+
(default is locale-specific)
493+
- `currencySign`
494+
- `accounting`
495+
- `standard` (default)
496+
- `currencyDisplay`
497+
- `narrowSymbol`
498+
- `symbol` (default)
499+
- `name`
500+
- `code`
501+
- `formalSymbol`
502+
- `never` (this is called `hidden` in ICU)
503+
- `useGrouping`
504+
- `auto` (default)
505+
- `always`
506+
- `never`
507+
- `min2`
508+
- `minimumIntegerDigits`
509+
- ([digit size option](#digit-size-options), default: `1`)
510+
- `fractionDigits` (unlike number/integer formats, the fraction digits for currency formatting are fixed)
511+
- `auto` (default) (the number of digits used by the currency)
512+
- ([digit size option](#digit-size-options))
513+
- `minimumSignificantDigits`
514+
- ([digit size option](#digit-size-options))
515+
- `maximumSignificantDigits`
516+
- ([digit size option](#digit-size-options))
517+
- `trailingZeroDisplay`
518+
- `auto` (default)
519+
- `stripIfInteger`
520+
- `roundingPriority`
521+
- `auto` (default)
522+
- `morePrecision`
523+
- `lessPrecision`
524+
- `roundingIncrement`
525+
- 1 (default), 2, 5, 10, 20, 25, 50, 100, 200, 250, 500, 1000, 2000, 2500, and 5000
526+
- `roundingMode`
527+
- `ceil`
528+
- `floor`
529+
- `expand`
530+
- `trunc`
531+
- `halfCeil`
532+
- `halfFloor`
533+
- `halfExpand` (default)
534+
- `halfTrunc`
535+
- `halfEven`
536+
537+
If the _operand_ of the _expression_ is an implementation-defined type,
538+
such as the _resolved value_ of an _expression_ with a `:currency` _annotation_,
539+
it can include option values.
540+
These are included in the resolved option values of the _expression_,
541+
with _options_ on the _expression_ taking priority over any option values of the _operand_.
542+
543+
> For example, the _placeholder_ in this _message_:
544+
> ```
545+
> .input {$n :currency currency=USD trailingZeroDisplay=stripIfInteger}
546+
> {{{$n :currency currencySign=accounting}}}
547+
> ```
548+
> would be formatted with the resolved options
549+
> `{ currencySign: 'accounting', trailingZeroDisplay: 'stripIfInteger', currency: 'USD' }`.
550+
551+
#### Resolved Value
552+
553+
The _resolved value_ of an _expression_ with a `:currency` _function_
554+
contains an implementation-defined currency value
555+
of the _operand_ of the annotated _expression_,
556+
together with the resolved options' values.
557+
558+
#### Selection
559+
560+
The _function_ `:currency` performs selection as described in [Number Selection](#number-selection) below.
561+
421562
### Number Operands
422563
423564
The _operand_ of a number function is either an implementation-defined type or

0 commit comments

Comments
 (0)