You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
143 lines
3.7 KiB
JavaScript
143 lines
3.7 KiB
JavaScript
'use strict';
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const sanitizeHTML = require('sanitize-html');
|
|
const nconf = require('nconf');
|
|
const winston = require('winston');
|
|
|
|
const file = require('../file');
|
|
const { Translator } = require('../translator');
|
|
|
|
function filterDirectories(directories) {
|
|
return directories.map(
|
|
// get the relative path
|
|
// convert dir to use forward slashes
|
|
dir => dir.replace(/^.*(admin.*?).tpl$/, '$1').split(path.sep).join('/')
|
|
).filter(
|
|
// exclude .js files
|
|
// exclude partials
|
|
// only include subpaths
|
|
// exclude category.tpl, group.tpl, category-analytics.tpl
|
|
dir => (
|
|
!dir.endsWith('.js') &&
|
|
!dir.includes('/partials/') &&
|
|
/\/.*\//.test(dir) &&
|
|
!/manage\/(category|group|category-analytics)$/.test(dir)
|
|
)
|
|
);
|
|
}
|
|
|
|
async function getAdminNamespaces() {
|
|
const directories = await file.walk(path.resolve(nconf.get('views_dir'), 'admin'));
|
|
return filterDirectories(directories);
|
|
}
|
|
|
|
function sanitize(html) {
|
|
// reduce the template to just meaningful text
|
|
// remove all tags and strip out scripts, etc completely
|
|
return sanitizeHTML(html, {
|
|
allowedTags: [],
|
|
allowedAttributes: [],
|
|
});
|
|
}
|
|
|
|
function simplify(translations) {
|
|
return translations
|
|
// remove all mustaches
|
|
.replace(/(?:\{{1,2}[^}]*?\}{1,2})/g, '')
|
|
// collapse whitespace
|
|
.replace(/(?:[ \t]*[\n\r]+[ \t]*)+/g, '\n')
|
|
.replace(/[\t ]+/g, ' ');
|
|
}
|
|
|
|
function nsToTitle(namespace) {
|
|
return namespace.replace('admin/', '').split('/').map(str => str[0].toUpperCase() + str.slice(1)).join(' > ')
|
|
.replace(/[^a-zA-Z> ]/g, ' ');
|
|
}
|
|
|
|
const fallbackCache = {};
|
|
|
|
async function initFallback(namespace) {
|
|
const template = await fs.promises.readFile(path.resolve(nconf.get('views_dir'), `${namespace}.tpl`), 'utf8');
|
|
|
|
const title = nsToTitle(namespace);
|
|
let translations = sanitize(template);
|
|
translations = Translator.removePatterns(translations);
|
|
translations = simplify(translations);
|
|
translations += `\n${title}`;
|
|
|
|
return {
|
|
namespace: namespace,
|
|
translations: translations,
|
|
title: title,
|
|
};
|
|
}
|
|
|
|
async function fallback(namespace) {
|
|
if (fallbackCache[namespace]) {
|
|
return fallbackCache[namespace];
|
|
}
|
|
|
|
const params = await initFallback(namespace);
|
|
fallbackCache[namespace] = params;
|
|
return params;
|
|
}
|
|
|
|
async function initDict(language) {
|
|
const namespaces = await getAdminNamespaces();
|
|
return await Promise.all(namespaces.map(ns => buildNamespace(language, ns)));
|
|
}
|
|
|
|
async function buildNamespace(language, namespace) {
|
|
const translator = Translator.create(language);
|
|
try {
|
|
const translations = await translator.getTranslation(namespace);
|
|
if (!translations || !Object.keys(translations).length) {
|
|
return await fallback(namespace);
|
|
}
|
|
// join all translations into one string separated by newlines
|
|
let str = Object.keys(translations).map(key => translations[key]).join('\n');
|
|
str = sanitize(str);
|
|
|
|
let title = namespace;
|
|
title = title.match(/admin\/(.+?)\/(.+?)$/);
|
|
title = `[[admin/menu:section-${
|
|
title[1] === 'development' ? 'advanced' : title[1]
|
|
}]]${title[2] ? (` > [[admin/menu:${
|
|
title[1]}/${title[2]}]]`) : ''}`;
|
|
|
|
title = await translator.translate(title);
|
|
return {
|
|
namespace: namespace,
|
|
translations: `${str}\n${title}`,
|
|
title: title,
|
|
};
|
|
} catch (err) {
|
|
winston.error(err.stack);
|
|
return {
|
|
namespace: namespace,
|
|
translations: '',
|
|
};
|
|
}
|
|
}
|
|
|
|
const cache = {};
|
|
|
|
async function getDictionary(language) {
|
|
if (cache[language]) {
|
|
return cache[language];
|
|
}
|
|
|
|
const params = await initDict(language);
|
|
cache[language] = params;
|
|
return params;
|
|
}
|
|
|
|
module.exports.getDictionary = getDictionary;
|
|
module.exports.filterDirectories = filterDirectories;
|
|
module.exports.simplify = simplify;
|
|
module.exports.sanitize = sanitize;
|
|
|
|
require('../promisify')(module.exports);
|