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

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

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

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

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

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

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

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

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

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

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

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

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

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

Warning

Передавайте код локали в точности так, как он настроен в дашборде — строчные буквы, подтеги разделены дефисами. Не передавайте системный идентификатор локали как есть: Locale.getDefault().toLanguageTag() возвращает pt-BR, а Locale.getDefault().toString() возвращает pt_BR, и оба варианта откатятся к локализации по умолчанию. Преобразуйте значение в приложении перед передачей.

Онбординги

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

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

Таким образом, pt_BR, pt-BR и pt-br — все они указывают на одну и ту же локализацию онбординга.

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

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

  • Флоу, созданные в билдере: SDK не считывает локаль устройства, поэтому определите её в своём приложении и передайте в аргумент locale метода AdaptyUI.getFlowConfiguration. Аргумент необязательный — если его не передать, флоу отобразится на en или на языке по умолчанию, если локализация en не настроена.
  • Кастомные пейволы (Remote Config): getFlow возвращает все настроенные локализации в flow.remoteConfigs. Каждая запись содержит код locale и содержимое конфига (jsonString или разобранный dataMap). Выберите запись, соответствующую пользователю, с собственной логикой фолбэка:
Adapty.getFlow("YOUR_PLACEMENT_ID") { result ->
    when (result) {
        is AdaptyResult.Success -> {
            val flow = result.value
            val config = flow.remoteConfigs.firstOrNull { it.locale == "en" }
                ?: flow.remoteConfigs.firstOrNull()
            // read your values from config?.dataMap
        }
        is AdaptyResult.Error -> {
            // handle the error
        }
    }
}

Adapty хранит коды locale в формате, описанном в разделе Стандарт кодов локалей в 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 strings.xml files

/*
strings.xml - Spanish
*/
<string name="adapty_paywalls_locale">es</string>

/*
strings.xml - Portuguese (Brazil)
*/
<string name="adapty_paywalls_locale">pt-br</string>

// 2. Extract and use the locale code

val localeCode = context.getString(R.string.adapty_paywalls_locale)
// pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method

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

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

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

val locale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
    context.resources.configuration.locales[0]
else
    context.resources.configuration.locale

val localeCode = locale.toLanguageTag()
// pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method

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

Если вы всё же решите использовать этот подход — убедитесь, что охватили все актуальные сценарии.