Skip to content

i18n: format-currency - bring formatCurrency method to i18n-calypso #100097

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

Merged
merged 6 commits into from
Feb 25, 2025

Conversation

chriskmnds
Copy link
Contributor

@chriskmnds chriskmnds commented Feb 20, 2025

Part of addressing https://github.com/Automattic/i18n-issues/issues/939
Based off #100008

Proposed Changes

We bring the formatCurrency method to i18n-calypso to begin centralizing with the other number-formatters.

  • This does not bring the full format-currency package - there is still getCurrencyObject to migrate.
  • This does not deprecate formatCurrency function either. We will target one consumer scenario, the plan prices, to verify. We will do the rest in follow-ups.

This is a crucial refactor and creates the point from which we absolutely need to push through the remaining work (to bring currency formatting in full into i18n-calypso and deprecate format-currency). In this state, there is insane duplication and risk.

Why are these changes being made?

This is part of addressing https://github.com/Automattic/i18n-issues/issues/939, which aims at unifying number & currency-number formatting

TODO

  • Target pricing in the plans-grid as the first scenario.
  • Add also the tests from format-currency package.

Testing Instructions

  • unit tests
  • the plan billing descriptions on plans pages are now served through this new method:
  1. go to /start/plans and /plans/:site
  2. confirm the billing descriptions render correctly. Use different locale & currency combinations

For EL locale & USD:

Screenshot 2025-02-24 at 5 04 50 PM

Pre-merge Checklist

  • Has the general commit checklist been followed? (PCYsg-hS-p2)
  • Have you written new tests for your changes?
  • Have you tested the feature in Simple (P9HQHe-k8-p2), Atomic (P9HQHe-jW-p2), and self-hosted Jetpack sites (PCYsg-g6b-p2)?
  • Have you checked for TypeScript, React or other console errors?
  • Have you used memoizing on expensive computations? More info in Memoizing with create-selector and Using memoizing selectors and Our Approach to Data
  • Have we added the "[Status] String Freeze" label as soon as any new strings were ready for translation (p4TIVU-5Jq-p2)?
    • For UI changes, have we tested the change in various languages (for example, ES, PT, FR, or DE)? The length of text and words vary significantly between languages.
  • For changes affecting Jetpack: Have we added the "[Status] Needs Privacy Updates" label if this pull request changes what data or activity we track or use (p4TIVU-aUh-p2)?

@chriskmnds chriskmnds self-assigned this Feb 20, 2025
Copy link

github-actions bot commented Feb 20, 2025

@matticbot
Copy link
Contributor

matticbot commented Feb 20, 2025

Here is how your PR affects size of JS and CSS bundles shipped to the user's browser:

App Entrypoints (~2011 bytes added 📈 [gzipped])

name                   parsed_size           gzip_size
entry-stepper              +5518 B  (+0.4%)    +1989 B  (+0.5%)
entry-main                 +5518 B  (+0.3%)    +1995 B  (+0.3%)
entry-subscriptions        +5487 B  (+0.3%)    +1973 B  (+0.4%)
entry-login                +5487 B  (+0.3%)    +1973 B  (+0.3%)
entry-domains-landing      +5487 B  (+0.8%)    +1973 B  (+1.0%)

Common code that is always downloaded and parsed every time the app is loaded, no matter which route is used.

Sections (~17 bytes added 📈 [gzipped])

name                      parsed_size           gzip_size
update-design-flow              +43 B  (+0.0%)      +17 B  (+0.0%)
plugins                         +43 B  (+0.0%)      +17 B  (+0.0%)
plans                           +43 B  (+0.0%)      +17 B  (+0.0%)
jetpack-app                     +43 B  (+0.0%)      +17 B  (+0.0%)
async-step-unified-plans        +43 B  (+0.0%)      +17 B  (+0.0%)

Sections contain code specific for a given set of routes. Is downloaded and parsed only when a particular route is navigated to.

Async-loaded Components (~17 bytes added 📈 [gzipped])

name                                             parsed_size           gzip_size
async-load-signup-steps-plans-theme-preselected        +43 B  (+0.0%)      +17 B  (+0.0%)
async-load-signup-steps-plans                          +43 B  (+0.0%)      +17 B  (+0.0%)

React components that are loaded lazily, when a certain part of UI is displayed for the first time.

Legend

What is parsed and gzip size?

Parsed Size: Uncompressed size of the JS and CSS files. This much code needs to be parsed and stored in memory.
Gzip Size: Compressed size of the JS and CSS files. This much data needs to be downloaded over network.

Generated by performance advisor bot at iscalypsofastyet.com.

@matticbot
Copy link
Contributor

This PR modifies the release build for the following Calypso Apps:

For info about this notification, see here: PCYsg-OT6-p2

  • blaze-dashboard
  • command-palette-wp-admin
  • happy-blocks
  • help-center
  • notifications
  • odyssey-stats
  • wpcom-block-editor

To test WordPress.com changes, run install-plugin.sh $pluginSlug update/i18n-format-currency-add-to-i18n-calypso on your sandbox.

@matticbot matticbot added the [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. label Feb 20, 2025
Copy link
Contributor Author

@chriskmnds chriskmnds Feb 20, 2025

Choose a reason for hiding this comment

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

@sirbrillig / @Automattic/i18n this will be the new (temporary) home for all number-formatters, form this point on including currency. The handlers themselves are raw, without state. The i18n-calypso instance/prototype simply lends its internal state for locale/geoLocation.

Once we migrate everything into this location, we can deprecate entirely format-currency and decide where to host number-formatters (it might move to a JP package or elsewhere). We can then introduce state handling to it if we want (or just keep using the handlers thorugh the i18n-calypso & JP number-format packages (which are basically portals/proxies).

Copy link
Member

@sirbrillig sirbrillig left a comment

Choose a reason for hiding this comment

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

Looks pretty good! I noticed one small edge case that I should have brought up in #99981

Comment on lines +30 to +38
if ( retries ) {
return getCachedFormatter( {
locale: fallbackLocale,
options,
retries: retries - 1,
} );
}

throw error;
Copy link
Contributor Author

@chriskmnds chriskmnds Feb 24, 2025

Choose a reason for hiding this comment

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

Added a limit on retries so it doesn't end up in an infinite loop - theoretically, as that's unlikely to happen with a valid fallback locale. Also failing loudly if for whatever reason it happens.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

These tests are identical to format-currency package's, although they are done through the more primitive number-formatters interface (where we pass the locale and everything else as properties).

@@ -307,6 +307,73 @@ describe( 'I18n', function () {
} );
} );

describe( 'formatCurrency', () => {
Copy link
Contributor Author

@chriskmnds chriskmnds Feb 24, 2025

Choose a reason for hiding this comment

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

The tests here combined with the primitive ones above should result in the same coverage as originally in format-currency package's. We basically test that the state handled properties (locale & geoLocation) propagate propagate properly into number-formatters.

@chriskmnds chriskmnds mentioned this pull request Feb 24, 2025
8 tasks
@chriskmnds chriskmnds marked this pull request as ready for review February 24, 2025 15:07
@chriskmnds chriskmnds requested review from a team as code owners February 24, 2025 15:07
@chriskmnds chriskmnds requested a review from jeyip February 24, 2025 15:07
@chriskmnds
Copy link
Contributor Author

This is now ready for testing. The plan billing descriptions are set through this method now. See testing instructions.

Once we deploy here, the next couple of PRs will aim at bringing getCurrencyObject to i18n-calypso, migrate all exiting uses of formatCurrency and getCurrencyObject to use i18n-calypso, deprecate/remove format-currency from repo. From there, we will decide on the final location of number-formatters (whether JP or monorepo).

cc @sirbrillig / @Automattic/i18n

@chriskmnds chriskmnds force-pushed the update/i18n-format-currency-add-to-i18n-calypso branch from 33a6230 to 7eb8d35 Compare February 24, 2025 15:13
@chriskmnds chriskmnds requested review from a team as code owners February 24, 2025 15:13
@chriskmnds chriskmnds changed the base branch from update/i18n-format-currency-normalize-code to trunk February 24, 2025 15:14
@chriskmnds
Copy link
Contributor Author

ah sorry for the wide ping. rebased then changed parent here

Copy link
Member

@sirbrillig sirbrillig left a comment

Choose a reason for hiding this comment

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

This works as described for me. The only thing I wasn't sure how to test is the logged-out plans page, and I'm not sure if that even uses these same code paths.

@chriskmnds
Copy link
Contributor Author

chriskmnds commented Feb 25, 2025

This works as described for me. The only thing I wasn't sure how to test is the logged-out plans page, and I'm not sure if that even uses these same code paths.

Thanks @sirbrillig ! Did you mean the /pricing page? That's a whole different (sad) story. It's a different piece of code that's mostly rendered server-side.

p.s. since you mentioned I checked, and it looks like the currencies aren't localised properly or consistently there. I'll send these out in a P2 post so it gets looked at:

  • logged-out with EL (el. prefixed URL):
Screenshot 2025-02-25 at 7 41 43 AM
  • logged-in with EL locale - there is an attempt to localise the currencies (still not fine. missing the US):
Screenshot 2025-02-25 at 7 50 44 AM
  • and if logged-in and visit without the el. prefix, it looks a little weird (currencies localised, text isn't):
Screenshot 2025-02-25 at 7 47 25 AM

@chriskmnds
Copy link
Contributor Author

This works as described for me. The only thing I wasn't sure how to test is the logged-out plans page, and I'm not sure if that even uses these same code paths.

Thanks @sirbrillig ! Did you mean the /pricing page? That's a whole different (sad) story. It's a different piece of code that's mostly rendered server-side.

p.s. since you mentioned I checked, and it looks like the currencies aren't localised properly or consistently there. I'll send these out in a P2 post so it gets looked at:

  • logged-out with EL (el. prefixed URL):
Screenshot 2025-02-25 at 7 41 43 AM * logged-in with EL locale - there is an attempt to localise the currencies (still not fine. missing the `US`): Screenshot 2025-02-25 at 7 50 44 AM * and if logged-in and visit without the `el.` prefix, it looks a little weird (currencies localised, text isn't): Screenshot 2025-02-25 at 7 47 25 AM

Well actually, let me tag someone from @Automattic/martech-autobots. For context - in EL/DE, symbol follows the number e.g. 123 €.

@chriskmnds chriskmnds merged commit be491de into trunk Feb 25, 2025
17 checks passed
@chriskmnds chriskmnds deleted the update/i18n-format-currency-add-to-i18n-calypso branch February 25, 2025 16:17
@github-actions github-actions bot removed the [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. label Feb 25, 2025
@claudiucelfilip
Copy link
Contributor

@chriskmnds Thanks for tagging us!
Here's how price localization works for the /pricing page:

  • the page's locale is not used for price localization, so adding el or de to the URL won't affect the price format.
  • to get the price symbol and position, we use the getCurrencyObject, which outputs $ and after position for el and de. en-GB or zh-tw should output the US$.
  • if the user is logged in, we use their selected locale
  • if the user is logged out, we use the browser's locale (ie. what getCurrencyObject determines). For testing, changing the Locale in the Sensor should affect the price localization.

@chriskmnds
Copy link
Contributor Author

@claudiucelfilip Thanks for replying :-)

  • the page's locale is not used for price localization, so adding el or de to the URL won't affect the price format.

Should it not though? It feels a bit weird to be accessing explicitly el.foo.com and seeing everything translated except for currencies and numbers. To my mind, I'd expect a fully translated page with some geo-location retrieving behind the scenes for locale variants.

I might be missing something, but it's also not done consistently e.g. img below / Enterprise price is properly rendered when in incognito. So for EL, it should in fact be 123 US$

Screenshot 2025-02-26 at 11 46 20 AM
  • to get the price symbol and position, we use the getCurrencyObject, which outputs $ and after position for el and de. en-GB or zh-tw should output the US$.

For EL/DE the symbol is also US$, at least according to monorepo's format-currency. (as done for Enterprise plan above)

  • if the user is logged out, we use the browser's locale (ie. what getCurrencyObject determines). For testing, changing the Locale in the Sensor should affect the price localization.

Is getCurrencyObject imported from format-currency NPM package? Or is it some other replica or PHP code?

@claudiucelfilip
Copy link
Contributor

claudiucelfilip commented Feb 26, 2025

Should it not though? It feels a bit weird to be accessing explicitly el.foo.com and seeing everything translated except for currencies and numbers. To my mind, I'd expect a fully translated page with some geo-location retrieving behind the scenes for locale variants.

That makes send, the other hand, it might be important to use the user's OS/browser locale settings. Might be best to get some more feedback as this has caused confusion in the past.

might be missing something, but it's also not done consistently e.g. img below / Enterprise price is properly rendered when in incognito. So for EL, it should in fact be 123 US$

Good catch. The price for Enterprise is formatted on the backend, which I think we should address.

Is getCurrencyObject imported from format-currency NPM package? Or is it some other replica or PHP code?

Yes, it's from the "@automattic/format-currency": "2.0.0" package.

@chriskmnds
Copy link
Contributor Author

Sounds good @claudiucelfilip

Yes, it's from the "@automattic/format-currency": "2.0.0" package.

Jsut a note on this one. We are actually in the process of "deprecating" that package in favour of a centralised number-formatters package. For the moment, we migrated everything into i18n-calypso (see this last PR where we update all refs within wp-calypso). Not sure yet how it will progress from here - it might end up a separate package (number-formatters) with internal state handling, or just the raw parts and continued use of i18n-calypso. Would it be a problem importing i18n-calypso in Landpack and using formatCurrency from there? (be worth checking that peer dependency in package.json whether it will be a problem)

@claudiucelfilip
Copy link
Contributor

Would it be a problem importing i18n-calypso in Landpack and using formatCurrency from there? (be worth checking that peer dependency in package.json whether it will be a problem)

@chriskmnds There shouldn't be a problem.
I tried it out but the i18n-calypso npm module isn't updated with the latest changes. Using the Calypso build, formatCurrency worked as expected.
There were a couple issues when switching the other two functions (getCurrencyObject, setDefaultLocale) to i18n-calypso:

  • the getCurrencyObject outputs a different symbol position for DE locale (before instead of after).
Screenshot 2025-03-03 at 11 39 48
  • setDefaultLocale is missing from the module, which is used in this fix D163955-code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants