diff --git a/frontend/src/components/Layout.tsx b/frontend/src/components/Layout.tsx index 2d14a51..aafacbe 100644 --- a/frontend/src/components/Layout.tsx +++ b/frontend/src/components/Layout.tsx @@ -1,5 +1,6 @@ import { Link, NavLink, Outlet, useNavigate } from 'react-router-dom'; import { Moon, Sun, Monitor } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; import { useAuth } from '@/hooks/useAuth'; import { useTheme } from '@/hooks/useTheme'; import type { Theme } from '@/hooks/useTheme'; @@ -20,6 +21,7 @@ export function Layout(): JSX.Element { const { user, isAdmin, isRedteam, logout } = useAuth(); const navigate = useNavigate(); const { theme, cycleTheme } = useTheme(); + const { t } = useTranslation(); const handleLogout = async () => { await logout(); @@ -52,7 +54,7 @@ export function Layout(): JSX.Element { onClick={handleLogout} className="text-[14px] underline-offset-2 hover:underline" > - Sign out + {t('nav.signOut')} ) : null} @@ -78,7 +80,7 @@ export function Layout(): JSX.Element { }` } > - Engagements + {t('nav.engagements')} {isAdmin || isRedteam ? ( - Templates + {t('nav.templates')} ) : null} {isAdmin ? ( @@ -105,7 +107,7 @@ export function Layout(): JSX.Element { }` } > - Users + {t('nav.users')} ) : null} diff --git a/frontend/src/components/ProtectedRoute.tsx b/frontend/src/components/ProtectedRoute.tsx index 97b3799..a109d65 100644 --- a/frontend/src/components/ProtectedRoute.tsx +++ b/frontend/src/components/ProtectedRoute.tsx @@ -1,5 +1,6 @@ import { useEffect } from 'react'; import { Navigate, Outlet, useLocation } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; import { useAuth } from '@/hooks/useAuth'; import { useToast } from '@/hooks/useToast'; import type { Role } from '@/api/types'; @@ -23,6 +24,7 @@ export function ProtectedRoute({ }: ProtectedRouteProps): JSX.Element { const { user, status } = useAuth(); const { push } = useToast(); + const { t } = useTranslation(); const location = useLocation(); const roleDenied = Boolean( @@ -31,12 +33,12 @@ export function ProtectedRoute({ useEffect(() => { if (roleDenied) { - push('Accès refusé', 'error'); + push(t('auth.forbidden'), 'error'); } - }, [roleDenied, push]); + }, [roleDenied, push, t]); if (status === 'loading') { - return ; + return ; } if (status === 'unauthenticated' || !user) { diff --git a/frontend/src/pages/LoginPage.tsx b/frontend/src/pages/LoginPage.tsx index 49daf16..93fcd71 100644 --- a/frontend/src/pages/LoginPage.tsx +++ b/frontend/src/pages/LoginPage.tsx @@ -1,5 +1,6 @@ import { useState, type FormEvent } from 'react'; import { Navigate, useLocation, useNavigate } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; import { extractApiError } from '@/api/client'; import { useAuth } from '@/hooks/useAuth'; import { FormField, TextInput } from '@/components/FormField'; @@ -14,6 +15,7 @@ export function LoginPage(): JSX.Element { const location = useLocation(); const fromPath = (location.state as LocationState | null)?.from; + const { t } = useTranslation(); const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const [submitting, setSubmitting] = useState(false); @@ -34,7 +36,7 @@ export function LoginPage(): JSX.Element { await login(username, password); navigate(fromPath ?? '/engagements', { replace: true }); } catch (err) { - setError(extractApiError(err, 'Invalid credentials')); + setError(extractApiError(err, t('auth.login.invalid'))); } finally { setSubmitting(false); } @@ -48,10 +50,10 @@ export function LoginPage(): JSX.Element {

Mimic

-

Sign in to access your engagements.

+

{t('auth.login.subtitle')}

- + - + - {submitting ? 'Signing in…' : 'Sign in'} + {submitting ? t('auth.login.signingIn') : t('auth.login.signIn')} diff --git a/frontend/vitest.setup.ts b/frontend/vitest.setup.ts index bb02c60..4ad2b0d 100644 --- a/frontend/vitest.setup.ts +++ b/frontend/vitest.setup.ts @@ -1 +1,2 @@ import '@testing-library/jest-dom/vitest'; +import './src/i18n';