Files

262 lines
8.2 KiB
JavaScript

// handels the language translation
(function attachAppLanguage(window, document) {
const DEFAULT_LANGUAGE = "de";
const DEFAULT_STORAGE_KEY = "preferredLanguage";
const DEFAULT_SUPPORTED_LANGUAGES = ["de", "en"];
function resolveSupportedLanguages(supportedLanguages = DEFAULT_SUPPORTED_LANGUAGES) {
const normalizedLanguages = Array.isArray(supportedLanguages)
? supportedLanguages
.map((language) => String(language || "").trim().slice(0, 2).toLowerCase())
.filter(Boolean)
: [];
return normalizedLanguages.length > 0 ? normalizedLanguages : DEFAULT_SUPPORTED_LANGUAGES.slice();
}
function normalizeLanguage(
language,
{
supportedLanguages = DEFAULT_SUPPORTED_LANGUAGES,
defaultLanguage = DEFAULT_LANGUAGE
} = {}
) {
const normalizedSupportedLanguages = resolveSupportedLanguages(supportedLanguages);
const normalizedDefaultLanguage = normalizedSupportedLanguages.includes(defaultLanguage)
? defaultLanguage
: normalizedSupportedLanguages[0] || DEFAULT_LANGUAGE;
const shortLanguage = String(language || "").trim().slice(0, 2).toLowerCase();
return normalizedSupportedLanguages.includes(shortLanguage) ? shortLanguage : normalizedDefaultLanguage;
}
function getStoredLanguage({ storageKey = DEFAULT_STORAGE_KEY } = {}) {
try {
return window.localStorage.getItem(storageKey);
} catch (error) {
return null;
}
}
function storeLanguage(language, { storageKey = DEFAULT_STORAGE_KEY } = {}) {
try {
window.localStorage.setItem(storageKey, language);
} catch (error) {
return;
}
}
function detectBrowserLanguage(options = {}) {
return normalizeLanguage(navigator.language || navigator.userLanguage || options.defaultLanguage, options);
}
function getPreferredLanguage(
{
supportedLanguages = DEFAULT_SUPPORTED_LANGUAGES,
defaultLanguage = DEFAULT_LANGUAGE,
storageKey = DEFAULT_STORAGE_KEY,
fallbackLanguage = defaultLanguage
} = {}
) {
return normalizeLanguage(
getStoredLanguage({ storageKey }) || detectBrowserLanguage({ supportedLanguages, defaultLanguage }) || fallbackLanguage,
{
supportedLanguages,
defaultLanguage: fallbackLanguage
}
);
}
function getNextLanguage(language, supportedLanguages = DEFAULT_SUPPORTED_LANGUAGES) {
const normalizedSupportedLanguages = resolveSupportedLanguages(supportedLanguages);
const currentLanguage = normalizeLanguage(language, {
supportedLanguages: normalizedSupportedLanguages,
defaultLanguage: normalizedSupportedLanguages[0]
});
const currentIndex = normalizedSupportedLanguages.indexOf(currentLanguage);
if (currentIndex === -1 || normalizedSupportedLanguages.length < 2) {
return currentLanguage;
}
return normalizedSupportedLanguages[(currentIndex + 1) % normalizedSupportedLanguages.length];
}
function setDocumentLanguage(language) {
if (document.documentElement) {
document.documentElement.lang = language;
}
if (document.body) {
document.body.dataset.language = language;
}
}
function applyTextTranslations({
translate,
selector = "[data-i18n]",
allowHtml = () => false
} = {}) {
if (typeof translate !== "function") {
return;
}
document.querySelectorAll(selector).forEach((element) => {
const key = element.dataset.i18n;
const translatedText = translate(key, element);
if (translatedText === undefined || translatedText === null) {
return;
}
if (allowHtml(element, translatedText, key)) {
element.innerHTML = String(translatedText);
return;
}
element.textContent = String(translatedText);
});
}
function applyAttributeTranslations({
translate,
mappings = []
} = {}) {
if (typeof translate !== "function") {
return;
}
mappings.forEach(({ selector, datasetKey, attribute }) => {
document.querySelectorAll(selector).forEach((element) => {
const key = element.dataset[datasetKey];
const translatedText = translate(key, element, attribute);
if (translatedText === undefined || translatedText === null) {
return;
}
element.setAttribute(attribute, String(translatedText));
});
});
}
function applyTranslations({
translate,
selector = "[data-i18n]",
allowHtml,
attributeMappings = []
} = {}) {
applyTextTranslations({ translate, selector, allowHtml });
applyAttributeTranslations({ translate, mappings: attributeMappings });
}
function updateLanguageSwitch(
button,
{
language,
label = String(language || "").toUpperCase(),
ariaLabel,
title
} = {}
) {
if (!button) {
return;
}
button.textContent = label;
if (ariaLabel !== undefined) {
button.setAttribute("aria-label", ariaLabel);
}
if (title !== undefined) {
button.title = title;
}
}
function createController({
button = document.getElementById("langSwitch"),
defaultLanguage = DEFAULT_LANGUAGE,
supportedLanguages = DEFAULT_SUPPORTED_LANGUAGES,
storageKey = DEFAULT_STORAGE_KEY,
onApply = () => { }
} = {}) {
const options = {
defaultLanguage,
supportedLanguages,
storageKey
};
let currentLanguage = normalizeLanguage(defaultLanguage, options);
function apply(language, source = "apply") {
currentLanguage = normalizeLanguage(language, options);
setDocumentLanguage(currentLanguage);
onApply(currentLanguage, {
source,
button,
applyTranslations,
updateLanguageSwitch: (switchOptions = {}) => updateLanguageSwitch(button, {
language: currentLanguage,
...switchOptions
}),
getNextLanguage: () => getNextLanguage(currentLanguage, supportedLanguages),
normalizeLanguage: (value) => normalizeLanguage(value, options)
});
storeLanguage(currentLanguage, { storageKey });
return currentLanguage;
}
function toggle() {
return apply(getNextLanguage(currentLanguage, supportedLanguages), "toggle");
}
function init(initialLanguage = getPreferredLanguage({
supportedLanguages,
defaultLanguage,
storageKey,
fallbackLanguage: defaultLanguage
})) {
if (button) {
button.addEventListener("click", toggle);
}
return apply(initialLanguage, "init");
}
return {
apply,
getCurrentLanguage: () => currentLanguage,
getPreferredLanguage: (fallbackLanguage = defaultLanguage) => getPreferredLanguage({
supportedLanguages,
defaultLanguage,
storageKey,
fallbackLanguage
}),
init,
toggle
};
}
window.AppLanguage = {
DEFAULT_LANGUAGE,
DEFAULT_STORAGE_KEY,
DEFAULT_SUPPORTED_LANGUAGES: DEFAULT_SUPPORTED_LANGUAGES.slice(),
applyAttributeTranslations,
applyTextTranslations,
applyTranslations,
createController,
detectBrowserLanguage,
getNextLanguage,
getPreferredLanguage,
getStoredLanguage,
normalizeLanguage,
setDocumentLanguage,
storeLanguage,
updateLanguageSwitch
};
})(window, document);