Commit 3a56ae23 authored by Kourser's avatar Kourser
Browse files

i18n : finir la traduction de la console, à moitié faite

L'en-tête du dictionnaire annonçait une traduction « ciblée sur
l'environnement joueur, la console restant en français ». Ce n'était
plus vrai : la console était traduite aux quatre cinquièmes, et les deux
langues se croisaient dans un même écran — « Player workspace skin »
suivi de « S'applique à tout l'exercice ». Un écran à moitié traduit se
lit plus mal que l'une ou l'autre langue.

111 chaînes manquaient, toutes dans la console : aucune côté joueur ni
sur les écrans publics, ce qui confirme où passait la frontière.

23 libellés de plus échappaient au relevé, parce qu'ils transitent par
une variable — « t(n.label) », « t(TABLE[clef]) » — et non par une
chaîne littérale. D'où « Mon compte » resté en français dans un menu
dont les cinq autres entrées étaient traduites. Les noms de marques
restent hors dictionnaire : identiques dans les deux langues, ils le
traversent sans clef, ce qui est le comportement voulu.

Co-Authored-By: default avatarClaude Opus 5 <noreply@anthropic.com>
parent 66cba582
Loading
Loading
Loading
Loading
+201 −0
Changes for apps/web/src/i18n.tsx: 201 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -1062,6 +1062,207 @@ const EN: Record<string, string> = {
  'repli de développement': 'development fallback',
  'origine inconnue': 'unknown origin',


  /*
   * --- Console d'animation, seconde moitie ---
   *
   * L'en-tete de ce fichier annonçait une traduction « ciblée sur l'environnement
   * joueur, la console restant en français ». Ce n'était plus vrai : la console
   * était traduite aux quatre cinquièmes, et les deux langues se croisaient dans un
   * même écran — « Player workspace skin » suivi de « S'applique à tout l'exercice ».
   * Un écran à moitié traduit se lit plus mal que l'une ou l'autre langue.
   */

  // Console d'instance : bac à sable public
  'Bac à sable ouvert.': 'Sandbox opened.',
  'Bac à sable fermé.': 'Sandbox closed.',
  'Ouvrir le bac à sable rend une route publique accessible sans compte : n’importe qui pourra créer un exercice de découverte sur cette instance. Confirmer ?':
    'Opening the sandbox exposes a public route with no account: anyone will be able to create a discovery exercise on this instance. Confirm?',
  'Bac à sable public': 'Public sandbox',
  'Ouvert au public': 'Open to the public',
  'Fermé': 'Closed',
  'Permet à un visiteur d’obtenir un exercice de découverte sans compte. Chaque visite crée une organisation éphémère, isolée et purgée à échéance.':
    'Lets a visitor get a discovery exercise without an account. Each visit creates an ephemeral organisation, isolated and purged when it expires.',
  'Ouvrir au public': 'Open to the public',
  'session(s) de découverte en cours': 'discovery session(s) running',
  'Durée de vie d’une session (minutes)': 'Session lifetime (minutes)',
  'Sessions simultanées au maximum': 'Maximum concurrent sessions',
  'Bornes imposées : 5 min à 24 h, et 50 sessions au plus. Elles évitent qu’un réglage vide de son sens la purge ou le plafond.':
    'Enforced bounds: 5 min to 24 h, and 50 sessions at most. They keep a setting from emptying the purge or the cap of their meaning.',
  'Une valeur non renseignée applique le défaut.': 'An empty value applies the default.',

  // Déroulé sans animateur
  'Exercice autonome': 'Unattended exercise',
  'L’horloge démarre au premier accès joueur et les injects partent seuls. Un animateur peut reprendre la main à tout moment.':
    'The clock starts on the first player access and injects go out on their own. A facilitator can take over at any time.',
  'Rythme de diffusion': 'Delivery pace',
  'Par défaut, chaque inject part à son T+ propre. Une cadence les fait partir l’un après l’autre, sans réécrire le chronogramme.':
    'By default each inject goes out at its own T+. A pace sends them one after another, without rewriting the timeline.',
  'Clôture automatique': 'Automatic closing',
  'Après le dernier inject, plus ce délai. Sans effet hors mode autonome.':
    'After the last inject, plus this delay. No effect outside unattended mode.',
  'Aucune': 'None',
  'Ouvrir le questionnaire de RETEX à la clôture':
    'Open the lessons learned questionnaire on closing',
  'Les joueurs répondent tant qu’ils sont là. Le rapport, lui, reste réservé à l’animation.':
    'Players answer while they are still there. The report stays with the facilitation team.',

  // Fiches réflexes
  'Briefing à l’ouverture': 'Briefing on opening',
  'Le joueur reçoit sa fiche en fenêtre d’accueil quand il ouvre son espace, une fois par onglet. Y compris s’il rejoint en cours de crise.':
    'The player gets their playbook in a welcome window when opening their workspace, once per tab. Including when they join mid-crisis.',
  'Onglet consultable pendant l’exercice': 'Tab available during the exercise',
  'Tous les rôles et leurs attendus, à tout moment. À réserver à un public débutant.':
    'Every role and what is expected of it, at any time. Best kept for a beginner audience.',
  'Aucune fiche. Installez le référentiel fourni, puis adaptez-le à votre exercice.':
    'No playbooks. Install the provided set, then adapt it to your exercise.',
  '+ Fiche': '+ Playbook',
  'Référentiel inspiré du pack « Réflexes Cyber » de l’ANSSI et du CDSE (Licence Ouverte v2.0). Les fiches installées sont des copies : adaptez-les librement.':
    'Set adapted from the ANSSI and CDSE « Réflexes Cyber » pack (Open Licence v2.0). Installed playbooks are copies: adapt them freely.',
  'Personnage à qui cette fiche s’applique': 'Character this playbook applies to',

  // Grille d'observation
  'Aucun critère d’observation. La grille se prépare dans l’onglet Préparation.':
    'No observation criteria. The grid is set up in the Preparation tab.',
  'Suivre la phase courante de l’exercice': 'Follow the current phase of the exercise',
  'Phase courante': 'Current phase',
  'Aucun critère pour cette phase.': 'No criteria for this phase.',
  'Observation (optionnelle)': 'Observation (optional)',
  'Thème': 'Theme',
  'Critère': 'Criterion',
  'tout l’exercice': 'the whole exercise',
  'Aucun critère. Installez une grille fournie, puis adaptez-la.':
    'No criteria. Install a provided grid, then adapt it.',
  '+ Critère': '+ Criterion',
  'Installer': 'Install',
  'Un critère sans phase reste visible tout au long de l’exercice. La saisie se fait dans l’onglet Animation, et reste modifiable depuis le rapport.':
    'A criterion without a phase stays visible throughout the exercise. Entry happens in the Facilitation tab, and stays editable from the report.',
  'Thème (ex. Pilotage)': 'Theme (e.g. Steering)',
  'Critère observé': 'Observed criterion',
  'critères appréciés': 'criteria rated',
  'observateur(s)': 'observer(s)',
  'moyenne': 'average',
  'Appréciations': 'Ratings',

  // Parcours de création d'exercice
  'Ex. Banque Méridien, Mairie de Astville…': 'E.g. Meridien Bank, Astville Town Hall…',
  'Organisation fictive mise en scène.': 'The fictional organisation being staged.',
  'Ville / localisation': 'Town / location',
  'Ex. Astville': 'E.g. Astville',
  'Ex. Finance, Industrie…': 'E.g. Finance, Manufacturing…',
  'Date-heure de démarrage': 'Start date and time',
  'Informatif (affiché à l\'animateur).': 'For information (shown to the facilitator).',
  'Personnaliser et installer le kit': 'Customise and install the kit',
  'Précédent': 'Back',
  'Suivant': 'Next',
  'Création…': 'Creating…',
  'Créer l\'exercice': 'Create exercise',

  // Phases de crise
  'Annoncer la phase courante aux joueurs': 'Announce the current phase to players',
  'Donner le découpage aide un public débutant, et retire du réalisme à un exercice qui se veut crédible.':
    'Showing the breakdown helps a beginner audience, and costs realism in an exercise meant to be credible.',
  'Passage forcé par l’animation': 'Forced through by facilitation',
  'Aucune phase. L’exercice se déroule alors sans découpage, comme avant : rien ne change.':
    'No phases. The exercise then runs without a breakdown, as before: nothing changes.',
  '+ Phase': '+ Phase',
  'Un inject appartient à la phase que son T+ désigne. Supprimer une phase ne supprime aucun inject : ils repassent en déduction.':
    'An inject belongs to the phase its T+ points to. Deleting a phase deletes no inject: they go back to being inferred.',
  'avant la première phase': 'before the first phase',
  'ensuite': 'then',
  'à': 'at',
  'Passer à la phase suivante sans attendre son T+':
    'Move to the next phase without waiting for its T+',
  'Phase suivante →': 'Next phase →',

  // Rapport : constats et points d'attention
  'Constats (CSV)': 'Findings (CSV)',
  'Points d’attention': 'Points of attention',
  'Aucune grille sur cet exercice.': 'No grid on this exercise.',
  'Aucun point d’attention détecté. Le rapport ne signale rien par défaut.':
    'No point of attention detected. The report flags nothing by default.',
  'Tous les constats ont été écartés.': 'Every finding has been set aside.',
  'Retirer ce constat du rapport remis': 'Remove this finding from the delivered report',
  'Écarter': 'Set aside',
  'Piste d’action': 'Suggested action',
  'constat(s) écarté(s), absent(s) du rapport remis':
    'finding(s) set aside, absent from the delivered report',
  'Rétablir': 'Restore',

  // Écran d'exercice : titres de section
  'Supprimer définitivement cet exercice archivé ? Cette action est irréversible.':
    'Permanently delete this archived exercise? This cannot be undone.',
  'Paramètres de l\'exercice': 'Exercise settings',
  'S\'applique à tout l\'exercice : messagerie, chat et réseaux sociaux des joueurs.':
    'Applies to the whole exercise: player mail, chat and social media.',
  'Déroulé sans animateur': 'Unattended run',
  'Phases de crise': 'Crisis phases',
  'Grille d’observation': 'Observation grid',
  'Fiches réflexes par rôle': 'Role playbooks',
  'Appel vocal': 'Voice call',

  // Éditeur de kit : phases et fiches réflexes
  'Ajouter une phase': 'Add a phase',
  'Phase': 'Phase',
  'Aucune phase. Les exercices installés depuis ce kit n’auront pas de découpage.':
    'No phases. Exercises installed from this kit will have no phase breakdown.',
  'Les bornes sont exprimées en minutes, comme les injects. Un inject appartient à la phase que son T+ désigne.':
    'Boundaries are in minutes, like injects. An inject belongs to the phase its T+ points to.',
  'Ajouter une fiche': 'Add a playbook',
  'Installer le référentiel fourni': 'Install the provided set',
  'Attribuée à': 'Assigned to',
  'Réflexes': 'Reflexes',
  'personne': 'nobody',
  'Aucune fiche. Un kit sans fiche installe un exercice sans fiche : rien ne change.':
    'No playbooks. A kit without them installs an exercise without them: nothing changes.',
  'Ces fiches sont copiées dans chaque exercice installé depuis ce kit. L’attribution suit le personnage du kit. Les deux réglages d’ouverture côté joueur restent fermés : ils dépendent du public, pas du scénario.':
    'These playbooks are copied into every exercise installed from this kit. Assignment follows the kit character. Both player-side switches stay off: they depend on the audience, not on the scenario.',
  'Modifier la fiche': 'Edit playbook',
  'Nouvelle fiche réflexe': 'New playbook',
  'Rôle (ex. Direction)': 'Role (e.g. Management)',
  'Personnage du kit à qui cette fiche s’applique': 'Kit character this playbook applies to',
  '— non attribuée —': '— unassigned —',
  'Mission du rôle': 'Role mission',
  'Un réflexe par ligne': 'One reflex per line',
  'Modifier la phase': 'Edit phase',
  'Nouvelle phase': 'New phase',
  'Nom de la phase (ex. Découverte de l’attaque)': 'Phase name (e.g. Discovering the attack)',
  'Description (optionnelle)': 'Description (optional)',

  /*
   * Libelles traduits PAR VARIABLE — `t(TABLE[clef])`, `t(n.label)`.
   *
   * Ils échappaient au relevé, qui ne voyait que les chaînes littérales passées à
   * `t(...)`. D'où « Mon compte » resté en français dans un menu dont les cinq
   * autres entrées étaient traduites.
   *
   * Les noms de marques (X, LinkedIn, Instagram, Microsoft, Google) n'y figurent
   * pas : identiques dans les deux langues, ils traversent le dictionnaire sans
   * clef, ce qui est le comportement voulu.
   */
  'Mon compte': 'My account',
  'À améliorer': 'Needs improvement',
  'Satisfaisant': 'Satisfactory',
  'Point fort': 'Strength',
  'Soutenu — 2 min': 'Brisk — 2 min',
  'Modéré — 3 min': 'Moderate — 3 min',
  'Posé — 5 min': 'Steady — 5 min',
  'Long format — 10 min': 'Long form — 10 min',
  'Partenaire / sous-traitant': 'Partner / subcontractor',
  'Média / journaliste': 'Media / journalist',
  'Autorité préfectorale': 'Prefectural authority',
  'Gestionnaire du réseau électrique': 'Power grid operator',
  'Nom de la solution de sécurité mise en cause.': 'Name of the security product involved.',
  'Ex. Sécuriscan EDR': 'E.g. Securiscan EDR',
  'Ex. LogiPro Services': 'E.g. LogiPro Services',
  'Ex. Le Quotidien Olympe': 'E.g. The Olympe Daily',
  'Ex. MéridienNet': 'E.g. MeridienNet',
  'Ex. MonRH': 'E.g. MyHR',
  'Ex. la Vézère': 'E.g. the Vezere',
  'Ex. la préfecture de la Dordogne': 'E.g. the Dordogne prefecture',
  'Ex. Enedis': 'E.g. Enedis',
  'Document': 'Document',
  'En retard': 'Late',
};

interface I18n {