(function () { 'use strict'; function detectLanguage() { var stored = localStorage.getItem('i18n-lang'); if (stored) return stored; var browserLang = navigator.language || navigator.userLanguage || ''; var short = browserLang.split('-')[0].toLowerCase(); if (short === 'en') return 'en'; return 'de'; } function interpolate(str, options) { if (!str || !options) return str; return str.replace(/\{\{(\w+)\}\}/g, function (match, key) { return options[key] !== undefined ? options[key] : match; }); } function translatePage() { var elements = document.querySelectorAll('[data-i18n]'); elements.forEach(function (el) { var rawKey = el.getAttribute('data-i18n'); if (!rawKey) return; var optionsAttr = el.getAttribute('data-i18n-options'); var options = optionsAttr ? JSON.parse(optionsAttr) : null; // Handle attribute prefixes like [value], [placeholder] var attrMatch = rawKey.match(/^\[(\w+)\](.+)$/); if (attrMatch && attrMatch[1] !== 'html') { var attr = attrMatch[1]; var tKey = attrMatch[2]; var val = i18next.t(tKey, options || {}); val = interpolate(val, options); el.setAttribute(attr, val); return; } // Handle [html] prefix for innerHTML var isHtml = false; var lookupKey = rawKey; if (rawKey.indexOf('[html]') === 0) { isHtml = true; lookupKey = rawKey.substring(6); } var translation = i18next.t(lookupKey, options || {}); translation = interpolate(translation, options); if (isHtml) { el.innerHTML = translation; } else { el.textContent = translation; } }); // Update document lang attribute document.documentElement.lang = i18next.language; // Update document title var pageKey = detectPageKey(); if (pageKey) { var titleTranslation = i18next.t(pageKey + '.page_title'); if (titleTranslation && titleTranslation !== pageKey + '.page_title') { document.title = titleTranslation; } } // Update active state on language switcher updateSwitcherActive(); } function detectPageKey() { var path = window.location.pathname; var filename = path.substring(path.lastIndexOf('/') + 1).replace('.html', ''); if (!filename || filename === '' || filename === 'index') return 'index'; return filename; } function updateSwitcherActive() { var lang = i18next.language; var options = document.querySelectorAll('.lang-option'); options.forEach(function (el) { if (el.getAttribute('data-lang') === lang) { el.classList.add('active'); el.setAttribute('aria-current', 'true'); } else { el.classList.remove('active'); el.removeAttribute('aria-current'); } }); } function initSwitcher() { document.addEventListener('click', function (e) { var target = e.target.closest('.lang-option'); if (!target) return; e.preventDefault(); var lang = target.getAttribute('data-lang'); if (lang && lang !== i18next.language) { i18next.changeLanguage(lang, function () { localStorage.setItem('i18n-lang', lang); translatePage(); }); } }); } var lng = detectLanguage(); i18next .use(i18nextHttpBackend) .init({ lng: lng, fallbackLng: 'de', backend: { loadPath: './locales/{{lng}}.json' }, interpolation: { escapeValue: false } }, function (err) { if (err) console.error('i18next init error:', err); translatePage(); initSwitcher(); // Signal that i18n is ready (used by preloader) window.i18nReady = true; document.dispatchEvent(new CustomEvent('i18nReady')); }); })();