From e77f2438e4fb18261c31c8d3b15ae815aac27daf Mon Sep 17 00:00:00 2001 From: Linux User Date: Fri, 12 Feb 2021 23:22:34 +0100 Subject: [PATCH] Add bilinguality --- bilingual.css | 11 ++++ bilingual.js | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 bilingual.css create mode 100644 bilingual.js diff --git a/bilingual.css b/bilingual.css new file mode 100644 index 0000000..1d81ec8 --- /dev/null +++ b/bilingual.css @@ -0,0 +1,11 @@ +.wiai-english { + display: none; +} + +.wiai-language-english .wiai-english { + display: block; +} + +.wiai-language-english .wiai-german { + display: none; +} diff --git a/bilingual.js b/bilingual.js new file mode 100644 index 0000000..a49c37e --- /dev/null +++ b/bilingual.js @@ -0,0 +1,174 @@ +// A list of all sections. +let sectionList; + +// The main content area. +let contentArea; + +// The language currently in use. +let currentLanguage = 'german'; + +// A hash of all elements explicitly marked as belonging to a language, +// e.g., by adding the class `wiai-german`. +const languageElements = {}; + +// All elements that contain multiple languages inline, +// separated by ' | '. +const multiLanguageElements = []; + +const LANGUAGES = ['german', 'english']; +const LANGUAGE_NAMES = {'german': 'Deutsch', 'english': 'English'}; +const LANGUAGE_PREFIXES = {'img[alt="German"]': 'german', 'img[alt="English"]': 'english'}; +const URL = 'https://wiai.stuve-bamberg.de/vc-customization/'; + +const MULTI_LANGUAGE_CANDIDATE_QUERY = 'h1, h2, h3, h4, h5, span.instancename'; +const STORAGE_LANGUAGE_PREFERENCE_KEY = 'wiai-language-preference'; + +window.addEventListener('load', init); +addStylesheetTag(); + +function init() { + initializeElements(); + categorizeElementsByPrefix(); + initializeMultiLanguageElements(); + addLanguageChooser(); + updateMultiLanguageElements(); + readUserPreferences(); +} + +/** + * Add a link to the bilingual.css stylesheet. + */ +function addStylesheetTag() { + let tag = document.createElement('link'); + tag.rel = 'stylesheet'; + tag.href = URL + 'bilingual.css'; + document.head.appendChild(tag); +} + +/** + * Fill the `languageElements` hash with lists of objects that have explicit language classes (e.g., `wiai-german`), + * as well as the `sectionList` array of all main sections and the `contentArea` element. + */ +function initializeElements() { + LANGUAGES.forEach(function (language) { + languageElements[language] = Array.from(document.querySelectorAll(`.${getClassNameForLanguage(language)}`)); + }); + sectionList = Array.from(document.querySelectorAll('.topics .section.main')); + contentArea = document.querySelector('.course-content'); +} + +/** + * Add the language chooser element to the top of the `contentArea`. + */ +function addLanguageChooser() { + let languageChooser = document.createElement('div'); + languageChooser.classList.add('wiai-language-chooser'); + + LANGUAGES.forEach(function (language) { + let languageLink = document.createElement('a'); + languageLink.href = '#'; + languageLink.classList.add('wiai-language-option'); + languageLink.setAttribute('data-wiai-language', language); + languageLink.textContent = LANGUAGE_NAMES[language]; + + languageLink.addEventListener('click', function (event) { + event.preventDefault(); + switchLanguage(currentLanguage, language); + let siblings = Array.from(link.parentElement.children); + siblings.forEach(function (element) { element.classList.remove('active'); }) + link.classList.add('active'); + }); + + languageChooser.appendChild(languageLink); + }); + + contentArea.prepend(languageChooser); +} + +/** + * Update the language class on the document body (`wiai-language-XYZ`) + * and update all elements in `multiLanguageElements`. + * The `currentLanguage` is updated in the process. + */ +function switchLanguage(oldLanguage, newLanguage) { + document.body.classList.remove(`wiai-language-${oldLanguage}`); + document.body.classList.add(`wiai-language-${newLanguage}`); + currentLanguage = newLanguage; + writeUserPreferences(); + updateMultiLanguageElements(); +} + +/** + * Update all `multiLanguageElements` to fit the new language. + **/ +function updateMultiLanguageElements() { + multiLanguageElements.forEach(function (element) { + element.textContent = element.getAttribute(`data-wiai-title-${currentLanguage}`); + }); +} + +/** + * Add the correct language class to elements starting with one of the + * `LANGUAGE_PREFIXES`. The prefix is removed from the element itself. + */ +function categorizeElementsByPrefix() { + Object.keys(LANGUAGE_PREFIXES).forEach(function (languagePrefix) { + const language = LANGUAGE_PREFIXES[languagePrefix]; + const prefixElements = document.querySelectorAll(languagePrefix); + prefixElements.forEach(function (prefixElement) { + const parent = prefixElement.parentElement; + parent.removeChild(prefixElement); + parent.classList.add(getClassNameForLanguage(language)); + }); + }); +} + +/** + * Find and process all elements containing multiple languages inline. + */ +function initializeMultiLanguageElements() { + const candidates = Array.from(contentArea.querySelectorAll(MULTI_LANGUAGE_CANDIDATE_QUERY)); + candidates.forEach(initializeMultiLanguageElement); +} + +/** + * Split the title of each `multiLanguageElement` and store the individual values + * in data attributes (`data-wiai-title-`). The text content is then set + * to match the `currentLanguage`. + */ +function initializeMultiLanguageElement(element) { + const title = element.textContent; + + if (title.includes(' | ')) { + const titleFragments = title.split(' | '); + for (let i = 0; i < titleFragments.length && i < LANGUAGES.length; i++) { + const language = LANGUAGES[i]; + const localTitle = titleFragments[i]; + element.setAttribute(`data-wiai-title-${language}`, localTitle); + multiLanguageElements.push(element); + } + + element.textContent = element.getAttribute(`data-wiai-title-${currentLanguage}`); + } +} + +function getClassNameForLanguage(language) { + return `wiai-${language}`; +} + +/** + * Read the user's language preference—if any—from LocalStorage and update elements accordingly. + */ +function readUserPreferences() { + if (localStorage.getItem(STORAGE_LANGUAGE_PREFERENCE_KEY) != null) { + currentLanguage = localStorage.getItem(STORAGE_LANGUAGE_PREFERENCE_KEY); + updateMultiLanguageElements(); + } +} + +/** + * Store the user's language preference in LocalStorage. + */ +function writeUserPreferences() { + localStorage.setItem(STORAGE_LANGUAGE_PREFERENCE_KEY, currentLanguage); +}