mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-07-17 00:02:53 +02:00
define plugin name and theme name regexs in one location for consistency define various shared paths in one place for consistency
139 lines
4.3 KiB
JavaScript
139 lines
4.3 KiB
JavaScript
'use strict';
|
|
|
|
const _ = require('lodash');
|
|
const nconf = require('nconf');
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
const util = require('util');
|
|
let mkdirp = require('mkdirp');
|
|
mkdirp = mkdirp.hasOwnProperty('native') ? mkdirp : util.promisify(mkdirp);
|
|
const rimraf = require('rimraf');
|
|
const rimrafAsync = util.promisify(rimraf);
|
|
|
|
const file = require('../file');
|
|
const Plugins = require('../plugins');
|
|
const { paths } = require('../constants');
|
|
|
|
const buildLanguagesPath = path.join(paths.baseDir, 'build/public/language');
|
|
const coreLanguagesPath = path.join(paths.baseDir, 'public/language');
|
|
|
|
async function getTranslationMetadata() {
|
|
const paths = await file.walk(coreLanguagesPath);
|
|
let languages = [];
|
|
let namespaces = [];
|
|
|
|
paths.forEach(function (p) {
|
|
if (!p.endsWith('.json')) {
|
|
return;
|
|
}
|
|
|
|
var rel = path.relative(coreLanguagesPath, p).split(/[/\\]/);
|
|
var language = rel.shift().replace('_', '-').replace('@', '-x-');
|
|
var namespace = rel.join('/').replace(/\.json$/, '');
|
|
|
|
if (!language || !namespace) {
|
|
return;
|
|
}
|
|
|
|
languages.push(language);
|
|
namespaces.push(namespace);
|
|
});
|
|
|
|
|
|
languages = _.union(languages, Plugins.languageData.languages).sort().filter(Boolean);
|
|
namespaces = _.union(namespaces, Plugins.languageData.namespaces).sort().filter(Boolean);
|
|
const configLangs = nconf.get('languages');
|
|
if (process.env.NODE_ENV === 'development' && Array.isArray(configLangs) && configLangs.length) {
|
|
languages = configLangs;
|
|
}
|
|
// save a list of languages to `${buildLanguagesPath}/metadata.json`
|
|
// avoids readdirs later on
|
|
await mkdirp(buildLanguagesPath);
|
|
const result = {
|
|
languages: languages,
|
|
namespaces: namespaces,
|
|
};
|
|
await fs.promises.writeFile(path.join(buildLanguagesPath, 'metadata.json'), JSON.stringify(result));
|
|
return result;
|
|
}
|
|
|
|
async function writeLanguageFile(language, namespace, translations) {
|
|
const dev = process.env.NODE_ENV === 'development';
|
|
const filePath = path.join(buildLanguagesPath, language, namespace + '.json');
|
|
|
|
await mkdirp(path.dirname(filePath));
|
|
await fs.promises.writeFile(filePath, JSON.stringify(translations, null, dev ? 2 : 0));
|
|
}
|
|
|
|
// for each language and namespace combination,
|
|
// run through core and all plugins to generate
|
|
// a full translation hash
|
|
async function buildTranslations(ref) {
|
|
const namespaces = ref.namespaces;
|
|
const languages = ref.languages;
|
|
const plugins = _.values(Plugins.pluginsData).filter(function (plugin) {
|
|
return typeof plugin.languages === 'string';
|
|
});
|
|
|
|
const promises = [];
|
|
|
|
namespaces.forEach(function (namespace) {
|
|
languages.forEach(function (language) {
|
|
promises.push(buildNamespaceLanguage(language, namespace, plugins));
|
|
});
|
|
});
|
|
|
|
await Promise.all(promises);
|
|
}
|
|
|
|
async function buildNamespaceLanguage(lang, namespace, plugins) {
|
|
const translations = {};
|
|
// core first
|
|
await assignFileToTranslations(translations, path.join(coreLanguagesPath, lang, namespace + '.json'));
|
|
|
|
await Promise.all(plugins.map(pluginData => addPlugin(translations, pluginData, lang, namespace)));
|
|
|
|
if (Object.keys(translations).length) {
|
|
await writeLanguageFile(lang, namespace, translations);
|
|
}
|
|
}
|
|
|
|
async function addPlugin(translations, pluginData, lang, namespace) {
|
|
const pluginLanguages = path.join(paths.nodeModules, pluginData.id, pluginData.languages);
|
|
const defaultLang = pluginData.defaultLang || 'en-GB';
|
|
|
|
// for each plugin, fallback in this order:
|
|
// 1. correct language string (en-GB)
|
|
// 2. old language string (en_GB)
|
|
// 3. corrected plugin defaultLang (en-US)
|
|
// 4. old plugin defaultLang (en_US)
|
|
const langs = [
|
|
defaultLang.replace('-', '_').replace('-x-', '@'),
|
|
defaultLang.replace('_', '-').replace('@', '-x-'),
|
|
lang.replace('-', '_').replace('-x-', '@'),
|
|
lang,
|
|
];
|
|
|
|
for (const language of langs) {
|
|
/* eslint-disable no-await-in-loop */
|
|
await assignFileToTranslations(translations, path.join(pluginLanguages, language, namespace + '.json'));
|
|
}
|
|
}
|
|
|
|
async function assignFileToTranslations(translations, path) {
|
|
try {
|
|
const fileData = await fs.promises.readFile(path, 'utf8');
|
|
Object.assign(translations, JSON.parse(fileData));
|
|
} catch (err) {
|
|
if (err.code !== 'ENOENT') {
|
|
throw err;
|
|
}
|
|
}
|
|
}
|
|
|
|
exports.build = async function buildLanguages() {
|
|
await rimrafAsync(buildLanguagesPath);
|
|
const data = await getTranslationMetadata();
|
|
await buildTranslations(data);
|
|
};
|