国际化与本地化,或者说全球化,其目的是让你的站点支持多个国家和区域。其中国际化是指功能和代码设计能处理多种语言和文化习俗,能够在创建不同语言版本时,不需要重新设计源程序代码。国际化的英文单词是 Internationalization ,简称 I18N。 本地化是将站点按照特定国家、地区或语言市场的需要进行加工,使之满足特定用户对语言和文化的特殊要求。本地化的英文对应Localization,缩写为L10N。举例 Moment,其支持 setLocale
方法切换语言就是国际化,每一个 locale
的配置文件定义了具体区域时间格式就是本地化。
think-i18n 是 ThinkJS 3.0 国际化方案的实现, 基于 Jed, Moment 和 Numeral.
npm install think-i18n --save
// ThinkJS config/extend.js
const createI18n = require('think-i18n');
const path = require('path');
module.exports = [
createI18n({
app: think.app, // 如果为空,__ 就不会被自动 `assign` 到 `think-view` 实例
i18nFolder: path.resolve(__dirname, '../i18n'),
localesMapping(locales) {return 'en';}
})
];
每个 locale 一个文件,放在 i18nFolder 目录下。
如果需要再controller 里面获取 I18n 的实例或者当前的 locale,可以调用
async indexAction(){
const __ = this.getI18n(/*forceLocale*/));
const locale = this.getLocale();
}
如果使用了 think-view 模块并配置了 app 参数, think-i18n 会自动调用注入一个实例到当前模板实例里,类似: this.assign('__', this.getI18n()), 这样在模板里面就可以使用直接使用 i18n 暴露的接口。
{{ __('some key') }}
{{ __.jed.dgettext('domain', 'some key') }}
{{ __.moment().format('llll') }}
{{ __.numeral(1000).format('currency') }}numberFormat.formats)
app:think.app 如果配置了此参数,则会监听 viewInit 事件并把 i18n 实例注入到模板的 __ 参数里面。
i18nFolder:string 放置配置文件的目录
localesMapping:function(locales){return localeId;} 从一个可能的 locale 数组,返回唯一一个 localeId。比如 header['accept-language'].split(',') 可以得到一个locale 的数组,我们可以写一些逻辑并返回最终我们想要的 localeId。
getLocale 如果为空,默认逻辑是从 http 头的 accept-language 里面获取,并用 ',' 分割开。 如果希望从 url 的 query 字段获取,设置为 {by: 'query', name: '字段名'}. 如果希望从 cookie 里面的某个字段获取, 设置为 {by: 'cookie', name: '字段名'} 也可以根据 controller.ctx 实现自己的逻辑, function(ctx) {return locale;}
debugLocale 用来调试某个 localeId
jedOptions 是一个对象,可以在里面配置 domain 和 missing_key_callback,具体请参考 jed options 文档.
默认的值是 {}, 最终用来实例化 jed 的 options 如下:
Object.assign(jedOptions, {locale_data: <your locale translation>})
// locale setting of en-CH.js
module.exports = {
localeId: 'en_CH',
translation: require('../english.po.json'),
dateFormat: require('../moment/en.json'),
numeralFormat: require('../numeral/en.json')
};
其中 ../moment/en.json
是一个json,格式参考 moment 的i18n文件,一模一样。
其中 ../numeral/en.json
是一个json,格式参考 numeral, 需要指出的是,额外的你可以在 numeral 的配置里面设置自定义的格式,并且这个是跟着locale走的,这个实现是个小小的黑魔法,但是对于 i18n 的最佳实践非常重要。
{
localeId: cn,
...
formats: [{name: 'currency', format: '000.00$'}]
}
总是使用自定义的格式,这样就可以通过配置定制不用locale下有不同的输出格式。同时也方便后期的维护,比如某天我们需要把所有长日期显示修改格式,不用到每个文件里面取修改,只需要改配置就好,相当于一层抽象。
如果定义了 en locale, 会覆盖 Numeral 默认的配置。
默认情况下,是通过读取 header['accept-language'] 的值,然后通过 localesMapping 转换后作为某一时刻采纳的 locale。如果需要调试,在 view 配置里面设置 debugLocal =