diff --git a/i18n.js b/i18n.js
deleted file mode 100644
index 5277e59..0000000
--- a/i18n.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import { initReactI18next } from 'react-i18next';
-import HttpBackend from 'i18next-http-backend';
-import LocalStorageBackend from 'i18next-localstorage-backend';
-import HttpApi from 'i18next-http-backend';
-import i18n from 'i18next';
-import LanguageDetector from 'i18next-browser-languagedetector';
-
-// Detect environment
-const isDev = process.env.NODE_ENV === 'development';
-
-// Register custom postProcessor: it capitalizes the first letter of a translation-
-// Usage:
-// t('greeting', { postProcess: 'capitalize' })
-const capitalize = {
- type: 'postProcessor',
- name: 'capitalize',
- process: (value) => {
- return value.charAt(0).toUpperCase() + value.slice(1);
- },
-};
-
-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)
- .use(initReactI18next)
- .use(capitalize)
- .init({
- backend: {
- backends: [LocalStorageBackend, HttpBackend],
- backendOptions: [
- {
- expirationTime: 7 * 24 * 60 * 60 * 1000, // 7 days
- },
- {
- loadPath: '/locales/{{lng}}/{{ns}}.json',
- },
- ],
- },
- debug: isDev,
- fallbackLng: 'en',
- interpolation: {
- escapeValue: false,
- },
- lng: navigator.language,
- ns: ['auth', 'core', 'group', 'tutorial'],
- supportedLngs: Object.keys(supportedLanguages),
- });
-
-export default i18n;
diff --git a/src/components/Language/LanguageSelector.tsx b/src/components/Language/LanguageSelector.tsx
index 751c0a9..ff78246 100644
--- a/src/components/Language/LanguageSelector.tsx
+++ b/src/components/Language/LanguageSelector.tsx
@@ -1,7 +1,13 @@
-import { useEffect, useRef, useState } from 'react';
+import { useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { supportedLanguages } from '../../../i18n';
-import { Tooltip, useTheme } from '@mui/material';
+import { supportedLanguages } from '../../i18n/i18n';
+import {
+ FormControl,
+ MenuItem,
+ Select,
+ Tooltip,
+ useTheme,
+} from '@mui/material';
const LanguageSelector = () => {
const { i18n, t } = useTranslation(['core']);
@@ -19,20 +25,6 @@ const LanguageSelector = () => {
const { name, flag } =
supportedLanguages[currentLang] || supportedLanguages['en'];
- // Detect clicks outside the component
- useEffect(() => {
- const handleClickOutside = (event) => {
- if (selectorRef.current && !selectorRef.current.contains(event.target)) {
- setShowSelect(false);
- }
- };
-
- document.addEventListener('mousedown', handleClickOutside);
- return () => {
- document.removeEventListener('mousedown', handleClickOutside);
- };
- }, []);
-
return (
{
position: 'absolute',
}}
>
-
- {showSelect ? (
-
- ) : (
+ {!showSelect && (
+
- )}
-
+
+ )}
+
+ {showSelect && (
+
+
+
+ )}
);
};
diff --git a/src/i18n/i18n.ts b/src/i18n/i18n.ts
new file mode 100644
index 0000000..8d267be
--- /dev/null
+++ b/src/i18n/i18n.ts
@@ -0,0 +1,54 @@
+import i18n from 'i18next';
+import { initReactI18next } from 'react-i18next';
+import LanguageDetector from 'i18next-browser-languagedetector';
+
+const capitalize = {
+ type: 'postProcessor',
+ name: 'capitalize',
+ process: (value: string) => value.charAt(0).toUpperCase() + value.slice(1),
+};
+
+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: '🇷🇺' },
+};
+
+// Load all JSON files under locales/**/*
+const modules = import.meta.glob('./locales/**/*.json', {
+ eager: true,
+}) as Record;
+
+// Construct i18n resources object
+const resources: Record> = {};
+
+for (const path in modules) {
+ // Path format: './locales/en/core.json'
+ const match = path.match(/\.\/locales\/([^/]+)\/([^/]+)\.json$/);
+ if (!match) continue;
+
+ const [, lang, ns] = match;
+ resources[lang] = resources[lang] || {};
+ resources[lang][ns] = modules[path].default;
+}
+
+i18n
+ .use(initReactI18next)
+ .use(LanguageDetector)
+ .use(capitalize as any)
+ .init({
+ resources,
+ fallbackLng: 'en',
+ lng: navigator.language,
+ supportedLngs: Object.keys(supportedLanguages),
+ ns: ['core', 'auth', 'group', 'tutorial'],
+ defaultNS: 'core',
+ interpolation: { escapeValue: false },
+ react: { useSuspense: false },
+ debug: import.meta.env.MODE === 'development',
+ });
+
+export default i18n;
diff --git a/public/locales/de/auth.json b/src/i18n/locales/de/auth.json
similarity index 100%
rename from public/locales/de/auth.json
rename to src/i18n/locales/de/auth.json
diff --git a/public/locales/de/core.json b/src/i18n/locales/de/core.json
similarity index 100%
rename from public/locales/de/core.json
rename to src/i18n/locales/de/core.json
diff --git a/public/locales/de/tutorial.json b/src/i18n/locales/de/tutorial.json
similarity index 100%
rename from public/locales/de/tutorial.json
rename to src/i18n/locales/de/tutorial.json
diff --git a/public/locales/en/auth.json b/src/i18n/locales/en/auth.json
similarity index 100%
rename from public/locales/en/auth.json
rename to src/i18n/locales/en/auth.json
diff --git a/public/locales/en/core.json b/src/i18n/locales/en/core.json
similarity index 100%
rename from public/locales/en/core.json
rename to src/i18n/locales/en/core.json
diff --git a/public/locales/en/group.json b/src/i18n/locales/en/group.json
similarity index 100%
rename from public/locales/en/group.json
rename to src/i18n/locales/en/group.json
diff --git a/public/locales/en/tutorial.json b/src/i18n/locales/en/tutorial.json
similarity index 100%
rename from public/locales/en/tutorial.json
rename to src/i18n/locales/en/tutorial.json
diff --git a/public/locales/es/auth.json b/src/i18n/locales/es/auth.json
similarity index 100%
rename from public/locales/es/auth.json
rename to src/i18n/locales/es/auth.json
diff --git a/public/locales/es/core.json b/src/i18n/locales/es/core.json
similarity index 100%
rename from public/locales/es/core.json
rename to src/i18n/locales/es/core.json
diff --git a/public/locales/es/tutorial.json b/src/i18n/locales/es/tutorial.json
similarity index 100%
rename from public/locales/es/tutorial.json
rename to src/i18n/locales/es/tutorial.json
diff --git a/public/locales/fr/auth.json b/src/i18n/locales/fr/auth.json
similarity index 100%
rename from public/locales/fr/auth.json
rename to src/i18n/locales/fr/auth.json
diff --git a/public/locales/fr/core.json b/src/i18n/locales/fr/core.json
similarity index 100%
rename from public/locales/fr/core.json
rename to src/i18n/locales/fr/core.json
diff --git a/public/locales/fr/tutorial.json b/src/i18n/locales/fr/tutorial.json
similarity index 100%
rename from public/locales/fr/tutorial.json
rename to src/i18n/locales/fr/tutorial.json
diff --git a/public/locales/it/auth.json b/src/i18n/locales/it/auth.json
similarity index 100%
rename from public/locales/it/auth.json
rename to src/i18n/locales/it/auth.json
diff --git a/public/locales/it/core.json b/src/i18n/locales/it/core.json
similarity index 100%
rename from public/locales/it/core.json
rename to src/i18n/locales/it/core.json
diff --git a/public/locales/it/group.json b/src/i18n/locales/it/group.json
similarity index 100%
rename from public/locales/it/group.json
rename to src/i18n/locales/it/group.json
diff --git a/public/locales/it/tutorial.json b/src/i18n/locales/it/tutorial.json
similarity index 100%
rename from public/locales/it/tutorial.json
rename to src/i18n/locales/it/tutorial.json
diff --git a/public/locales/ru/auth.json b/src/i18n/locales/ru/auth.json
similarity index 100%
rename from public/locales/ru/auth.json
rename to src/i18n/locales/ru/auth.json
diff --git a/public/locales/ru/core.json b/src/i18n/locales/ru/core.json
similarity index 100%
rename from public/locales/ru/core.json
rename to src/i18n/locales/ru/core.json
diff --git a/public/locales/ru/tutorial.json b/src/i18n/locales/ru/tutorial.json
similarity index 100%
rename from public/locales/ru/tutorial.json
rename to src/i18n/locales/ru/tutorial.json
diff --git a/src/main.tsx b/src/main.tsx
index 0a35316..d6da0d2 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -5,7 +5,7 @@ import './messaging/messagesToBackground';
import { MessageQueueProvider } from './MessageQueueContext.tsx';
import { ThemeProvider } from './components/Theme/ThemeContext.tsx';
import { CssBaseline } from '@mui/material';
-import '../i18n';
+import './i18n/i18n.js';
createRoot(document.getElementById('root')!).render(
<>
diff --git a/tsconfig.json b/tsconfig.json
index 24c5d39..95bc40f 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -8,12 +8,13 @@
"skipLibCheck": true,
/* Bundler mode */
- "moduleResolution": "bundler",
+ "moduleResolution": "node",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
+ "allowSyntheticDefaultImports": true,
/* Linting */
"strict": true,