Simplify server-side i18n code and make it a bit more understandable

This commit is contained in:
Marcel Klehr 2012-12-19 21:16:29 +01:00
parent 4a489f85f6
commit cf24e53eae

View file

@ -4,90 +4,70 @@ var languages = require('languages4translatewiki')
, express = require('express') , express = require('express')
, _ = require('underscore') , _ = require('underscore')
, npm = require('npm') , npm = require('npm')
, plugins = require('ep_etherpad-lite/static/js/pluginfw/plugins.js').plugins
; ;
/*
* PRIVATE
*/
// locales will store all locales ini files merged (core+plugins) in RAM
var locales = {};
//explore recursive subdirectories from root and execute callback
//don't explore symbolic links
var exploreDir = function (root, callback) {
var stat = fs.lstatSync(root);
if (stat.isDirectory() && !stat.isSymbolicLink()) {
var names = fs.readdirSync(root),
subdirs = [],
files = [];
names.forEach (function(file) {
file = path.resolve(root,file);
stat = fs.lstatSync(file);
if (stat.isDirectory() && !stat.isSymbolicLink()) {
subdirs.push(file);
} else {
files.push(file);
}
});
callback(root, subdirs, files);
subdirs.forEach(function (d) {
exploreDir(d, callback);
});
}
};
// return all files languages absolute path group by langcode // return all files languages absolute path group by langcode
// {es: [pathcore, pathplugin1...], en:...} // {es: [pathcore, pathplugin1...], en:...}
var getAllLocalesPaths = function () { function getAllLocales() {
var result = {}; var locales2paths = {};
// Puts the paths of all locale files contained in a given directory
// into `results` (files from various dirs are grouped by lang code)
// (only json files with valid language code as name)
function extractLangs(dir) {
var stat = fs.lstatSync(dir);
if (!stat.isDirectory() || stat.isSymbolicLink()) return;
fs.readdirSync(dir).forEach(function(file) {
file = path.resolve(dir, file);
stat = fs.lstatSync(file);
if (stat.isDirectory() || stat.isSymbolicLink()) return;
var ext = path.extname(file)
, locale = path.basename(file, ext).toLowerCase();
//extract only files paths with name is a supported language code and have json extension
var extractLangs = function (root, subdirs, files) {
_.each(files, function(file) {
var ext = path.extname(file),
locale = path.basename(file, ext).toLowerCase();
if ((ext == '.json') && languages.isValid(locale)) { if ((ext == '.json') && languages.isValid(locale)) {
if (!(_.has(result, locale))) result[locale] = []; if(!locales2paths[locale]) locales2paths[locale] = [];
result[locale].push(file); locales2paths[locale].push(file);
} }
}); });
} }
//add core supported languages first //add core supported languages first
exploreDir (npm.root+"/ep_etherpad-lite/locales", extractLangs); extractLangs(npm.root+"/ep_etherpad-lite/locales");
//add plugins languages (if any) -- bad practice //add plugins languages (if any)
exploreDir (npm.root, extractLangs); for(var pluginName in plugins) extractLangs(path.join(npm.root, pluginName, 'locales'));
return result; // Build a locale index (merge all locale data)
} var locales = {}
_.each (locales2paths, function(files, langcode) {
locales[langcode]={};
//save in locales all json files merged by language code files.forEach(function(file) {
var getAllLocales = function () { var fileContents = JSON.parse(fs.readFileSync(file,'utf8'));
_.each (getAllLocalesPaths(), function(files, langcode) { _.extend(locales[langcode], fileContents[langcode]);
locales[langcode]={}
_.each (files, function(file) {
_.extend(locales[langcode], JSON.parse(fs.readFileSync(file,'utf8'))[langcode]);
}); });
}); });
return locales;
} }
//return all languages availables with nativeName and direction // returns a hash of all available languages availables with nativeName and direction
//{es: {nativeName: "español", direction: "ltr"},...} // e.g. { es: {nativeName: "español", direction: "ltr"}, ... }
var getAvailableLangs = function () { function getAvailableLangs(locales) {
var result = {}; var result = {};
if (_.isEmpty(locales)) getAllLocales();
_.each(_.keys(locales), function(langcode) { _.each(_.keys(locales), function(langcode) {
result[langcode]=languages.getLanguageInfo(langcode); result[langcode] = languages.getLanguageInfo(langcode);
}); });
return result; return result;
} }
//return locale index that will be served in /locales.json // returns locale index that will be served in /locales.json
var generateLocaleIndex = function () { var generateLocaleIndex = function (locales) {
if (_.isEmpty(locales)) getAllLocales(); var result = _.clone(locales) // keep English strings
var result = _.clone(locales);
_.each(_.keys(locales), function(langcode) { _.each(_.keys(locales), function(langcode) {
if (langcode != 'en') result[langcode]='locales/'+langcode+'.json'; if (langcode != 'en') result[langcode]='locales/'+langcode+'.json';
}); });
@ -95,16 +75,12 @@ var generateLocaleIndex = function () {
} }
/*
* PUBLIC
*/
exports.expressCreateServer = function(n, args) { exports.expressCreateServer = function(n, args) {
//regenerate locales when server restart //regenerate locales on server restart
locales = {}; var locales = getAllLocales();
var localeIndex = generateLocaleIndex(); var localeIndex = generateLocaleIndex(locales);
exports.availableLangs = getAvailableLangs(); exports.availableLangs = getAvailableLangs(locales);
args.app.get ('/locales/:locale', function(req, res) { args.app.get ('/locales/:locale', function(req, res) {
//works with /locale/en and /locale/en.json requests //works with /locale/en and /locale/en.json requests