2025-05-12 05:38:44 +09:00

126 lines
3.0 KiB
JavaScript

var _ = require('lodash');
var path = require('path');
var fs = require('fs');
function I18n(opts) {
if (!(this instanceof I18n)) return new I18n(opts);
this.opts = _.defaults(opts || {}, {
defaultLocale: 'en'
});
this._locales = {};
_.bindAll(this, _.functionsIn(this));
}
// Extend locales
I18n.prototype.set = function(_locales) {
this._locales = _.extend(this._locales, _locales);
};
// Return a locales or all
I18n.prototype.get = function(lang) {
if (lang) {
lang = this.resolve(lang);
return this._locales[lang];
} else {
return this._locales;
}
};
// Return list of locales
I18n.prototype.locales = function() {
return _.keys(this._locales);
};
// Load locales from a folder
I18n.prototype.load = function(root) {
var locales = _.chain(fs.readdirSync(root))
.map(function(filename) {
var ext = path.extname(filename);
if (ext != '.json' && ext != '.js') return;
var lang = path.basename(filename, ext);
var filepath = path.resolve(root, filename);
return [
lang,
require(filepath)
];
})
.compact()
.fromPairs()
.value();
this.set(locales);
};
// Resolve a language to an existing locale
I18n.prototype.resolve = function(lang, defaultLocale) {
defaultLocale = _.isUndefined(defaultLocale)? this.opts.defaultLocale : defaultLocale;
return _.chain(this.locales())
.map(function(locale) {
return {
locale: locale,
score: compareLocales(lang, locale)
};
})
.filter(function(lang) {
return lang.score > 0;
})
.sortBy('score')
.map('locale')
.last()
.value() || defaultLocale;
};
// Translate a phrase
I18n.prototype.t = function(lang, phrase) {
var args = _.toArray(arguments).slice(2);
var kwargs = {};
var locale = this.get(lang);
if (_.isObject(_.last(args))) {
kwargs = _.last(args);
args = args.slice(0, -1);
}
var tpl = locale[phrase];
if (_.isUndefined(tpl)) {
tpl = this.get(this.opts.defaultLocale)[phrase];
}
return interpolate(tpl || phrase, args, kwargs);
};
// Compare two language to find the most adequate
function compareLocales(lang, locale) {
var langMain = _.first(lang.split('-'));
var langSecond = _.last(lang.split('-'));
var localeMain = _.first(locale.split('-'));
var localeSecond = _.last(locale.split('-'));
if (locale == lang) return 100;
if (localeMain == langMain && localeSecond == localeMain) return 51;
if (localeMain == langMain) return 50;
if (localeSecond == langSecond) return 20;
return 0;
}
// Interpolate a template
function interpolate(tpl, args, kwargs) {
var value = tpl;
kwargs = _.extend(kwargs, args);
return _.reduce(kwargs, function(value, val, key) {
var re = /{{([\s\S]*?[^\$])}}/g;
return value.replace(re, val);
}, tpl);
}
module.exports = I18n;