單頁面應用的前端多語言處理

Teambition從今年年初開始作國際化,當時的目標是兩個季度後可以在中文之外支持英文和日文兩個語言,所以團隊花了一些時間來嘗試一些適合Single
Page Web
App的多語言方案。本文是Teambition的前端工程師陳涌總結的一篇文章,推薦給每一位但願打造全球化的網頁應用的工程師看看=)前端

Teambition的全部產品線都是單頁面應用, HTML 在前端渲染所以在須要支持中英文時, 多種語言都加載到前端去渲染.
在切換到這個方案之前, wang'ye的語言是在服務端跟代碼一塊兒進行轉換的,下面寫的是切換前遇到問題, 和切換過程咱們採起的方案.編程

切換之前後端渲染的方案

最開始的方案當中, 在開發階段, 代碼編譯, 語言替換, 都在服務端經過中間件完成,
當瀏覽器請求對應的代碼時, 獲取的就是已經編譯好的 JavaScript, 已經對應的語言
所以模版也是在後端編譯的, 而多語言的內容, 就是經過其中一個 i18n 中間件完成的.後端

好比, CoffeeScript, doT 源代碼當中會有一些這樣的內容, 用來標記多語言,
這類代碼會在發送瀏覽器前會被處理, 編譯成對應的中文版或者英文版:瀏覽器

errorMessage = "{{__essageMessage}}"

在編譯上線的階段, 整個編譯過程咱們會對兩種語言都執行一次, 生成兩種語言的版本.
用戶請求應用時, 拿到的就是預先編譯好, 放在 CDN 上的對應語言的代碼.前端工程師

後端編譯的問題

開發階段, 服務端編譯, 由於 Node 自己性能問題, 加上應用體積增大, 響應的速度變得很慢.
加上前端調試廣泛的作法就是改一行代碼就刷新一次頁面, 收到性能的影響就更大了.工具

除了性能, 還有個問題是資源打包, 在咱們嘗試去掉中間件轉而用前端工具編程代碼的過程當中,
當語言是經過靜態替換強制寫入語言的, 意味着代碼傳輸到客戶端之前, 兩種語言的源碼文件已經存在,
因而, 上線以前就須要進行兩次打包, 或者說就是打兩份. 按上邊說的, 會有一些性能上的麻煩.性能

更大的麻煩在於編譯過程, 由於兩種語言的存在, 出現了一些意外的複雜問題.
代碼上線之前的編譯, 大體的流程是:測試

1) CoffeeScript 先轉換成 JavaScript,
2) 而後 JavaScript 通過 RequireJS 合併, 咱們也會留一個環境測試一下合併的代碼,
3) 最後代碼上線以前, 會通過壓縮,, 最後壓縮的代碼再上線.ui

編譯過程當中間有個調試過程, 這個調試過程, 基本上須要語言的, 也對應剛編譯到 JavaScript 這一步.
這就須要在編譯到 JavaScript 的時候, 就是上邊的編譯過程的第一步, 就已經作了多語言.
這以前還要加入一個步驟, 把最初的源代碼編譯出中英文兩份.
最終, 開發目錄就須要用到多個版本的項目代碼:spa

1) 源碼
2) 多語言的源碼
3) 編譯好的開發代碼
4) 合併好的代碼
5) 壓縮準備上線的代碼

注意, 從 2) 開始, 每一個源碼都須要有中英文兩份,
一般整個編譯過程寫下來, 上百行的 Gruntfile 是有了, 隨着兩種語言兩倍的代碼量, 整個更加複雜.
中間還有 RequireJS 之類的問題, 受到源碼複雜的路徑影響, 具體這裏不展開.
其餘還有 LESS, doT, Jade 幾種語言的編譯, 以及相對位置處理, 都比較繁瑣..

咱們的方案

固然解決方案基本的思路也是從不少已有的項目裏學的, 就是語言放到前端去渲染.
用這個方案, 代碼編譯的過程就不用編譯多個版本了, 編譯過程簡化..
同時修改一行語言, 就不用整個 CoffeeScript 文件都編譯, 只要頁面刷新就行了.
而後項目當中維護的文件跟着變少了, 相對維護多種語言的代碼就輕鬆了不少

這個方案的思路是, 語言文件會被整理成兩張 JSON 的表, 做爲 RequireJS 模塊一塊兒打包.
前端代碼運行過程當中檢測瀏覽器的語言環境, 或者寫在設置裏的語言,
根據這個語言, 從表中查詢內容, 用在頁面渲染. 好比這樣的代碼:

lang.getText('error-message')

固然瀏覽器當中, 模版一旦渲染完成, 多語言的內容就應該立刻跟上, 不然用戶看到當成亂碼了.
這裏可能有兩種策略, 一種模仿後端, 在渲染模版時將語言做爲數據傳入.
另外一種, 就是經過 DOM 操做, 在模版渲染後經過 jQuery 抓取節點渲染語言.

大體出於兩個考慮, 咱們選擇了後一種:

1) 不想在模版引擎中嵌入太多邏輯, 並且前端的模版相對後端較弱, 頻繁插入數據不那麼方便,
2) 使用 DOM 操做就有可能在不進行頁面刷新的狀況下切換語言了, 更加靈活

因而爲了語言的信息能在前端被 jQuery 正確識別, 咱們用了這樣的代碼來標記:

<span data-lang-text="error-message"></span>

對這樣的代碼, 咱們寫了一個 CoffeeScript View 方法, 用來對當前 View 的 DOM 進行替換.

renderLocales: ->
  # 獲取有 data-lang-* 屬性的全部標籤
  # 逐個標籤讀取
  # 取出屬性當中的內容做爲 key, 查詢語言
  # 按照 data-lang-* 的語義, 替換對應的語言

這當中的星號通常是上邊的 text, 也有多是 placeholder, 甚至 value 或者其餘內容.
極端的狀況還多是中英文版本的圖片, 那種狀況就特殊問題特殊處理吧...

另外一個沒有討論的問題是, DOM 渲染的性能問題, 經過屬性查詢確實不認爲是高性能的,
這裏先不深刻, 由於實際應用中, 這部分操做數量不大, 性能方面還不影響用戶體驗.

到這裏, 多語言渲染的問題基本完成了.

相關文章
相關標籤/搜索