mcms-node-localization
Version:
mcms node localization module
273 lines (220 loc) • 7.21 kB
JavaScript
var Sprintf = require('sprintf'),
sprintf = Sprintf.sprintf,
vsprintf = Sprintf.vsprintf,
fs = require('fs'),
path = require('path'),
wrench = require('wrench'),
async = require('async'),
lodash = require('lodash');
function Lang(options){
this.options = lodash.merge({
defaultLocale : 'en',
locale : 'en'
},options);
this.locale = this.options.locale;
this.translations = {};
return this;
}
Lang.prototype.add = function(options,callback){
if (typeof options == 'undefined'){
options = {};
}
var asyncObj = {};
var _this = this;
var directory = (typeof options.directory == 'undefined') ? this.options.directory : options.directory;
var locales = (typeof options.locales == 'undefined') ? this.options.locales : options.locales;
//load translations
for (var a in locales){
var locale = locales[a];
if (typeof this.translations[locale] == 'undefined'){
this.translations[locale] = {};
}
asyncObj[locale] = function(dir,locale,callback){
_this.readFiles(dir,locale,function(err,translation){
_this.translations[locale] = lodash.merge(translation,_this.translations[locale]);
callback(null,locale + ' done');
});
}.bind(null,directory + '/' + locale,locale);
}
async.parallel(asyncObj,function(err,translations){
if (typeof callback != 'undefined'){
callback(null,translations);
}
});
return this;
};
Lang.prototype.setLocale = function(locale){
this.locale = locale;
return this;
};
Lang.prototype.getLocale = function(){
return this.locale;
};
Lang.prototype.findMissing = function(){
};
Lang.prototype.readFiles = function(dir,locale,cb){
var obj = {};
var files = wrench.readdirSyncRecursive(dir);
for (var a in files){
var file = files[a];
if (path.extname(file) == '.json'){
var localeFile = fs.readFileSync(dir + '/' + file);
obj[path.basename(file,'.json')] = JSON.parse(localeFile);
} else if (path.extname(file) == '.js') {
obj[path.basename(file,'.js')] = require(dir + '/' + file);
}
}
cb(null,obj);
};
function translate(phrase){
var namedValues = {};
//we are calling with named parameters like {name : 'mike'}
if (typeof arguments[1] == 'object' && !Array.isArray(arguments[1])){
namedValues = arguments[1];
return sprintf(phrase, namedValues);
}
if (Array.isArray(arguments[1])) {
return vsprintf(phrase,arguments[1]);
}
//we are calling it with array params like %s,%s
var args = Array.prototype.slice.call(arguments);
args.shift();
return vsprintf(phrase,args);
}
function translatePlural(singular, plural, count){
var namedValues = {};
//we are calling with named parameters like {name : 'mike'}
if (typeof arguments[3] == 'object'){
namedValues = arguments[3];
namedValues = lodash.merge({count : count},namedValues);
if (count == 1){
return sprintf(singular,namedValues);
} else {
return sprintf(plural,namedValues);
}
}
//we are calling it with array params like %s,%s
var args = Array.prototype.slice.call(arguments);
args.shift();//get rid of singular
args.shift();;//get rid of plural
if (count == 1){
return vsprintf(singular,args);
} else {
return vsprintf(plural,args);
}
}
/**
* Return the raw translations
* @param key
* @returns {*}
*/
Lang.prototype.getRaw = function(key) {
const locale = this.getLocale();
if (!key) {
return this.translations[locale];
}
return this.translations[locale][key];
}
Lang.prototype.getKeys = function() {
return Object.keys(this.translations[this.getLocale()]);
}
Lang.prototype.getAll = function() {
return this.translations;
}
Lang.prototype.get = function(translation){
var locale = this.getLocale();
var args = Array.prototype.slice.call(arguments,1);
try {
if (translation.indexOf('.') != -1){
var phrase = Object.byString(this.translations[locale], translation);
if (!phrase) {return translation;}
args.unshift(phrase);
return translate.apply(this,args);
}
if (!this.translations[locale][translation]) {
return translation;
}
return translate.apply(this.translations[locale][translation],args);
}
catch (e){
return translation;
}
};
/**
*
* @param translation
* @param count
* @returns {*}
*/
Lang.prototype.choice = function(translation,count){
var locale = this.getLocale();
var args = Array.prototype.slice.call(arguments,1);
try {
if (translation.indexOf('.') != -1){
var phrase = Object.byString(this.translations[locale], translation);
args.unshift(phrase.one,phrase.other);
return translatePlural.apply(this,args);
}
return translate(this.translations[locale][translation],args);
}
catch (e){
return '';
}
};
/**
*
* @param translation. expects something like messages OR message.trans
* @param value. expects locales object like {en : 'trans', de : 'trans'} or {en : {var:'value'},de: {var:'value'}
*/
Lang.prototype.inject = function(translation,value){
if (translation.indexOf('.') == -1){//we expect an entire object
this.addToTranslations(translation,value,false);
return;
}
this.addToTranslations(translation,value,true);
return;
};
/**
*
* @param translation
* @param value
* @param isSingle. Defines whether we expect a full object or just a sub one
*/
Lang.prototype.addToTranslations = function(translation,value,isSingle){
for (var a in this.translations){
if (typeof value[a] != 'undefined'){
if (!isSingle){
this.translations[a][translation] = value[a];
}
else {
set(translation,value[a],this.translations[a]);
}
}
}
};
Object.byString = function(o, s) {
s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
s = s.replace(/^\./, ''); // strip leading dot
var a = s.split('.');
while (a.length) {
var n = a.shift();
if (n in o) {
o = o[n];
} else {
return;
}
}
return o;
};
function set(path, value,obj) {
var schema = obj; // a moving reference to internal objects within obj
var pList = path.split('.');
var len = pList.length;
for(var i = 0; i < len-1; i++) {
var elem = pList[i];
if( !schema[elem] ) schema[elem] = {}
schema = schema[elem];
}
schema[pList[len-1]] = value;
}
module.exports = Lang;