'use strict'; /** * Sprachen des Windows-Programms: Deutsch (Quelltext) und English. * Der Quelltext ist deutsch; bei English werden alle Texte beim Aufbau der Oberfläche über das Wörterbuch (lang-en.js) übersetzt: * Textknoten, Attribute (placeholder, title …), textContent, Meldungen (toast), confirm/alert und Benachrichtigungen. * Schlüssel = deutscher Text; "{}" = beliebiger Teil, "{#}" = Zahl, "{1}"/"{2}" = Reihenfolge in der Übersetzung. Was fehlt, bleibt deutsch. * Die Wahl steht in localStorage ("lang") und wird nach dem Umschalten (Klick auf eine Flagge) durch Neuladen übernommen. */ (function () { const stored = (() => { try { return localStorage.getItem('lang'); } catch { return null; } })(); const lang = stored === 'de' || stored === 'en' ? stored : ((navigator.language || 'de').toLowerCase().startsWith('de') ? 'de' : 'en'); const FLAG = { de: 'data:image/svg+xml;base64,' + btoa(''), en: 'data:image/svg+xml;base64,' + btoa(''), }; const NAMES = { de: 'Deutsch', en: 'English' }; const exact = new Map(); const patterns = []; const norm = (s) => String(s).replace(/\s+/g, ' ').trim(); if (lang === 'en' && window.I18N_EN) { for (const [k, v] of Object.entries(window.I18N_EN)) { if (!v || k[0] === '_') continue; const key = norm(k); if (key.includes('{}') || key.includes('{#}')) { const parts = key.split(/(\{#\}|\{\})/); const re = '^' + parts.map((p, i) => (i % 2 === 0 ? p.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') : (p === '{#}' ? '(\\d+)' : '(.+?)'))).join('') + '$'; patterns.push([new RegExp(re, 's'), v]); } else exact.set(key, v); } } // Übersetzt einen Text; Leerraum am Rand bleibt erhalten, unbekannte Texte bleiben unverändert function t(s) { if (lang !== 'en' || typeof s !== 'string' || s === '') return s; const m = /^(\s*)([\s\S]*?)(\s*)$/.exec(s); const key = norm(m[2]); if (!key) return s; let r = exact.get(key); if (r === undefined) { for (const [re, v] of patterns) { const mm = re.exec(key); if (mm) { let i = 0; // Eingefügte Teile werden selbst noch einmal übersetzt (zum Beispiel „in 2 Std 5 Min“ in „Lösung fällig: {}“) r = v.replace(/\{(\d+)\}/g, (_, n) => t(mm[+n] ?? '')).replace(/\{\}/g, () => t(mm[++i] ?? '')); break; } } } return r === undefined ? s : m[1] + r + m[3]; } if (lang === 'en') { // Textknoten, die über createTextNode oder append() entstehen const ct = Document.prototype.createTextNode; Document.prototype.createTextNode = function (d) { return ct.call(this, t(String(d))); }; for (const name of ['append', 'prepend']) { const orig = Element.prototype[name]; Element.prototype[name] = function (...a) { return orig.apply(this, a.map((x) => (typeof x === 'string' ? t(x) : x))); }; } const sa = Element.prototype.setAttribute; const attrs = new Set(['placeholder', 'title', 'aria-label', 'alt']); Element.prototype.setAttribute = function (n, v) { return sa.call(this, n, attrs.has(n) && typeof v === 'string' ? t(v) : v); }; const td = Object.getOwnPropertyDescriptor(Node.prototype, 'textContent'); Object.defineProperty(Node.prototype, 'textContent', { ...td, set(v) { td.set.call(this, typeof v === 'string' ? t(v) : v); } }); const ph = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'placeholder'); if (ph) Object.defineProperty(HTMLInputElement.prototype, 'placeholder', { ...ph, set(v) { ph.set.call(this, t(String(v))); } }); for (const fn of ['confirm', 'alert']) { const o = window[fn].bind(window); window[fn] = (m) => o(t(String(m))); } document.documentElement.lang = 'en'; } // Sprachwechsler mit Flaggen (gleiche Optik wie im Web) function switcher() { const box = document.createElement('span'); box.className = 'lang-switch'; box.setAttribute('role', 'group'); for (const code of ['de', 'en']) { const a = document.createElement('button'); a.type = 'button'; a.className = 'lang-flag' + (code === lang ? ' on' : ''); a.title = NAMES[code]; a.setAttribute('aria-label', NAMES[code]); if (code === lang) a.setAttribute('aria-current', 'true'); const img = document.createElement('img'); img.src = FLAG[code]; img.alt = ''; img.width = 24; img.height = 16; a.appendChild(img); a.addEventListener('click', () => { if (code !== lang) setLang(code); }); box.appendChild(a); } return box; } function setLang(code) { try { localStorage.setItem('lang', code); } catch {} try { window.deskhub?.setSettings?.({ language: code }); } catch {} location.reload(); } try { window.deskhub?.setSettings?.({ language: lang }); } catch {} window.I18N = { lang, t, switcher, setLang, locale: lang === 'en' ? 'en-GB' : 'de-DE' }; window.tr = t; })();