多端統(tǒng)一國際化

前言

國際化是軟件設(shè)計(jì)領(lǐng)域常見一個(gè)需求,其工作內(nèi)容常常包括:

  • 泛客戶端國際化,包括 iOS、Android 和 Web
  • 服務(wù)端國際化
  • 國際化資源文件管理
  • 項(xiàng)目之間、開發(fā)人員與翻譯者之間的協(xié)作

并且國際化方案常與具體技術(shù)棧綁定。

本套解決方案是在多端(iOS、Android 和 Web)確定各自國際化技術(shù)方案的基礎(chǔ)上,提供一套統(tǒng)一的國際化資源文件管理和相關(guān)合作伙伴協(xié)作的工作流。

需求痛點(diǎn)

目前,APP 端的國際化開發(fā)流程是,各端的開發(fā)人員會根據(jù)需求規(guī)格說明書在開發(fā)期間預(yù)定義待翻譯詞條對應(yīng)的 termId,然后翻譯人員后續(xù)把待翻譯的詞條列表以 excel 表格形式發(fā)送給各端人員,各端人員再根據(jù)對應(yīng)翻譯后的詞條,更新各自的翻譯文件。

以上的工作流程圖如下:

[圖片上傳失敗...(image-ef78cd-1614174010505)]

上述的工作流導(dǎo)致的問題在于:

  • 翻譯人員將花費(fèi)大量時(shí)間在整理待翻譯詞條的表格,然后給到開發(fā)人員
  • 開發(fā)人員拿到對應(yīng)翻譯后的詞條表格然后逐步比對各自的翻譯文件
  • 多端開發(fā)人員自行定義 termId,大概率會出現(xiàn)同一詞條在不同平臺上不同的 termId 的命名
  • 期間如果遇到缺漏翻譯的問題,開發(fā)人員需要再次向翻譯人員索要翻譯文本,翻譯工作與開發(fā)工作強(qiáng)耦合
  • 缺少自動(dòng)化翻譯工具,翻譯人員翻譯工作繁重

一個(gè)最為理想的協(xié)作流程理應(yīng)是:

  • 開發(fā)人員的待翻譯詞條不應(yīng)該從產(chǎn)品人員中獲取,而是從需要國際化的頁面的靜態(tài)文本中獲取,待翻譯的詞條空間是從開發(fā)期間提取出來的
  • 開發(fā)人員將提取后的待翻譯詞條上傳到翻譯平臺,然后通知翻譯人員進(jìn)行翻譯工作
  • 翻譯人員不用關(guān)注哪些詞條是需要待翻譯并且給到開發(fā)人員的,只關(guān)注于給到的待翻譯的詞條空間
  • 在翻譯平臺首先利用自動(dòng)翻譯工具將語言進(jìn)行初步翻譯,類似英文翻譯,利用自動(dòng)翻譯工具有可能會存在詞法上的偏差,所以還需要參考業(yè)內(nèi)常用的國際化文案進(jìn)行二次修正,見 https://i18ns.com/
  • 翻譯人員翻譯完成后通知開發(fā)人員,開發(fā)人員再從翻譯平臺下載翻譯后的文件

方案設(shè)計(jì)

前文提到一個(gè)最為理想的協(xié)作流程的愿景,但是理想是豐滿的,現(xiàn)實(shí)是骨感的。在實(shí)際的方案設(shè)計(jì)中需要結(jié)合目前多端、多平臺的差異性和項(xiàng)目的歷史技術(shù)債務(wù),綜合考慮得出一個(gè)對原有多端國際化技術(shù)影響的降到最小的解決方案。

根據(jù)客戶端同事反饋,原有的翻譯詞條達(dá)到 3000 多條,并且是以模塊為單位分散在各個(gè)文件夾下,如果將原有的翻譯文件納入新的工作流會導(dǎo)致重構(gòu)成本較大,因此本次多端統(tǒng)一國際化方案將不改變之前的翻譯文件的實(shí)施方式,而是對接下來的版本的多端國際化實(shí)施本套新的工作流;

多端國際化方案主要涉及以下方面:

  • 第三方翻譯平臺的選取
  • 多端國際化特點(diǎn)的差異化處理
  • 翻譯文件的上傳與下載

第三方翻譯平臺的選取

第三方翻譯平臺將選擇 POEditor,該平臺除了提供基礎(chǔ)的可視化詞條翻譯界面外,還支持自動(dòng)翻譯功能用以提高翻譯效率以及開放 API 以打造自動(dòng)化工作流。

此外,POEditor 還支持多平臺、多格式的翻譯源文件,包括 .po、.pot、.xls、.csv、xml、.strings 等。

多端國際化特點(diǎn)的差異化處理

前文已經(jīng)提到國際化方案常與具體的技術(shù)棧綁定,因此不同的客戶端(iOS、Android 和 Web)在國際化方案的實(shí)現(xiàn)方法中存在一定的差異。通過抽象找到多端存在的共同特征和差異性,在具體方法實(shí)施中需要找到合適的切入點(diǎn)。

一般來說,無論是什么平臺以及使用何種技術(shù)棧,國際化技術(shù)離不開翻譯詞條 id 對應(yīng)特定語言的翻譯這一基本原理,這是多端的共性所在,特性在于不同的翻譯源文件可能在數(shù)據(jù)結(jié)構(gòu)形式上存在一定的差異。

以下是Web、iOS 和 Android 的翻譯源文件,

Web 是采用 GNU 的 Gettext 方案,從源代碼中提取出來的 pot 文件;

// Web
#: src/pages/Index/index.tsx:23
msgid "一個(gè)蘋果"
msgid_plural "%d 個(gè)蘋果"
msgstr[0] ""

#: src/pages/Index/index.tsx:20
msgid "你好,悅跑圈"
msgstr ""

#: src/pages/Index/index.tsx:26
msgid "姓名:%s"
msgstr ""

Android 和 iOS 一樣,本身在框架內(nèi)已經(jīng)定義好一套國際化的解決方案,Android 是在特定目錄下創(chuàng)建不同語言版本的 string.xml 文件,而 iOS 則是 xxx.strings 文件。

// Android string.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="aitrain">AI Speech Training</string>
</resources>

// iOS Localizable.strings
"aitrain" = "AI Speech Training";

三者在詞條提取方法和詞條 id 的定義上存在一定的不同。

目前,web 端是采用 GNU 的 gettext 方案,從帶標(biāo)記的源碼中提取待翻譯的詞條生成合并后的 pot 文件,因此其對于的 termId 就是當(dāng)時(shí)標(biāo)記時(shí)的文本,表現(xiàn)為純中文;

而 Android 和 iOS 本身就從代碼組織層面講待翻譯的詞條從頁面中剝離,形成單獨(dú)的 xml 或是 strings 文件,頁面在引入各自的翻譯文件時(shí)需要根據(jù)對應(yīng)的 termId 去調(diào)用函數(shù)去設(shè)值,這里就會產(chǎn)生一個(gè)與 web 端所沒有的問題,初始化時(shí)的 termId 如何進(jìn)行定義?

與 web 端不同,termId 不是直接從帶標(biāo)記的文本中提取,而是直接寫在各自的獨(dú)立的翻譯文件中,并且 termId 必須使用英文進(jìn)行標(biāo)識。此外,由于 iOS 和 Android 分屬不同平臺,如何避免同一個(gè)頁面各自定義不同的 termId?

<colgroup><col><col><col><col></colgroup>
|

端或平臺

|

國際化技術(shù)框架

|

詞條提取方式

|

翻譯文件格式

|
|

Web 端

|

GNU 的 Gettext

|

從標(biāo)記的源碼中提取,termId 就是源碼中標(biāo)記時(shí)的文本

|

抽取的待翻譯文件是 pot 文件,翻譯后的文件采用 json 文件

|
|

iOS 端

|

框架限定

|

單獨(dú)的文件夾存放翻譯文件,無需從源碼中提取,但是 termId 需要預(yù)定義

|

翻譯前后的文件均為 .strings 文件

|
|

Android 端

|

框架限定

|

同上

|

翻譯前后的文件均為 string.xml 文件

|

方案輸出 *****

鑒于以上出現(xiàn)的問題,這里給出的解決方案如下:

對于 Web 端詞條 id 生成的特殊性,單獨(dú)建立一個(gè) POEDitor 項(xiàng)目,其將獨(dú)立于客戶端項(xiàng)目,自動(dòng)從源碼抽取帶標(biāo)記的文本生成對應(yīng)的翻譯文件然后上傳至翻譯平臺;

而對于 iOS 和 Android,則需要產(chǎn)品人員事先在需求規(guī)格說明書時(shí)就要在翻譯平臺初始化一份當(dāng)前版本新增的待翻譯詞條的默認(rèn)語言的源翻譯文件以約束開發(fā)人員使用統(tǒng)一一套 termId, 初始化后產(chǎn)品人員通知開發(fā)人員從翻譯平臺下載最新版本的默認(rèn)語言翻譯文件進(jìn)行開發(fā)工作,等到翻譯人員將多國語言的翻譯完成后,再次通知開發(fā)人員下載完整的翻譯后的文件。

值得注意的是,經(jīng)過和客戶端的同事溝通,原有的翻譯文件的組織方式是分散在各個(gè)模塊中,這樣一來采用多端國際化解決方案對于項(xiàng)目本地的翻譯文件管理就會造成一定的困難。因此,在后續(xù)的版本迭代中,iOS 和 Android 端將會獨(dú)立出一個(gè)公共的模塊用于統(tǒng)一管理國際化文件,其他模塊將會從這個(gè)公共的國際化模塊中引入翻譯后的文件,翻譯文件的上傳和下載也就針對該份文件。

下面舉個(gè)例子,例如假設(shè)新增的頁面涉及如下詞條,則產(chǎn)品人員可先在 POEditor 進(jìn)行形式化的 termId 定義:

<colgroup><col><col><col></colgroup>
|

termId

|

name

|

remark

|
|

login.btn.comfirm(Andrord 平臺內(nèi)在機(jī)制使用點(diǎn)分命名會產(chǎn)生命名變更)

login_btn_confirm

|

確認(rèn)

|

登錄頁確認(rèn)按鈕

|
|

run_btn_startRun

|

開始跑步

|

跑步頁開始跑步按鈕

|

termId 的命名規(guī)則大體上是 <頁面> + <控件類型> + <文本值>,待將本次版本更新后的初始化翻譯文件定義好后,通知開發(fā)人員下載默認(rèn)語言的翻譯清單。

// string.xml
<?xml version="1.0" encoding="utf-8"?>
    <resources>
      <string name="login_btn_confirm">確認(rèn)</string>
    </resources>

// locales.strings
"login_btn_confirm" = "確認(rèn)"

這樣一來客戶端就可以采用同一套默認(rèn)語言源文件去初始化各自不同平臺的翻譯文件,等到后續(xù)翻譯人員將多國語言翻譯好后,開發(fā)人員只需直接從 POEditor 下載即可。

372px上述的多端國際化工作流變?yōu)椋?/p>

[圖片上傳失敗...(image-2c58ae-1614174010505)]

下面討論一下這個(gè)解決方案的優(yōu)缺點(diǎn),

優(yōu)點(diǎn)在于即便是不同平臺的客戶端,其翻譯文件都是通過統(tǒng)一一套 termId 去標(biāo)識詞條,有利于打造多端統(tǒng)一國際化工作流;由于 POEditor 充當(dāng)類似”中間層“的角色,因此翻譯人員只需在翻譯平臺編輯詞條,而開發(fā)人員也只需從翻譯平臺上傳或下載詞條,實(shí)現(xiàn)工作流上的解耦。

缺點(diǎn)是開發(fā)人員需要等待產(chǎn)品人員事先提供一份待翻譯的詞條清單,一旦頁面存在缺漏或是需求上的變動(dòng),又需要產(chǎn)品人員給出變動(dòng)的詞條清單。這樣一來,產(chǎn)品和開發(fā)人員的工作又會陷入一定的耦合境地,但是從總體數(shù)量看,問題規(guī)模不會太大。

翻譯文件的上傳與下載

POEditor 提供 Open API 用以實(shí)現(xiàn)翻譯文件的上傳和下載功能,這里為了多端開發(fā)人員便于從 POEditor 平臺下載或上傳翻譯文件,將計(jì)劃打造一款基于 node 的命令行工具 poeditor,下載地址 here

提供 pull 和 push 兩個(gè)命令。

按照 Node.js 環(huán)境,https://nodejs.org/en/;

全局按照 poeditor.cli 命令行工具

$ npm i -g poeditor.cli

# 下載 upstream 更新后的翻譯文件
$ poeditor pull
# 上傳 downstream 新增或修改的翻譯文件
$ poeditor push

當(dāng)運(yùn)行上述命令時(shí),命名行會自動(dòng)讀取當(dāng)前項(xiàng)目根路徑下的 poeditor-config.json 配置文件;

{
  "apiToken": "",       // poeditor token
  "projectId": "",      // 項(xiàng)目 id
  "fileType": "",       // 下載的文件類型,可支持 (po, pot, mo, xls, csv, resw, resx, android_strings, apple_strings, xliff, properties, key_value_json, json, xmb, xtb)
  "targetDir": "",      // 本地翻譯文件文件夾
}

值得開發(fā)人員注意的是,雖然命令行提供 push 操作,但是不建議使用該命令,因?yàn)橛捎诓煌脚_的占位符的差異性所以會導(dǎo)致上傳的詞條會污染上游詞條。

翻譯人員的相關(guān)工作

翻譯人員需要登錄到 poeditor 平臺,初始化一份默認(rèn)語言的的翻譯詞條清單。

[圖片上傳失敗...(image-6610d-1614174010505)]

翻譯人員在翻譯詞條時(shí)有以下幾點(diǎn)需要注意:

  • 所有詞條的 Id 統(tǒng)一采用 <頁面><控件類型><文本值> 的定義形式
  • 翻譯平臺統(tǒng)一約定占位符為 '{variable} xxx',例如 '{count} 蘋果',iOS 在下載翻譯文件的時(shí)候,命令行工具會自動(dòng)替換為 '%@蘋果',Android 則會替換為 '%n$s蘋果'
  • 對于存在復(fù)數(shù)類型的詞條,統(tǒng)一使用兩個(gè)不同的 termId,如 app_fruit_apple 和 app_fruit_apples
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容