const I18n = { currentLang: 'ru', translations: {}, async init() { const savedLang = localStorage.getItem('lang') || 'ru'; await this.setLang(savedLang); }, async setLang(lang) { try { const res = await fetch(`/api/translations/${lang}`); if (!res.ok) throw new Error('Failed to load translations'); this.translations = await res.json(); this.currentLang = lang; localStorage.setItem('lang', lang); this.updateUI(); this.updateNavLabels(); } catch (err) { console.error('I18n error:', err); if (lang !== 'ru') { await this.setLang('ru'); } } }, t(key, replacements = {}) { let text = this.translations[key] || key; Object.entries(replacements).forEach(([k, v]) => { text = text.replace(`{${k}}`, v); }); return text; }, updateUI() { document.querySelectorAll('[data-i18n]').forEach(el => { const key = el.getAttribute('data-i18n'); const attr = el.getAttribute('data-i18n-attr'); const text = this.t(key); if (attr) { el.setAttribute(attr, text); } else { el.textContent = text; } }); document.querySelectorAll('[data-i18n-placeholder]').forEach(el => { const key = el.getAttribute('data-i18n-placeholder'); el.placeholder = this.t(key); }); }, updateNavLabels() { const langBtns = document.querySelectorAll('.lang-btn'); langBtns.forEach(btn => { btn.classList.toggle('active', btn.dataset.lang === this.currentLang); }); }, getInitials(name) { if (!name) return '?'; const parts = name.trim().split(/\s+/); if (parts.length >= 2) { return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase(); } return name.substring(0, 2).toUpperCase(); }, formatDate(dateStr) { const date = new Date(dateStr); const months = this.currentLang === 'ru' ? ['Января', 'Февраля', 'Марта', 'Апреля', 'Мая', 'Июня', 'Июля', 'Августа', 'Сентября', 'Октября', 'Ноября', 'Декабря'] : ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; return `${months[date.getMonth()]} ${date.getFullYear()}`; }, renderStars(count, max = 5) { let html = ''; for (let i = 1; i <= max; i++) { if (count >= i) { html += ''; } else if (count >= i - 0.5) { html += ''; } else { html += ''; } } return html; }, renderStarsStatic(count) { let html = ''; const fullStars = Math.floor(count); const hasHalf = count % 1 >= 0.5; for (let i = 0; i < 5; i++) { if (i < fullStars) { html += ''; } else if (i === fullStars && hasHalf) { html += ''; } else { html += ''; } } return html; } }; window.I18n = I18n;