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
@@ -68,7 +68,7 @@ public sealed class TelegramClientManager : IAsyncDisposable
"session_pathname" => _sessionPath,
"verification_code" => OnLoginCodeRequired != null
? OnLoginCodeRequired("Bitte Telegram-Verifizierungscode eingeben:").Result
? OnLoginCodeRequired("Please enter Telegram verification code:").Result
: throw new InvalidOperationException(
"Verification code required but no UI handler registered. " +
"Connect OnLoginCodeRequired to prompt the user."),
@@ -14,10 +14,10 @@ public sealed class TelegramClientTool : IAgentTool
public string Name => "TelegramClient";
public string Description => """
Liest Nachrichten aus dem persönlichen Telegram-Account des Nutzers.
Zugriff auf alle Chats, Gruppen und Kanäle in denen der Nutzer Mitglied ist.
NUR LESEN — kein Senden, kein Löschen, kein Bearbeiten.
Aktionen: list_chats, read_messages, read_new
Reads messages from the user's personal Telegram account.
Access to all chats, groups, and channels in which the user is a member.
READ-ONLY — no sending, deleting, or editing.
Actions: list_chats, read_messages, read_new
""";
public JsonElement InputSchema { get; } = JsonDocument.Parse("""
@@ -28,19 +28,19 @@ public sealed class TelegramClientTool : IAgentTool
"action": {
"type": "string",
"enum": ["list_chats", "read_messages", "read_new"],
"description": "list_chats: alle Chats/Gruppen/Kanäle auflisten. read_messages: letzte N Nachrichten aus einem Chat lesen. read_new: nur neue Nachrichten seit letztem Abruf."
"description": "list_chats: list all chats/groups/channels. read_messages: read last N messages from a chat. read_new: only read new messages since last fetch."
},
"chatId": {
"type": "integer",
"description": "Chat-ID aus list_chats Ergebnis. Erforderlich für read_messages und read_new."
"description": "Chat ID from list_chats result. Required for read_messages and read_new."
},
"username": {
"type": "string",
"description": "Alternativ zu chatId: @username einer Gruppe/Person auflösen."
"description": "Alternative to chatId: resolve @username of a group/person."
},
"limit": {
"type": "integer",
"description": "Max. Anzahl Nachrichten (default: 30, max: 100)"
"description": "Max. number of messages (default: 30, max: 100)"
}
}
}
@@ -54,7 +54,7 @@ public sealed class TelegramClientTool : IAgentTool
if (!_tg.IsConnected)
return ToolResult.Fail(
"Telegram-Client ist nicht verbunden. Bitte zuerst authentifizieren.");
"Telegram client is not connected. Please authenticate first.");
var action = input.GetProperty("action").GetString()
?? throw new ArgumentException("'action' is required");
@@ -212,7 +212,7 @@ public sealed class TelegramClientTool : IAgentTool
{
chatId = cid.GetInt64();
if (allowedChats != null && !allowedChats.Contains(chatId))
return (null, chatId, $"Agent hat keinen Zugriff auf Chat {chatId}.");
return (null, chatId, $"Agent does not have access to chat {chatId}.");
peer = _tg.GetInputPeerFromCache(chatId);
if (peer == null)
@@ -233,11 +233,11 @@ public sealed class TelegramClientTool : IAgentTool
chatId = resolved.peer.ID;
if (allowedChats != null && !allowedChats.Contains(chatId))
return (null, chatId, $"Agent hat keinen Zugriff auf Chat @{uname.GetString()}.");
return (null, chatId, $"Agent does not have access to chat @{uname.GetString()}.");
}
if (peer == null)
return (null, 0, "chatId oder username muss angegeben werden.");
return (null, 0, "Either chatId or username must be specified.");
return (peer, chatId, null);
}