feat: default the checkout locale to the buyer's browser locale#962
Open
vkartaviy wants to merge 3 commits into
Open
feat: default the checkout locale to the buyer's browser locale#962vkartaviy wants to merge 3 commits into
vkartaviy wants to merge 3 commits into
Conversation
The custom-checkout entry points (Web Billing, Stripe, Stripe Express, Paddle) defaulted selectedLocale to hardcoded English, while the paywall flow already defaults to navigator.language. This aligns all four checkout flows with the paywall path so the checkout UI and the lifecycle emails follow the buyer's browser locale by default; passing selectedLocale still overrides and English remains the final fallback.
The rationale (default for checkout, mirrors the paywall path) lives in the PR description; the function name and signature carry the rest.
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.
What
The four SDK checkout entry points now default
selectedLocaleto the buyer's browser locale (navigator.language) instead of hardcoded English, matching what the paywall flow (presentPaywall) already does. PassingselectedLocaleexplicitly still overrides, and English stays the final fallback.Why
Today the paywall flow and the custom-checkout flows resolve the default locale differently:
selectedLocaleis omittedpresentPaywallnavigator.language(auto-detected)purchase()-> Web BillingenglishLocale("en")purchase()-> StripeenglishLocale("en")presentExpressPurchaseButton(Stripe Express)englishLocale("en")purchase()-> PaddleenglishLocale("en")So a developer who renders a RevenueCat paywall gets a localized checkout for free, while a developer who builds their own UI and calls
purchase()silently gets an English checkout for every buyer unless they discover and passselectedLocale. Same SDK, opposite behavior, no warning.It also affects emails: the locale captured at checkout is persisted on the subscription and drives the language of the lifecycle/transactional emails. With the English default, a buyer on a Japanese browser sees an English checkout and receives English emails, with nothing in the integration to explain why.
Change
getBrowserLocale()helper insrc/helpers/locale-helper.ts: returnsnavigator.language, orundefinedoutside a browser (SSR-safe viagetNullableWindow).main.tsnow defaultselectedLocale = getBrowserLocale() ?? englishLocale.defaultLocaleand the explicitselectedLocaleoverride are unchanged. English remains the final fallback when the browser locale is unavailable.It localizes correctly for real regional tags
Browsers report regional tags (
ja-JP, not bareja). Verified the checkout renders in the buyer's language across realistic tags, with noselectedLocalepassed (the SDK normalizes region -> language internally):navigator.languageja-JPen-USpt-BRfr-FRde-DERollout / compatibility
selectedLocale(and optionallydefaultLocale); nothing changes for them.navigator.languagespreference list against the supported-locale set (instead of only the topnavigator.language), and route the paywall path through the samegetBrowserLocale()resolver so there is a single source of the default.Test plan
getBrowserLocale()(returnsnavigator.language;undefinedoutside a browser).svelte-checkclean; existing purchase-flow and locale suites pass.ja-JP/en-US/pt-BR/fr-FR/de-DEwith noselectedLocalepassed.Opening as a draft for feedback on the default change and the rollout approach.
Note
Medium Risk
Behavior change for integrations that omit selectedLocale: non-English buyers get localized checkout and persisted locale-driven emails; low code risk but meaningful product/compatibility impact for existing apps.
Overview
Custom checkout flows now default
selectedLocaleto the buyer's browser locale (navigator.languagevia new SSR-safegetBrowserLocale()), with English as fallback when the browser locale is unavailable. ExplicitselectedLocalestill overrides;defaultLocaleis unchanged.This applies to
presentExpressPurchaseButton, Stripe, Web Billing, and Paddle purchase paths inmain.ts, aligning them withpresentPaywallbehavior instead of silently defaulting to English.Unit tests cover
getBrowserLocale()in-browser and whenwindowis missing.Reviewed by Cursor Bugbot for commit 87eefda. Bugbot is set up for automated code reviews on this repo. Configure here.