The function :number
is a selector and formatter for numeric values.
The function :number
requires a Number Operand as its operand.
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 value of other options, or both.
Note
The names of options and their option values were derived from the
options
in JavaScript's Intl.NumberFormat
.
The following options are REQUIRED to be available on the function :number
:
select
(see Number Selection below)plural
(default)ordinal
exact
signDisplay
auto
(default)always
exceptZero
negative
never
useGrouping
auto
(default)always
never
min2
minimumIntegerDigits
- digit size option, default:
1
- digit size option, default:
minimumFractionDigits
- digit size option
maximumFractionDigits
- digit size option
minimumSignificantDigits
- digit size option
maximumSignificantDigits
- digit size option
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,
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 options of the operand.
For example, the placeholder in this message:
.input {$n :number minimumFractionDigits=2 signDisplay=always} {{{$n :number minimumFractionDigits=1}}}
would be formatted with the resolved options
{ minimumFractionDigits: '1', signDisplay: 'always' }
.
The resolved value of an expression with a :number
function
contains an implementation-defined numerical value
of the operand of the annotated expression,
together with the resolved options' values.
The function :number
performs selection as described in Number Selection below.
The function :integer
is a selector and formatter for matching or formatting numeric
values as integers.
The function :integer
requires a Number Operand as its operand.
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 value of other options, or both.
Note
The names of options and their option values were derived from the
options
in JavaScript's Intl.NumberFormat
.
The following options are REQUIRED to be available on the function :integer
:
select
(see Number Selection below)plural
(default)ordinal
exact
signDisplay
auto
(default)always
exceptZero
negative
never
useGrouping
auto
(default)always
never
min2
minimumIntegerDigits
- digit size option, default:
1
- digit size option, default:
maximumSignificantDigits
- digit size option
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,
it can include option values.
In general, these are included in the resolved option values of the expression,
with options on the expression taking priority over any options of the operand.
Options with the following names are however discarded if included in the operand:
minimumFractionDigits
maximumFractionDigits
minimumSignificantDigits
The resolved value of an expression with an :integer
function
contains the implementation-defined integer value
of the operand of the annotated expression,
together with the resolved options' values.
The function :integer
performs selection as described in Number Selection below.
Important
The function :math
has a status of Draft.
It is proposed for inclusion in a future release of this specification and is not Stable.
The function :math
is proposed as a selector and formatter for matching or formatting
numeric values to which a mathematical operation has been applied.
This function is useful for selection and formatting of values that differ from the input value by a specified amount. For example, it can be used in a message such as this:
.input {$like_count :integer} .local $others_count = {$like_count :math subtract=1} .match $like_count $others_count 0 * {{Your post has no likes.}} 1 * {{{$name} liked your post.}} * one {{{$name} and {$others_count} other user liked your post.}} * * {{{$name} and {$others_count} other users liked your post.}}
The function :math
requires a Number Operand as its operand.
The options on :math
are exclusive with each other,
and exactly one option is always required.
The options do not have default values.
The following options are REQUIRED to be available on the function :math
:
add
- digit size option
subtract
- digit size option
If no options or more than one option is set, or if an option value is not a digit size option, a Bad Option error is emitted and a fallback value used as the resolved value of the expression.
The resolved value of an expression with a :math
function
contains the implementation-defined numeric value
of the operand of the annotated expression.
If the add
option is set,
the numeric value of the resolved value is formed by incrementing
the numeric value of the operand by the integer value of the digit size option.
If the subtract
option is set,
the numeric value of the resolved value is formed by decrementing
the numeric value of the operand by the integer value of the digit size option.
If the operand of the expression is an implementation-defined numeric type,
such as the resolved value of an expression with a :number
or :integer
annotation,
it can include option values.
These are included in the resolved option values of the expression.
The :math
options are not included in the resolved option values.
Note
Implementations can encounter practical limits with :math
expressions,
such as the result of adding two integers exceeding
the storage or precision of some implementation-defined number type.
In such cases, implementations can emit an Unsupported Operation error
or they might just silently overflow the underlying data value.
The function :math
performs selection as described in Number Selection below.
Important
The function :currency
has a status of Draft.
It is proposed for inclusion in a future release of this specification and is not Stable.
The function :currency
is a formatter for currency values,
which are a specialized form of numeric formatting.
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, 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
well-formed Unicode Currency Identifier
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:
currency_code = 3ALPHA
A Number Operand 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
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.
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:
{
"value": 123.45,
"currency": "EUR"
}
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 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 option trailingZeroDisplay
has an option 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 trailingZeroDisplay=stripIfInteger}.
When used with the value
5.00 USD
in theen-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.
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 option values were derived from the
options
in JavaScript's Intl.NumberFormat
.
The following options are REQUIRED to be available on the function :currency
:
currency
- well-formed Unicode Currency Identifier (no default)
currencySign
accounting
standard
(default)
currencyDisplay
narrowSymbol
symbol
(default)name
code
never
(this is calledhidden
in ICU)
useGrouping
auto
(default)always
never
min2
minimumIntegerDigits
- digit size option, default:
1
- digit size option, default:
fractionDigits
(unlike number/integer formats, the fraction digits for currency formatting are fixed)auto
(default) (the number of digits used by the currency)- digit size option
minimumSignificantDigits
- digit size option
maximumSignificantDigits
- digit size option
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,
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 options of the operand.
For example, the placeholder in this message:
.input {$n :currency currency=USD trailingZeroDisplay=stripIfInteger} {{{$n :currency currencySign=accounting}}}
would be formatted with the resolved options
{ currencySign: 'accounting', trailingZeroDisplay: 'stripIfInteger', currency: 'USD' }
.
The resolved value of an expression with a :currency
function
contains an implementation-defined currency value
of the operand of the annotated expression,
together with the resolved options' values.
Important
The function :unit
has a status of Draft.
It is proposed for inclusion in a future release of this specification and is not Stable.
The function :unit
is proposed to be a RECOMMENDED formatter for unitized values,
that is, for numeric values associated with a unit of measurement.
This is a specialized form of numeric formatting.
The operand of the :unit
function can be one of any number of
implementation-defined types,
each of which contains a numerical value
plus a unit
or it can be a Number Operand, as long as the option
unit
is provided.
The value of the operand's unit
SHOULD be either a string containing a
valid Unit Identifier
or an implementation-defined unit type.
A Number Operand without a unit
option results in a Bad Operand error.
Note
For example, in ICU4J, the type com.ibm.icu.util.Measure
might be used
as an operand for :unit
because it contains the value
and unit
.
Note
For runtime environments that do not provide a ready-made data structure, class, or type for unit values, the implementation ought to provide a data structure, convenience function, or documentation on how to encode the value and unit for formatting. For example, such an implementation might define a "unit operand" to include a key-value structure with specific keys to be the local unit operand, which might look like the following:
{
"value": 123.45,
"unit": "kilometer-per-hour"
}
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 unit, the value of other options, or all of these.
The following options are REQUIRED to be available on the function :unit
,
unless otherwise indicated:
unit
- valid Unit Identifier (no default)
usage
[RECOMMENDED]- valid Unicode Unit Preference (no default, see Unit Conversion below)
unitDisplay
short
(default)narrow
long
signDisplay
auto
(default)always
exceptZero
negative
never
useGrouping
auto
(default)always
never
min2
minimumIntegerDigits
- digit size option, default:
1
- digit size option, default:
minimumFractionDigits
- digit size option
maximumFractionDigits
- digit size option
minimumSignificantDigits
- digit size option
maximumSignificantDigits
- digit size option
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 :unit
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 options of the operand.
For example, the placeholder in this message:
.input {$n :unit unit=furlong minimumFractionDigits=2} {{{$n :unit minimumIntegerDigits=1}}}
would have the resolved options:
{ unit: 'furlong', minimumFractionDigits: '2', minimumIntegerDigits: '1' }
.
The resolved value of an expression with a :unit
function
consist of an implementation-defined unit value
of the operand of the annotated expression,
together with the resolved options and their resolved values.
Implementations MAY support conversion to the locale's preferred units via the usage
option.
Implementing this option is optional.
Not all usage
option values are compatible with a given unit.
Implementations SHOULD emit an Unsupported Operation error if the requested conversion is not supported.
For example, trying to convert a
length
unit (such as "meters") to avolume
usage (which might be a unit akin to "liters" or "gallons", depending on the locale) could produce an Unsupported Operation error.
Implementations MUST NOT substitute the unit without performing the associated conversion.
For example, consider the value:
{ "value": 123.5, "unit": "meter" }
The following message might convert the formatted result to U.S. customary units in the
en-US
locale:You have {$v :unit usage=road maximumFractionDigits=0} to go.
This can produce "You have 405 feet to go."
The operand of a number function is either an implementation-defined type or
a literal whose contents match the following number-literal
production.
All other values produce a Bad Operand error.
number-literal = ["-"] (%x30 / (%x31-39 *DIGIT)) ["." 1*DIGIT] [%i"e" ["-" / "+"] 1*DIGIT]
For example, in Java, any subclass of
java.lang.Number
plus the primitive types (byte
,short
,int
,long
,float
,double
, etc.) might be considered as the "implementation-defined numeric types". Implementations in other programming languages would define different types or classes according to their local needs.
Note
String values passed as variables in the formatting context's
input mapping can be formatted as numeric values as long as their
contents match the number-literal
production.
For example, if the value of the variable num
were the string
-1234.567
, it would behave identically to the local
variable in this example:
.local $example = {|-1234.567| :number}
{{{$num :number} == {$example}}}
Note
Implementations are encouraged to provide support for compound types or data structures
that provide additional semantic meaning to the formatting of number-like values.
For example, in ICU4J, the type com.ibm.icu.util.Measure
can be used to communicate
a value that includes a unit
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).
Some options of number functions are defined to take a digit size option. The function handlers for number functions use these options to control aspects of numeric display such as the number of fraction, integer, or significant digits.
A digit size option is an option whose option value is interpreted by the function as a small integer greater than or equal to zero. Implementations MAY define an upper limit on the resolved value of a digit size option consistent with that implementation's practical limits.
In most cases, the value of a digit size option will be a string that encodes the value as a non-negative integer. Implementations MAY also accept implementation-defined types as the option value. When provided as a string, the representation of a digit size option matches the following ABNF:
digit-size-option = "0" / (("1"-"9") [DIGIT])
If the value of a digit size option does not evaluate as a non-negative integer, or if the value exceeds any implementation-defined and option-specific upper or lower limit, a Bad Option error is emitted. If the value exceeds an implementation-defined upper or lower limit, the implementation MAY replace the offending value with an implementation-defined value.
The option value of the select
option MUST be set by a literal.
Allowing a variable option value for select
would produce a message that
is impossible to translate because the set of keys is tied to the selector chosen.
If the option value is a variable or
if the select
option is set by an implementation-defined type used as an operand,
a Bad Option Error is emitted and
the resolved value of the expression MUST NOT support selection.
The formatting of the resolved value is not affected by the select
option.
Number selection has three modes:
exact
selection matches the operand to explicit numeric keys exactlyplural
selection matches the operand to explicit numeric keys exactly followed by a plural rule category if there is no explicit matchordinal
selection matches the operand to explicit numeric keys exactly followed by an ordinal rule category if there is no explicit match
When implementing MatchSelectorKeys(resolvedSelector, keys)
where resolvedSelector
is the resolved value of a selector
and keys
is a list of strings,
numeric selectors perform as described below.
- Let
exact
be the serialized representation of the numeric value ofresolvedSelector
. (See Exact Literal Match Serialization for details) - Let
keyword
be a string which is the result of rule selection onresolvedSelector
. - Let
resultExact
be a new empty list of strings. - Let
resultKeyword
be a new empty list of strings. - For each string
key
inkeys
:- If the value of
key
matches the productionnumber-literal
, then- If
key
andexact
consist of the same sequence of Unicode code points, then- Append
key
as the last element of the listresultExact
.
- Append
- If
- Else if
key
is one of the keywordszero
,one
,two
,few
,many
, orother
, then- If
key
andkeyword
consist of the same sequence of Unicode code points, then- Append
key
as the last element of the listresultKeyword
.
- Append
- If
- Else, emit a Bad Variant Key error.
- If the value of
- Return a new list whose elements are the concatenation of the elements (in order) of
resultExact
followed by the elements (in order) ofresultKeyword
.
Note
Implementations are not required to implement this exactly as written. However, the observed behavior must be consistent with what is described here.
The option 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 aone
plural:.input {$var :number} .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 astwo
,few
, andmany
.
Rule selection is intended to support the grammatical matching needs of different languages/locales in order to support plural or ordinal numeric values.
If the select
option value is exact
, rule-based selection is not used.
Otherwise rule selection matches the operand, as modified by function options, to exactly one of these keywords:
zero
, one
, two
, few
, many
, or other
.
The keyword other
is the default.
Note
Since valid keys cannot be the empty string in a numeric expression, returning the empty string disables keyword selection.
The meaning of the keywords is locale-dependent and implementation-defined.
A key that matches the rule-selected keyword is a stronger match than the fallback key *
but a weaker match than any exact match key value.
The rules for a given locale might not produce all of the keywords. A given operand value might produce different keywords depending on the locale.
Apply the rules to the resolved value of the operand and the relevant function options,
and return the resulting keyword.
If no rules match, return other
.
If the select
option value is plural
, the rules applied to selection SHOULD be
the CLDR plural rule data of type cardinal
.
See charts
for examples.
If the select
option value is ordinal
, the rules applied to selection SHOULD be
the CLDR plural rule data of type ordinal
.
See charts
for examples.
Example. In CLDR 44, the Czech (
cs
) plural rule set can be found here.A message in Czech might be:
.input {$numDays :number} .match $numDays one {{{$numDays} den}} few {{{$numDays} dny}} many {{{$numDays} dne}} * {{{$numDays} dní}}
Using the rules found above, the results of various operand values might look like:
Operand value Keyword Formatted Message 1 one
1 den 2 few
2 dny 5 other
5 dní 22 few
22 dny 27 other
27 dní 2.4 many
2,4 dne
If the numeric value of resolvedSelector
is an integer
and none of the following options are set for resolvedSelector
,
the serialized form of the numeric value MUST match the ABNF defined below for integer
,
representing its decimal value:
minimumFractionDigits
minimumIntegerDigits
minimumSignificantDigits
maximumSignificantDigits
integer = "0" / ["-"] ("1"-"9") *DIGIT
Otherwise, the serialized form of the numeric value is implementation-defined.
Important
The exact behavior of exact literal match is only well defined for integer values without leading zeros. Functions that use fraction digits or significant digits might work in specific implementation-defined ways. Users should avoid depending on these types of keys in message selection.