Files
Froidefond Julien d4f87c4044 feat: add i18n support (FR/EN) to backoffice with English as default
Implement full internationalization for the Next.js backoffice:
- i18n infrastructure: type-safe dictionaries (fr.ts/en.ts), cookie-based locale detection, React Context for client components, server-side translation helper
- Language selector in Settings page (General tab) with cookie + DB persistence
- All ~35 pages and components translated via t() / useTranslation()
- Default locale set to English, French available via settings

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 19:39:01 +01:00

61 lines
1.8 KiB
TypeScript

"use client";
import { createContext, useContext, useCallback, useState, type ReactNode } from "react";
import type { Locale } from "./types";
import { LOCALE_COOKIE } from "./types";
import { getDictionarySync, createTranslateFunction } from "./dictionaries";
import type { TranslateFunction } from "./dictionaries";
interface LocaleContextValue {
locale: Locale;
t: TranslateFunction;
setLocale: (locale: Locale) => void;
}
const LocaleContext = createContext<LocaleContextValue | null>(null);
interface LocaleProviderProps {
initialLocale: Locale;
children: ReactNode;
}
export function LocaleProvider({ initialLocale, children }: LocaleProviderProps) {
const [locale] = useState<Locale>(initialLocale);
const dict = getDictionarySync(locale);
const t = createTranslateFunction(dict);
const setLocale = useCallback(async (newLocale: Locale) => {
// Set cookie
document.cookie = `${LOCALE_COOKIE}=${newLocale};path=/;max-age=${365 * 24 * 60 * 60}`;
// Save to DB
try {
const apiBase = process.env.NEXT_PUBLIC_API_URL || "http://localhost:7080";
await fetch(`${apiBase}/settings`, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ language: newLocale }),
});
} catch {
// Best effort — cookie is the primary source for rendering
}
// Reload to apply new locale everywhere (server + client)
window.location.reload();
}, []);
return (
<LocaleContext.Provider value={{ locale, t, setLocale }}>
{children}
</LocaleContext.Provider>
);
}
export function useTranslation(): LocaleContextValue {
const ctx = useContext(LocaleContext);
if (!ctx) {
throw new Error("useTranslation must be used within a LocaleProvider");
}
return ctx;
}