feat(frontend): full FR i18n via react-i18next + 2-tab engagement detail (sprint 12) #14
Reference in New Issue
Block a user
Delete Branch "sprint/12-i18n-fr"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
fr-FR(jj/mm/aaaa). 13 commits livrés + le2c7fcecdu sprint 11 (build fixtext-caption-*).pending/active/done/etc.), traduction au rendering layer viai18n/status.ts+ hookuseTranslation()insideStatusBadge/SimulationStatusBadge(subscription réactive correcte).formatDate()/formatDateTime()danslib/format.tsutilisenttoLocaleDateString('fr-FR')/toLocaleString('fr-FR'). Appliqués à 5 sites (engagements list/detail, users admin, templates list, simulations list).Dépendance — sprint 11
Cette branche est basée sur
sprint/11-spectrum-ux(PR #13 toujours ouverte). Le diff inclura temporairement les commits sprint 11 — il se réduira automatiquement à sprint 12 seul une fois PR #13 mergée. Merger PR #13 avant celui-ci pour un diff propre.Test plan
tsc --noEmitclean,eslint --max-warnings=0clean.npm run build(=vite build) clean — PostCSS résout tous les@apply, aucune classe Tailwind non-résolue (leçon sprint 11feedback_css_apply_tokens).node_modules/.vitebustéavant la prise des screenshots de validation finale — élimine la suspicion de stale bundle (code-reviewer flag REG 1).Comment tester en local
Scénarios :
Mimic(brand),Connectez-vous pour accéder à vos engagements., fieldsNom d'utilisateur/Mot de passe, boutonSe connecter.Engagements/Templates/Utilisateurs/Se déconnecter. Footer FR :Mimic — Outillage interne Purple Team. Engagements autorisés uniquement.Engagements, subtitleMissions red team et leur statut., columnsNOM / STATUT / DÉBUT / FIN / CRÉÉ PAR / ACTIONS, badges status FR (Planifié/Actif/Clôturé), datesjj/mm/aaaa, actionsVoir/Modifier/Supprimer.Retour aux engagements, badge status FR juste sous le titre (Actif), tabsDescription(default) +Simulationsavec count pill. Dans le panel Description : header block avecDate de début/Date de fin/Statut(badge) /Créé le+ boutonMODIFIER, séparateur, puisDescriptiontext. Boutons header droite :EXPORTER+MODIFIER.Le nom est requis, etc.), boutonsEnregistrer les modifications/Annuler, toastEngagement mis à jour.success/warnen FR, status badges traduits réactivement.admin/redteam/socpeuvent rester en values), labels en FR, datesjj/mm/aaaa.Matrice MITRE ATT&CK, filterFiltrer, empty stateAucun résultat, aria-labelsReplier {{id}}/Déplier {{id}}.Configuration C2, fields en FR, checkboxVérifier le certificat TLS+ helper text MITM en FR (depuis sprint 10).Fichiers nouveaux
frontend/src/i18n/index.tsfrontend/src/i18n/fr.jsonfrontend/src/i18n/status.tsengagementStatusLabel/simulationStatusLabelnon-réactifs (call sites hors-component)frontend/tests/i18n.test.tsFichiers modifiés (sample, ~30 src files + 23 test files)
frontend/src/main.tsximport './i18n'avant<App />frontend/src/lib/format.tsformatDate/formatDateTimewrappersfr-FRfrontend/src/components/StatusBadge.tsxuseTranslation()réactiffrontend/src/components/SimulationStatusBadge.tsxuseTranslation()réactiffrontend/src/components/Layout.tsxt()frontend/src/components/ExportEngagementButton.tsxExporter+ aria + loading)frontend/src/components/AlertBanner.tsxfrontend/src/components/MitreMatrixModal.tsxAucun résultat+ ariaReplier/Déplier {{id}}frontend/src/components/C2*.tsxfrontend/src/pages/EngagementDetailPage.tsxfrontend/src/pages/LoginPage.tsxfrontend/src/pages/EngagementsListPage.tsxfrontend/src/pages/EngagementFormPage.tsxfrontend/src/pages/SimulationFormPage.tsxfrontend/src/pages/TemplatesListPage.tsxfrontend/src/pages/TemplateFormPage.tsxfrontend/src/pages/UsersAdminPage.tsxdata-testid="new-role-select"CHANGELOG.mdDécisions verrouillées (de la phase planning)
react-i18nextcomplet (deps + hook + JSON FR + interpolation + pluralization)i18n/status.tsfr-FR(jj/mm/aaaa)Engagement créé, pasEngagement enregistré avec succès)Patterns notables
main.tsximporte./i18navant<App />pour éviter les premières renders avec keys raw.useTranslation()inline dans les composants visibles → re-render automatique si la langue change (et timing-safe vis-à-vis HMR).engagementStatusLabel()/simulationStatusLabel()gardés pour les call sites hors-component (form options, banner content construction, etc.).formatDate/formatDateTimehardcodent'fr-FR'— pas de prop locale, pas de switcher. Si multi-langue un jour, c'est ici qu'on passera ài18n.language.tont été renommés entech/tac/tpl/toastpartout pour ne pas masquer letdeuseTranslation()._one/_other(c2.modal.execute.commandCount, c2.modal.import.toast.imported/partial, mitre.matrix.applyItem).Out of scope (reconnu, sprint 13+)
en.jsonsi jamais besoin, mais aucun switcher UI ni détection navigator. FR-only.ForbiddenState/NotFoundState: composants jamais créés (pas dans le code), pas de keys i18n.NITs rejetés
text-caption-md→caption-md(design NIT 1) : rejeté. Le sprint 11 build-fix a établi que les fontSize tokens (registered danstheme.extend) génèrent des utilitiestext-<key>, jamais des bare-name utilities. Le prefixtext-est correct, omettre casserait PostCSS. Documenté dansfeedback_css_apply_tokens.md.Commits (14 sur la branche, dont 12 nouveaux sprint 12)
(Plus
2c7fcecdu sprint 11 trail tail, sera absorbé par le merge.)🤖 Generated with Claude Code
Tabs: Schedule (default) / Description / Simulations, wired via useHashTab('schedule'). Count pill on Simulations tab. BackLink replaces hand-rolled Link. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>- StatusBadge/SimulationStatusBadge: swap bare i18n.t() helper for useTranslation() hook so badges re-render reactively on i18n init - EngagementDetailPage: formatDate() on start_date/end_date/created_at (was: raw ISO string, formatDateTime with noisy 00:00:00) - UsersAdminPage: formatDate() on created_at column (was: raw ISO string) - Layout footer: t('nav.footer') with FR string in fr.json Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>