本地化最佳实践
确保渲染时重新评估
Permalink to "确保渲染时重新评估"每次调用 msg
函数时,它会返回给定字符串或 Lit 模板在当前活动区域设置中的版本。然而,这个结果只是一个普通的字符串或模板;它不具备在区域设置变更时自动重新渲染自身的能力。
因此,重要的是要以确保每次 Lit 的 render
方法运行时都会重新评估 msg
调用的方式来编写代码。这样,当区域设置变更时,将返回最新区域设置的正确字符串或模板。
在这方面容易出错的一种情况是本地化属性默认值。可能自然而然地会这样写:
// 不要这样做!
label = msg('Default label')
render() {
return html`<button>${this.label}</button>`;
}
然而,上述模式没有提供在区域设置变更时更新默认标签的机会。默认值将停留在元素实例化时活动区域设置的版本。
一个简单的解决方法是将默认值回退直接移到 render 方法中:
render() {
return html`<button>${this.label ?? msg('Default label')}</button>`;
}
或者,可以使用自定义的 getter/setter 来创建更自然的接口:
private _label?: string;
@property()
get label() {
return this._label ?? msg('Default label');
}
set label(label: string) {
this._label = label;
}
render() {
return html`<button>${this.label}</button>`;
}
static properties = {
label: {}
};
get label() {
return this._label ?? msg('Default label');
}
set label(label) {
this._label = label;
}
render() {
return html`<button>${this.label}</button>`;
}
避免不必要的 HTML 标记
Permalink to "避免不必要的 HTML 标记"虽然 @lit/localize
完全支持在本地化模板中嵌入 HTML 标记,但最好尽可能避免这样做。这是因为:
对于翻译人员来说,处理简单的字符串短语比处理带有嵌入标记的短语更容易。
当标记变更时,例如添加一个影响外观但不改变含义的类时,可以避免不必要的重新翻译工作。
切换区域设置通常会更快,因为需要更新的 DOM 部分更少。此外,你的包中将包含更少的 JavaScript,因为常见标记不需要复制到每个翻译中。
不理想的做法:
render() {
// 不要这样做!在本地化模板中包含 <button> 标签没有理由。
return msg(html`<button>Launch rocket</button>`);
}
理想的做法:
render() {
// 好多了!现在短语 "Launch rocket" 可以更容易地单独翻译。
return html`<button>${msg('Launch rocket')}</button>`;
}
将模板分解为更小的部分也会有所帮助:
render() {
// 不要这样做!
return msg(html`
<p>The red button makes the rocket go up.</p>
<p>The green button makes the rocket do a flip.</p>
`);
}
render() {
// 更好!翻译人员不需要处理标记,每个句子可以独立翻译。
return html`
<p>${msg('The red button makes the rocket go up.')}</p>
<p>${msg('The green button makes the rocket do a flip.')}</p>
`;
}
在使用转换模式时,模板将自动扁平化,使它们尽可能小和高效。变换后,上述示例不会有任何占位符,因为系统知道字符串可以直接合并到 HTML 模板中。
在某些情况下,HTML 应该包含在本地化模板中。例如,当短语中间需要 HTML 标签时:
render() {
return msg(html`Lift off in <b>T-${this.countdown}</b> seconds`);
}
安全地重新导出或重新分配本地化 API
Permalink to "安全地重新导出或重新分配本地化 API"静态分析用于确定你何时调用 @lit/localize
的 msg
函数和其他 API,而不是调用同名的不同函数。
可以重新导出或重新分配 msg
函数和其他 API,大多数情况下这会正常工作。
然而,某些模式可能过于动态,以至于静态分析无法理解。如果消息提取失败,并且你已重新分配或重新导出了 msg
函数,这可能是原因。
要强制将函数分析为 @lit/localize
API,你可以在 JavaScript 中使用 JSDoc @type
注释,或在 TypeScript 中使用类型转换:
const myMsg = ... as typeof import('@lit/localize').msg;
/** @type import('@lit/localize').msg */
const myMsg = ...;