// Translation Manager class TranslationManager { constructor() { this.currentLanguage = 'en'; // Will be set during initialization this.translations = {}; this.supportedLanguages = { 'en': { name: 'English', flag: '🇬🇧' }, 'es': { name: 'Español', flag: '🇪🇸' }, 'sv': { name: 'Svenska', flag: '🇸🇪' }, 'el': { name: 'Ελληνικά', flag: '🇬🇷' } }; // Country to language mapping this.countryToLanguage = { // Spanish-speaking countries 'ES': 'es', 'MX': 'es', 'AR': 'es', 'CO': 'es', 'PE': 'es', 'VE': 'es', 'CL': 'es', 'EC': 'es', 'BO': 'es', 'PY': 'es', 'UY': 'es', 'CU': 'es', 'DO': 'es', 'GT': 'es', 'HN': 'es', 'SV': 'es', 'NI': 'es', 'CR': 'es', 'PA': 'es', 'BZ': 'es', 'EQ': 'es', // Swedish-speaking countries 'SE': 'sv', 'FI': 'sv', 'AX': 'sv', // Greek-speaking countries 'GR': 'el', 'CY': 'el', // Default to English for all others }; } // Detect language with geolocation fallback async detectLanguageWithGeolocation() { // Step 1: Check localStorage for saved preference const savedLanguage = localStorage.getItem('preferredLanguage'); if (savedLanguage && this.supportedLanguages[savedLanguage]) { console.log('Using saved language preference:', savedLanguage); return savedLanguage; } // Step 2: Try browser language detection const browserLang = this.detectBrowserLanguage(); if (browserLang !== 'en') { console.log('Using browser language:', browserLang); return browserLang; } // Step 3: Try geolocation API to get country and map to language try { const countryCode = await this.getCountryFromGeolocation(); if (countryCode) { const language = this.countryToLanguage[countryCode] || 'en'; console.log('Using geolocation-based language:', language, 'from country:', countryCode); return language; } } catch (error) { console.warn('Geolocation failed, continuing with fallback:', error.message); } // Step 4: Fallback to English console.log('Falling back to English'); return 'en'; } // Detect browser language detectBrowserLanguage() { const browserLang = navigator.language || navigator.userLanguage; const langCode = browserLang.split('-')[0]; // Check if the detected language is supported if (this.supportedLanguages[langCode]) { return langCode; } // Return 'en' if not supported (will trigger geolocation) return 'en'; } // Get country code from geolocation API async getCountryFromGeolocation() { const timeout = 5000; // 5 second timeout try { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeout); // Try ip-api.com (free, no auth required) const response = await fetch('https://ipapi.co/json/', { signal: controller.signal, headers: { 'Accept': 'application/json' } }); clearTimeout(timeoutId); if (!response.ok) { throw new Error(`API returned status ${response.status}`); } const data = await response.json(); const countryCode = data.country_code; if (countryCode && typeof countryCode === 'string') { console.log('Geolocation API returned country:', countryCode); return countryCode; } throw new Error('No country code in response'); } catch (error) { if (error.name === 'AbortError') { console.warn('Geolocation API request timed out'); } else { console.warn('Geolocation API error:', error.message); } return null; } } // Load translation file async loadTranslation(language) { try { const response = await fetch(`translations/${language}.json`); if (!response.ok) { throw new Error(`Failed to load ${language} translation`); } this.translations[language] = await response.json(); this.currentLanguage = language; localStorage.setItem('preferredLanguage', language); return true; } catch (error) { console.error('Error loading translation:', error); return false; } } // Get translated string t(key) { if (this.translations[this.currentLanguage] && this.translations[this.currentLanguage][key]) { return this.translations[this.currentLanguage][key]; } // Fallback to English if key not found if (this.translations['en'] && this.translations['en'][key]) { return this.translations['en'][key]; } // Return key if no translation found return key; } // Get current language getCurrentLanguage() { return this.currentLanguage; } // Get all supported languages getSupportedLanguages() { return this.supportedLanguages; } // Set language setLanguage(language) { if (this.supportedLanguages[language]) { this.currentLanguage = language; localStorage.setItem('preferredLanguage', language); return true; } return false; } // Initialize translations async initialize() { // Detect language using geolocation fallback chain this.currentLanguage = await this.detectLanguageWithGeolocation(); // Load all supported language files const loadPromises = Object.keys(this.supportedLanguages).map(lang => this.loadTranslation(lang) ); await Promise.all(loadPromises); // Ensure current language is set correctly if (!this.translations[this.currentLanguage]) { this.currentLanguage = 'en'; } } } // Create global instance const i18n = new TranslationManager();