Files
TenerifeProp/public/js/i18n.js
TenerifeProp Dev c1867fe074 feat: implement complete backend with Bun + Hono + SQLite
- Create SQLite database schema with all tables
- Implement REST API endpoints for properties, leads, testimonials, FAQ, services
- Add seed data with sample properties, testimonials, FAQ
- Create Docker configuration for deployment
- Add i18n system for translations
- Add API client for frontend integration
- Create Technical Documentation (TZ.md)
- Add detailed README with deployment instructions

🚀 Project is now fully functional:
- API: http://localhost:8080/api/*
- Properties CRUD with filtering
- Lead management
- Settings, Testimonials, FAQ, Services APIs
- SQLite database with seed data
2026-04-04 22:16:06 +01:00

96 lines
2.5 KiB
JavaScript

// TenerifeProp - Internationalization System
class I18n {
constructor() {
this.lang = localStorage.getItem('lang') || 'es';
this.translations = {};
this.listeners = [];
}
async init() {
await this.loadTranslations('es');
await this.loadTranslations('ru');
this.updateElements();
this.updateLangButtons();
}
async loadTranslations(lang) {
try {
// Translations are embedded in window.translations
this.translations[lang] = window.translations?.[lang] || {};
} catch (e) {
console.error(`Failed to load translations for ${lang}`, e);
}
}
setLanguage(lang) {
if (this.lang !== lang) {
this.lang = lang;
localStorage.setItem('lang', lang);
this.updateElements();
this.updateLangButtons();
this.listeners.forEach(cb => cb(lang));
}
}
t(key, fallback = '') {
const keys = key.split('.');
let value = this.translations[this.lang];
for (const k of keys) {
if (value && typeof value === 'object') {
value = value[k];
} else {
return fallback || key;
}
}
return value || fallback || key;
}
updateElements() {
document.querySelectorAll('[data-i18n]').forEach(el => {
const key = el.getAttribute('data-i18n');
const translation = this.t(key);
if (translation && translation !== key) {
el.textContent = translation;
}
});
document.querySelectorAll('[data-i18n-placeholder]').forEach(el => {
const key = el.getAttribute('data-i18n-placeholder');
const translation = this.t(key);
if (translation && translation !== key) {
el.setAttribute('placeholder', translation);
}
});
document.querySelectorAll('[data-i18n-title]').forEach(el => {
const key = el.getAttribute('data-i18n-title');
const translation = this.t(key);
if (translation && translation !== key) {
el.setAttribute('title', translation);
}
});
// Update HTML lang attribute
document.documentElement.lang = this.lang;
}
updateLangButtons() {
document.querySelectorAll('.lang-btn, .lang-switcher button').forEach(btn => {
const btnLang = btn.getAttribute('data-lang') || btn.textContent.toLowerCase();
btn.classList.toggle('active', btnLang === this.lang);
});
}
onLanguageChange(callback) {
this.listeners.push(callback);
}
}
// Initialize i18n
const i18n = new I18n();
window.i18n = i18n;
// Embedded translations (will be loaded from backend)
window.translations = window.translations || {};