57 lines
1.9 KiB
TypeScript
57 lines
1.9 KiB
TypeScript
import { useTranslation } from 'react-i18next'
|
|
import { LANGUAGES, type LanguageCode } from '@/i18n'
|
|
|
|
interface LanguageSelectorProps {
|
|
/** Additional CSS classes */
|
|
className?: string
|
|
/** Compact mode - shows only flag and code */
|
|
compact?: boolean
|
|
}
|
|
|
|
/**
|
|
* A dropdown component for selecting the application language.
|
|
* Uses i18next for language switching and persists choice to localStorage.
|
|
*/
|
|
export default function LanguageSelector({ className = '', compact = false }: LanguageSelectorProps) {
|
|
const { i18n, t } = useTranslation('common')
|
|
|
|
const handleLanguageChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
|
const newLang = e.target.value as LanguageCode
|
|
i18n.changeLanguage(newLang)
|
|
}
|
|
|
|
return (
|
|
<div className={`relative ${className}`}>
|
|
<select
|
|
value={i18n.language}
|
|
onChange={handleLanguageChange}
|
|
className="appearance-none bg-white border border-gray-300 rounded-md pl-3 pr-8 py-1.5 text-sm text-gray-700 hover:border-gray-400 focus:outline-none focus:ring-2 focus:ring-teal-500 focus:border-transparent cursor-pointer"
|
|
title={t('selectLanguage')}
|
|
aria-label={t('selectLanguage')}
|
|
>
|
|
{LANGUAGES.map((lang) => (
|
|
<option key={lang.code} value={lang.code}>
|
|
{compact ? `${lang.flag} ${lang.code.toUpperCase()}` : `${lang.flag} ${lang.label}`}
|
|
</option>
|
|
))}
|
|
</select>
|
|
{/* Custom dropdown arrow */}
|
|
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
|
|
<svg
|
|
className="h-4 w-4 text-gray-400"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
>
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth={2}
|
|
d="M19 9l-7 7-7-7"
|
|
/>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|