From f983d69a0cf2aeb26b4e35a12a50d9483c0840d4 Mon Sep 17 00:00:00 2001 From: chk <79915315+ChKendel@users.noreply.github.com> Date: Tue, 16 Jun 2026 13:55:42 +0200 Subject: [PATCH] Neue Marker Unterarm --- doc/multilingual.md | 232 +++++++++++++++++++++++++++++++ scripts/robot_1781069752019.json | 12 +- 2 files changed, 240 insertions(+), 4 deletions(-) create mode 100644 doc/multilingual.md diff --git a/doc/multilingual.md b/doc/multilingual.md new file mode 100644 index 0000000..9ebd271 --- /dev/null +++ b/doc/multilingual.md @@ -0,0 +1,232 @@ +# Mehrsprachigkeit (DE/EN) – Vorschlag + +## Ausgangslage + +Die App ist heute komplett deutschsprachig, und zwar an drei verschiedenen Stellen, die unterschiedlich behandelt werden müssen: + +1. **Statisches HTML-Markup** – Labels, Überschriften, `placeholder`/`title`-Attribute direkt in + `public/*.html` (`index.html`, `homing.html`, `calibration*.html`, …). + Beispiel: `

Aktionen

`, ` +``` + +Wichtig: Der **deutsche Text bleibt im HTML stehen** (als Fallback/Default und damit die Seite ohne +JS oder bei Ladefehler nicht leer ist). `i18n.js` ersetzt den Inhalt nur, wenn die Zielsprache nicht +Deutsch ist bzw. wenn ein Override gesetzt wurde. Das macht die Migration risikoarm: Man kann Seite +für Seite Attribute ergänzen, ohne dass etwas kaputtgeht, falls eine Seite noch nicht migriert ist. + +## 3. `i18n.js` – minimale Laufzeit-Bibliothek + +Kernfunktionen, ca. 60–80 Zeilen, kein Tooling nötig: + +```js +// public/i18n.js +const SUPPORTED = ['de', 'en']; +const FALLBACK = 'de'; + +function detectLang() { + const stored = localStorage.getItem('lang'); + if (stored && SUPPORTED.includes(stored)) return stored; + const nav = (navigator.language || FALLBACK).slice(0, 2).toLowerCase(); + return SUPPORTED.includes(nav) ? nav : FALLBACK; +} + +let dict = {}; +let fallbackDict = {}; + +export async function initI18n() { + const lang = detectLang(); + [dict, fallbackDict] = await Promise.all([ + fetch(`/i18n/${lang}.json`).then(r => r.json()), + lang === FALLBACK ? Promise.resolve({}) : fetch(`/i18n/${FALLBACK}.json`).then(r => r.json()), + ]); + document.documentElement.lang = lang; + applyToDom(); + return lang; +} + +export function t(key, vars) { + let str = dict[key] ?? fallbackDict[key] ?? key; // Key selbst als letzter Fallback -> sichtbar im UI statt "undefined" + if (vars) for (const [k, v] of Object.entries(vars)) str = str.replaceAll(`{${k}}`, v); + return str; +} + +function applyToDom(root = document) { + root.querySelectorAll('[data-i18n]').forEach(el => { el.textContent = t(el.dataset.i18n); }); + root.querySelectorAll('[data-i18n-attr-title]').forEach(el => { el.title = t(el.dataset.i18nAttrTitle); }); + root.querySelectorAll('[data-i18n-attr-placeholder]').forEach(el => { el.placeholder = t(el.dataset.i18nAttrPlaceholder); }); +} + +export async function setLang(lang) { + localStorage.setItem('lang', lang); + location.reload(); // einfach & robust, kein dynamisches Re-Rendering nötig bei dieser App-Größe +} +``` + +Einbindung pro Seite (vor dem bestehenden Seiten-Script): + +```html + + + +``` + +Da `client.js`/`homing.js`/`calibration.js` aktuell keine ES-Module sind, reicht es, `initI18n()` +in einem kleinen Inline-`