orderAction.actionType are covered in
Checkout Redirects & Action Types.
Which field controls the language the checkout is displayed in?
paymentInfo.cashierLanguage, passed when you create the order.
There is no Merchant Portal setting that pins the checkout language. If you
want a fixed language, pass
cashierLanguage on every order.
What format does cashierLanguage have to be in?
language[-script][-region], and nothing else:
Examples that pass:
Values that are rejected:
- Underscore separators —
en_USis not a BCP 47 tag. - Variant subtags —
de-DE-1996. - Extension subtags —
en-US-x-foo. - Anything longer than 24 characters.
en-us is accepted and stored as en-US.
What error do I get if the value is wrong?
Two distinct outcomes, and they mean different things:
Both are returned as HTTP 400 at order creation, so a bad value never reaches
the checkout page. If you get
A0047, fix the shape of the string. If you get
A0026, the shape is fine but the language itself is not one Waffo renders —
check the list below.
Does the same field work for subscriptions?
Yes.paymentInfo.cashierLanguage exists on subscription creation with the
same name, the same 24-character limit, the same BCP 47 rules and the same two
errors. It is validated in the same place in the subscription create flow.
Does cashierLanguage affect anything besides the checkout page?
For subscriptions, yes: end-user subscription notifications reuse the same
decision. When Waffo sends a subscription notification to your customer, the
language is cashierLanguage if you supplied one, and otherwise is inferred
from the customer’s payment currency.
Note the difference from the checkout page: a notification is not a browser
session, so there is no Accept-Language header and no country tab to read.
The fallback for notifications is currency-based; the fallback for the
checkout page is country-based (see the next question).
How does the checkout decide the display language? Is there a priority order?
Yes — five layers, evaluated top to bottom. The first layer that produces a value wins.
Two consequences worth designing around:
- Layers 0, 1 and 2 lock the language. Once one of them hits, the language no longer follows the country: the customer can switch the country tab and the copy stays put.
- Only layer 3 follows the country tab. So a customer with no
cashierLanguageand no usableAccept-Languagewill see the copy change as they switch countries — and a customer with either of those will not.
Which country does layer 3 actually use?
It depends on where the order is in its lifecycle, and the distinction matters because the “display country” and the “customer’s country” are not the same thing.
On the selection page the display country can be back-filled to some country
from the order’s candidate list when the customer’s own country is not among
them — that back-filled value does not describe where the customer is, so the
language decision deliberately does not use it.
Selecting the Global tab is not a location, so it is not treated as one: it
falls through to the IP-inferred country.
What is the frozen display language, and why does layer 0 exist?
When the customer submits their choice on the payment-method selection page, the checkout stores the language they were looking at onto the order. From then on that value wins over everything else. It exists to stop the language from drifting mid-payment. A globally available payment method moves the order’s display country to Global, which is a sentinel rather than a real country. Without the snapshot, an order that was being displayed in a local language would flip to the English fallback the moment the customer picked a global method — the customer would watch the page change language between choosing and paying. The snapshot pins whatever they already saw. You cannot set or read this value; it is written by the checkout at submission time. Its practical effect on your integration is only this: after the customer has submitted on the selection page, nothing changes the language any more.What exactly does the checkout read from Accept-Language?
Layer 2 is narrower than most people expect:
- Only the highest-weighted entry of the header is considered. If that one does not map to a supported language, the checkout does not try the next one — it drops to layer 3.
- Only the primary language subtag is used.
zh-Hant-TWin the header collapses tozh; the script and region in the header are discarded. - The accepted primary subtags are
en,es,id,ja,ko,ms,pl,pt,th,tr,vi,zh. Anything else —fr,ru, and so on — yields nothing and falls through to layer 3. - A malformed header (some older in-app browsers emit repeated quality values) degrades to reading the first language tag in the raw string, with the same mapping.
zh from the browser
renders Traditional Chinese — see the script fallback below.
Which languages does the checkout support?
These are the valuescashierLanguage accepts as complete tags:
You are not restricted to exactly these strings. Validation is per subtag, so
any combination of a supported language, an optional supported script, and a
valid ISO region is accepted —
en-SG, for example. What the region changes
is covered next.
I passed en-HK and the page looks identical to en. Is the region subtag ignored?
For the page copy, effectively yes. Checkout copy is maintained in 13
language buckets, and a tag is matched to a bucket by language plus script
only — the region subtag never selects a different set of copy:
So
es-PE and es-CL render the same Spanish copy, and en-KE and en-NG
render the same English copy. The region subtag is still carried on the order
and is still used for locale-aware formatting, but it does not fork the wording.
Two specific rules that surprise people:
- Bare
zhrenders Traditional Chinese. With no script subtag there is nothing to distinguish the two, so the checkout resolveszhtozh-Hant. If you want Simplified, pass aHansscript explicitly —zh-Hansorzh-Hans-HK. - A language with no bucket renders English.
ru-RUpasses validation, but Russian is not one of the 13 copy buckets, so the page renders in English.
I passed nothing at all. What language does the customer see?
Layers 2 to 4 decide, in that order:- If the customer’s browser sends a header whose top entry is one of the 12 accepted primary subtags, that language is used, and it will not change if they switch country tabs.
- Otherwise the language is inferred from the country — their real location before submission, the display country after — and does change as they switch tabs.
- If neither yields anything, the page is in English.
cashierLanguage
rather than relying on this chain.
Which languages can the customer pick when downloading a receipt?
The same 13 buckets, offered by their own names: English, Português, Español, 繁體中文, 简体中文, Tiếng Việt, ไทย, Bahasa Indonesia, 日本語, 한국어, Bahasa Melayu, Polski, Türkçe. The receipt language is the customer’s own choice at download time. It is not driven bycashierLanguage, and picking one does not change the language of
the checkout page.
Can I let the customer choose the checkout language themselves?
There is no language selector on the checkout page. The language is whatever the five-layer chain resolves to. What the customer can change is the country, on the payment-method selection page, and that shifts the language only when the chain reached layer 3 — that is, only when you did not passcashierLanguage and their browser header did
not match. See
Checkout Redirects & Action Types
for when the country selector is shown at all.