国际化
我们的应用程序拥有遍布世界各地的众多用户。为了帮助他们使用自己语言的 Metabase,我们将所有字符串标记为 i18n(国际化)。
快速指南
如果您需要添加新字符串(请谨慎添加文案),请执行以下操作:
- 在前端使用
t和jtES6 模板字面量标记字符串(更多详情请参阅 https://ttag.js.org/)
const someString = t`Hello ${name}!`;
const someJSX = <div>{jt`Hello ${name}`}</div>;
并在后端使用 trs(使用网站语言)或 tru(使用当前用户的语言)。
(trs "Hello {0}!" name)
翻译错误或缺失字符串
如果您看到您语言的字符串不正确或缺失,请访问我们的 Crowdin 项目 并在此处提交您的更正。
后端翻译指南
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 来生成它们。
我们有许多贡献者帮助我们维护了多种语言的翻译字符串语料库。我们使用 Crowdin 来维护一个权威列表。我们从 Crowdin 导出 .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 的文档。