在许多情况下,多语言用户将其系统语言设置为一种语言(例如英语),但他们希望为特定应用选择其他语言,例如荷兰语、中文或印地语。为了帮助应用为这些用户提供更好的体验,Android 13 为支持多种语言的应用引入了以下功能
系统设置:用户可以在其中为每个应用选择首选语言的集中位置。
您可以配置您的应用以自动生成支持每个应用语言首选项所需的文件,并在系统设置中显示。要了解更多信息,请参阅有关启用自动每个应用语言支持的说明。
其他 API:这些公共 API(例如
setApplicationLocales()
和getApplicationLocales()
方法在LocaleManager
中)允许应用在运行时设置与系统语言不同的语言。这些 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 支持库实现
使用 setApplicationLocales()
和 getApplicationLocales()
方法(在 Appcompat 1.6.0 或更高版本中)。请注意,对于 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)及更低版本的设备,请告诉 AndroidX 处理语言环境存储,方法是将 autoStoreLocales
值设置为 true
,并将 android:enabled
值设置为 false
,如以下代码片段所示:
<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
之前提供存储的语言环境,并在 Android 12(API 级别 32)或更低版本中对 AppCompatDelegate.setApplicationLocales()
的调用进行网关控制。
如果您的应用使用自定义区域设置存储位置,我们建议您在自定义区域设置存储解决方案和autoStoreLocales
之间进行一次性交接,以便用户能够继续使用他们喜欢的语言享受您的应用。这在设备升级到 Android 13 后首次运行您的应用时尤其适用。在这种情况下,您可以通过从自定义存储中检索区域设置并将区域设置传递到AppCompatDelegate.setApplicationLocales()
来提供预先存在的、用户请求的区域设置。
使用 Android 框架 API 实现
虽然我们强烈建议您使用 AndroidX 支持库来实现应用内语言选择器,但您也可以使用 Android 13 设备上的 Android 框架中的setApplicationLocales()
和getApplicationLocales()
方法。
例如,要设置用户的首选语言,您会要求用户在语言选择器中选择一个语言环境,然后在系统中设置该值。
// 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 标头
考虑通过Browser.EXTRA_HEADERS
添加Accept-Language 标头,以便在调用 Chrome 自定义标签时以应用的语言打开网页。
如果从系统设置中删除每个应用的语言首选项,请将应用区域设置重置为系统区域设置
如果从系统设置中删除应用的语言首选项(通过从应用的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());
其他资源
有关更多信息,请参阅我们的代码示例、博文和视频。
- 每个应用的语言首选项第 1 部分 博文
- 每个应用的语言首选项第 2 部分 博文
- 示例应用
- 构建多语言世界 视频
示例 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>