Mehrsprachigkeit (Englisch/Deutsch, Systemsprache oder Auswahl in den Einstellungen), README auf Englisch für Nutzer, Version 0.4.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+16
-12
@@ -9,6 +9,8 @@ const { SshManager } = require('./ssh');
|
||||
const rdp = require('./rdp');
|
||||
const { Updater } = require('./updater');
|
||||
const { createEmbed, embedSupported } = require('./rdp-embed');
|
||||
const i18n = require('../i18n');
|
||||
const applyLanguage = () => i18n.setLanguage(store.get().settings.language, app.getLocale());
|
||||
|
||||
let win;
|
||||
const store = new Store();
|
||||
@@ -34,12 +36,12 @@ async function confirmHostKey(target, fingerprint, known) {
|
||||
const changed = !!known;
|
||||
const r = await dialog.showMessageBox(win, {
|
||||
type: changed ? 'warning' : 'question',
|
||||
title: changed ? 'Host-Schlüssel hat sich geändert!' : 'Unbekannter Host',
|
||||
title: changed ? i18n.t('Host key has changed!') : i18n.t('Unknown host'),
|
||||
message: changed
|
||||
? `WARNUNG: Der Host-Schlüssel von ${target.host}:${target.port} hat sich geändert. Das kann auf einen Man-in-the-Middle-Angriff hindeuten.`
|
||||
: `Die Echtheit von ${target.host}:${target.port} kann nicht bestätigt werden.`,
|
||||
detail: `Fingerprint:\n${fingerprint}${changed ? `\n\nBisher gespeichert:\n${known.fingerprint}` : ''}`,
|
||||
buttons: [changed ? 'Trotzdem verbinden & ersetzen' : 'Vertrauen & verbinden', 'Abbrechen'],
|
||||
? i18n.t('WARNING: The host key of {target} has changed. This may indicate a man-in-the-middle attack.', { target: `${target.host}:${target.port}` })
|
||||
: i18n.t('The authenticity of {target} cannot be verified.', { target: `${target.host}:${target.port}` }),
|
||||
detail: `Fingerprint:\n${fingerprint}${changed ? `\n\n${i18n.t('Previously stored:')}\n${known.fingerprint}` : ''}`,
|
||||
buttons: [changed ? i18n.t('Connect anyway & replace') : i18n.t('Trust & connect'), i18n.t('Cancel')],
|
||||
defaultId: changed ? 1 : 0,
|
||||
cancelId: 1,
|
||||
});
|
||||
@@ -104,6 +106,7 @@ handle('vault:upsert', (col, item) => store.upsert(col, item));
|
||||
handle('vault:remove', (col, id) => store.remove(col, id));
|
||||
handle('vault:settings', (s) => {
|
||||
store.setSettings(s);
|
||||
if ('language' in s) applyLanguage();
|
||||
if ('rdpEmbed' in s) fs.writeFileSync(launchFile, JSON.stringify({ ...readLaunch(), x11: s.rdpEmbed !== false }));
|
||||
});
|
||||
handle('vault:forgetHost', (id) => { delete store.get().knownHosts[id]; store.save(); });
|
||||
@@ -125,7 +128,7 @@ handle('vault:import', async () => {
|
||||
// Import aus ~/.ssh/config
|
||||
handle('vault:importSshConfig', () => {
|
||||
const file = path.join(os.homedir(), '.ssh', 'config');
|
||||
if (!fs.existsSync(file)) throw new Error('~/.ssh/config nicht gefunden');
|
||||
if (!fs.existsSync(file)) throw new Error(i18n.t('~/.ssh/config not found'));
|
||||
const entries = [];
|
||||
let cur = null;
|
||||
for (const raw of fs.readFileSync(file, 'utf8').split(/\r?\n/)) {
|
||||
@@ -188,7 +191,7 @@ handle('key:pickFile', async () => {
|
||||
function hostWithOverrides(hostOrId) {
|
||||
if (typeof hostOrId === 'string') {
|
||||
const h = store.resolveHost(hostOrId);
|
||||
if (!h) throw new Error('Host nicht gefunden');
|
||||
if (!h) throw new Error(i18n.t('Host not found'));
|
||||
return h;
|
||||
}
|
||||
return hostOrId; // Quick-Connect: temporärer Host
|
||||
@@ -245,7 +248,7 @@ handle('local:op', (op, a, b) => {
|
||||
// ---------- Port-Forwarding ----------
|
||||
handle('fw:start', (id) => {
|
||||
const fw = store.get().forwards.find((f) => f.id === id);
|
||||
if (!fw) throw new Error('Regel nicht gefunden');
|
||||
if (!fw) throw new Error(i18n.t('Rule not found'));
|
||||
return ssh.startForward(fw, (ev) => send('fw:event', id, ev));
|
||||
});
|
||||
handle('fw:stop', (id) => ssh.stopForward(id));
|
||||
@@ -258,8 +261,8 @@ handle('rdp:launch', (hostId) => {
|
||||
if (host.id) store.addHistory({ hostId: host.id, at: Date.now() });
|
||||
const r = rdp.launch(host, store.get().settings);
|
||||
if (r.process) {
|
||||
r.process.on('exit', (code) => { if (code && code !== 0 && code !== 12) send('toast', `RDP beendet (Code ${code}): ${r.getErr().split('\n').filter(Boolean).slice(-1)[0] || ''}`, 'error'); });
|
||||
r.process.on('error', (e) => send('toast', 'RDP-Start fehlgeschlagen: ' + e.message, 'error'));
|
||||
r.process.on('exit', (code) => { if (code && code !== 0 && code !== 12) send('toast', i18n.t('RDP exited (code {code}): {err}', { code, err: r.getErr().split('\n').filter(Boolean).slice(-1)[0] || '' }), 'error'); });
|
||||
r.process.on('error', (e) => send('toast', i18n.t('RDP launch failed: {msg}', { msg: e.message }), 'error'));
|
||||
}
|
||||
return r.client;
|
||||
});
|
||||
@@ -268,7 +271,7 @@ handle('rdp:launch', (hostId) => {
|
||||
const rdpSessions = new Map();
|
||||
handle('rdp:embedSupported', () => {
|
||||
const s = embedSupported();
|
||||
if (s.ok && process.platform === 'linux' && !rdp.linuxClient(null, true)) return { ok: false, reason: 'xfreerdp3 fehlt (sudo pacman -S freerdp)' };
|
||||
if (s.ok && process.platform === 'linux' && !rdp.linuxClient(null, true)) return { ok: false, reason: i18n.t('xfreerdp3 missing (sudo pacman -S freerdp)') };
|
||||
return s;
|
||||
});
|
||||
handle('rdp:open', async (id, hostRef, bounds) => {
|
||||
@@ -320,7 +323,7 @@ handle('rdp:detach', (id) => {
|
||||
|
||||
// ---------- Import aus anderen Programmen (z. B. Devolutions RDM) ----------
|
||||
handle('import:pickFile', async (title, extensions) => {
|
||||
const r = await dialog.showOpenDialog(win, { title, filters: [{ name: title, extensions }, { name: 'Alle Dateien', extensions: ['*'] }], properties: ['openFile'] });
|
||||
const r = await dialog.showOpenDialog(win, { title, filters: [{ name: title, extensions }, { name: i18n.t('All files'), extensions: ['*'] }], properties: ['openFile'] });
|
||||
if (r.canceled) return null;
|
||||
const buf = fs.readFileSync(r.filePaths[0]);
|
||||
// UTF-16-Exporte (BOM) erkennen
|
||||
@@ -364,6 +367,7 @@ handle('shell:open', (url) => shell.openExternal(url));
|
||||
|
||||
app.whenReady().then(() => {
|
||||
store.load();
|
||||
applyLanguage();
|
||||
createWindow();
|
||||
if (store.get().settings.updateAutoCheck && app.isPackaged) {
|
||||
setTimeout(() => updater.check().then((r) => { if (r.available) send('update:available', r); }).catch(() => {}), 6000);
|
||||
|
||||
Reference in New Issue
Block a user