i18n-2 = function (opt) { var self = this; // Put into dev or production mode this.devMode = process.env.NODE_ENV !== "production"; // Copy over options for (var prop in opt) { this[prop] = opt[prop]; } // you may register helpers in global scope, up to you if (typeof this.register === "object") { i18n.resMethods.forEach(function (method) { self.register[method] = self[method].bind(self); }); } // implicitly read all locales // if it's an array of locale names, read in the data if (opt.locales && opt.locales.forEach) { this.locales = {}; opt.locales.forEach(function (locale) { self.readFile(locale); }); this.defaultLocale = opt.locales[0]; } // Set the locale to the default locale this.setLocale(this.defaultLocale); // Check the defaultLocale if (!this.locales[this.defaultLocale]) { console.error("Not a valid default locale."); } if (this.request) { if (this.subdomain) { this.setLocaleFromSubdomain(this.request); } if (this.query !== false) { this.setLocaleFromQuery(this.request); } if (this.session !== false) { this.setLocaleFromSessionVar(this.request); } this.prefLocale = this.preferredLocale(); if (this.prefLocale !== false && this.prefLocale !== this.locale) { this.setLocale(this.prefLocale); } } }
n/a
expressBind = function (app, opt) { if (!app) { return; } app.use(function (req, res, next) { opt.request = req; req.i18n = new i18n(opt); // Express 3 if (res.locals) { i18n.registerMethods(res.locals, req) } next(); }); // Express 2 if (app.dynamicHelpers) { app.dynamicHelpers(i18n.registerMethods({})); } }
...
## API:
### `new i18n(options)`
The `i18n` function is the return result from calling `require('i18n-2')`. You use this to instantiate an `I18n` instance
and set any configuration options. You'll probably only do this if you're not using the `expressBind` method.
### `i18n.expressBind(app, options)`
You'll use this method to attach the i18n functionality to the request object inside Express.js. The app argument should be
your Express.js app and the options argument should be the same as if you were calling `new i18n(options)`. See **"Using with
Express.js"** at the end of this README for more details.
### `__(string, [...])`
Translates a string according to the current locale. Also supports sprintf syntax, allowing you to replace text, using the node-
sprintf module.
...
i18n = function (opt) { var self = this; // Put into dev or production mode this.devMode = process.env.NODE_ENV !== "production"; // Copy over options for (var prop in opt) { this[prop] = opt[prop]; } // you may register helpers in global scope, up to you if (typeof this.register === "object") { i18n.resMethods.forEach(function (method) { self.register[method] = self[method].bind(self); }); } // implicitly read all locales // if it's an array of locale names, read in the data if (opt.locales && opt.locales.forEach) { this.locales = {}; opt.locales.forEach(function (locale) { self.readFile(locale); }); this.defaultLocale = opt.locales[0]; } // Set the locale to the default locale this.setLocale(this.defaultLocale); // Check the defaultLocale if (!this.locales[this.defaultLocale]) { console.error("Not a valid default locale."); } if (this.request) { if (this.subdomain) { this.setLocaleFromSubdomain(this.request); } if (this.query !== false) { this.setLocaleFromQuery(this.request); } if (this.session !== false) { this.setLocaleFromSessionVar(this.request); } this.prefLocale = this.preferredLocale(); if (this.prefLocale !== false && this.prefLocale !== this.locale) { this.setLocale(this.prefLocale); } } }
n/a
registerMethods = function (helpers, req) { i18n.resMethods.forEach(function (method) { if (req) { helpers[method] = req.i18n[method].bind(req.i18n); } else { helpers[method] = function (req) { return req.i18n[method].bind(req.i18n); }; } }); return helpers; }
n/a
i18n = function (opt) { var self = this; // Put into dev or production mode this.devMode = process.env.NODE_ENV !== "production"; // Copy over options for (var prop in opt) { this[prop] = opt[prop]; } // you may register helpers in global scope, up to you if (typeof this.register === "object") { i18n.resMethods.forEach(function (method) { self.register[method] = self[method].bind(self); }); } // implicitly read all locales // if it's an array of locale names, read in the data if (opt.locales && opt.locales.forEach) { this.locales = {}; opt.locales.forEach(function (locale) { self.readFile(locale); }); this.defaultLocale = opt.locales[0]; } // Set the locale to the default locale this.setLocale(this.defaultLocale); // Check the defaultLocale if (!this.locales[this.defaultLocale]) { console.error("Not a valid default locale."); } if (this.request) { if (this.subdomain) { this.setLocaleFromSubdomain(this.request); } if (this.query !== false) { this.setLocaleFromQuery(this.request); } if (this.session !== false) { this.setLocaleFromSessionVar(this.request); } this.prefLocale = this.preferredLocale(); if (this.prefLocale !== false && this.prefLocale !== this.locale) { this.setLocale(this.prefLocale); } } }
n/a
expressBind = function (app, opt) { if (!app) { return; } app.use(function (req, res, next) { opt.request = req; req.i18n = new i18n(opt); // Express 3 if (res.locals) { i18n.registerMethods(res.locals, req) } next(); }); // Express 2 if (app.dynamicHelpers) { app.dynamicHelpers(i18n.registerMethods({})); } }
...
## API:
### `new i18n(options)`
The `i18n` function is the return result from calling `require('i18n-2')`. You use this to instantiate an `I18n` instance
and set any configuration options. You'll probably only do this if you're not using the `expressBind` method.
### `i18n.expressBind(app, options)`
You'll use this method to attach the i18n functionality to the request object inside Express.js. The app argument should be
your Express.js app and the options argument should be the same as if you were calling `new i18n(options)`. See **"Using with
Express.js"** at the end of this README for more details.
### `__(string, [...])`
Translates a string according to the current locale. Also supports sprintf syntax, allowing you to replace text, using the node-
sprintf module.
...
registerMethods = function (helpers, req) { i18n.resMethods.forEach(function (method) { if (req) { helpers[method] = req.i18n[method].bind(req.i18n); } else { helpers[method] = function (req) { return req.i18n[method].bind(req.i18n); }; } }); return helpers; }
n/a
__ = function () { var msg = this.translate(this.locale, arguments[0]); if (arguments.length > 1) { msg = vsprintf(msg, Array.prototype.slice.call(arguments, 1)); } return msg; }
...
// Load Module and Instantiate
var i18n = new (require('i18n-2'))({
// setup some locales - other locales default to the first locale
locales: ['en', 'de']
});
// Use it however you wish
console.log( i18n.__("Hello!") );
## API:
### `new i18n(options)`
The `i18n` function is the return result from calling `require('i18n-2')`. You use this to instantiate an `I18n` instance
and set any configuration options. You'll probably only do this if you're not using the `expressBind` method.
...
__n = function (pathOrSingular, countOrPlural, additionalOrCount) { var msg; if (typeof countOrPlural === 'number') { var path = pathOrSingular; var count = countOrPlural; msg = this.translate(this.locale, path); msg = vsprintf(parseInt(count, 10) > 1 ? msg.other : msg.one, Array.prototype.slice.call(arguments, 1)); } else { var singular = pathOrSingular; var plural = countOrPlural; var count = additionalOrCount; msg = this.translate(this.locale, singular, plural); msg = vsprintf(parseInt(count, 10) > 1 ? msg.other : msg.one, [count]); if (arguments.length > 3) { msg = vsprintf(msg, Array.prototype.slice.call(arguments, 3)); } } return msg; }
...
i18n.__('foo.bar');
### `__n(one, other, count, [...])`
Different plural forms are supported as a response to `count`:
var singular = i18n.__n('%s cat', '%s cats', 1);
var plural = i18n.__n('%s cat', '%s cats', 3);
this gives you **1 cat** and **3 cats**. As with `__(...)` these could be nested:
var singular = i18n.__n('There is one monkey in the %%s', 'There are %d monkeys in the %%s', 1, 'tree
x27;);
var plural = i18n.__n('There is one monkey in the %%s', 'There are %d monkeys in the %%s', 3, 'tree'
;);
...
dump = function (data, indent) { return JSON.stringify(data, null, indent); }
n/a
getLocale = function () { return this.locale; }
n/a
initLocale = function (locale, data) { if (!this.locales[locale]) { this.locales[locale] = data; // Only cache the files when we're not in dev mode if (!this.devMode) { var file = this.locateFile(locale); if (!i18n.localeCache[file]) { i18n.localeCache[file] = data; } } } }
n/a
isPreferredLocale = function () { return !this.prefLocale || this.prefLocale === this.getLocale(); }
n/a
locateFile = function (locale) { return path.normalize(this.directory + '/' + locale + this.extension); }
n/a
function parse() { [native code] }
...
locales: ['at-de', 'de-de', 'at-en', 'de-en'],
base: function(locale) {
return locale.slice(-2);
}
### `parse(data, [indent])` and `dump(data)`
Optional custom methods to override `JSON.parse()` and `JSON.stringify()`, respectively
. One possible use for this is to allow for file formats other than JSON. For example:
var i18n = new (require('i18n-2'))({
locales: ['en', 'de'],
extension: '.yaml',
parse: function (data) {
return require('js-yaml').safeLoad(data);
},
...
preferredLocale = function (req) { req = req || this.request; if (!req || !req.headers) { return; } var accept = req.headers["accept-language"] || "", regExp = /(^|,\s*)([a-z0-9-]+)/gi, self = this, prefLocale; while (!prefLocale && (match = regExp.exec(accept))) { var locale = match[2].toLowerCase(); var parts = locale.split("-"); if (self.locales[locale]) { prefLocale = locale; } else if (parts.length > 1 && self.locales[parts[0]]) { prefLocale = parts[0]; } } return prefLocale || this.defaultLocale; }
n/a
readFile = function (locale) { var file = this.locateFile(locale); if (!this.devMode && i18n.localeCache[file]) { this.initLocale(locale, i18n.localeCache[file]); return; } try { var localeFile = fs.readFileSync(file); var base; // reading base file if 'base' provided if (typeof this.base === "function") { var baseFilename; try { baseFilename = this.base(locale); } catch (e) { console.error('base function threw exception for locale %s', locale, e); } if (typeof baseFilename === "string") { try { base = this.parse(fs.readFileSync(this.locateFile(baseFilename))); } catch (e) { console.error('unable to read or parse base file %s for locale %s', baseFilename, locale, e); } } } try { // parsing file content var content = this.parse(localeFile); if (base) { // writing content to the base and swapping for (var prop in content) { base[prop] = content[prop]; } content = base; } // putting content to locales[locale] this.initLocale(locale, content); } catch (e) { console.error('unable to parse locales from file (maybe ' + file + ' is empty or invalid ' + this.extension + '?): ', e); } } catch (e) { // unable to read, so intialize that file // locales[locale] are already set in memory, so no extra read required // or locales[locale] are empty, which initializes an empty locale.json file if (!fs.existsSync(file)) { this.writeFile(locale); } } }
n/a
setLocale = function (locale) { if (!locale) return; if (!this.locales[locale]) { if (this.devMode) { console.warn("Locale (" + locale + ") not found."); } locale = this.defaultLocale; } return (this.locale = locale); }
...
### `getLocale()`
Returns a string containing the current locale. If no locale has been specified then it default to the value specified in `defaultLocale
`.
### `setLocale(locale)`
Sets a locale to the specified string. If the locale is unknown, the locale defaults to the one specified by `defaultLocale`. For
example if you have locales of 'en' and 'de', and a `defaultLocale` of 'en', then call `.setLocale('ja')` it will be equivalent to calling `.setLocale('en')`.
### `setLocaleFromQuery([request])`
To be used with Express.js or another framework that provides a `request` object. Generally you would want to use this by setting
the `query` option to `true`.
This method takes in an Express.js request object, looks at the query property, and specifically at the `lang` parameter. Reading
the value of that parameter will then set the locale.
...
setLocaleFromCookie = function (req) { req = req || this.request; if (!req || !req.cookies || !this.cookieName || !req.cookies[this.cookieName]) { return; } var locale = req.cookies[this.cookieName].toLowerCase(); if (this.locales[locale]) { if (this.devMode) { console.log("Overriding locale from cookie: " + locale); } this.setLocale(locale); } }
...
// change the cookie name from 'lang' to 'locale'
cookieName: 'locale'
});
// This is how you'd set a locale from req.cookies.
// Don't forget to set the cookie either on the client or in your Express app.
app.use(function(req, res, next) {
req.i18n.setLocaleFromCookie();
next();
});
// Set up the rest of the Express middleware
app.use(app.router);
app.use(express.static(__dirname + '/public'));
...
setLocaleFromEnvironmentVariable = function () { if (!process.env.LANG) { return; } var locale = process.env.LANG.split("_")[0]; if (this.locales[locale]) { if (this.devMode) { console.log("Overriding locale from environment variable: " + locale); } this.setLocale(locale); } }
n/a
setLocaleFromQuery = function (req) { req = req || this.request; if (!req || !req.query || !req.query.lang) { return; } var locale = (req.query.lang+'').toLowerCase(); if (this.locales[locale]) { if (this.devMode) { console.log("Overriding locale from query: " + locale); } this.setLocale(locale); } }
n/a
setLocaleFromSessionVar = function (req) { req = req || this.request; if (!req || !req.session || !req.session[this.sessionVarName]) { return; } var locale = req.session[this.sessionVarName]; if (this.locales[locale]) { if (this.devMode) { console.log("Overriding locale from query: " + locale); } this.setLocale(locale); } }
n/a
setLocaleFromSubdomain = function (req) { req = req || this.request; if (!req || !req.headers || !req.headers.host) { return; } if (/^([^.]+)/.test(req.headers.host) && this.locales[RegExp.$1]) { if (this.devMode) { console.log("Overriding locale from host: " + RegExp.$1); } this.setLocale(RegExp.$1); } }
n/a
translate = function (locale, singular, plural) { if (!locale || !this.locales[locale]) { if (this.devMode) { console.warn("WARN: No locale found. Using the default (" + this.defaultLocale + ") as current locale"); } locale = this.defaultLocale; this.initLocale(locale, {}); } if (!this.locales[locale][singular]) { if (this.devMode) { dotNotation(this.locales[locale], singular, plural ? { one: singular, other: plural } : undefined); this.writeFile(locale); } } return dotNotation(this.locales[locale], singular, plural ? { one: singular, other: plural } : undefined); }
n/a
writeFile = function (locale) { // don't write new locale information to disk if we're not in dev mode if (!this.devMode) { // Initialize the locale if didn't exist already this.initLocale(locale, {}); return; } // creating directory if necessary try { fs.lstatSync(this.directory); } catch (e) { if (this.devMode) { console.log('creating locales dir in: ' + this.directory); } fs.mkdirSync(this.directory, 0755); } // Initialize the locale if didn't exist already this.initLocale(locale, {}); // writing to tmp and rename on success try { var target = this.locateFile(locale), tmp = target + ".tmp"; fs.writeFileSync(tmp, this.dump(this.locales[locale], this.indent), "utf8"); if (fs.statSync(tmp).isFile()) { fs.renameSync(tmp, target); } else { console.error('unable to write locales to file (either ' + tmp + ' or ' + target + ' are not writeable?): '); } } catch (e) { console.error('unexpected error writing files (either ' + tmp + ' or ' + target + ' are not writeable?): ', e); } }
n/a