JerDaSch's picture
language switch should switch between dislayed website language
2e7abca verified
Raw History Blame Contribute Delete
25.4 kB
// Shared JavaScript across all pages
// Initialize the application
document.addEventListener('DOMContentLoaded', function() {
initializeApp();
setupEventListeners();
loadInitialData();
});
// Global state
let appState = {
events: [],
resources: [],
currentLanguage: 'en',
darkMode: true,
translations: {
en: {
nav: {
about: "About",
lessons: "Lessons",
events: "Events",
resources: "Resources",
testimonials: "Testimonials",
gallery: "Gallery",
contact: "Contact"
},
hero: {
title: "Unlock Your Musical Potential",
subtitle: "Professional piano instruction tailored to your unique journey. From classical masterpieces to contemporary hits.",
explore_lessons: "Explore Lessons",
book_trial: "Book Trial Lesson"
},
about: {
title: "About Your Teacher",
content1: "With over 15 years of teaching experience and a Master's degree in Piano Performance, I'm passionate about helping students of all ages discover the joy of music.",
content2: "My teaching philosophy centers on creating a supportive, engaging environment where students can develop both technical skills and musical expression at their own pace.",
specialties: {
classical: "Classical",
jazz: "Jazz",
contemporary: "Contemporary",
music_theory: "Music Theory"
},
lessons: {
title: "Lessons & Services",
subtitle: "Flexible lesson formats designed to fit your schedule and learning preferences"
},
contact: {
title: "Get In Touch",
subtitle: "Ready to start your musical journey? Book a trial lesson today!"
},
form: {
name: "Full Name",
email: "Email Address",
phone: "Phone Number",
message: "Message",
trial_label: "I'm interested in a trial lesson",
send: "Send Message"
}
},
he: {
nav: {
about: "אודות",
lessons: "שיעורים",
events: "אירועים",
resources: "משאבים",
testimonials: "המלצות",
gallery: "גלריה",
contact: "צור קשר"
},
hero: {
title: "שחרר את הפוטנציאל המוזיקלי שלך",
subtitle: "הוראת פסנתר מקצועית המותאמת למסע הייחודי שלך. מיצירות קלאסיות ועד להיטים עכשוויים.",
explore_lessons: "חקור שיעורים",
book_trial: "הזמן שיעור ניסיון"
},
about: {
title: "אודות המורה שלך",
content1: "עם מעל 15 שנות ניסיון בהוראה ותואר שני בביצוע פסנתר, אני נלהב לעזור לתלמידים בכל הגילאים לגלות את השמחה במוזיקה.",
content2: "פילוסופיית ההוראה שלי מתמקדת ביצירת סביבה תומכת ומעוררת עניין בה תלמידים יכולים לפתח מיומנויות טכניות והבעה מוזיקלית בקצב שלהם.",
specialties: {
classical: "קלאסי",
jazz: "ג'אז",
contemporary: "עכשווי",
music_theory: "תורת המוזיקה"
},
lessons: {
title: "שיעורים ושירותים",
subtitle: "פורמטים גמישים של שיעורים שנועדו להתאים ללו\"ז שלך ולהעדפות הלמידה"
},
contact: {
title: "צור קשר",
subtitle: "מוכן להתחיל את המסע המוזיקלי שלך? הזמן שיעור ניסיון היום!"
},
form: {
name: "שם מלא",
email: "כתובת אימייל",
phone: "מספר טלפון",
message: "הודעה",
trial_label: "אני מעוניין/ת בשיעור ניסיון",
send: "שלח הודעה"
}
},
ru: {
nav: {
about: "О нас",
lessons: "Уроки",
events: "События",
resources: "Ресурсы",
testimonials: "Отзывы",
gallery: "Галерея",
contact: "Контакты"
},
hero: {
title: "Раскройте свой музыкальный потенциал",
subtitle: "Профессиональное обучение игре на фортепиано, адаптированное к вашему уникальному пути. От классических шедевров до современных хитов.",
explore_lessons: "Изучить уроки",
book_trial: "Записаться на пробный урок"
},
about: {
title: "О вашем преподавателе",
content1: "С более чем 15-летним опытом преподавания и степенью магистра в области фортепианного исполнения, я увлечен тем, что помогаю ученикам всех возрастов открыть для себя радость музыки.",
content2: "Моя философия преподавания сосредоточена на создании поддерживающей, увлекательной среды, где ученики могут развивать как технические навыки, так и музыкальную выразительность в своем собственном темпе.",
specialties: {
classical: "Классика",
jazz: "Джаз",
contemporary: "Современный",
music_theory: "Теория музыки"
},
lessons: {
title: "Уроки и услуги",
subtitle: "Гибкие форматы уроков, разработанные с учетом вашего расписания и предпочтений в обучении"
},
contact: {
title: "Свяжитесь с нами",
subtitle: "Готовы начать свой музыкальный путь? Запишитесь на пробный урок сегодня!"
},
form: {
name: "Полное имя",
email: "Адрес электронной почты",
phone: "Номер телефона",
message: "Сообщение",
trial_label: "Я заинтересован(а) в пробном уроке",
send: "Отправить сообщение"
}
}
}
};
// Initialize application
function initializeApp() {
console.log('Melodic Keys Academy initialized');
// Initialize language
initializeLanguage();
// Set initial dark mode
document.documentElement.classList.add('dark');
// Load initial data
loadEvents();
loadResources();
// Setup analytics (placeholder)
setupAnalytics();
// Setup privacy consent
setupPrivacyConsent();
}
// Setup event listeners
function setupEventListeners() {
// Contact form submission
const contactForm = document.getElementById('contact-form');
if (contactForm) {
contactForm.addEventListener('submit', handleContactFormSubmit);
}
// Language switcher
const langSwitchers = document.querySelectorAll('.lang-switch');
langSwitchers.forEach(switcher => {
switcher.addEventListener('click', handleLanguageSwitch);
});
}
// Load initial data
function loadInitialData() {
// These would typically come from an API
loadEvents();
loadResources();
}
// Events management
async function loadEvents() {
try {
// Simulate API call
const mockEvents = [
{
id: 1,
title: 'Spring Recital',
date: '2024-03-15',
time: '2:00 PM',
type: 'recital',
location: 'Community Center',
description: 'Annual spring student recital showcasing progress'
},
{
id: 2,
title: 'Music Theory Workshop',
date: '2024-03-22',
time: '4:00 PM',
type: 'workshop',
location: 'Studio',
description: 'Interactive workshop on music fundamentals'
},
{
id: 3,
title: 'Summer Registration Opens',
date: '2024-04-01',
time: 'All Day',
type: 'registration',
location: 'Online',
description: 'Registration for summer lessons and camps'
}
];
appState.events = mockEvents;
renderEvents();
} catch (error) {
console.error('Error loading events:', error);
}
}
function renderEvents() {
const container = document.getElementById('events-container');
if (!container) return;
container.innerHTML = appState.events.map(event => `
<div class="bg-gray-700 rounded-2xl p-6 card-hover">
<div class="flex items-center justify-between mb-4">
<span class="bg-primary-500 text-white px-3 py-1 rounded-full text-sm">
${event.type}
</span>
<h3 class="text-xl font-bold text-white mb-2">${event.title}</h3>
<div class="flex items-center gap-2 text-gray-400 mb-2">
<i data-feather="calendar" class="w-4 h-4"></i>
<span>${formatDate(event.date)} at ${event.time}</span>
</div>
<div class="flex items-center gap-2 text-gray-400 mb-3">
<i data-feather="map-pin" class="w-4 h-4"></i>
<span>${event.location}</span>
</div>
<p class="text-gray-300">${event.description}</p>
</div>
`).join('');
feather.replace();
}
function loadMoreEvents() {
// In a real app, this would load more events from an API
console.log('Loading more events...');
// Show loading state
const container = document.getElementById('events-container');
if (container) {
container.innerHTML += `
<div class="col-span-full text-center py-8">
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-primary-500 mx-auto"></div>
</div>
`;
// Simulate API delay
setTimeout(() => {
const additionalEvents = [
{
id: 4,
title: 'Jazz Improvisation Class',
date: '2024-04-05',
time: '5:00 PM',
type: 'class',
location: 'Studio',
description: 'Learn the art of jazz improvisation'
}
];
appState.events = [...appState.events, ...additionalEvents];
renderEvents();
}, 1000);
}
// Resources management
async function loadResources() {
try {
// Simulate API call
const mockResources = [
{
id: 1,
title: 'Beginner Practice Routine',
type: 'video',
category: 'practice',
description: 'Daily exercises for new piano students'
},
{
id: 2,
title: 'Classical Repertoire Collection',
type: 'sheet_music',
category: 'repertoire',
description: 'Essential pieces for developing technique'
}
];
appState.resources = mockResources;
renderResources();
} catch (error) {
console.error('Error loading resources:', error);
}
}
function renderResources() {
const container = document.getElementById('resources-content');
if (!container) return;
container.innerHTML = `
<h3 class="text-2xl font-bold mb-6 text-primary-400">Featured Resources</h3>
<div class="grid md:grid-cols-2 gap-6">
${appState.resources.map(resource => `
<div class="bg-gray-700 rounded-2xl p-6">
<div class="flex items-center gap-3 mb-3">
<div class="bg-primary-500/20 p-2 rounded-lg">
<i data-feather="${getResourceIcon(resource.type)}" class="text-primary-400"></i>
</div>
<h4 class="font-bold text-white mb-2">${resource.title}</h4>
<p class="text-gray-400 text-sm">${resource.description}</p>
<button class="mt-4 bg-primary-500 hover:bg-primary-600 text-white px-4 py-2 rounded-lg transition-all duration-300">
Access Resource
</button>
</div>
`).join('')}
</div>
`;
feather.replace();
}
function getResourceIcon(type) {
const icons = {
video: 'play-circle',
sheet_music: 'music',
article: 'file-text',
audio: 'headphones'
};
return icons[type] || 'file';
}
// Contact form handling
async function handleContactFormSubmit(event) {
event.preventDefault();
const formData = new FormData(event.target);
const data = Object.fromEntries(formData);
try {
// Show loading state
const submitBtn = event.target.querySelector('button[type="submit"]');
const originalText = submitBtn.textContent;
submitBtn.textContent = 'Sending...';
submitBtn.disabled = true;
// Simulate API call
await new Promise(resolve => setTimeout(resolve, 1500));
// Show success message
showNotification('Message sent successfully! We\'ll get back to you soon.', 'success');
// Reset form
event.target.reset();
submitBtn.textContent = originalText;
submitBtn.disabled = false;
} catch (error) {
console.error('Error sending message:', error);
showNotification('Error sending message. Please try again.', 'error');
}
}
// Language initialization and switching
function initializeLanguage() {
const savedLang = localStorage.getItem('preferredLanguage');
const browserLang = navigator.language.split('-')[0];
let defaultLang = 'en';
if (savedLang) {
defaultLang = savedLang;
} else if (['he', 'ru'].includes(browserLang)) {
defaultLang = browserLang;
}
switchLanguage(defaultLang);
}
function switchLanguage(lang) {
appState.currentLanguage = lang;
localStorage.setItem('preferredLanguage', lang);
// Update HTML attributes
document.documentElement.setAttribute('lang', lang);
if (lang === 'he') {
document.documentElement.setAttribute('dir', 'rtl');
} else {
document.documentElement.setAttribute('dir', 'ltr');
}
updatePageContent();
}
function updatePageContent() {
const currentLang = appState.currentLanguage;
const t = appState.translations?.[currentLang];
if (!t) return;
// Update meta tags
document.title = 'Melodic Keys Academy';
// Update navigation
updateNavigationText();
// Update hero section
updateHeroSection();
// Update about section
updateAboutSection();
// Update contact section
updateContactSection();
}
function updateNavigationText() {
const currentLang = appState.currentLanguage;
const t = appState.translations?.[currentLang]?.nav;
if (!t) return;
// Update navbar links
const navLinks = document.querySelectorAll('a[href="#about"], a[href="#lessons"], a[href="#events"], a[href="#resources"], a[href="#testimonials"], a[href="#gallery"], a[href="#contact"]');
navLinks.forEach(link => {
const href = link.getAttribute('href');
if (href === '#about') link.textContent = t.about;
else if (href === '#lessons') link.textContent = t.lessons;
else if (href === '#events') link.textContent = t.events;
else if (href === '#resources') link.textContent = t.resources;
else if (href === '#testimonials') link.textContent = t.testimonials;
else if (href === '#gallery') link.textContent = t.gallery;
else if (href === '#contact') link.textContent = t.contact;
});
}
function updateHeroSection() {
const currentLang = appState.currentLanguage;
const t = appState.translations?.[currentLang]?.hero;
if (!t) return;
const heroTitle = document.querySelector('section h1');
const heroSubtitle = document.querySelector('section p.text-xl');
const heroButtons = document.querySelectorAll('section a');
if (heroTitle && t.title) heroTitle.textContent = t.title;
if (heroSubtitle && t.subtitle) heroSubtitle.textContent = t.subtitle;
if (heroButtons[0] && t.explore_lessons) heroButtons[0].textContent = t.explore_lessons;
if (heroButtons[1] && t.book_trial) heroButtons[1].textContent = t.book_trial;
}
function updateAboutSection() {
const currentLang = appState.currentLanguage;
const t = appState.translations?.[currentLang]?.about;
if (!t) return;
const aboutTitle = document.querySelector('#about h2');
const aboutContent = document.querySelectorAll('#about p.text-lg');
if (aboutTitle && t.title) aboutTitle.textContent = t.title;
if (aboutContent[0] && t.content1) aboutContent[0].textContent = t.content1;
if (aboutContent[1] && t.content2) aboutContent[1].textContent = t.content2;
// Update specialties
const specialties = document.querySelectorAll('#about span');
if (specialties[0] && t.specialties?.classical) specialties[0].textContent = t.specialties.classical;
if (specialties[1] && t.specialties?.jazz) specialties[1].textContent = t.specialties.jazz;
if (specialties[2] && t.specialties?.contemporary) specialties[2].textContent = t.specialties.contemporary;
if (specialties[3] && t.specialties?.music_theory) specialties[3].textContent = t.specialties.music_theory;
}
function updateContactSection() {
const currentLang = appState.currentLanguage;
const t = appState.translations?.[currentLang]?.contact;
if (!t) return;
const contactTitle = document.querySelector('#contact h2');
const contactSubtitle = document.querySelector('#contact p.text-xl');
const contactForm = document.querySelector('#contact-form');
if (contactTitle && t.title) contactTitle.textContent = t.title;
if (contactSubtitle && t.subtitle) contactSubtitle.textContent = t.subtitle;
// Update form labels
const formLabels = contactForm?.querySelectorAll('label');
const formButton = contactForm?.querySelector('button');
if (contactTitle && t.title) contactTitle.textContent = t.title;
if (contactSubtitle && t.subtitle) contactSubtitle.textContent = t.subtitle;
if (formLabels[0] && t.form?.name) formLabels[0].textContent = t.form.name;
if (formLabels[1] && t.form?.email) formLabels[1].textContent = t.form.email;
if (formLabels[2] && t.form?.phone) formLabels[2].textContent = t.form.phone;
if (formLabels[3] && t.form?.message) formLabels[3].textContent = t.form.message;
if (formLabels[4] && t.form?.trial_label) formLabels[4].textContent = t.form.trial_label;
if (formButton && t.form?.send) formButton.textContent = t.form.send;
}
function updateURL(lang) {
const currentPath = window.location.pathname;
const newPath = `/${lang}${currentPath.replace(/^\/(en|he|ru)/, '')}`;
// Only update URL if it's different from current
if (!currentPath.startsWith(`/${lang}`)) {
window.history.replaceState({}, '', newPath);
}
}
function updateStructuredData() {
const script = document.querySelector('script[type="application/ld+json"]');
if (script) {
const data = JSON.parse(script.textContent);
data.availableLanguage = ['English', 'Hebrew', 'Russian'];
script.textContent = JSON.stringify(data);
}
}
// Handle language change events
document.addEventListener('languageChange', (e) => {
switchLanguage(e.detail.lang);
});
// Notification system
function showNotification(message, type = 'info') {
// Create notification element
const notification = document.createElement('div');
notification.className = `fixed top-4 right-4 z-50 p-4 rounded-lg shadow-lg transform transition-all duration-300 ${
type === 'success' ? 'bg-green-500 text-white' :
type === 'error' ? 'bg-red-500 text-white' :
'bg-primary-500 text-white'
}`;
notification.textContent = message;
document.body.appendChild(notification);
// Animate in
setTimeout(() => {
notification.classList.add('translate-x-0', 'opacity-100');
notification.classList.remove('translate-x-full', 'opacity-0');
}, 100);
// Auto remove after 5 seconds
setTimeout(() => {
notification.classList.remove('translate-x-0', 'opacity-100');
notification.classList.add('translate-x-full', 'opacity-0');
setTimeout(() => {
if (notification.parentNode) {
notification.parentNode.removeChild(notification);
}
}, 300);
}, 5000);
}
// Analytics setup (placeholder)
function setupAnalytics() {
// In a real app, this would initialize Google Analytics, etc.
console.log('Analytics initialized');
}
// Privacy consent banner
function setupPrivacyConsent() {
// Check if consent already given
const consentGiven = localStorage.getItem('privacyConsent');
if (!consentGiven) {
// Create consent banner
const banner = document.createElement('div');
banner.className = 'fixed bottom-0 left-0 right-0 bg-gray-800 border-t border-gray-700 p-4 z-40">
<div class="container mx-auto flex flex-col md:flex-row items-center justify-between gap-4">
<p class="text-gray-300 text-sm">We use cookies to enhance your experience. By continuing to visit this site you agree to our use of cookies.';
banner.innerHTML = `
<div class="flex-1">
<p class="text-gray-300">We use cookies to improve your experience. <a href="/privacy.html" class="text-primary-400 underline">Learn more</a></p>
<div class="flex gap-4">
<button onclick="acceptPrivacyConsent()" class="bg-primary-500 hover:bg-primary-600 text-white px-6 py-2 rounded-lg transition-colors duration-300">
Accept
</button>
<button onclick="declinePrivacyConsent()" class="bg-gray-700 hover:bg-gray-600 text-white px-6 py-2 rounded-lg transition-colors duration-300">
Decline
</button>
</div>
</div>
`;
document.body.appendChild(banner);
}
}
function acceptPrivacyConsent() {
localStorage.setItem('privacyConsent', 'true');
document.querySelector('.privacy-banner').remove();
}
function declinePrivacyConsent() {
localStorage.setItem('privacyConsent', 'false');
document.querySelector('.privacy-banner').remove();
}
// Utility functions
function formatDate(dateString) {
const date = new Date(dateString);
return date.toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
});
}
// Performance monitoring
if ('performance' in window) {
window.addEventListener('load', () => {
const perfData = performance.timing;
const loadTime = perfData.loadEventEnd - perfData.navigationStart;
console.log(`Page loaded in ${loadTime}ms`);
});
// Service Worker registration (for PWA capabilities)
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js')
.then(registration => console.log('SW registered: ', registration))
.catch(registrationError => console.log('SW registration failed: ', registrationError));
});
}
// Export for module usage if needed
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
initializeApp,
loadEvents,
loadResources
};
}