feat: dynamic language list from API instead of hardcoded array

Hide language switcher when only 1 language is available.

Cherry-picked from PR #365
This commit is contained in:
Fringg
2026-03-29 05:15:31 +03:00
parent 0d4ddb26d9
commit 07500ed215

View File

@@ -1,19 +1,27 @@
import { useTranslation } from 'react-i18next';
import { useState, useRef, useEffect } from 'react';
const languages = [
{ code: 'ru', name: 'RU', flag: '🇷🇺', fullName: 'Русский' },
{ code: 'en', name: 'EN', flag: '🇬🇧', fullName: 'English' },
{ code: 'zh', name: 'ZH', flag: '🇨🇳', fullName: '中文' },
{ code: 'fa', name: 'FA', flag: '🇮🇷', fullName: 'فارسی' },
];
import { infoApi, type LanguageInfo } from '@/api/info';
export default function LanguageSwitcher() {
const { i18n } = useTranslation();
const [isOpen, setIsOpen] = useState(false);
const [availableLanguages, setAvailableLanguages] = useState<LanguageInfo[]>([]);
const dropdownRef = useRef<HTMLDivElement>(null);
const currentLang = languages.find((l) => l.code === i18n.language) || languages[0];
useEffect(() => {
const fetchLanguages = async () => {
try {
const data = await infoApi.getLanguages();
setAvailableLanguages(data.languages);
} catch {
// Silently fall back to empty list — component handles it gracefully
}
};
fetchLanguages();
}, []);
const currentLang = availableLanguages.find((l) => l.code === i18n.language) ||
availableLanguages[0] || { code: 'ru', name: 'RU', flag: '🇷🇺' };
useEffect(() => {
function handleClickOutside(event: MouseEvent) {
@@ -27,16 +35,18 @@ export default function LanguageSwitcher() {
const changeLanguage = (code: string) => {
i18n.changeLanguage(code);
// Set document direction for RTL languages
document.documentElement.dir = code === 'fa' ? 'rtl' : 'ltr';
setIsOpen(false);
};
// Set initial direction on mount
useEffect(() => {
document.documentElement.dir = i18n.language === 'fa' ? 'rtl' : 'ltr';
}, [i18n.language]);
if (availableLanguages.length <= 1) {
return null;
}
return (
<div className="relative" ref={dropdownRef}>
<button
@@ -49,7 +59,7 @@ export default function LanguageSwitcher() {
aria-label="Change language"
>
<span>{currentLang.flag}</span>
<span className="font-medium text-dark-200">{currentLang.name}</span>
<span className="font-medium text-dark-200">{currentLang.code.toUpperCase()}</span>
<svg
className={`h-3.5 w-3.5 text-dark-400 transition-transform ${isOpen ? 'rotate-180' : ''}`}
fill="none"
@@ -62,7 +72,7 @@ export default function LanguageSwitcher() {
{isOpen && (
<div className="absolute right-0 z-50 mt-2 w-40 animate-fade-in rounded-xl border border-dark-700/50 bg-dark-800 py-1 shadow-lg">
{languages.map((lang) => (
{availableLanguages.map((lang) => (
<button
key={lang.code}
onClick={() => changeLanguage(lang.code)}
@@ -73,7 +83,7 @@ export default function LanguageSwitcher() {
}`}
>
<span>{lang.flag}</span>
<span>{lang.fullName}</span>
<span>{lang.name}</span>
</button>
))}
</div>