Files
habitica/website/server/libs/api-v2/i18n.js

181 lines
5.1 KiB
JavaScript

var fs = require('fs'),
path = require('path'),
_ = require('lodash'),
User = require('../../models/user').model,
accepts = require('accepts'),
shared = require('../../../../common'),
translations = {};
var localePath = path.join(__dirname, "/../../../../common/locales/")
var loadTranslations = function(locale){
var files = fs.readdirSync(path.join(localePath, locale));
translations[locale] = {};
_.each(files, function(file){
if(path.extname(file) !== '.json') return;
_.merge(translations[locale], require(path.join(localePath, locale, file)));
});
};
// First fetch english so we can merge with missing strings in other languages
loadTranslations('en');
fs.readdirSync(localePath).forEach(function(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);
});
var langCodes = Object.keys(translations);
var avalaibleLanguages = _.map(langCodes, function(langCode){
return {
code: langCode,
name: translations[langCode].languageName
}
});
// Load MomentJS localization files
var momentLangs = {};
// Handle different language codes from MomentJS and /locales
var momentLangsMapping = {
'en': 'en-gb',
'en_GB': 'en-gb',
'no': 'nn',
'zh': 'zh-cn',
'es_419': 'es'
};
var momentLangs = {};
_.each(langCodes, function(code){
var lang = _.find(avalaibleLanguages, {code: 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
var f = fs.readFileSync(path.join(__dirname, '/../../node_modules/moment/locale/' + lang.momentLangCode + '.js'), 'utf8');
momentLangs[code] = f;
}catch (e){}
});
// Remove en_GB from langCodes checked by browser to avaoi it being
// used in place of plain original 'en'
var defaultLangCodes = _.without(langCodes, 'en_GB');
// A list of languages that have different versions
var multipleVersionsLanguages = ['es', 'zh'];
var latinAmericanSpanishes = {
'es-419': 'es_419',
'es-mx': 'es_419',
'es-gt': 'es_419',
'es-cr': 'es_419',
'es-pa': 'es_419',
'es-do': 'es_419',
'es-ve': 'es_419',
'es-co': 'es_419',
'es-pe': 'es_419',
'es-ar': 'es_419',
'es-ec': 'es_419',
'es-cl': 'es_419',
'es-uy': 'es_419',
'es-py': 'es_419',
'es-bo': 'es_419',
'es-sv': 'es_419',
'es-hn': 'es_419',
'es-ni': 'es_419',
'es-pr': 'es_419',
};
var chineseVersions = {
'zh-tw': 'zh_TW',
};
var getUserLanguage = function(req, res, next){
var getFromBrowser = function(){
var acceptedLanguages = accepts(req).languages();
var acceptable = _(acceptedLanguages).map(function(lang){
return lang.slice(0, 2);
}).uniq().value();
var matches = _.intersection(acceptable, defaultLangCodes);
var iAcceptedCompleteLang = (matches.length > 0) ? multipleVersionsLanguages.indexOf(matches[0].toLowerCase()) : -1;
if(iAcceptedCompleteLang !== -1){
var acceptedCompleteLang = _.find(acceptedLanguages, function(accepted){
return accepted.slice(0, 2) == multipleVersionsLanguages[iAcceptedCompleteLang];
});
if(acceptedCompleteLang){
acceptedCompleteLang = acceptedCompleteLang.toLowerCase();
}else{
return 'en';
}
if(matches[0] === 'es'){
return latinAmericanSpanishes[acceptedCompleteLang] || 'es';
}else if(matches[0] === 'zh'){
return chineseVersions[acceptedCompleteLang] || 'zh';
}else{
return en;
}
}else if(matches.length > 0){
return matches[0].toLowerCase();
}else{
return 'en';
}
};
var getFromUser = function(user){
var lang;
if(user && user.preferences.language && translations[user.preferences.language]){
lang = user.preferences.language;
}else{
var preferred = getFromBrowser();
lang = translations[preferred] ? preferred : 'en';
}
req.language = lang;
next();
};
if(req.query.lang){
req.language = translations[req.query.lang] ? (req.query.lang) : 'en';
next();
}else if(req.locals && req.locals.user){
getFromUser(req.locals.user);
}else if(req.session && req.session.userId){
User.findOne({_id: req.session.userId}, 'preferences.language', function(err, user){
if(err) return next(err);
getFromUser(user);
});
}else{
getFromUser(null);
}
};
shared.i18n.translations = translations;
module.exports = {
translations: translations,
avalaibleLanguages: avalaibleLanguages,
langCodes: langCodes,
getUserLanguage: getUserLanguage,
momentLangs: momentLangs
};
// Export en strings only, temporary solution for mobile
// This is copied from middlewares/locals#t()
module.exports.enTranslations = function(){ // stringName and vars are the allowed parameters
var language = _.find(avalaibleLanguages, {code: 'en'});
//language.momentLang = ((!isStaticPage && i18n.momentLangs[language.code]) || undefined);
var args = Array.prototype.slice.call(arguments, 0);
args.push(language.code);
return shared.i18n.t.apply(null, args);
};