本地化工作流程

因为要求程序员自己知道一个魔术是不切实际的 表示特定消息的键,它代表 系统应提供一种符合人体工学的方法来以符号形式引用这些按键 方式(请记住上面的 MSG_Hello_World 的抽象示例。

根据 18n 和 l10n 的最佳实践,源字符串位于 XML 文件(此处命名为 strings.xml),如下所述。一个 strings.xml 文件示例如下所示。 此文件旨在声明我们的程序所用的所有外部化字符串, 使用,并赋予其本地唯一的 name。这些字符串将用作 进行转换,name 将用作符号 xml <!-- comment --> <?xml version="1.0" encoding="utf-8"?> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- comment --> <string name="STRING_NAME" >text_string</string> <string name="STRING_NAME_2" >text_string_2</string> <string name="STRING_NAME_3" >string with an intervening newline</string> </resources>

文件 strings.xml 会经历一系列转换,其中 由译者制作同一文件的不同语言版本。通过 翻译过程的输入-输出行为是:strings.xml 文件 用某种源(人类)语言编写的字符串和多种口味 共出 strings.xml,每个文件都翻译成了一种特定的语言。 在大型企业中,整个翻译过程可能会相当复杂 因此,翻译工作可能涉及到 由生活在世界各地的翻译人员来完成 以及专用翻译工具的得分。而是精确的 对我们作为消费者来说并不重要,只要输入、输出、 流程的行为,我们也知道 可能需要一些时间才能完成翻译所生成的文件将转换为 ,并且在同一 API 中与 Fuchsia 程序一起提供, Fuchsia 软件包 ,了解所有最新动态。 Fuchsia 软件包的一个重要特点是它们本身不是 而是按内容哈希指向文件的清单。因此 多个程序可以共享相同的文件, ("en-US", "en-GB") 可能会共享邮件磁盘空间。以下 图表简要概述了字符串的生命周期。

上图显示了本地化流程。由于 XML 文件带有注解,它们并不直接适合机器翻译,因此我们将其转换为 JSON 文件,然后我们可以重复使用可用的库来加载它们,并构建从键到消息字符串的映射。这些字符串随后可以用作“MessageFormat”中的格式字符串。

strings.xml

我们重复使用 Android 字符串资源 XML 格式来表示可本地化 字符串。由于我们不会向 strings.xml 格式添加任何内容, 将对功能的讨论被委派给字符串资源 页面

虽然上图中的所有 XML 都让本次讨论看起来只是 从 20 世纪 90 年代直接相连的虫洞中形成的,XML 实际上是 非常适合用来描述带注释的文本。strings.xml 格式 并在 Android 中经过时间测试,这样我们就能确定它是否足够, 也非常熟悉

例如,字符串资源可以使用交错的注解进行声明 插入源文本中。

<!-- … -->
<string name="title"
   >Best practices for <annotation font="title_emphasis">text</annotation> look like so</string>
<!-- … -->

上图:交错翻译文本和注解的示例。

可以交错显示应防止翻译的文字, 就像这样

<string name="countdown">
  <xliff:g id="time" example="5 days"
    >{1}</xliff:g> until holiday</string>

上图:一个围栏关闭参数的交错示例,带有 示例值,并使用不属于字符串的标记进行保护 资源数据架构。

如有需要,我们还可以定义自己向数据架构添加的内容 在现有架构中透明交错该数据架构。

上述文件的内容有一些必要的约束:

  • 文件中的每个 name 属性都必须是唯一的。
  • 名称标识符可以包含大写和小写 ASCII 字母、数字和下划线,但不能以数字开头。例如,允许使用 _H_e_L_L_o_wo_1_rld,但不允许使用 0cool
  • 文件中的 name-message 组合不得重复。

目前还没有关于在单个网域内添加多个字符串文件的规定 项目。

消息标识符

消息标识符(每条消息的“神奇”数字常量)是 根据 strings.xml 文件的内容生成。每个字符串 消息会获得一个唯一标识符,该标识符是根据单向哈希计算得出的 name 以及消息本身的内容。此标识符分配 可以确保两种不同的消息 意外地获得了相同的生成的标识符。

这些消息由 GN 构建规则在 Fuchsia 中,但最终是 由名为 strings_to_fidl. 此程序为消息 ID 生成 FIDL 中间表示法, 而常规的 FIDL 工具链用于生成特定语言版本的 这些信息。例如,C++ 风味是包含 以下内容:

namespace fuchsia {
namespace intl {

namespace l10n {
enum class MessageIds : uint64_t {
  STRING_NAME = 42u,
  STRING_NAME_2 = 43u,
  STRING_NAME_3 = 44u,
};

}  // namespace l10n
}  // namespace intl
}  // namespace fuchsia

分配给上例中每个特定枚举值的精确值 并不相关。目前,生成方法也不相关, 因为所有标识符都是在编译时生成的,没有机会 针对版本偏差进行优化。目前,我们可以放心地假设 组合将始终分配相同的邮件 ID。

将结果文件添加到 C++ 程序中非常简单。最小 示例如下,但请参考针对 线缆的精确细节库参数 fuchsia.intl.l10n 为 由作者直接作为标记提供给 strings_to_fidl;或者,如果 使用适当的 GN 模板,作为 GN 模板的参数。

#include <iostream>

// This header file has been generated from the strings library fuchsia.intl.l10n.
#include "fuchsia/intl/l10n/cpp/fidl.h"

// Each library name segment between dots gets its own nested namespace in
// the generated C++ code.
using fuchsia::intl::l10n::MessageIds;

int main() {
  std::cout << "Constant: " << static_cast<uint64_t>(MessageIds::STRING_NAME) << std::endl;
  return 0;
}

*.json

FIDL 和 C++ 代码生成使消息 ID 可供程序使用 作者。在包装方面,我们还必须为以下资源提供本地化资源: 支持的每种语言目前,此信息的编码为 JSON。这样做是为了方便起见,但还有许多改进空间 以提高性能和安全性。

生成此信息会委托给名为 strings_to_json, 它将原始 strings.xml 与语言特定的 文件(例如,法语翻译位于 strings_fr.xml)。 同样,对于由 GN 驱动的 build,调用 strings_to_json 封装在构建规则中

下面给出了生成的 JSON 文件的示例内容。

{
  "locale_id": "fr",
  "source_locale_id": "en-US",
  "num_messages": 3,
  "messages": {
    "42": "le string",
    "43": "le string 2",
    "44": "le string\nwith intervening newline"
  }
}

JSON 格式具有以下当前定义的字段。如果表 因此 JSON 结构的可靠来源是 字符串 模型

字段 类型 说明
locale_id 语言区域 ID(字符串) 消息翻译的语言区域。
source_locale_id 语言区域 ID(字符串) 来源消息文件的语言区域。
num_messages 正整数 原始 strings.xml 中存在的消息数量。这样,我们就可以将消息数量与 JSON 文件中存在的消息数量进行比较,从而快速估算翻译质量。
messages 地图:[u64->string] 从消息 ID 到相应消息的映射。