fix(adyen): send shopperLocale so redirect pages match the Drop-in language - #808
Open
acasazza wants to merge 3 commits into
Open
fix(adyen): send shopperLocale so redirect pages match the Drop-in language#808acasazza wants to merge 3 commits into
acasazza wants to merge 3 commits into
Conversation
…nguage Adyen uses two locales and only one of them was travelling: - `locale` in the Core configuration is client-side only — it selects the Drop-in's translation bundle. - `shopperLocale` in the payment request is what Adyen uses for the pages it renders itself, in particular the hosted page a redirect method sends the shopper to. `payment_request_data` carried `payment_method`, `return_url`, `origin`, `redirect_from_issuer_method`, `shopper_ip`, `shopperInteraction` and `browser_info`, but no `shopperLocale`, so Adyen fell back to the merchant account default or the country code. A Drop-in correctly rendered in English then handed over to a Klarna page in Italian for an IT market. `shopperLocale` is now sent, derived from the same value that drives the Drop-in (`order.language_code`, falling back to the `locale` prop). Commerce Layer's `language_code` is a bare ISO 639-1 code, so `getAdyenShopperLocale` expands it to the `language-REGION` form Adyen expects (`en` -> `en-US`, `it` -> `it-IT`). When a language cannot be expanded confidently it returns undefined and the field is omitted, preserving Adyen's current fallback rather than sending a locale it may reject. `AdyenPaymentConfig.shopperLocale` overrides the derived value: integrations that only reach the Drop-in through the container had no way to control this at all. The Drop-in's own `locale` is unchanged.
❌ Deploy Preview for commercelayer-react-components failed.
|
commit: |
`npm install -g npm@latest` in the publish workflow started failing with EBADENGINE: npm is now 12, which requires Node ^22.22.2 || ^24.15.0 || >=26, while the runner was pinned to 20.x. Node moves to 22.x, which satisfies it, and the two are now documented as having to move together. gh-pages used `node-version: "latest"`; it moves to 22.x so all three workflows agree on one version. Action versions, across all four workflows: - actions/checkout v4 -> v7 - actions/setup-node v3/v4/v5 -> v7 - pnpm/action-setup v3/v4 -> v6 - softprops/action-gh-release v1 -> v3 - actions/configure-pages v4 -> v6 - actions/upload-pages-artifact v3 -> v5 - actions/deploy-pages v4 -> v5 slackapi/slack-github-action is deliberately left at v1.25.0. v2 redesigned the inputs — the webhook moved from the SLACK_WEBHOOK_URL/SLACK_WEBHOOK_TYPE environment variables to `webhook`/`webhook-type` inputs — so bumping it without migrating the step would silently break the release notification.
acasazza
force-pushed
the
fix/adyen-shopper-locale
branch
from
August 1, 2026 13:01
4adba7d to
0830b2d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Reported
Both halves of that are accurate.
Cause
Adyen uses two locales, and only one of them was travelling:
localeoptions(AdyenPayment.tsx) ←order.language_codeshopperLocalepayment_request_datacarriedpayment_method,return_url,origin,redirect_from_issuer_method,shopper_ip,shopperInteractionandbrowser_info— but noshopperLocale. So Adyen fell back to the merchant account default or thecountryCode(IT), and a Drop-in correctly rendered in English handed over to a Klarna page in Italian.The second half of the report was also true: there was no way to pass this through the container at all.
Fix
shopperLocaleis now sent, derived from the same value that already drives the Drop-in (order.language_code, falling back to thelocaleprop).src/utils/adyenShopperLocale.ts— Commerce Layer'slanguage_codeis a bare ISO 639-1 code (en,it) while Adyen expectslanguage-REGION, so it is expanded:en → en-US,it → it-IT. A locale that already carries a region is just normalised (en_US → en-US). When a language cannot be expanded confidently the helper returnsundefinedand the field is omitted, preserving Adyen's current fallback rather than sending a locale it may reject.AdyenPaymentConfig.shopperLocaleoverrides the derived value, for integrations that need an exact Adyen locale.The Drop-in's own
localeis unchanged.Testing
specs/utils/adyenShopperLocale.spec.ts— 5 tests on the expansion, includingen → en-US(en-ENis not a locale, so it needs the explicit mapping) and the deliberateundefined.specs/payment_source/AdyenPayment.shopperLocale.spec.tsx— 5 tests that mount the component, fire the realonSubmithandler and assert what actually lands inpayment_request_data: derived from the order language, never taken from the country code, overridable by config, omitted when unexpandable, and falling back to thelocaleprop.Removing the one line that sends the field fails 4 of those 5, so they are load-bearing.
tsc --noEmitclean on the changed files;biome checkclean on the new files.--no-verify: the pre-commit hook runs the whole suite, which has 43 pre-existing failures on cleanmain(network-backed availability/price specs). Verified by stashing this branch's changes and re-running — identical count.Needs confirmation against a real account
I could not verify end-to-end that Commerce Layer forwards
shopperLocalefrompayment_request_datato Adyen's/payments, nor that Klarna honours it. The evidence is good — the SDK types the field asRecord<string, any>described as "The Adyen payment request data, collected by client", and the existing code already sends Adyen-native camelCase fields such asshopperInteractionthrough it — but it is evidence, not proof. Worth reproducing the reported order once with this build before shipping.If CL turns out to whitelist keys rather than pass them through, the fix moves to the API side and this PR becomes the client half of it.
🤖 Generated with Claude Code