feat(i18n): add LanguageSwitcher component and useLanguage hook
This commit is contained in:
parent
a93a343d2b
commit
77e0923f28
36
src/components/shared/LanguageSwitcher.tsx
Normal file
36
src/components/shared/LanguageSwitcher.tsx
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import {useLanguage, SUPPORTED_LANGUAGES} from '@/hooks/useLanguage';
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from '@/components/ui/dropdown-menu';
|
||||||
|
import {Button} from '@/components/ui/button';
|
||||||
|
import {Globe} from 'lucide-react';
|
||||||
|
|
||||||
|
export function LanguageSwitcher() {
|
||||||
|
const {currentLanguage, changeLanguage} = useLanguage();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger>
|
||||||
|
<Button variant="ghost" size="sm" className="gap-2">
|
||||||
|
<Globe className="h-4 w-4" />
|
||||||
|
<span>{currentLanguage.nativeName}</span>
|
||||||
|
</Button>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent align="end">
|
||||||
|
{SUPPORTED_LANGUAGES.map((lang) => (
|
||||||
|
<DropdownMenuItem
|
||||||
|
key={lang.code}
|
||||||
|
onClick={() => changeLanguage(lang.code)}
|
||||||
|
className={lang.code === currentLanguage.code ? 'bg-accent' : ''}
|
||||||
|
>
|
||||||
|
<span className="mr-2">{lang.nativeName}</span>
|
||||||
|
<span className="text-muted-foreground text-xs">{lang.name}</span>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
))}
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
);
|
||||||
|
}
|
||||||
29
src/hooks/useLanguage.ts
Normal file
29
src/hooks/useLanguage.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import {useTranslation} from 'react-i18next';
|
||||||
|
|
||||||
|
export const SUPPORTED_LANGUAGES = [
|
||||||
|
{code: 'en', name: 'English', nativeName: 'English'},
|
||||||
|
{code: 'zh', name: 'Chinese', nativeName: '中文'},
|
||||||
|
{code: 'de', name: 'German', nativeName: 'Deutsch'},
|
||||||
|
{code: 'fr', name: 'French', nativeName: 'Français'},
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export type SupportedLanguage = (typeof SUPPORTED_LANGUAGES)[number]['code'];
|
||||||
|
|
||||||
|
export function useLanguage() {
|
||||||
|
const {i18n} = useTranslation();
|
||||||
|
|
||||||
|
const currentLanguage = SUPPORTED_LANGUAGES.find(
|
||||||
|
(lang) => lang.code === i18n.language,
|
||||||
|
) ?? SUPPORTED_LANGUAGES[0];
|
||||||
|
|
||||||
|
const changeLanguage = (langCode: SupportedLanguage) => {
|
||||||
|
i18n.changeLanguage(langCode);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
currentLanguage,
|
||||||
|
changeLanguage,
|
||||||
|
supportedLanguages: SUPPORTED_LANGUAGES,
|
||||||
|
isLoading: !i18n.isInitialized,
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user