小編給大家分享一下基于webpack和gettext前端多語言的示例分析,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!
公司主營業(yè)務(wù):成都網(wǎng)站建設(shè)、網(wǎng)站建設(shè)、移動網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競爭能力。成都創(chuàng)新互聯(lián)公司是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊有機(jī)會用頭腦與智慧不斷的給客戶帶來驚喜。成都創(chuàng)新互聯(lián)公司推出東寧免費(fèi)做網(wǎng)站回饋大家。
gettext 是GNU 提供的一套 國際化與本地化 處理的相關(guān)函數(shù)庫。大多數(shù)語言都有對應(yīng)的gettext實(shí)現(xiàn)。本文主要使用jed 來實(shí)現(xiàn)gettext 一系列方法對應(yīng)的功能。
pot/po文件
pot文件 是po文件的模板文件,一般是通過 xgettext 程序生成出來的。
po文件 是根據(jù)pot文件通過msginit程序,設(shè)置對應(yīng)的國家語言生成用于填寫實(shí)際翻譯內(nèi)容的文件。
xgettext/msginit/msgmerge
xgettext 程序可以掃描指定的代碼文件,取出其中g(shù)ettext部分的內(nèi)容生成對應(yīng)的pot文件。
msginit 根據(jù)對應(yīng)的pot文件生成對應(yīng)語言版本用于實(shí)際翻譯的po文件。
msgmerge 如果對應(yīng)語言版本的po文件存在的話,則需要使用msgmerge方式把pot文件中新加入的一些msgid合并到po文件當(dāng)中。
多語言支持流程
安裝gettext
brew install gettext brew link gettext
langs-loader 加載語言文件
安裝
npm install git@github.com:ezbuy/langs-loader.git --save-dev
配置
需要修改webpack.config.js文件在module->rules(webpack 2.0)下面添加loader規(guī)則:
{ test: /\.pot$/i, use: [ "json", { loader: 'langs', options: {isLoadAll: isDev,format:"jed1.x", "fallback-to-msgid":true, code:langCode} } ] }
isLoadAll
isLoadAll表示會把所有語言版本的文件通過po2json轉(zhuǎn)換成json,然后組合成一個json作為數(shù)據(jù)傳給引用的地方。
code
code選項一般需要在代碼發(fā)布時指定,不同語言版本打包時通過傳入不同的code區(qū)分不同語言版本的代碼打包。
代碼中使用gettext系列函數(shù)
各端開發(fā)時使用各自實(shí)現(xiàn)的gettext方法去包裝需要實(shí)現(xiàn)多語言的文案。使用gettext函數(shù)包裝后, langs-util 就能知道代碼中有需要多語言翻譯的地方,并可以通過 langs-util 生成相關(guān)的pot及po文件。gettext方法底層我們使用jed 來實(shí)現(xiàn)其對應(yīng)功能。
import toi18n from "common/i18n"; const _ = toi18n(require("langs/index.pot")); const hiStr = _.gettext("Hi!"); const num = Math.ceil(Math.random() * 2); const numStr = _.ngettext("item", "items", num); // I like your red shirt. console.log(_.sprintf( "I like your %1$s %2$s.", 'red', 'shirt'));
gettext
一般使用 gettext 方法包裝一個需要翻譯的字符串。
ngettext
可以用于單復(fù)數(shù)處理,第一個參數(shù)傳入單數(shù)情況下的翻譯,第二個參數(shù)傳入復(fù)數(shù)情況下的翻譯,第三個傳入實(shí)際需要執(zhí)行判斷的數(shù)據(jù)。
sprintf
Jed內(nèi)置提供了sprintf的支持,它是使用javascript-sprintf的sprintf函數(shù)的實(shí)現(xiàn)。
通過gettext 一系列函數(shù)的配合,使用 langs-util 進(jìn)行生成處理后就能生成對應(yīng)的pot及po文件。
langs-util gen -i src/
# langs/index.pot msgid "Hi!" msgstr "" msgid "item" msgid_plural "items" msgstr[0] "" msgstr[1] ""
# langs/index.th.po msgid "Hi" msgstr "" msgid "item" msgid_plural "items" msgstr[0] "" msgstr[1] ""
把生成的文件交由對應(yīng)的翻譯人員完成翻譯就可以重新放回到文件夾當(dāng)中替換目標(biāo)po文件。
打包&發(fā)布
各端打包方式都會有相應(yīng)的差異,最終目的無非就是使線上代碼可以按照不同語言的版本加載不同的語言文件。對于 后臺 等系統(tǒng)則可以使用isLoadAll的方式把所有語言版本的文件都加載進(jìn)來,通過i18n的包裝函數(shù)去從數(shù)據(jù)源中拿出不同國家的多語言數(shù)據(jù)文件。
cross-env LANG_CODE=th
移動端發(fā)布使用環(huán)境變量 LANG_CODE 來區(qū)分要編譯成的語言版本。
const langCode = process.env.LANG_CODE { test: /\.pot$/i, use: [ "json", { loader: 'langs', options: {isLoadAll: isDev,format:"jed1.x", "fallback-to-msgid":true, code:langCode} } ] }
生成完所有語言語言版本的靜態(tài)文件后,需要讓瀏覽器能夠運(yùn)行不同語言版本的js文件。一種方式可以通過后臺程序讀出語言版本,再把正確語言版本的js路徑輸出到html當(dāng)中。另外一種方式可以新建一個多語言loader的文件,通過前端js代碼動態(tài)插入正確語言版本的js代碼(文件打包的時候需要把各語言版本的js文件路徑輸出到頁面之中)。
import {languageCode} from "common/constant"; const loadScript = (path: string) => { const script = window.document.createElement("script"); script.setAttribute("src", path); window.document.body.appendChild(script); return new Promise((resolve, reject) => { script.onload = resolve; script.onerror = reject; }); }; const {mainFilePath} = window; if (typeof mainFilePath === "string") { loadScript(mainFilePath); }else if (typeof mainFilePath !== "string") { loadScript(mainFilePath[languageCode] ); }
langs-loader 實(shí)現(xiàn)
在loader代碼中拿到require文件的實(shí)際路徑,如果存在code選項的話則根據(jù)pot文件找到對應(yīng)code的po文件,然后使用po2json轉(zhuǎn)換為對應(yīng)格式的json文件,最后再返回給引用的地方。如果存在isLoadAll選項并且isLoadAll選項為true的話,則會load 同名pot文件的所有對應(yīng)語言版本的po文件,然后再通過po2json轉(zhuǎn)換組合成一個json文件,再返回出去。
langs-util 實(shí)現(xiàn)
langs-util主要整合了xgettext/msginit/msgmerge等方法。傳入所需要解析的文件或文件夾,生成對應(yīng)的po及pot文件。
const genPoFiles = (inputFilePaths: string | string[], potFilePath: string, langs: string[]) => { const potDirName = dirname(potFilePath); const filename = basename(potFilePath, extname(potFilePath)); const filePaths = typeof inputFilePaths === "string" ? inputFilePaths : inputFilePaths.join(" "); execOnlyErrorOutput(`xgettext --language=JavaScript --add-comments --sort-output --from-code=UTF-8 --no-location --msgid-bugs-address=wanglin@ezbuy.com -o ${potFilePath} ${filePaths}`); checkFileExists(potFilePath).then((ifPotFileExists) => { if (ifPotFileExists) { console.log(green(potFilePath)); writeFileSync(potFilePath, readFileSync(potFilePath).toString().replace("charset=CHARSET", "charset=UTF-8")); langs.forEach((lang) => { const poFilePath = join(potDirName, `${filename}${lang === "" ? "" : `.${lang}` }.po`); checkFileExists(poFilePath).then((ifExists) => { if (ifExists) { execOnlyErrorOutput(`msgmerge --output-file=${poFilePath} ${poFilePath} ${potFilePath}`); }else { execOnlyErrorOutput(`msginit --no-translator --input=${potFilePath} --locale=${lang} --output=${poFilePath}`); } }); }); } }); };
生成po文件時,需要傳入需要給xgettext解析的文件列表以及目標(biāo)pot文件路徑還有生成的多語言版本種類。xgettext會根據(jù)傳入的解析文件生成新的pot文件,如果生成成功則開始生成對應(yīng)語言版本的po文件,如果對應(yīng)的po文件存在則使用msgmerge更新po文件,如果不存在則使用msginit創(chuàng)建新的po文件。
看完了這篇文章,相信你對“基于webpack和gettext前端多語言的示例分析”有了一定的了解,如果想了解更多相關(guān)知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!