- 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
96 lines
2.5 KiB
JavaScript
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 || {}; |