Use localizations and locale codes in React Native SDK
Why this is important
Locale codes come into play when Adapty picks the localization for a flow, and when you read a remote config for a custom paywall.
Locale codes are complicated and can vary from platform to platform, so Adapty relies on one internal standard across every platform it supports. Understanding that standard helps you predict which localization a user receives.
Locale code standard at Adapty
For locale codes, Adapty uses a slightly modified BCP 47 standard: every code consists of lowercase subtags, separated by hyphens. Some examples: en (English), pt-br (Portuguese (Brazil)), zh (Simplified Chinese), zh-hant (Traditional Chinese).
Locale code matching
When Adapty looks for the localization that matches a user’s locale, the following happens:
- The locale string is converted to lowercase and all the underscores (
_) are replaced with hyphens (-) - Adapty looks for the localization with the fully matching locale code
- If no match is found, Adapty takes the substring before the first hyphen (
ptforpt-br) and looks for the matching localization - If no match is found again, Adapty returns the content for the flow’s default locale
This way 'pt_BR', pt-BR, and pt-br all resolve to the same localization.
Implementing localizations
In SDK v4, you don’t pass a locale code when you fetch a flow — getFlow returns the flow with all of its localizations, and Adapty applies one when the flow view is built.
-
Flows built in the builder: the SDK doesn’t read the device locale, so resolve it in your app and pass it as the
localeparameter ofcreateFlowView, or in theparamsprop of the embeddedAdaptyFlowViewcomponent. It’s optional — omit it and the flow renders inen, or in its default locale when the flow has noenlocalization. When you request a localization the flow doesn’t have, the view falls back to the flow default without an error, and any strings the chosen localization lacks come from the default one.import { createFlowView } from 'react-native-adapty'; const view = await createFlowView(flow, { locale: 'es' });view.localereports the localization the view was actually built with — the locale you requested when that localization exists, and the flow’s default otherwise. Both thelocaleparameter andview.localerequire React Native SDK 4.0.2 or later, andview.localeisundefinedon earlier versions. -
Custom (remote config) paywalls:
getFlowreturns every configured localization inflow.remoteConfigs. Each entry has alangcode and adataobject. Select the entry that matches the user, with your own fallback:
import { adapty } from 'react-native-adapty';
const flow = await adapty.getFlow('placement_id');
const config = flow.remoteConfigs?.find((c) => c.lang === 'en') ?? flow.remoteConfigs?.[0];
// read your values from config?.dataThe locale code matching rules above describe how Adapty normalizes the lang codes stored on each remote config.
Why this is important
There are a few scenarios when locale codes come into play — for example, when you’re trying to fetch the correct paywall for the current localization of your app.
As locale codes are complicated and can vary from platform to platform, we rely on an internal standard for all the platforms we support. However, because these codes are complicated, it is really important for you to understand what exactly are you sending to our server to get the correct localization, and what happens next — so you will always receive what you expect.
Locale code standard at Adapty
For locale codes, Adapty uses a slightly modified BCP 47 standard: every code consists of lowercase subtags, separated by hyphens. Some examples: en (English), pt-br (Portuguese (Brazil)), zh (Simplified Chinese), zh-hant (Traditional Chinese).
Locale code matching
When Adapty receives a call from the client-side SDK with the locale code and starts looking for a corresponding localization of a paywall, the following happens:
- The incoming locale string is converted to lowercase and all the underscores (
_) are replaced with hyphens (-) - We then look for the localization with the fully matching locale code
- If no match was found, we take the substring before the first hyphen (
ptforpt-br) and look for the matching localization - If no match was found again, we return the content for the paywall’s default locale
This way an iOS device that sent 'pt_BR', an Android device that sent pt-BR, and another device that sent pt-br will get the same result.
Implementing localizations: recommended way
If you’re wondering about localizations, chances are you’re already dealing with the localized string files in your project. If that’s the case, we recommend placing some key-value with the intended Adapty locale code in each of your files for the corresponding localizations. And then extract the value for this key when calling our SDK, like so:
// 1. Modify your localization files (e.g., using react-i18next)
/*
en.json
*/
{
"adapty_paywalls_locale": "en"
}
/*
es.json
*/
{
"adapty_paywalls_locale": "es"
}
/*
pt-BR.json
*/
{
"adapty_paywalls_locale": "pt-br"
}
// 2. Extract and use the locale code
import { useTranslation } from 'react-i18next';
import { adapty } from 'react-native-adapty';
const MyComponent = () => {
const { t } = useTranslation();
const fetchPaywall = async () => {
const locale = t('adapty_paywalls_locale');
// pass locale code to adapty.getPaywall or adapty.getPaywallForDefaultAudience method
const paywall = await adapty.getPaywallForDefaultAudience('placement_id', locale);
};
};That way you can ensure you’re in full control of what localization will be retrieved for every user of your app.
Implementing localizations: the other way
You can get similar (but not identical) results without explicitly defining locale codes for every localization. That would mean extracting a locale code from the device, for example via react-native-localize:
import * as RNLocalize from 'react-native-localize';
import { adapty } from 'react-native-adapty';
const fetchPaywall = async () => {
// getLocales() returns the user's preferred locales in BCP-47 format (e.g., 'en-US', 'pt-BR')
const locale = RNLocalize.getLocales()[0].languageTag;
// pass locale code to adapty.getPaywall or adapty.getPaywallForDefaultAudience method
const paywall = await adapty.getPaywallForDefaultAudience('placement_id', locale);
};Note that we don’t recommend this approach due to few reasons:
- On iOS, preferred languages and the current regional locale are not identical. If you want the localization to be picked correctly, you’ll have to either rely on Apple’s resolution logic — which works out of the box when you use the recommended approach with localized string files — or re-create it yourself.
- The device locale may not match any localization you’ve configured in Adapty. In that case the SDK falls back to the first-subtag match or, ultimately, to
en— which may not be the language you’d want to default to for that user.
Should you decide to use this approach anyway — make sure you’ve covered all the relevant use cases.