本地化
本地化是在你的应用和组件中支持多种语言和地区的过程。Lit 通过 @lit/localize
库提供了对本地化的一流支持,相比第三方本地化库,它具有一些优势:
对本地化模板中的表达式和 HTML 标记提供原生支持。不需要为变量替换引入新的语法和插值运行时——只需使用你已经熟悉的模板。
当区域设置切换时,自动重新渲染 Lit 组件。
只增加 1.27 KiB(压缩后)的额外 JavaScript 代码。
可选择为每个区域设置进行编译,减少额外的 JavaScript 代码至 0 KiB。
安装 @lit/localize
客户端库和 @lit/localize-tools
命令行界面。
npm i @lit/localize
npm i -D @lit/localize-tools
- 使用
msg
函数包装字符串或模板(详情)。 - 创建
lit-localize.json
配置文件(详情)。 - 运行
lit-localize extract
生成 XLIFF 文件(详情)。 - 编辑生成的 XLIFF 文件,添加
<target>
翻译标签(详情)。 - 运行
lit-localize build
输出字符串和模板的本地化版本(详情)。
使字符串和模板可本地化
Permalink to "使字符串和模板可本地化"要使字符串或 Lit 模板可本地化,使用 msg
函数包装它。msg
函数返回给定字符串或模板在当前激活区域设置中的版本。
在你拥有任何翻译之前,msg
只是简单地返回原始字符串或模板,因此即使你还没有准备好进行实际本地化,使用它也是安全的。
import {html, LitElement} from 'lit';
import {customElement, property} from 'lit/decorators.js';
import {msg} from '@lit/localize';
@customElement('my-greeter')
class MyGreeter extends LitElement {
@property()
who = 'World';
render() {
return msg(html`Hello <b>${this.who}</b>`);
}
}
import {html, LitElement} from 'lit';
import {msg} from '@lit/localize';
class MyGreeter extends LitElement {
static properties = {
who: {},
};
constructor() {
super();
this.who = 'World';
}
render() {
return msg(html`Hello <b>${this.who}</b>`);
}
}
customElements.define('my-greeter', MyGreeter);
任何你通常用 Lit 渲染的字符串或模板都可以本地化,包括那些带有动态表达式和 HTML 标记的。
普通字符串:
msg('Hello World');
带表达式的普通字符串(关于 str
的详情请参见带表达式的字符串):
msg(str`Hello ${name}`);
HTML 模板:
msg(html`Hello <b>World</b>`);
带表达式的 HTML 模板:
msg(html`Hello <b>${name}</b>`);
本地化消息也可以嵌套在 HTML 模板内:
html`<button>${msg('Hello World')}</button>`;
带表达式的字符串
Permalink to "带表达式的字符串"包含表达式的字符串必须使用 html
或 str
标记才能进行本地化。当你的字符串不包含任何 HTML 标记时,应该优先使用 str
而不是 html
,因为它的性能开销略小。如果你在带有表达式的字符串上忘记了 html
或 str
标记,运行 lit-localize
命令时会引发错误。
错误的:
import {msg} from '@lit/localize';
msg(`Hello ${name}`);
正确的:
import {msg, str} from '@lit/localize';
msg(str`Hello ${name}`);
在这些情况下需要 str
标记,因为未标记的模板字符串字面量会在被 msg
函数接收之前被评估为普通字符串,这意味着动态表达式值无法被捕获并替换到字符串的本地化版本中。
区域设置代码
Permalink to "区域设置代码"区域设置代码是标识人类语言的字符串,有时也包括地区、脚本或其他变体。
Lit Localize 不强制使用任何特定的区域设置代码系统,但强烈建议使用 BCP 47 语言标签标准。BCP 47 语言标签的一些例子是:
- en:英语
- es-419:拉丁美洲使用的西班牙语
- zh-Hans:简体中文
Lit Localize 定义了一些与区域设置代码相关的术语。这些术语在本文档、Lit Localize 配置文件和 Lit Localize API 中使用:
- 源区域设置
用于在源代码中编写字符串和模板的区域设置。
- 目标区域设置
你的字符串和模板可以被翻译成的区域设置。
- 活动区域设置
当前正在显示的全局区域设置。
Lit Localize 支持两种输出模式:
_运行时_模式使用 Lit Localize 的 API 在运行时加载本地化消息。
_转换_模式通过为每个区域设置构建单独的 JavaScript 包来消除 Lit Localize 运行时代码。
不确定使用哪种模式? 从运行时模式开始。稍后切换模式很容易,因为核心 msg
API 是相同的。
运行时模式
Permalink to "运行时模式"在运行时模式下,为你的每个区域设置生成一个 JavaScript 或 TypeScript 模块。每个模块包含该区域设置的本地化模板。当活动区域设置切换时,导入该区域设置的模块,并重新渲染所有本地化组件。
运行时模式使切换区域设置非常快,因为不需要页面重新加载。然而,与转换模式相比,渲染性能会有轻微的成本。
生成输出示例
Permalink to "生成输出示例"// locales/es-419.ts
export const templates = {
hf71d669027554f48: html`Hola <b>Mundo</b>`,
};
有关运行时模式的完整详情,请参阅运行时模式页面。
在转换模式下,为每个区域设置生成一个单独的文件夹。每个文件夹包含该区域设置的应用程序的完整独立构建版本,其中 msg
包装器和所有其他 Lit Localize 运行时代码完全移除。
转换模式不需要额外的 JavaScript 代码(0 KiB),渲染速度极快。然而,切换区域设置需要重新加载页面,以便加载新的 JavaScript 包。
生成输出示例
Permalink to "生成输出示例"// en/my-element.js
render() {
return html`Hello <b>${this.who}</b>`;
}
// es-419/my-element.js
render() {
return html`Hola <b>${this.who}</b>`;
}
有关转换模式的完整详情,请参阅转换模式页面。
Lit Localize 需要一个名为 lit-localize.json
的配置文件,位于你的项目根目录下。这个文件告诉 Lit Localize 你的源代码和输出在哪里,以及你想要使用哪种输出模式。
下面是一个 runtime 模式的配置示例:
{
"$schema": "https://raw.githubusercontent.com/lit/lit/main/packages/localize-tools/config.schema.json",
"sourceLocale": "en",
"targetLocales": ["es-419", "zh-Hans"],
"tsConfig": "./tsconfig.json",
"output": {
"mode": "runtime",
"outputDir": "./src/generated/locales",
"localeCodesModule": "./src/generated/locale-codes.ts"
},
"interchange": {
"format": "xliff",
"xliffDir": "./xliff/"
}
}
这个配置会:
- 从项目中的
.ts
和.js
文件中提取msg
调用。 - 将翻译文件输出到
xliff
目录。 - 生成
es-419
和zh-Hans
区域设置的模块到src/generated/locales
目录。 - 生成一个
src/generated/locale-codes.ts
模块,导出源区域设置和目标区域设置的列表,这样你可以轻松引用它们。
如果你使用的是 transform 模式,则配置会略有不同:
{
"$schema": "https://raw.githubusercontent.com/lit/lit/main/packages/localize-tools/config.schema.json",
"sourceLocale": "en",
"targetLocales": ["es-419", "zh-Hans"],
"tsConfig": "./tsconfig.json",
"output": {
"mode": "transform",
"outputDir": "./build"
},
"interchange": {
"format": "xliff",
"xliffDir": "./xliff/"
}
}
此配置除了生成翻译文件外,还会将源代码编译成三个不同的版本:build/en
、build/es-419
和 build/zh-Hans
。
有关可用配置选项的完整列表,请参阅 CLI 和配置页面。
要从源代码中提取所有可本地化的字符串和模板,请运行 lit-localize extract
。
这将创建一个 XLIFF 文件,其中包含你应用程序中的每个可本地化字符串和模板。XLIFF(XML Localization Interchange File Format)是一种用于在不同本地化服务之间交换翻译的标准格式。
使用 XLIFF 翻译
Permalink to "使用 XLIFF 翻译"在使用 lit-localize extract
提取消息后,每个区域设置都会有一个 XLIFF 文件。例如,使用前面示例中的配置,你会得到两个文件:xliff/es-419.xlf
和 xliff/zh-Hans.xlf
,每个文件看起来类似于:
<?xml version="1.0" encoding="UTF-8"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file target-language="es-419" source-language="en" original="lit-localize-inputs">
<body>
<trans-unit id="hf71d669027554f48">
<source>Hello <ph id="0"><b></ph><ph id="1">${this.who}</ph><ph id="2"></b></ph></source>
</trans-unit>
</body>
</file>
</xliff>
编辑每个 XLIFF 文件,为每个 <trans-unit>
添加一个 <target>
元素,以包含对应的翻译。例如:
<?xml version="1.0" encoding="UTF-8"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file target-language="es-419" source-language="en" original="lit-localize-inputs">
<body>
<trans-unit id="hf71d669027554f48">
<source>Hello <ph id="0"><b></ph><ph id="1">${this.who}</ph><ph id="2"></b></ph></source>
<target>Hola <ph id="0"><b></ph><ph id="1">${this.who}</ph><ph id="2"></b></ph></target>
</trans-unit>
</body>
</file>
</xliff>
有几种方法可以从 XLIFF 文件创建翻译:
- 手动编辑每个 XLIFF 文件,就像上面的例子一样。
- 使用工具如 Phrase、Lokalise 或 译马 创建翻译。
- 使用 Google 云翻译。
翻译完成后,运行 lit-localize build
生成本地化版本的消息。
切换区域设置
Permalink to "切换区域设置"Lit Localize 提供了一个 API,用于在运行时模式下的区域设置之间切换。下面是一个简单切换器的示例:
import {configureLocalization} from '@lit/localize';
import {sourceLocale, targetLocales} from './generated/locale-codes.js';
// 本地化设置
export const {getLocale, setLocale} = configureLocalization({
sourceLocale,
targetLocales,
loadLocale: (locale) => import(`./generated/locales/${locale}.js`),
});
// 语言切换组件
export class LocalePicker extends LitElement {
render() {
return html`
<select @change=${this._localeChanged}>
<option value="en" ?selected=${getLocale() === 'en'}>English</option>
<option value="es-419" ?selected=${getLocale() === 'es-419'}>Español</option>
<option value="zh-Hans" ?selected=${getLocale() === 'zh-Hans'}>简体中文</option>
</select>
`;
}
private _localeChanged(event: Event) {
const newLocale = (event.target as HTMLSelectElement).value;
setLocale(newLocale);
}
}
customElements.define('locale-picker', LocalePicker);
在转换模式下,你需要使用浏览器导航或服务器配置来切换区域设置,因为每个区域设置都是一个独立的构建。完整的详情参见转换模式页面。
自定义消息 ID
Permalink to "自定义消息 ID"默认情况下,Lit Localize 从消息的内容自动生成 ID。有时你可能想要指定自定义 ID,例如,当你有一个需要在两个版本之间保持一致的消息,但其上下文发生了变化:
msg('Log in', {id: 'app.login'});
或者对于模板:
msg(html`Hello <b>World</b>`, {id: 'app.greeting'});
更多处理翻译的高级技巧,请参阅最佳实践页面。