Языковые настройки для отдельных приложений

Языки приложений в системных настройках

Часто пользователи, говорящие на нескольких языках, устанавливают один из них, например английский, как системный, но в некоторых приложениях хотят выбрать другой язык (нидерландский, китайский, хинди и т. п.). Чтобы приложения были удобнее для таких пользователей, в Android 13 появились следующие функции:

  • Системные настройки. Централизованный раздел, в котором пользователи могут выбрать предпочитаемый язык для каждого приложения.

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

  • Дополнительные API. Эти общедоступные API, например методы setApplicationLocales и getApplicationLocales в LocaleManager, позволяют приложениям устанавливать язык, отличный от системного, во время выполнения.

    Эти API автоматически синхронизируются с системными настройками. Таким образом, приложения, в которых эти API используются для создания собственных окон выбора языка, обеспечивают единообразный пользовательский интерфейс независимо от того, где пользователи выбирают языковые настройки. Общедоступные API также помогают сократить объем шаблонного кода, поддерживают раздельные APK и автоматическое резервное копирование для приложений, чтобы сохранять языковые настройки пользователя на уровне приложения.

    Для обратной совместимости с предыдущими версиями Android эквивалентные API также доступны в AndroidX. Однако обратно совместимые API работают с контекстом AppCompatActivity, а не с контекстом приложения для Android 12 (уровень API 32) и более ранних версий. Доступ к обратно совместимым API можно получить с помощью Appcompat 1.6.0 или более поздней версии.

Общие сведения о реализации этой функции

В таблице ниже приведены рекомендуемые реализации для разных сценариев использования.

Пример использования Рекомендуемые решения
В вашем приложении нет окна выбора языка.
  1. Включите автоматическую поддержку языков для отдельных приложений, чтобы создать файл LocaleConfig и добавить языки приложения в системные настройки.
  2. Если вы хотите добавить в приложение окно выбора языка, реализуйте его в Compose или используйте библиотеку AndroidX и включите реализацию API, чтобы обеспечить обратную совместимость через autoStoreLocales.
В вашем приложении уже есть окно выбора языка.
  1. Включите автоматическую поддержку языков для отдельных приложений, чтобы создать файл LocaleConfig и добавить языки приложения в системные настройки.
  2. Перенесите пользовательскую логику приложения в Compose или общедоступные API, чтобы обеспечить единообразие интерфейса.
  3. Обработайте следующие пограничные случаи:
    1. Вызовите AppCompatDelegate.setApplicationLocales при первом запуске приложения на устройстве с Android 13.
    2. Вызовите AppCompatDelegate.setApplicationLocales, чтобы предоставить системе ранее выбранные пользователем языки в следующих случаях:

Системные настройки для пользователей

В Android 13 и более поздних версиях в системных настройках есть раздел, где можно задать языковые настройки для отдельных приложений. Чтобы пользователи устройств с Android 13 или более поздней версии могли настраивать языки приложения в системных настройках, включите автоматическую поддержку языков для отдельных приложений (рекомендуется) или настройте поддержку вручную.

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

Это рекомендуемый способ добавить поддержку языков для отдельных приложений, поскольку он не требует изменений в XML.

Начиная с Android Studio Giraffe и AGP 8.1, вы можете настроить приложение так, чтобы оно автоматически поддерживало языковые настройки для отдельных приложений. На основе ресурсов проекта AGP генерирует файл LocaleConfig и добавляет ссылку на него в итоговый файл манифеста, поэтому вам больше не нужно делать это вручную. AGP использует ресурсы в папках res модулей приложения и зависимостей модулей библиотек, чтобы определить, какие языки нужно включить в файл LocaleConfig. Это значит, что если вы добавите в приложение ресурсы для нового языка, вам не придется обновлять файл LocaleConfig.

Обратите внимание, что автоматический выбор языка для отдельных приложений поддерживается на устройствах с Android 13 (уровень API 33) или более поздней версии. Чтобы использовать эту функцию, необходимо задать для compileSdkVersion значение 33 или выше. Чтобы настроить языковые предпочтения для отдельных приложений в предыдущих версиях Android, вам по-прежнему нужно использовать API и окна выбора языка в приложении.

Чтобы включить автоматическую поддержку языковых настроек для отдельных приложений, выполните следующие действия:

  1. Чтобы включить эту функцию, используйте настройку generateLocaleConfig в блоке androidResources {} файла build.gradle.kts на уровне модуля (файла build.gradle, если вы используете Groovy). По умолчанию эта функция отключена.

Kotlin

    android {
      androidResources {
        generateLocaleConfig = true
      }
    }

Яркий

  android {
    androidResources {
      generateLocaleConfig true
    }
  }
  1. Укажите региональные настройки по умолчанию:
    1. В папке res модуля приложения создайте файл с названием resources.properties.
    2. В файле resources.properties задайте региональные настройки по умолчанию с помощью ярлыка unqualifiedResLocale. Подробнее о том, как формировать названия региональных настроек…

AGP добавляет этот язык по умолчанию и все указанные вами альтернативные языки, используя каталоги values-* в папке res, в автоматически созданный файл LocaleConfig.

Как формируются названия региональных настроек

Чтобы сформировать название региональных настроек, объедините код языка с необязательными кодами скрипта и региона, разделяя их дефисом:

  • Язык. Используйте двух- или трехбуквенный код по стандарту ISO 639-2.
  • Письменность (необязательно): используйте код ISO 15924.
  • Регион (необязательно). Используйте двухбуквенный код ISO 3166-1-alpha-2 или трехзначный код UN_M.49.

Например, если по умолчанию выбран американский английский:

unqualifiedResLocale=en-US

Добавьте поддерживаемые языки в системных настройках с помощью android:localeConfig.

Вы можете вручную настроить приложение, чтобы его язык можно было выбирать в системных настройках на устройствах с Android 13 или более поздней версии. Для этого создайте XML-файл locale_config и добавьте его в манифест приложения с помощью атрибута android:localeConfig. Если не добавить запись android:localeConfig в манифест, пользователи не смогут выбрать для приложения язык, отличный от системного.

Чтобы вручную добавить поддерживаемые языки приложения в системные настройки пользователя, выполните следующие действия:

  1. Создайте файл res/xml/locale_config.xml и укажите языки приложения, в том числе основной резервный язык, который задан в файле res/values/strings.xml.

    Подробнее о формате названий региональных настроек… Список наиболее часто используемых региональных настроек можно найти в примере файла locale_config.xml.

    Например, если приложение поддерживает следующие языки, файл locale_config.xml должен выглядеть так:

    • Английский (США) как резервный язык
    • Английский (Великобритания)
    • Французский
    • Японский
    • Китайский (упрощенный, Макао)
    • Китайский (традиционный, Макао)
    <?xml version="1.0" encoding="utf-8"?>
    <locale-config xmlns:android="http://schemas.android.com/apk/res/android">
       <locale android:name="en-US"/>
       <locale android:name="en-GB"/>
       <locale android:name="fr"/>
       <locale android:name="ja"/>
       <locale android:name="zh-Hans-MO"/>
       <locale android:name="zh-Hant-MO"/>
    </locale-config>
    
  2. Добавьте в манифест строку, указывающую на этот новый файл:

    <manifest>
        ...
        <application
            ...
            android:localeConfig="@xml/locale_config">
        </application>
    </manifest>
    

Вы можете динамически обновлять файл localeConfig приложения с помощью LocaleManager.setOverrideLocaleConfig, чтобы настраивать набор языков, которые показываются в списке языков для каждого приложения в настройках Android. Это позволяет настраивать список языков для каждого региона, проводить A/B-эксперименты и предоставлять обновленные языковые стандарты, если ваше приложение использует серверные push-уведомления для локализации, как показано в следующем примере:

//For setOverrideLocaleConfig
val localeManager = applicationContext
    .getSystemService(LocaleManager::class.java)
localeManager.overrideLocaleConfig = LocaleConfig(
LocaleList.forLanguageTags("en-US,ja-JP,zh-Hans-SG")
)

//For getOverrideLocaleConfig
// The app calls the API to get the override LocaleConfig
val overrideLocaleConfig = localeManager.overrideLocaleConfig
// If the returned overrideLocaleConfig isn't equal to NULL, then the app calls the API to get the supported Locales
val supportedLocales = overrideLocaleConfig.supportedLocales()

Кроме того, теперь редакторы методов ввода могут использовать LocaleManager.getApplicationLocales, чтобы определять язык интерфейса текущего приложения и обновлять язык клавиатуры, как показано ниже.

val currentAppLocales: LocaleList = applicationContext.getSystemService(LocaleManager::class.java).getApplicationLocales(appPackageName)

Как указать поддерживаемые языки в Gradle

Если это ещё не сделано, укажите те же языки с помощью свойства resourceConfigurations в файле build.gradle на уровне модуля приложения:

android {
  ...
  defaultConfig {
    resourceConfigurations += ["en", "en-rGB", "fr", "ja", "b+zh+Hans+MO", "b+zh+Hant+MO"]
  }
}

Если свойство resourceConfigurations задано, система сборки включает в APK-файл только языковые ресурсы для указанных языков. Это позволяет избежать добавления переведенных строк из других библиотек, которые могут поддерживать языки, не поддерживаемые вашим приложением. Подробнее о том, как указать поддерживаемые языки…

Как пользователи выбирают язык приложения в системных настройках

Пользователи могут выбрать предпочитаемый язык для каждого приложения в настройках системы. Это можно сделать двумя способами:

  • Как открыть настройки через Систему

    Настройки > Система > Язык и ввод > Языки приложений > (выберите приложение)

  • Через настройки Приложения

    Настройки > Приложения > (выберите приложение) > Язык.

Как обрабатывать окна выбора языка в приложении

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

Реализация с помощью Jetpack Compose

Для приложений, созданных полностью с помощью Jetpack Compose, система автоматически обрабатывает обновления пользовательского интерфейса при изменении локали приложения. Вызов API для установки нового языка запускает изменение конфигурации. Compose реагирует на это, перекомпоновывая пользовательский интерфейс и автоматически разрешая любые вызовы stringResource с использованием нового региона.

Для обратной совместимости с Android 12 (уровень API 32) и более ранними версиями мы настоятельно рекомендуем использовать библиотеку поддержки AndroidX (AppCompatDelegate) при реализации окна выбора языка в приложении. Если вы используете этот подход, действие, в котором размещен интерфейс Compose, должно расширять AppCompatActivity. Однако при необходимости вы можете реализовать API фреймворка напрямую.

В следующем фрагменте кода показано, как считать текущие региональные настройки приложения и задать новые в composable-функции:

import androidx.appcompat.app.AppCompatDelegate
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.core.os.LocaleListCompat

@Composable
fun LanguageSelector() {
    // Retrieve the currently configured app locale.
    // If no app-specific locale is set, LocaleListCompat.get(0) returns null,
    // so we safely fall back to a default (e.g., "en").
    val appLocales = AppCompatDelegate.getApplicationLocales()
    val currentLocaleTag = appLocales.get(0)?.toLanguageTag() ?: "en"

    // Example UI: A button to toggle between English and Spanish
    Button(
        onClick = {
            val newLanguageTag = if (currentLocaleTag == "en") "es" else "en"
            val localeList = LocaleListCompat.forLanguageTags(newLanguageTag)

            // Setting the locale re-creates the Activity by default,
            // which automatically applies the new configuration to Compose.
            AppCompatDelegate.setApplicationLocales(localeList)
        }
    ) {
        Text(
            text = if (currentLocaleTag == "en") "Switch to Spanish" else "Switch to English"
        )
    }
}

Чтобы задать предпочитаемый язык пользователя, попросите его выбрать региональные настройки в окне выбора языка, а затем установите это значение в системе:

val appLocale: LocaleListCompat = LocaleListCompat.forLanguageTags("xx-YY")
// Call this on the main thread as it may require Activity.restart()
AppCompatDelegate.setApplicationLocales(appLocale)

Обратите внимание, что вызов setApplicationLocales заново создает Activity, если только ваше приложение не обрабатывает изменения конфигурации языковых стандартов самостоятельно.

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

Поддержка Android 12 и более ранних версий

Чтобы обеспечить поддержку устройств с Android 12 (уровень API 32) и более ранними версиями, настройте AndroidX для управления хранилищем региональных настроек. Для этого в записи манифеста для сервиса AppLocalesMetadataHolderService приложения задайте значение true для autoStoreLocales и false для android:enabled, как показано в следующем фрагменте кода:

<application
  ...
  <service
    android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
    android:enabled="false"
    android:exported="false">
    <meta-data
      android:name="autoStoreLocales"
      android:value="true" />
  </service>
  ...
</application>

Обратите внимание, что если задать для autoStoreLocales значение true, то в основном потоке будет выполняться чтение с блокировкой, что может привести к нарушению StrictMode diskRead и diskWrite, если вы регистрируете нарушения потока. Подробнее: AppCompatDelegate.setApplicationLocales.

Специальная обработка хранилища

Если вы не добавите запись в манифест или зададите для autoStoreLocales значение false, это будет означать, что вы сами управляете хранилищем. В этом случае необходимо предоставить сохраненные региональные настройки до onCreate в жизненном цикле объекта activity и вызовы шлюза к AppCompatDelegate.setApplicationLocales в Android 12 (уровень API 32) или более ранней версии.

Если в вашем приложении есть собственное хранилище региональных настроек, рекомендуем однократно перенести их в autoStoreLocales, чтобы пользователи могли и дальше работать с приложением на предпочитаемом языке. Это особенно важно, если приложение запускается впервые после обновления устройства до Android 13. В этом случае вы можете предоставить ранее выбранные пользователем региональные настройки, извлекая их из своего хранилища и передавая в AppCompatDelegate.setApplicationLocales.

Как реализовать функцию с помощью API фреймворка Android

Хотя мы настоятельно рекомендуем использовать библиотеку поддержки AndroidX для реализации окон выбора языка в приложении, вы также можете использовать методы setApplicationLocales и getApplicationLocales в платформе Android для устройств под управлением Android 13.

В следующем фрагменте кода показано, как задать и получить предпочитаемый язык пользователя с помощью системного сервиса LocaleManager:

import android.app.LocaleManager
import android.content.Context
import android.os.Build
import android.os.LocaleList
import androidx.annotation.RequiresApi
import java.util.Locale

@RequiresApi(Build.VERSION_CODES.TIRAMISU)
fun setAppLanguage(context: Context, languageTag: String) {
    // 1. Retrieve the system service
    val localeManager = context.getSystemService(LocaleManager::class.java)

    // 2. Create a LocaleList from the language tag (e.g., "es-ES" or "ja")
    val localeList = LocaleList(Locale.forLanguageTag(languageTag))

    // 3. Set the locale. The system automatically updates the locale and
    // restarts the app, including any necessary configuration updates.
    localeManager.applicationLocales = localeList
}

@RequiresApi(Build.VERSION_CODES.TIRAMISU)
fun getAppLanguage(context: Context): String {
    val localeManager = context.getSystemService(LocaleManager::class.java)
    val currentLocales = localeManager.applicationLocales

    // Return the primary app locale, or fall back to the system default
    return if (!currentLocales.isEmpty) {
        currentLocales.get(0).toLanguageTag()
    } else {
        Locale.getDefault().toLanguageTag()
    }
}

Дополнительные рекомендации

Ознакомьтесь с рекомендациями ниже.

Учитывайте язык при вызове намерения в другом приложении

Намерения, связанные с языком, могут позволить вам указать язык, на котором должно быть вызванное приложение. Один из примеров – функция EXTRA_LANGUAGE из Speech Recognizer API.

Учитывайте заголовок Accept-Language для специальной вкладки Chrome

Рекомендуем добавить заголовок Accept-Language через Browser.EXTRA_HEADERS, чтобы при вызове специальной вкладки Chrome веб-страница открывалась на языке приложения.

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

Если вы удалите языковые настройки приложения из системных настроек (удалив android:localeConfig из файла AndroidManifest.xml), пользователи не смогут легко сбросить язык приложения до системных настроек по умолчанию.

Поэтому, если вы удаляете android:localeConfig, рекомендуем сбросить региональные настройки приложения до системных с помощью LocaleListCompat.getEmptyLocaleList или LocaleList.getEmptyLocaleList, как показано в следующем фрагменте кода:

// Use the AndroidX APIs to reset to the system locale for backward and forward compatibility
AppCompatDelegate.setApplicationLocales(
  LocaleListCompat.getEmptyLocaleList()
)

// Or use the Framework APIs for Android 13 and above to reset to the system locale
val context = LocalContext.current
context.getSystemService(LocaleManager::class.java)
  .applicationLocales = LocaleList.getEmptyLocaleList()

Пример файла locale_config.xml

По умолчанию в Android Open Source Project (AOSP) включены переводы на уровне системы для стандартного набора наиболее часто используемых языков. В примере файла locale_config.xml, который приведен в этом разделе, показан рекомендуемый формат для каждого из этих регионов. Используйте этот пример, чтобы создать собственный файл locale_config.xml для языков, которые поддерживает ваше приложение.

<?xml version="1.0" encoding="utf-8"?>
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
   <locale android:name="af"/> <!-- Afrikaans -->
   <locale android:name="am"/> <!-- Amharic -->
   <locale android:name="ar"/> <!-- Arabic -->
   <locale android:name="as"/> <!-- Assamese -->
   <locale android:name="az"/> <!-- Azerbaijani -->
   <locale android:name="be"/> <!-- Belarusian -->
   <locale android:name="bg"/> <!-- Bulgarian -->
   <locale android:name="bn"/> <!-- Bengali -->
   <locale android:name="bs"/> <!-- Bosnian -->
   <locale android:name="ca"/> <!-- Catalan -->
   <locale android:name="cs"/> <!-- Czech -->
   <locale android:name="da"/> <!-- Danish -->
   <locale android:name="de"/> <!-- German -->
   <locale android:name="el"/> <!-- Greek -->
   <locale android:name="en-AU"/> <!-- English (Australia) -->
   <locale android:name="en-CA"/> <!-- English (Canada) -->
   <locale android:name="en-GB"/> <!-- English (United Kingdom) -->
   <locale android:name="en-IN"/> <!-- English (India) -->
   <locale android:name="en-US"/> <!-- English (United States) -->
   <locale android:name="es"/> <!-- Spanish (Spain) -->
   <locale android:name="es-US"/> <!-- Spanish (United States) -->
   <locale android:name="et"/> <!-- Estonian -->
   <locale android:name="eu"/> <!-- Basque -->
   <locale android:name="fa"/> <!-- Farsi -->
   <locale android:name="fi"/> <!-- Finnish -->
   <locale android:name="fil"/> <!-- Filipino -->
   <locale android:name="fr"/> <!-- French (France) -->
   <locale android:name="fr-CA"/> <!-- French (Canada) -->
   <locale android:name="gl"/> <!-- Galician -->
   <locale android:name="gu"/> <!-- Gujarati -->
   <locale android:name="hi"/> <!-- Hindi -->
   <locale android:name="hr"/> <!-- Croatian -->
   <locale android:name="hu"/> <!-- Hungarian -->
   <locale android:name="hy"/> <!-- Armenian -->
   <locale android:name="in"/> <!-- Indonesian -->
   <locale android:name="is"/> <!-- Icelandic -->
   <locale android:name="it"/> <!-- Italian -->
   <locale android:name="iw"/> <!-- Hebrew -->
   <locale android:name="ja"/> <!-- Japanese -->
   <locale android:name="ka"/> <!-- Georgian -->
   <locale android:name="kk"/> <!-- Kazakh -->
   <locale android:name="km"/> <!-- Khmer -->
   <locale android:name="kn"/> <!-- Kannada -->
   <locale android:name="ko"/> <!-- Korean -->
   <locale android:name="ky"/> <!-- Kyrgyz -->
   <locale android:name="lo"/> <!-- Lao -->
   <locale android:name="lt"/> <!-- Lithuanian -->
   <locale android:name="lv"/> <!-- Latvian -->
   <locale android:name="mk"/> <!-- Macedonian -->
   <locale android:name="ml"/> <!-- Malayalam -->
   <locale android:name="mn"/> <!-- Mongolian -->
   <locale android:name="mr"/> <!-- Marathi -->
   <locale android:name="ms"/> <!-- Malay -->
   <locale android:name="my"/> <!-- Burmese -->
   <locale android:name="nb"/> <!-- Norwegian -->
   <locale android:name="ne"/> <!-- Nepali -->
   <locale android:name="nl"/> <!-- Dutch -->
   <locale android:name="or"/> <!-- Odia -->
   <locale android:name="pa"/> <!-- Punjabi -->
   <locale android:name="pl"/> <!-- Polish -->
   <locale android:name="pt-BR"/> <!-- Portuguese (Brazil) -->
   <locale android:name="pt-PT"/> <!-- Portuguese (Portugal) -->
   <locale android:name="ro"/> <!-- Romanian -->
   <locale android:name="ru"/> <!-- Russian -->
   <locale android:name="si"/> <!-- Sinhala -->
   <locale android:name="sk"/> <!-- Slovak -->
   <locale android:name="sl"/> <!-- Slovenian -->
   <locale android:name="sq"/> <!-- Albanian -->
   <locale android:name="sr"/> <!-- Serbian (Cyrillic) -->
   <locale android:name="sr-Latn"/> <!-- Serbian (Latin) -->
   <locale android:name="sv"/> <!-- Swedish -->
   <locale android:name="sw"/> <!-- Swahili -->
   <locale android:name="ta"/> <!-- Tamil -->
   <locale android:name="te"/> <!-- Telugu -->
   <locale android:name="th"/> <!-- Thai -->
   <locale android:name="tr"/> <!-- Turkish -->
   <locale android:name="uk"/> <!-- Ukrainian -->
   <locale android:name="ur"/> <!-- Urdu -->
   <locale android:name="uz"/> <!-- Uzbek -->
   <locale android:name="vi"/> <!-- Vietnamese -->
   <locale android:name="zh-Hans"/> <!-- Chinese (Simplified) -->
   <locale android:name="zh-Hant"/> <!-- Chinese (Traditional) -->
   <locale android:name="zu"/> <!-- Zulu -->
</locale-config>

Дополнительные ресурсы

Дополнительную информацию вы найдете в примерах кода, статьях блога и видео.