项目国际化的难点痛点是什么
如果有做過項目國際化的應該了解, 國際化的工作項大概包括以下幾項:
【詞條相關工作】
- 文本包裹翻譯函數,如 $t
- 提取翻譯詞條到 json 文件里
- 翻譯并更新 json 文件
【三方庫相關工作】
- 組件庫的國際化配置,如 element-ui 組件庫
- 其他有詞條場景的三方庫的國際化配置
【圖片、文件相關工作】
- 圖片里出現中文時,需要準備國際化的圖片資源
- 文件里出現中文時,需要準備國際化的文件資源
- 通常是表格導入導出的 excel 文件、用戶聲明和軟件協議等 pdf 文檔或靜態 html 文件
【樣式相關工作】
- 國際化后的文本可能會出現顯示溢出、截斷、亂換行、排版錯亂、未對齊等場景,
- 需要針對不同語言處理不同樣式,互不影響
如果沒有相關經驗的,經常會以為國際化只有詞條相關工作項,這就是第一個坑點:工作量的評估過于樂觀,遺漏其他工作項
但當你真正去開發一個國際化項目后,你會發現,國際化的難點、痛點、坑點遠不止表面看到的這些,尤其是后期維護,痛點更大
相反,詞條工作可能都是最輕松的工作了,因為圈子里有各種各樣的自動化腳本工具來輔助你完成
下面我們就來聊一聊國際化里的各種痛點
如果你經歷過,歡迎一起來吐槽補充
如果你沒經歷過,希望這些痛點可以幫助你在將來如果遇到國際化工作時,可以更有準備的做好評估工作
詞條相關工作的痛點
痛點:詞條出現在各種各樣的地方
這里以 vue2.x 項目為例,詞條有可能存在于 vue 文件的 template 里,script 里,甚至 style 里;也可能存在于 js 文件里,html 文件里。出現在不同地方,需要使用的翻譯函數可能都不一樣,如:
<template>
<div>
<div>{{ $t("這里是中文") }}</div>
<div :label="$t('這里也是中文')"></div>
</div>
</template>
<script>
const ZH_KEY = window.$t("這里也可能有中文,還用不了this上下文");
export default {
props: {
label: {
type: String,
default: window.$t("這里的中文也用不了this上下文"),
},
},
data() {
return {
label2: this.$t("這里中文就用得上this.$t全局函數"),
};
},
mounted() {
setTimeout(function () {
// 異步回調函數不使用箭頭函數,導致 this 指向丟失,內部也無法訪問 this
this.$t(
"這里使用 this.$t() 會拋異常,因為沒有使用箭頭函數,this指向不是當前vue組件實例對象"
);
});
},
methods: {},
};
</script>
<style lang="scss" scoped>
.main {
&:empty {
content: "暫無數據";
// 這里的中文只能通過樣式優先級來覆蓋掉,用不了翻譯函數
[lang="en"] & {
content: "No Data";
}
}
}
</style>
如果你沒仔細看上述代碼里的中文詞條出現的場景的話,可能你會下意識的覺得,vue 里面出現中文的不就 template 模板代碼和 js 代碼里嗎,給 vue 掛個全局翻譯函數如 $t,包裹下出現的詞條不就好了嗎
正常場景下的確是這樣沒錯,但畢竟前端太靈活了,每個人能力水平和習慣不同,如果團隊有規范要求可能還可控點,如果沒有規范要求,或者又是個歷史久遠經手 N 多人的項目的話,你沒法保證代碼里會出現什么樣的寫法
比如,有人甚至通過 :empty 偽類選擇器來填充文本,那這種場景你要么改造掉,要么就只能用 css 優先級覆蓋來解決國際化問題,因為 css 里用不了 js 的函數
比如,有人傳給一些異步操作的回調函數就不使用箭頭函數,非使用原始的 function() {} 聲明,這就導致回調函數內部的 this 指向不是當前 vue 組件實例,所以你在里面使用 this.$t() 的話會導致程序異常。這時候要么改造成箭頭函數,要么就是舊時代還沒有箭頭函數時的解法(在函數聲明前先把 this 保存下來 const self = this,函數內部再通過 self 當前 this 使用)
比如,有人習慣把表單的校驗函數,或者一些靜態變量聲明在 script 標簽內,這里的 js 是運行在模塊作用域內,this 指向也不是當前 vue 組件實例。這時候要么把代碼下沉至 vue 內部,要么就使用 window 全局函數
比如,即使是在 vue 內部里的一些地方,也訪問不了 this,比如 props 里面聲明的組件輸入參數的默認值,如果是中文,這里也訪問不了 this.$t,比如 beforeRouteEnter 生命周期內也訪問不了 this。這種場景只能使用掛載在 window 全局上的翻譯函數了
所以你看,只是在 vue 組件內的代碼,中文詞條就有可能出現在各種各樣的地方,不同地方的上下文還都不一樣,還得分場景處理,得注意是否可以訪問 this 等等問題
更何況,還有 .js,.html 文件的場景
js 文件場景可能還好說,無非就是使用 window 上的全局翻譯函數,或者手動 import 進來一個翻譯函數給當前 js 模塊代碼使用
html 文件里,純原生的 html 里你怎么搞,這里又不是 vue,沒有模板語法可以讓你在 html 里調用 js 函數,那么你只能使用 jQuery 時代的那種思想,手動去操作 dom 進行修改了,舉個例子:
<!DOCTYPE html>
<html>
<head>
<title>這里是中文標題</title>
</head>
</html>
這里的中文,你只能通過 js 來操作 dom,如 document.title = 'xxx',如果不是 title 標簽,而是其他標簽,得先獲取到對應 dom,再做相對應的處理。雖然這種場景不多,但你沒法保證沒有,誰知道這個老項目以前的前輩會怎么寫
所以,給詞條包裹個翻譯函數的工作,也不輕松,坑也很多。即使是各個大佬在推崇的各種自動化插件、腳本工具,這些場景也仍舊需要去關注、小心
痛點:動態拼接的詞條
中文詞條有可能是固定的詞條,也有可能是動態拼接而成的詞條,舉個例子:
<template>
<div>
本次批量操作{{ total }}條,其中,成功{{ success }}條,失敗{{ error }}條
</div>
</template>
<script>
export default {
data() {
return {
total: 10,
success: 3,
error: 7,
};
},
mounted() {},
methods: {
removeItem(item) {
this.$confirm("確認是否要刪除【" + item.name + "】嗎?");
},
},
};
</script>
動態拼接的場景其實也非常常見,比如在一些表格的敏感操作提示、批量操作結果顯示、或者接口報錯提示原因等等場景,都需要根據用戶的行為來動態的拼接上一些業務數據來呈現
那么,這種動態拼接場景要怎么解決?
注意:各種推崇的國際化的自動化插件或腳本,局限之一就是無法解決這類動態拼接的場景,基本都只能人為處理
如果每個中文詞條片段都各自獨立包裹翻譯函數,如 this.$t("確認是否要刪除【") + item.name + this.$t("】嗎?"),這樣翻譯出來很容易會翻譯錯誤,而這種解法又基本都是自動化工具腳本的解法,因為腳本無法區分一句話是否結束了
這種場景目前我能想到的就是人為去處理,有經驗了之后,或許編寫代碼就會下意識的避免寫出這種代碼
人為的處理就是利用翻譯函數的占位符替換功能,給翻譯函數動態傳參方式,如:
<div>{{ $t("本次批量操作{0}條,其中,成功{1}條,失敗{2}條", [total, success, error]) }}</div>this.$confirm(this.$t("確認是否要刪除【{0}】嗎?", [item.name]));
所以,動態拼接詞條的場景,處理不難,但工作量大,基本沒法靠自動化腳本完成
痛點:詞條非得標紅加粗關鍵字顯示
關鍵詞高亮這種場景其實跟動態拼接詞條場景類似,一句完整詞條被其他東西*拆分成多個片段組成。
常見的場景就是搜索結果里對關鍵詞高亮處理,如百度的搜索結果:
實現方式上,無非就是把需要標紅加粗高亮的關鍵詞用其他標簽包裹起來,單獨設置樣式,如:
<div>這句話里<span style="color: red">我</span>要標紅顯示</div>
注意:跟動態拼接詞條相同,這種關鍵詞高亮場景也是自動化插件或腳本的局限之一,需要靠人為處理
至于解決方案,其實有兩種,一種是直接把帶有 html 標簽代碼的一整句話當作詞條,丟給翻譯組去翻譯,但需要跟人家解釋說明清楚,畢竟她們不懂代碼
另一種是參考動態拼接詞條的解法和 v-html 來解決,因為要讓 span 標簽被正確當前 html 代碼解析而不是字符串顯示,如
<div v-html="$t('這句話里{0}我{1}要標紅顯示', [`<span style='color: red'>`, '</span>'])"></div>
所以,關鍵詞加粗高亮的場景,處理起來更麻煩,能懟掉這需求就懟掉吧,實在不行,跟翻譯人員解釋下
幸好這種場景在項目里應該不多,比動態詞條拼接場景會少很多
痛點:后端接口返回的未翻譯詞條
理論上,前端的詞條前端翻譯,后端的詞條后端翻譯。接口返回的詞條理應由后端去翻譯就好了
遇到這種場景,能懟回去就懟回去吧
真的由于各種原因,后端就是改不了,非得前端來翻譯,那就專門準備一個 json 文件來維護后端沒翻譯的這類詞條場景吧
然后找到使用接口返回字段的地方,在呈現前,先用 $t 包裹翻譯處理下,主要是找代碼的工作量,其他都還好
痛點:中文做 key 值怎么辦
還是那句話,每個人的能力水平習慣不同,老項目經手 N 多人,什么牛鬼神蛇的代碼都有可能存在
用中文做 key 值也就不奇怪了,這里說幾種場景:
-
if (type === '其他') { // ... }- 用中文做判斷
-
const map = { 折線圖: 'line', 餅圖: 'pie' }- 用中文做對象的 key 值
用中文做判斷的話,如果確保國際化下 type 的賦值也能正確被翻譯的話,那其實應該還好,因為兩邊都翻譯了,只要翻譯是一樣的,那判斷邏輯還是能夠正常執行,但怕就怕翻譯不一致,或者 type 根本沒翻譯
畢竟你只有去確認過邏輯才能保證有沒有問題,那確認邏輯這個工作量就特別大了。或者也許可以這么處理:
-
if (this.$t(type) === this.$t('其他'))- 兩邊都翻譯了再進行判斷,可能某些場景下會出問題,比如誤翻譯
-
if (type === '其他' || type === this.$t('其他'))- 多加個判斷條件,這樣總有一個判斷能滿足,但也怕會誤傷,不過應該還好
至于用中文做對象 key 值的場景,就要去區分這個中文能不能被翻譯了,萬一不能被翻譯但卻給翻譯了,就會引起取數匹配不到,導致業務功能異常,如果可以翻譯,那么加個 [] 就能調用翻譯函數,如:
const map = { [this.$t('折線圖')]: 'line', [this.$t('餅圖')]: 'pie' }
所以,中文做 key 值,最大的問題就是要去梳理確認邏輯,到底這個中文能不能被翻譯處理,而且這種場景很難主動發現,因為不好找,通常發現時已經是被測出功能故障來了
不同技術棧項目的痛點
痛點:jQuery 老項目的國際化
vue 項目通常是用 vue-i18n 作為國際化方案基礎,那非 vue 項目呢,比如以前的 jQuery 項目呢?
不同項目都有各自的國際化框架,雖然框架不一樣,但本質上基本都是一樣的,無非就是翻譯函數和詞條文件
區別可能是翻譯函數名不一樣,詞條文件不一樣
比如 vue-i18n 是用 json 來維護詞條文件,而 jquery.i18n 是用 properties 來維護詞條文件
你可以不同項目直接用不同方案去實現、維護國際化,但這個可能對能力有些要求,有些新人可能轉不過來,因為出現過帶的一些新人平時不關注國際化底層實現原理,只會用,導致換了個不同技術棧的老項目就完全不知道怎么搞了,教了就忘
針對這種場景,我們實踐出來的解決方案就是開發個抹平不同框架的自動化 node 腳本,雖然框架不同,但大家都是基于 node
當然,對于一些老項目,還需要擴展下原國際化框架的能力,盡可能讓它在使用、維護上跟其他框架保持一致
比如擴展下 jquery.i18n 框架能力,讓它也支持用 json 文件來維護詞條文件
自動化腳本我會再寫篇文章介紹,本篇主要是講痛點和解決方案思路
樣式相關工作的痛點
痛點:相互影響,修復完中文樣式、英文出異常
樣式的工作經常是會被遺漏掉的工作項,不同語言的對齊、寬度、間距、換行等是有可能需要不同的處理的,尤其是在表單的 label 寬度上,通常需要單獨設置
而且樣式的處理上,影響點其實很大的,很容易不經意間就相互影響了
而測試又默認不影響,所以可能會導致測試沒覆蓋到而引發生產口碑問題了
比如你改了一個英文樣式問題,但卻影響到了中文時的呈現,但測試關 BUG 時又只驗證了英文的,這就容易出問題了
純 css 代碼樣式問題修復就還好,加個作用域,再配合語言切換時往 body 上掛個屬性上去,就能限制影響范圍,如:
.input {
width: "220px";
work-break: break-all;
// 加個作用域,限制生效范圍,非 en 語言下就不生效。
[lang="en"] & {
width: "300px";
work-break: break-word;
}
}
但如果是模板代碼或者 js 代碼里,就需要使用到判斷邏輯來分場景處理了,這里建議是用對象取值方式替換掉三元運算符,這樣方便后續再擴展其他語言,如:
<template>
<!-- 推薦 -->
<el-form :label-width="{ en: '150px' }[lang] || '80px'"></el-form>
<!-- 不推薦 -->
<!-- <el-form :label-width="lang === 'en' ? '150px' : '80px'"></el-form> -->
</template>
所以,樣式工作主要是影響點,注意宣講到位,測試到位,避免將問題遺漏到生產上
三方庫相關工作的痛點
項目里通常會使用到一些三方的基礎組件庫,國際化就需要按照對應組件庫的國際化方案來進行相對應配置
這個難度不大,主要問題也是容易被遺漏
痛點:三方庫不支持國際化怎么辦
但如果項目里使用到了不支持國際化的三方庫,這時候,沒辦法了
只能是魔改源碼,改造成直接引入 js 的方式替換掉 package.json 里的依賴構建模式了
圖片、文件相關工作
這個場景也是經常容易被遺漏的工作項,有時甚至都不知道原來國際化還要處理圖片、文件這類場景
經歷多了后,以后在評審高保設計圖時,就盡量讓設計人員不要設計帶中文文案的圖片了,如果非要帶,就連同其他語言的圖片一起出了,省得后期找不到人出圖
至于文件場景,現在基本都是后端維護,交給后端去處理就行
有些老項目是把文件放前端資源里直接下載的,注意下也有這種場景就像
維護相關工作的痛點
除了開發階段有一堆痛點外,其實后續的迭代維護,也是一個大痛點
痛點:經常有遺漏的未翻譯詞條
當你的項目已經完成了國際化了,然后又經歷了一次新的需求迭代開發,有多個人一起參與,新增了很多功能,也在原有功能上做了很多改動。
好,問題來了。
你如何確保你們這么多人在這次迭代的改動里,新增或修改的代碼里的詞條都進行了國際化處理呢?
相互 review? 自測一輪?
這也是種解決方案,但需要投入資源成本,而且本身這次迭代開發里除了正常需求開發工作量外,也需要投入國際化處理的工作量
注:國際化事項就是文章開頭列出的事項,每次迭代基本都需要處理
最完美的解決方案應該是自動化腳本,讓腳本來解決這種問題,下篇會介紹下團隊大佬開發的自動化腳本
痛點:如何在 json 里增量式撈取未翻譯的詞條
跟上一個痛點是一樣的背景,在一次迭代里新增或修改的代碼里多少會引入、修改、刪除中文詞條,那么如果增量式的更新到 json 文件中去呢?
靠人工手動去更新,工作量大,而不靠譜穩定
而且,我們詞條翻譯不是通過機翻,而是需求把詞條撈出來提供給翻譯團隊進行翻譯
那我怎么在上萬條詞條里面,把那些未翻譯的撈出來呢?
一條條過嗎,太不現實了,還不如在迭代開發寫代碼過程中就一條條記錄下來
但仍舊是需要耗費大量工作,而且一旦這個步驟忘記,后續再想手工撈取工作量只會更大
而且就算你是機翻,難道每次都把所有詞條,包括已經翻譯好的詞條都丟給機器嗎,嫌錢不夠花嘛
最完美的解決方案還是自動化腳本,一切重復、耗時的工作都可以讓腳本來替代
痛點:如何把翻譯好的詞條更新回 json 文件里
還是跟上一個痛點是一樣的背景,當從翻譯組拿到了這次迭代里那些詞條的翻譯后,怎么更新回 json 文件里呢
尤其跟翻譯組的往來文件有可能是 excel 文件,并不是 json 文件
所以,完美的解決方案還是自動化腳本,腳本去解析 excel,然后回填到 json 文件里,工作效率提升百分百,一鍵式就搞定
痛點:json 越來越龐大,甚至導致編譯時撐爆內存
項目只會越來越大,如果把整個項目的翻譯詞條都放到一個 json 文件里維護,那這份 json 文件只會越來越大,萬級別,甚至百萬千萬級別,那到時就非常考研設備性能,開發維護都是個問題,因為我們已經遇到過一些老項目上構建時直接撐爆了內存,導致構建失敗,都沒辦法進行熱更新開發調試了
所以,json 還是要按模塊,拆分成多份維護
而這個工作,仍舊可以交給自動化腳本來處理
痛點:多人多分支時,合并時的大量沖突
這也是國際化項目容易出現的問題,不同分支如果都進行了國際化,就會導致基本每個文件每行代碼都發生變更,如果兩個分支并行了,那合并時就會是個災難
我今年經過過 N 次這種場景,領導根本不關注是不是國際化,只關注說幾個月前某個分支不是已經國際化做完了,現在合并到 xx 分支上就好了,為什么還需要這么多天的工作量
但其實這個合并工作量巨大,而且風險很大,因為是人為一個個解決沖突,代碼還不是就一個人開發,但合并就一個人合并
至于解決方案,懟吧,這種分支管理不合理
要國際化就盡量不要并行
要么就是分支就只單純國際化,不要做其他需求開發了,這樣借助腳本,還能直接在新分支上跑下腳本,然后同步下樣式或者動態詞條處理這些場景的代碼變更就行
總之,這個場景沒有想到好的解決方案,只能從管理上,從規范流程上盡量去避免
痛點:翻譯函數的 key 值如果不是中文詞條,維護代碼成本可能會增大
有些國際化方案里會單獨為每個詞條定義一個 code,然后代碼里是使用這個 code,而非中文詞條,在根據不同翻譯文件對每個 code 進行翻譯
element-ui 組件庫的國際化就是這種方案,它提供了一份內部所有詞條的 code,然后我們根據需要,傳入不同 code 語言的翻譯文件就行
這種方案不是說有問題,而是其實不適用到每個項目里,組件庫這種是比較穩定不怎么變更的項目,而且沒有業務性質的項目,可以使用這種方案
但在真實的業務項目里,如果把每個業務頁面里的中文詞條都換成一個唯一的 code 值,這其實是非常降低閱讀性的
而且你想想,一個項目上百個頁面,上千個代碼文件,我不可能對每個代碼文件都很熟悉,很多時候的迭代開發或者故障排查,都是基于特定頁面開始在項目里找代碼,因為我也不知道在哪里
那通常都是根據界面上的中文詞條或者路由等信息找到代碼文件后,開始梳理邏輯
中文作為我們的母語,自然是直接看到夾帶著中文的代碼會更容易閱讀和理解,如果是 code 的話,還得特意去轉換一遍
效率非常低下
至少我們有個老項目就是用 code 這種方式,導致我們閱讀、維護都非常費勁
而且,都是 code 的話,也非常不利于自動化腳本的工作,因為自動化腳本需要根據一定的規則來撈取詞條,本來中文就是最好撈取規則了,現在整成 code,還得定義系列規范跟代碼含義區分開
綜上,我們團隊一致建議翻譯詞條就直接用中文做 key 值,就像文章開頭給出的實例代碼
最后
網上好多關于國際化的文章不是介紹類似 vue-i18n 框架的使用,就是推崇下一些自動化工具腳本
但當經歷過國際化工作后,尤其是一些老項目,才發現,國際化工作里,除了詞條相關工作外,還有其他很多方面的工作項
而且就算是詞條工作,也存在各自各樣的場景要處理,坑很多,痛點也很多
不是一個自動化腳本就能完全搞定的,腳本只能幫忙把重復、低效的手工工作替換掉,但腳本沒法完成的仍舊需要我們自行去完成
所以本篇才想匯總來聊一聊國際化工作中,我所遇到的各種痛點
但是啊,自動化腳本還是不能少的哈,它至少能提效 50% 以上的效率
曾經它幫我把兩周的工作量直接節省到 1 天內搞定
所以,下篇就想來聊一聊國際化的自動化腳本
總結
以上是生活随笔為你收集整理的项目国际化的难点痛点是什么的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Volcano 原理、源码分析(二)
- 下一篇: B612咔叽怎么开启镜像模式