国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

詳解基于webpack&gettext的前端多語言方案

2019-11-19 12:11:54
字體:
來源:轉載
供稿:網(wǎng)友

gettext 是GNU 提供的一套 國際化與本地化 處理的相關函數(shù)庫。大多數(shù)語言都有對應的gettext實現(xiàn)。本文主要使用jed 來實現(xiàn)gettext 一系列方法對應的功能。

pot/po文件

  • pot文件 是po文件的模板文件,一般是通過 xgettext 程序生成出來的。
  • po文件 是根據(jù)pot文件通過msginit程序,設置對應的國家語言生成用于填寫實際翻譯內(nèi)容的文件。

xgettext/msginit/msgmerge

  • xgettext 程序可以掃描指定的代碼文件,取出其中gettext部分的內(nèi)容生成對應的pot文件。
  • msginit 根據(jù)對應的pot文件生成對應語言版本用于實際翻譯的po文件。
  • msgmerge 如果對應語言版本的po文件存在的話,則需要使用msgmerge方式把pot文件中新加入的一些msgid合并到po文件當中。

多語言支持流程

安裝gettext

brew install gettextbrew 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轉換成json,然后組合成一個json作為數(shù)據(jù)傳給引用的地方。

  • code

code選項一般需要在代碼發(fā)布時指定,不同語言版本打包時通過傳入不同的code區(qū)分不同語言版本的代碼打包。

代碼中使用gettext系列函數(shù)

各端開發(fā)時使用各自實現(xiàn)的gettext方法去包裝需要實現(xiàn)多語言的文案。使用gettext函數(shù)包裝后, langs-util 就能知道代碼中有需要多語言翻譯的地方,并可以通過 langs-util 生成相關的pot及po文件。gettext方法底層我們使用jed 來實現(xiàn)其對應功能。

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

可以用于單復數(shù)處理,第一個參數(shù)傳入單數(shù)情況下的翻譯,第二個參數(shù)傳入復數(shù)情況下的翻譯,第三個傳入實際需要執(zhí)行判斷的數(shù)據(jù)。

  • sprintf

Jed內(nèi)置提供了sprintf的支持,它是使用javascript-sprintf的sprintf函數(shù)的實現(xiàn)。

通過gettext 一系列函數(shù)的配合,使用 langs-util 進行生成處理后就能生成對應的pot及po文件。

langs-util gen -i src/
# langs/index.potmsgid "Hi!"msgstr ""msgid "item"msgid_plural "items"msgstr[0] ""msgstr[1] ""
# langs/index.th.pomsgid "Hi"msgstr ""msgid "item"msgid_plural "items"msgstr[0] ""msgstr[1] ""

把生成的文件交由對應的翻譯人員完成翻譯就可以重新放回到文件夾當中替換目標po文件。

打包&發(fā)布

各端打包方式都會有相應的差異,最終目的無非就是使線上代碼可以按照不同語言的版本加載不同的語言文件。對于 后臺 等系統(tǒng)則可以使用isLoadAll的方式把所有語言版本的文件都加載進來,通過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)文件后,需要讓瀏覽器能夠運行不同語言版本的js文件。一種方式可以通過后臺程序讀出語言版本,再把正確語言版本的js路徑輸出到html當中。另外一種方式可以新建一個多語言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 實現(xiàn)

在loader代碼中拿到require文件的實際路徑,如果存在code選項的話則根據(jù)pot文件找到對應code的po文件,然后使用po2json轉換為對應格式的json文件,最后再返回給引用的地方。如果存在isLoadAll選項并且isLoadAll選項為true的話,則會load 同名pot文件的所有對應語言版本的po文件,然后再通過po2json轉換組合成一個json文件,再返回出去。

langs-util 實現(xiàn)

langs-util主要整合了xgettext/msginit/msgmerge等方法。傳入所需要解析的文件或文件夾,生成對應的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解析的文件列表以及目標pot文件路徑還有生成的多語言版本種類。xgettext會根據(jù)傳入的解析文件生成新的pot文件,如果生成成功則開始生成對應語言版本的po文件,如果對應的po文件存在則使用msgmerge更新po文件,如果不存在則使用msginit創(chuàng)建新的po文件。

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持武林網(wǎng)。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 岳池县| 台东县| 五原县| 文昌市| 土默特右旗| 邵东县| 察隅县| 绵竹市| 通州市| 卫辉市| 巴林右旗| 古田县| 灌云县| 玉环县| 香河县| 马公市| 肥乡县| 会理县| 华宁县| 罗山县| 济源市| 福安市| 遵义市| 洛隆县| 沾化县| 长阳| 杨浦区| 正镶白旗| 儋州市| 河北区| 伊金霍洛旗| 麻栗坡县| 泊头市| 武功县| 林州市| 黄陵县| 大名县| 西青区| 广丰县| 延长县| 齐河县|