port i18n lib to es6 and extract middleware
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import _ from 'lodash';
|
||||
import shared from '../../../../common';
|
||||
|
||||
const localePath = path.join(__dirname, '/../../../../common/locales/');
|
||||
|
||||
// Store translations
|
||||
export let translations = {};
|
||||
// Store MomentJS localization files
|
||||
export let momentLangs = {};
|
||||
|
||||
// Handle differencies in language codes between MomentJS and /locales
|
||||
let momentLangsMapping = {
|
||||
en: 'en-gb',
|
||||
en_GB: 'en-gb', // eslint-disable-line camelcase
|
||||
no: 'nn',
|
||||
zh: 'zh-cn',
|
||||
es_419: 'es', // eslint-disable-line camelcase
|
||||
};
|
||||
|
||||
function _loadTranslations (locale) {
|
||||
let files = fs.readdirSync(path.join(localePath, locale));
|
||||
|
||||
translations[locale] = {};
|
||||
|
||||
files.forEach((file) => {
|
||||
if (path.extname(file) !== '.json') return;
|
||||
|
||||
// We use require to load and parse a JSON file
|
||||
_.merge(translations[locale], require(path.join(localePath, locale, file))); // eslint-disable-line global-require
|
||||
});
|
||||
}
|
||||
|
||||
// First fetch English strings so we can merge them with missing strings in other languages
|
||||
_loadTranslations('en');
|
||||
|
||||
// Then load all other languages
|
||||
fs.readdirSync(localePath).forEach((file) => {
|
||||
if (file === 'en' || fs.statSync(path.join(localePath, file)).isDirectory() === false) return;
|
||||
_loadTranslations(file);
|
||||
|
||||
// Merge missing strings from english
|
||||
_.defaults(translations[file], translations.en);
|
||||
});
|
||||
|
||||
// Add translations to shared
|
||||
shared.i18n.translations = translations;
|
||||
|
||||
export let langCodes = Object.keys(translations);
|
||||
|
||||
export let avalaibleLanguages = langCodes.map((langCode) => {
|
||||
return {
|
||||
code: langCode,
|
||||
name: translations[langCode].languageName,
|
||||
};
|
||||
});
|
||||
|
||||
langCodes.forEach((code) => {
|
||||
let lang = _.find(avalaibleLanguages, {code});
|
||||
|
||||
lang.momentLangCode = momentLangsMapping[code] || code;
|
||||
|
||||
try {
|
||||
// MomentJS lang files are JS files that has to be executed in the browser so we load them as plain text files
|
||||
// We wrap everything in a try catch because the file might not exist
|
||||
let f = fs.readFileSync(path.join(__dirname, `/../../../node_modules/moment/locale/${lang.momentLangCode}.js`), 'utf8');
|
||||
|
||||
momentLangs[code] = f;
|
||||
} catch (e) { // eslint-disable-lint no-empty
|
||||
// TODO implement some type of error loggin?
|
||||
// The catch block is mandatory so can't be removed
|
||||
}
|
||||
});
|
||||
|
||||
// Remove en_GB from langCodes checked by browser to avoid it being
|
||||
// used in place of plain original 'en' (it's an optional language that can be enabled only in setting)
|
||||
export let defaultLangCodes = _.without(langCodes, 'en_GB');
|
||||
|
||||
// A map of languages that have different versions and the relative versions
|
||||
export let multipleVersionsLanguages = {
|
||||
es: ['es-419', 'es-mx', 'es-gt', 'es-cr', 'es-pa', 'es-do', 'es-ve', 'es-co', 'es-pe',
|
||||
'es-ar', 'es-ec', 'es-cl', 'es-uy', 'es-py', 'es-bo', 'es-sv', 'es-hn',
|
||||
'es-ni', 'es-pr'],
|
||||
zh: ['zh-tw'],
|
||||
};
|
||||
|
||||
// Export en strings only, temporary solution for mobile
|
||||
// This is copied from middlewares/locals#t()
|
||||
// TODO review if this can be removed since the old mobile app is no longer active
|
||||
// stringName and vars are the allowed parameters
|
||||
export function enTranslations (...args) {
|
||||
let language = _.find(avalaibleLanguages, {code: 'en'});
|
||||
|
||||
// language.momentLang = ((!isStaticPage && i18n.momentLangs[language.code]) || undefined);
|
||||
args.push(language.code);
|
||||
return shared.i18n.t(...args);
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
import { model as User } from '../../models/user';
|
||||
import accepts from 'accepts';
|
||||
import _ from 'lodash';
|
||||
import {
|
||||
translations,
|
||||
defaultLangCodes,
|
||||
multipleVersionsLanguages,
|
||||
} from '../../libs/api-v3/i18n';
|
||||
|
||||
function _getFromBrowser (req) {
|
||||
let acceptedLanguages = accepts(req).languages();
|
||||
|
||||
let acceptable = _(acceptedLanguages).map((lang) => {
|
||||
return lang.slice(0, 2);
|
||||
}).uniq().value();
|
||||
|
||||
let matches = _.intersection(acceptable, defaultLangCodes);
|
||||
|
||||
let iAcceptedCompleteLang = matches.length > 0 ? multipleVersionsLanguages.indexOf(matches[0].toLowerCase()) : -1;
|
||||
|
||||
if (iAcceptedCompleteLang !== -1) {
|
||||
let acceptedCompleteLang = _.find(acceptedLanguages, (accepted) => {
|
||||
return accepted.slice(0, 2) === multipleVersionsLanguages[iAcceptedCompleteLang];
|
||||
});
|
||||
|
||||
if (acceptedCompleteLang) {
|
||||
acceptedCompleteLang = acceptedCompleteLang.toLowerCase();
|
||||
} else {
|
||||
return 'en';
|
||||
}
|
||||
|
||||
if (matches[0] === 'es') {
|
||||
// In case of a Latin American version of Spanish use 'es_419'
|
||||
return multipleVersionsLanguages.es.indexOf(acceptedCompleteLang !== -1) ? 'es_419' : 'es';
|
||||
} else if (matches[0] === 'zh') {
|
||||
let iChinese = multipleVersionsLanguages.zh.indexOf(acceptedCompleteLang.toLowerCase());
|
||||
|
||||
return iChinese !== -1 ? multipleVersionsLanguages.zh[iChinese] : 'zh';
|
||||
} else {
|
||||
return 'en';
|
||||
}
|
||||
} else if (matches.length > 0) {
|
||||
return matches[0].toLowerCase();
|
||||
} else {
|
||||
return 'en';
|
||||
}
|
||||
}
|
||||
|
||||
function _getFromUser (user, req) {
|
||||
let lang;
|
||||
|
||||
if (user && user.preferences.language && translations[user.preferences.language]) {
|
||||
lang = user.preferences.language;
|
||||
} else {
|
||||
let preferred = _getFromBrowser(req);
|
||||
|
||||
lang = translations[preferred] ? preferred : 'en';
|
||||
}
|
||||
|
||||
return lang;
|
||||
}
|
||||
|
||||
export default function getUserLanguage (req, res, next) {
|
||||
if (req.query.lang) { // In case the language is specified in the request url, use it
|
||||
req.language = translations[req.query.lang] ? req.query.lang : 'en';
|
||||
return next();
|
||||
} else if (req.locals && req.locals.user) { // If the request is authenticated, use the user's preferred language
|
||||
req.language = _getFromUser(req.locals.user, req);
|
||||
return next();
|
||||
} else if (req.session && req.session.userId) { // Same thing if the user has a valid session
|
||||
User
|
||||
.findOne({
|
||||
_id: req.session.userId,
|
||||
}, 'preferences.language')
|
||||
.exec()
|
||||
.then((user) => {
|
||||
req.language = _getFromUser(user, req);
|
||||
return next();
|
||||
})
|
||||
.catch(next);
|
||||
} else { // Otherwise get from browser
|
||||
req.language = _getFromUser(null, req);
|
||||
return next();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user