redmine-client/node_modules/i18next/lib/i18nextWrapper.js
2014-12-26 04:41:54 +01:00

370 lines
12 KiB
JavaScript

(function() {
// when updating dep/i18next.xx.js update version here
var i18nVersion = '1.7.3';
var i18n = require('./dep/i18next')//-' + i18nVersion)
, url = require('url')
, Cookies = require('cookies')
, wrapper = {};
wrapper.version = require('../package.json').version;
wrapper.clientVersion = i18nVersion;
if (typeof module !== 'undefined' && module.exports) {
module.exports = wrapper;
}
// detection subfunctions
function detectLanguageFromUserland(req, res, options) {
var locale, locales = [];
locale = options.detectLanguageFn(req, res);
if (locale) locales.push({lng: cleanLngString(locale, options), q: 1});
return locales;
}
function detectLanguageFromPath(req, res, options) {
var locale, locales = [];
var parts = req.originalUrl.split('/');
if (parts.length > options.detectLngFromPath + 1) {
var part = parts[options.detectLngFromPath + 1];
var lookUp = wrapper.pluralExtensions.rules[part.split('-')[0]];
if (lookUp) locale = part;
}
if (locale) locales.push({lng: cleanLngString(locale, options), q: 1});
return locales;
}
function detectLanguageFromQuerystring(req, res, options) {
var locale, locales = [];
if (req.query) {
locale = req.query[options.detectLngQS];
} else {
var querystring = url.parse(req.url, true);
locale = querystring.query[options.detectLngQS];
}
if (locale) locales.push({lng: cleanLngString(locale, options), q: 1});
return locales;
}
function detectLanguageFromCookie(req, res, options) {
var locale, locales = [];
if (req.cookies) {
locale = req.cookies[options.cookieName];
} else {
var cookies = new Cookies(req, res);
locale = cookies.get(options.cookieName);
}
if (locale) locales.push({lng: cleanLngString(locale, options), q: 1});
return locales;
}
var detectLanguageFromHeader = function(req, res, options) {
var headers = req.headers;
var locales = [];
if (!headers) {
return locales;
}
var acceptLanguage = headers['accept-language'];
if (acceptLanguage) {
var lngs = [], i;
// associate language tags by their 'q' value (between 1 and 0)
acceptLanguage.split(',').forEach(function(l) {
var parts = l.split(';'); // 'en-GB;q=0.8' -> ['en-GB', 'q=0.8']
// get the language tag qvalue: 'q=0.8' -> 0.8
var qvalue = 1; // default qvalue
for (i = 0; i < parts.length; i++) {
var part = parts[i].split('=');
if (part[0] === 'q' && !isNaN(part[1])) {
qvalue = Number(part[1]);
break;
}
}
// add the tag and primary subtag to the qvalue associations
lngs.push({lng: cleanLngString(parts[0], options), q: qvalue});
});
lngs.sort(function(a,b) {
return b.q - a.q;
});
for (i = 0; i < lngs.length; i++) {
locales.push(lngs[i]);
}
}
return locales;
};
function checkAgainstSupportedLng(locales, supportedLngs) {
if (!supportedLngs.length && locales.length) {
return [locales[0]];
} else {
for (var i = 0, len = locales.length; i < len; i++) {
var locale = locales[i];
if (supportedLngs.indexOf(locale.lng) > -1) {
return [locale];
}
if (locale.lng.indexOf('-') > -1) {
var unspecific = locale.lng.split('-')[0];
if (supportedLngs.indexOf(unspecific) > -1) {
locale.lng = unspecific;
return [locale];
}
}
}
}
return [];
}
function cleanLngString(lng, options) {
if (typeof lng === 'string' && lng.indexOf('-') > -1) {
var parts = lng.split('-');
lng = options.lowerCaseLng ?
parts[0].toLowerCase() + '-' + parts[1].toLowerCase() :
parts[0].toLowerCase() + '-' + parts[1].toUpperCase();
}
return lng;
}
// overriding detect language function
var detectLanguage = function(req, res) {
var locales = []
, opts = wrapper.options;
if (typeof req === 'object') {
// user-land fn
if (!locales.length && opts.detectLanguageFn) {
locales = detectLanguageFromUserland(req, res, opts);
locales = checkAgainstSupportedLng(locales, opts.supportedLngs);
}
// from path
if (!locales.length && opts.detectLngFromPath !== false) {
locales = detectLanguageFromPath(req, res, opts);
locales = checkAgainstSupportedLng(locales, opts.supportedLngs);
if (!locales.length && opts.forceDetectLngFromPath) {
locales = [{lng: opts.fallbackLng[0], q: 1}];
}
}
// from querystring
if (!locales.length) {
locales = detectLanguageFromQuerystring(req, res, opts);
locales = checkAgainstSupportedLng(locales, opts.supportedLngs);
}
// from cookie
if (!locales.length && opts.useCookie) {
locales = detectLanguageFromCookie(req, res, opts);
locales = checkAgainstSupportedLng(locales, opts.supportedLngs);
}
// from headers
if (!locales.length && opts.detectLngFromHeaders) {
locales = detectLanguageFromHeader(req, res, opts);
locales = checkAgainstSupportedLng(locales, opts.supportedLngs);
}
}
if (!locales.length) locales.push({lng: opts.fallbackLng[0] || 'en', q: 1});
return locales[0].lng;
};
// overriding for the functions in i18next.js
var f = {
extend: function(target, source) {
if (!source || typeof source === 'function') {
return target;
}
for (var attr in source) { target[attr] = source[attr]; }
return target;
},
each: function( object, callback, args ) {
var name, i = 0,
length = object.length,
isObj = length === undefined || typeof object === "function";
if (args) {
if (isObj) {
for (name in object) {
if (callback.apply(object[name], args) === false) {
break;
}
}
} else {
for ( ; i < length; ) {
if (callback.apply(object[i++], args) === false) {
break;
}
}
}
// A special, fast, case for the most common use of each
} else {
if (isObj) {
for (name in object) {
if (callback.call(object[name], name, object[name]) === false) {
break;
}
}
} else {
for ( ; i < length; ) {
if (callback.call(object[i], i, object[i++]) === false) {
break;
}
}
}
}
return object;
},
ajax: function() { return null; },
detectLanguage: detectLanguage,
detectLanguageFromPath: detectLanguageFromPath,
detectLanguageFromQuerystring: detectLanguageFromQuerystring,
detectLanguageFromCookie: detectLanguageFromCookie,
detectLanguageFromHeader: detectLanguageFromHeader,
checkAgainstSupportedLng: checkAgainstSupportedLng,
cookie: {
create: function() {},
read: function() {},
remove: function() {}
}
};
f.extend(i18n.functions, f);
// override unused sync stuff
i18n.functions.extend(i18n.sync, {
reload: function (cb) {
this.resStore = {};
i18n.setLng(i18n.lng, cb);
},
configure: function(rstore, options, functions) {
this.resStore = rstore || {};
this.functions = functions;
this.options = options;
this._fetch = this.fetch;
this._fetchOne = this.fetchOne;
},
load: function(lngs, options, cb) {
var self = this
, missingLngs = [];
for (var i = 0, len = lngs.length; i < len; i++) {
if (!this.resStore[lngs[i]]) missingLngs.push(lngs[i]);
}
if (missingLngs.length > 0) {
this.fetch(missingLngs, options, function(err, fetched) {
if (err) i18n.functions.log(err);
self.functions.extend(self.resStore, fetched);
cb(err, self.resStore);
});
} else {
cb(null, self.resStore);
}
},
fetch: function(lngs, options, cb) {
var self = this
, ns = options.ns
, store = {};
var todo = ns.namespaces.length * lngs.length
, errors;
if(ns.namespaces.length === 0)
cb('namespaces not found', null);
else {
// load each file individual
f.each(ns.namespaces, function(nsIndex, nsValue) {
f.each(lngs, function(lngIndex, lngValue) {
self.fetchOne(lngValue, nsValue, function(err, data) {
if(err) {
errors = errors || [];
errors.push(err);
}
store[lngValue] = store[lngValue] || {};
if(err) {
store[lngValue][nsValue] = {};
}
else {
store[lngValue][nsValue] = data;
}
todo--; // wait for all done befor callback
if(todo === 0) {
cb(errors, store);
}
});
});
});
}
},
postMissing: function(lng, ns, key, defaultValue) {
var self = this
, lngs = [];
if (this.options.sendMissingTo === 'fallback' && this.options.fallbackLng !== false) {
lngs.push(this.options.fallbackLng[0]);
} else if (this.options.sendMissingTo === 'current' || (this.options.sendMissingTo === 'fallback' && this.options.fallbackLng[0] !== false)) {
lngs.push(lng);
} else if (this.options.sendMissingTo === 'all') {
lngs = i18n.functions.toLanguages(lng);
}
f.each(lngs, function(i, l) {
if (!self.resStore[l] || !self.resStore[l][ns]) {
self.functions.log('error saving missingKey `' + key + '` cause namespace `' + ns + '` was not loaded for language `' + l + '`.' );
} else {
self.saveMissing(l, ns, key, defaultValue);
}
});
},
_loadLocal: function(lngs, cb) {
cb('not supported');
},
_storeLocal: function(store) {
return;
}
});
f.extend(wrapper, i18n);
wrapper.detectLanguage = function () {
// use the real f.detectLanguage() in case .init() overwrote it
return wrapper.functions.detectLanguage.apply(wrapper, arguments);
};
})();