diff --git a/lib/i18n.js b/lib/i18n.js index da6164a279e312dc39a08792d7af3a69778e586b..314049da3d05c2c3b57575a1e8386def64b801d5 100644 --- a/lib/i18n.js +++ b/lib/i18n.js @@ -22,6 +22,8 @@ var logger = require('./logging.js').logger, const BIDI_RTL_LANGS = ['ar', 'db-LB', 'fa', 'he']; +var mo_cache = {}; + /** * Connect middleware which is i18n aware. * @@ -40,18 +42,44 @@ exports.abide = function (options) { if (! options.ngettext_alias) options.ngettext_alias = 'ngettext'; if (! options.supported_languages) options.supported_languages = ['en-US']; if (! options.default_lang) options.default_lang = 'en-US'; + if (! options.debug_lang) options.debug_lang = 'it-CH'; if (! options.locale_directory) options.locale_directory = 'locale'; + var mo_file_path = function (locale) { + return path.resolve( + path.join(__dirname, '..'), + options.locale_directory, + path.join(locale, 'LC_MESSAGES', 'messages.mo')); + }; + + options.supported_languages.forEach(function (lang, i) { + var l = localeFrom(lang); + + mo_cache[l] = { + exists: path.existsSync(mo_file_path(l)), + gt: null + }; + + if (! mo_cache[l].exists && l !== 'it_CH') { + var msg = util.format('Bad locale=[%s] mo file does not exist: [%s]. See locale/README', l, mo_file_path(l)); + if (l == 'en_US') { + logger.warn(msg); + } else { + logger.error(msg); + throw msg; + } + } + }); + return function(req, resp, next) { var langs = parseAcceptLanguage(req.headers['accept-language']), lang_dir, lang = bestLanguage(langs, options.supported_languages, options.default_lang), + debug_lang = options.debug_lang.toLowerCase(), locale; - // TODO(aok): Check if we're not in production mode before switching eo to db-LB - // Must fix before Esperanto could ship. - if (lang && lang.toLowerCase && lang.toLowerCase() == 'it-ch') { + if (lang && lang.toLowerCase && lang.toLowerCase() == debug_lang) { lang = 'db-LB'; // What? http://www.youtube.com/watch?v=rJLnGjhPT1Q } @@ -63,35 +91,28 @@ exports.abide = function (options) { req.lang = lang; locale = localeFrom(lang); + resp.local('locale', locale); req.locale = locale; - // Thread saftey, app startup or per request? - gt = new Gettext(); - - // Figure out where the mofile should live, and support absolute or - // relative paths - mo_path = path.resolve( - path.join(__dirname, '..'), - options.locale_directory, - path.join(locale, 'LC_MESSAGES', 'messages.mo')); - resp.local('format', format); req.format = format; - if (path.existsSync(mo_path)) { - gt.addTextdomain(locale, fs.readFileSync(mo_path)); - - // Per request ??? - gt.textdomain(locale); + if (mo_cache[locale].exists) { + if (mo_cache[locale].gt === null) { + mo_cache[locale].gt = new Gettext(); + mo_path = mo_file_path(locale); + mo_cache[locale].gt.addTextdomain(locale, + fs.readFileSync(mo_path)); + mo_cache[locale].gt.textdomain(locale); + } + var gt = mo_cache[locale].gt; resp.local(options.gettext_alias, gt.gettext.bind(gt)); req.gettext = gt.gettext.bind(gt); resp.local(options.ngettext_alias, gt.ngettext.bind(gt)); req.ngettext = gt.ngettext.bind(gt); } else { - // TODO if in development mode, warn, test ignore and production error - /* logger.error('Bad language=' + lang + ' or locale=' + locale + - ' mo file does not exist. [' + mo_path + ']'); */ + // en-US in a non gettext environment... fake it var identity = function (a, b) { return a; }; resp.local(options.gettext_alias, identity); req.gettext = identity;