Skip to main content

国际化

国际化采用 Angular 官方解决方案 i18n,翻译文件的格式采用 XLIFF(1.2)

XLIFF 是由软件开发商、本地化服务提供商、本地化工具提供商等团体共同倡议和设计,由 OASIS标准组织 发布的用于本地化数据交换的格式标准。它基于XML技术制定软件资源文件格式的转换规格,其目的在于提高软件的本地化作业效率。

国际化工作会经历以下4个阶段来完成

  • 定义翻译内容(开发人员需要仔细阅读)
  • 翻译内容提取
  • 如何翻译
  • 部署

定义翻译内容(开发人员需要仔细阅读)#

需要翻译的内容会分布在两种文件里面,模板(*.html)文件ts文件内容,这两种需要以不同的方式定义。

定义模板中的翻译内容#

在 Angular 定义哪些需要去做国际化的部分是通过 i18n 标记来完成

<!-- 定义可翻译的 html -->
<h1 i18n>iMOS 管道管理系统</h1>

除了给元素内容翻译,也可以 html 元素属性进行翻译,属性翻译以 i18n-* 的命名方式声明。

<!-- 为 input 的 placeholder 翻译 -->
<input type="text" placeholder="请输入用户名" i18n-placeholder>

也可以给 Angular 组件的属性进行翻译

<!-- 为 NtFormFieldComponent 组件的 label 属性翻译 -->
<nt-form-field label="用户名" i18n-label>
...
</nt-form-field>

翻译一段纯文本

<ng-container i18n>我不会输出 html 元素</ng-container>

除此之外,还有复数与选择的表达式的内容,这部分请到官网阅读。

定义 *.ts 文件中的翻译内容#

ts 文件中的内容我们需要借助 @ngx-translate/i18n-polyfill 库来完成。

截止到目前(2018-12-13),angular i18n 团队并没有对这部分提供解决方案,但是 angular i18n 团队正在跟另一个翻译工具库 @ngx-translate 的开发团队进行合作补充这部分的内容,@ngx-translate/i18n-polyfill 就是最终方案发布之前的临时库,在官方正式发布之前我们使用这个临时库来解决问题。 

i18n-polyfill 提供一个可注入的服务 I18n,我们可以像调用方法一样使用它,这就像模板上声明类似。

import { I18n } from '@ngx-translate/i18n-polyfill';
import { NotifyService } from '@app/components/notify';
export class AppComponent {
constructor(
private i18n: I18n,
private notifyService: NotifyService) {
// 纯文本翻译
this.notifyService.success(this.i18n('这是一段需要翻译的成功提醒文本'));
// 支持 ICU 表达式
this.notifyService.success(
this.i18n('欢迎使用 iMOS 系统,{{user}}', { user: 'admin' })
);
}
}

提高可维护性#

Angular 的 i18n 提取工具会为模板中每个带有 i18n 属性的元素生成一个翻译单元(translation unit)条目,并保存到一个文件中。默认情况下,它为每个翻译单元指定一个唯一的 id,就像这样:

<trans-unit id="ba0cc104d3d69bf669f97b8d96a4c5d8d9559aa3" datatype="html">

当你修改这段可翻译的文字时,提取工具会为那个翻译单元生成一个新的 id,你就要使用这个新的 id 来修改这个翻译文件。

另一种方案是,你可以使用 @@ 前缀在 i18n 属性中指定一个自定义的 id。 下面这个例子就定义了一个自定义 id global.appName:

id 的命名以 a.b.c 的方式命名

  1. 全局内容以 global.xxx 开始,比如:global.appName
  2. 页面中的变量跟菜单的命名空间保持一致 topMenu.subMenu.xxx,

以系统功能/用户管理模块为例:

  • 用户列表页标题 system.members.pageTitle,
  • 用户列表页搜索框的提示:system.members.searchPlaceholder
  • 添加页面的标题:system.members.add.pageTitle
  • 添加页面的用户字段名:system.members.add.userInputLabel
  • 添加页面的组织字段名:system.members.add.orgInputLabel
  • 添加页面的组织选择框的提示:system.members.add.orgInputPlaceholder
<h1 i18n="@@global.appName">iMOS 管道管理系统</h1>

自定义 id 是永久性的,翻译工具待翻译文本发生变化时不会修改它。 因此,你不必修改翻译结果。这种方式可以让维护变得更简单。

除此之外也可以为文本添加 描述(description) 和 意图(meaning) 等额外的说明信息来帮助翻译人员的理解。

<!-- 增加描述的翻译内容 -->
<h1 i18n="登陆页要显示的 App 名称">iMOS 管道管理系统</h1>
<!-- 增加意图要在描述的前面用 | 将其与描述文字隔开(<意图>|<描述>)。 -->
<h1 i18n="文本表达的含义|翻译内容的额外描述信息">iMOS 管道管理系统</h1>
<!-- 包含所有信息 <element i18n="<意图>|<描述>@@id">...</element> -->
<h1 i18n="文本表达的含义|翻译内容的额外描述信息@@global.appName">
iMOS 管道管理系统
</h1>

为 *.ts 文件,I18n 服务方法除了可以传入字符串还可以传入 I18nDef 对象类型的定义信息

import { I18n } from '@ngx-translate/i18n-polyfill';
import { NotifyService } from '@app/components/notify';
/**
* i18n 方法接收 string | I18nDef 类型的内容。
*/
interface I18nDef {
value: string;
id?: string;
meaning?: string;
description?: string;
}
export class AppComponent {
constructor(
private i18n: I18n,
private notifyService: NotifyService) {
this.notifyService.success(
this.i18n({
value: '欢迎使用 iMOS 系统,{{user}}',
id: 'global.welcome',
meaning: '文本表达的含义',
description: '翻译内容的额外描述信息'
}, { user: 'admin' })
);
}
}

翻译内容提取#

当标记已经完成,这时候需要开始提取并准备翻译,翻译提取是通过 ng i18nngx-extractor 命令完成,下面不再深入讲述它们的使用方式,关于更多信息可以查看文档。

Angular i18n 文档

i18n-polyfill

在工程中,运行 npm 脚本 npm run extract 会在 src/i18n 目录下生成名字为 messages.xlf 的翻译源文件文件。

官方的 ng i18n 只会从模板中提取内容,ngx-extractor 是 i18n-polyfill 提供的翻译内容提取器,它会找到工程的翻译源文件所在目录并且会合并通过 I18n 注入服务定义的翻译内容,npm run extract 脚本会依次执行上述操作。

接下来我们就可以通过编辑器来翻译这些内容。

如何翻译#

提取的文件是一个 XLIFF(1.2) 格式,这些实际上是 XML 格式的数据,因为翻译的内容很多,直接编辑这个文件并不可取,所以我们需要编辑器来完成这个工作。

<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file source-language="zh" datatype="plaintext" original="ng2.template">
<body>
<trans-unit id="page.main.allProjects" datatype="html">
<source>查看所有项目</source>
<context-group purpose="location">
<context context-type="sourcefile">app/pages/project/project-wrapper.page.html</context>
<context context-type="linenumber">15</context>
</context-group>
</trans-unit>
...
</body>
</file>
</xliff>

目前在使用 www.transifex.com 提供的在线编辑软件。

transifex 是个收费软件,目前在试用中,每个帐号可以试用 15 天。

部署#

后续继续补充