本地化最佳实践
确保在渲染时重新求值
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 标记,但最好尽可能避免这样做。原因是:
翻译人员更容易处理简单的字符串短语,而不是包含嵌入标记的短语。
避免在标记更改时产生不必要的重新翻译工作,例如在添加仅影响外观而不改变含义的 class 时。
切换语言区域通常会更快,因为 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 = ...;