Files
hermes-agent/web/src/i18n/fr.ts
T
Austin PickettandCursor 6d14a24b79 feat(dashboard): nous-blue theme, bulk sessions, schedule picker (#37383)
* feat(dashboard): nous-blue theme, bulk sessions, schedule picker

Batch of related dashboard improvements gathered on
austin/fix/dashboard-changes:

* Nous Blue theme — faithful port of the LENS_5I overlay system onto
  the existing DashboardTheme. Lifts the foreground inversion layer to
  z-index 200 to fix the long-standing hover / loading visual artifact,
  adds an explicit swatchColors slot so the theme picker shows the
  post-inversion preview, and migrates the legacy "lens-5i" theme key
  from localStorage / API to "nous-blue" on first read.
* Theme-aware series colors: new --series-input-token /
  --series-output-token CSS vars consumed by Analytics + Models
  charts; ToolCall + ModelInfoCard switched to semantic
  --color-success for diff lines and the Tools capability badge.
* Analytics + Models headers: consolidate period selector + refresh
  next to the page title and drop the redundant period badge.
* Bulk session management — "Delete empty (N)" button + per-row
  checkboxes with shift-click range select and a bulk-delete action
  bar. Backed by SessionDB.delete_sessions() /
  delete_empty_sessions() plus POST /api/sessions/bulk-delete and
  DELETE /api/sessions/empty (registered before the templated
  /api/sessions/{session_id} family so they don't get shadowed).
  Hard cap of 500 IDs per bulk request. Full pytest coverage.
* Cron page — human-readable schedule picker (every-interval / daily
  / weekly / monthly / once / custom) replaces the raw cron
  expression input; the job list now renders "Weekly on Mon, Wed,
  Fri at 14:30" instead of "30 14 * * 1,3,5". English-only ordinals
  for monthly schedules so non-English locales don't get incorrect
  suffixes.
* example-dashboard plugin moved from plugins/ to tests/fixtures/ so
  stock installs no longer ship the demo. Tests install it
  dynamically via a pytest fixture that also reorders the FastAPI
  routes.
* i18n: 40+ new keys for the bulk-select UI and schedule
  picker/describer translated across all 16 locales.

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor(dashboard): dedupe memory provider picker

The memory provider <Select> lived on both /system and /plugins,
writing the same config.yaml field through two different endpoints
with no cross-page refresh. Remove the picker from /system in favor
of a read-only status row + link to /plugins, where it pairs with
the context-engine picker under "Plugin providers".

/system retains the destructive admin controls (file sizes, Reset
MEMORY.md / USER.md / all). The api.setMemoryProvider client and
PUT /api/memory/provider backend endpoint are left in place for
CLI / script callers.

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs(dashboard): address Copilot review on PR #37383

- Backdrop layer-stack comment claimed LENS_5I-style themes override
  --component-backdrop-bg-blend-mode to multiply, but our only
  LENS_5I-style theme (nous-blue) keeps the default difference.
  Reword to describe what the code actually does and present the
  var as a forward-looking extension hook.
- /api/sessions/bulk-delete docstring promised the response would
  echo back the list of deleted IDs, but the implementation only
  returns {ok, deleted}. Tighten the docstring to match the wire
  format; the client already knows what it asked to delete, so the
  IDs aren't needed.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(dashboard): address copilot review on cron describe + bulk-select checkbox

- schedule.ts: restrict `describeCronExpression` to strictly 5-field cron
  expressions. The backend `parse_schedule` also accepts the 6-field
  `min hour dom month dow year` form, and humanising those by
  destructuring only the first five fields would silently drop the year
  (e.g. ``0 9 * * * 2099`` rendered as "Daily at 09:00"). 6+ field
  expressions now fall through to the raw-string fallback so the user
  sees what's actually scheduled.

- SessionsPage.tsx (SessionRow): wire the bulk-select Checkbox's
  ``onClick`` directly instead of attaching it to a parent ``<span>``
  with a no-op ``onCheckedChange``. Radix forwards onClick to the
  underlying ``<button role=checkbox>``, so the same handler now drives
  both mouse clicks (preserving shift-key state for range select) and
  keyboard activation (Space on the focused checkbox, which the browser
  synthesises as a click on the <button>). Improves a11y / keyboard UX
  without changing the controlled-selection model.

- SessionsPage.tsx: also extend ``SessionRowProps`` with the new
  ``onRename`` / ``onExport`` props introduced on main so the row's
  destructured prop types resolve after the merge.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 12:37:40 -04:00

753 lines
30 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { Translations } from "./types";
export const fr: Translations = {
common: {
save: "Enregistrer",
saving: "Enregistrement...",
cancel: "Annuler",
close: "Fermer",
confirm: "Confirmer",
delete: "Supprimer",
refresh: "Actualiser",
retry: "Réessayer",
search: "Rechercher...",
loading: "Chargement...",
create: "Créer",
creating: "Création...",
set: "Définir",
replace: "Remplacer",
clear: "Effacer",
live: "En direct",
off: "Désactivé",
enabled: "activé",
disabled: "désactivé",
active: "actif",
inactive: "inactif",
unknown: "inconnu",
untitled: "Sans titre",
none: "Aucun",
form: "Formulaire",
noResults: "Aucun résultat",
of: "sur",
page: "Page",
msgs: "msgs",
tools: "outils",
match: "correspondance",
other: "Autre",
configured: "configuré",
removed: "supprimé",
failedToToggle: "Échec du basculement",
failedToRemove: "Échec de la suppression",
failedToReveal: "Échec de l'affichage",
collapse: "Réduire",
expand: "Développer",
general: "Général",
messaging: "Messagerie",
pluginLoadFailed:
"Impossible de charger le script de ce plugin. Vérifiez l'onglet Réseau (dashboard-plugins/…) et le chemin des plugins du serveur.",
pluginNotRegistered:
"Le script du plugin n'a pas appelé register(), ou le script a échoué. Ouvrez la console du navigateur pour plus de détails.",
},
app: {
brand: "Hermes Agent",
brandShort: "HA",
closeNavigation: "Fermer la navigation",
closeModelTools: "Fermer modèle et outils",
footer: {
org: "Nous Research",
},
activeSessionsLabel: "Sessions actives:",
gatewayStatusLabel: "État de la passerelle:",
gatewayStrip: {
failed: "Échec du démarrage",
off: "Désactivé",
running: "En cours",
starting: "Démarrage",
stopped: "Arrêté",
},
nav: {
analytics: "Analyses",
chat: "Chat",
config: "Configuration",
cron: "Cron",
documentation: "Documentation",
keys: "Clés",
logs: "Journaux",
models: "Modèles",
profiles: "profils : multi agents",
plugins: "Plugins",
sessions: "Sessions",
skills: "Compétences",
},
modelToolsSheetSubtitle: "& outils",
modelToolsSheetTitle: "Modèle",
navigation: "Navigation",
openDocumentation: "Ouvrir la documentation dans un nouvel onglet",
openNavigation: "Ouvrir la navigation",
pluginNavSection: "Plugins",
sessionsActiveCount: "{count} actives",
statusOverview: "Aperçu de l'état",
system: "Système",
webUi: "Web UI",
},
status: {
actionFailed: "Action échouée",
actionFinished: "Terminé",
actions: "Actions",
agent: "Agent",
activeSessions: "Sessions actives",
connected: "Connecté",
connectedPlatforms: "Plateformes connectées",
disconnected: "Déconnecté",
error: "Erreur",
failed: "Échec",
gateway: "Passerelle",
gatewayFailedToStart: "Le démarrage de la passerelle a échoué",
lastUpdate: "Dernière mise à jour",
noneRunning: "Aucun",
notRunning: "Non lancé",
pid: "PID",
platformDisconnected: "déconnecté",
platformError: "erreur",
recentSessions: "Sessions récentes",
restartGateway: "Redémarrer la passerelle",
restartingGateway: "Redémarrage de la passerelle…",
running: "En cours",
runningRemote: "En cours (distant)",
startFailed: "Échec du démarrage",
starting: "Démarrage",
startedInBackground: "Démarré en arrière-plan — consultez les journaux pour la progression",
stopped: "Arrêté",
updateHermes: "Mettre à jour Hermes",
updatingHermes: "Mise à jour de Hermes…",
waitingForOutput: "En attente de la sortie…",
},
sessions: {
title: "Sessions",
history: "Historique",
overview: "Aperçu",
searchPlaceholder: "Rechercher dans les messages...",
noSessions: "Aucune session pour l'instant",
noMatch: "Aucune session ne correspond à votre recherche",
startConversation: "Démarrez une conversation pour la voir ici",
noMessages: "Aucun message",
untitledSession: "Session sans titre",
deleteSession: "Supprimer la session",
confirmDeleteTitle: "Supprimer la session ?",
confirmDeleteMessage:
"Cela supprime définitivement la conversation et tous ses messages. Cette action est irréversible.",
sessionDeleted: "Session supprimée",
failedToDelete: "Échec de la suppression de la session",
deleteEmpty: "Supprimer les vides",
deleteEmptyConfirmTitle: "Supprimer les sessions vides ?",
deleteEmptyConfirmMessage:
"Cela supprime définitivement {count} sessions sans messages. Les sessions actives et archivées sont ignorées. Cette action est irréversible.",
emptySessionsDeleted: "{count} sessions vides supprimées",
failedToDeleteEmpty: "Échec de la suppression des sessions vides",
selectSession: "Sélectionner la session",
selectAllOnPage: "Tout sélectionner sur cette page",
clearSelection: "Effacer la sélection",
selectedCount: "{count} sélectionnée(s)",
deleteSelected: "Supprimer {count}",
deleteSelectedConfirmTitle: "Supprimer {count} sessions ?",
deleteSelectedConfirmMessage:
"Cela supprime définitivement {count} sessions sélectionnées et tous leurs messages. Cette action est irréversible.",
selectedSessionsDeleted: "{count} sessions supprimées",
failedToDeleteSelected: "Échec de la suppression des sessions sélectionnées",
resumeInChat: "Reprendre dans le chat",
previousPage: "Page précédente",
nextPage: "Page suivante",
roles: {
user: "Utilisateur",
assistant: "Assistant",
system: "Système",
tool: "Outil",
},
},
analytics: {
period: "Période:",
totalTokens: "Tokens totaux",
totalSessions: "Sessions totales",
apiCalls: "Appels API",
dailyTokenUsage: "Utilisation quotidienne des tokens",
dailyBreakdown: "Détail quotidien",
perModelBreakdown: "Détail par modèle",
topSkills: "Compétences les plus utilisées",
skill: "Compétence",
loads: "Agent chargé",
edits: "Agent géré",
lastUsed: "Dernière utilisation",
input: "Entrée",
output: "Sortie",
total: "Total",
noUsageData: "Aucune donnée d'utilisation pour cette période",
startSession: "Démarrez une session pour voir les analyses ici",
date: "Date",
model: "Modèle",
tokens: "Tokens",
perDayAvg: "/jour moy",
acrossModels: "sur {count} modèles",
inOut: "{input} entrée / {output} sortie",
},
models: {
modelsUsed: "Modèles utilisés",
estimatedCost: "Coût est.",
tokens: "tokens",
sessions: "sessions",
avgPerSession: "moy/session",
apiCalls: "appels API",
toolCalls: "appels d'outil",
noModelsData: "Aucune donnée de modèle pour cette période",
startSession: "Démarrez une session pour voir les données de modèle ici",
},
logs: {
title: "Journaux",
autoRefresh: "Actualisation auto",
file: "Fichier",
level: "Niveau",
component: "Composant",
lines: "Lignes",
noLogLines: "Aucune ligne de journal trouvée",
},
cron: {
confirmDeleteMessage:
"Cela supprime la tâche du planning. Cette action est irréversible.",
confirmDeleteTitle: "Supprimer la tâche planifiée ?",
newJob: "Nouvelle tâche cron",
nameOptional: "Nom (facultatif)",
namePlaceholder: "ex. Résumé quotidien",
prompt: "Invite",
promptPlaceholder: "Que doit faire l'agent à chaque exécution ?",
schedule: "Planning (expression cron)",
schedulePlaceholder: "0 9 * * *",
scheduleMode: "Planification",
scheduleModes: {
interval: "Intervalle récurrent",
daily: "Quotidien",
weekly: "Hebdomadaire",
monthly: "Mensuel",
once: "Une fois",
custom: "Personnalisé (expression cron)",
intervalEvery: "Toutes les",
intervalUnit: "Unité",
unitMinutes: "minutes",
unitHours: "heures",
unitDays: "jours",
timeOfDay: "Heure de la journée",
weekdays: "Jours de la semaine",
weekdaysShort: ["Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam"],
dayOfMonth: "Jour du mois",
onceAt: "Exécuter le",
customLabel: "Expression cron",
customPlaceholder: "0 9 * * *",
customHint:
"Expression cron à cinq champs (minute, heure, jour, mois, jour de la semaine).",
preview: "Envoyé sous la forme",
previewEmpty: "(incomplet)",
},
scheduleDescribe: {
none: "—",
everyMinutes: "Toutes les {n} min",
everyHours: "Toutes les {n} h",
everyDays: "Tous les {n} j",
dailyAt: "Tous les jours à {time}",
weeklyAt: "Chaque {days} à {time}",
monthlyAt: "Le {day} de chaque mois à {time}",
onceAt: "Une fois le {time}",
},
deliverTo: "Livrer à",
scheduledJobs: "Tâches planifiées",
noJobs: "Aucune tâche cron configurée. Créez-en une ci-dessus.",
last: "Dernière",
next: "Prochaine",
pause: "Pause",
resume: "Reprendre",
triggerNow: "Déclencher maintenant",
delivery: {
local: "Local",
telegram: "Telegram",
discord: "Discord",
slack: "Slack",
email: "Email",
},
},
profiles: {
newProfile: "Nouveau profil",
name: "Nom",
namePlaceholder: "ex. coder, writer, etc.",
nameRequired: "Le nom est requis",
nameRule:
"Lettres minuscules, chiffres, _ et - uniquement ; doit commencer par une lettre ou un chiffre ; jusqu'à 64 caractères.",
invalidName: "Nom de profil invalide",
cloneFromDefault: "Cloner la configuration du profil par défaut",
allProfiles: "Profils",
noProfiles: "Aucun profil trouvé.",
defaultBadge: "défaut",
hasEnv: "env",
model: "Modèle",
skills: "Compétences",
rename: "Renommer",
editSoul: "Modifier SOUL.md",
soulSection: "SOUL.md (personnalité / invite système)",
soulPlaceholder: "# Comment cet agent doit se comporter…",
saveSoul: "Enregistrer SOUL",
soulSaved: "SOUL.md enregistré",
openInTerminal: "Copier la commande CLI",
commandCopied: "Copié dans le presse-papiers",
copyFailed: "Impossible de copier",
confirmDeleteTitle: "Supprimer le profil ?",
confirmDeleteMessage:
"Cela supprime définitivement le profil '{name}' — configuration, clés, mémoires, sessions, compétences, tâches cron. Action irréversible.",
created: "Créé",
deleted: "Supprimé",
renamed: "Renommé",
},
pluginsPage: {
contextEngineLabel: "Moteur de contexte",
dashboardSlots: "Emplacements du tableau de bord",
disableRuntime: "Désactiver",
enableAfterInstall: "Activer après l'installation",
enableRuntime: "Activer",
forceReinstall: "Forcer la réinstallation (supprimer d'abord le dossier existant)",
headline:
"Découvrez, installez, activez et mettez à jour les plugins Hermes (parité avec `hermes plugins`).",
identifierLabel: "URL Git ou owner/repo",
inactive: "inactif",
installBtn: "Installer",
installHeading: "Installer depuis GitHub / URL Git",
installHint: "Utilisez le raccourci owner/repo ou une URL de clonage complète https:// ou git@.",
memoryProviderLabel: "Fournisseur de mémoire",
missingEnvWarn: "Définissez ces variables dans Clés avant que le plugin puisse s'exécuter:",
noDashboardTab: "Aucun onglet de tableau de bord",
openTab: "Ouvrir",
orphanHeading: "Extensions du tableau de bord uniquement (aucune correspondance plugin.yaml d'agent)",
pluginListHeading: "Plugins installés",
providerDefaults: "intégré / par défaut",
providersHeading: "Plugins fournisseurs d'exécution",
providersHint:
"Écrit memory.provider (vide = intégré) et context.engine dans config.yaml. Prend effet à la prochaine session.",
refreshDashboard: "Re-scanner les extensions du tableau de bord",
removeConfirm: "Retirer ce plugin de ~/.hermes/plugins/ ?",
removeHint: "Seuls les plugins installés par l'utilisateur sous ~/.hermes/plugins peuvent être supprimés.",
rescanHeading: "Registre des plugins SPA",
rescanHint: "Re-scannez après avoir ajouté des fichiers sur le disque pour que la barre latérale prenne en compte les nouveaux manifestes.",
runtimeHeading: "Exécution de la passerelle (plugins YAML)",
saveProviders: "Enregistrer les paramètres de fournisseur",
savedProviders: "Paramètres de fournisseur enregistrés.",
sourceBadge: "Source",
authRequired: "Authentification requise",
authRequiredHint: "Exécutez cette commande pour vous authentifier:",
updateGit: "Git pull",
versionBadge: "Version",
showInSidebar: "Afficher dans la barre latérale",
hideFromSidebar: "Masquer de la barre latérale",
},
skills: {
title: "Compétences",
searchPlaceholder: "Rechercher des compétences et des outils...",
enabledOf: "{enabled}/{total} activées",
all: "Toutes",
categories: "Catégories",
filters: "Filtres",
noSkills: "Aucune compétence trouvée. Les compétences sont chargées depuis ~/.hermes/skills/",
noSkillsMatch: "Aucune compétence ne correspond à votre recherche ou filtre.",
skillCount: "{count} compétence{s}",
resultCount: "{count} résultat{s}",
noDescription: "Aucune description disponible.",
toolsets: "Ensembles d'outils",
toolsetLabel: "Ensemble d'outils {name}",
noToolsetsMatch: "Aucun ensemble d'outils ne correspond à la recherche.",
setupNeeded: "Configuration nécessaire",
disabledForCli: "Désactivé pour CLI",
more: "+{count} de plus",
},
config: {
configPath: "~/.hermes/config.yaml",
filters: "Filtres",
sections: "Sections",
exportConfig: "Exporter la configuration en JSON",
importConfig: "Importer la configuration depuis JSON",
resetDefaults: "Réinitialiser aux valeurs par défaut",
resetScopeTooltip: "Réinitialiser {scope} aux valeurs par défaut",
confirmResetScope: "Réinitialiser tous les paramètres de {scope} aux valeurs par défaut ? Cela ne met à jour que le formulaire — les modifications ne sont écrites dans config.yaml qu'après avoir appuyé sur Enregistrer.",
resetScopeToast: "{scope} réinitialisé aux valeurs par défaut — vérifiez et enregistrez pour conserver",
rawYaml: "Configuration YAML brute",
searchResults: "Résultats de recherche",
fields: "champ{s}",
noFieldsMatch: 'Aucun champ ne correspond à "{query}"',
configSaved: "Configuration enregistrée",
yamlConfigSaved: "Configuration YAML enregistrée",
failedToSave: "Échec de l'enregistrement",
failedToSaveYaml: "Échec de l'enregistrement YAML",
failedToLoadRaw: "Échec du chargement de la configuration brute",
configImported: "Configuration importée — vérifiez et enregistrez",
invalidJson: "Fichier JSON invalide",
categories: {
general: "Général",
agent: "Agent",
terminal: "Terminal",
display: "Affichage",
delegation: "Délégation",
memory: "Mémoire",
compression: "Compression",
security: "Sécurité",
browser: "Navigateur",
voice: "Voix",
tts: "Synthèse vocale",
stt: "Reconnaissance vocale",
logging: "Journalisation",
discord: "Discord",
auxiliary: "Auxiliaire",
},
},
env: {
changesNote: "Les modifications sont enregistrées sur le disque immédiatement. Les sessions actives récupèrent les nouvelles clés automatiquement.",
confirmClearMessage:
"La valeur stockée pour cette variable sera supprimée de votre fichier .env. Cette action ne peut pas être annulée depuis l'interface.",
confirmClearTitle: "Effacer cette clé ?",
description: "Gérer les clés API et les secrets stockés dans",
hideAdvanced: "Masquer les options avancées",
showAdvanced: "Afficher les options avancées",
showLess: "Afficher moins",
showMore: "Afficher plus",
llmProviders: "Fournisseurs LLM",
providersConfigured: "{configured} sur {total} fournisseurs configurés",
getKey: "Obtenir la clé",
notConfigured: "{count} non configuré",
notSet: "Non défini",
keysCount: "{count} clé{s}",
enterValue: "Saisir une valeur...",
replaceCurrentValue: "Remplacer la valeur actuelle ({preview})",
showValue: "Afficher la valeur réelle",
hideValue: "Masquer la valeur",
},
oauth: {
title: "Connexions fournisseurs (OAuth)",
providerLogins: "Connexions fournisseurs (OAuth)",
description: "{connected} sur {total} fournisseurs OAuth connectés. Les flux de connexion s'exécutent actuellement via le CLI ; cliquez sur Copier la commande et collez-la dans un terminal pour configurer.",
connected: "Connecté",
expired: "Expiré",
notConnected: "Non connecté. Exécutez {command} dans un terminal.",
runInTerminal: "dans un terminal.",
noProviders: "Aucun fournisseur compatible OAuth détecté.",
login: "Connexion",
disconnect: "Déconnecter",
managedExternally: "Géré en externe",
copied: "Copié ✓",
cli: "Copier",
copyCliCommand: "Copier la commande CLI (pour externe / repli)",
connect: "Connecter",
sessionExpires: "La session expire dans {time}",
initiatingLogin: "Lancement du flux de connexion…",
exchangingCode: "Échange du code contre des jetons…",
connectedClosing: "Connecté ! Fermeture…",
loginFailed: "Échec de la connexion.",
sessionExpired: "Session expirée. Cliquez sur Réessayer pour démarrer une nouvelle connexion.",
reOpenAuth: "Rouvrir la page d'authentification",
reOpenVerification: "Rouvrir la page de vérification",
submitCode: "Soumettre le code",
pasteCode: "Collez le code d'autorisation (avec suffixe #state accepté)",
waitingAuth: "En attente de votre autorisation dans le navigateur…",
enterCodePrompt: "Un nouvel onglet s'est ouvert. Saisissez ce code si demandé:",
pkceStep1: "Un nouvel onglet s'est ouvert vers claude.ai. Connectez-vous et cliquez sur Autoriser.",
pkceStep2: "Copiez le code d'autorisation affiché après autorisation.",
pkceStep3: "Collez-le ci-dessous et soumettez.",
flowLabels: {
pkce: "Connexion navigateur (PKCE)",
device_code: "Code d'appareil",
external: "CLI externe",
},
expiresIn: "expire dans {time}",
},
language: {
switchTo: "Changer de langue",
},
theme: {
title: "Thème",
switchTheme: "Changer de thème",
},
achievements: {
hero: {
kicker: "Agentic Gamerscore",
title: "Hermes Achievements",
subtitle:
"Badges Hermes à collectionner, gagnés à partir de l'historique réel des sessions. Les succès connus non terminés sont affichés comme Découverts ; les succès secrets restent cachés jusqu'à l'apparition du premier comportement correspondant.",
scan_subtitle:
"Analyse de l'historique des sessions Hermes en cours. Le premier scan peut prendre 5 à 10 secondes sur les historiques volumineux.",
},
actions: {
rescan: "Relancer le scan",
},
stats: {
unlocked: "Débloqués",
unlocked_hint: "badges obtenus",
discovered: "Découverts",
discovered_hint: "connus, pas encore obtenus",
secrets: "Secrets",
secrets_hint: "cachés jusqu'au premier signal",
highest_tier: "Niveau le plus élevé",
highest_tier_hint: "Copper → Silver → Gold → Diamond → Olympian",
latest: "Dernier",
latest_hint_empty: "utilisez Hermes davantage",
none_yet: "Aucun pour l'instant",
},
state: {
unlocked: "Débloqué",
discovered: "Découvert",
secret: "Secret",
},
tier: {
target: "Cible {tier}",
hidden: "Caché",
complete: "Terminé",
objective: "Objectif",
},
progress: {
hidden: "caché",
},
scan: {
building_headline: "Création du profil de succès…",
building_detail:
"Lecture des sessions, des appels d'outils, des métadonnées du modèle et de l'état de déblocage.",
starting_headline: "Démarrage du scan des succès…",
progress_detail:
"{scanned} sessions analysées sur {total} · {pct}%. Les badges se débloquent à mesure que l'historique est traité.",
idle_detail:
"Lecture des sessions, des appels d'outils, des métadonnées du modèle et de l'état de déblocage. Les badges apparaissent ici à mesure qu'ils se débloquent.",
},
guide: {
tiers_header: "Niveaux",
secret_header: "Succès secrets",
secret_body:
"Les secrets cachent leur déclencheur exact. Dès qu'Hermes détecte un signal lié, la carte passe à Découvert et affiche son exigence.",
scan_status_header: "État du scan",
scan_status_body:
"Hermes analyse l'historique local une seule fois, puis les cartes apparaîtront automatiquement. Rien n'est bloqué si cela prend quelques secondes.",
what_scanned_header: "Ce qui est analysé",
what_scanned_body:
"Sessions, appels d'outils, métadonnées du modèle, erreurs, succès et état de déblocage local.",
},
card: {
share_title: "Partager ce succès",
share_label: "Partager {name}",
share_text: "Partager",
how_to_reveal: "Comment le révéler",
what_counts: "Ce qui compte",
evidence_label: "Preuve",
evidence_session_fallback: "session",
no_evidence: "Pas encore de preuve",
},
latest: {
header: "Déblocages récents",
},
empty: {
no_secrets_header: "Plus aucun secret caché dans ce scan.",
no_secrets_body:
"Indice: les secrets démarrent généralement à partir d'échecs inhabituels ou de schémas d'utilisateurs avancés — conflits de ports, murs de permissions, variables d'environnement manquantes, erreurs YAML, collisions Docker, utilisation de rollback/checkpoint, succès de cache ou petits correctifs après beaucoup de texte rouge.",
},
filters: {
all_categories: "Tous",
visibility_all: "tous",
visibility_unlocked: "débloqués",
visibility_discovered: "découverts",
visibility_secret: "secrets",
},
share: {
dialog_label: "Partager le succès",
header: "Partager: {name}",
close: "Fermer",
rendering: "Rendu en cours…",
card_alt: "Carte de partage {name}",
error_generic: "Une erreur s'est produite.",
x_title: "Ouvre X avec une publication préremplie",
x_button: "Partager sur X",
copy_title: "Copiez l'image pour la coller dans votre publication",
copy_button: "Copier l'image",
copied: "Copié ✓",
download_button: "Télécharger le PNG",
hint:
"Partager sur X ouvre une publication préremplie dans un nouvel onglet. Cliquez d'abord sur Copier l'image si vous voulez joindre le badge 1200×630 — X vous laisse le coller directement dans l'éditeur de tweet. Télécharger le PNG enregistre le fichier pour l'utiliser n'importe où.",
clipboard_unsupported:
"La copie d'image dans le presse-papiers n'est pas prise en charge par ce navigateur — utilisez Télécharger à la place.",
tweet_text: "Just unlocked {tier_part}\"{name}\" in Hermes Agent ☤",
},
},
kanban: {
loading: "Chargement du tableau Kanban…",
loadFailed: "Échec du chargement du tableau Kanban: ",
loadFailedHint:
"Le backend crée automatiquement kanban.db à la première lecture. Si le problème persiste, consultez les logs du dashboard.",
board: "Tableau",
newBoard: "+ Nouveau tableau",
newBoardTitle: "Nouveau tableau",
newBoardDescription:
"Les tableaux vous permettent de séparer des flux de travail indépendants — un par projet, dépôt ou domaine. Les workers d'un tableau ne voient jamais les tâches d'un autre.",
slug: "Slug",
slugHint: "— minuscules, tirets, par ex. atm10-server",
displayName: "Nom affiché",
displayNameHint: "(facultatif)",
description: "Description",
descriptionHint: "(facultatif)",
icon: "Icône",
iconHint: "(un seul caractère ou emoji)",
switchAfterCreate: "Basculer sur ce tableau après l'avoir créé",
cancel: "Annuler",
creating: "Création…",
createBoard: "Créer le tableau",
search: "Rechercher",
filterCards: "Filtrer les cartes…",
tenant: "Tenant",
allTenants: "Tous les tenants",
assignee: "Assigné à",
allProfiles: "Tous les profils",
showArchived: "Afficher les archivés",
lanesByProfile: "Couloirs par profil",
nudgeDispatcher: "Solliciter le dispatcher",
refresh: "Rafraîchir",
selected: "sélectionné(s)",
complete: "Terminer",
archive: "Archiver",
apply: "Appliquer",
clear: "Effacer",
createTask: "Créer une tâche dans cette colonne",
noTasks: "— aucune tâche —",
unassigned: "non assigné",
untitled: "(sans titre)",
loadingDetail: "Chargement…",
addComment: "Ajouter un commentaire… (Enter pour envoyer)",
comment: "Commentaire",
status: "Statut",
workspace: "Workspace",
skills: "Compétences",
createdBy: "Créé par",
result: "Result",
comments: "Commentaires",
events: "Événements",
runHistory: "Historique d'exécution",
workerLog: "Log du worker",
loadingLog: "Chargement du log…",
noWorkerLog:
"— pas encore de log du worker (la tâche n'a pas démarré ou le log a été effacé par rotation) —",
noDescription: "— aucune description —",
noComments: "— aucun commentaire —",
edit: "modifier",
save: "Enregistrer",
dependencies: "Dépendances",
parents: "Parents:",
children: "Enfants:",
none: "aucun",
addParent: "— ajouter un parent —",
addChild: "— ajouter un enfant —",
removeDependency: "Supprimer la dépendance",
block: "Bloquer",
unblock: "Débloquer",
notifyHomeChannels: "Notifier les canaux home",
diagnostics: "Diagnostics",
hide: "Masquer",
show: "Afficher",
attention: "Attention",
tasksNeedAttention: "tâches nécessitent une attention",
taskNeedsAttention: "1 tâche nécessite une attention",
diagnostic: "diagnostic",
open: "Ouvrir",
close: "Fermer (Esc)",
reassignTo: "Réassigner à:",
copied: "Copié",
copyCommand: "Copier la commande dans le presse-papiers",
reclaim: "Récupérer",
reassign: "Réassigner",
renderingError: "L'onglet Kanban a rencontré une erreur de rendu",
reloadView: "Recharger la vue",
wsAuthFailed:
"Échec d'authentification WebSocket — rechargez la page pour rafraîchir le jeton de session.",
markDone: "Marquer {n} tâche(s) comme terminée(s) ?",
markArchived: "Archiver {n} tâche(s) ?",
warning: "Avertissement",
phantomIds: "IDs fantômes:",
active: "actif",
ended: "terminé",
noProfile: "(aucun profil)",
showAllAttempts: "Afficher toutes les tentatives",
sendingUpdates: "Envoi des mises à jour à",
sendNotifications: "Envoyer les notifications completed / blocked / gave_up à",
archiveBoardConfirm:
"Archiver le tableau '{name}' ? Il sera déplacé vers boards/_archived/ pour pouvoir être récupéré plus tard. Les tâches de ce tableau n'apparaîtront plus nulle part dans l'UI.",
archiveBoardTitle: "Archiver ce tableau",
boardSwitcherHint: "Les tableaux vous permettent de séparer des flux de travail indépendants",
taskCreatedWarning: "Tâche créée, mais: ",
moveFailed: "Échec du déplacement: ",
bulkFailed: "Lot: ",
completionBlockedHallucination: "⚠ Achèvement bloqué — IDs de carte fantômes",
suspectedHallucinatedReferences: "⚠ Le texte a référencé des IDs de carte fantômes",
pickProfileFirst: "Choisissez d'abord un profil.",
unblockedMessage: "Débloqué {id}. La tâche est prête pour le prochain tick.",
unblockFailed: "Échec du déblocage: ",
reclaimedMessage: "Récupéré {id}. La tâche est de nouveau prête.",
reclaimFailed: "Échec de la récupération: ",
reassignedMessage: "Réassigné {id} à {profile}.",
reassignFailed: "Échec de la réassignation: ",
selectForBulk: "Sélectionner pour des actions groupées",
clickToEdit: "Cliquez pour modifier",
clickToEditAssignee: "Cliquez pour modifier l'assigné",
emptyAssignee: "(vide = désassigner)",
columnLabels: {
triage: "Triage",
todo: "À faire",
scheduled: "Planifié",
ready: "Prêt",
running: "En cours",
blocked: "Bloqué",
done: "Terminé",
archived: "Archivé",
},
columnHelp: {
triage: "Idées brutes — un specifier rédigera la spécification",
todo: "En attente de dépendances ou non assigné",
scheduled: "En attente d'un délai connu ou d'un suivi planifié",
ready: "Dépendances satisfaites ; assignez un profil pour dispatch",
running: "Réclamé par un worker — en cours d'exécution",
blocked: "Le worker a demandé une intervention humaine",
done: "Terminé",
archived: "Archivé",
},
confirmDone:
"Marquer cette tâche comme terminée ? La revendication du worker est libérée et les enfants dépendants deviennent prêts.",
confirmArchive:
"Archiver cette tâche ? Elle disparaîtra de la vue par défaut du tableau.",
confirmBlocked:
"Marquer cette tâche comme bloquée ? La revendication du worker est libérée.",
completionSummary:
"Résumé d'achèvement pour {label}. Stocké comme result de la tâche.",
completionSummaryRequired:
"Un résumé d'achèvement est requis avant de marquer une tâche comme terminée.",
triagePlaceholder: "Idée approximative — l'IA la spécifiera…",
taskTitlePlaceholder: "Titre de la nouvelle tâche…",
specifier: "specifier",
assigneePlaceholder: "assigné",
priority: "Priorité",
skillsPlaceholder:
"compétences (facultatif, séparées par virgules): translation, github-code-review",
noParent: "— aucun parent —",
workspacePathDir: "chemin du workspace (requis, par ex. ~/projects/my-app)",
workspacePathOptional:
"chemin du workspace (facultatif, dérivé de l'assigné si vide)",
logTruncated: "(affichage des derniers 100 KB — log complet à ",
logAt: ")",
},
};