2021-01-21 22:06:52 +01:00
|
|
|
'use strict';
|
|
|
|
|
2020-11-23 19:24:19 +01:00
|
|
|
const languages = require('languages4translatewiki');
|
|
|
|
const fs = require('fs');
|
|
|
|
const path = require('path');
|
|
|
|
const _ = require('underscore');
|
|
|
|
const npm = require('npm');
|
2021-01-21 22:06:52 +01:00
|
|
|
const plugins = require('../../static/js/pluginfw/plugin_defs.js').plugins;
|
2020-11-23 19:24:19 +01:00
|
|
|
const existsSync = require('../utils/path_exists');
|
2021-01-21 22:06:52 +01:00
|
|
|
const settings = require('../utils/Settings');
|
2012-11-28 23:54:23 +01:00
|
|
|
|
2012-12-23 22:43:32 +01:00
|
|
|
// returns all existing messages merged together and grouped by langcode
|
|
|
|
// {es: {"foo": "string"}, en:...}
|
2021-01-21 22:06:52 +01:00
|
|
|
const getAllLocales = () => {
|
2020-11-23 19:24:19 +01:00
|
|
|
const locales2paths = {};
|
2012-12-19 21:16:29 +01:00
|
|
|
|
|
|
|
// Puts the paths of all locale files contained in a given directory
|
2012-12-23 22:43:32 +01:00
|
|
|
// into `locales2paths` (files from various dirs are grouped by lang code)
|
2012-12-19 21:16:29 +01:00
|
|
|
// (only json files with valid language code as name)
|
2021-01-21 22:06:52 +01:00
|
|
|
const extractLangs = (dir) => {
|
2020-11-23 19:24:19 +01:00
|
|
|
if (!existsSync(dir)) return;
|
|
|
|
let stat = fs.lstatSync(dir);
|
2012-12-19 21:16:29 +01:00
|
|
|
if (!stat.isDirectory() || stat.isSymbolicLink()) return;
|
|
|
|
|
2020-11-23 19:24:19 +01:00
|
|
|
fs.readdirSync(dir).forEach((file) => {
|
2012-12-19 21:16:29 +01:00
|
|
|
file = path.resolve(dir, file);
|
|
|
|
stat = fs.lstatSync(file);
|
|
|
|
if (stat.isDirectory() || stat.isSymbolicLink()) return;
|
|
|
|
|
2020-11-23 19:24:19 +01:00
|
|
|
const ext = path.extname(file);
|
|
|
|
const locale = path.basename(file, ext).toLowerCase();
|
2012-12-17 18:18:07 +01:00
|
|
|
|
2021-01-21 22:06:52 +01:00
|
|
|
if ((ext === '.json') && languages.isValid(locale)) {
|
2020-11-23 19:24:19 +01:00
|
|
|
if (!locales2paths[locale]) locales2paths[locale] = [];
|
2012-12-19 21:16:29 +01:00
|
|
|
locales2paths[locale].push(file);
|
2012-12-17 18:18:07 +01:00
|
|
|
}
|
|
|
|
});
|
2021-01-21 22:06:52 +01:00
|
|
|
};
|
2012-12-17 18:18:07 +01:00
|
|
|
|
2020-11-23 19:24:19 +01:00
|
|
|
// add core supported languages first
|
|
|
|
extractLangs(`${npm.root}/ep_etherpad-lite/locales`);
|
2019-10-20 02:09:22 +02:00
|
|
|
|
2020-11-23 19:24:19 +01:00
|
|
|
// add plugins languages (if any)
|
|
|
|
for (const pluginName in plugins) extractLangs(path.join(npm.root, pluginName, 'locales'));
|
2012-12-17 18:18:07 +01:00
|
|
|
|
2020-05-19 14:21:31 +02:00
|
|
|
// Build a locale index (merge all locale data other than user-supplied overrides)
|
2020-11-23 19:24:19 +01:00
|
|
|
const locales = {};
|
|
|
|
_.each(locales2paths, (files, langcode) => {
|
|
|
|
locales[langcode] = {};
|
2012-12-17 18:18:07 +01:00
|
|
|
|
2020-11-23 19:24:19 +01:00
|
|
|
files.forEach((file) => {
|
2020-09-15 03:53:01 +02:00
|
|
|
let fileContents;
|
|
|
|
try {
|
2020-11-23 19:24:19 +01:00
|
|
|
fileContents = JSON.parse(fs.readFileSync(file, 'utf8'));
|
2020-09-15 03:53:01 +02:00
|
|
|
} catch (err) {
|
|
|
|
console.error(`failed to read JSON file ${file}: ${err}`);
|
|
|
|
throw err;
|
|
|
|
}
|
2012-12-23 22:43:32 +01:00
|
|
|
_.extend(locales[langcode], fileContents);
|
2012-12-17 18:18:07 +01:00
|
|
|
});
|
|
|
|
});
|
2012-12-19 21:16:29 +01:00
|
|
|
|
2020-05-19 14:21:31 +02:00
|
|
|
// Add custom strings from settings.json
|
|
|
|
// Since this is user-supplied, we'll do some extra sanity checks
|
|
|
|
const wrongFormatErr = Error(
|
2020-11-23 19:24:19 +01:00
|
|
|
'customLocaleStrings in wrong format. See documentation ' +
|
|
|
|
'for Customization for Administrators, under Localization.');
|
2020-05-19 14:21:31 +02:00
|
|
|
if (settings.customLocaleStrings) {
|
2020-11-23 19:24:19 +01:00
|
|
|
if (typeof settings.customLocaleStrings !== 'object') throw wrongFormatErr;
|
|
|
|
_.each(settings.customLocaleStrings, (overrides, langcode) => {
|
|
|
|
if (typeof overrides !== 'object') throw wrongFormatErr;
|
|
|
|
_.each(overrides, (localeString, key) => {
|
|
|
|
if (typeof localeString !== 'string') throw wrongFormatErr;
|
|
|
|
locales[langcode][key] = localeString;
|
|
|
|
});
|
|
|
|
});
|
2020-05-19 14:21:31 +02:00
|
|
|
}
|
|
|
|
|
2012-12-19 21:16:29 +01:00
|
|
|
return locales;
|
2021-01-21 22:06:52 +01:00
|
|
|
};
|
2012-12-17 18:18:07 +01:00
|
|
|
|
2012-12-19 21:16:29 +01:00
|
|
|
// returns a hash of all available languages availables with nativeName and direction
|
|
|
|
// e.g. { es: {nativeName: "español", direction: "ltr"}, ... }
|
2021-01-21 22:06:52 +01:00
|
|
|
const getAvailableLangs = (locales) => {
|
2020-11-23 19:24:19 +01:00
|
|
|
const result = {};
|
|
|
|
_.each(_.keys(locales), (langcode) => {
|
2012-12-19 21:16:29 +01:00
|
|
|
result[langcode] = languages.getLanguageInfo(langcode);
|
2012-12-17 18:18:07 +01:00
|
|
|
});
|
|
|
|
return result;
|
2021-01-21 22:06:52 +01:00
|
|
|
};
|
2012-12-17 18:18:07 +01:00
|
|
|
|
2012-12-19 21:16:29 +01:00
|
|
|
// returns locale index that will be served in /locales.json
|
2021-01-21 22:06:52 +01:00
|
|
|
const generateLocaleIndex = (locales) => {
|
2020-11-23 19:24:19 +01:00
|
|
|
const result = _.clone(locales); // keep English strings
|
|
|
|
_.each(_.keys(locales), (langcode) => {
|
2021-01-21 22:06:52 +01:00
|
|
|
if (langcode !== 'en') result[langcode] = `locales/${langcode}.json`;
|
2012-12-17 18:18:07 +01:00
|
|
|
});
|
|
|
|
return JSON.stringify(result);
|
2020-11-23 19:24:19 +01:00
|
|
|
};
|
2012-12-04 12:12:58 +01:00
|
|
|
|
2012-11-10 14:12:17 +01:00
|
|
|
|
2021-01-21 22:06:52 +01:00
|
|
|
exports.expressCreateServer = (n, args, cb) => {
|
2020-11-23 19:24:19 +01:00
|
|
|
// regenerate locales on server restart
|
|
|
|
const locales = getAllLocales();
|
|
|
|
const localeIndex = generateLocaleIndex(locales);
|
2012-12-19 21:16:29 +01:00
|
|
|
exports.availableLangs = getAvailableLangs(locales);
|
2012-12-17 18:18:07 +01:00
|
|
|
|
2020-11-23 19:24:19 +01:00
|
|
|
args.app.get('/locales/:locale', (req, res) => {
|
|
|
|
// works with /locale/en and /locale/en.json requests
|
|
|
|
const locale = req.params.locale.split('.')[0];
|
2012-12-17 18:18:07 +01:00
|
|
|
if (exports.availableLangs.hasOwnProperty(locale)) {
|
2021-02-13 08:35:25 +01:00
|
|
|
res.setHeader('Cache-Control', `public, max-age=${settings.maxAge}`);
|
2012-12-19 19:49:25 +01:00
|
|
|
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
2020-11-23 19:24:19 +01:00
|
|
|
res.send(`{"${locale}":${JSON.stringify(locales[locale])}}`);
|
2012-12-17 18:18:07 +01:00
|
|
|
} else {
|
2015-04-10 21:10:55 +02:00
|
|
|
res.status(404).send('Language not available');
|
2012-12-17 18:18:07 +01:00
|
|
|
}
|
2020-11-23 19:24:19 +01:00
|
|
|
});
|
2019-10-20 02:09:22 +02:00
|
|
|
|
2020-11-23 19:24:19 +01:00
|
|
|
args.app.get('/locales.json', (req, res) => {
|
2021-02-13 08:35:25 +01:00
|
|
|
res.setHeader('Cache-Control', `public, max-age=${settings.maxAge}`);
|
2012-12-19 19:49:25 +01:00
|
|
|
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
2012-11-14 17:01:59 +01:00
|
|
|
res.send(localeIndex);
|
2020-11-23 19:24:19 +01:00
|
|
|
});
|
2019-10-20 02:09:22 +02:00
|
|
|
|
2020-10-11 04:51:26 +02:00
|
|
|
return cb();
|
2020-11-23 19:24:19 +01:00
|
|
|
};
|