背景
最近接到一個海外專案業務需求,專案最終會被來自不同國家的客戶所使用,期望能讓客戶有一個良好的使用者體驗,因此前端需要適配國際化。
面臨的挑戰
乍一聽,這個海外專案需求並沒有什麼特別的地方,似乎就多了一個國際化適配。但細細一想,事情可沒這麼簡單,前端開發面臨了很多新的問題。下面梳理一下國際化開發中通常會面臨的挑戰:
-
頁面文案全部可配置 需要配置的文案大致有四種:label、placeholder、欄位校驗提示資訊、超連結。
-
頁面文案樣式處理 文案樣式需要特別注意,不同語言的文字,可能會有不同的表現。例如下面兩張圖所示:
- 英語(頁面樣式正常)
- 俄語(頁面樣式異常)
-
日期、數字格式處理 頁面上展示日期或數量的地方,也是需要做國際化適配。
-
LTR/RTL 很多中東國家的語言習慣都是 RTL,可以嘗試使用 direction 和 transform 來解決。
-
圖片(banner)國際化 如果你想把國際化做的足夠精細,那麼圖片國際化也是需要考慮的。
-
第三方 UI 元件 如果使用了第三方 UI 元件,如:elementUI、ant design UI 等,這些 UI 框架通常都宣稱支援國際化,但支援的國際化語言數量有限,並不一定能滿足業務需求。
-
前端開發工作量和後期維護成本激增 大量的文案需要被提取出來,被提取出來的文案最終會被合併到一個檔案中去,如:en-US.json。這些工作如果通過手工完成,那麼工作量會是非常巨大的。
國際化文案的處理思路
以上列舉出了很多挑戰,但實際上“頁面文案處理”才是最主要的矛盾,因為它直接導致前端開發工作量和維護成本的激增。下面我們重點來討論文案處理思路,其實從實現國際化的角度來看,jQuery、Vue、React 等都只是載體而已,實現思路都是相通的,因此國際化文案處理與具體的技術框架並不耦合。接下來將會丟擲幾種國際化文案處理思路,每種思路對生產力和生產關係的要求有高有低,姑且將其分別對應為石器時期、青銅時期、黃金時期。
石器時期
傳統的國際化開發流程:前端開發到一定階段,將文案提取到資原始檔(通常為 en-US.json),然後將資原始檔傳送給翻譯團隊,翻譯團隊翻譯出各國語言版本的文案,每種語言對應一個資原始檔,最後將這些資原始檔發回給前端開發人員,前端開發人員更新到自己本地。如下圖所示:
-
適用場景
- 頁面上要提取的文案不多
- 支援的國際化語言較少,比如:只需要支援中文和英文
- 專案需求較固定,後期只做簡單維護,不會新增大的需求
-
分析 這是國際化開發的基本流程,“前端開發”和“翻譯團隊”是必不可少的兩個節點,但它們相互之間依賴的太重。“提取文案”的過程本質上是在重複勞動,因此可以考慮由程式來完成。
-
程式碼示例
- App.js
import React, { Component } from 'react'; import { IntlProvider, FormattedMessage } from 'react-intl'; import qs from 'querystring'; import logo from './logo.svg'; import './App.css'; import DEFAULT_MESSAGES from './i18n/en-US.json'; const DEFAULT_LOCALE = 'en-US'; class App extends Component { state = { messages: DEFAULT_MESSAGES, }; componentWillMount() { const search = window.location.search.slice(1); const params = qs.parse(search); const locale = params.locale || DEFAULT_LOCALE; const messages = require(`./i18n/${locale}.json`); debugger; this.setState({ messages, }); } render() { const { messages } = this.state; return ( <IntlProvider locale="en" messages={messages}> <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p> <FormattedMessage id="welcome" defaultMessage={`Hello world!`} /> </p> <a className="App-link" href="/?locale=zh-CN" rel="noopener noreferrer" > zh-CN </a> <a className="App-link" href="/?locale=en-US" rel="noopener noreferrer" > en-US </a> </header> </div> </IntlProvider> ); } } export default App; 複製程式碼
- en-US.json
{ "welcome": "Hello world!" } 複製程式碼
青銅時期
前面分析了“提取文案”的過程本質上是在重複勞動,那我們看看有沒有辦法進行改進。我們可以先對比一下“無國際化需求”和“有國際化需求”時的前端開發流程。如圖所示:
可以看出右邊多了三個過程:
- 將文案提取為變數
- 為變數命名,要合乎其場景
- 將變數和文案資訊存到資原始檔
這裡我們提出一個期望或願景:希望能像開發普通業務一樣去開發有國際化需求的業務!
為了達成這一願景,我們需要有一個工具:它能夠掃描指定的檔案,並能識別出檔案中的字串,然後能根據字串的含義生成變數名,並用變數表示式替換掉原來的字串,最後能夠將提取出來的變數自動追加到資原始檔中。
如何實現這樣的工具?我們可以用 Babel 將js檔案解析為一顆語法樹,然後遍歷並找出字串節點,接下來呼叫 Google Cloud Translation API 將字串翻譯為英文,並以此作為變數名得到變數表示式,最後用變數表示式替換掉原來的文字即可。如下圖所示:
幸運的是,i18n-pick 已經有那麼點味道了~
- 分析 這是站在開發層面,對前端開發體驗和開發效率提出的改進辦法,將重複的事情交給程式去完成。
黃金時期
有了石器時期的生產方式作為鋪墊,我們可以在此基礎上繼續做改進。既然“前端開發”和“翻譯團隊”之間依賴的太重,那我們可以在中間加一個節點“文案配置平臺”。前端將提取的文案直接上傳到“文案配置平臺”,翻譯團隊直接在“文案配置平臺”上進行文案翻譯,前端直接從“文案配置平臺”獲取翻譯後的最新文案。
- 文案配置平臺應當具備的基本能力
- 面向前端開發人員:文案錄入、輸出
- 面向翻譯團隊:文案翻譯、釋出
- 其他:文案版本控制
- 適用場景
- 有大量的國際化業務需求
- 希望將其沉澱為通用能力平臺,提升業務開發效率
- 分析 這是從架構層面對國際化開發方式進行優化和提效,一般大的網際網路公司因為其自身業務的複雜度,都早已沉澱出很多的通用能力平臺。
總結
以上每種思路都有各自適用的場景,實際生產中需要從開發成本、開發體驗、後期維護、能力沉澱等多維度進行考慮。這篇文章旨在拋磚引玉開啟思路,各位看官可以將自己的思路丟擲來一起討論。
參考
- Internationalization
- 國際化 - 通用 LTR/RTL 佈局解決方案
- i18n-pick
- Babel 外掛開發指南
- Google Cloud Translation API: Node.js Client
文章可隨意轉載,但請保留此 原文連結。
非常歡迎有激情的你加入 ES2049 Studio,簡歷請傳送至 caijun.hcj(at)alibaba-inc.com 。