Skip to content

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

Open
wants to merge 21 commits into
base: main
Choose a base branch
from

Conversation

aphillips
Copy link
Member

@aphillips aphillips commented Apr 7, 2025

This document now includes the proposed design discussed in the (poorly documented, sparsely attended) 2025-05-19 call. The emerging consensus appears to be:

  • :number/:integer with option style=percent (this is the current design) with scaling
  • :unit with unit percent is REQUIRED but other units are not required, this function has NO scaling

The most recent commit posits that :number/:integer select after scaling because we don't support fraction selection currently.

Note

All previous conversations were marked resolved on purpose and not because their content was in any way deficient, off topic, or necessarily addressed. Please comment on the proposed design.

This document is focused for now on documenting the options.
@aphillips aphillips added design Design document or issues related to design functions Issue pertains to the default function set LDML48 LDML48 Release labels Apr 7, 2025
@eemeli
Copy link
Collaborator

eemeli commented Apr 22, 2025

I just realised that this whole discussion is also related to #1015 (review), which we probably ought to address as well.

In other words, as we currently don't have :number notation, we probably ought to figure out how we're going to do its style of scaling as well.

aphillips and others added 4 commits April 23, 2025 07:18
In the 2025-05-05 call, we agreed to remove the proposed design so that we can commit the design document to the main line in the repo.
Copy link
Collaborator

@eemeli eemeli left a comment

Choose a reason for hiding this comment

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

Without an explicit proposed design, I have no objections to merging this. I've added a couple of comments inline, along with typo-ish corrections.

aphillips added 2 commits May 19, 2025 08:45
In our most recent call, we discussed adopting the proposed design found in this commit. Note the addition of selector behavior.
Comment on lines +143 to +144
- REQUIRE the `:number` and `:integer` functions to support `style=percent` as an option
- The functions `:number` and `:integer` scale the operand, e.g. `{5 :integer style=percent}` formats as `500%`.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I find :integer style=percent to be confusing, and I don't think we should support it. Even though it may be well specified, it's not obvious to a reader whether the scaling happens before the rounding, or after it. We should avoid introducing unnecessary uncertainty, esp. as it's likely that implementations will choose to default to maximumFractionDigits=0 for percent formatting.

Already now, the options supported by :integer are a subset of the options supported by :number, so this would only extend the set of excluded options.

Suggested change
- REQUIRE the `:number` and `:integer` functions to support `style=percent` as an option
- The functions `:number` and `:integer` scale the operand, e.g. `{5 :integer style=percent}` formats as `500%`.
- REQUIRE the `:number` function to support `style=percent` as an option
- The function `:number` scales the operand, e.g. `{5 :number style=percent}` formats as `500%`.

Copy link
Member Author

Choose a reason for hiding this comment

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

Fair enough. In this commit I was trying to capture the WG telecon conversation and I understood it to include :integer.

I don't think :integer style=percent is confusing, but it does add more surface to number formatting. Do I suppose correctly that you'd oppose adding other stylistic options (compact, scientific, etc.) to :integer as well?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Probably, yes. I don't want to commit to the position prematurely, but it'd be my starting point to be a bit queasy about needing to think about whether 4.2e2 is really an "integer" or not.

Comment on lines +145 to +146
Note that the selector selects on the scaled value
(selectors currently cannot select fractional parts)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Highlighting for @sffc and @ryzokuken that this may require supporting something like style as an Intl.PluralRules option, or being ok with Intl.MessageFormat offering a capability beyond Intl.PluralRules.

Is plural category selection on percent-formatted values already well supported by the ICU libraries?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Also, if selection makes sense for :number style=percent, is there a reason to not allow selection for :unit unit=percent as well? And if the latter is fine, then why not allow selection for all of :unit.

My preference would be for us to not allow for selection with percent formatting at this time.

Copy link
Member Author

Choose a reason for hiding this comment

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

this may require supporting something like style as an Intl.PluralRules option

I don't think this necessarily follows? The function handler would scale the value before using plural rules, just as the function handler calls Intl.NumberFormat to format the number later.

My preference would be for us to not allow for selection with percent formatting at this time.

This would require a separate placeholder just to perform message selection on what is fundamentally a number.

Copy link
Collaborator

Choose a reason for hiding this comment

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

this may require supporting something like style as an Intl.PluralRules option

I don't think this necessarily follows? The function handler would scale the value before using plural rules, just as the function handler calls Intl.NumberFormat to format the number later.

Quite recently in tc39/ecma402#989 we added notation as one of the Intl.PluralRules options. It would therefore be a bit surprising to effectively support style=percent for selection scaling in Intl.MessageFormat, but not for Intl.PluralRules.

My preference would be for us to not allow for selection with percent formatting at this time.

This would require a separate placeholder just to perform message selection on what is fundamentally a number.

Does your position generalise to preferring selection to work on all :unit values?

Copy link
Member Author

Choose a reason for hiding this comment

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

Does your position generalise to preferring selection to work on all :unit values?

I'm not sure. I think it might, at least in terms of exact selection. Plural rules don't work well/aren't needed (what's actually wanted is more like inflection). But there are plenty of cases where one might want a specific value to produce a specific message, with 0 being the most common case.

A lot of unit selection cases actually look like what ChoiceFormat is good at: separating messages above/below a given threshold, e.g. switching from kilometers to meters (or miles to feet) in driving directions at some cutoff.

Comment on lines +148 to +153
> Examples. These are equivalent **except** that `:unit` does NOT scale.
>```
> {{You have {$pct :number style=percent} remaining.}}
> {{You have {$pct :unit unit=percent} remaining.}}
> {{You have {$pct :integer style=percent} remaining.}}
>```
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
> Examples. These are equivalent **except** that `:unit` does NOT scale.
>```
> {{You have {$pct :number style=percent} remaining.}}
> {{You have {$pct :unit unit=percent} remaining.}}
> {{You have {$pct :integer style=percent} remaining.}}
>```
> Examples. These are equivalent **except** that `:unit` does NOT scale.
>```
> {{You have {$pct :number style=percent} remaining.}}
> {{You have {$scaledPct :unit unit=percent} remaining.}}
>```

@@ -0,0 +1,389 @@
# Formatting Percent Values

Status: **Proposed**
Copy link
Collaborator

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.

Copy link
Member Author

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.

Copy link
Member

@sffc sffc left a comment

Choose a reason for hiding this comment

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

I'm not happy with the Proposed Design: Let's not add the style option back to :number. It was productive when we removed it, and I don't want to go back. Among other things, it causes problems when mixed with other options, questionable plural selection behavior as @eemeli noted, and inconsistent with Intl.NumberFormat which uses style for currency and unit as well.

I also do not like requiring :unit unit=percent, because we want percent formatting to not pull in all unit formatting data, but this is unavoidable in this design for reasons the ICU4X TC has expressed previously.


## Constraints

_What prior decisions and existing conditions limit the possible design?_
Copy link
Member

Choose a reason for hiding this comment

The 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?

Copy link
Member Author

Choose a reason for hiding this comment

The 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.

Comment on lines +251 to +256
_Cons_
- Adds to a (growing) list of functions
- Not "special enough" to warrant its own formatter?
- Unlike `:currency`, because currency formatting depends on currency codes,
which in turn impact default fraction digits, and other presentation details.
Nothing like that applies to percents.
Copy link
Member

Choose a reason for hiding this comment

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

I don't buy any of these cons.

  1. There is no set of rules I've seen to dictate when or when not to add new functions. Apparently we are okay with :integer and :number being separate even though one is a superset of another. And we seem to have been okay with :date, :time, and :datetime being different. So I don't think "we don't want to grow the list of functions" is sufficient justification to not add this function.
  2. This document is self-contradictory in percent formatting being "important enough". Apparently the author thinks that it is "important enough" to muddy :number by adding back the style=percent option, and that it is important enough to make :unit unit=percent be REQUIRED.
  3. We have evidence of at least one option being different, a potential scaling option. But, besides this, I point back to :integer which is just a subset of :number.

Copy link
Member Author

Choose a reason for hiding this comment

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

There is no set of rules I've seen to dictate when or when not to add new functions. Apparently we are okay with :integer and :number being separate even though one is a superset of another. And we seem to have been okay with :date, :time, and :datetime being different. So I don't think "we don't want to grow the list of functions" is sufficient justification to not add this function.

In the call (and elsewhere), we discussed that :integer is a convenience function for :number (specifically a shorthand for {$n :number maximumFractionDigits=0}. The question is whether we are "splitters" or "lumpers" for functions, that is, whether we prefer a single function with lots of options or many functions with few(er) options.

I called out in the call that there is no rhyme nor reason to our current policy.

Apparently the author thinks that it is "important enough" to muddy :number by adding back the style=percent option, and that it is important enough to make :unit unit=percent be REQUIRED.

The author is recording what the WG wanted recorded. (In fact, the author does not agree with this design)

@aphillips
Copy link
Member Author

(chair hat OFF)

Adding style=percent to :number would not prevent us from having a convenience function :percent later (or now). This suggests that we prefer a "lumping" vs. "splitting" design for functions, with at least one function with "all the options", possibly surrounded by a host of convenience functions. This is to some degree what we have now, e.g.:

  • :number with :integer and possibly :percent and other later functions as convenience
  • :datetime with :date, :time (and as many as 16 more) functions as convenience

I'm not opposed to adding convenience functions. I think :integer was exactly the right thing to do for our users.

Alternatively we could regard :percent as a separate function handler (including with the special selection logic related to scaling) with targeted options. This suggests that we might add other specialized functions in the future, although it doesn't require it. We also have this as a model:

  • :number has :currency as a (draft) friend. :number cannot format currency values (it can format a number from a currency, but not as a currency)

I think :unit unit=percent is a red herring. It exists because carving out percent from CLDR units is janky (especially given that per-mille and per-myriad exist). My guess is that no one will use it when there's a big shiny function :percent available. Having two baroque means ({$p :number style=percent} and {$p :unit unit=percent}) for formatting percentages is just weird: we have a common-enough use case and two different, equally-inconvenient means of formatting it?

My preferred solution is:

  • add :percent
  • do NOT add :number style=percent
  • do NOT require :unit unit=percent (but permit it)

(chair hat ON)

I observe that we're not closing on a design. If we do not achieve consensus on a design in the next (2025-06-02) call, I will call for a ballot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
design Design document or issues related to design functions Issue pertains to the default function set LDML48 LDML48 Release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants