-
-
Notifications
You must be signed in to change notification settings - Fork 36
Design document for percent formatting #1068
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
base: main
Are you sure you want to change the base?
Changes from 1 commit
9a08e14
659a375
442722b
813226a
9a76ea7
817b58b
d914945
3b10266
e4ef2a4
23c1d99
03b1f78
72b11d2
c95919d
a4b0b1b
7ab3bf0
0e9c442
377bced
863734b
1186c95
81a9234
6399c83
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 |
---|---|---|
@@ -0,0 +1,169 @@ | ||
# Formatting Percent Values | ||
|
||
Status: **Proposed** | ||
|
||
<details> | ||
<summary>Metadata</summary> | ||
<dl> | ||
<dt>Contributors</dt> | ||
<dd>@aphillips</dd> | ||
<dt>First proposed</dt> | ||
<dd>2025-04-07</dd> | ||
<dt>Pull Requests</dt> | ||
<dd>#000</dd> | ||
</dl> | ||
</details> | ||
|
||
## Objective | ||
|
||
_What is this proposal trying to achieve?_ | ||
|
||
One the capabilities present in ICU MessageFormat is the ability to format a number as a percentage. | ||
This design enumerates the approaches considered for adding this ability as a _default function_ | ||
in Unicode MessageFormat. | ||
|
||
## Background | ||
|
||
_What context is helpful to understand this proposal?_ | ||
|
||
> [!NOTE] | ||
> This design is an outgrowth of discussions in #956 and various teleconferences. | ||
|
||
Developers and translators often need to insert a numeric value into a formatted message as a percentage. | ||
The format of a percentage can vary by locale including | ||
the symbol used, | ||
the presence or absence of spaces, | ||
the shaping of digits, | ||
the position of the symbol, | ||
and other variations. | ||
|
||
One of the key problems is whether the value should be "scaled". | ||
That is, does the value `0.5` format as `50%` or `0.5%`? | ||
Developers need to know which behavior will occur so that they can adjust the value passed appropriately. | ||
|
||
> [!NOTE] | ||
> MessageFormat (MF1) in ICU4J scales. | ||
> MeasureFormat in ICU4J does not scale. | ||
aphillips marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
It is also possible for Unicode MessageFormat to provide support for scaling in the message itself, | ||
perhaps by extending the `:math` function. | ||
|
||
An addition concern is whether to add a dedicated `:percent` function, | ||
use one of the existing number-formatting functions `:number` and `:integer` with an option `type=percent`, | ||
or use the proposed _optional_ function `:unit` with an option `unit=percent`. | ||
Combinations of these approached might also be used. | ||
|
||
## Use-Cases | ||
|
||
_What use-cases do we see? Ideally, quote concrete examples._ | ||
|
||
Developers wish to write messages that format a numeric value as a percentage in a locale-sensitive manner. | ||
|
||
The numeric value is not scaled because it is the result of a computation, e.g. `var savings = discount / price`. | ||
|
||
The numeric value is scaled, e.g. `var savingsPercent = 50` | ||
|
||
Users need control over most formatting details, identical to general number formatting: | ||
- negative number sign display | ||
- digit shaping | ||
- minimum number of fractional digits | ||
- maximum number of fractional digits | ||
- minimum number of decimal digits | ||
- group used (for very large percentages, i.e. > 999%) | ||
- etc. | ||
|
||
## Requirements | ||
|
||
_What properties does the solution have to manifest to enable the use-cases above?_ | ||
|
||
|
||
aphillips marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## Constraints | ||
|
||
_What prior decisions and existing conditions limit the possible design?_ | ||
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. I think we should mention that since MF1 scales, we want MF2 to be able to scale? 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. We don't necessarily want MF2 to scale. There is a hot debate about whether scaling or non-scaling is preferred. |
||
|
||
## Proposed Design | ||
|
||
_Describe the proposed solution. Consider syntax, formatting, errors, registry, tooling, interchange._ | ||
|
||
- Use a dedicated function `:percent` that scales by default. | ||
- Provide an option `scaling` with values `true` and `false` and defaulting to `true`. | ||
- Provide all options identical to `:number` _except_ that `select` does not provide `ordinal` value. | ||
- Allow `unit=percent` in `:unit` that is identical to `:percent` in formatting performance, | ||
aphillips marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for compatibility with CLDR units, | ||
but document that this usage is not preferred. | ||
aphillips marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## Alternatives Considered | ||
|
||
_What other solutions are available?_ | ||
_How do they compare against the requirements?_ | ||
_What other properties they have?_ | ||
|
||
### Function Alternatives | ||
|
||
#### Use `:unit` | ||
|
||
Leverage the `:unit` function by using the existing unit option value `percent`. | ||
The ICU implementation of `MeasureFormat` does **_not_** scale the percentage, | ||
although this does not have to be the default behavior of UMF's percent unit format. | ||
|
||
``` | ||
You saved {$savings :unit unit=percent} on your order today! | ||
``` | ||
|
||
**Pros** | ||
- Uses an existing set of functionality | ||
- Removes percentages from `:number` and `:integer`, making those functions more "pure" | ||
aphillips marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
**Cons** | ||
- `:unit` won't be REQUIRED, so percentage format will not be guaranteed across implementations. | ||
Requiring `:unit type=percent` would be complicated at best. | ||
aphillips marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- More verbose placeholder | ||
- Could require a scaling mechanism | ||
|
||
#### Use `:number`/`:integer` with `type=percent` | ||
aphillips marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Use the existing functions for number formatting with a separate `type` option for `percent`. | ||
(This was previously the design) | ||
|
||
``` | ||
You saved {$savings :number type=percent} on your order today! | ||
``` | ||
aphillips marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
**Pros** | ||
- Consistent with ICU MessageFormat | ||
|
||
aphillips marked this conversation as resolved.
Show resolved
Hide resolved
|
||
**Cons** | ||
- It's the only special case remaining in these functions. Why? | ||
|
||
#### Use a dedicated `:percent` function | ||
|
||
Use a new function `:percent` dedicated to percentages. | ||
aphillips marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
``` | ||
You saved {$savings :percent} on your order today! | ||
``` | ||
|
||
**Pros** | ||
- Least verbose placeholder | ||
- Clear what the placeholder does; self-documenting? | ||
|
||
**Cons** | ||
- Adds to a (growing) list of functions | ||
- Not "special enough" to warrant its own formatter? | ||
|
||
### Scaling Alternatives | ||
|
||
#### No Scaling | ||
User has to scale the number. The value `0.5` formats as `0.5%` | ||
|
||
#### Scaling | ||
aphillips marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Implementation always scales the number. The value `0.5` formats as `50%` | ||
aphillips marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
#### Optional Scaling | ||
Implementation automatically does (or does not) scale. | ||
There is an option to switch to the other behavior. | ||
aphillips marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
#### Use `:math` to scale | ||
Provide functionality to scale numbers arbitrarily using the `:math` function. | ||
This alternative can be used with scaling/no scaling to fix the passed value appropriately without altering userland code. | ||
aphillips marked this conversation as resolved.
Show resolved
Hide resolved
|
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.
If this PR is intended to close #956, then we should not be landing this document with just "Proposed" status.
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 hope that we will choose a design before committing.