diff --git a/assets/i18n.js b/assets/i18n.js new file mode 100644 index 0000000..ccda472 --- /dev/null +++ b/assets/i18n.js @@ -0,0 +1,58 @@ +// Simple client-side i18n loader using JSON files in /locales/ +(function(){ + const defaultLang = localStorage.getItem('lang') || (navigator.language && navigator.language.startsWith && navigator.language.startsWith('en') ? 'en' : 'fr'); + let current = defaultLang; + + async function loadLocale(lang){ + try{ + const res = await fetch(`locales/${lang}.json`); + if(!res.ok) throw new Error('locale not found'); + return await res.json(); + }catch(e){ + console.error('i18n load error', e); + return {}; + } + } + + function applyTranslations(messages){ + document.querySelectorAll('[data-i18n]').forEach(el => { + const key = el.getAttribute('data-i18n'); + const txt = messages[key]; + if(!txt) return; + if(el.placeholder !== undefined && el.tagName.toLowerCase()==='input'){ + el.placeholder = txt; + } else if (el.hasAttribute('data-i18n-html')) { + el.innerHTML = txt; + } else { + el.textContent = txt; + } + }); + } + + async function setLang(lang){ + const messages = await loadLocale(lang); + applyTranslations(messages); + localStorage.setItem('lang', lang); + current = lang; + try{ document.documentElement.lang = lang; }catch(e){} + document.querySelectorAll('.lang-toggle').forEach(btn => { + btn.classList.toggle('active', btn.getAttribute('data-lang')===lang); + }); + } + + // init on DOMContentLoaded + document.addEventListener('DOMContentLoaded', () => { + // attach toggles + document.querySelectorAll('.lang-toggle').forEach(btn => { + btn.addEventListener('click', e => { + e.preventDefault(); + const l = btn.getAttribute('data-lang'); + setLang(l); + }); + }); + setLang(current); + }); + + // expose for debug + window.__i18n = { setLang }; +})(); diff --git a/cours.html b/cours.html new file mode 100644 index 0000000..ec16117 --- /dev/null +++ b/cours.html @@ -0,0 +1,47 @@ + + +
+ + + + +