应用本地化

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 控制台中。它允许您从翻译公司获取即时报价并下订单。您可以为应用 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的文件,则将模拟器或设备设置为纵向方向,然后查看应用是否运行。