From 1edc571686cea52767b3e30683a0e4b982385308 Mon Sep 17 00:00:00 2001
From: Sucukdeluxe <259325684+Sucukdeluxe@users.noreply.github.com>
Date: Sat, 22 Aug 2026 10:07:46 +0200
Subject: [PATCH] fix: align German online backup controls
Use compact German key labels and a shared fixed label column so both online-backup inputs and actions align consistently across languages. Restore the narrow one-column breakpoint after later settings overrides and cover translations plus real hidden CSS geometry.
---
renderer/app.js | 4 ++--
renderer/i18n.js | 2 ++
renderer/styles.css | 10 ++++++++--
tests/i18n.test.js | 7 +++++++
tests/startup-renderer.test.js | 19 ++++++++++++++++++-
5 files changed, 37 insertions(+), 5 deletions(-)
diff --git a/renderer/app.js b/renderer/app.js
index 383ba1e..856c55f 100644
--- a/renderer/app.js
+++ b/renderer/app.js
@@ -4872,12 +4872,12 @@ function renderSettings() {
Jeder Export erzeugt einen neuen Schlüssel. Ältere Schlüssel bleiben gültig.
-
+
-
+
diff --git a/renderer/i18n.js b/renderer/i18n.js
index 929bbd5..efb4771 100644
--- a/renderer/i18n.js
+++ b/renderer/i18n.js
@@ -309,7 +309,9 @@
['Neuen Schlüssel erzeugen', 'Generate new key'],
['Jeder Export erzeugt einen neuen Schlüssel. Ältere Schlüssel bleiben gültig.', 'Each export creates a new key. Older keys remain valid.'],
['Dein neuer Schlüssel', 'Your new key'],
+ ['Neuer Schlüssel', 'Your new key'],
['Vorhandenen Schlüssel importieren', 'Import existing key'],
+ ['Schlüssel importieren', 'Import existing key'],
['Online importieren', 'Import online'],
['Behandle den Schlüssel wie ein Passwort. Wer ihn besitzt, kann die verschlüsselten Einstellungen entschlüsseln.', 'Treat the key like a password. Anyone who has it can decrypt the encrypted settings.'],
['Lokales Datei-Backup', 'Local file backup'],
diff --git a/renderer/styles.css b/renderer/styles.css
index e1c33ed..62a540f 100644
--- a/renderer/styles.css
+++ b/renderer/styles.css
@@ -1896,7 +1896,7 @@ select.hs-input { max-width: none; width: auto; min-width: 140px; }
.online-backup-key-row {
display: grid;
- grid-template-columns: minmax(170px, auto) minmax(240px, 1fr) auto;
+ grid-template-columns: 150px minmax(240px, 1fr) auto;
gap: 10px;
align-items: center;
}
@@ -3603,7 +3603,13 @@ input[type="checkbox"] {
}
.online-backup-key-row {
- grid-template-columns: minmax(140px, auto) minmax(180px, 1fr) auto;
+ grid-template-columns: 150px minmax(180px, 1fr) auto;
+}
+
+@media (max-width: 820px) {
+ .online-backup-key-row {
+ grid-template-columns: 1fr;
+ }
}
#settings-view {
diff --git a/tests/i18n.test.js b/tests/i18n.test.js
index c9d5e37..47b79bb 100644
--- a/tests/i18n.test.js
+++ b/tests/i18n.test.js
@@ -16,6 +16,13 @@ test('translates the remaining upload size label', () => {
assert.equal(translateText('Remaining size', 'de'), 'Verbleibende Größe');
});
+test('translates compact online backup labels in both directions', () => {
+ assert.equal(translateText('Neuer Schlüssel', 'en'), 'Your new key');
+ assert.equal(translateText('Your new key', 'de'), 'Neuer Schlüssel');
+ assert.equal(translateText('Schlüssel importieren', 'en'), 'Import existing key');
+ assert.equal(translateText('Import existing key', 'de'), 'Schlüssel importieren');
+});
+
test('translates the account check timestamp label', () => {
assert.equal(translateText('geprüft', 'en'), 'checked');
assert.equal(translateText('checked', 'de'), 'geprüft');
diff --git a/tests/startup-renderer.test.js b/tests/startup-renderer.test.js
index ba1ec88..d468e1e 100644
--- a/tests/startup-renderer.test.js
+++ b/tests/startup-renderer.test.js
@@ -69,6 +69,17 @@ contextBridge.exposeInMainWorld('api', {
getConfig() { return new Promise(() => {}); }
});
`, 'utf8');
+ const onlineBackupLayoutScript = `(() => {
+ document.documentElement.lang = 'de';
+ document.body.innerHTML = '';
+ const rows = [...document.querySelectorAll('.online-backup-key-row')];
+ return rows.map(row => {
+ const label = row.querySelector('label').getBoundingClientRect();
+ const input = row.querySelector('input').getBoundingClientRect();
+ const button = row.querySelector('button').getBoundingClientRect();
+ return { labelWidth: label.width, inputLeft: input.left, buttonRight: button.right };
+ });
+ })()`;
const probeSource = `
const { app, BrowserWindow, screen } = require('electron');
const { execFileSync } = require('node:child_process');
@@ -104,6 +115,7 @@ app.whenReady().then(async () => {
const middleY = Math.floor(size.height / 2);
await window.loadFile(process.env.MHU_RENDERER_PATH, { query: { language: 'en', version: '2.1.31' } });
const liveSpeedChart = await window.webContents.executeJavaScript('({ baselinePresent: Boolean(document.querySelector(".upload-speed-baseline")), canvasWidth: document.getElementById("uploadSpeedCanvas")?.getBoundingClientRect().width || 0 })');
+ const onlineBackupLayout = await window.webContents.executeJavaScript(${JSON.stringify(onlineBackupLayoutScript)});
fs.writeFileSync(outputPath, JSON.stringify({
size,
dom,
@@ -114,7 +126,8 @@ app.whenReady().then(async () => {
rendererCommandLine,
leftEdge: pixelAt(bitmap, size.width, 0, middleY),
rightEdge: pixelAt(bitmap, size.width, size.width - 1, middleY),
- liveSpeedChart
+ liveSpeedChart,
+ onlineBackupLayout
}), 'utf8');
window.destroy();
app.exit(0);
@@ -154,6 +167,10 @@ app.whenReady().then(async () => {
assert.ok(result.rightEdge[0] > result.rightEdge[1] && result.rightEdge[2] > result.rightEdge[1]);
assert.ok(result.liveSpeedChart.canvasWidth > 0);
assert.equal(result.liveSpeedChart.baselinePresent, false);
+ assert.equal(result.onlineBackupLayout.length, 2);
+ assert.ok(Math.abs(result.onlineBackupLayout[0].labelWidth - result.onlineBackupLayout[1].labelWidth) <= 1);
+ assert.ok(Math.abs(result.onlineBackupLayout[0].inputLeft - result.onlineBackupLayout[1].inputLeft) <= 1);
+ assert.ok(Math.abs(result.onlineBackupLayout[0].buttonRight - result.onlineBackupLayout[1].buttonRight) <= 1);
} finally {
fs.rmSync(probeRoot, { recursive: true, force: true });
}