Skip to content
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

Provide correct WPCOM language code as locale when requesting CSV exports #10197

Open
wants to merge 11 commits into
base: develop
Choose a base branch
from

Conversation

Jinksi
Copy link
Member

@Jinksi Jinksi commented Jan 20, 2025

Fixes #10149

Warning

Blocked due to issues with email translations not working on transact-platform-server. See https://github.com/Automattic/transact-platform-server/issues/7161 for this.

Changes proposed in this Pull Request

Transact-platform-server (WPCOM) uses different language codes for translations than WordPress. Rather than language_country (en_US), wpcom language codes are mostly just language (en). Some wpcom language codes are represented as language-region, e.g. pt-br for Portugese (Brazil) (see translate.wordpress.com).

When requesting CSV exports, region-specific language codes were not working correctly, as reported in #10149.

This PR fixes this by:

  • Fixing convert_to_server_locale:
    • Correctly convert WP locales to wpcom-compatible language codes, in particular, region-specific languages.
    • Reducing the list of hard-coded language codes to only region-specific languages to reduce the maintenance burden when new languages are introduced.
    • More thoroughly documenting what is occurring in the function and where the wpcom language codes are sourced from.
    • Added a unit test for this function to validate the expected conversion for multiple strings
  • Reducing redundant code related to passing the locate from PHP → JS → PHP.
    • Since the current user's WP locale is already available in wcSettings, I've relied on this to replace wcpaySettings.userLocale.
    • This reduces the maintenance burden of redundant, duplicate code.
  • Map the WP locale → WPCOM language code within the REST API controller, rather than within JS.
    • This simplifies the client logic, allowing it to pass the available WordPress locale code without modification, relying on the API controller layer to transform the request into a transact-platform-server compatible locale code.

Testing instructions

Important

You must use production or sandbox transact-platform-server for email/CSV translations to work correctly.
Alternatively, if you've figured out how to get these email/CSV translations working on your local transact-platform-server, please let me know how!

  1. Browse to WP Admin -> Users -> Profile
  2. Change the profile language to a wpcom-supported region-specific language:
    • pt_BR Portugese (Brazil)
    • zh_CN Chinese (Simplified)
    • zh_TW Chinese (Traditional)
  3. Run a CSV export of transactions, payouts or disputes, making sure you have more than a single pagination to trigger a server export
  4. Ensure the email and CSV are provided in the user language.
  5. Repeat steps above with other wpcom-supported languages
  6. Repeat steps above with a language unsupported by wpcom, e.g. Polish pl_PL
    • The email and CSV language should be provided in English.

WPCOM-compatible languages

WPCOM language code WP locale code Language
ar ar Arabic
de de_* German
es es_* Spanish
fr fr_* French
he he_* Hebrew
id id_* Indonesian
it it_* Italian
ja ja Japanese
ko ko_* Korean
nl nl_* Dutch (Netherlands)
pt-br pt_BR Portuguese (Brazil)
ru ru_* Russian (Russia)
sv sv_* Swedish (Sweden)
tr tr_* Turkish (Turkey)
zh-cn zh_CN Simplified Chinese (Singapore)
zh-tw zh_TW Traditional Chinese (Taiwan)

TODO

  • Consider mutating locale to match WPCOM langCode in PHP REST API controller instead
    • I've taken this approach in 069aab4
  • Run npm run changelog to add a changelog file, choose patch to leave it empty if the change is not significant. You can add multiple changelog files in one PR by running this command a few times.
  • Covered with tests (or have a good reason not to test in description ☝️)
  • Tested on mobile (or does not apply)

Post merge

Additional information

As discussed in the #10149 comments, I initially considered using the WP localeWPCOM language code mapping available in @automattic/languages. This would have allowed us to rely on this package as the source of truth for wpcom "langSlugs". A downside of this approach is that this package is relatively heavy, adding +5kB to various WooPayments JS bundle sizes.

Instead, I've decided to reduce the complexity of this solution and move the language code conversion logic to PHP.

I have not found a PHP package/resource with the same list of WP Locale → WPCOM Language. However, in reducing the hardcoded list to only the three that are region-specific, the maintenance burden is reduced. This approach is common across A8C (GH search), of which I found Jetpack's to be the simplest, which I've adapted and used in #10197.

@botwoo
Copy link
Collaborator

botwoo commented Jan 20, 2025

Test the build

Option 1. Jetpack Beta

  • Install and activate Jetpack Beta.
  • Use this build by searching for PR number 10197 or branch name fix/10149-csv-export-dash-separated-locales-not-working in your-test.site/wp-admin/admin.php?page=jetpack-beta&plugin=woocommerce-payments

Option 2. Jurassic Ninja - available for logged-in A12s

🚀 Launch a JN site with this branch 🚀

ℹ️ Install this Tampermonkey script to get more options.


Build info:

  • Latest commit: 3e2c750
  • Build time: 2025-01-21 01:12:40 UTC

Note: the build is updated when a new commit is pushed to this PR.

Copy link
Contributor

github-actions bot commented Jan 20, 2025

Size Change: -5 B (0%)

Total Size: 1.36 MB

Filename Size Change
release/woocommerce-payments/dist/index.js 301 kB +2 B (0%)
release/woocommerce-payments/dist/multi-currency-switcher-block.js 60.9 kB -2 B (0%)
release/woocommerce-payments/dist/multi-currency.js 57.6 kB -2 B (0%)
release/woocommerce-payments/dist/payment-gateways.js 38.7 kB -1 B (0%)
release/woocommerce-payments/dist/settings.js 224 kB -2 B (0%)
ℹ️ View Unchanged
Filename Size
release/woocommerce-payments/assets/css/admin.css 1.37 kB
release/woocommerce-payments/assets/css/admin.rtl.css 1.37 kB
release/woocommerce-payments/assets/css/success.css 182 B
release/woocommerce-payments/assets/css/success.rtl.css 184 B
release/woocommerce-payments/dist/blocks-checkout-rtl.css 2.64 kB
release/woocommerce-payments/dist/blocks-checkout.css 2.64 kB
release/woocommerce-payments/dist/blocks-checkout.js 55.6 kB
release/woocommerce-payments/dist/cart-block.js 17.2 kB
release/woocommerce-payments/dist/cart.js 5.73 kB
release/woocommerce-payments/dist/checkout-rtl.css 1.13 kB
release/woocommerce-payments/dist/checkout.css 1.13 kB
release/woocommerce-payments/dist/checkout.js 33.6 kB
release/woocommerce-payments/dist/express-checkout-rtl.css 229 B
release/woocommerce-payments/dist/express-checkout.css 229 B
release/woocommerce-payments/dist/express-checkout.js 15.7 kB
release/woocommerce-payments/dist/frontend-tracks.js 854 B
release/woocommerce-payments/dist/index-rtl.css 39.5 kB
release/woocommerce-payments/dist/index.css 39.5 kB
release/woocommerce-payments/dist/multi-currency-analytics.js 1.08 kB
release/woocommerce-payments/dist/multi-currency-rtl.css 4.47 kB
release/woocommerce-payments/dist/multi-currency.css 4.47 kB
release/woocommerce-payments/dist/order-rtl.css 730 B
release/woocommerce-payments/dist/order.css 730 B
release/woocommerce-payments/dist/order.js 42.3 kB
release/woocommerce-payments/dist/payment-gateways-rtl.css 1.33 kB
release/woocommerce-payments/dist/payment-gateways.css 1.33 kB
release/woocommerce-payments/dist/plugins-page-rtl.css 386 B
release/woocommerce-payments/dist/plugins-page.css 386 B
release/woocommerce-payments/dist/plugins-page.js 20.1 kB
release/woocommerce-payments/dist/product-details-rtl.css 433 B
release/woocommerce-payments/dist/product-details.css 436 B
release/woocommerce-payments/dist/product-details.js 12.5 kB
release/woocommerce-payments/dist/settings-rtl.css 11.6 kB
release/woocommerce-payments/dist/settings.css 11.5 kB
release/woocommerce-payments/dist/subscription-edit-page.js 703 B
release/woocommerce-payments/dist/subscription-product-onboarding-modal-rtl.css 524 B
release/woocommerce-payments/dist/subscription-product-onboarding-modal.css 524 B
release/woocommerce-payments/dist/subscription-product-onboarding-modal.js 20.2 kB
release/woocommerce-payments/dist/subscription-product-onboarding-toast.js 730 B
release/woocommerce-payments/dist/subscriptions-empty-state-rtl.css 120 B
release/woocommerce-payments/dist/subscriptions-empty-state.css 120 B
release/woocommerce-payments/dist/subscriptions-empty-state.js 19.3 kB
release/woocommerce-payments/dist/tokenized-express-checkout-rtl.css 229 B
release/woocommerce-payments/dist/tokenized-express-checkout.css 229 B
release/woocommerce-payments/dist/tokenized-express-checkout.js 16.6 kB
release/woocommerce-payments/dist/tos-rtl.css 235 B
release/woocommerce-payments/dist/tos.css 235 B
release/woocommerce-payments/dist/tos.js 21.8 kB
release/woocommerce-payments/dist/woopay-direct-checkout.js 6.13 kB
release/woocommerce-payments/dist/woopay-express-button.js 25 kB
release/woocommerce-payments/dist/woopay-rtl.css 4.31 kB
release/woocommerce-payments/dist/woopay.css 4.28 kB
release/woocommerce-payments/dist/woopay.js 71 kB
release/woocommerce-payments/includes/subscriptions/assets/css/plugin-page.css 625 B
release/woocommerce-payments/includes/subscriptions/assets/js/plugin-page.js 814 B
release/woocommerce-payments/vendor/automattic/jetpack-assets/build/i18n-loader.js 2.46 kB
release/woocommerce-payments/vendor/automattic/jetpack-assets/build/jetpack-script-data.js 772 B
release/woocommerce-payments/vendor/automattic/jetpack-assets/src/js/i18n-loader.js 1.02 kB
release/woocommerce-payments/vendor/automattic/jetpack-assets/src/js/script-data.js 69 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/babel.config.js 163 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/identity-crisis.css 2.47 kB
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/identity-crisis.js 14.2 kB
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/identity-crisis.rtl.css 2.47 kB
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-connection.css 10 kB
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-connection.js 28.4 kB
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-connection.rtl.css 10 kB
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-admin-create-user.css 198 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-admin-create-user.js 280 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-admin-create-user.rtl.css 198 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-login.css 625 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-login.js 333 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-login.rtl.css 626 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-users.js 424 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/tracks-ajax.js 521 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/tracks-callables.js 585 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/src/sso/jetpack-sso-admin-create-user.css 215 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/src/sso/jetpack-sso-admin-create-user.js 521 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/src/sso/jetpack-sso-login.css 721 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/src/sso/jetpack-sso-login.js 412 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/src/sso/jetpack-sso-users.js 632 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/about.css 1.04 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/admin-empty-state.css 294 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/admin-order-statuses.css 408 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/admin.css 3.59 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/checkout.css 301 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/modal.css 746 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/view-subscription.css 574 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/wcs-upgrade.css 414 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/admin-pointers.js 543 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/admin.js 9.4 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/jstz.js 6.78 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/jstz.min.js 3.84 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/meta-boxes-coupon.js 545 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/meta-boxes-subscription.js 2.52 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/moment.js 22.2 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/moment.min.js 11.7 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/payment-method-restrictions.js 1.29 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/wcs-meta-boxes-order.js 507 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/frontend/payment-methods.js 358 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/frontend/single-product.js 428 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/frontend/view-subscription.js 1.38 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/frontend/wcs-cart.js 782 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/modal.js 1.09 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/wcs-upgrade.js 1.26 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/build/index.css 391 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/build/index.js 3.04 kB

compressed-size-action

@@ -84,7 +84,7 @@ const formatQueryFilters = ( query ) => ( {
],
status_is: query.statusIs,
status_is_not: query.statusIsNot,
locale: query.userLocale,
locale: query.locale,
Copy link
Member Author

Choose a reason for hiding this comment

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

Leaving this as a generic query param, since this could be site, user or manually-selected locale in the future. These endpoints do not mandate this to be the user locale.

Copy link
Contributor

Choose a reason for hiding this comment

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

(Side note not relevant to this PR)

Is this formatQueryFilters operating as an "allow list"?

It looks like the outcome of this method is to:

  • Convert "pascalCase" keys to underscore snake_case vibe (server uses snake_case convention).
  • Format (render to consistent text) some query data e.g. dates.
  • And in the case of match and locale, allow them through unchanged.

Low priority questions…

  • Is the "allow list" functionality intended, would it be simpler to trust the client (calling code) and only format what needs formatting, allow any keys through?
  • Could we use a generic snake_case conversion instead of doing it manually, key by key?

*
* @return array
*/
public static function get_language_data( $language ) {
Copy link
Member Author

Choose a reason for hiding this comment

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

get_language_data is no longer used.

Copy link
Contributor

Choose a reason for hiding this comment

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

Nice. And to confirm, it was only used to generate/render our JS settings data, which was not needed?

return $base_locale;
public static function convert_to_server_locale( string $wp_locale ): string {
$wp_locale_lowercase = strtolower( $wp_locale );
$region_specific_wpcom_language_codes = [ 'pt_br', 'pt-br', 'zh_tw', 'zh-tw', 'zh_cn', 'zh-cn' ];
Copy link
Member Author

Choose a reason for hiding this comment

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

Reducing the manual mapping of locales only to those that are region-specific.

This approach is borrowed from Jetpack's get_iso_639_locale()

Copy link
Contributor

Choose a reason for hiding this comment

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

This approach is borrowed from Jetpack's get_iso_639_locale()

Recommend adding a comment "maintenance hint" about this, i.e. guide future team when WPCOM adds a new language (or removes one).

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe in the docblock.

@@ -75,7 +75,8 @@ global.wcSettings = {
failed: 'Failed',
paid: 'Paid',
},
l10n: {
locale: {
siteLocale: 'en_US',
userLocale: 'en_US',
Copy link
Member Author

Choose a reason for hiding this comment

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

Updating this to the accurately match what is available in the wcSettings global JS variable.

@Jinksi
Copy link
Member Author

Jinksi commented Jan 21, 2025

In testing, I've noticed that using "Portugese" other than "Portugese (Brazil)" pt_PT results in partially translated emails.

image

⚠️ Before merging, we'll need to clarify the expected behaviour:

  • If partially-translated emails are to be avoided, reinstate the hard-coded list of translations and enforce the fallback to en within client.
    • Alternatively, let server manage which languages will be provided and which will fall back to en (this makes more sense)
  • If partially-translated emails are OK, continue allowing server to handle the fallback translations.

Update in testing, I notice that other emails are partially translated when using pt_PT, e.g. WooCommerce new order emails.

Copy link
Contributor

@haszari haszari left a comment

Choose a reason for hiding this comment

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

I have done a code review only. I approve!

  • Great to see some redundant code / data (page bloat!) removed.
  • The mapping is clearly defined and easier to maintain when supported languages change.

I left a bunch of comments about style and architecture considerations, I'll leave it to y'all to decide if any are worth following up.

Also I suggest tweaking the title to celebrate the win - translated service-generated emails now use correct language? The description has good info on the "how" :)

@@ -84,7 +84,7 @@ const formatQueryFilters = ( query ) => ( {
],
status_is: query.statusIs,
status_is_not: query.statusIsNot,
locale: query.userLocale,
locale: query.locale,
Copy link
Contributor

Choose a reason for hiding this comment

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

(Side note not relevant to this PR)

Is this formatQueryFilters operating as an "allow list"?

It looks like the outcome of this method is to:

  • Convert "pascalCase" keys to underscore snake_case vibe (server uses snake_case convention).
  • Format (render to consistent text) some query data e.g. dates.
  • And in the case of match and locale, allow them through unchanged.

Low priority questions…

  • Is the "allow list" functionality intended, would it be simpler to trust the client (calling code) and only format what needs formatting, allow any keys through?
  • Could we use a generic snake_case conversion instead of doing it manually, key by key?

@@ -38,7 +38,7 @@ const formatQueryFilters = ( query ) => ( {
: query.search,
status_is: query.statusIs,
status_is_not: query.statusIsNot,
locale: query.userLocale,
locale: query.locale,
} );
Copy link
Contributor

Choose a reason for hiding this comment

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

Similar comment to above: are these intentionally allow-lists or could we simplify by using generic processing for query args.

@@ -214,7 +214,7 @@ export const DepositsList = (): JSX.Element => {

const endpointExport = async () => {
const userEmail = wcpaySettings.currentUserEmail;
const userLocale = wcpaySettings.userLocale.code;
const locale = wcSettings.locale.userLocale;
Copy link
Contributor

Choose a reason for hiding this comment

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

This is deceptive!

  • Is wcSettings.locale.userLocale a ~2-letter code?
  • wcpaySettings.userLocale.code is a struct with other stuff in it (code: english_name: ; native_name: ;) - do we need it in our settings?

Using the store settings seems cleaner to me 🚀

Copy link
Contributor

Choose a reason for hiding this comment

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

This is deceptive!

(i.e. took me a while to see what was changing)

Copy link
Contributor

Choose a reason for hiding this comment

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

OMG nice, you have removed wcpaySettings.userLocale 🫡

* @example 'Español'
*/
native_name: string;
};
Copy link
Contributor

Choose a reason for hiding this comment

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

🫡 oh captain, my captain

remove that redundant code 🧹

$wpcom_locale = WC_Payments_Utils::convert_to_server_locale(
$request->get_param( 'locale' )
);
$filters = $this->get_disputes_filters( $request );
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice and simple to do this inline. Long term I wonder if we might want middleware-style generic converters for various standard args.

That is probably overengineering, but at the same time, I worry that our request wrapper handling in client is too manual, since it's almost a 1:1 mapping to the service API, tweaking a few things here and there. One way to document that "magic" is to implement as middleware pattern. For example, WooPayments JavaScript front end calls store PHP/REST API, store PHP generically adds authentication for WooPayments Service (WPCOM) API.

return $base_locale;
public static function convert_to_server_locale( string $wp_locale ): string {
$wp_locale_lowercase = strtolower( $wp_locale );
$region_specific_wpcom_language_codes = [ 'pt_br', 'pt-br', 'zh_tw', 'zh-tw', 'zh_cn', 'zh-cn' ];
Copy link
Contributor

Choose a reason for hiding this comment

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

This approach is borrowed from Jetpack's get_iso_639_locale()

Recommend adding a comment "maintenance hint" about this, i.e. guide future team when WPCOM adds a new language (or removes one).

$base_locale = substr( $locale, 0, 2 );
if ( in_array( $base_locale, $supported, true ) ) {
return $base_locale;
public static function convert_to_server_locale( string $wp_locale ): string {
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor nitpick on naming, could be clearer IMO.

  • convert – is map clearer? I.e. we are mapping from one system to another.
  • server – I will always rail against the word server, it's too generic. In this case we could use wpcom (the platform our service runs on), or woopayments_service.
  • Maybe map_to_wpcom_locale_code? I think code helps too, clarify that the input and output are the ~2 letter code things; locale could be represented a few ways.

Also suggest refreshing the doc comment (it's pretty clear as is), especially if you tweak the name.

return $base_locale;
public static function convert_to_server_locale( string $wp_locale ): string {
$wp_locale_lowercase = strtolower( $wp_locale );
$region_specific_wpcom_language_codes = [ 'pt_br', 'pt-br', 'zh_tw', 'zh-tw', 'zh_cn', 'zh-cn' ];
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe in the docblock.


if ( empty( $language_code ) ) {
// If the language code is empty, we return 'en' as a fallback.
return 'en';
Copy link
Contributor

Choose a reason for hiding this comment

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

There's a mix of early-return and "return $language_code" style here. I recommend rewriting as early-return while here, then each case will be a single if, no nesting.

Hmm .. if this is verbatim from Jetpack code … maybe should leave as is? If so make that clear in the comments.

'Supported locale (Chinese (Simplified))' => [ 'zh_CN', 'zh-cn' ],
'Supported locale (Chinese (Traditional))' => [ 'zh_TW', 'zh-tw' ],
'Empty locale fallback to en' => [ '', 'en' ],
];
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it worth testing a range of unsupported locales? The empty case is likely less important than uncommon language.

Also I would like to see a test for inexact match, e.g. en_AU or pt_PT. Maybe useful to group & comment the various test (map) scenarios in the provider too. Another way to do that is to have separate tests for each of the mapping scenarios, then the test name + provider name are "self documenting".

@nagpai
Copy link
Contributor

nagpai commented Jan 22, 2025

⚠️ I did a manual test on my Pressable hosted test site.

  • I set the user profile language to Brazilian Portuguese.
  • For some reason, I see the locale param being passed as pt_BR . I would expect this to be pt-br

image

  • The language of the email seems English, but the headers look Portuguese.

Here's what I see when I change the language to German .

image

@nagpai nagpai requested a review from a team January 22, 2025 09:47
@Jinksi
Copy link
Member Author

Jinksi commented Jan 22, 2025

Thanks for testing @nagpai

For some reason, I see the locale param being passed as pt_BR . I would expect this to be pt-br

In this new implementation, the locale passed from browser -> PHP REST API controller should be the WP locale ('pt_BR'). This will map to 'pt-br' when passing from controller → WPCOM.

So the headers are correct for this implementation.

The email should translate for 'pt-br', so I'll also conduct further testing to see if I can see the correctly translated emails for various languages.

@Jinksi Jinksi added status: blocked The issue is blocked from progressing, waiting for another piece of work to be done. pr: in progress and removed pr: needs review labels Jan 22, 2025
@Jinksi
Copy link
Member Author

Jinksi commented Jan 22, 2025

The language of the email seems English, but the headers look Portuguese.

@nagpai This highlights a problem with our approach to email transactions.

I've been able to reproduce this problem where emails are in one language, CSV in another.

Config:

  • Site & WCPay account WP locale code ja
  • User profile language WP locale code pt_BR

Result:

  • Email translated to Japanese
  • CSV translated to Portuguese

Therefore:

  • CSV export emails will always be sent in the site locale: source.
  • A transact-platform-server change is required to ensure the user locale is used for email as well.
  • Due to a separate transact-platform-server issue (I’ll open one today), emails will not be translated for the majority of WP site locales represented by > 2 chars, falling back to English.
  • I will mark this PR as blocked and open a new transact-platform-server PR proposing a fix for email translations. This client PR may change, removing the WP → WPCOM locale mapping from the client. FYI @haszari, I'll also take your suggestions on board once I finalise what code is remaining (e.g. the comments on the mapping function may not be relevant).

@Jinksi
Copy link
Member Author

Jinksi commented Jan 23, 2025

I will mark this PR as blocked and open a new transact-platform-server PR proposing a fix for email translations.

I've opened issue https://github.com/Automattic/transact-platform-server/issues/7161 for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pr: in progress status: blocked The issue is blocked from progressing, waiting for another piece of work to be done.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

CSV export email messages for pt_BR, zh_CN, zh_TW fall back to en_US, instead of using user language
4 participants