详解基于webpack&gettext的前端多语言方案

gettext 是GNU 提供的一套 国际化与本地化 处理的相关函数库。大多数语言都有对应的gettext实现。本文主要使用jed 来实现gettext 一系列方法对应的功能。

pot/po文件

pot文件 是po文件的模板文件,一般是通过 xgettext 程序生成出来的。

po文件 是根据pot文件通过msginit程序,设置对应的国家语言生成用于填写实际翻译内容的文件。

xgettext/msginit/msgmerge

xgettext 程序可以扫描指定的代码文件,取出其中gettext部分的内容生成对应的pot文件。

msginit 根据对应的pot文件生成对应语言版本用于实际翻译的po文件。

msgmerge 如果对应语言版本的po文件存在的话,则需要使用msgmerge方式把pot文件中新加入的一些msgid合并到po文件当中。

多语言支持流程

安装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规则:

{ test: /\.pot$/i, use: [ "json", { loader: 'langs', options: {isLoadAll: isDev,format:"jed1.x", "fallback-to-msgid":true, code:langCode} } ] }

isLoadAll

isLoadAll表示会把所有语言版本的文件通过po2json转换成json,然后组合成一个json作为数据传给引用的地方。

code

code选项一般需要在代码发布时指定,不同语言版本打包时通过传入不同的code区分不同语言版本的代码打包。

代码中使用gettext系列函数

各端开发时使用各自实现的gettext方法去包装需要实现多语言的文案。使用gettext函数包装后, langs-util 就能知道代码中有需要多语言翻译的地方,并可以通过 langs-util 生成相关的pot及po文件。gettext方法底层我们使用jed 来实现其对应功能。

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

可以用于单复数处理,第一个参数传入单数情况下的翻译,第二个参数传入复数情况下的翻译,第三个传入实际需要执行判断的数据。

sprintf

Jed内置提供了sprintf的支持,它是使用的sprintf函数的实现。

通过gettext 一系列函数的配合,使用 langs-util 进行生成处理后就能生成对应的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] ""

把生成的文件交由对应的翻译人员完成翻译就可以重新放回到文件夹当中替换目标po文件。

打包&发布

各端打包方式都会有相应的差异,最终目的无非就是使线上代码可以按照不同语言的版本加载不同的语言文件。对于 后台 等系统则可以使用isLoadAll的方式把所有语言版本的文件都加载进来,通过i18n的包装函数去从数据源中拿出不同国家的多语言数据文件。

cross-env LANG_CODE=th

移动端发布使用环境变量 LANG_CODE 来区分要编译成的语言版本。

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} } ] }

生成完所有语言语言版本的静态文件后,需要让浏览器能够运行不同语言版本的js文件。一种方式可以通过后台程序读出语言版本,再把正确语言版本的js路径输出到html当中。另外一种方式可以新建一个多语言loader的文件,通过前端js代码动态插入正确语言版本的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 实现

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/31ea482f14f647eaf1618095a967cb24.html