mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-18 15:17:25 +01:00
181 lines
5.1 KiB
JavaScript
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);
|
|
};
|