Added --translate to MeshCentral server and allow translated custom web pages to be served.

Ylian Saint-Hilaire committed Jan 27, 2020 at 17:52 UTC 790d5be6e935dd1dc95ef2904a4eddad348e5da8
4 files changed +86 -16
meshcentral.js
+39 -6
@@ -154,19 +154,52 @@ function CreateMeshCentralServer(config, args) {
154
155 // Perform web site translations into different languages
156 if (obj.args.translate) {
157 + // Check NodeJS version
158 + const NodeJSVer = Number(process.version.match(/^v(\d+\.\d+)/)[1]);
159 + if (NodeJSVer < 8) { console.log("Translation feature requires Node v8 or above, current version is " + process.version + "."); process.exit(); return; }
160 +
161 // Check if translate.json is in the "meshcentral-data" folder, if so use that and translate default pages.
158 - // TODO
162 + var translationFile = null, customTranslation = false;
163 + if (require('fs').existsSync(obj.path.join(obj.datapath, 'translate.json'))) { translationFile = obj.path.join(obj.datapath, 'translate.json'); console.log("Using translate.json in meshentral-data."); customTranslation = true; }
164 + if (translationFile == null) { if (require('fs').existsSync(obj.path.join(__dirname, 'translate', 'translate.json'))) { translationFile = obj.path.join(__dirname, 'translate', 'translate.json'); console.log("Using default translate.json."); } }
165 + if (translationFile == null) { console.log("Unable to find translate.json."); process.exit(); return; }
166
167 + // Perform translation operations
168 + var didSomething = false;
169 process.chdir('./translate');
170 var translateEngine = require('./translate/translate.js')
162 - translateEngine.startEx(['', '', 'minifyall']);
163 - translateEngine.startEx(['', '', 'translateall']);
164 - translateEngine.startEx(['', '', 'extractall']);
165 - process.exit();
171 + if (customTranslation == true) {
172 + // Translate all of the default files using custom translation file
173 + translateEngine.startEx(['', '', 'minifyall']);
174 + translateEngine.startEx(['', '', 'translateall', translationFile]);
175 + translateEngine.startEx(['', '', 'extractall', translationFile]);
176 + didSomething = true;
177 + }
178
179 // Check is "meshcentral-web" exists, if so, translate all pages in that folder.
168 - // TODO
180 + if (obj.webViewsOverridePath != null) {
181 + didSomething = true;
182 + var files = obj.fs.readdirSync(obj.webViewsOverridePath);
183 + for (var i in files) {
184 + var file = obj.path.join(obj.webViewsOverridePath, files[i]);
185 + if (file.endsWith('.handlebars') && !file.endsWith('-min.handlebars')) {
186 + translateEngine.startEx(['', '', 'translate', '*', translationFile, file, '--subdir:translations']);
187 + }
188 + }
189 + }
190 + if (obj.webPublicOverridePath != null) {
191 + didSomething = true;
192 + var files = obj.fs.readdirSync(obj.webPublicOverridePath);
193 + for (var i in files) {
194 + var file = obj.path.join(obj.webPublicOverridePath, files[i]);
195 + if (file.endsWith('.htm') && !file.endsWith('-min.htm')) {
196 + translateEngine.startEx(['', '', 'translate', '*', translationFile, file, '--subdir:translations']);
197 + }
198 + }
199 + }
200
201 + if (didSomething == false) { console.log("Nothing to do."); }
202 + process.exit();
203 return;
204 }
205
package.json
+1 -1
@@ -1,6 +1,6 @@
1 {
2 "name": "meshcentral",
3 - "version": "0.4.8-a",
3 + "version": "0.4.8-b",
4 "keywords": [
5 "Remote Management",
6 "Intel AMT",
translate/translate.js
+25 -8
@@ -112,7 +112,7 @@ function startEx(argv) {
112 log(' EXTRACT [languagefile] [files]');
113 log(' Extract strings from web pages and generate a language (.json) file.');
114 log('');
115 - log(' EXTRACTALL');
115 + log(' EXTRACTALL (languagefile)');
116 log(' Extract all MeshCentral strings from web pages and generate the languages.json file.');
117 log('');
118 log(' TRANSLATE [language] [languagefile] [files]');
@@ -196,7 +196,15 @@ function startEx(argv) {
196 }
197
198 // Extract or translate all MeshCentral strings
199 - if (command == 'extractall') { extract("translate.json", meshCentralSourceFiles); }
199 + if (command == 'extractall') {
200 + if (argv.length > 4) { lang = argv[4].toLowerCase(); }
201 + var translationFile = 'translate.json';
202 + if (argv.length > 3) {
203 + if (fs.existsSync(argv[3]) == false) { log('Unable to find: ' + argv[3]); return; } else { translationFile = argv[3]; }
204 + }
205 + extract(translationFile, meshCentralSourceFiles, translationFile);
206 + }
207 +
208 if (command == 'translateall') {
209 if (fs.existsSync('../views/translations') == false) { fs.mkdirSync('../views/translations'); }
210 if (fs.existsSync('../public/translations') == false) { fs.mkdirSync('../public/translations'); }
@@ -226,11 +234,16 @@ function startEx(argv) {
234 var langFile = argv[4];
235 if (fs.existsSync(langFile) == false) { log("Missing language file: " + langFile); process.exit(); return; }
236
229 - var sources = [];
230 - for (var i = 5; i < argv.length; i++) { if (fs.existsSync(argv[i]) == false) { log("Missing file: " + argv[i]); process.exit(); return; } sources.push(argv[i]); }
237 + var sources = [], subdir = null;
238 + for (var i = 5; i < argv.length; i++) {
239 + if (argv[i].startsWith('--subdir:')) {
240 + subdir = argv[i].substring(9);
241 + } else {
242 + if (fs.existsSync(argv[i]) == false) { log("Missing file: " + argv[i]); process.exit(); return; } sources.push(argv[i]);
243 + }
244 + }
245 if (sources.length == 0) { log("No source files specified."); process.exit(); return; }
232 -
233 - translate(lang, langFile, sources, false);
246 + translate(lang, langFile, sources, subdir);
247 }
248
249 if (command == 'minifyall') {
@@ -414,7 +427,7 @@ function translateSingleThreaded(lang, langFile, sources, createSubDir) {
427 try { langFileData = JSON.parse(fs.readFileSync(langFile)); } catch (ex) { }
428 if ((langFileData == null) || (langFileData.strings == null)) { log("Invalid language file."); process.exit(); return; }
429
417 - if (lang != null) {
430 + if ((lang != null) && (lang != '*')) {
431 // Translate a single language
432 translateEx(lang, langFileData, sources, createSubDir);
433 } else {
@@ -553,7 +566,11 @@ function translateFromHtml(lang, file, createSubDir) {
566
567 var outname = file;
568 var outnamemin = null;
556 - if (createSubDir != null) { outname = path.join(path.dirname(file), createSubDir, path.basename(file)); }
569 + if (createSubDir != null) {
570 + var outfolder = path.join(path.dirname(file), createSubDir);
571 + if (fs.existsSync(outfolder) == false) { fs.mkdirSync(outfolder); }
572 + outname = path.join(path.dirname(file), createSubDir, path.basename(file));
573 + }
574 if (outname.endsWith('.handlebars')) {
575 outnamemin = (outname.substring(0, outname.length - 11) + '-min_' + lang + '.handlebars');
576 outname = (outname.substring(0, outname.length - 11) + '_' + lang + '.handlebars');
webserver.js
+21 -1
@@ -4332,7 +4332,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4332
4333 // Render a page using the proper language
4334 function render(req, res, filename, args) {
4335 - if ((obj.parent.webViewsOverridePath == null) && (obj.renderPages != null)) {
4335 + if (obj.renderPages != null) {
4336 // If a user set a localization, use that
4337 if ((req.query.lang == null) && (req.session != null) && (req.session.userid)) {
4338 var user = obj.users[req.session.userid];
@@ -4375,6 +4375,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4375
4376 // Get the list of pages with different languages that can be rendered
4377 function getRenderList() {
4378 + // Fetch default rendeing pages
4379 var translateFolder = null;
4380 if (obj.fs.existsSync('views/translations')) { translateFolder = 'views/translations'; }
4381 if (obj.fs.existsSync(obj.path.join(__dirname, 'views', 'translations'))) { translateFolder = obj.path.join(__dirname, 'views', 'translations'); }
@@ -4395,6 +4396,25 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4396 }
4397 }
4398 }
4399 +
4400 + // See if there are any custom rending pages that will override the default ones
4401 + if (obj.parent.webViewsOverridePath != null) {
4402 + translateFolder = null;
4403 + if (obj.fs.existsSync(obj.path.join(obj.parent.webViewsOverridePath, 'translations'))) { translateFolder = obj.path.join(obj.parent.webViewsOverridePath, 'translations'); }
4404 + var files = obj.fs.readdirSync(translateFolder);
4405 + for (var i in files) {
4406 + var name = files[i];
4407 + if (name.endsWith('.handlebars')) {
4408 + name = name.substring(0, name.length - 11);
4409 + var xname = name.split('_');
4410 + if (xname.length == 2) {
4411 + if (obj.renderPages[xname[0]] == null) { obj.renderPages[xname[0]] = {}; }
4412 + obj.renderPages[xname[0]][xname[1]] = obj.path.join(translateFolder, name);
4413 + if (obj.renderLanguages.indexOf(xname[1]) == -1) { obj.renderLanguages.push(xname[1]); }
4414 + }
4415 + }
4416 + }
4417 + }
4418 }
4419 }
4420