I18n Workflow for React Project

Michael Hsu
5 min readApr 21, 2017

--

多國語言的機制建議盡量在專案初期就能有好的規劃,不至中後期要把字串抽出將會是件累人的事,而在現今前端開發的演進下,多國語言的流程也出現了一些不同的處理方式,以下簡介我們在 MediaTek 內前端專案處理的模式。

MVC Framework

在以前像是 Rails 類的 MVC 框架中,其實已經定義好多國語言應該怎麼處理,例如 Laravel 會把文案抽出定義在 lang 結構下的檔案:

// resources/lang/en/about.php
<?php
return [
'about' => [
'title' => 'About us',
],
];

如此頁面或是 API Response 的內容可以集中管理在這些檔案中,當 User 需要更新文案只要找到檔案位置即可一次更新所有相關的字串。

Problems

  1. 流程分離:在上個段落其實已經是很好的解法了,但是這會碰到一個問題是,後續新增其他語言的文案時,必須是熟悉專案的人員才能來幫忙更新,雖然應該是不會動到核心程式碼,但是工程師難免還是會提心吊膽,因此將工作流程切分開來會是比較好的做法。
  2. SPA 開發模式:在現今前端的發展下,大部分都開始做前後端分離,因此多半不會再仰賴 MVC 的框架,這時候前端就需要自己處理多國語言的問題了。

React-intl 解決方案

在 React 專案中可以透過 Yahoo Open Source 的 React-intl 專案來幫忙,第一種是用 Component 來定義字串,像是這樣:

<FormattedMessage
id="CopyButton.text"
defaultMessage="複製"
/>

第二種是用在某些無法塞 Component 的情況,例如 Input 的 placeholder Attribute,這時候可以使用 HOC 把翻譯的 Function 以 props 傳遞進去:

injectIntl(Component);
this.props.intl.formatMessage(...);

Babel Plugin

在專案內順利地使用 React-intl 定義完後,接下來是要想如何有效率的把字串抽出來,這時候是透過 babel-plugin-react-intl 在 Babel 階段來處理,因此跑過整份專案後就可以產生相對應一份份的 Json 格式檔案:

// components/CopyButton.js
[
{
"id": "CopyButton.text",
"defaultMessage": "複製"
}
]

接下來就可以對這些抽取出來的字串進行操作、翻譯、合併、轉換。

Poedit Editor

在 React-intl 的設計上是使用 ICU 的規範,但感覺都沒有以前在寫 Angular 用的 Poedit 來得友善,因此在這邊我們考慮把 ICU 轉換為 PO 來做後續的操作。

Poedit 介面

當然在轉換的過程會失去原有 ICU 處理變數以及單複數的模式,但是比較少用到因此直接忽略。

POT Convertor:React-intl-po

要將 Babel 抽取出來的 Json File 轉換成 POT 格式其實是一件很簡單但是無聊的格式轉換問題,因此我就把這段 Script 抽出來發佈在 NPM 上供之後的專案使用,沒想到這個 Edge Case 除了我們內部專案使用外還有一些人也在使用。因此整體的流程變成下圖,其中 React-intl-po 處理了橘色的兩個步驟:

翻譯包版本控制

產品上線有版號控制,當然語言包也要做版本控制,這邊使用 Git 進行管理,每當產品要部署就安裝新的翻譯包,所以我們要把翻譯包獨立一個 Repository,也能協助參與人員各司其職:

  1. 開發者:開發完後產生一份檔案供翻譯者使用。也就是 POT 未被翻譯的檔案。
  2. 譯者:收到新的 POT 的檔案後更新翻譯包。也就是翻譯後的 PO 檔案。
  3. 部署:上版時在 GitHub 上操作 Release 進行版控。

後記

本篇提到的多國語言處理算是一個 Workaround,可能也只適用於特定情境,但是畢竟都寫了與其埋沒在專案內,還不如直接以 NPM 的套件方式丟出去看看,除了跨專案能重複使用外,也許還會獲得不少反饋!

--

--