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')}
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';