const translations = window.translations; const languageLocales = { vi: 'vi_VN', ru: 'ru_RU', en: 'en_US', zh: 'zh_CN', de: 'de_DE', fr: 'fr_FR' }; let currentLang = 'vi'; let currentWeatherCondition = 'weather_loading'; function getWeatherPresentation(code) { if (code === 0) return { key: 'weather_clear', icon: 'fa-sun', color: 'text-amber-500' }; if (code === 1) return { key: 'weather_mainly_clear', icon: 'fa-cloud-sun', color: 'text-amber-500' }; if (code === 2) return { key: 'weather_partly_cloudy', icon: 'fa-cloud-sun', color: 'text-amber-500' }; if (code === 3) return { key: 'weather_overcast', icon: 'fa-cloud', color: 'text-gray-500' }; if ([45, 48].includes(code)) return { key: 'weather_fog', icon: 'fa-smog', color: 'text-gray-500' }; if ([51, 53, 55, 56, 57].includes(code)) return { key: 'weather_drizzle', icon: 'fa-cloud-rain', color: 'text-sky-500' }; if ([61, 63, 65, 66, 67].includes(code)) return { key: 'weather_rain', icon: 'fa-cloud-rain', color: 'text-sky-600' }; if ([71, 73, 75, 77].includes(code)) return { key: 'weather_snow', icon: 'fa-snowflake', color: 'text-sky-500' }; if ([80, 81, 82, 85, 86].includes(code)) return { key: 'weather_showers', icon: 'fa-cloud-showers-heavy', color: 'text-sky-600' }; if ([95, 96, 99].includes(code)) return { key: 'weather_thunderstorm', icon: 'fa-cloud-bolt', color: 'text-indigo-500' }; return { key: 'weather_partly_cloudy', icon: 'fa-cloud-sun', color: 'text-amber-500' }; } function renderWeatherCondition() { const condition = document.getElementById('weather-condition'); if (condition) condition.textContent = translations[currentLang][currentWeatherCondition] || translations.en[currentWeatherCondition]; } async function loadCurrentWeather() { const temperature = document.getElementById('weather-temperature'); const icon = document.getElementById('weather-icon'); try { const response = await fetch('https://api.open-meteo.com/v1/forecast?latitude=12.2388&longitude=109.1967¤t=temperature_2m,weather_code&timezone=Asia%2FHo_Chi_Minh'); if (!response.ok) throw new Error('Weather request failed'); const data = await response.json(); const presentation = getWeatherPresentation(data.current.weather_code); temperature.textContent = `${Math.round(data.current.temperature_2m)}°C`; icon.className = `fa-solid ${presentation.icon} text-2xl ${presentation.color}`; currentWeatherCondition = presentation.key; } catch { temperature.textContent = '--°C'; icon.className = 'fa-solid fa-cloud text-2xl text-gray-400'; currentWeatherCondition = 'weather_unavailable'; } renderWeatherCondition(); } function getPreferredLanguage() { const supported = Object.keys(translations); const preferences = navigator.languages?.length ? navigator.languages : [navigator.language]; for (const locale of preferences) { const language = locale.toLowerCase().split(/[-_]/)[0]; if (supported.includes(language)) return language; } return 'vi'; } function getRequestedLanguage() { const requested = new URLSearchParams(window.location.search).get('lang'); return translations[requested] ? requested : null; } function setLanguage(lang) { if (!translations[lang]) lang = 'vi'; currentLang = lang; document.querySelectorAll('[data-i18n]').forEach(el => { const key = el.getAttribute('data-i18n'); if (translations[lang] && translations[lang][key]) { el.textContent = translations[lang][key]; } }); // Reset language button styles const langs = ['vi', 'ru', 'en', 'zh', 'de', 'fr']; langs.forEach(l => { const btn = document.getElementById(`btn-${l}`); if (btn) { if (l === lang) { btn.className = "px-2.5 py-1.5 font-bold rounded-lg transition bg-white text-brand-600 shadow-sm"; } else { btn.className = "px-2.5 py-1.5 font-bold rounded-lg transition text-gray-600 hover:text-brand-600"; } } }); document.documentElement.lang = lang; const languageUrl = new URL(window.location.href); languageUrl.searchParams.set('lang', lang); history.replaceState(null, '', `${languageUrl.pathname}${languageUrl.search}${languageUrl.hash}`); const canonicalUrl = new URL(`/?lang=${lang}`, window.location.origin).href; document.getElementById('canonical-url').href = canonicalUrl; document.getElementById('meta-description').content = translations[lang].meta_description; document.getElementById('og-title').content = translations[lang].page_title; document.getElementById('og-description').content = translations[lang].meta_description; document.getElementById('og-url').content = canonicalUrl; document.getElementById('og-locale').content = languageLocales[lang]; renderWeatherCondition(); } function toggleMobileMenu() { const menu = document.getElementById('mobile-menu'); menu.classList.toggle('hidden'); document.querySelector('[aria-controls="mobile-menu"]').setAttribute('aria-expanded', !menu.classList.contains('hidden')); } function filterAttractions(category, event) { document.querySelectorAll('.filter-btn').forEach(btn => { btn.className = "filter-btn px-5 py-2 rounded-xl text-sm font-bold bg-white text-gray-600 hover:bg-gray-100 shadow-sm"; }); event.currentTarget.className = "filter-btn active px-5 py-2 rounded-xl text-sm font-bold bg-brand-500 text-white shadow"; document.querySelectorAll('.attraction-card').forEach(card => { if (category === 'all' || card.getAttribute('data-category') === category) { card.style.display = 'flex'; } else { card.style.display = 'none'; } }); } async function handleBooking(event) { event.preventDefault(); const form = event.currentTarget; const submitButton = form.querySelector('[type="submit"]'); const status = document.getElementById('form-status'); status.classList.add('hidden'); submitButton.disabled = true; try { const response = await fetch(form.action, { method: form.method, body: new FormData(form), headers: { Accept: 'application/json' } }); if (!response.ok) throw new Error('Form submission failed'); form.reset(); document.getElementById('success-modal').classList.remove('hidden'); } catch { status.classList.remove('hidden'); } finally { submitButton.disabled = false; } } function closeModal() { document.getElementById('success-modal').classList.add('hidden'); } setLanguage(getRequestedLanguage() || getPreferredLanguage()); loadCurrentWeather(); setInterval(loadCurrentWeather, 30 * 60 * 1000);