國際化

我們是一個在全球擁有眾多使用者的應用程式。為了幫助他們以自己的語言使用 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 文件。