-
-
Notifications
You must be signed in to change notification settings - Fork 34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add :percent
#988
base: main
Are you sure you want to change the base?
Add :percent
#988
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -43,9 +43,6 @@ The following options and their values are required to be available on the funct | |||||
- `exceptZero` | ||||||
- `negative` | ||||||
- `never` | ||||||
- `style` | ||||||
- `decimal` (default) | ||||||
- `percent` (see [Percent Style](#percent-style) below) | ||||||
- `useGrouping` | ||||||
- `auto` (default) | ||||||
- `always` | ||||||
|
@@ -120,21 +117,6 @@ but can cause problems in target locales that the original developer is not cons | |||||
> 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`. | ||||||
|
||||||
##### Percent Style | ||||||
|
||||||
When implementing `style=percent`, the numeric value of the _operand_ | ||||||
MUST be multiplied by 100 for the purposes of formatting. | ||||||
|
||||||
> For example, | ||||||
> | ||||||
> ``` | ||||||
> The total was {0.5 :number style=percent}. | ||||||
> ``` | ||||||
> | ||||||
> should format in a manner similar to: | ||||||
> | ||||||
> > The total was 50%. | ||||||
|
||||||
#### Resolved Value | ||||||
|
||||||
The _resolved value_ of an _expression_ with a `:number` _function_ | ||||||
|
@@ -183,9 +165,6 @@ function `:integer`: | |||||
- `exceptZero` | ||||||
- `negative` | ||||||
- `never` | ||||||
- `style` | ||||||
- `decimal` (default) | ||||||
- `percent` (see [Percent Style](#percent-style) below) | ||||||
- `useGrouping` | ||||||
- `auto` (default) | ||||||
- `always` | ||||||
|
@@ -232,21 +211,6 @@ but can cause problems in target locales that the original developer is not cons | |||||
> 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`. | ||||||
|
||||||
##### Percent Style | ||||||
|
||||||
When implementing `style=percent`, the numeric value of the _operand_ | ||||||
MUST be multiplied by 100 for the purposes of formatting. | ||||||
|
||||||
> For example, | ||||||
> | ||||||
> ``` | ||||||
> The total was {0.5 :number style=percent}. | ||||||
> ``` | ||||||
> | ||||||
> should format in a manner similar to: | ||||||
> | ||||||
> > The total was 50%. | ||||||
|
||||||
#### Resolved Value | ||||||
|
||||||
The _resolved value_ of an _expression_ with an `:integer` _function_ | ||||||
|
@@ -526,6 +490,117 @@ together with the resolved options' values. | |||||
|
||||||
The _function_ `:currency` performs selection as described in [Number Selection](#number-selection) below. | ||||||
|
||||||
### The `:percent ` function | ||||||
|
||||||
The function `:percent` is a formatter for percentage values, | ||||||
which are a specialized form of numeric formatting. | ||||||
|
||||||
#### Operands | ||||||
|
||||||
The function `:percent` requires a [Number Operand](#number-operands) as its _operand_. | ||||||
|
||||||
For the purposes of formatting, | ||||||
the numeric value of the _operand_ is multiplied by 100. | ||||||
|
||||||
> For example, | ||||||
> | ||||||
> ``` | ||||||
> The total was {0.5 :percent}. | ||||||
> ``` | ||||||
> | ||||||
> should format in a manner similar to: | ||||||
> | ||||||
> > The total was 50%. | ||||||
|
||||||
#### 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 value of other options, or both. | ||||||
|
||||||
> [!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`: | ||||||
|
||||||
- `numberingSystem` | ||||||
- valid [Unicode Number System Identifier](https://cldr-smoke.unicode.org/spec/main/ldml/tr35.html#UnicodeNumberSystemIdentifier) | ||||||
(default is locale-specific) | ||||||
- `signDisplay` | ||||||
- `auto` (default) | ||||||
- `always` | ||||||
- `exceptZero` | ||||||
- `negative` | ||||||
- `never` | ||||||
- `useGrouping` | ||||||
- `auto` (default) | ||||||
- `always` | ||||||
- `never` | ||||||
- `min2` | ||||||
- `minimumIntegerDigits` | ||||||
- ([digit size option](#digit-size-options), default: `1`) | ||||||
- `minimumFractionDigits` | ||||||
- ([digit size option](#digit-size-options)) | ||||||
- `maximumFractionDigits` | ||||||
- ([digit size option](#digit-size-options)) | ||||||
- `minimumSignificantDigits` | ||||||
- ([digit size option](#digit-size-options)) | ||||||
- `maximumSignificantDigits` | ||||||
- ([digit size option](#digit-size-options)) | ||||||
- `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. | ||||||
In general, 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_. | ||||||
Option values with the following names are however discarded if included in the _operand_: | ||||||
|
||||||
- `compactDisplay` | ||||||
- `notation` | ||||||
- `select` | ||||||
Comment on lines
+578
to
+582
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just say that all options not named in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That would be different from what we do with other functions, such as An implementation could support additional options that are set in the calling code on the value being formatted, and are understood by the formatter. For a somewhat silly example, an implementation could support colour as a property of numbers, and format a "green 0.42" so that the % sign was also green in the output. If we here said that all options not explicitly listed are discarded, this kind of extensibility would not be possible. |
||||||
|
||||||
> For example, the _placeholder_ in this _message_: | ||||||
> | ||||||
> ``` | ||||||
> .input {$n :number minimumFractionDigits=2 roundingMode=floor} | ||||||
> {{{$n :percent minimumFractionDigits=1}}} | ||||||
> ``` | ||||||
> | ||||||
> would be formatted with the resolved options | ||||||
> `{ minimumFractionDigits: '1', roundingMode: 'floor' }`. | ||||||
|
||||||
#### Resolved Value | ||||||
|
||||||
The _resolved value_ of an _expression_ with a `:percent` _function_ | ||||||
contains an implementation-defined numerical value | ||||||
of the _operand_ of the annotated _expression_ multiplied by 100, | ||||||
together with the resolved options' values. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For clarity, and since "resolved value" and "options" are the terms, perhaps:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Variants of this same snippet are used in nearly all the functions. This change would be better made separately, affecting all of them at once. But yes, referring to the options' resolved values would be appropriate, but note that this isn't the same as options, given that the resolved options are determined by the function handler. In practice they can include ones coming from the operand as well, and don't necessarily contain all of the options. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps "resolved values of the resolved list of options"? Oh the pedantry... |
||||||
|
||||||
To avoid potential confusion from the multiplication of the _operand_ value, | ||||||
this _resolved value_ MUST NOT be considered a valid [Number Operand](#number-operands). | ||||||
|
||||||
### The `:unit` function | ||||||
|
||||||
The _function_ `:unit` is **Proposed** for inclusion in the next release of this specification but has not yet been finalized. | ||||||
|
@@ -863,7 +938,6 @@ representing its decimal value: | |||||
- `minimumSignificantDigits` | ||||||
- `maximumSignificantDigits` | ||||||
- `notation` | ||||||
- `style` | ||||||
|
||||||
```abnf | ||||||
integer = "0" / ["-"] ("1"-"9") *DIGIT | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we have a separate function, purpose built for it, should we offer a pre-computed mode?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean an option toggling if the input is multiplied or not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, exactly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ICU4C calls it "scale" or "multiplier"
ICU4X calls it "multiply_pow10"
I don't think we've had a proper bikeshedding session on this before. I've sort-of named it what I felt like naming it and no one ever pushed back with better names.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that we'll be defaulting to a value 1 getting formatted as something like "100%", I think
scale
makes the most sense, with a default value of1
and supporting100
as an alternative. With this approach,would then be formatted as "42%".
Or is the ICU4C meaning of this option the exact opposite?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another thought: an enumeration might be appropriate here. Something like:
scalingMode: "scale"
scales the number: 0.5 => 50%scalingMode: "passThrough"
passes through the number: 50 => 50%(sorry for the quad-post)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In that case,
scale
is a rather sub-optimal choice, as it demonstrably can be understood as either "scale the number by this much" or "the scale extends to this value as the maximum".There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More suggestions, with some help from an LLM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe
style=raw
, as an alternative to a defaultstyle=scaled
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like to avoid any option with the unqualified
style
name.