diff --git a/assets/js/languageSuggestion.js b/assets/js/languageSuggestion.js new file mode 100644 index 000000000..588195024 --- /dev/null +++ b/assets/js/languageSuggestion.js @@ -0,0 +1,115 @@ +import * as params from "@params"; + +const languageSuggestion = (() => { + const supportedLanguages = params.supportedLanguages || []; + const defaultLanguage = "en"; + const DISMISSED_KEY = "languageSuggestionDismissed"; + + const getPreferredLanguage = () => { + const nav = window.navigator; + if (!Array.isArray(nav.languages)) { + return null; + } + + for (const language of nav.languages) { + for (const lang of supportedLanguages) { + if (language.toLowerCase().includes(lang)) { + return lang; + } + } + } + return defaultLanguage; + }; + + const isDismissed = (currentLang, preferredLang) => { + try { + const dismissed = sessionStorage.getItem(DISMISSED_KEY); + if (!dismissed) return false; + const dismissedData = JSON.parse(dismissed); + return ( + dismissedData.currentLang === currentLang && + dismissedData.preferredLang === preferredLang + ); + } catch { + return false; + } + }; + + const setDismissed = (currentLang, preferredLang) => { + try { + sessionStorage.setItem( + DISMISSED_KEY, + JSON.stringify({ currentLang, preferredLang }), + ); + } catch {} + }; + + const init = () => { + const suggestionElement = document.getElementById("language-suggestion"); + if (!suggestionElement) return; + + const currentLang = suggestionElement.dataset.currentLang; + const preferredLang = getPreferredLanguage(); + + if (!preferredLang || preferredLang === currentLang) { + return; + } + + if (isDismissed(currentLang, preferredLang)) { + return; + } + + const translationUrl = + suggestionElement.dataset[ + `translation${preferredLang.charAt(0).toUpperCase() + preferredLang.slice(1)}` + ]; + if (!translationUrl) { + return; + } + + const message = + suggestionElement.dataset[ + `message${preferredLang.charAt(0).toUpperCase() + preferredLang.slice(1)}` + ]; + const buttonText = + suggestionElement.dataset[ + `buttonText${preferredLang.charAt(0).toUpperCase() + preferredLang.slice(1)}` + ]; + + const messageElement = suggestionElement.querySelector( + ".o-language-suggestion__message", + ); + if (messageElement && message) { + messageElement.textContent = message; + } + + const linkElement = suggestionElement.querySelector( + ".o-language-suggestion__link", + ); + if (linkElement && buttonText) { + linkElement.href = translationUrl; + linkElement.textContent = buttonText; + linkElement.style.display = "inline-block"; + } + + suggestionElement.style.display = "block"; + + const dismissButton = suggestionElement.querySelector( + ".o-language-suggestion__dismiss", + ); + if (dismissButton) { + dismissButton.addEventListener("click", () => { + suggestionElement.style.display = "none"; + setDismissed(currentLang, preferredLang); + }); + } + }; + + return { init, getPreferredLanguage }; +})(); + +document.addEventListener("DOMContentLoaded", () => { + languageSuggestion.init(); +}); + +export default languageSuggestion; diff --git a/assets/js/main.js b/assets/js/main.js index 647af03a0..4f920b72f 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -9,3 +9,4 @@ import "./darkmode.js"; import "./search.js"; import "./interactiveMap.js"; import "./expander.js"; +import "./languageSuggestion.js"; diff --git a/assets/js/mobileMenu.js b/assets/js/mobileMenu.js index 03ef0deea..6add0b2cb 100644 --- a/assets/js/mobileMenu.js +++ b/assets/js/mobileMenu.js @@ -1,5 +1,3 @@ -//import {initWindowOnClick} from './windowOnClickHandling'; - function initMobileMenu() { const menuButton = document.querySelector(".o-nav__menu-button"); const closeButton = document.querySelector(".o-nav__close-button"); @@ -13,7 +11,6 @@ function initMobileMenu() { }); window.onclick = (e) => { - //console.log(e.target); if (e.target.classList.contains("o-header__curtain")) { closeMobileMenu(); } diff --git a/assets/sass/languageSuggestion.scss b/assets/sass/languageSuggestion.scss new file mode 100644 index 000000000..f5fda977d --- /dev/null +++ b/assets/sass/languageSuggestion.scss @@ -0,0 +1,44 @@ +@import "variables"; + +.o-language-suggestion { + padding: 1.2rem 1.6rem; + margin-bottom: 1.5rem; + border: 0.2rem solid; + position: relative; + + &__message { + margin: 0 0 1rem 0; + padding-right: 3rem; + } + + &__actions { + display: flex; + align-items: center; + gap: 1.2rem; + flex-wrap: wrap; + } + + &__dismiss { + position: absolute; + top: 1.2rem; + right: 1.2rem; + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.4rem; + background: transparent; + border: none; + cursor: pointer; + color: var(--color-body); + + &:hover, + &:focus { + color: var(--link-default); + } + + svg { + width: 2rem; + height: 2rem; + } + } +} diff --git a/assets/sass/main.scss b/assets/sass/main.scss index ca189390a..ea02adb3f 100644 --- a/assets/sass/main.scss +++ b/assets/sass/main.scss @@ -3,6 +3,7 @@ @import "fonts.scss"; @import "navigation.scss"; @import "contentNavigation"; +@import "languageSuggestion"; @import "search.scss"; @import "teaser.scss"; @import "footer.scss"; diff --git a/i18n/de.yaml b/i18n/de.yaml index 9a717d931..8b79f1605 100644 --- a/i18n/de.yaml +++ b/i18n/de.yaml @@ -68,6 +68,7 @@ interactiveMap: language-switcher: aria-label: Sprache wechseln dropdown-label: Verfügbare Sprachen + suggestion: Diese Seite ist in deiner bevorzugten Sprache verfügbar. menu: close: label: Schließen diff --git a/i18n/en.yaml b/i18n/en.yaml index 07b2274c1..94b238a00 100644 --- a/i18n/en.yaml +++ b/i18n/en.yaml @@ -67,6 +67,7 @@ interactiveMap: language-switcher: aria-label: Switch language dropdown-label: Available languages + suggestion: This page is available in your preferred language. menu: close: label: Close diff --git a/i18n/fr.yaml b/i18n/fr.yaml index 9486095a0..0e699164a 100644 --- a/i18n/fr.yaml +++ b/i18n/fr.yaml @@ -67,6 +67,7 @@ interactiveMap: language-switcher: aria-label: Changer de langue dropdown-label: Langues disponibles + suggestion: Cette page est disponible dans votre langue préférée. menu: close: label: Fermer diff --git a/layouts/alias.html b/layouts/alias.html index f7ca85b16..25fcaf5a7 100644 --- a/layouts/alias.html +++ b/layouts/alias.html @@ -7,34 +7,22 @@ - - diff --git a/layouts/partials/head/js.html b/layouts/partials/head/js.html index cf3c3c122..60d73b887 100644 --- a/layouts/partials/head/js.html +++ b/layouts/partials/head/js.html @@ -1,10 +1,14 @@ +{{ $supportedLanguages := slice }} +{{ range site.Languages }} + {{ $supportedLanguages = $supportedLanguages | append .Lang }} +{{ end }} {{- with resources.Get "js/main.js" }} {{- if eq hugo.Environment "development" }} - {{- with . | js.Build }} + {{- with . | js.Build (dict "params" (dict "supportedLanguages" $supportedLanguages)) }} {{- end }} {{- else }} - {{- $opts := dict "minify" true }} + {{- $opts := dict "minify" true "params" (dict "supportedLanguages" $supportedLanguages) }} {{- with . | js.Build $opts | fingerprint }} diff --git a/layouts/partials/language-suggestion.html b/layouts/partials/language-suggestion.html new file mode 100644 index 000000000..c594a4b1f --- /dev/null +++ b/layouts/partials/language-suggestion.html @@ -0,0 +1,31 @@ +