
在许多情况下,多语言用户会将系统语言设置为一种语言(例如英语),但他们希望为特定应用选择其他语言,例如荷兰语、中文或印地语。为了帮助应用为这些用户提供更好的体验,Android 13 为支持多种语言的应用引入了以下功能:
系统设置:用户可以在此集中位置为每个应用选择首选语言。
您可以配置应用以自动生成支持应用语言偏好设置所需的文件,并使其显示在系统设置中。如需了解详情,请参阅启用自动应用语言支持的说明。
附加 API:这些公共 API(例如
LocaleManager
中的setApplicationLocales()
和getApplicationLocales()
方法)允许应用在运行时设置不同于系统语言的语言。这些 API 会自动与系统设置同步;因此,使用这些 API 创建自定义应用内语言选择器的应用将确保其用户无论在哪里选择语言偏好设置,都能获得一致的用户体验。公共 API 还有助于您减少样板代码量,它们支持拆分 APK,并支持应用自动备份以存储应用级别的用户语言设置。
为了与之前的 Android 版本向后兼容,AndroidX 中也提供了等效的 API。但是,对于 Android 12(API 级别 32)及更早版本,向后兼容的 API 适用于 AppCompatActivity 上下文,而非应用上下文。使用 Appcompat 1.6.0 或更高版本访问向后兼容的 API。
实现此功能概览
下表显示了基于不同用例的建议实现。
用例 | 建议实现 |
---|---|
您的应用没有应用内语言选择器 |
|
您的应用已有应用内语言选择器 |
|
用户系统设置
从 Android 13 开始,Android 在系统设置中包含一个集中位置,用于设置应用语言偏好设置。为确保您的应用语言可在运行 Android 13 或更高版本的设备的系统设置中进行配置,请启用自动应用语言支持(建议)或手动配置支持。
启用自动应用语言支持
从 Android Studio Giraffe 和 AGP 8.1 开始,您可以配置您的应用以自动支持应用语言偏好设置。根据您的项目资源,AGP 会生成 LocaleConfig
文件,并在最终清单文件中添加对其的引用,因此您不再需要手动操作。AGP 使用应用模块和任何库模块依赖项的 res
文件夹中的资源来确定要包含在 LocaleConfig
文件中的语言区域。这意味着如果您为应用添加新语言的资源,您不必担心更新 LocaleConfig
文件。
请注意,自动应用语言功能支持运行 Android 13 (API 级别 33) 或更高版本的应用。要使用此功能,您必须将 compileSdkVersion
设置为 33 或更高。要为 Android 的早期版本配置应用语言偏好设置,您仍然需要使用 API 和应用内语言选择器。
要启用自动应用语言支持,请按照以下步骤操作:
- 要开启此功能,请在模块级
build.gradle.kts
文件(如果您使用 Groovy,则是build.gradle
文件)的androidResources {}
块中使用generateLocaleConfig
设置。此功能默认关闭。Kotlin
android { androidResources { generateLocaleConfig = true } }
Groovy
android { androidResources { generateLocaleConfig true } }
- 指定默认语言区域
- 在应用模块的
res
文件夹中,创建一个名为resources.properties
的新文件。 在
resources.properties
文件中,使用unqualifiedResLocale
标签设置默认语言区域。有关语言区域名称的格式,请参阅如何形成语言区域名称。
- 在应用模块的
AGP 会将此默认语言区域以及您使用 res
文件夹中的 values-*
目录指定的任何替代语言区域添加到自动生成的 LocaleConfig
文件中。
如何形成语言区域名称
要形成语言区域名称,请将语言代码与可选的脚本和区域代码组合起来,并用破折号分隔开:
- 语言:使用两或三字母的 ISO 639-1 代码。
- 脚本(可选):使用 ISO 15924 代码。
- 区域(可选):使用两字母的 ISO 3166-1-alpha-2 代码或三位数字的 UN_M.49 代码。
例如,如果您的默认语言区域是美式英语:
unqualifiedResLocale=en-US
使用 android:localeConfig
将支持的语言添加到系统设置
您可以手动设置您的应用,以确保其语言可在运行 Android 13 或更高版本的设备的系统设置中进行配置。为此,请创建一个 locales_config
XML 文件,并使用 android:localeConfig
属性将其添加到您的应用清单中。省略 android:localeConfig
清单条目表示用户不应能够在系统设置中独立于其系统语言设置您的应用语言。
要手动将您的应用支持的语言添加到用户的系统设置:
创建一个名为
res/xml/locales_config.xml
的文件,并指定您的应用语言,包括您的应用的最终回退语言区域,即res/values/strings.xml
中指定的语言区域。有关格式要求,请参阅如何形成语言区域名称。另请参阅示例
locale_config.xml
文件,其中列出了最常用的语言区域。例如,对于支持以下语言的应用,请像这样格式化
locales_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>
在清单中,添加一行指向此新文件:
<manifest> ... <application ... android:localeConfig="@xml/locales_config"> </application> </manifest>
您可以使用 LocaleManager.setOverrideLocaleConfig
动态更新应用的 localeConfig
,以自定义 Android 设置中按应用语言列表显示的语言集。这使您可以按区域自定义语言列表、运行 A/B 实验,并在您的应用使用服务器端本地化推送时提供更新的语言环境,如以下示例所示:
Kotlin
//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()
Java
//For setOverrideLocaleConfig mContext.getSystemService(LocaleManager.class).setOverrideLocaleConfig(new LocaleConfig(LocaleList.forLanguageTags("en-US,ja-JP,zh-Hans-SG"))); //For getOverrideLocaleConfig // The app calls the API to get the override LocaleConfig LocaleConfig overrideLocaleConfig = mContext.getSystemService(LocaleManager.class).getOverrideLocaleConfig(); // If the returned overrideLocaleConfig isn't equal to NULL, then the app calls the API to get the supported Locales LocaleList supportedLocales = overrideLocaleConfig.getSupportedLocales();
此外,IME 现在可以使用 LocaleManager.getApplicationLocales
来了解当前应用的 UI 语言,以更新键盘语言,如所示:
Kotlin
val currentAppLocales: LocaleList = applicationContext.getSystemService(LocaleManager::class.java).getApplicationLocales(appPackageName)
Java
LocaleList currentAppLocales = mContext.getSystemService(LocaleManager.class).getApplicationLocales(appPackageName);
在 Gradle 中指定支持的语言
如果您的应用模块级 build.gradle
文件中尚未包含,请使用 resourceConfigurations
属性指定相同的语言:
android {
...
defaultConfig {
resourceConfigurations += ["en", "en-rGB", "fr", "ja", "b+zh+Hans+MO", "b+zh+Hant+MO"]
}
}
当 resourceConfigurations
属性存在时,构建系统只会在 APK 中包含这些指定语言的语言资源,从而避免包含来自可能支持您的应用不支持的其他语言的库的翻译字符串。如需了解更多信息,请参阅指定您的应用支持的语言。
用户如何在系统设置中选择应用语言
用户可以通过系统设置选择每个应用的首选语言。他们可以通过两种不同的方式访问这些设置:
通过系统设置访问
设置 > 系统 > 语言和输入法 > 应用语言 > (选择一个应用)
通过应用设置访问
设置 > 应用 > (选择一个应用) > 语言
处理应用内语言选择器
对于已包含应用内语言选择器或希望使用该选择器的应用,请使用公共 API 而非自定义应用逻辑来处理设置和获取用户为您的应用首选的语言。如果您将公共 API 用于您的应用内语言选择器,设备的系统设置将自动更新,以匹配用户通过您的应用内体验选择的任何语言。
为了与之前的 Android 版本向后兼容,我们强烈建议在实现应用内语言选择器时使用 AndroidX 支持库。但是,如果需要,您也可以直接实现框架 API。
使用 AndroidX 支持库实现
使用 Appcompat 1.6.0 或更高版本中的 setApplicationLocales()
和 getApplicationLocales()
方法。请注意,对于 Android 12 (API 级别 32) 及更早版本,向后兼容的 API 适用于 AppCompatActivity 上下文,而非应用上下文。
例如,要设置用户的首选语言,您可以要求用户在语言选择器中选择一个语言区域,然后将该值设置到系统中:
Kotlin
val appLocale: LocaleListCompat = LocaleListCompat.forLanguageTags("xx-YY") // Call this on the main thread as it may require Activity.restart() AppCompatDelegate.setApplicationLocales(appLocale)
Java
LocaleListCompat appLocale = 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)及更低版本的设备,请通过在应用的 AppLocalesMetadataHolderService
服务的清单条目中将 autoStoreLocales
值设置为 true
并将 android:enabled
设置为 false
,告知 AndroidX 处理语言区域存储,如以下代码段所示:
<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
表示您正在自行处理存储。在这种情况下,您必须在 Activity 生命周期的 onCreate
之前提供存储的语言区域,并在 Android 12 (API 级别 32) 或更低版本中对 AppCompatDelegate.setApplicationLocales()
的调用进行限制。
如果您的应用具有自定义语言区域存储位置,我们建议在您的自定义语言区域存储解决方案和 autoStoreLocales
之间进行一次性切换,以便用户继续以他们偏好的语言使用您的应用。这尤其适用于您的应用在设备升级到 Android 13 后首次运行的情况。在这种情况下,您可以通过从自定义存储中检索语言区域并将其传递到 AppCompatDelegate.setApplicationLocales()
来提供预先存在的、用户请求的语言区域。
使用 Android 框架 API 实现
虽然我们强烈建议您使用 AndroidX 支持库来实现应用内语言选择器,但您也可以将 Android 框架中的 setApplicationLocales()
和 getApplicationLocales()
方法用于运行 Android 13 的设备。
例如,要设置用户的首选语言,您可以要求用户在语言选择器中选择一个语言区域,然后将该值设置到系统中:
// 1. Inside an activity, in-app language picker gets an input locale "xx-YY"
// 2. App calls the API to set its locale
mContext.getSystemService(LocaleManager.class
).setApplicationLocales(new LocaleList(Locale.forLanguageTag("xx-YY")));
// 3. The system updates the locale and restarts the app, including any configuration updates
// 4. The app is now displayed in "xx-YY" language
要获取用户的当前首选语言以在语言选择器中显示,您的应用可以从系统中获取值:
// 1. App calls the API to get the preferred locale
LocaleList currentAppLocales =
mContext.getSystemService(LocaleManager.class).getApplicationLocales();
// 2. App uses the returned LocaleList to display languages to the user
其他最佳实践
请注意以下最佳实践。
在其他应用中调用 Intent 时考虑语言
以语言为中心的 Intent 可能允许您指定您希望调用的应用所使用的语言。一个例子是语音识别器 API 中的 EXTRA_LANGUAGE
功能。
考虑 Chrome 自定义标签页的 Accept-Language 标头
在调用 Chrome 自定义标签页时,考虑通过 Browser.EXTRA_HEADERS
添加 Accept-Language 标头,以在您的应用语言中打开网页。
如果您在系统设置中移除应用语言偏好设置,请将应用语言区域重置为系统语言区域
如果您从系统设置中移除应用的语言偏好设置(通过从应用的 AndroidManifest.xml
中移除 android:localeConfig
),用户将无法轻易地将应用语言重置回系统默认设置。
因此,如果您移除 android:localeConfig
,请考虑使用 LocaleListCompat.getEmptyLocaleList()
或 LocaleList.getEmptyLocaleList()
将应用语言区域重置为系统语言区域,如以下代码段所示:
Kotlin
// 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()
Java
// 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 mContext.getSystemService(LocaleManager.class) .setApplicationLocales(LocaleList.getEmptyLocaleList());
其他资源
有关更多信息,请参阅我们的代码示例、博客文章和视频。
示例 locale_config.xml 文件
默认情况下,Android 在 Android 开源项目 (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>