Skip to content

Conversation

USERSATOSHI
Copy link
Contributor

@USERSATOSHI USERSATOSHI commented Aug 14, 2025

What?

Closes #22628

This PR adds numberFormatI18n function to the @wordpress/i18n package that formats numbers according to the current locale settings, providing a JavaScript equivalent to WordPress's PHP number_format_i18n function

Why?

WordPress translation functions have had number_format_i18n for formatting numbers in a locale-appropriate way for some time. This functionality was missing from the JavaScript @wordpress/i18n package, making it difficult for developers to format numbers consistently with the site's locale in JavaScript/React components.

How?

The implementation adds a numberFormatI18n function that:

  1. Leverages locale information from the i18n system: Uses the lang property from existing locale data rather than adding dependencies on other packages
  2. Converts WordPress locales to JavaScript-compatible format: Transforms WordPress locale format (e.g., de_DE) to JavaScript BCP 47 format (e.g., de-DE)
  3. Uses native Intl.NumberFormat: Utilizes the browser's built-in internationalization API for consistent formatting
  4. Handles edge cases:
    • Falls back to en-US for invalid or unrecognized locales
    • Clamps decimal places to 0-20 range for Node.js compatibility
    • Supports domain-specific locale settings

Syntax

// CreateI18n
numberFormatI18n(number: number, decimals?: number, domain?: TextDomain): string

// DefaultI18n
numberFormatI18n(number: number, decimals?: number): string

Testing Instructions

Unit Tests for this function in create-i18n test file should suffice.

Screenshots or screencast

image

@USERSATOSHI USERSATOSHI changed the title Add numberFormatI18n Port to @wordpress/i18n Prototype numberFormatI18n Port to @wordpress/i18n Aug 14, 2025
Comment on lines 413 to 420
const wpLocale = localeData.lang || 'en_US';
let jsLocale;
if ( ! I18N_WP_LOCALE_REGEXP.test( wpLocale ) ) {
// If the locale is not in the expected format, default to 'en-US'.
jsLocale = 'en-US';
} else {
jsLocale = wpLocale.replace( '_', '-' );
}
Copy link
Member

Choose a reason for hiding this comment

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

Let's make sure this works for all the locales listed at https://make.wordpress.org/polyglots/teams/

I just tested them with Intl.getCanonicalLocales() and here are my findings:

  • de-DE-formal are actually supported (I thought it wasn't), so we should make it work too.
  • art-xemoji is supported too
  • pt-PT-ao90 doesn't work, and Intl.getCanonicalLocales() throws

So a regex is too overkill, maybe simply replacing the underscores is enough. And then perhaps try { Intl.getCanonicalLocales() } catch ... to prevent errors.

We should have tests for such "special" locales too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, thanks for informing, updating to reflect this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

pt-PT-ao90 doesn't work, and Intl.getCanonicalLocales() throws

Seems likes this is not yet supported in both browsers and Node.js Intl so either we have to make it fallback to en-US ( current behaviour ) or write an if statement to make it fallback to pt-PT.

Other than that, I have changed to use getCanonicalLocales() to test locale and I have updated the tests to include both special locales and all the wp Locales mentioned in make.wordpress.org/polyglots/teams

cc: @swissspidy

- added tests for special locales and all polygot locales
- switched form regex to a getCanonicalLocale() test to check locale validity
@USERSATOSHI USERSATOSHI marked this pull request as ready for review August 19, 2025 07:33
@USERSATOSHI USERSATOSHI requested a review from swissspidy August 19, 2025 07:33
Copy link

github-actions bot commented Aug 19, 2025

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: USERSATOSHI <[email protected]>
Co-authored-by: swissspidy <[email protected]>
Co-authored-by: pedro-mendonca <[email protected]>
Co-authored-by: Clorith <[email protected]>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@USERSATOSHI USERSATOSHI changed the title Prototype numberFormatI18n Port to @wordpress/i18n Add numberFormatI18n Port to @wordpress/i18n Aug 19, 2025
@swissspidy swissspidy added [Type] Enhancement A suggestion for improvement. Internationalization (i18n) Issues or PRs related to internationalization efforts [Package] i18n /packages/i18n labels Aug 19, 2025
Co-authored-by: Pascal Birchler <[email protected]>
Comment on lines +431 to +437
/**
* Range limit of `maximumFractionDigits` in Node.js is 0-20
* Max limit of `maximumFractionDigits` in Browsers is 0-100 ( {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#maximumfractiondigits} )
*
* Hence we limit the decimals to 20 to ensure compatibility across environments.
*/
const validDecimals = Math.max( 0, Math.min( decimals, 20 ) );
Copy link
Member

Choose a reason for hiding this comment

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

What's the motivation for this? Is it really our responsibility to clamp this value? Seems more like the consumer's job.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The reason behind this was that during testing I found out that while Browser supported upto 100 decimals , Nodejs was limited to around 20 decimal points and anything above that it would throw an error saying invalid range.
Hence I thought of adding clamp to this to prevent this error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Internationalization (i18n) Issues or PRs related to internationalization efforts [Package] i18n /packages/i18n [Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Introduce number_format_i18n for @wordpress/i18n
2 participants