373 lines
11 KiB
JavaScript
373 lines
11 KiB
JavaScript
const SUPPORTED_LANGS = Object.keys(DICT);
|
|
let LANG = DEFAULT_LANG;
|
|
|
|
function getStripePricingTableHtml(lang) {
|
|
const pricingTableId =
|
|
SITE_CONFIG.stripe.pricingTableIds[lang] ||
|
|
SITE_CONFIG.stripe.pricingTableIds.en;
|
|
|
|
return (
|
|
`<stripe-pricing-table pricing-table-id="${pricingTableId}" ` +
|
|
`publishable-key="${SITE_CONFIG.stripe.publishableKey}"></stripe-pricing-table>`
|
|
);
|
|
}
|
|
|
|
function normalizeLang(value) {
|
|
if (!value) return null;
|
|
const lang = String(value).toLowerCase().split(/[-_]/)[0];
|
|
return DICT[lang] ? lang : null;
|
|
}
|
|
|
|
function getStoredLang() {
|
|
const cookieMatch = document.cookie.match(
|
|
new RegExp(`(?:^|; )${LANG_STORAGE_KEY}=([^;]*)`),
|
|
);
|
|
try {
|
|
return (
|
|
normalizeLang(localStorage.getItem(LANG_STORAGE_KEY)) ||
|
|
normalizeLang(cookieMatch && decodeURIComponent(cookieMatch[1]))
|
|
);
|
|
} catch (e) {
|
|
return normalizeLang(cookieMatch && decodeURIComponent(cookieMatch[1]));
|
|
}
|
|
}
|
|
|
|
function getUrlLang() {
|
|
return normalizeLang(new URLSearchParams(location.search).get("lang"));
|
|
}
|
|
|
|
function getBrowserLang() {
|
|
const browserLangs = navigator.languages && navigator.languages.length
|
|
? navigator.languages
|
|
: [navigator.language];
|
|
for (const lang of browserLangs) {
|
|
const normalized = normalizeLang(lang);
|
|
if (normalized) return normalized;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function getInitialLang() {
|
|
return getUrlLang() || getStoredLang() || getBrowserLang() || DEFAULT_LANG;
|
|
}
|
|
|
|
function getRootPrefix() {
|
|
if (document.body && document.body.dataset.rootPrefix) {
|
|
return document.body.dataset.rootPrefix;
|
|
}
|
|
const pathParts = location.pathname.split("/").filter(Boolean);
|
|
const parentDir = pathParts.length > 1 ? pathParts[pathParts.length - 2] : "";
|
|
return SUPPORTED_LANGS.includes(parentDir) ? "../" : "./";
|
|
}
|
|
|
|
function withLangParam(href, lang) {
|
|
const [pathWithSearch, hash = ""] = href.split("#");
|
|
const [path, search = ""] = pathWithSearch.split("?");
|
|
const params = new URLSearchParams(search);
|
|
params.set("lang", lang);
|
|
return `${path}?${params.toString()}${hash ? `#${hash}` : ""}`;
|
|
}
|
|
|
|
function getLocalizedPageUrl(lang) {
|
|
const pathParts = location.pathname.split("/").filter(Boolean);
|
|
const parentDir = pathParts.length > 1 ? pathParts[pathParts.length - 2] : "";
|
|
const fileName = pathParts[pathParts.length - 1] || "";
|
|
if (!SUPPORTED_LANGS.includes(parentDir)) return null;
|
|
if (fileName !== "cgv.html" && fileName !== "legals.html") return null;
|
|
return withLangParam(`../${lang}/${fileName}`, lang);
|
|
}
|
|
|
|
function updateInternalLinks(lang) {
|
|
const rootPrefix = getRootPrefix();
|
|
const homeHref = withLangParam(rootPrefix, lang);
|
|
const offerHref = withLangParam(`${rootPrefix}offre.html`, lang);
|
|
const legalPrefix = `${rootPrefix}${lang}/`;
|
|
const anchors = {
|
|
nav_offer: `${homeHref}#offre`,
|
|
nav_acad: `${homeHref}#academies`,
|
|
nav_how: `${homeHref}#how`,
|
|
nav_faq: `${homeHref}#faq`,
|
|
legal1: withLangParam(`${legalPrefix}cgv.html`, lang),
|
|
legal2: withLangParam(`${legalPrefix}legals.html`, lang),
|
|
};
|
|
|
|
Object.entries(anchors).forEach(([key, href]) => {
|
|
document
|
|
.querySelectorAll(`a[data-i18n="${key}"]`)
|
|
.forEach((link) => link.setAttribute("href", href));
|
|
});
|
|
|
|
document.querySelectorAll("a.brand, a.foot-logo-wrap").forEach((link) => {
|
|
link.setAttribute("href", homeHref);
|
|
});
|
|
|
|
document.querySelectorAll("a[href]").forEach((link) => {
|
|
const href = link.getAttribute("href");
|
|
if (!href || href.startsWith("http") || href.startsWith("mailto:")) return;
|
|
if (href.includes("offre.html")) {
|
|
link.setAttribute("href", offerHref);
|
|
} else if (href === "#offre" || href === "./#offre") {
|
|
link.setAttribute("href", `${homeHref}#offre`);
|
|
} else if (href === "#academies" || href === "./#academies") {
|
|
link.setAttribute("href", `${homeHref}#academies`);
|
|
}
|
|
});
|
|
}
|
|
|
|
function updateGoogleTagManagerNoScript() {
|
|
const gtmId = SITE_CONFIG.googleTagManagerId;
|
|
if (!gtmId) return;
|
|
|
|
document
|
|
.querySelectorAll('iframe[src*="googletagmanager.com/ns.html"]')
|
|
.forEach((iframe) => {
|
|
iframe.setAttribute(
|
|
"src",
|
|
`https://www.googletagmanager.com/ns.html?id=${gtmId}`,
|
|
);
|
|
});
|
|
}
|
|
|
|
function loadGoogleTagManagerScript() {
|
|
const gtmId = SITE_CONFIG.googleTagManagerId;
|
|
if (!gtmId) return;
|
|
if (
|
|
document.querySelector(
|
|
`script[src*="googletagmanager.com/gtm.js?id=${gtmId}"]`,
|
|
)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
(function (w, d, s, l, i) {
|
|
w[l] = w[l] || [];
|
|
w[l].push({ "gtm.start": new Date().getTime(), event: "gtm.js" });
|
|
const f = d.getElementsByTagName(s)[0];
|
|
const j = d.createElement(s);
|
|
const dl = l !== "dataLayer" ? `&l=${l}` : "";
|
|
j.async = true;
|
|
j.src = `https://www.googletagmanager.com/gtm.js?id=${i}${dl}`;
|
|
f.parentNode.insertBefore(j, f);
|
|
})(window, document, "script", "dataLayer", gtmId);
|
|
}
|
|
|
|
function updateConfiguredSiteUrl() {
|
|
const siteUrl = SITE_CONFIG.siteUrl;
|
|
const siteUrlAliases = SITE_CONFIG.siteUrlAliases || [];
|
|
if (!siteUrl) return;
|
|
|
|
document.querySelectorAll("[href], [src]").forEach((el) => {
|
|
["href", "src"].forEach((attr) => {
|
|
const value = el.getAttribute(attr);
|
|
const alias = siteUrlAliases.find(
|
|
(item) => value && value.includes(item),
|
|
);
|
|
if (alias) {
|
|
el.setAttribute(attr, value.replaceAll(alias, siteUrl));
|
|
}
|
|
});
|
|
});
|
|
|
|
if (!document.createTreeWalker || !document.body) return;
|
|
const walker = document.createTreeWalker(document.body, 4);
|
|
let node = walker.nextNode();
|
|
while (node) {
|
|
const alias = siteUrlAliases.find((item) =>
|
|
node.nodeValue.includes(item),
|
|
);
|
|
if (alias) {
|
|
node.nodeValue = node.nodeValue.replaceAll(alias, siteUrl);
|
|
}
|
|
node = walker.nextNode();
|
|
}
|
|
}
|
|
|
|
function updateSocialLinks() {
|
|
const socialLinks = SITE_CONFIG.socialLinks || {};
|
|
const selectors = {
|
|
instagram: 'a[aria-label="Instagram"]',
|
|
facebook: 'a[aria-label="Facebook"]:not([data-disabled="true"])',
|
|
tiktok: 'a[aria-label="TikTok"]:not([data-disabled="true"])',
|
|
linkedin: 'a[aria-label="LinkedIn"]:not([data-disabled="true"])',
|
|
};
|
|
|
|
Object.entries(selectors).forEach(([key, selector]) => {
|
|
const href = socialLinks[key];
|
|
if (!href) return;
|
|
document
|
|
.querySelectorAll(selector)
|
|
.forEach((link) => {
|
|
link.setAttribute("href", href);
|
|
link.setAttribute("target", "_blank");
|
|
link.setAttribute("rel", "noopener noreferrer");
|
|
});
|
|
});
|
|
}
|
|
|
|
function getFooterPath() {
|
|
return `${getRootPrefix()}footer.html`;
|
|
}
|
|
|
|
async function loadFooter() {
|
|
const placeholders = document.querySelectorAll('[data-include="footer"]');
|
|
if (!placeholders.length || !window.fetch) return;
|
|
|
|
try {
|
|
const response = await fetch(getFooterPath());
|
|
if (!response.ok) return;
|
|
|
|
const rootPrefix = getRootPrefix();
|
|
const footerHtml = (await response.text()).replaceAll(
|
|
'src="assets/',
|
|
`src="${rootPrefix}assets/`,
|
|
);
|
|
|
|
placeholders.forEach((placeholder) => {
|
|
placeholder.innerHTML = footerHtml;
|
|
});
|
|
|
|
setLang(LANG);
|
|
updateConfiguredSiteUrl();
|
|
updateSocialLinks();
|
|
} catch (e) {}
|
|
}
|
|
|
|
function setLang(l, options = {}) {
|
|
const normalizedLang = normalizeLang(l);
|
|
if (!normalizedLang) return;
|
|
LANG = normalizedLang;
|
|
if (options.persist) {
|
|
try {
|
|
localStorage.setItem(LANG_STORAGE_KEY, normalizedLang);
|
|
} catch (e) {}
|
|
document.cookie = `${LANG_STORAGE_KEY}=${encodeURIComponent(
|
|
normalizedLang,
|
|
)};path=/;max-age=31536000;SameSite=Lax`;
|
|
}
|
|
const localizedPageUrl = options.navigate
|
|
? getLocalizedPageUrl(normalizedLang)
|
|
: null;
|
|
if (localizedPageUrl && localizedPageUrl !== location.pathname + location.search) {
|
|
location.href = localizedPageUrl;
|
|
return;
|
|
}
|
|
document.documentElement.lang = normalizedLang;
|
|
document.querySelectorAll("[data-i18n]").forEach((el) => {
|
|
const v = DICT[normalizedLang][el.getAttribute("data-i18n")];
|
|
if (v != null) el.textContent = v;
|
|
});
|
|
document.querySelectorAll("[data-i18n-html]").forEach((el) => {
|
|
const key = el.getAttribute("data-i18n-html");
|
|
const v =
|
|
key === "pricing"
|
|
? getStripePricingTableHtml(normalizedLang)
|
|
: DICT[normalizedLang][key];
|
|
if (v != null) el.innerHTML = v;
|
|
});
|
|
document.querySelectorAll("[data-i18n-content]").forEach((el) => {
|
|
const v = DICT[normalizedLang][el.getAttribute("data-i18n-content")];
|
|
if (v != null) el.setAttribute("content", v);
|
|
});
|
|
document.querySelectorAll("[data-i18n-ph]").forEach((el) => {
|
|
const v = DICT[normalizedLang][el.getAttribute("data-i18n-ph")];
|
|
if (v != null) el.setAttribute("placeholder", v);
|
|
});
|
|
document
|
|
.querySelectorAll(".langsw button")
|
|
.forEach((b) => {
|
|
const isActive = b.dataset.lang === normalizedLang;
|
|
b.classList.toggle("on", isActive);
|
|
b.setAttribute("aria-pressed", String(isActive));
|
|
});
|
|
updateInternalLinks(normalizedLang);
|
|
renderCountdown();
|
|
}
|
|
document
|
|
.querySelectorAll(".langsw button")
|
|
.forEach((b) =>
|
|
b.addEventListener("click", () =>
|
|
setLang(b.dataset.lang, { persist: true, navigate: true }),
|
|
)
|
|
);
|
|
|
|
loadGoogleTagManagerScript();
|
|
updateGoogleTagManagerNoScript();
|
|
updateConfiguredSiteUrl();
|
|
updateSocialLinks();
|
|
loadFooter();
|
|
|
|
/* ---------------- countdown ---------------- */
|
|
const TARGET = new Date("2026-07-19T23:59:59+02:00").getTime();
|
|
function renderCountdown() {
|
|
const now = Date.now();
|
|
let diff = Math.max(0, TARGET - now);
|
|
const d = Math.floor(diff / 86400000);
|
|
diff -= d * 86400000;
|
|
const h = Math.floor(diff / 3600000);
|
|
diff -= h * 3600000;
|
|
const m = Math.floor(diff / 60000);
|
|
diff -= m * 60000;
|
|
const s = Math.floor(diff / 1000);
|
|
const p = (n) => String(n).padStart(2, "0");
|
|
const du = (DICT[LANG] && DICT[LANG].cd_d) || "d";
|
|
const str = `${d}${du} ${p(h)}h ${p(m)}m ${p(s)}s`;
|
|
document.querySelectorAll(".js-cd").forEach((e) => (e.textContent = str));
|
|
}
|
|
setLang(getInitialLang());
|
|
setInterval(renderCountdown, 1000);
|
|
|
|
/* ---------------- header scroll ---------------- */
|
|
const hd = document.getElementById("hd");
|
|
if (hd) {
|
|
addEventListener(
|
|
"scroll",
|
|
() => hd.classList.toggle("scrolled", scrollY > 10),
|
|
{ passive: true },
|
|
);
|
|
}
|
|
|
|
/* ---------------- mobile menu ---------------- */
|
|
const burger = document.getElementById("burger");
|
|
if (burger && hd) {
|
|
burger.addEventListener("click", () => {
|
|
const open = hd.classList.toggle("menu-open");
|
|
burger.setAttribute("aria-expanded", open);
|
|
});
|
|
}
|
|
document.querySelectorAll("#navlinks a").forEach((a) =>
|
|
a.addEventListener("click", () => {
|
|
if (hd) hd.classList.remove("menu-open");
|
|
if (burger) burger.setAttribute("aria-expanded", "false");
|
|
}),
|
|
);
|
|
|
|
/* ---------------- faq accordion ---------------- */
|
|
document.querySelectorAll(".qa button").forEach((btn) => {
|
|
btn.addEventListener("click", () => {
|
|
const qa = btn.parentElement,
|
|
ans = qa.querySelector(".ans"),
|
|
open = qa.classList.toggle("open");
|
|
btn.setAttribute("aria-expanded", open);
|
|
ans.hidden = !open;
|
|
});
|
|
});
|
|
|
|
/* ---------------- reveal on scroll ---------------- */
|
|
const reduce = matchMedia("(prefers-reduced-motion:reduce)").matches;
|
|
if (!reduce && "IntersectionObserver" in window) {
|
|
const io = new IntersectionObserver(
|
|
(es) => {
|
|
es.forEach((e) => {
|
|
if (e.isIntersecting) {
|
|
e.target.classList.add("in");
|
|
io.unobserve(e.target);
|
|
}
|
|
});
|
|
},
|
|
{ threshold: 0.14 },
|
|
);
|
|
document.querySelectorAll(".rv").forEach((el) => io.observe(el));
|
|
} else {
|
|
document.querySelectorAll(".rv").forEach((el) => el.classList.add("in"));
|
|
}
|