Improved translation web application.

This commit is contained in:
Ylian Saint-Hilaire 2019-12-06 16:49:40 -08:00
parent a38aa6e450
commit 4cc4835bd9
14 changed files with 6558 additions and 28 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "meshcentral", "name": "meshcentral",
"version": "0.4.5-i", "version": "0.4.5-j",
"keywords": [ "keywords": [
"Remote Management", "Remote Management",
"Intel AMT", "Intel AMT",

View File

@ -9,8 +9,8 @@ if (!String.prototype.startsWith) { String.prototype.startsWith = function (str)
if (!String.prototype.endsWith) { String.prototype.endsWith = function (str) { return this.indexOf(str, this.length - str.length) !== -1; }; } if (!String.prototype.endsWith) { String.prototype.endsWith = function (str) { return this.indexOf(str, this.length - str.length) !== -1; }; }
// Quick UI functions, a bit of a replacement for jQuery // Quick UI functions, a bit of a replacement for jQuery
//function Q(x) { if (document.getElementById(x) == null) { console.log('Invalid element: ' + x); } return document.getElementById(x); } // "Q" function Q(x) { if (document.getElementById(x) == null) { console.log('Invalid element: ' + x); } return document.getElementById(x); } // "Q"
function Q(x) { return document.getElementById(x); } // "Q" //function Q(x) { return document.getElementById(x); } // "Q"
function QS(x) { try { return Q(x).style; } catch (x) { } } // "Q" style function QS(x) { try { return Q(x).style; } catch (x) { } } // "Q" style
function QE(x, y) { try { Q(x).disabled = !y; } catch (x) { } } // "Q" enable function QE(x, y) { try { Q(x).disabled = !y; } catch (x) { } } // "Q" enable
function QV(x, y) { try { QS(x).display = (y ? '' : 'none'); } catch (x) { } } // "Q" visible function QV(x, y) { try { QS(x).display = (y ? '' : 'none'); } catch (x) { } } // "Q" visible

View File

@ -18,6 +18,7 @@
margin: 4px; margin: 4px;
padding: 6px; padding: 6px;
text-align: left; text-align: left;
cursor: pointer;
} }
.listItem:hover { .listItem:hover {
@ -35,12 +36,18 @@
} }
</style> </style>
</head> </head>
<body style="overflow:hidden"> <body style="overflow:hidden" onbeforeunload="return onBeforeUnload(event)">
<div id=p11 class="noselect" style="overflow:hidden"> <div id=p11 class="noselect" style="overflow:hidden;position:relative">
<div id="startTips" style="top:15px;right:15px;width:calc(50vh);position:absolute;background-color:gold;z-index:1000;padding:10px;border-radius:8px;box-shadow:3px 3px 10px gray">
Welcome to the MeshCentral translator. You can use this to help translate MeshCentral into other languages. Start by selecting a language, translate a few strings and save the strings to your server. Then, hit "Translate Server" to apply your changes to your server's web pages.<br /><br />
When ready, please mail the "meshcentral-data/translate.json" file to <a href="mailto:ylianst@gmail.com">ylianst@gmail.com</a> for inclusion in the MeshCentral official builds.<br /><br />
<a onclick="closeStartTips()"><b>Close</b></a>
</div>
<div id=deskarea0> <div id=deskarea0>
<div id="bigok" style="display:none;left:calc((100vh / 2))"><b>&checkmark;</b></div> <div id="bigok" style="display:none;left:calc((100vh / 2))"><b>&checkmark;</b></div>
<div id="bigfail" style="display:none;left:calc((100vh / 2))"><b>&#10007;</b></div> <div id="bigfail" style="display:none;left:calc((100vh / 2))"><b>&#10007;</b></div>
<div id=deskarea0 style="position:absolute;left:0;right:0;top:0;height:28px;background-color:#036;color:#c8c8c8"> <div id=deskarea0 style="position:absolute;left:0;right:0;top:0;height:28px;background-color:#036;color:#c8c8c8">
<input style="float:right;margin:3px" id="TransServerButton" type=button value="Translate Server" onclick="translateServer()">
<div style="float:right;padding:2px" id="mainStatus"></div> <div style="float:right;padding:2px" id="mainStatus"></div>
<div style="font-size:20px;font-family:Arial;padding:3px"><b>MeshCentral Translator</b></div> <div style="font-size:20px;font-family:Arial;padding:3px"><b>MeshCentral Translator</b></div>
</div> </div>
@ -50,9 +57,9 @@
</div> </div>
<div> <div>
<input id="OpenFileButton" type=button value="Open File..." onclick="openfile()" style="display:none"> <input id="OpenFileButton" type=button value="Open File..." onclick="openfile()" style="display:none">
<input id="SaveFileButton" type=button value="Save to Server..." onclick="saveServerTranslations()"> <input id="SaveServerButton" type=button value="Save to Server..." onclick="saveServerTranslations()">
<input id="SaveFileButton" type=button value="Save to File..." onclick="saveToFile()"> <input id="SaveFileButton" type=button value="Save to File..." onclick="saveToFile()">
<select id="langSelector" onclick="langSelectorChange()" onchange="langSelectorChange()"> <select id="langSelector" onchange="langSelectorChange()">
<option value="ar">Arabic (ar)</option> <option value="ar">Arabic (ar)</option>
<option value="fr">French (fr)</option> <option value="fr">French (fr)</option>
<option value="cs">Czech (cs)</option> <option value="cs">Czech (cs)</option>
@ -82,17 +89,19 @@
<div id="masterListArea" style="height:calc(33.33vh);overflow-y:scroll"> <div id="masterListArea" style="height:calc(33.33vh);overflow-y:scroll">
<div class="listItem"><div style="display:inline-block;width:calc(40% - 10px)"></div><div style="display:inline-block;width:calc(40% - 10px)"></div><div style="display:inline-block;width:calc(20% - 10px)"></div></div> <div class="listItem"><div style="display:inline-block;width:calc(40% - 10px)"></div><div style="display:inline-block;width:calc(40% - 10px)"></div><div style="display:inline-block;width:calc(20% - 10px)"></div></div>
</div> </div>
<textarea id="defaultTextArea" autocomplete=off readonly style="height:calc(33.33vh);overflow-y:scroll;width:calc(100% - 5px);resize:none;background-color:#EFE"></textarea> <textarea id="defaultTextArea" autocomplete=off readonly style="height:calc(28.33vh);overflow-y:scroll;width:calc(100% - 5px);resize:none;background-color:#EFE"></textarea>
<textarea id="translatedTextArea" autocomplete=off style="height:calc(33.33vh - 70px);overflow-y:scroll;width:calc(100% - 5px);resize:none"></textarea> <textarea id="translatedTextArea" autocomplete=off style="height:calc(38.33vh - 96px);overflow-y:scroll;width:calc(100% - 5px);resize:none;background-color:#EFE" onkeyup="onSourceChange()"></textarea>
</div> </div>
<div id=deskarea4 class="areaFoot"> <div id=deskarea4 class="areaFoot">
<div class="toright2"> <div class="toright2">
<input id="CopySource" type=button value="Copy English" onclick="copySource()">
<input id="PrevButton" type=button value="Prev" onclick="prev()"> <input id="PrevButton" type=button value="Prev" onclick="prev()">
<input id="NextButton" type=button value="Next" onclick="next()"> <input id="NextButton" type=button value="Next" onclick="next()">
</div> </div>
<div style="height:22px"> <div style="height:22px">
&nbsp; &nbsp;
<input id="CopySource" type=button value="Copy Source" onclick="copySource()"> <input id="SetButton" type=button value="Set" onclick="setTranslation()">
<input id="CancelButton" type=button value="Cancel" onclick="cancelTranslation()">
</div> </div>
</div> </div>
</div> </div>
@ -120,6 +129,7 @@
var translations = null; var translations = null;
var selectedLanguage = Q('langSelector').value; var selectedLanguage = Q('langSelector').value;
var selectedItem = 0; var selectedItem = 0;
var changes = false;
function start() { function start() {
window.onresize = deskAdjust; window.onresize = deskAdjust;
@ -129,12 +139,20 @@
document.onkeypress = onkeypress; document.onkeypress = onkeypress;
updateMasterList(); updateMasterList();
loadServerTranslations(); loadServerTranslations();
QE('SaveServerButton', false);
} }
function onBeforeUnload(e) {
if (changes) { e.preventDefault(); e.resturnValue = ''; }
}
function closeStartTips() { QV('startTips', false); }
function langSelectorChange() { function langSelectorChange() {
selectedLanguage = Q('langSelector').value; selectedLanguage = Q('langSelector').value;
updateMasterList(); updateMasterList();
onSearchChanged(true); onSearchChanged(true);
select(0, true, false);
} }
function cleanup() { function cleanup() {
@ -233,14 +251,17 @@
if (translations[i][selectedLanguage] != null) { target = EscapeHtml(translations[i][selectedLanguage]); } if (translations[i][selectedLanguage] != null) { target = EscapeHtml(translations[i][selectedLanguage]); }
var comment = ''; var comment = '';
// <span id=ns' + i + ' style=display:none>&#9654;&nbsp;</span> // <span id=ns' + i + ' style=display:none>&#9654;&nbsp;</span>
x.push('<div class="listItem" id=nx' + i + ' onclick=select(' + i + ')><div style="display:inline-block;width:calc(40% - 10px)">' + source + '</div><div style="display:inline-block;width:calc(40% - 10px)">' + target + '</div><div style="display:inline-block;width:calc(20% - 10px)">' + comment + '</div></div>'); x.push('<div class="listItem" id=nx' + i + ' onclick=select(' + i + ')><div id=ns' + i + ' style="display:inline-block;width:calc(40% - 10px)">' + source + '</div><div id=nt' + i + ' style="display:inline-block;width:calc(40% - 10px)">' + target + '</div><div id=nc' + i + ' style="display:inline-block;width:calc(20% - 10px)">' + comment + '</div></div>');
} }
} }
QH('masterListArea', x.join('')); QH('masterListArea', x.join(''));
updateButtons(); updateButtons();
} }
function select(i, scroll) { function select(i, scroll, nofocus) {
// Hold selection is a change was made but not commited.
if ((scroll == null) && (isTargetChanged() == true)) { return; }
Q('nx' + selectedItem).classList.remove('listItemSel'); Q('nx' + selectedItem).classList.remove('listItemSel');
Q('nx' + selectedItem).classList.add('listItem'); Q('nx' + selectedItem).classList.add('listItem');
selectedItem = i; selectedItem = i;
@ -253,22 +274,22 @@
} }
onLocChanged(); onLocChanged();
if (translations[i][selectedLanguage] != null) { if (translations[i][selectedLanguage] != null) {
QH('translatedTextArea', translations[selectedItem][selectedLanguage]); Q('translatedTextArea').value = translations[selectedItem][selectedLanguage];
} else { } else {
QH('translatedTextArea', ''); Q('translatedTextArea').value = '';
} }
Q('translatedTextArea').focus(); if (nofocus == true) { Q('translatedTextArea').focus(); }
updateButtons(); updateButtons();
} }
function next() { select(selectedItem + 1, true); } function next() { select(selectedItem + 1, true); }
function prev() { select(selectedItem - 1, true); } function prev() { select(selectedItem - 1, true); }
function copySource() { QH('translatedTextArea', translations[selectedItem].en); Q('translatedTextArea').focus(); } function copySource() { Q('translatedTextArea').value = translations[selectedItem].en; Q('translatedTextArea').focus(); }
function updateButtons() { function updateButtons() {
QE('SaveFileButton', translations != null); QE('SaveFileButton', translations != null);
QE('NextButton', (translations != null) && (selectedItem < (translations.length - 1))); QE('NextButton', (isTargetChanged() == false) && (translations != null) && (selectedItem < (translations.length - 1)));
QE('PrevButton', (translations != null) && (selectedItem > 0)); QE('PrevButton', (isTargetChanged() == false) && (translations != null) && (selectedItem > 0));
QE('CopySource', translations != null); QE('CopySource', translations != null);
if (translations == null) { if (translations == null) {
QH('status', ''); QH('status', '');
@ -277,6 +298,7 @@
QH('status', (selectedItem + 1) + ' / ' + translations.length); QH('status', (selectedItem + 1) + ' / ' + translations.length);
QS('progressbar').width = Math.floor(100 * ((selectedItem + 1) / translations.length)) + '%'; QS('progressbar').width = Math.floor(100 * ((selectedItem + 1) / translations.length)) + '%';
} }
onSourceChange();
} }
function enSort(a, b) { if (a.en.toLowerCase() > b.en.toLowerCase()) return 1; if (a.en.toLowerCase() < b.en.toLowerCase()) return -1; return 0; } function enSort(a, b) { if (a.en.toLowerCase() > b.en.toLowerCase()) return 1; if (a.en.toLowerCase() < b.en.toLowerCase()) return -1; return 0; }
@ -285,12 +307,13 @@
function onSearchChanged(force) { function onSearchChanged(force) {
if ((force != true) && (currentSearchFilter == Q('searchInput').value)) return; if ((force != true) && (currentSearchFilter == Q('searchInput').value)) return;
currentSearchFilter = Q('searchInput').value; currentSearchFilter = Q('searchInput').value;
var currentSearchFilterLower = currentSearchFilter.toLowerCase();
if (translations != null) { if (translations != null) {
for (var i in translations) { for (var i in translations) {
if (currentSearchFilter == '') { if (currentSearchFilter == '') {
QV('nx' + i, true); QV('nx' + i, true);
} else { } else {
QV('nx' + i, ((translations[i][selectedLanguage] != null) && (translations[i][selectedLanguage].indexOf(currentSearchFilter) >= 0)) || (translations[i]['en'].indexOf(currentSearchFilter) >= 0)); QV('nx' + i, ((translations[i][selectedLanguage] != null) && (translations[i][selectedLanguage].toLowerCase().indexOf(currentSearchFilterLower) >= 0)) || (translations[i]['en'].toLowerCase().indexOf(currentSearchFilterLower) >= 0));
} }
} }
} }
@ -346,8 +369,14 @@
xdr.onload = function () { xdr.onload = function () {
var x = null; var x = null;
try { x = JSON.parse(this.responseText); } catch (ex) { } try { x = JSON.parse(this.responseText); } catch (ex) { }
if ((x == null) || (typeof x.strings != 'object')) { messagebox('Translations', 'ERROR: Unable to parse server response.'); return; } if ((x == null) || (x.response == null)) { messagebox('Translations', 'ERROR: Unable to parse server response.'); return; }
// x if (x.response == 'ok') {
changes = false;
QE('SaveServerButton', false);
QS('SaveServerButton')['background-color'] = null;
} else {
messagebox('Translations', 'ERROR: ' + x.response);
}
}; };
xdr.onerror = function () { messagebox('Translations', 'ERROR: Unable to save translations to server.'); }; xdr.onerror = function () { messagebox('Translations', 'ERROR: Unable to save translations to server.'); };
xdr.send(JSON.stringify({ 'action': 'setTranslations', strings: translations })); xdr.send(JSON.stringify({ 'action': 'setTranslations', strings: translations }));
@ -357,6 +386,73 @@
saveAs(data2blob(JSON.stringify({ strings: translations })), 'translate.json'); saveAs(data2blob(JSON.stringify({ strings: translations })), 'translate.json');
} }
function setTranslation() {
if (Q('translatedTextArea').value == '') {
delete translations[selectedItem][selectedLanguage];
QH('nt' + selectedItem, '');
} else {
translations[selectedItem][selectedLanguage] = Q('translatedTextArea').value;
QH('nt' + selectedItem, translations[selectedItem][selectedLanguage]);
}
onSourceChange();
changes = true;
QE('SaveServerButton', true);
QS('SaveServerButton')['background-color'] = '#F93';
}
function cancelTranslation() {
Q('translatedTextArea').value = translations[selectedItem][selectedLanguage];
}
function isTargetChanged() {
if (translations == null) { return false; }
var source = '';
if (translations[selectedItem][selectedLanguage] != null) { source = translations[selectedItem][selectedLanguage]; }
return (source != Q('translatedTextArea').value);
}
function onSourceChange() {
var x = isTargetChanged();
QE('SetButton', x);
QE('CancelButton', x);
QE('NextButton', (isTargetChanged() == false) && (translations != null) && (selectedItem < (translations.length - 1)));
QE('PrevButton', (isTargetChanged() == false) && (translations != null) && (selectedItem > 0));
QS('translatedTextArea')['background-color'] = ((x == true) ? 'white' : '#EFE');
QE('SaveFileButton', !x);
QE('searchInput', !x);
QE('showLocCheck', !x);
QE('langSelector', !x);
QE('TransServerButton', !x);
QE('SaveServerButton', changes && !x);
}
function translateServer() {
var x = 'Perform server translation? The MeshCentral server will reset for 10 to 30 seconds to perform this operation.';
setDialogMode(2, "Translate Server", 3, translateServerEx, x);
}
function translateServerEx() {
QE('TransServerButton', false);
setTimeout(function () { QE('TransServerButton', true); }, 5000);
var xdr = null;
try { xdr = new XDomainRequest(); } catch (e) { }
if (!xdr) xdr = new XMLHttpRequest();
xdr.open('POST', window.location.origin + '/translations');
xdr.timeout = 30000;
xdr.onload = function () {
var x = null;
try { x = JSON.parse(this.responseText); } catch (ex) { }
if ((x == null) || (x.response == null)) { messagebox('Server Translation', 'ERROR: Unable to parse server response.'); return; }
if (x.response == 'ok') {
messagebox('Server Translation', 'Server translation initiated, this will take a minute or two. Once done, you can refresh the MeshCentral web pages to see the changes.<br /><br />When ready, please mail the file "meshcentral-data/translate.json" to <a href="mailto:ylianst@gmail.com">ylianst@gmail.com</a> for inclusion on the official build.');
} else {
messagebox('Server Translation', 'ERROR: ' + x.response);
}
};
xdr.onerror = function () { messagebox('Translations', 'ERROR: Unable to save translations to server.'); };
xdr.send(JSON.stringify({ 'action': 'translateServer', strings: translations }));
}
// //
// POPUP DIALOG // POPUP DIALOG
// //

View File

@ -72,7 +72,7 @@ function start() {
console.log(' TRANSLATE [language] [languagefile] [files]'); console.log(' TRANSLATE [language] [languagefile] [files]');
console.log(' Use a language (.json) file to translate web pages to a give language.'); console.log(' Use a language (.json) file to translate web pages to a give language.');
console.log(''); console.log('');
console.log(' TRANSLATEALL'); console.log(' TRANSLATEALL (languagefile)');
console.log(' Translate all MeshCentral strings using the languages.json file.'); console.log(' Translate all MeshCentral strings using the languages.json file.');
console.log(''); console.log('');
console.log(' MINIFYALL'); console.log(' MINIFYALL');
@ -110,8 +110,21 @@ function start() {
if (command == 'translateall') { if (command == 'translateall') {
if (fs.existsSync("../views/translations") == false) { fs.mkdirSync("../views/translations"); } if (fs.existsSync("../views/translations") == false) { fs.mkdirSync("../views/translations"); }
if (fs.existsSync("../public/translations") == false) { fs.mkdirSync("../public/translations"); } if (fs.existsSync("../public/translations") == false) { fs.mkdirSync("../public/translations"); }
if ((process.argv.length > 3)) {
if (fs.existsSync(process.argv[3]) == false) {
console.log('Unable to find: ' + process.argv[3]);
} else {
translate(null, process.argv[3], meshCentralSourceFiles, "translations");
}
} else {
if (fs.existsSync("translate.json") == false) {
console.log('Unable to find translate.json.');
} else {
translate(null, "translate.json", meshCentralSourceFiles, "translations"); translate(null, "translate.json", meshCentralSourceFiles, "translations");
} }
}
return;
}
// Translate web pages to a given language given a language file // Translate web pages to a given language given a language file
if (command == 'translate') { if (command == 'translate') {

File diff suppressed because one or more lines are too long

View File

@ -5958,6 +5958,11 @@
y += addHtmlValue("Language", z); y += addHtmlValue("Language", z);
} }
y += addHtmlValue("Dates & Time", x); y += addHtmlValue("Dates & Time", x);
if ((userinfo.siteadmin == 0xFFFFFFFF) && (domain == '')) {
y += '<br /><a rel="noreferrer noopener" target="_blank" href="translator.htm">' + "Help translate MeshCentral" + '</a>';
}
setDialogMode(2, "Localization Settings", 3, account_showLocalizationSettingsEx, y); setDialogMode(2, "Localization Settings", 3, account_showLocalizationSettingsEx, y);
return false; return false;
} }

View File

@ -6969,6 +6969,11 @@
y += addHtmlValue("Language", z); y += addHtmlValue("Language", z);
} }
y += addHtmlValue("Dates & Time", x); y += addHtmlValue("Dates & Time", x);
if ((userinfo.siteadmin == 0xFFFFFFFF) && (domain == '')) {
y += '<br /><a rel="noreferrer noopener" target="_blank" href="translator.htm">' + "Help translate MeshCentral" + '</a>';
}
setDialogMode(2, "Localization Settings", 3, account_showLocalizationSettingsEx, y); setDialogMode(2, "Localization Settings", 3, account_showLocalizationSettingsEx, y);
return false; return false;
} }

View File

@ -5958,6 +5958,11 @@
y += addHtmlValue("Jazyk", z); y += addHtmlValue("Jazyk", z);
} }
y += addHtmlValue("Datum & čas", x); y += addHtmlValue("Datum & čas", x);
if ((userinfo.siteadmin == 0xFFFFFFFF) && (domain == '')) {
y += '<br /><a rel="noreferrer noopener" target="_blank" href="translator.htm">' + "Help translate MeshCentral" + '</a>';
}
setDialogMode(2, "Localization Settings", 3, account_showLocalizationSettingsEx, y); setDialogMode(2, "Localization Settings", 3, account_showLocalizationSettingsEx, y);
return false; return false;
} }

View File

@ -5958,6 +5958,11 @@
y += addHtmlValue("Langages", z); y += addHtmlValue("Langages", z);
} }
y += addHtmlValue("Dates & Time", x); y += addHtmlValue("Dates & Time", x);
if ((userinfo.siteadmin == 0xFFFFFFFF) && (domain == '')) {
y += '<br /><a rel="noreferrer noopener" target="_blank" href="translator.htm">' + "Help translate MeshCentral" + '</a>';
}
setDialogMode(2, "Localization Settings", 3, account_showLocalizationSettingsEx, y); setDialogMode(2, "Localization Settings", 3, account_showLocalizationSettingsEx, y);
return false; return false;
} }

View File

@ -6967,6 +6967,11 @@
y += addHtmlValue("Jazyk", z); y += addHtmlValue("Jazyk", z);
} }
y += addHtmlValue("Datum & čas", x); y += addHtmlValue("Datum & čas", x);
if ((userinfo.siteadmin == 0xFFFFFFFF) && (domain == '')) {
y += '<br /><a rel="noreferrer noopener" target="_blank" href="translator.htm">' + "Help translate MeshCentral" + '</a>';
}
setDialogMode(2, "Localization Settings", 3, account_showLocalizationSettingsEx, y); setDialogMode(2, "Localization Settings", 3, account_showLocalizationSettingsEx, y);
return false; return false;
} }

View File

@ -6967,6 +6967,11 @@
y += addHtmlValue("Langages", z); y += addHtmlValue("Langages", z);
} }
y += addHtmlValue("Dates & Time", x); y += addHtmlValue("Dates & Time", x);
if ((userinfo.siteadmin == 0xFFFFFFFF) && (domain == '')) {
y += '<br /><a rel="noreferrer noopener" target="_blank" href="translator.htm">' + "Help translate MeshCentral" + '</a>';
}
setDialogMode(2, "Localization Settings", 3, account_showLocalizationSettingsEx, y); setDialogMode(2, "Localization Settings", 3, account_showLocalizationSettingsEx, y);
return false; return false;
} }

File diff suppressed because one or more lines are too long

View File

@ -29,7 +29,7 @@
</div> </div>
<div id="column_l"> <div id="column_l">
<h1>Bienvenue</h1> <h1>Bienvenue</h1>
<div id="welcomeText" style="display:none">Connect to your home or office devices from anywhere in the world using <a href="http://www.meshcommander.com/meshcentral2">MeshCentral</a>, the real time, open source remote monitoring and management web site. You will need to download and install a management agent on your computers. Once installed, computers will show up in the "My Devices" section of this web site and you will be able to monitor them and take control of them.</div> <div id="welcomeText" style="display:none">Connect to your home or office devices from anywhere in the world using <a href="http://www.meshcommander.com/meshcentral2">MeshCentral</a>, le site web open source de surveillance et de gestion dordinateur à distance en temps réel. Vous devrez télécharger et installer un agent de gestion sur vos ordinateurs. Une fois installés, les ordinateurs apparaîtront dans la section "Mes appareils" de ce site et vous pourrez les surveiller et en prendre le contrôle.</div>
<table id="centralTable" style=""> <table id="centralTable" style="">
<tbody><tr> <tbody><tr>
<td id="welcomeimage"> <td id="welcomeimage">

View File

@ -574,7 +574,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
fmt: "fido-u2f", fmt: "fido-u2f",
publicKey: webAuthnKey.publicKey, publicKey: webAuthnKey.publicKey,
prevCounter: webAuthnKey.counter, prevCounter: webAuthnKey.counter,
userHandle: Buffer(user._id, 'binary').toString('base64') userHandle: Buffer.from(user._id, 'binary').toString('base64')
}; };
var webauthnResponse = null; var webauthnResponse = null;
@ -1973,7 +1973,26 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
try { res.sendFile(obj.path.join(__dirname, 'translate', 'translate.json')); } catch (ex) { res.sendStatus(404); } try { res.sendFile(obj.path.join(__dirname, 'translate', 'translate.json')); } catch (ex) { res.sendStatus(404); }
} else { res.sendStatus(404); } } else { res.sendStatus(404); }
} else if (data.action == 'setTranslations') { } else if (data.action == 'setTranslations') {
obj.fs.writeFile(obj.path.join(obj.parent.datapath, 'translate.json'), JSON.stringify({ strings: data.strings } ), function (err) { res.send(JSON.stringify({ response:err })); }); obj.fs.writeFile(obj.path.join(obj.parent.datapath, 'translate.json'), JSON.stringify({ strings: data.strings }), function (err) { if (err == null) { res.send(JSON.stringify({ response: 'ok' })); } else { res.send(JSON.stringify({ response: err })); } });
} else if (data.action == 'translateServer') {
if (obj.pendingTranslation === true) { res.send(JSON.stringify({ response: 'Server is already performing a translation.' })); return; }
const nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]);
if (nodeVersion < 8) { res.send(JSON.stringify({ response: 'Server requires NodeJS 8.x or better.' })); return; }
var translateFile = obj.path.join(obj.parent.datapath, 'translate.json');
if (obj.fs.existsSync(translateFile) == false) { translateFile = obj.path.join(__dirname, 'translate', 'translate.json'); }
if (obj.fs.existsSync(translateFile) == false) { res.send(JSON.stringify({ response: 'Unable to find translate.js file on the server.' })); return; }
res.send(JSON.stringify({ response: 'ok' }));
console.log('Started server translation...');
obj.pendingTranslation = true;
require('child_process').exec('node translate.js translateall \"' + translateFile + '\"', { maxBuffer: 512000, timeout: 120000, cwd: obj.path.join(__dirname, 'translate') }, function (error, stdout, stderr) {
delete obj.pendingTranslation;
//console.log('error', error);
//console.log('stdout', stdout);
//console.log('stderr', stderr);
//console.log('Server restart...'); // Perform a server restart
//process.exit(0);
console.log('Server translation completed.');
});
} else { } else {
// Unknown request // Unknown request
res.sendStatus(404); res.sendStatus(404);