Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | 7x 226x 226x 226x 226x 4x 4x 4x 4x 4x 4x 226x 2034x | import React from 'react';
import { useTranslation } from 'react-i18next';
import { Globe } from 'lucide-react';
import { updateUserPreferences } from '../../../services/api/userApi';
import { useAuth } from '../../../hooks/useAuth';
import type { UpdatePreferencesRequest } from '../../../types/user';
/**
* Language selector. Tailwind + a native <select> (no MUI): this control sits in the
* public navigation, which is part of the eager homepage graph, so keeping it MUI-free
* is what stops @mui/material from being pulled into the public entry chunk. Styling is
* neutral (transparent bg, inherited text colour) so it reads correctly on both the
* dark public nav and the light auth pages where it is also used.
*/
const LanguageSwitcher: React.FC = () => {
const { i18n } = useTranslation();
const { isAuthenticated } = useAuth();
const languages = [
{ code: 'de', label: 'DE — Deutsch' },
{ code: 'en', label: 'EN — English' },
{ code: 'fr', label: 'FR — Français' },
{ code: 'it', label: 'IT — Italiano' },
{ code: 'rm', label: 'RM — Rumantsch' },
{ code: 'es', label: 'ES — Español' },
{ code: 'fi', label: 'FI — Suomi' },
{ code: 'nl', label: 'NL — Nederlands' },
{ code: 'ja', label: 'JA — 日本語' },
];
const handleLanguageChange = async (event: React.ChangeEvent<HTMLSelectElement>) => {
const newLang = event.target.value;
await i18n.changeLanguage(newLang);
document.documentElement.lang = newLang;
localStorage.setItem('batbern-language', newLang);
// Persist to API only if authenticated (backend is ready, Story 2.6)
Iif (isAuthenticated) {
try {
await updateUserPreferences({ language: newLang as UpdatePreferencesRequest['language'] });
console.log('[LanguageSwitcher] Language preference saved to backend');
} catch (error) {
console.error('[LanguageSwitcher] Failed to persist language preference:', error);
// Continue anyway - localStorage update was successful
}
} else {
console.log('[LanguageSwitcher] Skipping backend save - user not authenticated');
}
};
return (
<div className="flex items-center gap-2">
<Globe className="h-4 w-4 flex-shrink-0" aria-hidden="true" />
<select
value={i18n.language}
onChange={handleLanguageChange}
aria-label="Language selector"
data-testid="language-selector"
className="min-w-[160px] cursor-pointer rounded-md border border-current/20 bg-transparent px-3 py-1.5 text-sm text-inherit focus:outline-none focus:ring-2 focus:ring-ring/50"
>
{languages.map(({ code, label }) => (
<option key={code} value={code} className="bg-zinc-800 text-zinc-100">
{label}
</option>
))}
</select>
</div>
);
};
export default LanguageSwitcher;
|