摘要:前端通用國際化解決方案背景前端技術日新月異,技術棧繁多。接下來針對這幾塊內容并結合日常的開發流程說明國際化的通用解決方案。
文章首發于個人blog,歡迎大家關注。
DI18n前端通用國際化解決方案
背景前端技術日新月異,技術棧繁多。以前端框架來說有React, Vue, Angular等等,再配以webpack, gulp, Browserify, fis等等構建工具去滿足日常的開發工作。同時在日常的工作當中,不同的項目使用的技術棧也會不一樣。當需要對部分項目進行國際化改造時,由于技術棧的差異,這時你需要去尋找和當前項目使用的技術棧相匹配的國際化的插件工具。比如:
vue + vue-i18n
angular + angular-translate
react + react-intl
jquery + jquery.i18n.property
等等,同時可能有些頁面沒有使用框架,或者完全是沒有進行工程化的靜態前端頁面。
為了減少由于不同技術棧所帶來的學習相關國際化插件的成本及開發過程中可能遇到的國際化坑,在嘗試著分析前端國際化所面臨的主要問題及相關的解決方案后,我覺得是可以使用更加通用的技術方案去完成國際化的工作。
國際化所面臨的問題1.語言翻譯
靜態文案翻譯(前端靜態模板文案)
動態文案翻譯(server端下發的動態數據)
2.樣式
不同語言文案長度不一樣造成的樣式錯亂
圖片的替換
3.map表維護
4.第三方服務
SDK
5.本地化
貨幣單位
貨幣匯率
時間格式
6.打包方案
運行時
編譯后
解決方案在日常的開發過程當中,遇到的最多的需要國際化的場景是:語言翻譯,樣式,map表維護及打包方案。接下來針對這幾塊內容并結合日常的開發流程說明國際化的通用解決方案。
首先來看下當前開發環境可能用的技術棧:
1.使用了構建工具
webpack
gulp
fis
browserify
...
基于這些構建工具,使用:
Vue
Angular
React
Backbone
...
未使用任何framework
2.未使用構建工具
使用了jquery或zepto等類庫
原生js
其中在第一種開發流程當中,可用的國際化的工具可選方案較多:
從框架層面來看,各大框架都會有相對應的國際化插件,例如:vue-i18n, angular-translate, react-intl等,這些插件可以無縫接入當前的開發環節當中。優點是這些框架層面的國際化插件使用靈活,可以進行靜態文案的翻譯,動態文案的翻譯。缺點就是開發過程中使用不同的框架還需要去學習相對應的插件,存在一定的學習成本,同時在業務代碼中可能存在不同語言包判斷邏輯。
從構建工具層面來看, webpack有相對應的i18n-webpack-plugin, gulp有gulp-static-i18n等相應的插件。這些插件的套路一般都是在你自定義map語言映射表,同時根據插件定義好的需要被編譯的代碼格式,然后在代碼的編譯階段,通過字符串匹配的形式去完成靜態文案的替換工作。這些插件僅僅解決了靜態文案的問題,比如一些樣式,圖片替換,class屬性,以及動態文案的翻譯等工作并沒有做。
事實上,這些插件在編譯過程中對于樣式,圖片替換, class屬性等替換工作是非常容易完成的,而動態文案的翻譯因為缺少context,所以不會選擇使用這些編譯插件去完成動態文案的翻譯工作。相反,將動態文案的翻譯放到運行時去完成應該是更加靠譜的。
但是換個角度,拋開基于這些構建工具進行開發的框架來說,構建工具層面的國際化插件可以很好的抹平使用不同框架的差異,通過將國際化的過程從運行時轉到編譯時,在編譯的過程中就完成大部分的國際化任務,降低學習相對應國際化插件的成本,同時在構建打包環節可實現定制化。不過也存在一定的缺點,就是這些構建工具層面的國際化插件只能完成一些基本的靜態文案的翻譯,因為缺少context,并不能很好的去完成動態文案的翻譯工作,它比較適用于一些純靜態,偏展示性的網頁。
在第二種開發流程當中,可使用的國際化工具較少,大多都會搭配jquery這些類庫及相對應的jquery.i18n或i18next等插件去完成國際化。
綜合不同的構建工具,開發框架及類庫,針對不同的開發環境似乎是可以找到一個比較通用的國際化的方案的。
這個方案的大致思路就是:通過構建工具去完成樣式, 圖片替換, class屬性等的替換工作,在業務代碼中不會出現過多的因國際化而多出的變量名,同時使用一個通用的翻譯函數去完成靜態文案及動態文案的翻譯工作,而不用使用不同框架提供的相應的國際化插件。簡單點來說就是:
依據你使用的構建工具 + 一個通用的翻譯函數去完成前端國際化
首先,這個通用的語言翻譯函數: di18n-translate。它所提供的功能就是靜態和動態文案的翻譯, 不依賴開發框架及構建工具。
npm install di18n-translate
// 模塊化寫法 const LOCALE = "en" const DI18n = require("di18n-translate") const di18n = new DI18n({ locale: LOCALE, // 語言環境 isReplace: false, // 是否開始運行時(適用于沒有使用任何構建工具開發流程) messages: { // 語言映射表 en: { 你好: "Hello, {person}" }, zh: { 你好: "你好, {person}" } } }) di18n繼承于一個翻譯類,提供了2個方法`$t`, `$html`: di18n.$t("你好", {person: "xl"}) // 輸出: Hello, xl di18n.$html(htmlTemp) // 傳入字符串拼接的dom, 返回匹配后的字符串,具體示例可見下文 // 外鏈形式
這個時候你只需要將這個通用的翻譯函數以適當的方式集成到你的開發框架當中去。
接下來會結合具體的不同場景去說明下相應的解決方案:
使用MVVM類的framework使用了MVVM類的framework時,可以借助framework幫你完成view層的渲染工作, 那么你可以在代碼當中輕松的通過代碼去控制class的內容, 以及不同語言環境下的圖片替換工作.
例如vue, 示例(1):
main.js文件: window.LOCALE = "en"
app.vue文件: // imgSrc去控制圖片路徑
這個時候你再加入翻譯函數,就可以滿足大部分的國際化的場景了,現在在main.js中添加對翻譯函數di18n-translate的引用:
main.js文件: import Vue from "vue" window.LOCALE = "en" const DI18n = require("di18n-translate") const di18n = new DI18n({ locale: LOCALE, // 語言環境 isReplace: false, // 是否進行替換(適用于沒有使用任何構建工具開發流程) messages: { // 語言映射表 en: { 你好: "Hello, {person}" }, zh: { 你好: "你好, {person}" } } }) Vue.prototype.d18n = di18n
翻譯函數的基本使用, 當然你還可以使用其他的方式集成到你的開發環境當中去:
app.vue文件: // imgSrc去控制圖片路徑{{title}}
使用mvvm framework進行國際化,上述方式應該是較為合適的,主要是借助了framework幫你完成view層的渲染工作, 然后再引入一個翻譯函數去完成一些動態文案的翻譯工作
這種國際化的方式算是運行時處理,不管是開發還是最終上線都只需要一份代碼。
當然在使用mvvm framework的情況下也是可以不借助framework幫我們完成的view層的這部分的功能,而通過構建工具去完成, 這部分的套路可以參見下午的示例3
未使用mvvm框架,使用了構建工具(如webpack/gulp/browserify/fis) 使用了前端模板國際化的方式和上面說的使用mvvm框架的方式一致,因為有模板引擎幫你完成了view層的渲染.所以對于樣式,圖片,class屬性的處理可以和上述方式一致, 動態文案的翻譯需引入翻譯函數。
這種國際化的方式也算是運行時處理,開發和最終上線都只需要一份代碼。
沒有使用前端模板因為沒用使用前端模板,便少了對于view層的處理。這個時候你的DOM結構可能是在html文件中一開始就定義好的了,也可能是借助于webpack這樣能允許你使用模塊化進行開發,通過js動態插入DOM的方式。
接下來我們先說說沒有借助webpack這樣允許你進行模塊化開發的構建工具,DOM結構直接是在html文件中寫死的項目。這種情況下你失去了對view層渲染能力。那么這種情況下有2種方式去處理這種情況。
第一種方式就是可以在你自己的代碼中添加運行時的代碼。大致的思路就是在DOM層面添加屬性,這些屬性及你需要翻譯的map表所對應的key值:
示例(2):
html文件:
運行時:
最后html會轉化為:
Hello
第二種方式就是借助于構建工具在代碼編譯的環節就完成國際化的工作,以webpack為例:
示例(3):
html文件:
$t("你好")
這個時候使用了一個webpack的preloader: locale-path-loader,它的作用就是在編譯編譯前,就通過webpack完成語言環境的配置工作,在你的業務代碼中不會出現過多的關于語言環境變量以及很好的解決了運行時作為css的background的圖片替換工作, 具體的locale-path-loader的文檔請戳我
使用方法:
npm install locale-path-loader
webpack 1.x 配置:
module.exports = { .... preLoaders: [ { test: /.*$/, exclude: /node_modules/, loaders: [ "eslint", "locale-path?outputDir=./src/common&locale=en&inline=true" ] } ] .... }
webpack 2 配置:
module.exports = { .... module: { rules: [{ test: /.*$/, enforce: "pre", exclude: /node_modules/, use: [{ loader: "locale-path-loader", options: { locale: "en", outputDir: "./src/common", inline: true } }] }] } .... }
經過webpack的preloader處理后,被插入到頁面中的DOM最后成為:
Hello
但是使用這種方案需要在最后的打包環節做下處理,因為通過preloader的處理,頁面已經被翻譯成相對應的語言版本了,所以需要通過構建工具以及改變preloader的參數去輸出不同的語言版本文件。當然構建工具不止webpack這一種,不過這種方式處理的思路是一致的。
這種方式屬于編譯時處理,開發時只需要維護一份代碼,但是最后輸出的時候會輸出不同語言包的代碼。當然這個方案還需要服務端的支持,根據不同語言環境請求,返回相對應的入口文件。關于這里使用webpack搭配locale-path-loader進行分包的內容可參見vue-demo:
|--deploy | | | |---en | | |--app.js | | |--vendor.js | | |--index.html | |---zh | | |--app.js | | |--vendor.js | | |--index.html | |---jp | | |--app.js | | |--vendor.js | | |--index.html | |----lang.json
接下來繼續說下借助構建工具進行模塊化開發的項目, 這些項目可能最后頁面上的DOM都是通過js去動態插入到頁面當中的。那么,很顯然,可以在DOM被插入到頁面前即可以完成靜態文案翻譯,樣式, 圖片替換, class屬性等替換的工作。
示例(4):
html文件:
$t("你好")
js文件:
let tpl = require("html!./index.html") let wrapper = document.querySelector(".box-wrapper") // di18n.$html方法即對你所加載的html字符串進行replace,最后相對應的語言版本 wrapper.innerHTML = di18n.$html(tpl)
最后插入到的頁面當中的DOM為:
Hello
這個時候動態翻譯再借助引入的di18n上的$t方法
di18n.$t("你好")
這種開發方式也屬于運行時處理,開發和上線后只需要維護一份代碼。
沒有使用任何framework及構建工具的純靜態,偏展示性的網頁這類網頁的國際化,可以用上面提到的通過在代碼中注入運行時來完成基本的國際化的工作, 具體內容可以參見示例(2)以及倉庫中的html-demo文件夾。
語言包map表的維護建議將語言包多帶帶新建文件維護,通過異步加載的方式去獲取語言包.
項目地址(如果覺得文章不錯,請不要吝嗇你的star~~)請戳我
最后需要感謝 @kenberkeley 同學,之前和他有過幾次關于國際化的探討,同時關于編譯時這塊的內容,他的有篇文章(請戳我)也給了我一些比較好的思路。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/82478.html
摘要:近期在做國際化的改造,做了相應的調研,簡單做下項目前端國際化的小結國際化可以分為前端國際化和后端國際化,也可以是前后端組合的國際化后端多為國際化,這里不做展開,百度一下到處都是常見型常見的前端國際化方法步驟如下原理定義國際化配置根據環境讀取 近期在做國際化的改造,做了相應的調研,簡單做下項目前端國際化的小結 國際化可以分為前端國際化和后端國際化,也可以是前后端組合的國際化后端多為spr...
摘要:近期在做國際化的改造,做了相應的調研,簡單做下項目前端國際化的小結國際化可以分為前端國際化和后端國際化,也可以是前后端組合的國際化后端多為國際化,這里不做展開,百度一下到處都是常見型常見的前端國際化方法步驟如下原理定義國際化配置根據環境讀取 近期在做國際化的改造,做了相應的調研,簡單做下項目前端國際化的小結 國際化可以分為前端國際化和后端國際化,也可以是前后端組合的國際化后端多為spr...
摘要:網頁可訪問性似乎是一項艱巨的任務,但它確實比聽起來要容易很多,這十條網頁可訪問性準則旨在確保所有網站都是通用的。 推薦 1. 阿里電商架構演變之路 https://yq.aliyun.com/article... 首屆阿里巴巴中間件技術峰會上,阿里巴巴中間件技術部專家唐三帶來阿里電商架構演變之路的演講,本文從阿里業務和技術架構開始引入,分別分享了阿里電商從1.0到4.0架構的演變之路,...
摘要:精讀前端可以從多個角度理解,比如規范框架語言社區場景以及整條研發鏈路。同是前端未來展望,不同的文章側重的格局不同,兩個標題相同的文章內容可能大相徑庭。作為使用者,現在和未來的主流可能都是微軟系,畢竟微軟在操作系統方面人才儲備和經驗積累很多。 1. 引言 前端展望的文章越來越不好寫了,隨著前端發展的深入,需要擁有非常寬廣的視野與格局才能看清前端的未來。 筆者根據自身經驗,結合下面幾篇文章...
閱讀 1518·2023-04-25 17:41
閱讀 3040·2021-11-22 15:08
閱讀 842·2021-09-29 09:35
閱讀 1604·2021-09-27 13:35
閱讀 3322·2021-08-31 09:44
閱讀 2715·2019-08-30 13:20
閱讀 1937·2019-08-30 13:00
閱讀 2556·2019-08-26 12:12