i18n 国际化支持
此功能分为两部分,middleware 层面的支持和模板引擎层面的支持,基于 i18next 实现。
配置
应用配置:
i18n: {
enable: true, // default false,
forceLng: undefined, // default undefined, will always use this language if set.
defaultLng: 'zh-CN', // default zh-CN, the default and fallback language
cookieKey: 'lng', // default lng, whick cookie key to find when detect lanaguage
resources: 'locales', // default locales, relative to options.root
resourceFormat: 'yml', // default yml, can be json
defaultNS: 'translation', // default translation, the default and fallback namespace
whitelist: ['zh-CN', 'en-US'], // default undefined, the list of allowed language
},
资源文件:
请以 {resources}/{namespace}/{lng}.{resourceFormat}
格式放置资源文件,例如:
project/locales
├── ns
│ ├── en-US.yml
│ └── zh-CN.yml
└── translation
├── en-US.yml
└── zh-CN.yml
每个文件中都是 k-v 对。
Tips: 如果某个资源文本的 key 和 value 是一样的,为了避免重复书写,可以选择不写整个 k-v 或者使用 null 作为 value 。
语言检测
遵循以下步骤:
- 判断
forceLng
是否被设置,是就使用forceLng
- 判断
cookies[cookieKey]
是否存在,存在就使用 - 取
headers['Accept-Language']
按 q 排序后从前到后顺序获取 - 未取到则使用
defaultLng
- 如果设置了
whitelist
,将上面步骤中获取的可能语言顺序去 whitelist 中尝试进行模糊匹配 - 如未设置
whitelist
,将上面步骤中获取的可能语言顺序尝试使用defaultNS
逐个查找资源是否存在,存在则匹配(不支持模糊匹配)
模糊匹配:en 可匹配到 en 、en-US 、en-UK;en-US 也可匹配到 en 、en-US 、en-UK。原则上是优先全部匹配,否则优先语言再是地区。
使用
注:如果 key 未匹配到语言文本,则会使用 key 本身作为文本。
Middleware 中
在启用 i18n 后,在 koa 上下文 ctx 下会存在两个相关对象。
ctx.i18n 包含内容
{ t, // 调用 i18n 的方法 lng, // 当前检测到的语言 ns, // namespace 数组 defaultNS, // 默认 namespace }
ctx.lng === ctx.i18n.lng
Handlebars helpers
提供一个
{ {i18n key [...index_params] [...key=value] [bundle=namespace]} }
的 helper 。除第一个参数必选,为文本 key 之外;可通过参数传入编号参数,可通过 hash 传入命名参数,可通过 bundle 指定 namespace 。{ {i18n "Text { {0} } { {1} }" "haha" "hehe"} } -> Text haha hehe { {i18n "Text { {p1} } { {p2} }" p1="haha" p2="hehe"} } -> Text haha hehe
后端渲染直接使用即可,前端见下节 。
前端使用
前端需要组合使用两个库来使用后端的 i18n 资源并渲染:@terminus/i18n-frontend
,@terminus/i18n-handlebars-helpers
。
使用一个后端 i18n helper 来输出一些必须信息:{ {i18nEnv} }
还要保证一个前提,资源文件可以被前端访问到(例如通过 nginx 代理)。
使用 browserify 或 webpack
在下面的 js 被加载前,与页面上放置标签:
<script> { { i18nEnv; } } </script>
require("@terminus/i18n-handlebars-helpers")(Handlebars); // 传入 Handlebars 来注册 helpers require("@terminus/i18n-frontend")({ callback: function () { // 把初始化代码放在这个回调里,否则你的前端渲染动作可能无法正确获取资源 // 因为 i18n-frontend 通过 xhr 异步获取远端资源 }, resourceFormat: "yml", // 可选,默认为 yml ,可以为 json resourcePath: "/resources", // 可选,默认访问路径为 /resources ,会使用 ${resourcePath}/${ns}/${lng}.${resourceFormat} 去尝试获取资源文件 yamlImpl: window.jsyaml, // 可选,当 resourceFormat 为 yml 时才需要,如果不填就去寻找 window.jsyaml ,暂时只支持 js-yaml 这个库 cache: { // 可选,以下为默认配置,使用 localStorage 来 cache 资源 enable: true, prefix: "i18next_res_", expire: 7 * 24 * 60 * 60 * 1000, }, });
直接使用 js
<script src="http://registry.terminus.io/packages/i18n-helpers/0.1.0/index.js"></script> <script src="http://registry.terminus.io/packages/i18n-frontend/0.1.0/browser.js"></script> <script> { { i18nEnv; } } i18nIniter({ callback: function () { // 参考上一部分的注释说明 }, }); </script>
第一个 js 资源在被加载执行前,需要确保 window.Handlebars 对象的存在。
第二个 js 资源在被加载执行后,会创建 window.i18nIniter 方法供接下来的使用。