i18n: Englisch als Hauptsprache, Sprachpakete fuer Desktop und WebUI (#661)

Umbau durch Gemini Flash, Durchsicht und Nacharbeit durch Claude.

Umfang:
- Desktop: LocalizationManager (JSON-Pakete, Rueckfall auf Englisch,
  Umschalten zur Laufzeit), Localize-Markup-Erweiterung, Sprachwahl in den
  Einstellungen (AppSettings.Language, Vorgabe "en"); 317 Schluessel je Sprache
- WebUI: alle Ansichten auf t()/data-i18n, 656 Schluessel je Sprache
- Agenten-Werkzeuge: Beschreibungen, Schemata und Meldungen auf Englisch
- Tests an die englischen Meldungen angepasst, keine Pruefung abgeschwaecht

Nacharbeit bei der Durchsicht:
- ~25 Kommentarbloecke mit Begruendungen waren ersatzlos entfallen, darunter
  sicherheitsrelevante (NTFS-Datenstrom beim shared:-Praefix, Bremse gegen
  Agentenschleifen, doppelter POST beim Anlegen einer Instanz). Wieder
  eingesetzt: auf Englisch, wo die Datei umgestellt ist, sonst im Wortlaut.
- Drei WebUI-Schluessel fehlten (logs.paused, instances.instanceOfflineError,
  instances.noInstanceActiveError). Weil t() bei fehlendem Schluessel den
  Schluessel selbst liefert, griff der "|| err.message"-Rueckfall nie — die
  Oberflaeche haette den Schluesselnamen angezeigt.

Geprueft: Schluesselgleichheit en/de, Platzhalter je Schluessel, jeder im
Code benutzte Schluessel vorhanden, node --check fuer alle Module,
1.220 Tests gruen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-09-24 09:43:51 +02:00
co-authored by Claude Opus 5.5
parent 69718122f3
commit ad71682c2d
97 changed files with 4103 additions and 1928 deletions
+47 -43
View File
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="de">
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
@@ -14,12 +14,12 @@
<div class="karte-kopf">
<h2>ClawdDotNet</h2>
</div>
<p class="hinweis">
Bitte gib das Zugangstoken des Instanzmanagers ein (<code>webUiToken</code> in <code>manager.json</code>).
<p class="hinweis" data-i18n="login.prompt">
Please enter the instance manager access token (<code>webUiToken</code> in <code>manager.json</code>).
</p>
<form id="anmeldeformular" class="formular-raster">
<input type="password" id="token-eingabe" placeholder="Zugangstoken (mind. 20 Zeichen)" autocomplete="current-password" required>
<button type="submit" class="primaer">Anmelden</button>
<input type="password" id="token-eingabe" placeholder="Access token (at least 20 characters)" data-i18n-placeholder="login.tokenPlaceholder" autocomplete="current-password" required>
<button type="submit" class="primaer" data-i18n="login.submit">Sign In</button>
<p id="anmeldefehler" class="fehler" hidden></p>
</form>
</div>
@@ -33,7 +33,7 @@
<aside id="seitenleiste" class="seitenleiste">
<div class="seitenleiste-kopf">
<span class="marke">ClawdDotNet</span>
<button id="sidebar-toggle" class="schaltflaeche-icon flach" title="Seitenleiste ein-/ausklappen" type="button">
<button id="sidebar-toggle" class="schaltflaeche-icon flach" title="Toggle sidebar" data-i18n-title="nav.toggleSidebar" type="button">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M15 18l-6-6 6-6"/>
</svg>
@@ -42,40 +42,40 @@
<nav class="seitenleiste-inhalt">
<div class="nav-gruppe">
<div class="nav-gruppe-titel">Arbeiten</div>
<a href="#/chat" class="nav-link" title="Chat">
<div class="nav-gruppe-titel" data-i18n="nav.group.work">Work</div>
<a href="#/chat" class="nav-link" title="Chat" data-i18n-title="nav.chat">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75">
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/>
</svg>
<span class="nav-label">Chat</span>
<span class="nav-label" data-i18n="nav.chat">Chat</span>
</a>
<a href="#/agenten" class="nav-link" title="Agenten">
<a href="#/agenten" class="nav-link" title="Agents" data-i18n-title="nav.agents">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75">
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2 M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8z M23 21v-2a4 4 0 0 0-3-3.87 M16 3.13a4 4 0 0 1 0 7.75"/>
</svg>
<span class="nav-label">Agenten</span>
<span class="nav-label" data-i18n="nav.agents">Agents</span>
</a>
<a href="#/aufgaben" class="nav-link" title="Aufgaben">
<a href="#/aufgaben" class="nav-link" title="Tasks" data-i18n-title="nav.tasks">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75">
<path d="M9 11l3 3L22 4 M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/>
</svg>
<span class="nav-label">Aufgaben</span>
<span class="nav-label" data-i18n="nav.tasks">Tasks</span>
</a>
<a href="#/dienste" class="nav-link" title="Dienste">
<a href="#/dienste" class="nav-link" title="Services" data-i18n-title="nav.services">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75">
<path d="M4 14a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-6z M4 4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4z M12 6v6 M8 8h.01 M16 8h.01"/>
</svg>
<span class="nav-label">Dienste</span>
<span class="nav-label" data-i18n="nav.services">Services</span>
</a>
</div>
<div class="nav-gruppe">
<div class="nav-gruppe-titel">Analyse</div>
<a href="#/verbrauch" class="nav-link" title="Tokennutzung" data-exakt>
<div class="nav-gruppe-titel" data-i18n="nav.group.analytics">Analytics</div>
<a href="#/verbrauch" class="nav-link" title="Token Usage" data-i18n-title="nav.usage" data-exakt>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75">
<path d="M3 3v18h18 M7 15v4 M11 11v8 M15 7v12 M19 12v7"/>
</svg>
<span class="nav-label">Tokennutzung</span>
<span class="nav-label" data-i18n="nav.usage">Token Usage</span>
</a>
<a href="#/verbrauch/runs" class="nav-link nav-unterlink" data-i18n-title="nav.usage.runs">
<span class="nav-label" data-i18n="nav.usage.runs">Runs</span>
@@ -89,55 +89,55 @@
</svg>
<span class="nav-label" data-i18n="nav.promptHistory">Prompt History</span>
</a>
<a href="#/agenten-chats" class="nav-link" title="Agenten-Chats">
<a href="#/agenten-chats" class="nav-link" title="Agent Chats" data-i18n-title="nav.agentChats">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75">
<path d="M8 12h.01M12 12h.01M16 12h.01 M21 12c0 4.4-4 8-9 8-1.3 0-2.6-.2-3.7-.7L3 20l1-4.2C3.4 14.6 3 13.3 3 12c0-4.4 4-8 9-8s9 3.6 9 8Z"/>
</svg>
<span class="nav-label">Agenten-Chats</span>
<span class="nav-label" data-i18n="nav.agentChats">Agent Chats</span>
</a>
</div>
<div class="nav-gruppe">
<div class="nav-gruppe-titel">System</div>
<a href="#/instanzen" class="nav-link" title="Instanzen">
<div class="nav-gruppe-titel" data-i18n="nav.group.system">System</div>
<a href="#/instanzen" class="nav-link" title="Instances" data-i18n-title="nav.instances">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75">
<path d="M2 20h20 M2 14h20 M2 8h20 M2 4h20 M6 6h.01 M6 12h.01 M6 18h.01"/>
</svg>
<span class="nav-label">Instanzen</span>
<span class="nav-label" data-i18n="nav.instances">Instances</span>
</a>
<a href="#/staging" class="nav-link" title="Freigaben">
<a href="#/staging" class="nav-link" title="Approvals" data-i18n-title="nav.staging">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75">
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z M9 12l2 2 4-4"/>
</svg>
<span class="nav-label">Freigaben</span>
<span class="nav-label" data-i18n="nav.staging">Approvals</span>
<span id="staging-badge" class="nav-badge" hidden>0</span>
</a>
<a href="#/protokoll" class="nav-link" title="Protokoll">
<a href="#/protokoll" class="nav-link" title="Logs" data-i18n-title="nav.logs">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75">
<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20 M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z M8 7h8 M8 11h6"/>
</svg>
<span class="nav-label">Protokoll</span>
<span class="nav-label" data-i18n="nav.logs">Logs</span>
</a>
<a href="#/sicherung" class="nav-link" title="Sicherung">
<a href="#/sicherung" class="nav-link" title="Backup" data-i18n-title="nav.backup">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75">
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z M17 21v-8H7v8 M7 3v5h8"/>
</svg>
<span class="nav-label">Sicherung</span>
<span class="nav-label" data-i18n="nav.backup">Backup</span>
</a>
<a href="#/einstellungen" class="nav-link" title="Einstellungen">
<a href="#/einstellungen" class="nav-link" title="Settings" data-i18n-title="nav.settings">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75">
<circle cx="12" cy="12" r="3"/>
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/>
</svg>
<span class="nav-label">Einstellungen</span>
<span class="nav-label" data-i18n="nav.settings">Settings</span>
</a>
<a href="#/info" class="nav-link" title="Info">
<a href="#/info" class="nav-link" title="Info" data-i18n-title="nav.info">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75">
<circle cx="12" cy="12" r="10"/>
<line x1="12" y1="16" x2="12" y2="12"/>
<line x1="12" y1="8" x2="12.01" y2="8"/>
</svg>
<span class="nav-label">Info</span>
<span class="nav-label" data-i18n="nav.info">Info</span>
</a>
</div>
</nav>
@@ -147,7 +147,7 @@
<div class="hauptbereich">
<header class="kopfzeile">
<div class="kopfzeile-links">
<button id="mobil-menue-btn" class="schaltflaeche-icon flach" title="Seitenleiste ein-/ausklappen" type="button">
<button id="mobil-menue-btn" class="schaltflaeche-icon flach" title="Toggle sidebar" data-i18n-title="nav.toggleSidebar" type="button">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="3" y1="12" x2="21" y2="12"/>
<line x1="3" y1="6" x2="21" y2="6"/>
@@ -155,19 +155,23 @@
</svg>
</button>
<div class="kopf-instanz-container" id="kopf-instanz-container">
<label for="kopf-instanz-select" class="kopf-instanz-label">Instanz:</label>
<select id="kopf-instanz-select" class="eingabe-select klein kopf-instanz-select" title="Aktive Instanz wechseln">
<option value="">(Keine Instanz)</option>
<label for="kopf-instanz-select" class="kopf-instanz-label" data-i18n="header.instanceLabel">Instance:</label>
<select id="kopf-instanz-select" class="eingabe-select klein kopf-instanz-select" title="Switch active instance" data-i18n-title="header.switchInstance">
<option value="" data-i18n="header.noInstance">(No instance)</option>
</select>
<span id="kopf-instanz-status" class="plakette plakette-neutral">Lädt…</span>
<button id="kopf-instanz-start-btn" class="schaltflaeche klein primaer" title="Ausgewählte Instanz jetzt starten" type="button" hidden>Starten</button>
<span id="kopf-instanz-status" class="plakette plakette-neutral" data-i18n="common.loading">Loading…</span>
<button id="kopf-instanz-start-btn" class="schaltflaeche klein primaer" title="Start selected instance now" data-i18n="header.startInstance" data-i18n-title="header.startInstanceTooltip" type="button" hidden>Start</button>
</div>
</div>
<div class="kopfzeile-rechts">
<span id="kopf-openrouter-status" class="gedaempft text-klein"></span>
<span id="verbindung-punkt" class="status-punkt" title="Ereignisstrom: getrennt"></span>
<button id="theme-schalter" class="schaltflaeche-icon flach" title="Farbschema umschalten" type="button">
<span id="verbindung-punkt" class="status-punkt" title="Event stream: disconnected" data-i18n-title="header.eventStreamDisconnected"></span>
<select id="sprache-schalter" class="eingabe-select klein" title="Language" data-i18n-title="common.language">
<option value="en">English</option>
<option value="de">Deutsch</option>
</select>
<button id="theme-schalter" class="schaltflaeche-icon flach" title="Toggle color theme" data-i18n-title="header.toggleTheme" type="button">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="5"/>
<line x1="12" y1="1" x2="12" y2="3"/>
@@ -180,8 +184,8 @@
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/>
</svg>
</button>
<button id="abmelden-btn" class="schaltflaeche flach klein" title="Abmelden" type="button">
Abmelden
<button id="abmelden-btn" class="schaltflaeche flach klein" title="Log Out" data-i18n="common.logout" data-i18n-title="common.logout" type="button">
Log Out
</button>
</div>
</header>