Closed cfoellmann closed 5 months ago
ok ive added a fix to my PR so you can use node node_modules/meshcentral.js --translate
HOWEVER i cant fix the translate in the WEB UI yet as ths requires some work
because the webui just calls the translate.js
file,
but the translate.js
file has no knowlege of the domains etc (which is correct as its a standalone utility)
ok ive merged the PR, which means
you create your files default.handlebars, login2.handlebars, etc
in your views
folder,
then you can run node node_modules/meshcentral --translate
and let it translate/minify all your files!
you can also use https://MYMESHSERVER.COM/translator.htm
, edit translations, then save to server
and run the --translate
command
(DONT USE THE TRANSLATE SERVER
BUTTON IN THE WEB UI!)
im still looking into the button as it only translates the default views
folder inside meshcentral
and not your web
folders you create
@si458 I have changed a lot of stuff in the default.handlebars file. Now it stopped working to modify it.
I connect of the console of the docker container and run "meshcentral.js --translate" which generates translation in the mapped folder meshcentral/web-csystems/views/translations
as default_de.handlebars
in the folder in views.
These generated files reflect the changed template but it is not loaded in the UI (if set to non-EN)
How can that be? Is the location not respected anymore?
@cfoellmann do you have minify:true
set?
has the --translate
produced -min.handlebars
files?
yes, it has produced those and those contain the "new" code
have you tried ctrl+f5 and also restarting the meshcentral container?
also try setting minify: false
then restarting the container and seeing if your changes get applied.
I had a look at my config.json and it is already minify: false
set. For both domains like in the definition shown.
But it is still producing -min files.
Everything refreshed. ctrl+F5, browser cache, container restart, restartserver command. is there more?
oh hang on ive just re-read ur message.
so you changed default.handlebars
in /opt/meshcentral/web-csystems/views
then ran translate
which generates the files correctly
and if you load up ENGLISH it loads ur custom file correctly
BUT if you load up say german/french/etc, its loading the original translate files and not your custom file thats been translated!
will have alook into it!
not really.
it used to work. but now it wont pick up new changes. I am on the latest :master the translate function is killing me.
One more thing:
I used the following command from within the container node /opt/meshcentral/meshcentral/meshcentral.js --translate
I will use the way described in #6168
And I have not refreshed the template from the master.
That is a very bad merge since my git does not show my commit changes. probably because of the file size (Line count)
The --translate operation exits with an error (presumably) after these lines:
...
Translating HTML (hu): device-notify.html
Translating HTML (hu): device-help.html
Translating TXT (hu): account-check.txt
Translating TXT (hu): account-invite.txt
Translating TXT (hu): account-login.txt
Translating TXT (hu): account-reset.txt
Translating TXT (hu): mesh-invite.txt
Translating TXT (hu): device-notify.txt
Translating TXT (hu): device-help.txt
Translating TXT (hu): sms-messages.txt
Translating JSON (All): agent-translations.json
Translating JSON (All): coretranslations.json
Processing HTML: agentinvite.handlebars
Processing HTML: invite.handlebars
Processing HTML: default.handlebars
Processing HTML: default-mobile.handlebars
Processing HTML: download.handlebars
Processing HTML: download2.handlebars
Processing HTML: error404.handlebars
Processing HTML: error404-mobile.handlebars
Processing HTML: login.handlebars
Processing HTML: login2.handlebars
Processing HTML: login-mobile.handlebars
Processing HTML: terms.handlebars
Processing HTML: terms-mobile.handlebars
Processing HTML: xterm.handlebars
Processing HTML: message.handlebars
Processing HTML: message2.handlebars
Processing HTML: messenger.handlebars
Processing HTML: player.handlebars
Processing HTML: sharing.handlebars
Processing HTML: mstsc.handlebars
Processing HTML: ssh.handlebars
Processing HTML: account-check.html
Processing HTML: account-invite.html
Processing HTML: account-login.html
Processing HTML: account-reset.html
Processing HTML: mesh-invite.html
Processing HTML: device-notify.html
Processing HTML: device-help.html
Processing TXT: account-check.txt
Processing TXT: account-invite.txt
Processing TXT: account-login.txt
Processing TXT: account-reset.txt
Processing TXT: mesh-invite.txt
Processing TXT: device-notify.txt
Processing TXT: device-help.txt
Processing TXT: sms-messages.txt
Processing JSON: agent-translations.json
Processing JSON: coretranslations.json
3379 strings in output file.
Generating default-min.handlebars...
I can only see the bottom half (I hope its half) of the error which comes down to this:
...
;
var vers_not_compat = ' [ <span onclick="return setDialogMode(2, \'Compatibility Issue\', 1, null, \'This plugin version is not compatible with your MeshCentral installation, please upgrade MeshCentral first.\');" title="' + "Version incompatible, please upgrade your MeshCentral installation first" + '" style="cursor: pointer; color:red;"> ! </span> ]';
var tbl = Q('p42tbl');
installedPluginList.forEach(function(p){
var cant_action = [];
if (p.hasAdminPanel == true && p.status) {
p.nameHtml = '<a onclick="return goPlugin(\'' + p.shortName + '\', \'' + p.name.replace(/'/g, "\\'") + '\');">' + EscapeHtml(p.name) + '</a>';
} else {
p.nameHtml = EscapeHtml(p.name);
}
p.statusText = statusMap[p.status].text;
p.statusColor = statusMap[p.status].color;
if (p.versionHistoryUrl == null) { cant_action.push('downgrade'); }
if (!p.status) { p.version = ' - '; } // It isn't technically installed, so no version number
p.upgradeAvail = "Checking...";
if (installedPluginList['version_info'] != null && installedPluginList['version_info'][p._id] != null) {
var vin = installedPluginList['version_info'][p._id];
if (vin.hasUpdate) {
p.upgradeAvail = '<a title="' + "View Changelog" + '" rel="noreferrer noopener" target="_blank" href="' + vin.changelogUrl + '">' + vin.version + '</a>';
} else {
cant_action.push('upgrade');
if (p.status) p.upgradeAvail = "Up to date";
else p.upgradeAvail = '<a title="' + "View Changelog" + '" rel="noreferrer noopener" target="_blank" href="' + vin.changelogUrl + '">' + vin.version + '</a>';
}
if (!vin.meshCentralCompat) {
p.upgradeAvail += vers_not_compat;
cant_action.push('install');
cant_action.push('upgrade');
}
}
p.actions = '<select onchange="return pluginAction(this,\'' + p._id + '\');"><option value=""> --</option>';
var entries = Object.entries(statusAvailability[p.status]);
for (var k in entries) {
if (cant_action.indexOf(entries[k][0]) === -1) {
p.actions += '<option value="' + entries[k][0] + '">' + entries[k][1] + '</option>';
}
}
p.actions += '</select>';
var tpl = '<td><img style=margin-top:3px src=images/plugin24.png></td><td class=gradTable1> </td><td class=gradTable2>' + p.nameHtml + '</td><td class=gradTable2>' + EscapeHtml(p.description) + '</td><td class=gradTable2 style=text-align:center><a href="' + EscapeHtml(p.homepage) + '" rel="noreferrer noopener" target="_blank">Home</a></td><td class=gradTable2 style=text-align:center>' + EscapeHtml(p.version) + '</td><td style=text-align:center class="pluginUpgradeAvailable gradTable2">' + p.upgradeAvail + '</td><td class=gradTable2 style="text-align:center;color:#' + p.statusColor + '">' + p.statusText + '</td><td class="pluginAction gradTable2" style=text-align:center>' + p.actions + '</td><td class=gradTable3> </td>';
var tr = tbl.insertRow(-1);
tr.innerHTML = tpl;
tr.classList.add('p42tblRow');
tr.setAttribute('data-id', p._id);
tr.setAttribute('id', 'pluginRow-' + p._id);
});
} else {
var tr = Q('p42tbl').querySelectorAll('.p42tblRow');
for (var i in Object.values(tr)) { tr[i].parentNode.removeChild(tr[i]); }
}
if (versInfo == null) refreshPluginLatest();
}
function refreshPluginLatest() {
if (pluginHandler == null) return;
meshserver.send({ action: 'pluginLatestCheck' });
}
function distributeCore() {
if (pluginHandler == null) return;
meshserver.send({ action: 'distributeCore', nodes: nodes }); // All nodes the user has access to
QV('pluginRestartNotice', false);
}
function pluginActionEx() {
if (pluginHandler == null) return;
var act = Q('lastPluginAct').value, id = Q('lastPluginId').value, pVersUrl = Q('lastPluginVersion').value;
switch(act) {
case 'upgrade':
case 'install':
meshserver.send({ 'action': 'installplugin', 'id': id, 'version_only': false });
break;
case 'downgrade':
Q('lastPluginVersion').querySelectorAll('option').forEach(function(opt) {
if (opt.value == pVersUrl) pVers = opt.text;
});
meshserver.send({ 'action': 'installplugin', 'id': id, 'version_only': { 'name': pVers, 'url': pVersUrl }});
break;
case 'delete':
meshserver.send({ 'action': 'removeplugin', 'id': id });
break;
case 'disable':
meshserver.send({ 'action': 'disableplugin', 'id': id });
break;
}
QV('pluginRestartNotice', true);
}
function pluginAction(elem, id) {
if (pluginHandler == null) return;
if (elem.value == 'downgrade') {
meshserver.send({ 'action': 'getpluginversions', 'id': id });
} else {
var plugin = null;
for (var i in installedPluginList) { if (installedPluginList[i]._id == id) { plugin = installedPluginList[i]; } }
setDialogMode(2, "Plugin Action", 3, pluginActionEx, format("Are you sure you want to {0} the plugin: {1}", elem.value, plugin.name) + '<input id="lastPluginAct" type="hidden" value="' + elem.value + '" /><input id="lastPluginId" type="hidden" value="' + id + '" /><input id="lastPluginVersion" type="hidden" value="" />');
}
elem.value = '';
}
function goPlugin(pname, title) {
if (pluginHandler == null) return;
if (pname == null) { Q('p43iframe').src = ''; } else { QH('p43title', title); Q('p43iframe').src = '/pluginadmin.ashx?pin=' + pname; go(43); }
}
//
// Access Control Functions
// These must match server
//
// Remove user rights
function removeUserRights(rights, userid) {
if ((userid != userinfo._id) || (userinfo.removeRights == null)) return rights;
var add = 0, substract = 0;
if ((userinfo.removeRights & 0x00000008) != 0) { substract += 0x00000008; } // No Remote Control
if ((userinfo.removeRights & 0x00010000) != 0) { add += 0x00010000; } // No Desktop
if ((userinfo.removeRights & 0x00000100) != 0) { add += 0x00000100; } // Desktop View Only
if ((userinfo.removeRights & 0x00000200) != 0) { add += 0x00000200; } // No Terminal
if ((userinfo.removeRights & 0x00000400) != 0) { add += 0x00000400; } // No Files
if ((userinfo.removeRights & 0x00000010) != 0) { substract += 0x00000010; } // No Console
if ((userinfo.removeRights & 0x00008000) != 0) { substract += 0x00008000; } // No Uninstall
if ((userinfo.removeRights & 0x00020000) != 0) { substract += 0x00020000; } // No Remote Command
if ((userinfo.removeRights & 0x00000040) != 0) { substract += 0x00000040; } // No Wake
if ((userinfo.removeRights & 0x00040000) != 0) { substract += 0x00040000; } // No Reset/Off
if (rights != 0xFFFFFFFF) {
// If not administrator, add and subsctract restrictions
rights |= add;
rights &= (0xFFFFFFFF - substract);
} else {
// If administrator for a device group, start with permissions and add and subsctract restrictions
rights = 1 + 2 + 4 + 8 + 32 + 64 + 128 + 16384 + 32768 + 131072 + 262144 + 524288 + 1048576;
rights |= add;
rights &= (0xFFFFFFFF - substract);
}
return rights;
}
// Get the right of a user on a given device group
function GetMeshRights(mesh, userid) {
if (mesh == null) { return 0; }
if (userid == null) { userid = userinfo._id; }
if (typeof mesh == 'string') { mesh = meshes[mesh] }
if ((mesh == null) || (mesh.links == null)) { return 0; }
// Check if super user
if (serverinfo.manageAllDeviceGroups && (userid == userinfo._id)) return removeUserRights(0xFFFFFFFF, userid);
// Check device group link permission
var rights = 0, r = mesh.links[userid];
if (r != null) {
if (r.rights == 0xFFFFFFFF) { return removeUserRights(0xFFFFFFFF, userid); } // User has full rights thru a device group link, stop here.
rights = r.rights;
}
// Check permissions thru user groups
var user = null;
if (userid == userinfo._id) { user = userinfo; } else { if (users != null) { user = users[userid]; } }
if (user != null) {
for (var i in user.links) {
if (i.startsWith('ugrp/')) {
r = mesh.links[i];
if (r != null) {
if (r.rights == 0xFFFFFFFF) { return removeUserRights(0xFFFFFFFF, userid); } // User has full rights thru a user group, stop here.
rights |= r.rights; // TODO: Deal with reverse permissions
}
}
}
}
return removeUserRights(rights, userid);
}
// Returns true if the user can view the given device group
function IsMeshViewable(mesh, userid) {
if (mesh == null) { return false; }
if (userid == null) { userid = userinfo._id; }
if (typeof mesh == 'string') { mesh = meshes[mesh] }
if ((mesh == null) || (mesh.links == null)) { return false; }
if (mesh.links[userid] != null) { return true; } // User has visilibity thru a direct link
// Check if user user
if (serverinfo.manageAllDeviceGroups && (userid == userinfo._id)) return true;
// Check permissions thru user groups
var user = null;
if (userid == userinfo._id) { user = userinfo; } else { if (users != null) { user = users[userid]; } }
if (user != null) {
for (var i in user.links) {
if ((i.startsWith('ugrp/')) && (mesh.links[i] != null)) { return true; } // User has visilibity thru a user group
}
}
return false;
}
// Return the user rights for a given node
function GetNodeRights(node, userid) {
if (node == null) { return 0; }
if (userid == null) { userid = userinfo._id; }
if (typeof node == 'string') { node = getNodeFromId(node); if (node == null) { return 0; } }
var r = GetMeshRights(node.meshid, userid);
if (r == 0xFFFFFFFF) return removeUserRights(r, userid);
// Check direct device rights using device data
if ((node.links != null) && (node.links[userid] != null)) { r |= node.links[userid].rights; } // TODO: Deal with reverse permissions
// Check direct device rights thru user groups
if ((node.links != null) && (userinfo.links != null)) {
for (var i in node.links) {
if (i.startsWith('ugrp/') && (userinfo.links[i] != null) && (node.links[i].rights != null)) { r |= node.links[i].rights; }
}
}
// Check direct device rights using user data
/*
var user = null;
if (userid == userinfo._id) { user = userinfo; } else { if (users != null) { user = users[userid]; } }
if ((user != null) && (user.links != null)) {
var r2 = user.links[node._id];
if (r2 != null) {
if (r2.rights == 0xFFFFFFFF) { return 0xFFFFFFFF; } // User has full rights thru a device link, stop here.
r |= r2.rights; // TODO: Deal with reverse permissions
}
}
*/
return removeUserRights(r, userid);
}
// Return true if the device is visible to the user
function IsNodeViewable(node, userid) {
if (node == null) { return false; }
if (userid == null) { userid = userinfo._id; }
if (typeof node == 'string') { node = getNodeFromId(node); if (node == null) { return false; } }
if (IsMeshViewable(node.meshid, userid)) return true;
// Check direct device visibility using device data
if ((node.links != null) && (node.links[userid] != null)) { return true; }
// Check direct device visibility thru user groups
if ((node.links != null) && (userinfo.links != null)) {
for (var i in node.links) { if (i.startsWith('ugrp/') && (userinfo.links[i] != null) && (node.links[i].rights != null)) { return true; } }
}
return false;
}
//
// Generic methods
//
// Converts string to UTF8 byte array, polyfill for IE.
// Following method is code from Mozilla: https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder
if (typeof TextEncoder === 'undefined') {
window.TextEncoder=function TextEncoder(){};
TextEncoder.prototype.encode = function encode(str) {
'use strict';
var Len = str.length, resPos = -1;
var resArr = typeof Uint8Array === 'undefined' ? new Array(Len * 1.5) : new Uint8Array(Len * 3);
for (var point=0, nextcode=0, i = 0; i !== Len; ) {
point = str.charCodeAt(i), i += 1;
if (point >= 0xD800 && point <= 0xDBFF) {
if (i === Len) { resArr[resPos += 1] = 0xef; resArr[resPos += 1] = 0xbf; resArr[resPos += 1] = 0xbd; break; }
nextcode = str.charCodeAt(i);
if (nextcode >= 0xDC00 && nextcode <= 0xDFFF) {
point = (point - 0xD800) * 0x400 + nextcode - 0xDC00 + 0x10000;
i += 1;
if (point > 0xffff) { resArr[resPos += 1] = (0x1e<<3) | (point>>>18); resArr[resPos += 1] = (0x2<<6) | ((point>>>12)&0x3f); resArr[resPos += 1] = (0x2<<6) | ((point>>>6)&0x3f); resArr[resPos += 1] = (0x2<<6) | (point&0x3f); continue; }
} else { resArr[resPos += 1] = 0xef; resArr[resPos += 1] = 0xbf; resArr[resPos += 1] = 0xbd; continue; }
}
if (point <= 0x007f) {
resArr[resPos += 1] = (0x0<<7) | point;
} else if (point <= 0x07ff) {
resArr[resPos += 1] = (0x6<<5) | (point>>>6); resArr[resPos += 1] = (0x2<<6) | (point&0x3f);
} else {
resArr[resPos += 1] = (0xe<<4) | (point>>>12); resArr[resPos += 1] = (0x2<<6) | ((point>>>6)&0x3f); resArr[resPos += 1] = (0x2<<6) | (point&0x3f);
}
}
if (typeof Uint8Array !== 'undefined') return resArr.subarray(0, resPos + 1);
resArr.length = resPos + 1;
return resArr;
};
TextEncoder.prototype.toString = function(){return '[object TextEncoder]'};
try {
Object.defineProperty(TextEncoder.prototype,'encoding',{
get:function(){ if(TextEncoder.prototype.isPrototypeOf(this)) return'utf-8'; else throw TypeError('Illegal invocation'); }
});
} catch(e) { TextEncoder.prototype.encoding = 'utf-8'; }
if (typeof Symbol!=='undefined')TextEncoder.prototype[Symbol.toStringTag]='TextEncoder';
}
// Used to convert Base64 public VAPID key to bytearray.
function urlBase64ToUint8Array(base64String) {
var padding = '='.repeat((4 - base64String.length % 4) % 4);
var base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');
var rawData = atob(base64);
var outputArray = new Uint8Array(rawData.length);
for (var i = 0; i < rawData.length; ++i) { outputArray[i] = rawData.charCodeAt(i); }
return outputArray;
}
function joinPaths() { var x = []; for (var i in arguments) { var w = arguments[i]; if ((w != null) && (w != '')) { while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); } while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); } x.push(w); } } return x.join('/'); }
function putstore(name, val) {
try {
if ((typeof (localStorage) === 'undefined') || (localStorage.getItem(name) == val)) return;
if (val == null) { localStorage.removeItem(name); } else { localStorage.setItem(name, val); }
} catch (ex) { }
if (name[0] != '_') {
var s = {};
try {
for (var i = 0, len = localStorage.length; i < len; ++i) {
var k = localStorage.key(i);
if (k[0] != '_') {
s[k] = localStorage.getItem(k);
if ((k != 'desktopsettings') && (k != 'stars') && (k != 'deskKeyShortcuts') && (k != 'deskStrings') && (k != 'cmdopt') && (typeof s[k] == 'string') && (s[k].length > 64)) { delete s[k]; }
}
}
} catch (ex) {}
meshserver.send({ action: 'userWebState', state: JSON.stringify(s) });
}
}
// Convert a string into a UTF8 blob with the UTF8 header in front of it.
function stringToUtf8Blob(str) {
const bytes = new TextEncoder().encode(str);
var bytes2 = new Uint8Array(3 + bytes.length);
bytes2[0] = 0xEF; // This is the UTF-8 header for CSV files, add it to the start of the file.
bytes2[1] = 0xBB;
bytes2[2] = 0xBF;
for (var i = 0; i < bytes.length; i++) { bytes2[i + 3] = bytes[i]; }
return new Blob([bytes2], { type: 'application/octet-stream' }) // application/json;charset=utf-8
}
// Convert a string into a UTF8 blob
function stringToUtf8BlobNoHeader(str) {
return new Blob([new TextEncoder().encode(str)], { type: 'application/octet-stream' }) // application/json;charset=utf-8
}
function multiTranslate(s) { var i = s.indexOf(']|'); return s.substring(i + 2); } // Used when an English string can have different meanings, so "[MEANING]|word" is used instead as translation key.
function getLang() { if (navigator.languages != undefined) { return navigator.languages[0]; } return navigator.language; }
function getNodeAmtVersion(node) { if ((node == null) || (node.intelamt == null) || (typeof node.intelamt.ver != 'string')) return 0; var verSplit = node.intelamt.ver.split('.'); if (verSplit.length < 2) return 0; return parseInt(verSplit[0]) + (parseInt(verSplit[1]) / 100); }
function getstore(name, val) { try { if (typeof (localStorage) === 'undefined') return val; var v = localStorage.getItem(name); if ((v == null) || (v == null)) return val; return v; } catch (e) { return val; } }
function addLink(x, f) { return '<span tabindex=0 style=cursor:pointer;text-decoration:none onclick=\'' + f + '\' onkeypress="if (event.key==\'Enter\') {' + f + '} ">' + x + ' <img class=hoverButton src=images/link5.png></span>'; }
function addLinkConditional(x, f, c) { if (c) return addLink(x, f); return x; }
function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
function addOption(q, t, i) { var option = document.createElement('option'); option.text = t; option.value = i; Q(q).add(option); }
function passwordcheck(p) { return (p.length > 7) && (/\d/.test(p)) && (/[a-z]/.test(p)) && (/[A-Z]/.test(p)) && (/\W/.test(p)); }
function methodcheck(r) { if (r && r != null && r.Body && r.Body.ReturnValueStr != 'SUCCESS') { messagebox("Call Error", r.Header.Method + ': ' + r.Body.ReturnValueStr.replace('_', ' ')); return true; } return false; }
function TableStart() { return '<table cellpadding=0 cellspacing=0 style=width:100%;border-radius:8px><tr><td width=200px><p><td>'; }
function TableStart2() { return '<table cellpadding=0 cellspacing=0 style=width:100%;border-radius:8px><tr><td><p><td>'; }
function TableEntry(n, v) { return '<tr><td><p>' + n + '<td>' + v; }
function FullTable(x, e) { var r = TableStart(); for (i in x) { if (i && x[i]) r += TableEntry(i, x[i]); } return r + TableEnd(e); }
function TableEnd(n) { return '<tr><td colspan=2><p>' + (n?n:'') + '</table>'; }
function AddButton(v, f) { return '<input type=button value="' + v + '" onclick="' + f + '" style=margin:4px>'; }
function AddButton2(v, f) { return '<input type=button value="' + v + '" onclick="' + f + '">'; }
function AddRefreshButton(f) { return '<input type=button name=refreshbtn value=Refresh onclick="refreshButtons(false);' + f + '" style=margin:4px ' + (refreshButtonsState==false?'disabled':'') + '>'; }
function MoreStart() { return '<div id=idx_dlgMoreButtons3 style=display:none><hr>'; };
function MoreEnd() { return '</div>'; };
function MoreToggle(v) { QV('idx_dlgMoreButtons1',!v); QV('idx_dlgMoreButtons2',v); QV('idx_dlgMoreButtons3',v); }
function getSelectedOptions(sel) { var opts = [], opt; for (var i = 0, len = sel.options.length; i < len; i++) { opt = sel.options[i]; if (opt.selected) { opts.push(opt.value); } } return opts; }
function getInstance(x, y) { for (var i in x) { if (x[i]['InstanceID'] == y) return x[i]; } return null; }
function getItem(x, y, z) { for (var i in x) { if (x[i][y] == z) return x[i]; } return null; }
function guidToStr(g) { return g.substring(6, 8) + g.substring(4, 6) + g.substring(2, 4) + g.substring(0, 2) + '-' + g.substring(10, 12) + g.substring(8, 10) + '-' + g.substring(14, 16) + g.substring(12, 14) + '-' + g.substring(16, 20) + '-' + g.substring(20); }
function getUrlVars() { var j, hash, vars = [], hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); for (var i = 0; i < hashes.length; i++) { j = hashes[i].indexOf('='); if (j > 0) { vars[hashes[i].substring(0, j)] = hashes[i].substring(j + 1, hashes[i].length); } } return vars; }
//function getDocWidth() { if (window.innerWidth) return window.innerWidth; if (document.documentElement && document.documentElement.clientWidth && document.documentElement.clientWidth != 0) return document.documentElement.clientWidth; return document.getElementsByTagName('body')[0].clientWidth; }
//function addHtmlValue(t, v) { return '<div style=height:20px><div style=float:right;width:220px><b>' + v + '</b></div><div>' + t + '</div></div>'; }
function addHtmlValue(t, v) { return '<table><td style=width:120px>' + t + '<td><b>' + v + '</b></table>'; }
function addHtmlValue2(t, v) { return '<div><div style=display:inline-block;float:right>' + v + '</div><div style=display:inline-block>' + t + '</div></div>'; }
function addHtmlValue3(t, v) { return '<div><b>' + t + '</b></div><div style=margin-left:16px>' + v + '</div>'; }
function addHtmlValue4(t, v) { return '<table style=width:100%><td style=width:120px>' + t + '<td style=text-align:right><b>' + v + '</b></table>'; }
function addHtmlValue5(t, v) { return '<div style=padding:4px><div style=display:inline-block;float:right><b>' + v + '</b></div><div style=display:inline-block>' + t + '</div></div>'; }
function focusTextBox(x) { setTimeout(function(){ Q(x).selectionStart = Q(x).selectionEnd = 65535; Q(x).focus(); }, 0); }
function validateEmail(v) { var emailReg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; return emailReg.test(v); } // New version
function isPrivateIP(a) { return (a.startsWith('10.') || a.startsWith('172.16.') || a.startsWith('192.168.')); }
function u2fSupported() { return (window.u2f && ((navigator.userAgent.indexOf('Chrome/') > 0) || (navigator.userAgent.indexOf('Firefox/') > 0) || (navigator.userAgent.indexOf('Opera/') > 0) || (navigator.userAgent.indexOf('Safari/') > 0))); }
function findOne(arr1, arr2) { if ((arr1 == null) || (arr2 == null)) return false; return arr2.some(function (v) { return arr1.indexOf(v) >= 0; }); };
function copyTextToClip(txt) { function selectElementText(e) { if (document.selection) { var range = document.body.createTextRange(); range.moveToElementText(e); range.select(); } else if (window.getSelection) { var range = document.createRange(); range.selectNode(e); window.getSelection().removeAllRanges(); window.getSelection().addRange(range); } } var e = document.createElement('DIV'); e.textContent = txt; document.body.appendChild(e); selectElementText(e); document.execCommand('copy'); e.remove(); }
function copyTextToClip2(txt) { function selectElementText(e) { if (document.selection) { var range = document.body.createTextRange(); range.moveToElementText(e); range.select(); } else if (window.getSelection) { var range = document.createRange(); range.selectNode(e); window.getSelection().removeAllRanges(); window.getSelection().addRange(range); } } var e = document.createElement('DIV'); e.textContent = decodeURIComponent(txt); document.body.appendChild(e); selectElementText(e); document.execCommand('copy'); e.remove(); }
function capitalizeFirstLetter(x) { return x.charAt(0).toUpperCase() + x.slice(1); }
function printDate(d) { return d.toLocaleDateString(args.locale); }
function printTime(d) { return d.toLocaleTimeString(args.locale); }
function printDateTime(d) { return d.toLocaleString(args.locale); }
function printFlexDateTime(d) { if (printDate(new Date()) == printDate(d)) { return printTime(d); } else { return printDateTime(d); } }
function addDetailItem(title, value, state) { return '<table style=width:100%><td>' + nobreak(title) + '<td style=text-align:right>' + value + '</table>'; }
function format(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); };
function addTextLink(subtext, text, link) { var i = text.toLowerCase().indexOf(subtext.toLowerCase()); if (i == -1) { return text; } return text.substring(0, i) + '<a href="' + link + '">' + subtext + '</a>' + text.substring(i + subtext.length); }
function getOrderedList(objList, oname) { var r = []; for (var i in objList) { r.push(objList[i]); } r.sort(function(a, b) { var aa = a[oname].toLowerCase(), bb = b[oname].toLowerCase(); if (aa > bb) return 1; if (aa < bb) return -1; return 0; }); return r; }
function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); }
function nobreak(x) { return x.split(' ').join(' '); }
function pad2(num) { var s = '00' + num; return s.substr(s.length - 2); }
function encodeURIComponentEx(txt) { return encodeURIComponent(txt).replace(/'/g,'%27'); };
function getUserName(userid) {
var useridsplit = userid.split('/'), userid2 = useridsplit[0] + '/' + useridsplit[1] + '/' + useridsplit[2], guestname = '';
if ((useridsplit.length == 4) && (useridsplit[3].startsWith('guest:'))) { guestname = ' - ' + decode_utf8(atob(useridsplit[3].substring(6))); }
if (users && users[userid2] != null) { if (users[userid2].realname != null) return (users[userid2].realname + guestname); else return (users[userid2].name + guestname); }
return (useridsplit[2] + guestname);
}
function round(value, precision) { var multiplier = Math.pow(10, precision || 0); return Math.round(value * multiplier) / multiplier; }
function safeNewWindow(url, target) { var newWindow = window.open(url, target, 'noopener,noreferrer'); if (newWindow) { newWindow.opener = null; } }
function isWindowsNode(node) { if ((node.mtype != 2) || (node.agent == null) || (node.agent.id == null)) return false; return ([1,2,3,4,21,22,34].indexOf(node.agent.id) >= 0); }
// Webkit seems to have a problem with "download" tag causing "network error", but openning the download in a hidden frame fixes it.
// So we do that for all browsers except FireFox
function downloadFile(link, name, closeDialog) {
var element = document.createElement('a');
element.setAttribute('href', link);
element.setAttribute('rel', 'noreferrer noopener');
element.setAttribute('target', 'fileDownloadFrame');
if (navigator.userAgent.indexOf('Firefox') >= 0) { element.setAttribute('download', decodeURIComponent(name?name:'')); }
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
if (closeDialog) { setDialogMode(0); }
}
// Make the dialog box movable
function dialogBoxDrag() {
var elmnt = Q('dialog');
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
Q('dialogHeader').onmousedown = dragMouseDown;
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
elmnt.style.top = (elmnt.offsetTop - pos2) + 'px';
elmnt.style.left = (elmnt.offsetLeft - pos1) + 'px';
}
function closeDragElement() {
document.onmouseup = null;
document.onmousemove = null;
}
}
// Request Confirmation if closing while a desktop, terminal session is active
window.addEventListener('beforeunload', function (e) {
if (((desktop != null) && (xxcurrentView == 11)) || ((terminal != null) && (xxcurrentView == 12))) { e.preventDefault(); e.returnValue = ''; }
});
</script>
</body>
</html>
at new HTMLParser (/opt/meshcentral/node_modules/meshcentral/node_modules/html-minifier/src/htmlparser.js:244:13)
at minify (/opt/meshcentral/node_modules/meshcentral/node_modules/html-minifier/src/htmlminifier.js:980:3)
at exports.minify (/opt/meshcentral/node_modules/meshcentral/node_modules/html-minifier/src/htmlminifier.js:1341:16)
at Object.startEx (/opt/meshcentral/node_modules/meshcentral/translate/translate.js:508:31)
at CreateMeshCentralServer.obj.Start (/opt/meshcentral/node_modules/meshcentral/meshcentral.js:240:41)
at /opt/meshcentral/node_modules/meshcentral/meshcentral.js:4147:24
at InstallModules (/opt/meshcentral/node_modules/meshcentral/meshcentral.js:3894:178)
at /opt/meshcentral/node_modules/meshcentral/meshcentral.js:4144:9
at InstallModules (/opt/meshcentral/node_modules/meshcentral/meshcentral.js:3894:178)
at mainStart (/opt/meshcentral/node_modules/meshcentral/meshcentral.js:3978:5)
Node.js v18.19.0
HUH? 😕
will try have a look tonight/2moz, as i havent changed anything for the translate since https://github.com/Ylianst/MeshCentral/pull/6027
I did refresh the default.handlebars and did another node /opt/meshcentral/meshcentral/meshcentral.js --translate
resulting in correct files in web-csystems/views/translations
. Ignoring minify: false which is no problem.
But the views are being use from some other location with another old version of my translated template.
just fyi
I finally found the files that are being used:
Although it is translating correctly it is again falling for the views/
files from the default domain ''
:-(
I finally found the files that are being used: Although it is translating correctly it is again falling for the
views/
files from the default domain''
:-(
So you have not found a cause yet?
no, it is doing minification despite the minify: false
and it is ignoring the views from the second domain folder.
I am using a custom meshcentral-web
folder, so I do not know if that's relevant
hello all, sorry for delay, been poorly again (wish my body would tell colds to do one and not return!)
my findings on things
node node_modules/meshcentral --translate
now translates/minify all files correctly
views
folders inside node_modules/meshcentral
meshcentral-web
and meshcentral-web-subdomain
its slow translating because its using 1 core instead of 8 cores but it works!meshcentral-web
works for ENGLISH AND OTHER LANGUAGES
verified this by changing the title line in default.handlebars to says titlehere-mainweb
in meshcentral-web
then translate it and restarting meshcentralmeshcentral-web-subdomain
for ENGLISH works!
again i verified this by changing the title line in default.handlebars to says titlehere-subdomainweb
in meshcentral-web
then translate it and restarting meshcentralmeshcentral-web-subdomain
for NON-ENGLISH doesnt work!
it seems to be just using the meshcentral-web
versions of NON-ENGLISH!ok ive found the issue! going to take awhile to fix but im on it!
on startup it builds a list of files and languages, from either the default location OR the meshcentral-web
folder!
its just totally ignoring the fact we can now customise by each domain too!
fileOptions {
bs: '/home/simon/meshcentral/meshcentral-web/views/translations/default_bs',
cs: '/home/simon/meshcentral/meshcentral-web/views/translations/default_cs',
da: '/home/simon/meshcentral/meshcentral-web/views/translations/default_da',
de: '/home/simon/meshcentral/meshcentral-web/views/translations/default_de',
es: '/home/simon/meshcentral/meshcentral-web/views/translations/default_es',
fi: '/home/simon/meshcentral/meshcentral-web/views/translations/default_fi',
fr: '/home/simon/meshcentral/meshcentral-web/views/translations/default_fr',
hi: '/home/simon/meshcentral/meshcentral-web/views/translations/default_hi',
hu: '/home/simon/meshcentral/meshcentral-web/views/translations/default_hu',
it: '/home/simon/meshcentral/meshcentral-web/views/translations/default_it',
ja: '/home/simon/meshcentral/meshcentral-web/views/translations/default_ja',
ko: '/home/simon/meshcentral/meshcentral-web/views/translations/default_ko',
nl: '/home/simon/meshcentral/meshcentral-web/views/translations/default_nl',
pl: '/home/simon/meshcentral/meshcentral-web/views/translations/default_pl',
'pt-br': '/home/simon/meshcentral/meshcentral-web/views/translations/default_pt-br',
pt: '/home/simon/meshcentral/meshcentral-web/views/translations/default_pt',
ru: '/home/simon/meshcentral/meshcentral-web/views/translations/default_ru',
sv: '/home/simon/meshcentral/meshcentral-web/views/translations/default_sv',
tr: '/home/simon/meshcentral/meshcentral-web/views/translations/default_tr',
'zh-chs': '/home/simon/meshcentral/meshcentral-web/views/translations/default_zh-chs',
'zh-cht': '/home/simon/meshcentral/meshcentral-web/views/translations/default_zh-cht'
}
all fixed! #6180 if you want to look/apply the fix!
basically its as explained above, it builds an array of files and languages from 'views' and 'meshcentral-web' and totally forgetting about 'meshcentral-web-domain'!
so now it builds the array, and falls back
so use meshcentral-web-domain
if a file exists in the language or english
then use meshcentral-web
if a file exists in that language or english
then use views
if a file exists in that language or english
then all else 404 as what have you done with the default 'views' folder!?
the current :master is broken for me.
2024-06-17T08:35:22.377051000Z SHA384 cert hash: xxx
2024-06-17T08:35:22.377257000Z SHA384 key hash: yyy
2024-06-17T08:35:22.457112000Z ERR: node:internal/modules/cjs/loader:1143
2024-06-17T08:35:22.457406000Z const err = new Error(message);
2024-06-17T08:35:22.457571000Z ^
2024-06-17T08:35:22.457833000Z Error: Cannot find module 'connect-flash'
2024-06-17T08:35:22.457979000Z Require stack:
2024-06-17T08:35:22.458115000Z - /opt/meshcentral/meshcentral/webserver.js
2024-06-17T08:35:22.458313000Z - /opt/meshcentral/meshcentral/meshcentral.js
2024-06-17T08:35:22.458463000Z at Module._resolveFilename (node:internal/modules/cjs/loader:1143:15)
2024-06-17T08:35:22.458602000Z at Module._load (node:internal/modules/cjs/loader:984:27)
2024-06-17T08:35:22.458740000Z at Module.require (node:internal/modules/cjs/loader:1231:19)
2024-06-17T08:35:22.458884000Z at require (node:internal/modules/helpers:179:18)
2024-06-17T08:35:22.459024000Z at setupDomainAuthStrategy (/opt/meshcentral/meshcentral/webserver.js:7191:21)
2024-06-17T08:35:22.459238000Z at setupAllDomainAuthStrategies (/opt/meshcentral/meshcentral/webserver.js:6504:88)
2024-06-17T08:35:22.459378000Z at serverStart (/opt/meshcentral/meshcentral/webserver.js:6491:13)
2024-06-17T08:35:22.459524000Z at /opt/meshcentral/meshcentral/webserver.js:309:17
2024-06-17T08:35:22.459661000Z at /opt/meshcentral/meshcentral/db.js:2028:136
2024-06-17T08:35:22.459803000Z at Query.<anonymous> (/opt/meshcentral/meshcentral/db.js:1301:39) {
2024-06-17T08:35:22.459940000Z code: 'MODULE_NOT_FOUND',
2024-06-17T08:35:22.460087000Z requireStack: [
2024-06-17T08:35:22.460274000Z '/opt/meshcentral/meshcentral/webserver.js',
2024-06-17T08:35:22.460425000Z '/opt/meshcentral/meshcentral/meshcentral.js'
2024-06-17T08:35:22.460566000Z ]
2024-06-17T08:35:22.460697000Z }
2024-06-17T08:35:22.460970000Z Node.js v20.12.1
2024-06-17T08:35:22.493619000Z Error: Command failed: /usr/bin/node /opt/meshcentral/meshcentral/meshcentral --configfile config.json --launch 7
2024-06-17T08:35:22.493849000Z node:internal/modules/cjs/loader:1143
2024-06-17T08:35:22.494009000Z const err = new Error(message);
2024-06-17T08:35:22.494222000Z ^
2024-06-17T08:35:22.494504000Z Error: Cannot find module 'connect-flash'
2024-06-17T08:35:22.494638000Z Require stack:
2024-06-17T08:35:22.494770000Z - /opt/meshcentral/meshcentral/webserver.js
2024-06-17T08:35:22.494904000Z - /opt/meshcentral/meshcentral/meshcentral.js
2024-06-17T08:35:22.495028000Z at Module._resolveFilename (node:internal/modules/cjs/loader:1143:15)
2024-06-17T08:35:22.495221000Z at Module._load (node:internal/modules/cjs/loader:984:27)
2024-06-17T08:35:22.495395000Z at Module.require (node:internal/modules/cjs/loader:1231:19)
2024-06-17T08:35:22.495532000Z at require (node:internal/modules/helpers:179:18)
2024-06-17T08:35:22.495658000Z at setupDomainAuthStrategy (/opt/meshcentral/meshcentral/webserver.js:7191:21)
2024-06-17T08:35:22.495804000Z at setupAllDomainAuthStrategies (/opt/meshcentral/meshcentral/webserver.js:6504:88)
2024-06-17T08:35:22.495936000Z at serverStart (/opt/meshcentral/meshcentral/webserver.js:6491:13)
2024-06-17T08:35:22.496073000Z at /opt/meshcentral/meshcentral/webserver.js:309:17
2024-06-17T08:35:22.496259000Z at /opt/meshcentral/meshcentral/db.js:2028:136
2024-06-17T08:35:22.496402000Z at Query.<anonymous> (/opt/meshcentral/meshcentral/db.js:1301:39) {
2024-06-17T08:35:22.496545000Z code: 'MODULE_NOT_FOUND',
2024-06-17T08:35:22.496684000Z requireStack: [
2024-06-17T08:35:22.496815000Z '/opt/meshcentral/meshcentral/webserver.js',
2024-06-17T08:35:22.496957000Z '/opt/meshcentral/meshcentral/meshcentral.js'
2024-06-17T08:35:22.497083000Z ]
2024-06-17T08:35:22.497283000Z }
2024-06-17T08:35:22.497545000Z Node.js v20.12.1
2024-06-17T08:35:22.497804000Z at genericNodeError (node:internal/errors:984:15)
2024-06-17T08:35:22.497949000Z at wrappedFn (node:internal/errors:538:14)
2024-06-17T08:35:22.498110000Z at ChildProcess.exithandler (node:child_process:422:12)
2024-06-17T08:35:22.498310000Z at ChildProcess.emit (node:events:530:35)
2024-06-17T08:35:22.498438000Z at maybeClose (node:internal/child_process:1105:16)
2024-06-17T08:35:22.498556000Z at ChildProcess._handle.onexit (node:internal/child_process:305:5) {
2024-06-17T08:35:22.498731000Z code: 1,
2024-06-17T08:35:22.498841000Z killed: false,
2024-06-17T08:35:22.498973000Z signal: null,
2024-06-17T08:35:22.499142000Z cmd: '/usr/bin/node /opt/meshcentral/meshcentral/meshcentral --configfile config.json --launch 7'
2024-06-17T08:35:22.499319000Z }
2024-06-17T08:35:22.499469000Z ERROR: MeshCentral failed with critical error, check mesherrors.txt. Restarting in 5 seconds...
@cfoellmann just go into /opt/meshcentral/meshcentral
and do an npm list
Check if connect-flash
is there
If not do npm install connect-flash
and restart container.
I will have another quick look as I did move the connect-flash
include but i might of moved it too soon on the start-up
was not in the list.
did a npm install connect-flash
. -> works now
yeh its ok ive fixed the bug, doing a few merges of things and new builds!
the connect-flash is only used with oidc
but was trying to include if you didnt use it!
but moved it back to only include with oidc
!
but i have a feeling its needed for saml too now, so just double checking,
thanks for catching the bug tho!
I had to also install jsdom for the --translate
option to work which added a lot of vulnerabilities... unfortunately.
root@mesh:/opt/meshcentral# node node_modules/meshcentral --translate
Installing modules [ 'jsdom@22.1.0', 'minify-js@0.0.4', 'html-minifier@4.0.0' ]
Using default translate.json.
node:internal/modules/cjs/loader:1137
throw err;
^
Error: Cannot find module 'jsdom'
Require stack:
- /opt/meshcentral/node_modules/meshcentral/translate/translate.js
- /opt/meshcentral/node_modules/meshcentral/meshcentral.js
at Module._resolveFilename (node:internal/modules/cjs/loader:1134:15)
at Module._load (node:internal/modules/cjs/loader:975:27)
at Module.require (node:internal/modules/cjs/loader:1225:19)
at require (node:internal/modules/helpers:177:18)
at Object.startEx (/opt/meshcentral/node_modules/meshcentral/translate/translate.js:172:13)
at CreateMeshCentralServer.obj.Start (/opt/meshcentral/node_modules/meshcentral/meshcentral.js:227:33)
at /opt/meshcentral/node_modules/meshcentral/meshcentral.js:4147:24
at /opt/meshcentral/node_modules/meshcentral/meshcentral.js:3922:9
at ChildProcess.exithandler (node:child_process:414:7)
at ChildProcess.emit (node:events:517:28) {
code: 'MODULE_NOT_FOUND',
requireStack: [
'/opt/meshcentral/node_modules/meshcentral/translate/translate.js',
'/opt/meshcentral/node_modules/meshcentral/meshcentral.js'
]
}
Node.js v18.19.0
root@mesh:/opt/meshcentral# npm install jsdom
npm WARN deprecated urix@0.1.0: Please see https://github.com/lydell/urix#deprecated
npm WARN deprecated source-map-url@0.4.1: See https://github.com/lydell/source-map-url#deprecated
npm WARN deprecated resolve-url@0.2.1: https://github.com/lydell/resolve-url#deprecated
npm WARN deprecated source-map-resolve@0.5.3: See https://github.com/lydell/source-map-resolve#deprecated
npm WARN deprecated chokidar@1.7.0: Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.
added 149 packages, and audited 715 packages in 4s
43 packages are looking for funding
run `npm fund` for details
63 vulnerabilities (1 low, 4 moderate, 18 high, 40 critical)
To address issues that do not require attention, run:
npm audit fix
Some issues need review, and may require choosing
a different dependency.
Is this normal?
@cfoellmann ok fixed the connect-flash https://github.com/Ylianst/MeshCentral/commit/7955bc49549be93b8605f9f825e27ab2261bb5f7 as its needed in a few places, not just oidc!
@DaanSelen yes thats perfectly normal,
for some mad reason (yet to find out why?)
even tho we tell meshcentral to install the translate modules (as they arent needed by default)
when it then included them a few seconds after installing them, it cant find them?
BUT if you then re-run the command, it finds them no problems!
its as if NodeJS is caching what modules are installed when you first run the command,
but then not reloading them when you do an npm install
while its running,
so you have to run it again for it to go oh looks theres a module that wasnt there before, ill load it
P.S both, just pushed new commit so new master images be ready soon for you to try with the language translate fixes in!
where the --translate fixes not in?
I tried a --translate and it still giving me the views from the custom domain folder :-(
@cfoellmann try the new master image from 2 mins ago https://github.com/Ylianst/MeshCentral/pkgs/container/meshcentral https://github.com/users/Ylianst/packages/container/meshcentral/230915165?tag=master
you might have to re-run the --translate
function and let it regenerate all the translations, then restart the container for meshcentral to pick it up
@DaanSelen yes thats perfectly normal,
I was talking about the vulnerabilities introduces with this npm installation,
@si458 working now. very much appreciated as always!!
@DaanSelen I am pretty sure that most of the packages installed on the "start" of meshcentral would produce the "same" warnings: The npm feature to show vulnerabilities is a good thing but with these many inter-dependencies (715 packages) it is nearly impossible to get a working result without some outdated packages in there, right? @si458
@DaanSelen sorry having a mad monday morning, mis-read message completely.
yes its normal to see the 63 vulnerabilities (1 low, 4 moderate, 18 high, 40 critical)
line
because npm install
warns you so you can update packages if needs be.
as @DaanSelen explained, packages require packages, require packages require packages, so tracking down WHICH ONES are vulnerable is time consuming, but we do try to stay on top of package updates and make sure not to break meshcenteal in the process!
p.s: dont forget to donate ❤️ https://www.si458.co.uk/2024/01/05/donation/
For me this issue still persists.
} catch (ex) {}
meshserver.send({ action: 'userWebState', state: JSON.stringify(s) });
}
}
// Convert a string into a UTF8 blob with the UTF8 header in front of it.
function stringToUtf8Blob(str) {
const bytes = new TextEncoder().encode(str);
var bytes2 = new Uint8Array(3 + bytes.length);
bytes2[0] = 0xEF; // This is the UTF-8 header for CSV files, add it to the start of the file.
bytes2[1] = 0xBB;
bytes2[2] = 0xBF;
for (var i = 0; i < bytes.length; i++) { bytes2[i + 3] = bytes[i]; }
return new Blob([bytes2], { type: 'application/octet-stream' }) // application/json;charset=utf-8
}
// Convert a string into a UTF8 blob
function stringToUtf8BlobNoHeader(str) {
return new Blob([new TextEncoder().encode(str)], { type: 'application/octet-stream' }) // application/json;charset=utf-8
}
function multiTranslate(s) { var i = s.indexOf(']|'); return s.substring(i + 2); } // Used when an English string can have different meanings, so "[MEANING]|word" is used instead as translation key.
function getLang() { if (navigator.languages != undefined) { return navigator.languages[0]; } return navigator.language; }
function getNodeAmtVersion(node) { if ((node == null) || (node.intelamt == null) || (typeof node.intelamt.ver != 'string')) return 0; var verSplit = node.intelamt.ver.split('.'); if (verSplit.length < 2) return 0; return parseInt(verSplit[0]) + (parseInt(verSplit[1]) / 100); }
function getstore(name, val) { try { if (typeof (localStorage) === 'undefined') return val; var v = localStorage.getItem(name); if ((v == null) || (v == null)) return val; return v; } catch (e) { return val; } }
function addLink(x, f) { return '<span tabindex=0 style=cursor:pointer;text-decoration:none onclick=\'' + f + '\' onkeypress="if (event.key==\'Enter\') {' + f + '} ">' + x + ' <img class=hoverButton src=images/link5.png></span>'; }
function addLinkConditional(x, f, c) { if (c) return addLink(x, f); return x; }
function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
function addOption(q, t, i) { var option = document.createElement('option'); option.text = t; option.value = i; Q(q).add(option); }
function passwordcheck(p) { return (p.length > 7) && (/\d/.test(p)) && (/[a-z]/.test(p)) && (/[A-Z]/.test(p)) && (/\W/.test(p)); }
function methodcheck(r) { if (r && r != null && r.Body && r.Body.ReturnValueStr != 'SUCCESS') { messagebox("Call Error", r.Header.Method + ': ' + r.Body.ReturnValueStr.replace('_', ' ')); return true; } return false; }
function TableStart() { return '<table cellpadding=0 cellspacing=0 style=width:100%;border-radius:8px><tr><td width=200px><p><td>'; }
function TableStart2() { return '<table cellpadding=0 cellspacing=0 style=width:100%;border-radius:8px><tr><td><p><td>'; }
function TableEntry(n, v) { return '<tr><td><p>' + n + '<td>' + v; }
function FullTable(x, e) { var r = TableStart(); for (i in x) { if (i && x[i]) r += TableEntry(i, x[i]); } return r + TableEnd(e); }
function TableEnd(n) { return '<tr><td colspan=2><p>' + (n?n:'') + '</table>'; }
function AddButton(v, f) { return '<input type=button value="' + v + '" onclick="' + f + '" style=margin:4px>'; }
function AddButton2(v, f) { return '<input type=button value="' + v + '" onclick="' + f + '">'; }
function AddRefreshButton(f) { return '<input type=button name=refreshbtn value=Refresh onclick="refreshButtons(false);' + f + '" style=margin:4px ' + (refreshButtonsState==false?'disabled':'') + '>'; }
function MoreStart() { return '<div id=idx_dlgMoreButtons3 style=display:none><hr>'; };
function MoreEnd() { return '</div>'; };
function MoreToggle(v) { QV('idx_dlgMoreButtons1',!v); QV('idx_dlgMoreButtons2',v); QV('idx_dlgMoreButtons3',v); }
function getSelectedOptions(sel) { var opts = [], opt; for (var i = 0, len = sel.options.length; i < len; i++) { opt = sel.options[i]; if (opt.selected) { opts.push(opt.value); } } return opts; }
function getInstance(x, y) { for (var i in x) { if (x[i]['InstanceID'] == y) return x[i]; } return null; }
function getItem(x, y, z) { for (var i in x) { if (x[i][y] == z) return x[i]; } return null; }
function guidToStr(g) { return g.substring(6, 8) + g.substring(4, 6) + g.substring(2, 4) + g.substring(0, 2) + '-' + g.substring(10, 12) + g.substring(8, 10) + '-' + g.substring(14, 16) + g.substring(12, 14) + '-' + g.substring(16, 20) + '-' + g.substring(20); }
function getUrlVars() { var j, hash, vars = [], hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); for (var i = 0; i < hashes.length; i++) { j = hashes[i].indexOf('='); if (j > 0) { vars[hashes[i].substring(0, j)] = hashes[i].substring(j + 1, hashes[i].length); } } return vars; }
//function getDocWidth() { if (window.innerWidth) return window.innerWidth; if (document.documentElement && document.documentElement.clientWidth && document.documentElement.clientWidth != 0) return document.documentElement.clientWidth; return document.getElementsByTagName('body')[0].clientWidth; }
//function addHtmlValue(t, v) { return '<div style=height:20px><div style=float:right;width:220px><b>' + v + '</b></div><div>' + t + '</div></div>'; }
function addHtmlValue(t, v) { return '<table><td style=width:120px>' + t + '<td><b>' + v + '</b></table>'; }
function addHtmlValue2(t, v) { return '<div><div style=display:inline-block;float:right>' + v + '</div><div style=display:inline-block>' + t + '</div></div>'; }
function addHtmlValue3(t, v) { return '<div><b>' + t + '</b></div><div style=margin-left:16px>' + v + '</div>'; }
function addHtmlValue4(t, v) { return '<table style=width:100%><td style=width:120px>' + t + '<td style=text-align:right><b>' + v + '</b></table>'; }
function addHtmlValue5(t, v) { return '<div style=padding:4px><div style=display:inline-block;float:right><b>' + v + '</b></div><div style=display:inline-block>' + t + '</div></div>'; }
function focusTextBox(x) { setTimeout(function(){ Q(x).selectionStart = Q(x).selectionEnd = 65535; Q(x).focus(); }, 0); }
function validateEmail(v) { var emailReg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; return emailReg.test(v); } // New version
function isPrivateIP(a) { return (a.startsWith('10.') || a.startsWith('172.16.') || a.startsWith('192.168.')); }
function u2fSupported() { return (window.u2f && ((navigator.userAgent.indexOf('Chrome/') > 0) || (navigator.userAgent.indexOf('Firefox/') > 0) || (navigator.userAgent.indexOf('Opera/') > 0) || (navigator.userAgent.indexOf('Safari/') > 0))); }
function findOne(arr1, arr2) { if ((arr1 == null) || (arr2 == null)) return false; return arr2.some(function (v) { return arr1.indexOf(v) >= 0; }); };
function copyTextToClip(txt) { function selectElementText(e) { if (document.selection) { var range = document.body.createTextRange(); range.moveToElementText(e); range.select(); } else if (window.getSelection) { var range = document.createRange(); range.selectNode(e); window.getSelection().removeAllRanges(); window.getSelection().addRange(range); } } var e = document.createElement('DIV'); e.textContent = txt; document.body.appendChild(e); selectElementText(e); document.execCommand('copy'); e.remove(); }
function copyTextToClip2(txt) { function selectElementText(e) { if (document.selection) { var range = document.body.createTextRange(); range.moveToElementText(e); range.select(); } else if (window.getSelection) { var range = document.createRange(); range.selectNode(e); window.getSelection().removeAllRanges(); window.getSelection().addRange(range); } } var e = document.createElement('DIV'); e.textContent = decodeURIComponent(txt); document.body.appendChild(e); selectElementText(e); document.execCommand('copy'); e.remove(); }
function capitalizeFirstLetter(x) { return x.charAt(0).toUpperCase() + x.slice(1); }
function printDate(d) { return d.toLocaleDateString(args.locale); }
function printTime(d) { return d.toLocaleTimeString(args.locale); }
function printDateTime(d) { return d.toLocaleString(args.locale); }
function printFlexDateTime(d) { if (printDate(new Date()) == printDate(d)) { return printTime(d); } else { return printDateTime(d); } }
function addDetailItem(title, value, state) { return '<table style=width:100%><td>' + nobreak(title) + '<td style=text-align:right>' + value + '</table>'; }
function format(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); };
function addTextLink(subtext, text, link) { var i = text.toLowerCase().indexOf(subtext.toLowerCase()); if (i == -1) { return text; } return text.substring(0, i) + '<a href="' + link + '">' + subtext + '</a>' + text.substring(i + subtext.length); }
function getOrderedList(objList, oname) { var r = []; for (var i in objList) { r.push(objList[i]); } r.sort(function(a, b) { var aa = a[oname].toLowerCase(), bb = b[oname].toLowerCase(); if (aa > bb) return 1; if (aa < bb) return -1; return 0; }); return r; }
function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); }
function nobreak(x) { return x.split(' ').join(' '); }
function pad2(num) { var s = '00' + num; return s.substr(s.length - 2); }
function encodeURIComponentEx(txt) { return encodeURIComponent(txt).replace(/'/g,'%27'); };
function getUserName(userid) {
var useridsplit = userid.split('/'), userid2 = useridsplit[0] + '/' + useridsplit[1] + '/' + useridsplit[2], guestname = '';
if ((useridsplit.length == 4) && (useridsplit[3].startsWith('guest:'))) { guestname = ' - ' + decode_utf8(atob(useridsplit[3].substring(6))); }
if (users && users[userid2] != null) { if (users[userid2].realname != null) return (users[userid2].realname + guestname); else return (users[userid2].name + guestname); }
return (useridsplit[2] + guestname);
}
function round(value, precision) { var multiplier = Math.pow(10, precision || 0); return Math.round(value * multiplier) / multiplier; }
function safeNewWindow(url, target) { var newWindow = window.open(url, target, 'noopener,noreferrer'); if (newWindow) { newWindow.opener = null; } }
function isWindowsNode(node) { if ((node.mtype != 2) || (node.agent == null) || (node.agent.id == null)) return false; return ([1,2,3,4,21,22,34].indexOf(node.agent.id) >= 0); }
// Webkit seems to have a problem with "download" tag causing "network error", but openning the download in a hidden frame fixes it.
// So we do that for all browsers except FireFox
function downloadFile(link, name, closeDialog) {
var element = document.createElement('a');
element.setAttribute('href', link);
element.setAttribute('rel', 'noreferrer noopener');
element.setAttribute('target', 'fileDownloadFrame');
if (navigator.userAgent.indexOf('Firefox') >= 0) { element.setAttribute('download', decodeURIComponent(name?name:'')); }
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
if (closeDialog) { setDialogMode(0); }
}
// Make the dialog box movable
function dialogBoxDrag() {
var elmnt = Q('dialog');
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
Q('dialogHeader').onmousedown = dragMouseDown;
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
elmnt.style.top = (elmnt.offsetTop - pos2) + 'px';
elmnt.style.left = (elmnt.offsetLeft - pos1) + 'px';
}
function closeDragElement() {
document.onmouseup = null;
document.onmousemove = null;
}
}
// Request Confirmation if closing while a desktop, terminal session is active
window.addEventListener('beforeunload', function (e) {
if (((desktop != null) && (xxcurrentView == 11)) || ((terminal != null) && (xxcurrentView == 12))) { e.preventDefault(); e.returnValue = ''; }
});
</script>
</body>
</html>
at new HTMLParser (/opt/meshcentral/node_modules/html-minifier/src/htmlparser.js:244:13)
at minify (/opt/meshcentral/node_modules/html-minifier/src/htmlminifier.js:980:3)
at exports.minify (/opt/meshcentral/node_modules/html-minifier/src/htmlminifier.js:1341:16)
at Object.startEx (/opt/meshcentral/node_modules/meshcentral/translate/translate.js:508:31)
at CreateMeshCentralServer.obj.Start (/opt/meshcentral/node_modules/meshcentral/meshcentral.js:240:41)
at /opt/meshcentral/node_modules/meshcentral/meshcentral.js:4147:24
at InstallModules (/opt/meshcentral/node_modules/meshcentral/meshcentral.js:3894:178)
at /opt/meshcentral/node_modules/meshcentral/meshcentral.js:4144:9
at InstallModules (/opt/meshcentral/node_modules/meshcentral/meshcentral.js:3894:178)
at mainStart (/opt/meshcentral/node_modules/meshcentral/meshcentral.js:3978:5)
Node.js v18.19.0
Is what I get when passing in node node_modules/meshcentral --translate
. I have a default MeshCentral install, with the exception of a custom UI under meshcentral-web
@DaanSelen the must be some value or string inside your custom file that it just doesnt like!
try renaming your custom file to default.handlebars.backup
, rerun the --translate
and see if it translates ok
if it does, then rename ur file back and run again,
if it then errors out, the is something inside the default.handlebars
of your file it just doesnt like!
and im guessing it must be around
} catch (ex) {}
meshserver.send({ action: 'userWebState', state: JSON.stringify(s) });
then rename ur file back and run again, if it then errors out, the is something inside the
default.handlebars
of your file it just doesnt like! and im guessing it must be around} catch (ex) {}
Your fix for translating correctly. When I move it as backup file it works, but how can I troubleshoot where it errors?
so if you renamed the file to .backup
and its translating ok BUT then rename your file back and its NOT translating ok, then the is something wrong in your file
its going to be very hard to work out what its not working?
if your happy to, email me the file and ill have a quick dig https://github.com/si458 -> email on left!
Also something, I don't know if this is related. But after removing the custom meshcentral-web
folder and moving it outside its scope, then restarting meshcentral does not fix the Old returning:
The Desktop and Terminal and files tab is not present. This should all be a default Meshcentral installation
@DaanSelen Sorry for the delay, Mad day!
Lines 1724 and 1746 of ur file u sent
you have double arrows <<input
which is causing the html to be phased incorrectly!
It should only be <input
Also the default.handlebars files was updated last month in the latest release (last week if using the master image),
so ur behind by 5 months on changes in code
https://github.com/Ylianst/MeshCentral/blob/1.1.24/views/default.handlebars
Not related to this issue, thanks for your work though Simon! Regarding: https://github.com/Ylianst/MeshCentral/issues/5496 is there currently any plans for UI changes?
modifying views for a domain in
meshcentral-web
ormeshcentral-web-domain2
do only work for language = enThe translation tool seems to not pick up these modified files and does not translate.