Internationalization and localization, often abbreviated to the numeronyms i18n and l10n. I18n is the process of designing a software application so that it can be adapted to various languages and regions without engineering changes. Localization is the process of adapting internationalized software for a specific region or language by adding locale-specific components and translating text. Localization (which is potentially performed multiple times, for different locales) uses the infrastructure or flexibility provided by internationalization (which is ideally performed only once, or as an integral part of ongoing development). Take Moment.js as an example, it supports setLocale
to switch to different language is the way it implement I18N, each locale
configure file specific the time format and other regional related behaviors is what called localization.
i18n solution in thinkjs 3.0, implement base on Jed, Moment and Numeral.
npm install think-i18n --save
// thinkjs config/extend.js
const createI18n = require('think-i18n');
const path = require('path');
module.exports = [
createI18n({
i18nFolder: path.resolve(__dirname, '../i18n'),
localesMapping(locales) {return 'en';}
})
];
Each locale settings is a javascript file. see example
module.exports = {
app: think.app, // if not passed in, __ will not be auto `assign` into `think-view` instance
localeId,
translation,
dateFormat, // optional
numeralFormat, // optional
}
localeId: The unique name of your locale.
dateFormat: Will apply to moment.local(localeId, dateFormat); if empty you will get a moment instance with 'en' locale.
numeralFormat: Will apply numeral.locales[localeId] = numeralFormat; if empty you will get numeral instance with 'en' locale.
translation: Equivalent to Jed locale_data, if you use .po file, jed suggest use po2json which support jed format transform.
You can get i18n instance or current locale
in controller.
async indexAction(){
this.assign(this.i18n(/*forceLocale*/));
...
}
If you used think-view , think-i18n will auto-inject an i18n instance into __
field, like
this.assign('__', this.getI18n())
.
{{ __('some key') }} translation
{{ __.jed.dgettext('domain', 'some key') }} translation in specify domain
{{ __.moment().format('llll') }} datetime format
{{ __.numeral(1000).format('currency') }} number format (see numberFormat.formats)
i18nFolder:string Directory path where you put all locale settings files
localesMapping:function(locales){return localeId;} Given a list of possible locales, return a localeId
getLocale default logic is to extract header['accept-language'] if set to falsy value. To get from url query locale, set to {by: 'query', name: 'locale'}. To get from cookie of locale, set to {by: 'cookie', name: 'locale'} To implement your own logic, function(ctx) {return locale;}
debugLocale set to value of localeId
jedOptions You can set domain and missing_key_callback, for details refer to jed doc.
default value is {}, the final jed options will be
Object.assign(jedOptions, {locale_data: <your locale translation>})
Why combine all there libraries' i18n config into one? the answer is for transparent but most importantly, flexibility to compose you date, number and message's behavior per locale, for example, you have a website in China and want to provide English translation, but keep the chinese currency symbol, so you can compose english translation and chinese date and currency in your en.js locale setting.
// locale setting of en.js
module.exports = {
localeId: 'en_ch',
translation: require('../english.po.json'),
dateFormat: require('../moment/en.json'),
numeralFormat: require('../numeral/en.json')
};
We should always use customize format.