Skip to content

fix(mf1/runtime): Use CLDR currency fraction digits - #476

Open
NUAAwqy wants to merge 1 commit into
messageformat:mainfrom
NUAAwqy:fix/mf1-currency-fraction-digits
Open

NUAAwqy wants to merge 1 commit into
messageformat:mainfrom
NUAAwqy:fix/mf1-currency-fraction-digits

Conversation

@NUAAwqy

@NUAAwqy NUAAwqy commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

Addresses #327 (the first of its two asks).

What's broken

numberFmt() in mf1/packages/runtime/src/fmt/number.ts hard-codes minimumFractionDigits: 2 / maximumFractionDigits: 2 for the currency style, so every currency is formatted with two decimals regardless of what CLDR says for that code: JPY comes out as ¥5.55 instead of ¥6, and KWD as 5.56 instead of 5.555. Intl.NumberFormat already applies the CLDR digit ranges itself; the pins are a remnant from before it did — as the maintainer noted on #327, "those lines could now be dropped" and PRs for that would be welcome.

The fix

Drop the two pins in numberFmt() (the {V, number, currency} / {V, number, currency:JPY} path) and do the same in numberCurrency() (the ::currency/XXX skeleton path), letting Intl.NumberFormat use the CLDR digit range for the currency code:

locale / currency {V, number, currency} before after
ja, JPY, V=5.55 The total is ¥5.55. The total is ¥6.
en, JPY, V=5.55 (currency:JPY) The total is ¥5.55. The total is ¥6.
en, KWD, V=5.555 The total is 5.56. The total is 5.555.
en, USD, V=5.555 The total is 5.56. The total is 5.56. (unchanged)

2-decimal currencies — the overwhelming majority, and every existing expectation in the repo — are unchanged, because CLDR's digit count for them is 2 anyway.

Scope

This is deliberately only the first half of #327, hence Addresses rather than Fixes. The skeleton half of that issue (¤#,##0.0000 should clamp to USD's 2 digits) lives in @messageformat/number-skeleton, is the disputed half, and needs its own change.

Validation

  • Five new cases added to the existing Number formatter table in mf1/packages/core/src/messages.test.ts. Red first: on the pristine tree Tests 4 failed | 188 passed (192); with the fix, 192 passed.
  • Whole-repo A/B: pristine 614f28f → Tests 2792 passed | 4 skipped; with the fix → 2797 passed | 4 skipped — exactly the 5 new cases, and no existing expectation had to be edited.
  • Mutation checks: reverting only numberCurrency fails exactly the 3 skeleton-currency cases; reverting only numberFmt fails exactly the {V, number, {type}} case. Neither hunk is carried by the other.
  • Gates, all rc=0: npm test, npm run build, npm run lint, npx prettier --check .
  • The KWD/USD expectations use regular expressions such as /5\.555\.$/ because the currency symbol varies by ICU build; the digit counts themselves are ICU-version-independent.

Prepared and tested with AI assistance; no human review is claimed.

`numberFmt()` and `numberCurrency()` pinned `minimumFractionDigits: 2` and
`maximumFractionDigits: 2` for currency formatting. Those overrides win
against the digit count that `Intl.NumberFormat` derives from the currency
itself, so a zero-digit currency such as JPY formatted `¥5.55` instead of
`¥6`, and a three-digit currency such as KWD was rounded down to `5.56`.

Leaving both options unset restores each currency's own precision, and
leaves two-digit currencies exactly as they were.

Addresses messageformat#327

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant