story-research-zapwall/components/LanguageSelector.tsx
Nicolas Cantu cc49c9d7c1 Add language preference selector in settings
**Motivations:**
- Allow users to set their preferred language (fr/en) in the settings page
- Load language preference from localStorage at startup to configure the application locale

**Root causes:**
- Language preference was only available in the header via LanguageSelector component
- Language preference was stored in IndexedDB instead of localStorage
- No centralized language settings management in the settings page

**Correctifs:**
- Created LanguageSettingsManager component for settings page
- Migrated language storage from IndexedDB to localStorage for consistency
- Updated _app.tsx to load locale from localStorage synchronously at startup
- Updated useI18n hook to use localStorage instead of IndexedDB
- Updated LanguageSelector component to use localStorage instead of IndexedDB

**Evolutions:**
- Added language preference section in settings page (displayed first)
- Language preference is now loaded at application startup from localStorage
- Added translations for language settings (settings.language.*)

**Pages affectées:**
- components/LanguageSettingsManager.tsx (new)
- pages/settings.tsx
- pages/_app.tsx
- hooks/useI18n.ts
- components/LanguageSelector.tsx
- locales/fr.txt
- locales/en.txt
2026-01-06 14:57:38 +01:00

71 lines
2.1 KiB
TypeScript

import { useState, useEffect } from 'react'
import { setLocale, getLocale, type Locale } from '@/lib/i18n'
const LOCALE_STORAGE_KEY = 'zapwall-locale'
interface LocaleButtonProps {
locale: Locale
label: string
currentLocale: Locale
onClick: (locale: Locale) => void
}
function LocaleButton({ locale, label, currentLocale, onClick }: LocaleButtonProps): React.ReactElement {
const isActive = currentLocale === locale
return (
<button
onClick={() => onClick(locale)}
className={`px-2 py-1 text-xs font-medium rounded transition-colors ${
isActive
? 'bg-neon-cyan/20 text-neon-cyan border border-neon-cyan/50'
: 'text-cyber-accent hover:text-neon-cyan border border-transparent hover:border-neon-cyan/30'
}`}
>
{label}
</button>
)
}
export function LanguageSelector(): React.ReactElement {
const [currentLocale, setCurrentLocale] = useState<Locale>(getLocale())
useEffect(() => {
// Load saved locale from localStorage
const loadLocale = (): void => {
try {
if (typeof window !== 'undefined') {
const savedLocale = localStorage.getItem(LOCALE_STORAGE_KEY) as Locale | null
if (savedLocale && (savedLocale === 'fr' || savedLocale === 'en')) {
setLocale(savedLocale)
setCurrentLocale(savedLocale)
}
}
} catch (e) {
console.error('Error loading locale:', e)
}
}
loadLocale()
}, [])
const handleLocaleChange = (locale: Locale): void => {
setLocale(locale)
setCurrentLocale(locale)
try {
if (typeof window !== 'undefined') {
localStorage.setItem(LOCALE_STORAGE_KEY, locale)
}
} catch (e) {
console.error('Error saving locale:', e)
}
// Force page reload to update all translations
window.location.reload()
}
return (
<div className="flex items-center gap-2">
<LocaleButton locale="fr" label="FR" currentLocale={currentLocale} onClick={handleLocaleChange} />
<LocaleButton locale="en" label="EN" currentLocale={currentLocale} onClick={handleLocaleChange} />
</div>
)
}