本地化您的应用

许多地区的许多设备上都搭载了 Android。为了覆盖大多数用户,请确保您的应用以适合其所在语言区域的方式处理文本、音频文件、数字、货币和图形。

本页将向您介绍将 Android 应用本地化的最佳实践。

您需要具备 Kotlin 或 Java 编程语言的实战知识,熟悉 Android 资源加载在 XML 中声明界面元素activity 生命周期等开发注意事项,以及国际化和本地化的基本原则。

使用 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/
    包含针对日语环境优化的图形。

如果应用在配置为使用日语的设备上运行,则 Android 会从 res/drawable-ja/ 加载图形,即使设备恰好需要使用触控笔输入,并且配有横屏 QVGA 低密度屏幕也是如此。

例外:在选择过程中,唯一优先于语言区域的限定符是移动设备国家/地区代码 (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 指南

在设计和开发界面时,请密切关注您与用户交流的方式。一般而言,应使用友好而简洁的风格,并且整个界面应采用一致的风格。

请务必阅读并遵循 Material Design 关于写作风格和字词选择的建议。这样做能够让您的应用显得更有品质,并且有助于用户快速理解您的界面。

另外,还应尽可能地使用 Android 标准术语,例如对于界面元素,使用操作栏、选项菜单、系统栏、通知等。确保 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 管理中心。您可使用该服务获得即时报价并向翻译公司下订单。您可以为应用界面字符串、Play 商店商品详情文本、IAP 名称和广告系列文本订购一种或多种语言的翻译。

测试已本地化的应用

在设备上或使用 Android 模拟器测试已本地化的应用。尤其需要测试并确保您的应用中包含所有必要的默认资源。

在设备上测试

请注意,您测试所用的设备可能与其他地方的消费者所用设备有很大差异。您设备上提供的语言区域可能与其他设备上提供的语言区域不同。此外,设备屏幕的分辨率和密度也可能不同,这可能会影响界面中的字符串和可绘制对象的显示。

您可以通过“设置”应用更改设备的语言区域或语言。

在模拟器上测试

如需详细了解如何使用模拟器,请参阅在 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 language tag];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 的文件,则将模拟器或设备设置为竖屏模式,看看应用是否会运行。