321 lines
10 KiB
JavaScript
321 lines
10 KiB
JavaScript
(function() {
|
|
|
|
var i18n = require('./i18nextWrapper')
|
|
, i18nWT = require('./i18nextWTWrapper')
|
|
, fs = require('fs')
|
|
, filesync = require('./filesync')
|
|
, Cookies = require('cookies');
|
|
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = i18n;
|
|
}
|
|
|
|
var resStore
|
|
, backend
|
|
, orgInit = i18n.init
|
|
, registeredAppHelpers;
|
|
|
|
i18n.init = function(options, cb) {
|
|
if (typeof options === 'function') {
|
|
cb = options;
|
|
options = {};
|
|
}
|
|
|
|
options = options || {};
|
|
options.resSetPath = options.resSetPath || 'locales/__lng__/__ns__.json';
|
|
options.sendMissing = options.sendMissing || options.saveMissing || false;
|
|
options.detectLngFromPath = options.detectLngFromPath === undefined ? false : options.detectLngFromPath;
|
|
options.forceDetectLngFromPath = options.forceDetectLngFromPath !== true ? false : options.forceDetectLngFromPath;
|
|
options.detectLngFromHeaders = options.detectLngFromHeaders !== false ? true : options.detectLngFromHeaders;
|
|
options.supportedLngs = options.supportedLngs || [];
|
|
options.ignoreRoutes = options.ignoreRoutes || [];
|
|
options.cookieName = options.cookieName || 'i18next';
|
|
resStore = options.resStore ? options.resStore : {};
|
|
|
|
// obsolete
|
|
// if (options.useSync) console.log('options.useSync is obsolete use i18next.backend(...) instead.');
|
|
|
|
var o = i18n.functions.extend(i18n.options, options);
|
|
|
|
if (!backend) backend = filesync;
|
|
|
|
if (!i18n.sync.fetchOne) i18n.functions.extend(i18n.sync, backend);
|
|
|
|
if ((!i18n.sync.resStore || options.resStore) && typeof i18n.sync.configure === 'function') {
|
|
i18n.sync.configure(resStore, o, i18n.functions);
|
|
}
|
|
|
|
orgInit(options, cb);
|
|
|
|
// override functions: .log(), .detectLanguage(), etc
|
|
if (options.functions) {
|
|
i18n.functions.extend(i18n.functions, options.functions);
|
|
}
|
|
};
|
|
|
|
i18n.backend = function(sync) {
|
|
// reset sync
|
|
if (i18n.sync.fetchOne) delete i18n.sync.fetchOne;
|
|
if (i18n.sync.resStore) delete i18n.sync.resStore;
|
|
resStore = {};
|
|
|
|
backend = sync;
|
|
};
|
|
|
|
i18n.handle = function(req, res, next) {
|
|
var ignore = i18n.options.ignoreRoutes;
|
|
for (var i = 0, len = ignore.length; i < len; i++) {
|
|
if (req.path.indexOf(ignore[i]) > -1) {
|
|
return next();
|
|
}
|
|
}
|
|
|
|
var languages = i18n.functions.toLanguages(i18n.detectLanguage(req, res));
|
|
var locale = languages[0];
|
|
|
|
// set locale & i18n in req
|
|
req.locale = req.lng = req.language = locale;
|
|
|
|
// assert t function returns always translation
|
|
// in given lng inside this request
|
|
var t = function(key, options) {
|
|
options = options || {};
|
|
options.lng = options.lng || req.lng || i18n.lng();
|
|
return i18n.t(key, options);
|
|
};
|
|
|
|
var i18nDummy = {
|
|
t: t,
|
|
translate: t,
|
|
lng: function() { return locale; },
|
|
locale: function() { return locale; },
|
|
language: function() { return locale; },
|
|
setLng: function(lng) { req.lng = lng; }
|
|
};
|
|
|
|
// assert for req
|
|
req.i18n = i18nDummy;
|
|
req.t = req.t || t;
|
|
|
|
// assert for res -> template
|
|
if (registeredAppHelpers) {
|
|
if (res.locals) {
|
|
res.locals.t = t;
|
|
res.locals.i18n = i18nDummy;
|
|
}
|
|
}
|
|
|
|
i18n.setLng(locale, function() {
|
|
if (i18n.options.useCookie) i18n.persistCookie(req, res, locale);
|
|
next();
|
|
});
|
|
};
|
|
|
|
i18n.registerAppHelper = function(app) {
|
|
registeredAppHelpers = true;
|
|
|
|
|
|
if(app.dynamicHelpers) {
|
|
app.dynamicHelpers({
|
|
t: function(req, res) {
|
|
return req.t;
|
|
},
|
|
i18n: function(req, res) {
|
|
return req.i18n;
|
|
}
|
|
});
|
|
// app.helpers({
|
|
// t: i18n.t,
|
|
// i18n: {
|
|
// t: i18n.t,
|
|
// translate: i18n.t,
|
|
// lng: i18n.lng,
|
|
// locale: i18n.lng,
|
|
// language: i18n.lng
|
|
// }
|
|
// });
|
|
}
|
|
|
|
return i18n;
|
|
};
|
|
|
|
i18n.serveClientScript = function(app, options) {
|
|
options = options || {};
|
|
var maxAge = options.maxAge ? options.maxAge : 60 * 60 * 24 * 30;
|
|
|
|
app.get('/i18next/i18next.js', function(req, res) {
|
|
//var filename = (process.env.NODE_ENV !== 'production' || process.env.DEBUG) ? __dirname + '/dep/i18next-' + i18n.clientVersion + '.js' : __dirname + '/dep/i18next-' + i18n.clientVersion + '.min.js';
|
|
var filename = (process.env.NODE_ENV !== 'production' || process.env.DEBUG) ? __dirname + '/dep/i18next.js' : __dirname + '/dep/i18next.min.js';
|
|
|
|
if (options.cache !== undefined ? options.cache : process.env.NODE_ENV === 'production') {
|
|
res.header('Cache-Control', 'public max-age=' + maxAge);
|
|
res.header('Expires', (new Date(new Date().getTime() + maxAge * 1000)).toUTCString());
|
|
} else {
|
|
res.header('Pragma', 'no-cache');
|
|
res.header('Cache-Control', 'no-cache');
|
|
}
|
|
|
|
// Fix express 4 deprecation warning
|
|
if(res.sendFile)
|
|
res.sendFile(filename);
|
|
else
|
|
res.sendfile(filename);
|
|
});
|
|
|
|
return i18n;
|
|
};
|
|
|
|
i18n.serveWebTranslate = function(app, options) {
|
|
i18nWT.serve(app, options);
|
|
|
|
return i18n;
|
|
};
|
|
|
|
i18n.serveDynamicResources = function(app, options) {
|
|
options = options || {};
|
|
var maxAge = options.maxAge ? options.maxAge : 60 * 60 * 24 * 30;
|
|
|
|
app.get('/locales/resources.json', function(req, res) {
|
|
|
|
var resources = {};
|
|
|
|
res.contentType('json');
|
|
if (options.cache !== undefined ? options.cache : process.env.NODE_ENV === 'production') {
|
|
res.header('Cache-Control', 'public max-age=' + maxAge);
|
|
res.header('Expires', (new Date(new Date().getTime() + maxAge * 1000)).toUTCString());
|
|
} else {
|
|
res.header('Pragma', 'no-cache');
|
|
res.header('Cache-Control', 'no-cache');
|
|
}
|
|
|
|
var languages = req.query.lng ? req.query.lng.split(' ') : []
|
|
, opts = { ns: { namespaces: req.query.ns ? req.query.ns.split(' ') : [] } };
|
|
|
|
i18n.sync.load(languages, opts, function() {
|
|
|
|
languages.forEach(function(lng) {
|
|
if (!resources[lng]) resources[lng] = {};
|
|
|
|
opts.ns.namespaces.forEach(function(ns) {
|
|
if (!resources[lng][ns]) resources[lng][ns] = i18n.sync.resStore[lng][ns] || {};
|
|
});
|
|
});
|
|
|
|
res.send(resources);
|
|
});
|
|
});
|
|
|
|
return i18n;
|
|
};
|
|
|
|
i18n.serveMissingKeyRoute = function(app, authenticated) {
|
|
app.post('/locales/add/:lng/:ns', function(req, res) {
|
|
if (authenticated && !authenticated(req, res)) {
|
|
res.end();
|
|
return;
|
|
}
|
|
|
|
var lng = req.params.lng;
|
|
var ns = req.params.ns;
|
|
|
|
for (var m in req.body) {
|
|
i18n.sync.postMissing(lng, ns, m, req.body[m]);
|
|
}
|
|
|
|
res.json('ok');
|
|
});
|
|
|
|
return i18n;
|
|
};
|
|
|
|
i18n.serveChangeKeyRoute = function(app, authenticated) {
|
|
app.post('/locales/change/:lng/:ns', function(req, res) {
|
|
if (authenticated && !authenticated(req, res)) {
|
|
res.end();
|
|
return;
|
|
}
|
|
|
|
var lng = req.params.lng;
|
|
var ns = req.params.ns;
|
|
|
|
for (var m in req.body) {
|
|
i18n.sync.postChange(lng, ns, m, req.body[m]);
|
|
}
|
|
|
|
res.json('ok');
|
|
});
|
|
|
|
return i18n;
|
|
};
|
|
|
|
i18n.serveRemoveKeyRoute = function(app, authenticated) {
|
|
app.post('/locales/remove/:lng/:ns', function(req, res) {
|
|
if (authenticated && !authenticated(req, res)) {
|
|
res.end();
|
|
return;
|
|
}
|
|
|
|
var lng = req.params.lng;
|
|
var ns = req.params.ns;
|
|
|
|
for (var m in req.body) {
|
|
i18n.sync.postRemove(lng, ns, m, req.body[m]);
|
|
}
|
|
|
|
res.json('ok');
|
|
});
|
|
|
|
return i18n;
|
|
};
|
|
|
|
i18n.persistCookie = function(req, res, locale) {
|
|
var cookies = new Cookies(req, res);
|
|
var expirationDate = new Date();
|
|
expirationDate.setFullYear(expirationDate.getFullYear() + 1);
|
|
|
|
cookies.set(i18n.options.cookieName, locale, { expires: expirationDate, domain: i18n.options.cookieDomain, httpOnly : false });
|
|
};
|
|
|
|
i18n.addRoute = function(route, lngs, app, verb, fc) {
|
|
if (typeof verb === 'function') {
|
|
fc = verb;
|
|
verb = 'get';
|
|
}
|
|
|
|
// Combine `fc` and possible more callbacks to one array
|
|
var callbacks = [fc].concat(Array.prototype.slice.call(arguments, 5));
|
|
|
|
for (var i = 0, li = lngs.length; i < li; i++) {
|
|
var parts = route.split('/');
|
|
var locRoute = [];
|
|
for (var y = 0, ly = parts.length; y < ly; y++) {
|
|
var part = parts[y];
|
|
if (part.indexOf(':') === 0 || part === '') {
|
|
locRoute.push(part);
|
|
} else {
|
|
locRoute.push(i18n.t(part, { lng: lngs[i] }));
|
|
}
|
|
}
|
|
|
|
// Apply the route and its callbacks
|
|
// with a prepended middleware to ensure
|
|
// :lng contains a supported language
|
|
app[verb || 'get'].apply(app, [locRoute.join('/'), ensureIsSupportedLanguage(lngs)].concat(callbacks));
|
|
}
|
|
};
|
|
|
|
// Middleware that checks for
|
|
// the parameter :lng to contain
|
|
// a supported language.
|
|
// If not, it skips the route.
|
|
function ensureIsSupportedLanguage(languages) {
|
|
return function (req, res, next) {
|
|
if (req.params.lng && languages.indexOf(req.params.lng) >= 0) {
|
|
return next();
|
|
}
|
|
|
|
next('route');
|
|
};
|
|
}
|
|
|
|
})();
|