feat(lang): routage préfixé /fr/ et /en/ avec redirect JS langue sur les chemins non préfixés

- 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)
This commit is contained in:
riricdev 2026-09-06 16:12:16 +02:00
commit 370b3d8752
30 changed files with 566 additions and 124 deletions

View file

@ -9,28 +9,14 @@
function path() { return location.pathname; }
function lang() { return /^\/en(\/|$)/.test(path()) ? 'en' : 'fr'; }
function isHome() { var p = path(); return p === '/' || p === '/index.html' || p === '/en/' || p === '/en/index.html'; }
function frLink() {
var p = path();
if (p === '/en/') return '/';
var m = p.match(/^(\/[^/]+)\/en\/?$/);
if (m) return m[1] + '/';
return p;
}
function enLink() {
var p = path();
if (p === '/' || p === '/index.html') return '/en/';
if (/\/en\/?$/.test(p)) return p;
return p.replace(/\/?$/, '/en/');
}
function isHome() { var p = path(); return p === '/' || p === '/index.html' || p === '/fr/' || p === '/fr/index.html' || p === '/en/' || p === '/en/index.html'; }
function buildHeader() {
var h = lang();
var l = h === 'fr' ? '/fr' : '/en';
var skip = h === 'fr' ? 'Aller au contenu' : 'Skip to content';
var html = '<a class="skip-link" href="#main">' + skip + '</a>';
html += '<a class="brand" href="/">' + BRAND + '</a>';
html += '<a class="brand" href="' + (h === 'fr' ? '/fr/' : '/en/') + '">' + BRAND + '</a>';
html += '<input type="checkbox" id="nav-toggle" class="nav-toggle-input" />';
html += '<label for="nav-toggle" class="nav-burger" aria-label="Menu">';
html += '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h16"/></svg>';
@ -39,9 +25,9 @@
html += '<nav class="site-nav" aria-label="Navigation">';
html += '<a href="/blog" data-lang-path="/blog" data-i18n="nav.blog">Blog</a>';
html += '<a href="/projets" data-lang-path="/projets" data-i18n="nav.projects">Projets</a>';
html += '<a href="/equipe" data-lang-path="/equipe" data-i18n="nav.team">\u00c9quipe</a>';
html += '<a href="' + l + '/blog" data-lang-path="/blog" data-i18n="nav.blog">Blog</a>';
html += '<a href="' + l + '/projets" data-lang-path="/projets" data-i18n="nav.projects">Projets</a>';
html += '<a href="' + l + '/equipe" data-lang-path="/equipe" data-i18n="nav.team">\u00c9quipe</a>';
if (isHome()) {
html += '<a href="#principes" data-i18n="nav.principes">Nos principes</a>';
html += '<a href="#faq" data-i18n="nav.faq">FAQ</a>';
@ -63,8 +49,8 @@
var tos = h === 'fr' ? "Conditions d\u2019utilisation" : 'Terms of Service';
var priv = h === 'fr' ? 'Confidentialit\u00e9' : 'Privacy';
var note = h === 'fr' ? 'Ce site ne collecte rien. Aucun cookie, aucun tracker.' : 'This site collects nothing. No cookies, no trackers.';
var tosHref = h === 'fr' ? '/tos' : '/en/tos';
var privHref = h === 'fr' ? '/privacy-policy' : '/en/privacy-policy';
var tosHref = h === 'fr' ? '/fr/tos' : '/en/tos';
var privHref = h === 'fr' ? '/fr/privacy-policy' : '/en/privacy-policy';
var html = '';
html += '<p>Zektyc \u00b7 France</p>';

View file

@ -113,18 +113,13 @@
try {
localStorage.setItem(STORAGE_KEY, lang)
} catch (err) {}
apply(lang)
var currentPath = window.location.pathname
var isHome = currentPath === "/" || currentPath === "/index.html" || currentPath === "/en/" || currentPath === "/en/index.html"
if (isHome) {
var newUrl = lang === "fr" ? "/" : "/en/"
if (currentPath !== newUrl) history.pushState(null, "", newUrl)
return
var target = currentPath
if (/^\/fr(\/|$)/.test(currentPath) || /^\/en(\/|$)/.test(currentPath)) {
target = "".concat("/", lang, currentPath.slice(3))
}
var target = "/" + lang + "/" + (window.location.hash || "")
if (window.location.pathname !== "/" + lang + "/") {
if (window.location.pathname !== target) {
window.location.href = target
}
})