按应用设定的语言偏好设置

在许多情况下,多语言用户会将其系统语言设置为某一种语言(例如英语),但又想为特定应用选择其他语言(例如荷兰语、中文或印地语)。为了帮助应用为这些用户提供更好的体验,Android 13 针对支持多种语言的应用引入了以下功能:

  • 系统设置,可让用户在一个位置为各个应用选择首选语言。

    您的应用必须在应用的清单中声明 android:localeConfig 属性,以告知系统它支持多种语言。如需了解详情,请参阅有关创建资源文件并在应用的清单文件中声明资源的说明。

  • 使应用可在运行时设置在界面中使用的其他语言的 API

    使用自定义应用内语言选择器的应用应当使用这些新 API,以确保无论用户通过何种方式选择其语言偏好设置,都能获得一致的用户体验。新的 API 还有助于减少样板代码量、支持拆分 APK,并且支持应用自动备份,以存储应用级的用户语言设置。

    为了向后兼容以前的 Android 版本,AndroidX 中也提供了相应 API。我们建议使用 Appcompat 1.6.0-alpha04 或更高版本。

不支持多种语言的应用不受这些变更的影响。

实现此功能概览

下表根据不同的用例展示了推荐的实现方式。

用例 推荐的实现方式
您的应用没有应用内语言选择器
  1. 使用应用清单中的 android:localeConfig 属性将应用的语言添加到手机设置中。
  2. (可选)如果您想添加应用内语言选择器:请使用 AndroidX 库并选择接受 API 实现,以通过 autoStoreLocales 支持向后兼容性。
您的应用已有应用内语言选择器
  1. 使用应用清单中的 android:localeConfig 属性将应用的语言添加到手机设置中。
  2. 迁移应用的自定义逻辑以使用新 API,确保用户获得一致的体验。
  3. 处理以下极端情况:
    1. 应用在搭载 Android 13 的设备上首次运行时调用 AppCompatDelegate.setApplicationLocales()
    2. 针对以下情况,调用 AppCompatDelegate.setApplicationLocales() 以向系统提供用户请求的现有语言区域:

面向用户的系统设置

Android 13 在手机设置中新增了一个集中设置选项,用于设置各应用语言偏好设定。为了确保在搭载 Android 13 的设备上,在系统设置中可以配置应用的语言,请创建一个 locales_config XML 文件,并使用 android:localeConfig 属性将其添加到应用的清单中。省略 android:localeConfig 清单条目表明用户不应该能够在他们的手机设置中独立于系统语言来设置您的应用语言。

使用 android:localeConfig 将受支持的语言添加到手机设置中

若要将应用支持的语言添加到用户的手机设置中,请执行以下操作:

  1. 创建一个名为 res/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="ja"/>
       <locale android:name="fr"/>
       <locale android:name="en"/>
    </locale-config>
    
  2. 在清单中,添加一行指向这个新文件的代码:

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

用户在系统设置中如何选择应用语言

用户可以通过新的系统设置为每个应用选择首选语言。他们可以通过以下两种方式访问这些设置:

  • 通过系统设置访问

    设置 > 系统 > 语言和输入法 > 应用语言 >(选择一款应用)

  • 通过应用设置访问

    设置 > 应用 >(选择一款应用)> 语言

已知问题

在测试应用时,有一些已知问题需要注意。

  • AGP 7.3.0-alpha07 存在一个已知问题,可能会导致通过 android:localeConfig 关联资源失败。如需解决此问题,请使用较低版本的 AGP。此问题应该会在即将发布的版本中得到解决。

处理应用内语言选择器

对于具有或想要使用应用内语言选择器的应用,请使用这些新 API(而非自定义应用逻辑)来处理相关设置和获取用户对应用的首选语言设置。

为了向后兼容以前的 Android 版本,强烈建议使用 AndroidX 支持库来实现应用内语言选择器。不过,如有需要,您也可以直接实现框架 API

使用 AndroidX 支持库来实现

使用 Appcompat 1.6.0-alpha04 或更高版本中的 setApplicationLocales() 方法。

例如,如需设置用户的首选语言,您需要让用户在语言选择器中选择语言区域,然后在系统中设置该值:

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);

支持 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 diskReaddiskWrite 违规行为(如果您记录线程违规行为)。如需了解详情,请参阅 AppCompatDelegate.setApplicationLocales()

自定义存储空间处理方式

省略清单条目或将 autoStoreLocales 设置为 false 表示您在处理自己的存储空间。在这种情况下,在 Android 12(API 级别 32)或更低版本中,您必须在 activity 生命周期的 onCreate 之前提供已存储的语言区域,并限制对 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(newLocaleList(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 可能允许您指定所调用的应用要使用的语言。一个示例是 Speech Recognizer API 的 EXTRA_LANGUAGE 功能。

考虑使用 Chrome 自定义标签页的 Accept-Language 标头

考虑通过 Browser.EXTRA_HEADERS 添加 Accept-Language 标头,以便在调用 Chrome 自定义标签页时使用您的应用语言打开网页。