Add language selector

This commit is contained in:
Nicola Benaglia 2025-04-24 09:12:33 +02:00
parent a70d77c17e
commit d627c6a142
7 changed files with 92 additions and 2 deletions

11
i18n.js
View File

@ -19,6 +19,15 @@ const capitalize = {
},
};
export const supportedLanguages = {
de: { name: 'Deutsch', flag: '🇩🇪' },
en: { name: 'English', flag: '🇬🇧' },
es: { name: 'Español', flag: '🇪🇸' },
fr: { name: 'Français', flag: '🇫🇷' },
it: { name: 'Italiano', flag: '🇮🇹' },
ru: { name: 'Русский', flag: '🇷🇺' },
};
i18n
.use(HttpApi)
.use(LanguageDetector)
@ -43,7 +52,7 @@ i18n
},
lng: navigator.language,
ns: ['auth', 'core', 'group', 'tutorial'],
supportedLngs: ['en', 'it', 'es', 'fr', 'de', 'ru'],
supportedLngs: Object.keys(supportedLanguages),
});
export default i18n;

View File

@ -137,6 +137,7 @@ import { GeneralNotifications } from './components/GeneralNotifications';
import { PdfViewer } from './common/PdfViewer';
import ThemeSelector from './components/Theme/ThemeSelector.tsx';
import { useTranslation } from 'react-i18next';
import LanguageSelector from './components/Language/LanguageSelector.tsx';
type extStates =
| 'not-authenticated'
@ -3704,6 +3705,7 @@ function App() {
/>
)}
<LanguageSelector />
<ThemeSelector />
</AppContainer>
);

View File

@ -31,6 +31,7 @@ import { GlobalContext } from '../App';
import Tooltip, { TooltipProps, tooltipClasses } from '@mui/material/Tooltip';
import ThemeSelector from '../components/Theme/ThemeSelector';
import { useTranslation } from 'react-i18next';
import LanguageSelector from '../components/Language/LanguageSelector';
const manifestData = {
version: '0.5.3',
@ -1097,6 +1098,7 @@ export const NotAuthenticated = ({
/>
</ButtonBase>
<LanguageSelector />
<ThemeSelector />
</>
);

View File

@ -15,6 +15,7 @@ import { extractComponents } from '../Chat/MessageDisplay';
import ArrowOutwardIcon from '@mui/icons-material/ArrowOutward';
import { AppsPrivate } from './AppsPrivate';
import ThemeSelector from '../Theme/ThemeSelector';
import LanguageSelector from '../Language/LanguageSelector';
export const AppsHomeDesktop = ({
setMode,
@ -157,6 +158,7 @@ export const AppsHomeDesktop = ({
/>
</AppsContainer>
<LanguageSelector />
<ThemeSelector />
</>
);

View File

@ -8,6 +8,7 @@ import { enabledDevModeAtom } from '../atoms/global';
import { AppsIcon } from '../assets/Icons/AppsIcon';
import ThemeSelector from './Theme/ThemeSelector';
import { CoreSyncStatus } from './CoreSyncStatus';
import LanguageSelector from './Language/LanguageSelector';
export const DesktopSideBar = ({
goToHome,
@ -139,6 +140,7 @@ export const DesktopSideBar = ({
</ButtonBase>
)}
<LanguageSelector />
<ThemeSelector />
</Box>
);

View File

@ -0,0 +1,73 @@
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { supportedLanguages } from '../../../i18n';
import { Tooltip } from '@mui/material';
const LanguageSelector = () => {
const { i18n } = useTranslation();
const [showSelect, setShowSelect] = useState(false);
const handleChange = (e) => {
const newLang = e.target.value;
i18n.changeLanguage(newLang);
setShowSelect(false);
};
const currentLang = i18n.language;
const { name, flag } =
supportedLanguages[currentLang] || supportedLanguages['en'];
return (
<div
style={{
bottom: '5%',
display: 'flex',
gap: '12px',
left: '1.5vh',
position: 'absolute',
}}
>
<Tooltip
title="Pollo"
// {
// themeMode === 'dark'
// ? t('core:theme.light', {
// postProcess: 'capitalize',
// })
// : t('core:theme.light', {
// postProcess: 'capitalize',
// })
// }
>
{showSelect ? (
<select
value={currentLang}
onChange={handleChange}
onBlur={() => setShowSelect(false)}
>
{Object.entries(supportedLanguages).map(([code, { name }]) => (
<option key={code} value={code}>
{code.toUpperCase()} - {name}
</option>
))}
</select>
) : (
<button
onClick={() => setShowSelect(true)}
style={{
fontSize: '1.5rem',
border: 'none',
background: 'none',
cursor: 'pointer',
}}
aria-label={`Current language: ${name}`}
>
{flag}
</button>
)}
</Tooltip>
</div>
);
};
export default LanguageSelector;

View File

@ -14,7 +14,7 @@ const ThemeSelector = () => {
bottom: '1%',
display: 'flex',
gap: '12px',
left: '1.5vh',
left: '1.2vh',
position: 'absolute',
}}
>