本地化您的应用

Android 在许多地区的许多设备上运行。为了覆盖最多的用户,请确保您的应用程序以适合应用程序使用地区的区域设置的方式处理文本、音频文件、数字、货币和图形。

本页面介绍了本地化 Android 应用程序的最佳实践。

您需要熟悉 Kotlin 或 Java 编程语言,并熟悉 Android 资源加载在 XML 中声明用户界面元素、开发考虑因素(如 活动生命周期)以及国际化和本地化的通用原则。

使用 Android 资源框架尽可能地将应用程序的本地化方面与核心应用程序功能分离是一种很好的做法。

  • 如本页面和 应用程序资源概述中所述,将应用程序用户界面的大部分或全部 *内容* 放入资源文件。
  • 另一方面,用户界面的 *行为* 由基于 Kotlin 或基于 Java 的代码驱动。例如,如果用户输入的数据需要根据区域设置进行不同的格式化或排序,那么您使用 Kotlin 或 Java 编程语言以编程方式处理数据。本页面不介绍如何本地化基于 Kotlin 或基于 Java 的代码。

有关在应用程序中本地化字符串的简要指南,请参阅 支持不同的语言和文化

概述:Android 中的资源切换

资源是文本字符串、布局、声音、图形以及 Android 应用程序需要的任何其他静态数据。应用程序可以包含多组资源,每组资源都针对不同的设备配置进行了定制。当用户运行应用程序时,Android 会自动选择并加载最适合设备的资源。

本页面重点介绍本地化和区域设置。有关资源切换和您可以指定的各种配置类型的完整说明(如屏幕方向或触摸屏类型),请参阅 提供备用资源

在编写应用程序时,您会为应用程序创建默认资源和备用资源。当用户运行应用程序时,Android 系统会根据设备的区域设置选择要加载的资源。要创建资源,您需要将文件放在项目 res/ 目录的特定命名子目录中。

默认资源为何重要

当应用程序在您未提供特定于区域设置的文本的任何区域设置中运行时,Android 会从 res/values/strings.xml 加载默认字符串。如果此默认文件不存在,或者它缺少应用程序需要的字符串,那么您的应用程序将无法运行并显示错误。以下示例说明了默认文本文件不完整时可能发生的情况。

示例

应用程序的基于 Kotlin 或基于 Java 的代码仅引用两个字符串,text_atext_b。应用程序包含一个本地化资源文件 (res/values-en/strings.xml),它以英语定义 text_atext_b。应用程序还包含一个默认资源文件 (res/values/strings.xml),其中包含对 text_a 的定义,但不包含对 text_b 的定义。

  • 当此应用程序在区域设置设置为英语的设备上启动时,应用程序可能可以正常运行,因为 res/values-en/strings.xml 包含两个所需的文本字符串。
  • 但是,当此应用程序在设置为非英语语言的设备上启动时,用户会看到错误消息和“强制关闭”按钮。该应用程序无法加载。

为了防止这种情况,请确保存在 res/values/strings.xml 文件,并且它定义了所有需要的字符串。这种情况适用于所有类型的资源,而不仅仅是字符串:您需要创建一个默认资源文件集,其中包含应用程序调用的所有资源,例如布局、可绘制对象或动画。有关测试的信息,请参阅 测试默认资源 部分。

使用资源进行本地化

本节讨论如何创建默认资源以及备用资源。它还解释了资源如何分配优先级以及如何在代码中引用资源。

创建默认资源

将应用程序的默认文本放在 res/values/strings.xml 中。对于这些字符串,使用默认语言 - 您预计大多数应用程序用户使用的语言。

默认资源集还包括所有默认的可绘制对象和布局,并且可以包括其他类型的资源,例如动画。这些资源位于以下目录中

  • res/drawable/:必需目录,至少包含一个图形文件,用于应用程序在 Google Play 上的图标
  • res/layout/:必需目录,包含定义默认布局的 XML 文件
  • res/anim/:如果您有任何 res/anim-<qualifiers> 文件夹,则需要此文件夹
  • res/xml/:如果您有任何 res/xml-<qualifiers> 文件夹,则需要此文件夹
  • res/raw/:如果您有任何 res/raw-<qualifiers> 文件夹,则需要此文件夹

提示: 在您的代码中,检查对 Android 资源的每个引用。确保为每个资源定义了默认资源。还要确保默认字符串文件完整:本地化字符串文件可以包含字符串的子集,但默认字符串文件必须包含所有字符串。

创建备用资源

本地化应用程序的一个重要部分是为不同的语言提供备用文本。在某些情况下,您还提供备用图形、声音、布局和其他特定于区域设置的资源。

应用程序可以指定许多 res/<qualifiers>/ 目录,每个目录都有不同的限定符。要为不同的区域设置创建备用资源,您可以使用指定语言或语言区域组合的限定符。资源目录的名称必须符合 提供备用资源 中描述的命名方案,否则您的应用程序无法编译。

示例

假设您的应用程序的默认语言是英语,并且您希望将应用程序中的所有文本本地化为法语,并将除应用程序标题之外的所有文本本地化为日语。在这种情况下,您创建三个 strings.xml 文件,每个文件都存储在特定于区域设置的资源目录中

  1. res/values/strings.xml
    包含应用程序使用的所有字符串的英文文本,包括名为 title 的字符串的文本。
  2. res/values-fr/strings.xml
    包含所有字符串的法文文本,包括 title
  3. res/values-ja/strings.xml
    包含所有字符串的日语文本,除了 title

如果您的基于 Kotlin 或 Java 的代码引用 R.string.title,以下是运行时发生的情况

  • 如果设备设置为除法语以外的任何语言,Android 会从 res/values/strings.xml 文件加载 title
  • 如果设备设置为法语,Android 会从 res/values-fr/strings.xml 文件加载 title

如果设备设置为日语,Android 会在 res/values-ja/strings.xml 文件中查找 title。但由于该文件中未包含此类字符串,因此 Android 会回退到默认值,并从 res/values/strings.xml 文件加载英文版的 title

哪些资源优先?

如果多个资源文件与设备的配置匹配,Android 会遵循一组规则来决定使用哪个文件。在可以在资源目录名称中指定的限定符中,区域设置几乎总是优先。

示例

假设一个应用程序包含一组默认图形和另外两组图形,每组都针对不同的设备设置进行了优化

  • res/drawable/
    包含默认图形。
  • res/drawable-small-land-stylus/
    包含针对使用预期从手写笔输入并具有横向模式的 QVGA 低密度屏幕的设备进行优化的图形。
  • res/drawable-ja/
    包含针对使用日语进行优化的图形。

如果应用程序在设置为使用日语的设备上运行,即使设备恰好是预期从手写笔输入并具有横向模式的 QVGA 低密度屏幕的设备,Android 也会从 res/drawable-ja/ 加载图形。

例外: 在选择过程中,唯一优先于区域设置的限定符是移动国家代码 (MCC) 和移动网络代码 (MNC)。

示例

假设您有以下情况

  • 应用程序代码需要 R.string.text_a
  • .
  • 两个相关的资源文件可用
    • res/values-mcc404/strings.xml,其中包含应用程序默认语言的 text_a,在本例中为英语。
    • res/values-hi/strings.xml,其中包含印地语的 text_a
  • 应用程序正在具有以下配置的设备上运行
    • SIM 卡连接到印度的移动网络 (MCC 404)。
    • 语言设置为印地语 (hi)。

Android 从 res/values-mcc404/strings.xml(英文)加载 text_a,即使设备配置为印地语也是如此。这是因为在资源选择过程中,Android 更倾向于 MCC 匹配而不是语言匹配。

选择过程并不总是像这些示例所示的那样简单明了。有关此过程更细致入微的描述,请参阅 Android 如何找到最佳匹配资源。所有限定符在 应用程序资源概述 中按优先级顺序进行了描述和列出。

在代码中引用资源

在应用程序的基于 Kotlin 或 Java 的代码中,您可以使用语法 R.resource_type.resource_nameandroid.R.resource_type.resource_name 引用资源。有关详细信息,请参阅 访问您的应用程序资源

管理用于本地化的字符串

本节介绍了有关管理与本地化相关的字符串的最佳做法。

将所有字符串移到 strings.xml 中

在构建应用程序时,请勿对任何字符串进行硬编码。相反,将所有字符串声明为默认 strings.xml 文件中的资源,这使得更新和本地化它们变得容易。 strings.xml 文件中的字符串可以轻松提取、翻译并与适当的限定符一起重新集成到应用程序中,而无需对编译后的代码进行任何更改。

如果您使用文本生成图像,请也将这些字符串放在 strings.xml 中,并在翻译后重新生成图像。

遵循 Android 的 UI 字符串指南

在设计和开发 UI 时,请密切注意与用户交流的方式。一般来说,使用简洁的风格,既友好又简洁,并在整个 UI 中使用一致的风格。

确保您阅读并遵循 Material Design 的 写作风格和词语选择 建议。这样做可以让您的应用程序在用户看来更加精致,并帮助用户更快地理解您的 UI。

此外,无论何时可能,请始终使用 Android 标准术语,例如用于应用程序栏、选项菜单、系统栏和通知等 UI 元素。正确且一致地使用 Android 术语可以简化翻译,并为用户提供更好的最终产品。

为已声明的字符串提供足够的上下文

strings.xml 文件中声明字符串时,请确保描述使用该字符串的上下文。此信息对翻译人员来说非常宝贵,可以提高翻译质量。它还有助于您更有效地管理字符串。

以下是一个示例

<!-- The action for submitting a form. This text is on a button that can fit 30 chars -->
<string name="login_submit_button">Sign in</string>

考虑提供以下上下文信息

  • 此字符串是做什么用的?何时何地向用户展示它?
  • 它在布局中的什么位置?例如,翻译在按钮中的灵活性不如在文本框中。

标记不应翻译的消息部分

字符串通常包含不应翻译成其他语言的文本。常见的示例包括代码段、值占位符、特殊符号或名称。在准备字符串进行翻译时,请查找并标记必须保持原样且不应翻译的文本,以便翻译人员不会更改它。

要标记不应翻译的文本,请使用 <xliff:g> 占位符标签。以下是一个示例标签,它指示文本 "%1$s" 不应在翻译过程中更改,以避免破坏消息

<string name="countdown">
  <xliff:g id="time" example="5 days">%1$s</xliff:g> until holiday
</string>

在声明占位符标签时,请添加一个解释占位符用途的 ID 属性。如果您的应用程序稍后替换了占位符值,请务必提供一个示例属性以澄清预期的使用情况。

以下是占位符标签的一些其他示例

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Example placeholder for a special Unicode symbol -->
<string name="star_rating">Check out our 5
    <xliff:g id="star">\u2605</xliff:g>
</string>
<!-- Example placeholder for a URL -->
<string name="app_homeurl">
    Visit us at <xliff:g
    id="application_homepage">http://my/app/home.html</xliff:g>
</string>
<!-- Example placeholder for a name -->
<string name="prod_name">
    Learn more at <xliff:g id="prod_gamegroup">Game Group</xliff:g>
</string>
<!-- Example placeholder for a literal -->
<string name="promo_message">
    Please use the "<xliff:g id="promotion_code">ABCDEFG</xliff:g>" to get a discount.
</string>
...
</resources>

本地化清单

有关本地化和分发 Android 应用程序过程的完整概述,请参阅 翻译和本地化您的应用程序

本地化提示

在本地化应用程序时,请遵循以下提示。

设计您的应用程序以在任何区域设置中工作

不要对用户运行应用程序的设备做任何假设。该设备可能具有您没有预料到的硬件,或者它可能设置为您没有计划或无法测试的区域设置。设计您的应用程序,使其无论在什么设备上运行都能正常运行或优雅地失败。

重要: 确保您的应用程序包含一组完整的默认资源:包含 res/drawable/ 和一个 res/values/ 文件夹,这些文件夹在文件夹名称中没有额外的修饰符,包含应用程序所需的所有图像和文本。

如果应用程序缺少一个默认资源,它将无法在设置为不支持的区域设置的设备上运行。例如,如果 res/values/strings.xml 默认文件缺少应用程序需要的字符串,当应用程序在不支持的区域设置中运行并尝试加载 res/values/strings.xml 时,用户会看到错误消息和“强制关闭”按钮。

有关详细信息,请参阅 测试默认资源 部分。

设计灵活的布局

如果您需要重新排列布局以适合某种语言,您可以为该语言创建备用布局,例如 res/layout-de/main.xml 用于德语布局。但是,这样做会导致应用程序更难维护。最好创建一个更灵活的单一布局。

另一种常见的情况是,语言需要不同的布局。例如,当应用在日语环境下运行时,您可能需要一个包含两个姓名字段的联系表单,但在其他语言环境下运行时,则需要三个姓名字段。您可以通过以下两种方式处理这种情况:

  • 创建一个包含一个可以根据语言编程启用或禁用的字段的布局。
  • 让主布局包含另一个包含可变字段的布局。第二个布局可以针对不同的语言进行不同的配置。

避免创建超出您需要的资源文件和文本字符串。

您可能不需要为应用中的每个资源创建特定于区域设置的替代方案。例如,在 res/layout/main.xml 文件中定义的布局可能适用于任何区域设置,在这种情况下,无需创建任何替代布局文件。

此外,您可能不需要为每个字符串创建替代文本。例如,假设以下情况:

  • 应用的默认语言是美式英语。应用使用的所有字符串都使用美式英语拼写方式定义在 res/values/strings.xml 中。
  • 对于一些重要的短语,您希望提供英式英语拼写。您希望这些替代字符串在应用在英国设备上运行时使用。

为此,请创建一个名为 res/values-en-rGB/strings.xml 的小型文件,其中仅包含在应用在英国运行时不同的字符串。对于所有其他字符串,应用将回退到默认值,并使用 res/values/strings.xml 中定义的内容。

使用 Android Context 对象进行手动区域设置查找

您可以使用 Android 提供的 Context 对象来查找区域设置,如以下示例所示

Kotlin

val primaryLocale: Locale = context.resources.configuration.locales[0]
val locale: String = primaryLocale.displayName

Java

Locale primaryLocale = context.getResources().getConfiguration().getLocales().get(0);
String locale = primaryLocale.getDisplayName();

使用应用翻译服务

应用翻译服务 集成到 Play Console 中。它让您可以立即获得报价,并向翻译公司下订单。您可以为应用 UI 字符串、Play 商店列表文本、IAP 名称和广告活动文本订购翻译成一种或多种语言。

测试本地化应用

在设备上或使用 Android 模拟器测试本地化应用。特别是,测试应用以确保包含所有必要的默认资源。

在设备上测试

请记住,您正在测试的设备可能与其他地方消费者可用的设备有很大不同。您的设备上的可用区域设置可能与其他设备上的可用区域设置不同。此外,设备屏幕的分辨率和密度可能会有所不同,这会影响 UI 中字符串和可绘制对象的显示。

要更改设备上的区域设置或语言,请使用“设置”应用。

在模拟器上测试

有关使用模拟器的详细信息,请参阅 在 Android 模拟器上运行应用

创建和使用自定义区域设置

“自定义”区域设置是 Android 系统映像不支持的语言或区域组合。您可以通过在模拟器中创建自定义区域设置来测试应用在自定义区域设置中的运行情况。有两种方法可以做到这一点:

  • 使用“自定义区域设置”应用,该应用可从应用选项卡访问。创建自定义区域设置后,通过触摸并按住区域设置名称来切换到该区域设置。
  • adb shell 切换到自定义区域设置,如下一节所述。

当您将模拟器设置为 Android 系统映像中不可用的区域设置时,系统本身将以其默认语言显示。但是,您的应用会正确本地化。

从 adb shell 更改模拟器区域设置

要使用 adb shell 更改模拟器中的区域设置,请执行以下操作:

  1. 选择您要测试的区域设置,并确定其 BCP-47 语言标签,例如 fr-CA 表示加拿大法语。
  2. 启动模拟器。
  3. 从主机上的命令行 shell 中运行以下命令:
    adb shell
    或者,如果您已连接设备,请指定您想要模拟器,方法是添加 -e 选项:
    adb -e shell
  4. adb shell 提示符 (#) 中,运行以下命令:
    setprop persist.sys.locale [BCP-47 语言标签];stop;sleep 5;start
    将方括号中的部分替换为步骤 1 中的相应代码。

    例如,要以加拿大法语进行测试:
    setprop persist.sys.locale fr-CA;stop;sleep 5;start

这会导致模拟器重新启动。主屏幕再次出现后,重新启动应用,应用将使用新的区域设置启动。

测试默认资源

要测试应用是否包含所有需要的字符串资源,请执行以下操作:

  1. 将模拟器或设备设置为应用不支持的语言。例如,如果应用在 res/values-fr/ 中包含法语字符串,但在 res/values-es/ 中不包含任何西班牙语字符串,则将模拟器的区域设置设置为西班牙语。您可以使用“自定义区域设置”应用将模拟器设置为不受支持的区域设置。
  2. 运行应用。
  3. 如果应用显示错误消息和“强制关闭”按钮,则它可能正在查找不可用的字符串。确保您的 res/values/strings.xml 文件包含应用使用的每个字符串的定义。

如果测试成功,请针对其他类型的配置重复该测试。例如,如果应用包含名为 res/layout-land/main.xml 的布局文件,但未包含名为 res/layout-port/main.xml 的文件,则将模拟器或设备设置为纵向方向,看看应用是否能运行。