国际化

我们是一款全球拥有众多用户的软件。为了帮助他们使用自己语言版本的 Metabase,我们将所有字符串都标记为 i18n。

快速指南

如果您需要添加新的字符串(尽量谨慎添加副本),请按照以下步骤操作

  1. 在前端使用 tjt 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-servertr-user

工作原理

从高层次来看,要翻译的字符串被视为一个查找键,指向源字符串 -> 本地化字符串的映射。这个翻译字符串的使用如下


;; from source of `translate` in `metabase.util.i18n`

(.format (MessageFormat. looked-up-string) (to-array args))

其他都是大量的簿记。这使用 java.text.MessageFormat 类来拼接格式参数。

函数 trstru 分别创建了两个记录的实例,SiteLocalizedStringUserLocalizedString,并对 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版本的文档。

想改进这些文档? 提出更改。