lets user change languages,
v1.18.x
barisusakli 11 years ago
parent 98b112bb36
commit 3e60451ce4

@ -69,5 +69,6 @@
"invisible": "Invisible",
"offline": "Offline",
"privacy": "Privacy"
"privacy": "Privacy",
"language": "Language"
}

@ -178,7 +178,7 @@ var ajaxify = ajaxify || {};
}
data.relative_path = RELATIVE_PATH;
templates.parse(tpl_url, data, function(template) {
translator.translate(template, function(translatedTemplate) {
$('#content').html(translatedTemplate);

@ -7,16 +7,21 @@ define(['forum/accountheader'], function(header) {
$('#submitBtn').on('click', function() {
var settings = {};
$('.account input, .account textarea').each(function(id, input) {
$('.account').find('input, textarea, select').each(function(id, input) {
input = $(input);
var setting = input.attr('data-property');
if (input.is('select')) {
settings[setting] = input.val();
return;
}
switch (input.attr('type')) {
case 'text' :
case 'textarea' :
settings[input.attr('data-property')] = input.val();
settings[setting] = input.val();
break;
case 'checkbox' :
settings[input.attr('data-property')] = input.is(':checked') ? 1 : 0;
settings[setting] = input.is(':checked') ? 1 : 0;
break;
}
});
@ -32,9 +37,16 @@ define(['forum/accountheader'], function(header) {
});
socket.emit('user.getSettings', function(err, settings) {
for (var setting in settings) {
if (settings.hasOwnProperty(setting)) {
var input = $('.account input[data-property="' + setting + '"]');
var inputs = $('.account').find('input, textarea, select');
inputs.each(function(index, input) {
input = $(input);
var setting = input.attr('data-property');
if (setting) {
if (input.is('select')) {
input.val(settings[setting]);
return;
}
switch (input.attr('type')) {
case 'text' :
@ -46,7 +58,7 @@ define(['forum/accountheader'], function(header) {
break;
}
}
}
});
});
};

@ -4,17 +4,15 @@
var translator = {},
files = {
loaded: {},
loading: {},
callbacks: {} // could be combined with "loading" in future.
};
languages = {};
module.exports = translator;
// Use this in plugins to add your own translation files.
translator.addTranslation = function(filename, translations) {
files.loaded[filename] = translations;
translator.addTranslation = function(language, filename, translations) {
languages[language] = languages[language] || {};
languages[language].loaded = languages[language].loaded || {};
languages[language].loaded[filename] = translations;
};
translator.getLanguage = function() {
@ -67,11 +65,21 @@
}
};
translator.translate = function (data, callback) {
translator.translate = function (data, language, callback) {
if (!data) {
return callback(data);
}
if (typeof language === 'function') {
callback = language;
if ('undefined' !== typeof window && config) {
language = config.defaultLang || 'en_GB';
} else {
var meta = require('../../src/meta');
language = meta.config.defaultLang || 'en_GB';
}
}
function insertLanguage(text, key, value, variables) {
if (value) {
for (var i = 1, ii = variables.length; i < ii; i++) {
@ -109,12 +117,12 @@
var languageFile = parsedKey[0];
parsedKey = ('' + parsedKey[1]).split(',')[0];
if (files.loaded[languageFile]) {
data = insertLanguage(data, key, files.loaded[languageFile][parsedKey], variables);
if (isLanguageFileLoaded(language, languageFile)) {
data = insertLanguage(data, key, languages[language].loaded[languageFile][parsedKey], variables);
} else {
loading++;
(function (languageKey, parsedKey, languageFile, variables) {
translator.load(languageFile, function (languageData) {
translator.load(language, languageFile, function (languageData) {
data = insertLanguage(data, languageKey, languageData[parsedKey], variables);
loading--;
checkComplete();
@ -132,61 +140,73 @@
}
};
translator.clearLoadedFiles = function() {
files.loaded = {};
files.loading = {};
};
translator.load = function (filename, callback) {
translator.load = function (language, filename, callback) {
if (files.loaded[filename] && !files.loading[filename]) {
if (isLanguageFileLoaded(language, filename)) {
if (callback) {
callback(files.loaded[filename]);
callback(languages[language].loaded[filename]);
}
} else if (files.loading[filename]) {
} else if (isLanguageFileLoading(language, filename)) {
if (callback) {
files.callbacks[filename] = files.callbacks[filename] || [];
files.callbacks[filename].push(callback);
addLanguageFileCallback(language, filename, callback);
}
} else {
files.loading[filename] = true;
languages[language] = languages[language] || {loading: {}, loaded: {}, callbacks: []};
languages[language].loading[filename] = true;
load(language, filename, function(translations) {
load(filename, function(language) {
files.loaded[filename] = language;
languages[language].loaded[filename] = translations;
if (callback) {
callback(language);
callback(translations);
}
while (files.callbacks[filename] && files.callbacks[filename].length) {
files.callbacks[filename].pop()(language);
while (languages[language].callbacks[filename] && languages[language].callbacks[filename].length) {
languages[language].callbacks[filename].pop()(translations);
}
files.loading[filename] = false;
languages[language].loading[filename] = false;
});
}
};
function load(filename, callback) {
function isLanguageFileLoaded(language, filename) {
var languageObj = languages[language];
return languageObj && languageObj.loaded && languageObj.loaded[filename] && !languageObj.loading[filename];
}
function isLanguageFileLoading(language, filename) {
return languages[language] && languages[language].loading && languages[language].loading[filename];
}
function addLanguageFileCallback(language, filename, callback) {
languages[language].callbacks = languages[language].callbacks || {};
languages[language].callbacks[filename] = languages[language].callbacks[filename] || [];
languages[language].callbacks[filename].push(callback);
}
function load(language, filename, callback) {
if ('undefined' !== typeof window) {
loadClient(filename, callback);
loadClient(language, filename, callback);
} else {
loadServer(filename, callback);
loadServer(language, filename, callback);
}
}
function loadClient(filename, callback) {
function loadClient(language, filename, callback) {
var timestamp = new Date().getTime();
$.getJSON(config.relative_path + '/language/' + config.defaultLang + '/' + filename + '.json?v=' + timestamp, callback);
$.getJSON(config.relative_path + '/language/' + language + '/' + filename + '.json?v=' + timestamp, callback);
}
function loadServer(filename, callback) {
function loadServer(language, filename, callback) {
var fs = require('fs'),
path = require('path'),
winston = require('winston'),
meta = require('../../src/meta'),
language = meta.config.defaultLang || 'en_GB';
meta = require('../../src/meta');
if (!fs.existsSync(path.join(__dirname, '../language', language))) {
winston.warn('[translator] Language \'' + meta.config.defaultLang + '\' not found. Defaulting to \'en_GB\'');

@ -15,6 +15,7 @@ var fs = require('fs'),
utils = require('./../../public/src/utils'),
meta = require('./../meta'),
plugins = require('./../plugins'),
languages = require('./../languages'),
image = require('./../image'),
file = require('./../file');
@ -331,22 +332,29 @@ accountsController.accountSettings = function(req, res, next) {
return next(err);
}
user.getUserFields(uid, ['username', 'userslug'], function(err, userData) {
async.parallel({
user: function(next) {
user.getUserFields(uid, ['username', 'userslug'], next);
},
languages: function(next) {
languages.list(next);
}
}, function(err, results) {
if (err) {
return next(err);
}
if(!userData) {
if(!results.user) {
return userNotFound();
}
userData.yourid = req.user.uid;
userData.theirid = uid;
userData.settings = settings;
res.render('accountsettings', userData);
results.user.yourid = req.user.uid;
results.user.theirid = uid;
results.user.settings = settings;
res.render('accountsettings', results);
});
});
});
};

@ -58,6 +58,7 @@ apiController.getConfig = function(req, res, next) {
config.topicsPerPage = settings.topicsPerPage;
config.postsPerPage = settings.postsPerPage;
config.notificationSounds = settings.notificationSounds;
config.defaultLang = settings.language || config.defaultLang;
if (res.locals.isAPI) {
res.json(200, config);

@ -63,11 +63,6 @@ var fs = require('fs'),
callback(err, res);
}
// this might be a good spot to add a hook
if (field === 'defaultLang') {
translator.clearLoadedFiles();
}
});
},
setOnEmpty: function (field, value, callback) {
@ -173,10 +168,8 @@ var fs = require('fs'),
isTopic: /^topic\/\d+\/?/,
isUserPage: /^user\/[^\/]+(\/[\w]+)?/
},
build: function (urlFragment, callback) {
var user = require('./user');
Meta.title.parseFragment(decodeURIComponent(urlFragment), function(err, title) {
build: function (urlFragment, language, callback) {
Meta.title.parseFragment(decodeURIComponent(urlFragment), language, function(err, title) {
if (err) {
title = Meta.config.browserTitle || 'NodeBB';
} else {
@ -186,14 +179,14 @@ var fs = require('fs'),
callback(null, title);
});
},
parseFragment: function (urlFragment, callback) {
parseFragment: function (urlFragment, language, callback) {
var translated = ['', 'recent', 'unread', 'users', 'notifications'];
if (translated.indexOf(urlFragment) !== -1) {
if (!urlFragment.length) {
urlFragment = 'home';
}
translator.translate('[[pages:' + urlFragment + ']]', function(translated) {
translator.translate('[[pages:' + urlFragment + ']]', language, function(translated) {
callback(null, translated);
});
} else if (this.tests.isCategory.test(urlFragment)) {
@ -215,7 +208,7 @@ var fs = require('fs'),
User.getUsernameByUserslug(userslug, function(err, username) {
if (subpage) {
translator.translate('[[pages:user.' + subpage + ', ' + username + ']]', function(translated) {
translator.translate('[[pages:user.' + subpage + ', ' + username + ']]', language, function(translated) {
callback(null, translated);
});
} else {

@ -143,30 +143,31 @@ middleware.checkAccountPermissions = function(req, res, next) {
};
middleware.buildHeader = function(req, res, next) {
async.parallel([
function(next) {
res.locals.renderHeader = true;
next();
},
function(next) {
controllers.api.getConfig(req, res, function(err, config) {
res.locals.config = config;
next(err);
});
res.locals.renderHeader = true;
async.parallel({
config: function(next) {
controllers.api.getConfig(req, res, next);
},
function(next) {
// consider caching this, since no user specific information is loaded here
app.render('footer', {}, function(err, template) {
translator.translate(template, function(parsedTemplate) {
res.locals.footer = parsedTemplate;
next(err);
});
});
footer: function(next) {
app.render('footer', {}, next);
}
}, function(err, results) {
if (err) {
return next(err);
}
], next);
res.locals.config = results.config;
translator.translate(results.footer, results.config.defaultLang, function(parsedTemplate) {
res.locals.footer = parsedTemplate;
next();
});
});
};
middleware.renderHeader = function(req, res, callback) {
var uid = req.user ? parseInt(req.user.uid, 10) : 0;
var custom_header = {
'navigation': []
};
@ -218,8 +219,6 @@ middleware.renderHeader = function(req, res, callback) {
}
}
var uid = '0';
templateValues.metaTags = defaultMetaTags.concat(res.locals.metaTags || []).map(function(tag) {
if(!tag || typeof tag.content !== 'string') {
winston.warn('Invalid meta tag. ', tag);
@ -239,9 +238,6 @@ middleware.renderHeader = function(req, res, callback) {
href: nconf.get('relative_path') + '/favicon.ico'
});
if(req.user && req.user.uid) {
uid = req.user.uid;
}
templateValues.useCustomCSS = false;
if (meta.config.useCustomCSS === '1') {
@ -249,34 +245,30 @@ middleware.renderHeader = function(req, res, callback) {
templateValues.customCSS = meta.config.customCSS;
}
async.parallel([
function(next) {
translator.translate('[[pages:' + path.basename(req.url) + ']]', function(translated) {
var metaTitle = templateValues.metaTags.filter(function(tag) {
return tag.name === 'title';
});
if (translated) {
templateValues.browserTitle = translated;
} else if (metaTitle.length > 0 && metaTitle[0].content) {
templateValues.browserTitle = metaTitle[0].content;
} else {
templateValues.browserTitle = meta.config.browserTitle || 'NodeBB';
}
next();
});
async.parallel({
title: function(next) {
if (uid) {
user.getSettings(uid, function(err, settings) {
if (err) {
return next(err);
}
meta.title.build(req.url.slice(1), settings.language, next);
});
} else {
meta.title.build(req.url.slice(1), meta.config.defaultLang, next);
}
},
function(next) {
user.isAdministrator(uid, function(err, isAdmin) {
templateValues.isAdmin = isAdmin || false;
next();
});
isAdmin: function(next) {
user.isAdministrator(uid, next);
}
], function() {
app.render('header', templateValues, function(err, template) {
callback(null, template);
});
}, function(err, results) {
if (err) {
return next(err);
}
templateValues.browserTitle = results.title;
templateValues.isAdmin = results.isAdmin || false;
app.render('header', templateValues, callback);
});
});
};
@ -322,7 +314,7 @@ middleware.processRender = function(req, res, next) {
middleware.renderHeader(req, res, function(err, template) {
str = template + str;
translator.translate(str, function(translated) {
translator.translate(str, res.locals.config.defaultLang, function(translated) {
fn(err, translated);
});
});

@ -32,7 +32,16 @@ SocketMeta.reconnected = function(socket) {
};
SocketMeta.buildTitle = function(socket, text, callback) {
meta.title.build(text, callback);
if (socket.uid) {
user.getSettings(socket.uid, function(err, settings) {
if (err) {
return callback(err);
}
meta.title.build(text, settings.language, callback);
});
} else {
meta.title.build(text, meta.config.defaultLang, callback);
}
};
SocketMeta.updateHeader = function(socket, data, callback) {

@ -29,6 +29,7 @@ module.exports = function(User) {
settings.topicsPerPage = settings.topicsPerPage ? parseInt(settings.topicsPerPage, 10) : parseInt(meta.config.topicsPerPage, 10) || 20;
settings.postsPerPage = settings.postsPerPage ? parseInt(settings.postsPerPage, 10) : parseInt(meta.config.postsPerPage, 10) || 10;
settings.notificationSounds = settings.notificationSounds ? parseInt(settings.notificationSounds, 10) === 1 : true;
settings.language = settings.language || meta.config.defaultLang || 'en_GB';
callback(null, settings);
});
});
@ -47,7 +48,8 @@ module.exports = function(User) {
usePagination: data.usePagination,
topicsPerPage: data.topicsPerPage,
postsPerPage: data.postsPerPage,
notificationSounds: data.notificationSounds
notificationSounds: data.notificationSounds,
language: data.language || meta.config.defaultLang
}, callback);
};
};
Loading…
Cancel
Save