国际化
我们是一个在全球拥有众多用户的应用程序。为了帮助他们使用自己的语言使用 Metabase,我们将所有字符串标记为 i18n。
快速指南
如果您需要添加新字符串(尽量谨慎添加副本),请执行以下操作
- 在前端使用
t
和jt
ES6 模板字面量标记字符串(更多详情请参阅 https://ttag.js.org/)
const someString = t`Hello ${name}!`;
const someJSX = <div>{jt`Hello ${name}`}</div>;
并在后端使用 trs
(使用站点语言)或 tru
(使用当前用户的语言)
(trs "Hello {0}!" name)
翻译错误或缺失字符串
如果您发现您的语言存在不正确或缺失的字符串,请访问我们的 POEditor 项目 并在那里提交您的修复。
后端翻译指南
Metabase 允许翻译成多种语言。权威列表可以在 resources/locales.clj
中找到。
Metabase 端
Metabase 关注本地化为两种不同的语言环境:翻译成服务器的语言环境和翻译成用户的语言环境。主要区别在于:这将记录在服务器上还是通过网络发送回用户。
要为服务器翻译字符串,请使用 metabase.util.i18n/trs
,对于用户的语言环境,请使用类似的 metabase.util.i18n/tru
。可以理解为 tr-server
和 tr-user
。
工作原理
从高层次上讲,要翻译的字符串被视为查找键,用于查找源字符串 -> 本地化字符串的映射。翻译后的字符串像这样使用
;; from source of `translate` in `metabase.util.i18n`
(.format (MessageFormat. looked-up-string) (to-array args))
其他一切基本上都是簿记。这使用 java.text.MessageFormat 类来拼接格式参数。
函数 trs
和 tru
分别创建 SiteLocalizedString
和 UserLocalizedString
这两个记录的实例,并重写了 toString
方法。此方法将查找当前语言环境(用户或站点,视情况而定),查找要翻译的字符串对应的已翻译字符串,然后在 MessageFormat
上调用 .format
方法。
从源字符串到翻译字符串的映射
我们构建过程中的一个步骤是为我们支持的每种语言环境创建一个从源字符串到翻译字符串的 edn 文件。这些文件位于 resources/i18n
中。如果您没有这些文件,可以运行 bin/build-translation-resources
来生成它们。
我们有很多贡献者帮助我们维护一个包含多种不同语言的翻译字符串语料库。我们使用 POEditor 来维护权威列表。我们从中导出 .po
文件,这本质上是一个从源字符串到翻译字符串的字典。作为构建过程的一部分,我们将这些文件格式化为 edn 文件,即每种语言环境从源字符串到翻译字符串的映射。
格式参数
除了字符串字面量,我们还想翻译中间拼接了参数的字符串。我们使用之前提到的 java.text.MessageFormat 类中的语法。这些是以零索引参数形式 {0}
、{1}
。
例如,
(trs "{0} accepted their {1} invite" (:common_name new-user) (app-name-trs))
(tru "{0}th percentile of {1}" p (aggregation-arg-display-name inner-query arg))
(tru "{0} driver does not support foreign keys." driver/*driver*)
转义
每种字符串语言都需要一个转义字符。由于 {0}
是要拼接的参数,那么如何在字符串中放入字面量“{0}”呢?撇号充当了这个角色,并在 MessageFormat javadocs 中进行了描述。
虽然这有一个不幸的副作用。由于撇号是如此常见的语音部分(尤其是在法语中),我们经常最终将转义字符用作字符串的常规部分,而不是转义字符。格式字符串需要使用双撇号,例如 (deferred-tru "SAML attribute for the user''s email address")
以转义撇号。
法语中有很多翻译字符串错误地使用了单撇号。(例如“l’URL”而不是“l’‘URL”)。我们在 bin/i18n/src/i18n/create_artifacts/backend.clj
中对此进行了手动修复,我们在其中尝试识别这些不是转义字符的撇号,并将它们替换为双引号。
阅读其他 Metabase 版本 的文档。