Files
chill.social/themes/chill-theme/layouts/partials/language-detection.html
T

106 lines
3.7 KiB
HTML

{{/*
Language preference + browser language detection.
Rendered inline in <head> on purpose: it must run before the page paints so
a visitor is never shown a flash of the wrong language, and inlining avoids
an extra HTTP request for ~1 KB of script.
Hugo hands the script everything it needs, so the script never has to guess
URLs: the home page of every language and the translations of *this* page.
That keeps it correct even though French is served from the site root ("/")
while the other languages sit under a prefix ("/en/", "/nl/").
*/}}
{{ if hugo.IsMultilingual }}
{{ $homes := dict }}
{{ range hugo.Sites }}
{{ $homes = merge $homes (dict .Language.Lang .Home.RelPermalink) }}
{{ end }}
{{ $translations := dict }}
{{ range .AllTranslations }}
{{ $translations = merge $translations (dict .Lang .RelPermalink) }}
{{ end }}
<script>
(function () {
'use strict';
var STORAGE_KEY = 'hugo_preferred_language';
var SESSION_KEY = 'language_redirected';
var CURRENT = {{ .Site.Language.Lang }};
var HOMES = {{ $homes | jsonify | safeJS }};
var TRANSLATIONS = {{ $translations | jsonify | safeJS }};
var AVAILABLE = Object.keys(HOMES);
function read(store, key) {
try { return window[store].getItem(key); } catch (e) { return null; }
}
function write(store, key, value) {
try { window[store].setItem(key, value); } catch (e) { /* private mode */ }
}
/* Match a browser language tag ("nl-BE", "en") against the languages this
site actually publishes, comparing on the primary subtag. */
function matchLanguage(tag) {
var primary = String(tag).toLowerCase().split('-')[0];
for (var i = 0; i < AVAILABLE.length; i++) {
if (AVAILABLE[i].toLowerCase().split('-')[0] === primary) {
return AVAILABLE[i];
}
}
return null;
}
function detectFromBrowser() {
var tags = navigator.languages || (navigator.language ? [navigator.language] : []);
for (var i = 0; i < tags.length; i++) {
var match = matchLanguage(tags[i]);
if (match) { return match; }
}
return null;
}
function targetFor(lang) {
/* Prefer the translation of the page being viewed, so a deep link keeps
the visitor on the same page in their language. */
return TRANSLATIONS[lang] || HOMES[lang] || null;
}
function resolveAndRedirect() {
/* Auto-redirect at most once per browsing session: after that the
visitor is free to navigate to any language by hand. */
if (read('sessionStorage', SESSION_KEY)) { return; }
write('sessionStorage', SESSION_KEY, '1');
var stored = read('localStorage', STORAGE_KEY);
var wanted = (stored && HOMES[stored]) ? stored : detectFromBrowser();
if (!wanted || wanted === CURRENT) { return; }
var target = targetFor(wanted);
if (target) {
window.location.replace(target + window.location.search + window.location.hash);
}
}
/* Remember an explicit choice made through the language switcher. */
function rememberChoices() {
var links = document.querySelectorAll('.language-switch-link');
for (var i = 0; i < links.length; i++) {
links[i].addEventListener('click', function () {
var lang = this.getAttribute('data-lang');
if (lang) { write('localStorage', STORAGE_KEY, lang); }
});
}
}
resolveAndRedirect();
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', rememberChoices);
} else {
rememberChoices();
}
})();
</script>
{{ end }}