/** * Automatic Language Detection System * Detects user's country and sets appropriate language */ class LanguageDetector { constructor() { this.primaryAPI = 'https://ipinfo.io/json'; this.fallbackAPI = 'https://ipapi.co/json'; this.cookieName = 'voucher_magnet_language_choice'; this.overlayShown = false; this.init(); } async init() { // Check if we should show the English overlay (after server redirect) if (this.getCookie('show_english_overlay')) { // Remove the temporary cookie this.deleteCookie('show_english_overlay'); // Check if user already made a language choice const savedChoice = this.getCookie(this.cookieName); if (!savedChoice) { // Get current language from URL const urlParams = new URLSearchParams(window.location.search); const currentLang = urlParams.get('lang') || 'en'; // Show overlay offering English if not already on English if (currentLang !== 'en') { this.showEnglishSwitchOverlay(currentLang); } } return; } // Check if user already made a language choice const savedChoice = this.getCookie(this.cookieName); if (savedChoice) { // Check if we're already on the correct language const urlParams = new URLSearchParams(window.location.search); const currentLang = urlParams.get('lang') || 'en'; if (savedChoice !== currentLang) { // Redirect to saved preference console.log('Redirecting to saved language preference:', savedChoice); this.redirectToLanguage(savedChoice); return; } console.log('User language preference applied:', savedChoice); return; } // No client-side detection needed - server handles initial redirect console.log('Language detection handled server-side'); } async detectAndSetLanguage() { let countryCode = null; let detectedLanguage = 'en'; // fallback try { // Try primary API first (IPinfo Lite) countryCode = await this.getCountryFromIP(this.primaryAPI); } catch (error) { console.warn('Primary geolocation API failed, trying fallback...'); try { // Try fallback API countryCode = await this.getCountryFromIP(this.fallbackAPI); } catch (fallbackError) { console.warn('Fallback geolocation API also failed:', fallbackError); return; // Give up on auto-detection } } if (countryCode) { // Map country to language detectedLanguage = this.mapCountryToLanguage(countryCode); console.log(`Detected country: ${countryCode}, mapped to language: ${detectedLanguage}`); // Get current language from URL or default const currentLang = new URLSearchParams(window.location.search).get('lang') || 'en'; // Automatic redirect to detected language, then offer English switch if (detectedLanguage !== currentLang) { // Always redirect to detected language first const newUrl = this.updateURLParameter(window.location.href, 'lang', detectedLanguage); window.location.href = newUrl; return; // Don't show overlay yet, wait for redirect } else if (detectedLanguage !== 'en' && currentLang === detectedLanguage) { // User is on their detected language, offer English switch this.showEnglishSwitchOverlay(detectedLanguage); } } } async getCountryFromIP(apiUrl) { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 5000); try { const response = await fetch(apiUrl, { method: 'GET', headers: { 'Accept': 'application/json' }, signal: controller.signal }); clearTimeout(timeoutId); if (!response.ok) { throw new Error(`API request failed: ${response.status}`); } const data = await response.json(); // Handle different API response formats if (data.country) { return data.country; // IPinfo format } else if (data.countryCode) { return data.countryCode; // IP-API format } else if (data.country_code) { return data.country_code; // ipapi.co format } throw new Error('Country code not found in API response'); } catch (error) { clearTimeout(timeoutId); throw error; } } mapCountryToLanguage(countryCode) { const countryToLangMap = { // Major European Countries 'DE': 'de', 'AT': 'de', 'CH': 'de', // German 'FR': 'fr', 'BE': 'fr', 'MC': 'fr', // French 'IT': 'it', 'SM': 'it', 'VA': 'it', // Italian 'ES': 'es', 'AD': 'es', // Spanish 'NL': 'nl', // Dutch 'CZ': 'cz', // Czech 'SK': 'sk', // Slovak 'PL': 'pl', // Polish 'RU': 'ru', 'BY': 'ru', 'KZ': 'ru', // Russian 'PT': 'pt', 'BR': 'pt', // Portuguese // Asian Countries 'JP': 'jp', // Japanese 'IN': 'hi', // Hindi 'PK': 'ur', 'BD': 'ur', // Urdu 'MY': 'ms', 'BN': 'ms', // Malay // Middle East & North Africa 'SA': 'ar', 'AE': 'ar', 'EG': 'ar', 'MA': 'ar', 'TN': 'ar', 'DZ': 'ar', 'LB': 'ar', 'SY': 'ar', 'IQ': 'ar', 'JO': 'ar', 'QA': 'ar', 'KW': 'ar', 'BH': 'ar', 'OM': 'ar', 'YE': 'ar', 'LY': 'ar' }; return countryToLangMap[countryCode] || 'en'; } showLanguageSwitchOverlay(detectedLanguage, currentLanguage, redirectUrl) { if (this.overlayShown) return; this.overlayShown = true; const languageNames = { 'de': 'Deutsch', 'fr': 'Français', 'it': 'Italiano', 'es': 'Español', 'nl': 'Nederlands', 'cz': 'Čeština', 'sk': 'Slovenčina', 'pl': 'Polski', 'ru': 'Русский', 'jp': '日本語', 'pt': 'Português', 'hi': 'हिन्दी', 'ur': 'اردو', 'ms': 'Bahasa Melayu', 'ar': 'العربية' }; const overlay = document.createElement('div'); overlay.id = 'language-overlay'; overlay.innerHTML = `
`; document.body.appendChild(overlay); // Handle user choice document.getElementById('switch-detected').addEventListener('click', () => { this.saveLanguageChoice(detectedLanguage); overlay.remove(); window.location.href = redirectUrl; }); document.getElementById('stay-current').addEventListener('click', () => { this.saveLanguageChoice(currentLanguage); overlay.remove(); }); } showLocalLanguageOverlay(detectedLanguage, redirectUrl) { if (this.overlayShown) return; this.overlayShown = true; const languageNames = { 'de': 'Deutsch', 'fr': 'Français', 'it': 'Italiano', 'es': 'Español', 'nl': 'Nederlands', 'cz': 'Čeština', 'sk': 'Slovenčina', 'pl': 'Polski', 'ru': 'Русский', 'jp': '日本語', 'pt': 'Português', 'hi': 'हिन्दी', 'ur': 'اردو', 'ms': 'Bahasa Melayu', 'ar': 'العربية' }; const overlay = document.createElement('div'); overlay.id = 'language-overlay'; overlay.innerHTML = ` `; document.body.appendChild(overlay); // Handle user choice document.getElementById('switch-local').addEventListener('click', () => { this.saveLanguageChoice(detectedLanguage); overlay.remove(); window.location.href = redirectUrl; }); document.getElementById('stay-english').addEventListener('click', () => { this.saveLanguageChoice('en'); overlay.remove(); }); } showEnglishSwitchOverlay(currentLanguage) { if (this.overlayShown) return; this.overlayShown = true; const languageNames = { 'de': 'Deutsch', 'fr': 'Français', 'it': 'Italiano', 'es': 'Español', 'nl': 'Nederlands', 'cz': 'Čeština', 'sk': 'Slovenčina', 'pl': 'Polski', 'ru': 'Русский', 'jp': '日本語', 'pt': 'Português', 'hi': 'हिन्दी', 'ur': 'اردو', 'ms': 'Bahasa Melayu', 'ar': 'العربية' }; const overlay = document.createElement('div'); overlay.id = 'language-overlay'; overlay.innerHTML = ` `; document.body.appendChild(overlay); // Handle user choice document.getElementById('switch-english').addEventListener('click', () => { this.saveLanguageChoice('en'); overlay.remove(); const newUrl = this.updateURLParameter(window.location.href, 'lang', 'en'); window.location.href = newUrl; }); document.getElementById('stay-current').addEventListener('click', () => { this.saveLanguageChoice(currentLanguage); overlay.remove(); }); } saveLanguageChoice(language) { this.setCookie(this.cookieName, language, 365); // Save for 1 year console.log('Language choice saved:', language); } updateURLParameter(url, param, paramVal) { let newAdditionalURL = ""; let tempArray = url.split("?"); let baseURL = tempArray[0]; let additionalURL = tempArray[1]; let temp = ""; if (additionalURL) { tempArray = additionalURL.split("&"); for (let i = 0; i < tempArray.length; i++) { if (tempArray[i].split('=')[0] != param) { newAdditionalURL += temp + tempArray[i]; temp = "&"; } } } let newURL = baseURL + "?" + newAdditionalURL + temp + param + "=" + paramVal; return newURL.replace(/[?&]$/, "").replace(/\?&/, "?"); } setCookie(name, value, days) { const expires = new Date(); expires.setTime(expires.getTime() + (days * 24 * 60 * 60 * 1000)); document.cookie = name + '=' + value + ';expires=' + expires.toUTCString() + ';path=/;SameSite=Strict' + (window.location.protocol === 'https:' ? ';Secure' : ''); } getCookie(name) { const nameEQ = name + "="; const ca = document.cookie.split(';'); for (let i = 0; i < ca.length; i++) { let c = ca[i]; while (c.charAt(0) == ' ') c = c.substring(1, c.length); if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length); } return null; } deleteCookie(name) { document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/;'; } } // Initialize when DOM is loaded document.addEventListener('DOMContentLoaded', () => { new LanguageDetector(); });