Использование локализаций и кодов локали в Capacitor SDK

Почему это важно

Коды локали используются, когда Adapty выбирает локализацию для флоу или онбординга, а также при чтении Remote Config для кастомного пейвола.

Коды локали устроены непросто и могут отличаться от платформы к платформе, поэтому Adapty использует единый внутренний стандарт для всех поддерживаемых платформ. Понимание этого стандарта помогает предсказать, какую локализацию получит пользователь.

Стандарт кодов локализации в Adapty

В кодах локализации Adapty использует слегка изменённый стандарт BCP 47: каждый код состоит из подтегов в нижнем регистре, разделённых дефисами. Например: en (английский), pt-br (португальский (Бразилия)), zh (упрощённый китайский), zh-hant (традиционный китайский).

Соответствие кодов локали

В SDK v4 флоу и онбординги сопоставляют коды локали по-разному: флоу локализуются SDK на устройстве, онбординги — сервером Adapty.

Флоу и пейволы Paywall Builder

Пейвол, созданный в Paywall Builder, в SDK v4 доставляется как флоу, поэтому описанное ниже правило распространяется на оба случая.

Сравнение выполняется точное. SDK сравнивает переданный вами код с кодами локализации флоу посимвольно: не меняет регистр, не заменяет подчёркивания (_) дефисами (-) и не откатывается к языковому субтегу. Для флоу с локализацией pt-br подходит только pt-br: pt-BR, pt_BR и pt-PT — не совпадут.

Когда код не совпадает ни с одной локализацией, флоу молча отображается в своей локализации по умолчанию — SDK не возвращает ошибку и не записывает предупреждение.

Когда код совпадает, Adapty объединяет локализацию с локализацией по умолчанию: строки и ресурсы, не определённые в найденной локализации, берутся из локализации по умолчанию.

Отсутствие кода локали — это не то же самое, что запросить локализацию флоу по умолчанию: SDK подставляет фиксированный en. Флоу, у которого локаль по умолчанию — de, всё равно отображается на en, если у него есть локализация en, и только при её отсутствии откатывается к de.

Warning

Передавайте код локали точно в том виде, в каком он настроен в дашборде — строчные подтеги, разделённые дефисами. Не передавайте системный идентификатор локали как есть: navigator.language возвращает pt-BR, и это приведёт к откату на локализацию по умолчанию. Преобразуйте значение в приложении перед передачей.

Онбординги

Онбординги локализуются на сервере, и серверная логика допускает различные форматы. Когда вы передаёте locale в getOnboarding:

  1. Строка локали приводится к нижнему регистру, все символы подчёркивания (_) заменяются дефисами (-)
  2. Adapty ищет локализацию с точно совпадающим кодом локали
  3. Если совпадение не найдено, Adapty берёт подстроку до первого дефиса (pt для pt-br) и ищет соответствующую локализацию
  4. Если совпадение снова не найдено, Adapty возвращает контент для локали онбординга по умолчанию

This way pt_BR, pt-BR, and pt-br all resolve to the same onboarding localization.

Реализация локализаций

В SDK v4 при получении флоу не нужно передавать код локали — getFlow возвращает флоу со всеми его локализациями, а Adapty применяет одну из них при построении представления флоу.

  • Флоу, собранные в билдере: SDK не считывает локаль устройства, поэтому определите её в своём приложении и передайте через опцию locale в createFlowView. Это необязательно — если не передать, флоу отобразится на en или в локали по умолчанию, если флоу не имеет локализации en.

    import { createFlowView } from '@adapty/capacitor';
    
    const view = await createFlowView(flow, { locale: 'es' });

view.locale сообщает о локализации, с которой было построено представление. Оба параметра — locale и view.locale — требуют Capacitor SDK 4.0.1-beta.1, а на более ранних версиях view.locale возвращает undefined. Обработчик onAppeared возвращает то же значение.

  • Пользовательские пейволы (Remote Config): getFlow возвращает все настроенные локализации в flow.remoteConfigs. Каждая запись содержит код lang и объект data. Выберите запись, соответствующую пользователю, с собственным фолбэком:

const flow = await adapty.getFlow({ placementId: 'placement_id' });
const config = flow.remoteConfigs?.find((c) => c.lang === 'en') ?? flow.remoteConfigs?.[0];
// read your values from config?.data

Adapty хранит коды lang в формате, описанном в разделе Стандарт кодов локалей в Adapty. SDK не сопоставляет Remote Config с локалью автоматически, поэтому выбор нужной записи остаётся на усмотрение вашего приложения.

Почему это важно

Коды локалей используются в нескольких сценариях — например, когда нужно получить правильный пейвол для текущей локализации приложения.

Поскольку коды локалей сложны и могут отличаться от платформы к платформе, мы опираемся на внутренний стандарт для всех поддерживаемых платформ. Именно поэтому важно понимать, что именно вы отправляете на наш сервер для получения правильной локализации и что происходит дальше — чтобы вы всегда получали ожидаемый результат.

Стандарт кодов локалей в Adapty

Для кодов локалей Adapty использует слегка модифицированный стандарт BCP 47: каждый код состоит из подтегов в нижнем регистре, разделённых дефисами. Несколько примеров: en (английский), pt-br (португальский (Бразилия)), zh (китайский упрощённый), zh-hant (китайский традиционный).

Сопоставление кода локали

Когда Adapty получает вызов от клиентского SDK с кодом локали и начинает поиск соответствующей локализации пейвола, происходит следующее:

  1. Входящая строка локали приводится к нижнему регистру, а все символы подчёркивания (_) заменяются дефисами (-)
  2. Затем выполняется поиск локализации с полностью совпадающим кодом локали
  3. Если совпадение не найдено, берётся подстрока до первого дефиса (pt для pt-br) и выполняется поиск совпадающей локализации
  4. Если совпадение снова не найдено, возвращается контент для локали пейвола по умолчанию

Таким образом, устройства iOS, отправившее 'pt_BR', Android-устройство, отправившее pt-BR, и другое устройство, отправившее pt-br, получат один и тот же результат.

Если вы думаете о локализациях, скорее всего, вы уже работаете с локализованными строковыми файлами в вашем проекте. В таком случае мы рекомендуем добавить пару ключ-значение с нужным кодом локали Adapty в каждый из ваших файлов для соответствующих локализаций. Затем извлекайте значение для этого ключа при вызове SDK:

// 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

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);
  };
};

Таким образом вы можете быть уверены, что полностью контролируете, какая локализация будет получена для каждого пользователя вашего приложения.

Альтернативный способ реализации локализаций

Похожего (но не идентичного) результата можно добиться, не задавая явно коды локалей для каждой локализации. Для этого достаточно извлечь код локали из других объектов, предоставляемых платформой, например:


const getLocaleCode = () => {
  if (Capacitor.getPlatform() === 'ios') {
    return navigator.language || 'en';
  } else {
    return navigator.language || 'en';
  }
};

const fetchPaywall = async () => {
  const locale = getLocaleCode();
  // pass locale code to adapty.getPaywall or adapty.getPaywallForDefaultAudience method
  const paywall = await adapty.getPaywallForDefaultAudience('placement_id', locale);
};

Обратите внимание, что мы не рекомендуем этот подход по нескольким причинам:

  1. На iOS предпочитаемые языки и текущая локаль — это не одно и то же. Чтобы локализация выбиралась корректно, придётся либо положиться на логику Apple, которая работает из коробки при рекомендуемом подходе с локализованными файлами строк, либо воспроизвести её самостоятельно.
  2. Сложно предсказать, что именно получит сервер Adapty. Например, на iOS с устройства можно передать локаль вида ar_OM@numbers='latn', и в ответ на этот запрос вы получите не локализацию ar-om, которую ожидали, а ar — что, скорее всего, будет неожиданностью. Should you decide to use this approach anyway — make sure you’ve covered all the relevant use cases.