feat: implement lazy loading for languages in i18n, enhance LanguageSwitcher to handle language changes asynchronously, and update available languages management

This commit is contained in:
sebseb7
2025-07-20 15:44:50 +02:00
parent 2b64719758
commit 5202ff6e3e
3 changed files with 246 additions and 362 deletions

View File

@@ -24,10 +24,14 @@ class LanguageSwitcher extends Component {
this.setState({ anchorEl: null }); this.setState({ anchorEl: null });
}; };
handleLanguageChange = (language) => { handleLanguageChange = async (language) => {
const { languageContext } = this.props; const { languageContext } = this.props;
if (languageContext) { if (languageContext) {
languageContext.changeLanguage(language); try {
await languageContext.changeLanguage(language);
} catch (error) {
console.error('Failed to change language:', error);
}
} }
this.handleClose(); this.handleClose();
}; };
@@ -126,8 +130,8 @@ class LanguageSwitcher extends Component {
const { languageContext } = this.props; const { languageContext } = this.props;
if (anchorEl && !prevState.anchorEl && languageContext) { if (anchorEl && !prevState.anchorEl && languageContext) {
// Menu just opened, lazy load all flags // Menu just opened, lazy load flags for all languages (not just available ones)
languageContext.availableLanguages.forEach(lang => { languageContext.allLanguages.forEach(lang => {
if (!this.state.loadedFlags[lang]) { if (!this.state.loadedFlags[lang]) {
this.loadFlagComponent(lang); this.loadFlagComponent(lang);
} }
@@ -197,7 +201,7 @@ class LanguageSwitcher extends Component {
return null; return null;
} }
const { currentLanguage, availableLanguages } = languageContext; const { currentLanguage, allLanguages } = languageContext;
const open = Boolean(anchorEl); const open = Boolean(anchorEl);
return ( return (
@@ -237,7 +241,8 @@ class LanguageSwitcher extends Component {
horizontal: 'right', horizontal: 'right',
}} }}
> >
{availableLanguages.map((language) => ( {allLanguages.map((language) => {
return (
<MenuItem <MenuItem
key={language} key={language}
onClick={() => this.handleLanguageChange(language)} onClick={() => this.handleLanguageChange(language)}
@@ -259,7 +264,8 @@ class LanguageSwitcher extends Component {
{this.getLanguageLabel(language)} {this.getLanguageLabel(language)}
</Typography> </Typography>
</MenuItem> </MenuItem>
))} );
})}
</Menu> </Menu>
</Box> </Box>
); );

View File

@@ -1,178 +1,128 @@
import i18n from 'i18next'; import i18n from 'i18next';
import { initReactI18next } from 'react-i18next'; import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector'; // Note: LanguageDetector not used - we have custom detector
// Import all translation files // Only import German translations by default
import translationDE from './locales/de/index.js'; import translationDE from './locales/de/index.js';
import translationEN from './locales/en/index.js';
import translationAR from './locales/ar/translation.js';
import translationBG from './locales/bg/translation.js';
import translationCS from './locales/cs/translation.js';
import translationEL from './locales/el/translation.js';
import translationES from './locales/es/translation.js';
import translationFR from './locales/fr/translation.js';
import translationHR from './locales/hr/translation.js';
import translationHU from './locales/hu/translation.js';
import translationIT from './locales/it/translation.js';
import translationPL from './locales/pl/translation.js';
import translationRO from './locales/ro/translation.js';
import translationRU from './locales/ru/translation.js';
import translationSK from './locales/sk/translation.js';
import translationSL from './locales/sl/translation.js';
import translationSR from './locales/sr/translation.js';
import translationSV from './locales/sv/translation.js';
import translationTR from './locales/tr/translation.js';
import translationUK from './locales/uk/translation.js';
import translationZH from './locales/zh/translation.js';
// Import legal translations for all languages
// German
import legalAgbDE from './locales/de/legal-agb.js'; import legalAgbDE from './locales/de/legal-agb.js';
import legalDatenschutzDE from './locales/de/legal-datenschutz.js'; import legalDatenschutzDE from './locales/de/legal-datenschutz.js';
import legalImpressumDE from './locales/de/legal-impressum.js'; import legalImpressumDE from './locales/de/legal-impressum.js';
import legalWiderrufDE from './locales/de/legal-widerruf.js'; import legalWiderrufDE from './locales/de/legal-widerruf.js';
import legalBatterieDE from './locales/de/legal-batterie.js'; import legalBatterieDE from './locales/de/legal-batterie.js';
// English // Language loading cache to prevent duplicate loads
import legalAgbEN from './locales/en/legal-agb.js'; const languageCache = new Set(['de']);
import legalDatenschutzEN from './locales/en/legal-datenschutz.js'; const loadingPromises = new Map();
import legalImpressumEN from './locales/en/legal-impressum.js';
import legalWiderrufEN from './locales/en/legal-widerruf.js';
import legalBatterieEN from './locales/en/legal-batterie.js';
// Arabic // Lazy loading function for languages
import legalAgbAR from './locales/ar/legal-agb.js'; const loadLanguage = async (language) => {
import legalDatenschutzAR from './locales/ar/legal-datenschutz.js'; if (languageCache.has(language)) {
import legalImpressumAR from './locales/ar/legal-impressum.js'; return; // Already loaded
import legalWiderrufAR from './locales/ar/legal-widerruf.js'; }
import legalBatterieAR from './locales/ar/legal-batterie.js';
// Bulgarian if (loadingPromises.has(language)) {
import legalAgbBG from './locales/bg/legal-agb.js'; return loadingPromises.get(language); // Already loading
import legalDatenschutzBG from './locales/bg/legal-datenschutz.js'; }
import legalImpressumBG from './locales/bg/legal-impressum.js';
import legalWiderrufBG from './locales/bg/legal-widerruf.js';
import legalBatterieBG from './locales/bg/legal-batterie.js';
// Czech const loadingPromise = (async () => {
import legalAgbCS from './locales/cs/legal-agb.js'; try {
import legalDatenschutzCS from './locales/cs/legal-datenschutz.js'; console.log(`🌍 Lazy loading language: ${language}`);
import legalImpressumCS from './locales/cs/legal-impressum.js';
import legalWiderrufCS from './locales/cs/legal-widerruf.js';
import legalBatterieCS from './locales/cs/legal-batterie.js';
// Greek // Dynamic imports for lazy loading
import legalAgbEL from './locales/el/legal-agb.js'; const [
import legalDatenschutzEL from './locales/el/legal-datenschutz.js'; translation,
import legalImpressumEL from './locales/el/legal-impressum.js'; legalAgb,
import legalWiderrufEL from './locales/el/legal-widerruf.js'; legalDatenschutz,
import legalBatterieEL from './locales/el/legal-batterie.js'; legalImpressum,
legalWiderruf,
legalBatterie
] = await Promise.all([
import(`./locales/${language}/index.js`),
import(`./locales/${language}/legal-agb.js`),
import(`./locales/${language}/legal-datenschutz.js`),
import(`./locales/${language}/legal-impressum.js`),
import(`./locales/${language}/legal-widerruf.js`),
import(`./locales/${language}/legal-batterie.js`)
]);
// Spanish // Add the loaded resources to i18n
import legalAgbES from './locales/es/legal-agb.js'; i18n.addResourceBundle(language, 'translation', translation.default);
import legalDatenschutzES from './locales/es/legal-datenschutz.js'; i18n.addResourceBundle(language, 'legal-agb', legalAgb.default);
import legalImpressumES from './locales/es/legal-impressum.js'; i18n.addResourceBundle(language, 'legal-datenschutz', legalDatenschutz.default);
import legalWiderrufES from './locales/es/legal-widerruf.js'; i18n.addResourceBundle(language, 'legal-impressum', legalImpressum.default);
import legalBatterieES from './locales/es/legal-batterie.js'; i18n.addResourceBundle(language, 'legal-widerruf', legalWiderruf.default);
i18n.addResourceBundle(language, 'legal-batterie', legalBatterie.default);
// French languageCache.add(language);
import legalAgbFR from './locales/fr/legal-agb.js'; console.log(`✅ Language ${language} loaded successfully`);
import legalDatenschutzFR from './locales/fr/legal-datenschutz.js'; } catch (error) {
import legalImpressumFR from './locales/fr/legal-impressum.js'; console.error(`❌ Failed to load language ${language}:`, error);
import legalWiderrufFR from './locales/fr/legal-widerruf.js'; throw error;
import legalBatterieFR from './locales/fr/legal-batterie.js'; } finally {
loadingPromises.delete(language);
}
})();
// Croatian loadingPromises.set(language, loadingPromise);
import legalAgbHR from './locales/hr/legal-agb.js'; return loadingPromise;
import legalDatenschutzHR from './locales/hr/legal-datenschutz.js'; };
import legalImpressumHR from './locales/hr/legal-impressum.js';
import legalWiderrufHR from './locales/hr/legal-widerruf.js';
import legalBatterieHR from './locales/hr/legal-batterie.js';
// Hungarian // Custom language detector that prioritizes session storage and defaults to German
import legalAgbHU from './locales/hu/legal-agb.js'; const customDetector = {
import legalDatenschutzHU from './locales/hu/legal-datenschutz.js'; name: 'customDetector',
import legalImpressumHU from './locales/hu/legal-impressum.js'; lookup() {
import legalWiderrufHU from './locales/hu/legal-widerruf.js'; // Only try storage in browser environment
import legalBatterieHU from './locales/hu/legal-batterie.js'; if (typeof window === 'undefined') {
return 'de';
}
// Italian // 1. Check session storage first
import legalAgbIT from './locales/it/legal-agb.js'; try {
import legalDatenschutzIT from './locales/it/legal-datenschutz.js'; if (typeof sessionStorage !== 'undefined') {
import legalImpressumIT from './locales/it/legal-impressum.js'; const sessionLang = sessionStorage.getItem('i18nextLng');
import legalWiderrufIT from './locales/it/legal-widerruf.js'; if (sessionLang && sessionLang !== 'de') {
import legalBatterieIT from './locales/it/legal-batterie.js'; return sessionLang;
}
}
} catch {
// Session storage not available
}
// Polish // 2. Check localStorage
import legalAgbPL from './locales/pl/legal-agb.js'; try {
import legalDatenschutzPL from './locales/pl/legal-datenschutz.js'; if (typeof localStorage !== 'undefined') {
import legalImpressumPL from './locales/pl/legal-impressum.js'; const localLang = localStorage.getItem('i18nextLng');
import legalWiderrufPL from './locales/pl/legal-widerruf.js'; if (localLang && localLang !== 'de') {
import legalBatteriePL from './locales/pl/legal-batterie.js'; return localLang;
}
}
} catch {
// LocalStorage not available
}
// Romanian // 3. Always default to German (don't detect browser language)
import legalAgbRO from './locales/ro/legal-agb.js'; return 'de';
import legalDatenschutzRO from './locales/ro/legal-datenschutz.js'; },
import legalImpressumRO from './locales/ro/legal-impressum.js'; cacheUserLanguage(lng) {
import legalWiderrufRO from './locales/ro/legal-widerruf.js'; // Only cache in browser environment
import legalBatterieRO from './locales/ro/legal-batterie.js'; if (typeof window === 'undefined') {
return;
}
// Russian try {
import legalAgbRU from './locales/ru/legal-agb.js'; if (typeof sessionStorage !== 'undefined') {
import legalDatenschutzRU from './locales/ru/legal-datenschutz.js'; sessionStorage.setItem('i18nextLng', lng);
import legalImpressumRU from './locales/ru/legal-impressum.js'; }
import legalWiderrufRU from './locales/ru/legal-widerruf.js'; if (typeof localStorage !== 'undefined') {
import legalBatterieRU from './locales/ru/legal-batterie.js'; localStorage.setItem('i18nextLng', lng);
}
// Slovak } catch {
import legalAgbSK from './locales/sk/legal-agb.js'; // Storage not available
import legalDatenschutzSK from './locales/sk/legal-datenschutz.js'; }
import legalImpressumSK from './locales/sk/legal-impressum.js'; }
import legalWiderrufSK from './locales/sk/legal-widerruf.js'; };
import legalBatterieSK from './locales/sk/legal-batterie.js';
// Slovenian
import legalAgbSL from './locales/sl/legal-agb.js';
import legalDatenschutzSL from './locales/sl/legal-datenschutz.js';
import legalImpressumSL from './locales/sl/legal-impressum.js';
import legalWiderrufSL from './locales/sl/legal-widerruf.js';
import legalBatterieSL from './locales/sl/legal-batterie.js';
// Serbian
import legalAgbSR from './locales/sr/legal-agb.js';
import legalDatenschutzSR from './locales/sr/legal-datenschutz.js';
import legalImpressumSR from './locales/sr/legal-impressum.js';
import legalWiderrufSR from './locales/sr/legal-widerruf.js';
import legalBatterieSR from './locales/sr/legal-batterie.js';
// Swedish
import legalAgbSV from './locales/sv/legal-agb.js';
import legalDatenschutzSV from './locales/sv/legal-datenschutz.js';
import legalImpressumSV from './locales/sv/legal-impressum.js';
import legalWiderrufSV from './locales/sv/legal-widerruf.js';
import legalBatterieSV from './locales/sv/legal-batterie.js';
// Turkish
import legalAgbTR from './locales/tr/legal-agb.js';
import legalDatenschutzTR from './locales/tr/legal-datenschutz.js';
import legalImpressumTR from './locales/tr/legal-impressum.js';
import legalWiderrufTR from './locales/tr/legal-widerruf.js';
import legalBatterieTR from './locales/tr/legal-batterie.js';
// Ukrainian
import legalAgbUK from './locales/uk/legal-agb.js';
import legalDatenschutzUK from './locales/uk/legal-datenschutz.js';
import legalImpressumUK from './locales/uk/legal-impressum.js';
import legalWiderrufUK from './locales/uk/legal-widerruf.js';
import legalBatterieUK from './locales/uk/legal-batterie.js';
// Chinese
import legalAgbZH from './locales/zh/legal-agb.js';
import legalDatenschutzZH from './locales/zh/legal-datenschutz.js';
import legalImpressumZH from './locales/zh/legal-impressum.js';
import legalWiderrufZH from './locales/zh/legal-widerruf.js';
import legalBatterieZH from './locales/zh/legal-batterie.js';
// Initialize i18n with only German resources
const resources = { const resources = {
de: { de: {
translation: translationDE, translation: translationDE,
@@ -181,185 +131,28 @@ const resources = {
'legal-impressum': legalImpressumDE, 'legal-impressum': legalImpressumDE,
'legal-widerruf': legalWiderrufDE, 'legal-widerruf': legalWiderrufDE,
'legal-batterie': legalBatterieDE 'legal-batterie': legalBatterieDE
},
en: {
translation: translationEN,
'legal-agb': legalAgbEN,
'legal-datenschutz': legalDatenschutzEN,
'legal-impressum': legalImpressumEN,
'legal-widerruf': legalWiderrufEN,
'legal-batterie': legalBatterieEN
},
ar: {
translation: translationAR,
'legal-agb': legalAgbAR,
'legal-datenschutz': legalDatenschutzAR,
'legal-impressum': legalImpressumAR,
'legal-widerruf': legalWiderrufAR,
'legal-batterie': legalBatterieAR
},
bg: {
translation: translationBG,
'legal-agb': legalAgbBG,
'legal-datenschutz': legalDatenschutzBG,
'legal-impressum': legalImpressumBG,
'legal-widerruf': legalWiderrufBG,
'legal-batterie': legalBatterieBG
},
cs: {
translation: translationCS,
'legal-agb': legalAgbCS,
'legal-datenschutz': legalDatenschutzCS,
'legal-impressum': legalImpressumCS,
'legal-widerruf': legalWiderrufCS,
'legal-batterie': legalBatterieCS
},
el: {
translation: translationEL,
'legal-agb': legalAgbEL,
'legal-datenschutz': legalDatenschutzEL,
'legal-impressum': legalImpressumEL,
'legal-widerruf': legalWiderrufEL,
'legal-batterie': legalBatterieEL
},
es: {
translation: translationES,
'legal-agb': legalAgbES,
'legal-datenschutz': legalDatenschutzES,
'legal-impressum': legalImpressumES,
'legal-widerruf': legalWiderrufES,
'legal-batterie': legalBatterieES
},
fr: {
translation: translationFR,
'legal-agb': legalAgbFR,
'legal-datenschutz': legalDatenschutzFR,
'legal-impressum': legalImpressumFR,
'legal-widerruf': legalWiderrufFR,
'legal-batterie': legalBatterieFR
},
hr: {
translation: translationHR,
'legal-agb': legalAgbHR,
'legal-datenschutz': legalDatenschutzHR,
'legal-impressum': legalImpressumHR,
'legal-widerruf': legalWiderrufHR,
'legal-batterie': legalBatterieHR
},
hu: {
translation: translationHU,
'legal-agb': legalAgbHU,
'legal-datenschutz': legalDatenschutzHU,
'legal-impressum': legalImpressumHU,
'legal-widerruf': legalWiderrufHU,
'legal-batterie': legalBatterieHU
},
it: {
translation: translationIT,
'legal-agb': legalAgbIT,
'legal-datenschutz': legalDatenschutzIT,
'legal-impressum': legalImpressumIT,
'legal-widerruf': legalWiderrufIT,
'legal-batterie': legalBatterieIT
},
pl: {
translation: translationPL,
'legal-agb': legalAgbPL,
'legal-datenschutz': legalDatenschutzPL,
'legal-impressum': legalImpressumPL,
'legal-widerruf': legalWiderrufPL,
'legal-batterie': legalBatteriePL
},
ro: {
translation: translationRO,
'legal-agb': legalAgbRO,
'legal-datenschutz': legalDatenschutzRO,
'legal-impressum': legalImpressumRO,
'legal-widerruf': legalWiderrufRO,
'legal-batterie': legalBatterieRO
},
ru: {
translation: translationRU,
'legal-agb': legalAgbRU,
'legal-datenschutz': legalDatenschutzRU,
'legal-impressum': legalImpressumRU,
'legal-widerruf': legalWiderrufRU,
'legal-batterie': legalBatterieRU
},
sk: {
translation: translationSK,
'legal-agb': legalAgbSK,
'legal-datenschutz': legalDatenschutzSK,
'legal-impressum': legalImpressumSK,
'legal-widerruf': legalWiderrufSK,
'legal-batterie': legalBatterieSK
},
sl: {
translation: translationSL,
'legal-agb': legalAgbSL,
'legal-datenschutz': legalDatenschutzSL,
'legal-impressum': legalImpressumSL,
'legal-widerruf': legalWiderrufSL,
'legal-batterie': legalBatterieSL
},
sr: {
translation: translationSR,
'legal-agb': legalAgbSR,
'legal-datenschutz': legalDatenschutzSR,
'legal-impressum': legalImpressumSR,
'legal-widerruf': legalWiderrufSR,
'legal-batterie': legalBatterieSR
},
sv: {
translation: translationSV,
'legal-agb': legalAgbSV,
'legal-datenschutz': legalDatenschutzSV,
'legal-impressum': legalImpressumSV,
'legal-widerruf': legalWiderrufSV,
'legal-batterie': legalBatterieSV
},
tr: {
translation: translationTR,
'legal-agb': legalAgbTR,
'legal-datenschutz': legalDatenschutzTR,
'legal-impressum': legalImpressumTR,
'legal-widerruf': legalWiderrufTR,
'legal-batterie': legalBatterieTR
},
uk: {
translation: translationUK,
'legal-agb': legalAgbUK,
'legal-datenschutz': legalDatenschutzUK,
'legal-impressum': legalImpressumUK,
'legal-widerruf': legalWiderrufUK,
'legal-batterie': legalBatterieUK
},
zh: {
translation: translationZH,
'legal-agb': legalAgbZH,
'legal-datenschutz': legalDatenschutzZH,
'legal-impressum': legalImpressumZH,
'legal-widerruf': legalWiderrufZH,
'legal-batterie': legalBatterieZH
} }
}; };
i18n i18n
.use(LanguageDetector) .use({
type: 'languageDetector',
async: false,
detect: customDetector.lookup,
init() {},
cacheUserLanguage: customDetector.cacheUserLanguage
})
.use(initReactI18next) .use(initReactI18next)
.init({ .init({
resources, resources,
fallbackLng: 'de', // German as fallback since it's your primary language lng: 'de', // Force German as default
fallbackLng: 'de',
debug: process.env.NODE_ENV === 'development', debug: process.env.NODE_ENV === 'development',
// Language detection options // Disable automatic language detection from browser
detection: { detection: {
// Order of language detection methods order: ['customDetector'],
order: ['localStorage', 'navigator', 'htmlTag'], caches: ['localStorage', 'sessionStorage']
// Cache the language selection
caches: ['localStorage'],
// Check for language in localStorage
lookupLocalStorage: 'i18nextLng'
}, },
interpolation: { interpolation: {
@@ -372,10 +165,57 @@ i18n
// React-specific options // React-specific options
react: { react: {
useSuspense: false // Disable suspense for class components compatibility useSuspense: false // Disable suspense for class components compatibility
} },
// Load missing keys as fallback
saveMissing: process.env.NODE_ENV === 'development'
}); });
// Export withI18n and other utilities for easy access // Override changeLanguage to load languages on demand
export { withI18n, withTranslation, withLanguage, LanguageContext, LanguageProvider } from './withTranslation.js'; const originalChangeLanguage = i18n.changeLanguage.bind(i18n);
i18n.changeLanguage = async (language) => {
if (language !== 'de' && !languageCache.has(language)) {
try {
await loadLanguage(language);
} catch {
console.error(`Failed to load language ${language}, falling back to German`);
language = 'de';
}
}
return originalChangeLanguage(language);
};
// Check session storage on initialization and load language if needed
const initializeLanguage = async () => {
// Only run in browser environment
if (typeof window === 'undefined' || typeof sessionStorage === 'undefined') {
return;
}
try {
const sessionLang = sessionStorage.getItem('i18nextLng');
if (sessionLang && sessionLang !== 'de' && !languageCache.has(sessionLang)) {
console.log(`🔄 Restoring session language: ${sessionLang}`);
await loadLanguage(sessionLang);
await i18n.changeLanguage(sessionLang);
}
} catch {
console.warn('Failed to restore session language');
}
};
// Initialize language on DOM ready (browser only)
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializeLanguage);
} else {
initializeLanguage();
}
}
export default i18n; export default i18n;
export { loadLanguage };
// Re-export withI18n and other utilities for compatibility
export { withI18n, withTranslation, withLanguage, LanguageContext, LanguageProvider } from './withTranslation.js';

View File

@@ -1,5 +1,6 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { withTranslation as reactI18nextWithTranslation } from 'react-i18next'; import { withTranslation as reactI18nextWithTranslation } from 'react-i18next';
import { loadLanguage } from './index.js';
// HOC to provide translation functions to class components // HOC to provide translation functions to class components
export const withTranslation = (namespaces = 'translation') => (WrappedComponent) => { export const withTranslation = (namespaces = 'translation') => (WrappedComponent) => {
@@ -10,7 +11,7 @@ export const withTranslation = (namespaces = 'translation') => (WrappedComponent
export const LanguageContext = React.createContext({ export const LanguageContext = React.createContext({
currentLanguage: 'de', currentLanguage: 'de',
changeLanguage: () => {}, changeLanguage: () => {},
availableLanguages: ['ar', 'bg', 'cs', 'de', 'el', 'en', 'es', 'fr', 'hr', 'hu', 'it', 'pl', 'ro', 'ru', 'sk', 'sl', 'sr', 'sv', 'tr', 'uk', 'zh'] availableLanguages: ['de'] // Start with only German
}); });
// Provider component for language management // Provider component for language management
@@ -18,14 +19,16 @@ export class LanguageProvider extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
// Get initial language from i18n instance // Always start with German
const currentLanguage = props.i18n?.language || 'de'; const currentLanguage = 'de';
this.state = { this.state = {
currentLanguage, currentLanguage,
availableLanguages: ['ar', 'bg', 'cs', 'de', 'el', 'en', 'es', 'fr', 'hr', 'hu', 'it', 'pl', 'ro', 'ru', 'sk', 'sl', 'sr', 'sv', 'tr', 'uk', 'zh'], availableLanguages: ['de'], // Start with only German visible
demoMode: false, // Enable demo mode allLanguages: ['ar', 'bg', 'cs', 'de', 'el', 'en', 'es', 'fr', 'hr', 'hu', 'it', 'pl', 'ro', 'ru', 'sk', 'sl', 'sr', 'sv', 'tr', 'uk', 'zh'],
currentLanguageIndex: 0 demoMode: false,
currentLanguageIndex: 0,
loadingLanguages: new Set()
}; };
this.demoInterval = null; this.demoInterval = null;
@@ -124,14 +127,47 @@ export class LanguageProvider extends Component {
} }
}; };
changeLanguage = (language) => { changeLanguage = async (language) => {
if (this.props.i18n && this.state.availableLanguages.includes(language)) { if (this.props.i18n && this.state.allLanguages.includes(language)) {
// Stop demo mode if user manually changes language // Stop demo mode if user manually changes language
if (this.state.demoMode) { if (this.state.demoMode) {
this.stopDemo(); this.stopDemo();
} }
this.props.i18n.changeLanguage(language); // If language is not German and not already available, load it
if (language !== 'de' && !this.state.availableLanguages.includes(language)) {
// Check if already loading
if (this.state.loadingLanguages.has(language)) {
return; // Already loading
}
// Mark as loading
this.setState(prevState => ({
loadingLanguages: new Set([...prevState.loadingLanguages, language])
}));
try {
console.log(`🌍 Loading language: ${language}`);
await loadLanguage(language);
// Add to available languages after successful load
this.setState(prevState => ({
availableLanguages: [...prevState.availableLanguages, language],
loadingLanguages: new Set([...prevState.loadingLanguages].filter(l => l !== language))
}));
console.log(`✅ Language ${language} now available`);
} catch (error) {
console.error(`❌ Failed to load language ${language}:`, error);
this.setState(prevState => ({
loadingLanguages: new Set([...prevState.loadingLanguages].filter(l => l !== language))
}));
return; // Don't change language if loading failed
}
}
// Change the language
await this.props.i18n.changeLanguage(language);
} }
}; };
@@ -140,6 +176,8 @@ export class LanguageProvider extends Component {
currentLanguage: this.state.currentLanguage, currentLanguage: this.state.currentLanguage,
changeLanguage: this.changeLanguage, changeLanguage: this.changeLanguage,
availableLanguages: this.state.availableLanguages, availableLanguages: this.state.availableLanguages,
allLanguages: this.state.allLanguages,
loadingLanguages: this.state.loadingLanguages,
demoMode: this.state.demoMode, demoMode: this.state.demoMode,
stopDemo: this.stopDemo stopDemo: this.stopDemo
}; };