- page-redirect sur / et tous les chemins sans préfixe : localStorage zektyc-lang puis navigator.language, défaut fr ; fallback FR si la page n'a pas de version EN - /en/ sert enfin la home EN (public/en/), fix de LANG_ROUTES.en - home EN générée à partir d'i18n.json (ld+json Organization/FAQPage valides) - i18n.js/components.js : switch de langue par préfixe + liens préfixés - anciennes URLs /zmap/en/* : 301 vers /en/zmap/* ; pages EN zmap déplacées vers le layout <page>/en/ standard - canonicals/hreflang fr-en-x-default sur toutes les pages statiques + sitemaps (équipe, zmap, archives, vitesses-par-route ajoutées) ; suppression du domaine obsolète zektyc.duckdns.org (robots, sitemap index, security.txt)
136 lines
4.2 KiB
JavaScript
136 lines
4.2 KiB
JavaScript
(function () {
|
|
var STORAGE_KEY = "zektyc-lang"
|
|
var DEFAULT_LANG = "fr"
|
|
var translations = {}
|
|
|
|
function urlLang() {
|
|
var path = window.location.pathname
|
|
if (path === "/en" || path.indexOf("/en/") === 0) return "en"
|
|
if (path === "/fr" || path.indexOf("/fr/") === 0) return "fr"
|
|
return null
|
|
}
|
|
|
|
function detect() {
|
|
var forced = urlLang()
|
|
if (forced) return forced
|
|
|
|
try {
|
|
var stored = localStorage.getItem(STORAGE_KEY)
|
|
if (stored && translations[stored]) return stored
|
|
} catch (e) {}
|
|
|
|
var candidates = []
|
|
if (navigator.languages && navigator.languages.length) {
|
|
candidates = candidates.concat(navigator.languages)
|
|
}
|
|
if (navigator.language) candidates.push(navigator.language)
|
|
if (navigator.userLanguage) candidates.push(navigator.userLanguage)
|
|
|
|
for (var i = 0; i < candidates.length; i++) {
|
|
var raw = String(candidates[i] || "").trim().toLowerCase()
|
|
if (!raw) continue
|
|
if (raw.indexOf("en") === 0) return "en"
|
|
if (raw.indexOf("fr") === 0) return "fr"
|
|
}
|
|
return DEFAULT_LANG
|
|
}
|
|
|
|
function apply(lang) {
|
|
var dict = translations[lang]
|
|
if (!dict) return
|
|
|
|
document.documentElement.lang = lang
|
|
|
|
if (dict["meta.title"]) document.title = dict["meta.title"]
|
|
var desc = document.querySelector('meta[name="description"]')
|
|
if (desc && dict["meta.description"]) {
|
|
desc.setAttribute("content", dict["meta.description"])
|
|
}
|
|
var ogTitle = document.querySelector('meta[property="og:title"]')
|
|
if (ogTitle && dict["meta.title"]) {
|
|
ogTitle.setAttribute("content", dict["meta.title"])
|
|
}
|
|
var ogDesc = document.querySelector('meta[property="og:description"]')
|
|
if (ogDesc && dict["meta.description"]) {
|
|
ogDesc.setAttribute("content", dict["meta.description"])
|
|
}
|
|
|
|
var nodes = document.querySelectorAll("[data-i18n]")
|
|
for (var i = 0; i < nodes.length; i++) {
|
|
var key = nodes[i].getAttribute("data-i18n")
|
|
if (dict[key] !== undefined) nodes[i].textContent = dict[key]
|
|
}
|
|
|
|
var btns = document.querySelectorAll("[data-lang]")
|
|
for (var j = 0; j < btns.length; j++) {
|
|
btns[j].classList.toggle(
|
|
"active",
|
|
btns[j].getAttribute("data-lang") === lang
|
|
)
|
|
}
|
|
|
|
var langLinks = document.querySelectorAll("[data-lang-path]")
|
|
for (var k = 0; k < langLinks.length; k++) {
|
|
langLinks[k].setAttribute(
|
|
"href",
|
|
"/" + lang + langLinks[k].getAttribute("data-lang-path")
|
|
)
|
|
}
|
|
}
|
|
|
|
fetch("/data/i18n.json", { cache: "no-cache" })
|
|
.then(function (res) {
|
|
if (!res.ok) throw new Error("status " + res.status)
|
|
return res.json()
|
|
})
|
|
.then(function (data) {
|
|
if (data && typeof data === "object") translations = data
|
|
})
|
|
.catch(function (e) {
|
|
if (window.console && console.warn) {
|
|
console.warn("[i18n] impossible de charger les traductions:", e)
|
|
}
|
|
})
|
|
.then(function () {
|
|
var detected = detect()
|
|
if (window.console && console.info) {
|
|
console.info(
|
|
"[i18n] langue détectée:",
|
|
detected,
|
|
"| navigator.language:",
|
|
navigator.language,
|
|
"| navigator.languages:",
|
|
navigator.languages
|
|
)
|
|
}
|
|
apply(detected)
|
|
|
|
document.addEventListener("click", function (e) {
|
|
var btn = e.target.closest ? e.target.closest("[data-lang]") : null
|
|
if (!btn) return
|
|
var lang = btn.getAttribute("data-lang")
|
|
if (!translations[lang]) return
|
|
try {
|
|
localStorage.setItem(STORAGE_KEY, lang)
|
|
} catch (err) {}
|
|
|
|
var currentPath = window.location.pathname
|
|
var target = currentPath
|
|
if (/^\/fr(\/|$)/.test(currentPath) || /^\/en(\/|$)/.test(currentPath)) {
|
|
target = "".concat("/", lang, currentPath.slice(3))
|
|
}
|
|
if (window.location.pathname !== target) {
|
|
window.location.href = target
|
|
}
|
|
})
|
|
|
|
var navToggle = document.getElementById("nav-toggle")
|
|
if (navToggle) {
|
|
document.addEventListener("click", function (e) {
|
|
if (e.target.closest && e.target.closest(".site-nav")) {
|
|
navToggle.checked = false
|
|
}
|
|
})
|
|
}
|
|
})
|
|
})()
|