国际化与本地化
国际化与本地化
概述
国际化与本地化,或者说全球化,其目的是让你的站点支持多个国家和区域。其中国际化是指功能和代码设计能处理多种语言和文化习俗,能够在创建不同语言版本时,不需要重新设计源程序代码。国际化的英文单词是 Internationalization ,简称 I18N。 本地化是将站点按照特定国家、地区或语言市场的需要进行加工,使之满足特定用户对语言和文化的特殊要求。本地化的英文对应Localization,缩写为L10N。举例 Moment,其支持 setLocale
方法切换语言就是国际化,每一个 locale
的配置文件定义了具体区域时间格式就是本地化。
think-i18n
think-i18n 是 ThinkJS 3.0 国际化方案的实现, 基于 Jed, Moment 和 Numeral.
安装
npm install think-i18n --save
配置 extends.js
// 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 文件
每个 locale 一个文件,放在 i18nFolder 目录下。
dateFormat
会应用到 moment.local(localeId,dateFormat
如果不提供配置,默认使用 en
Controller 和 View (nunjucks)
Controller
如果需要再controller 里面获取 I18n 的实例或者当前的 locale,可以调用
async indexAction(){
const __ = this.getI18n(/*forceLocale*/)
const locale = this.getLocale(
}
View
如果使用了 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 实例注入到模板的 __ 参数里面。
Object.assign(jedOptions, {locale_data: <your locale translation>})
背后的思考
- 你可能会觉得这个方案太复杂,但是 i18n 本来就很复杂,要想实现的好,你可能需要的只会更多。
// 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下有不同的输出格式。同时也方便后期的维护,比如某天我们需要把所有长日期显示修改格式,不用到每个文件里面取修改,只需要改配置就好,相当于一层抽象。
- 使用
__.moment().format('llll')
而不是 moment().format('YYYY-MM-dd HH:mm').
注
如果定义了 en
locale, 会覆盖 Numeral 默认的配置。
调试某个 locale
默认情况下,是通过读取 header['accept-language'] 的值,然后通过 localesMapping 转换后作为某一时刻采纳的 locale。如果需要调试,在 view 配置里面设置 debugLocal
=