UNPKG

sails

Version:

API-driven framework for building realtime apps, using MVC conventions (based on Express and Socket.io)

211 lines (161 loc) 8.29 kB
module.exports = function(sails) { /** * Module dependencies. */ var util = require('util'); var path = require('path'); var _ = require('@sailshq/lodash'); var i18nFactory = require('i18n-2'); // The file extension for locales files (e.g. in config/locales/) var I18N_LOCALES_FILE_EXTENSION = '.json'; // Declare a var to hold the hook's singleton i18n instance. // (if we're unable to initialize this hook properly and we skip it, // then this will still be set to `undefined`) var i18n; // Hold the resolved absolute path to the configured locales dir. // (if we're unable to initialize this hook properly and we skip it, // then this will still be set to `undefined`) var resolvedLocalesDirectory; /** * Expose hook definition */ return { defaults: { // i18n i18n: { locales: [], // ^^this is just the implicit default (is overridden by boilerplate settings in `config/i18n.js`) defaultLocale: 'en', localesDirectory: 'config/locales/' } }, configure: function() { if (!_.isArray(sails.config.i18n.locales)) { throw new Error('`sails.config.i18n.locales` must be an array of strings like [\'en\', \'es\'], but instead got: '+util.inspect(sails.config.i18n.locales, {depth:null})+''); } if (!sails.config.i18n.localesDirectory || !_.isString(sails.config.i18n.localesDirectory)) { throw new Error('`sails.config.i18n.localesDirectory` must be a string like "config/locales/". But, instead got: '+util.inspect(sails.config.i18n.localesDirectory, {depth:null})+''); } // If we have a default locale config, and it exists in the list of configured locales, // move it to the top of the list. This is a workaround for https://github.com/jeresig/i18n-node-2/issues/90 if (sails.config.i18n.defaultLocale && sails.config.i18n.locales && _.contains(sails.config.i18n.locales, sails.config.i18n.defaultLocale)) { sails.config.i18n.locales = [sails.config.i18n.defaultLocale].concat(_.without(sails.config.i18n.locales, sails.config.i18n.defaultLocale)); } }, initialize: function(cb) { var self = this; // If the array of locales is empty, then bail out now. // (There's nothing for us to do in this hook.) if (sails.config.i18n.locales.length === 0) { sails.log.verbose('Skipping i18n hook because configured locales (`sails.config.i18n.locales`) is an empty array.'); // Delete sails.hooks.i18n so that checks like `if (sails.hooks.i18n)` come back falsey. delete sails.hooks.i18n; // Add __ and i18n functions that just pass through the string (and return a warning). sails.__ = sails.i18n = function(str) { sails.log.warn('i18n hook has disabled itself due to misconfiguration -- returning input string as-is. Set `sails.config.i18n.locales` to activate i18n.'); return str; }; // Add passthru __ and i18n to res.locals. sails.on('router:before', function () { sails.router.bind('all /*', function addLocalizationMethod (req, res, next) { res.locals.__ = res.locals.i18n = sails.__; return next(); }); });//</sails.on> return cb(); }//-• // Determine the abs path to the locales dir, resolving relative from the appPath. // (supports absolute or relative path) resolvedLocalesDirectory = path.resolve(sails.config.appPath, sails.config.i18n.localesDirectory); // Override logger while initializing i18n-2, since it uses console function directly. // We'll just buffer any messages and replay them when i18n-2 is done (or fails) initializing. var logs = []; var warns = []; var errors = []; var origLog = console.log; var origWarn = console.warn; var origError = console.error; console.log = function() {logs.push(Array.prototype.slice.call(arguments));}; console.warn = function() {warns.push(Array.prototype.slice.call(arguments));}; console.error = function() {errors.push(Array.prototype.slice.call(arguments));}; // Attempt to initialize i18n. This will fail if there's no `config/locales` directory. try { i18n = new i18nFactory({ locales: sails.config.i18n.locales, defaultLocale: sails.config.i18n.defaultLocale, directory: resolvedLocalesDirectory, extension: I18N_LOCALES_FILE_EXTENSION }); // Add all of the i18n prototype methods into this hook. _.each(i18nFactory.prototype, function(val, key) { if (_.isFunction(val)) { self[key] = i18n[key].bind(i18n); } }); // Expose global access to locale strings sails.__ = self.__; sails.i18n = self.__; } catch (e) { sails.log.error('Failed to initialize i18n hook. (Tip: Does the ' + resolvedLocalesDirectory + ' directory exist?)'); sails.log.error(e.stack); return cb(e); } // Restore the original console logger functions, and then // replay any logs that were generated while trying to init i18n-2. console.log = origLog; console.warn = origWarn; console.error = origError; _.each(logs, function(log) {sails.log.verbose.apply(this, log);}); _.each(warns, function(warn) {sails.log.warn.apply(this, warn);}); _.each(errors, function(error) {sails.log.error.apply(this, error);}); // When Sails is ready to bind "before" shadow routes, bind a shadow route that // adds the localization methods and locals. sails.on('router:before', function (){ sails.router.bind('all /*', function addLocalizationMethod (req, res, next) { return sails.hooks.i18n.expressMiddleware(req, res, next); }); });//</sails.on> // Finally, call the callback to indicate that the hook is done initializing. return cb(); }, // Express middleware that adds translation capabilities (e.g. the __ function) // to the `res` object. Useful mainly for doing internationalization in views. expressMiddleware: function (req, res, next) { // If we don't have res.locals, we don't have anything to mix i18n options onto. if (!res.locals) { return next(new Error('Provided `res` must contain `res.locals`.')); } // If we weren't able to initialize the singleton i18n module, then we // should never have made it here. if (!i18n) { return next(new Error('Consistency violation: This should never happen -- sails.hooks.i18n.expressMiddleware should never be available if i18n could not be initialized.')); } // Try to create a new i18n instance. This is necessary because // locale is set on a per-instance basis, and the request header // may change the locale for a given instance (but we wouldn't // want it to change for the instance connected to `sails.__()` ) try { req.i18n = new i18nFactory({ locales: sails.config.i18n.locales, defaultLocale: sails.config.i18n.defaultLocale, directory: resolvedLocalesDirectory, extension: I18N_LOCALES_FILE_EXTENSION, request: req }); // Mix translation capabilities into res.locals. i18nFactory.registerMethods(res.locals, req); // Add `setLocale()` method for convenience. // (This is documented and fully supported as of Sails v1.0 and beyond.) req.setLocale = req.i18n.setLocale.bind(req.i18n); // For backwards compatibility: // • Add `i18n` method as alias to `__` // • Add `getLocale()` method to `req` res.locals.i18n = res.locals.__; req.getLocale = req.i18n.getLocale.bind(req.i18n); } catch (e) { // Seeing as we have a valid i18n singleton already, the // initialization failing now seems more serious, but we // still don't want to crash because of it. // We should at least log the error though. sails.log.error('Error attaching i18n to response:'); sails.log.error(e); } // Continue processing the request. return next(); }, }; };