From 0d41e94ca99ca873148081e597fabf5d339f267b Mon Sep 17 00:00:00 2001 From: Miniding Date: Tue, 5 May 2026 19:26:00 +0200 Subject: [PATCH] feat(i18n): add French (fr) locale support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add fr.yaml with French translations for approval prompts and gateway messages - Register 'fr' in SUPPORTED_LANGUAGES - Add French aliases: french, français, fr-fr, fr-be, fr-ca, fr-ch - Update locale sync comment in en.yaml --- agent/i18n.py | 5 +++-- locales/en.yaml | 2 +- locales/fr.yaml | 24 ++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 locales/fr.yaml diff --git a/agent/i18n.py b/agent/i18n.py index 98d7ebce9a..c700491522 100644 --- a/agent/i18n.py +++ b/agent/i18n.py @@ -25,7 +25,7 @@ Language resolution order: 3. ``display.language`` from config.yaml 4. ``"en"`` (baseline) -Supported languages: en, zh, ja, de, es. Unknown values fall back to en. +Supported languages: en, zh, ja, de, es, fr. Unknown values fall back to en. """ from __future__ import annotations @@ -39,7 +39,7 @@ from typing import Any logger = logging.getLogger(__name__) -SUPPORTED_LANGUAGES: tuple[str, ...] = ("en", "zh", "ja", "de", "es") +SUPPORTED_LANGUAGES: tuple[str, ...] = ("en", "zh", "ja", "de", "es", "fr") DEFAULT_LANGUAGE = "en" # Accept a few natural aliases so users who type "chinese" / "zh-CN" / "jp" @@ -50,6 +50,7 @@ _LANGUAGE_ALIASES: dict[str, str] = { "japanese": "ja", "jp": "ja", "ja-jp": "ja", "german": "de", "deutsch": "de", "de-de": "de", "spanish": "es", "español": "es", "espanol": "es", "es-es": "es", "es-mx": "es", + "french": "fr", "français": "fr", "france": "fr", "fr-fr": "fr", "fr-be": "fr", "fr-ca": "fr", "fr-ch": "fr", } _catalog_cache: dict[str, dict[str, str]] = {} diff --git a/locales/en.yaml b/locales/en.yaml index 283f8cb871..10c522dd25 100644 --- a/locales/en.yaml +++ b/locales/en.yaml @@ -7,7 +7,7 @@ # # Keys are dotted paths; nesting below is purely for readability. Values may # contain {placeholder} tokens for str.format substitution. When adding a -# new key, add it to EVERY locale file (en/zh/ja/de/es) in the same commit -- +# new key, add it to EVERY locale file (en/zh/ja/de/es/fr) in the same commit -- # tests/agent/test_i18n.py asserts catalog parity. approval: diff --git a/locales/fr.yaml b/locales/fr.yaml new file mode 100644 index 0000000000..2127f7396b --- /dev/null +++ b/locales/fr.yaml @@ -0,0 +1,24 @@ +# Hermes static-message catalog -- French (français) +# See locales/en.yaml for the source of truth; keep keys in sync. + +approval: + dangerous_header: "⚠️ COMMANDE DANGEREUSE : {description}" + choose_long: " [o]ne fois | [s]ession | [t]oujours | [r]efuser" + choose_short: " [o]ne fois | [s]ession | [r]efuser" + prompt_long: " Choix [o/s/t/R] : " + prompt_short: " Choix [o/s/R] : " + timeout: " ⏱ Délai dépassé — commande refusée" + allowed_once: " ✓ Autorisé une fois" + allowed_session: " ✓ Autorisé pour cette session" + allowed_always: " ✓ Ajouté à la liste d'autorisation permanente" + denied: " ✗ Refusé" + cancelled: " ✗ Annulé" + blocklist_message: "Cette commande est sur la liste de blocage inconditionnel et ne peut pas être approuvée." + +gateway: + approval_expired: "⚠️ Approbation expirée (l'agent n'attend plus). Demandez à l'agent de réessayer." + draining: "⏳ Vidage de {count} agent(s) actif(s) avant redémarrage..." + goal_cleared: "✓ Objectif effacé." + no_active_goal: "Aucun objectif actif." + config_read_failed: "⚠️ Impossible de lire config.yaml : {error}" + config_save_failed: "⚠️ Impossible de sauvegarder la configuration : {error}"