Использование локализаций и кодов локали в Unity 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.

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

Онбординги

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

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

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

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

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

  • Пейволы, созданные во Flow Builder и Paywall Builder: SDK не считывает локаль устройства, поэтому определите её в приложении и передайте при создании отображения. Код локали необязателен — если его не указать, флоу отображается на en, или в своей локали по умолчанию, если локализации en нет.
  • Кастомные (Remote Config) пейволы: GetFlow возвращает все настроенные локализации в flow.RemoteConfigs. Каждый элемент — это AdaptyRemoteConfig с кодом Locale и словарём Dictionary со значениями. Выберите элемент, соответствующий пользователю, реализовав собственный фолбэк:
using System.Linq;
using AdaptySDK;

Adapty.GetFlow("YOUR_PLACEMENT_ID", (flow, error) => {
    if (error != null) {
        // handle the error
        return;
    }

    var config = flow.RemoteConfigs.FirstOrDefault(c => c.Locale == "en")
        ?? flow.RemoteConfigs.FirstOrDefault();
    // read your values from config?.Dictionary
});

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

Выбор локализации флоу

Чтобы отобразить флоу или пейвол с определённой локализацией, передайте код локали в SetLocale при создании представления:

var parameters = new AdaptyUICreateFlowViewParameters()
    .SetLocale("pt-br");

AdaptyUI.CreateFlowView(flow, parameters, (view, error) => {
    if (error != null) {
        // handle the error
        return;
    }

    // view.Locale — the localization the view was built with
});

Представление сообщает локализацию, с которой оно фактически было собрано, в view.Locale: ту, которую вы запросили, если она существует, или локализацию флоу по умолчанию в противном случае.

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

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

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

Стандарт кодов локалей в 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 Unity's Localization package)

/*
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
using UnityEngine;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;
using AdaptySDK;

public class PaywallManager : MonoBehaviour
{
    public async void FetchPaywall()
    {
        // Get the current locale from Unity's Localization system
        var locale = LocalizationSettings.SelectedLocale;
        var localeCode = GetAdaptyLocaleCode(locale);
        
        // Pass locale code to Adapty.GetPaywall or Adapty.GetPaywallForDefaultAudience method
        Adapty.GetPaywall("placement_id", localeCode, (paywall, error) => {
            if (error != null) {
                // handle the error
                return;
            }
            // Use the paywall
        });
    }
    
    private string GetAdaptyLocaleCode(Locale locale)
    {
        // Convert Unity locale to Adapty format
        var localeIdentifier = locale.Identifier.Code;
        return localeIdentifier.ToLower().Replace('_', '-');
    }
}

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

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

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

using UnityEngine;
using System.Globalization;
using AdaptySDK;

public class PaywallManager : MonoBehaviour
{
    public void FetchPaywall()
    {
        var localeCode = GetSystemLocaleCode();
        
        // Pass locale code to Adapty.GetPaywall or Adapty.GetPaywallForDefaultAudience method
        Adapty.GetPaywall("placement_id", localeCode, (paywall, error) => {
            if (error != null) {
                // handle the error
                return;
            }
            // Use the paywall
        });
    }
    
    private string GetSystemLocaleCode()
    {
        // Get the system's current culture
        var culture = CultureInfo.CurrentCulture;
        var languageCode = culture.TwoLetterISOLanguageName;
        var regionCode = culture.Name.Contains('-') ? culture.Name.Split('-')[1] : null;
        
        if (!string.IsNullOrEmpty(regionCode))
        {
            return $"{languageCode}-{regionCode.ToLower()}";
        }
        
        return languageCode;
    }
}

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

  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.