From def92d1b8e9d373e2f6f27c366d578d97d8960c6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 15 May 2024 05:34:50 +0200 Subject: Merging upstream version 126.0. Signed-off-by: Daniel Baumann --- browser/components/preferences/translations.js | 270 +++++++++++++++++++++++++ 1 file changed, 270 insertions(+) (limited to 'browser/components/preferences/translations.js') diff --git a/browser/components/preferences/translations.js b/browser/components/preferences/translations.js index c9cfe472ac..1bfa021d59 100644 --- a/browser/components/preferences/translations.js +++ b/browser/components/preferences/translations.js @@ -4,6 +4,10 @@ /* import-globals-from preferences.js */ +ChromeUtils.defineESModuleGetters(this, { + TranslationsParent: "resource://gre/actors/TranslationsParent.sys.mjs", +}); + let gTranslationsPane = { init() { document @@ -11,5 +15,271 @@ let gTranslationsPane = { .addEventListener("click", function () { gotoPref("general"); }); + + document + .getElementById("translations-settings-always-translate-list") + .addEventListener("command", this.addAlwaysLanguage); + + document + .getElementById("translations-settings-never-translate-list") + .addEventListener("command", this.addNeverLanguage); + + this.buildLanguageDropDowns(); + this.buildDownloadLanguageList(); + }, + + /** + * Populate the Drop down list with the list of supported languages + * for the user to choose languages to add to Always translate and + * Never translate settings list. + */ + async buildLanguageDropDowns() { + const { fromLanguages } = await TranslationsParent.getSupportedLanguages(); + let alwaysLangPopup = document.getElementById( + "translations-settings-always-translate-popup" + ); + let neverLangPopup = document.getElementById( + "translations-settings-never-translate-popup" + ); + + for (const { langTag, displayName } of fromLanguages) { + const alwaysLang = document.createXULElement("menuitem"); + alwaysLang.setAttribute("value", langTag); + alwaysLang.setAttribute("label", displayName); + alwaysLangPopup.appendChild(alwaysLang); + const neverLang = document.createXULElement("menuitem"); + neverLang.setAttribute("value", langTag); + neverLang.setAttribute("label", displayName); + neverLangPopup.appendChild(neverLang); + } + }, + + /** + * Show a list of languages for the user to be able to install + * and uninstall language models for local translation. + */ + async buildDownloadLanguageList() { + const supportedLanguages = await TranslationsParent.getSupportedLanguages(); + const languageList = TranslationsParent.getLanguageList(supportedLanguages); + + let installList = document.querySelector( + ".translations-settings-language-list" + ); + + // The option to download "All languages" is added in xhtml. + // Here the option to download individual languages is dynamically added + // based on the supported language list + installList + .querySelector("moz-button") + .addEventListener("click", installLanguage); + + for (const language of languageList) { + const languageElement = document.createElement("div"); + languageElement.classList.add("translations-settings-language"); + + const languageLabel = document.createElement("label"); + languageLabel.textContent = language.displayName; + languageLabel.setAttribute("value", language.langTag); + // Using the language tag suffix to create unique id for each language + languageLabel.id = "translations-settings-download-" + language.langTag; + + const installButton = document.createElement("moz-button"); + installButton.classList.add("translations-settings-download-icon"); + installButton.setAttribute("type", "ghost icon"); + installButton.addEventListener("click", installLanguage); + installButton.setAttribute("aria-label", languageLabel.id); + + languageElement.appendChild(installButton); + languageElement.appendChild(languageLabel); + installList.appendChild(languageElement); + } + }, + + /** + * Event handler when the user wants to add a language to + * Always translate settings list. + */ + addAlwaysLanguage(event) { + /* TODO: + The function addLanguage adds the HTML element. + It will be moved to the observer in the next Bug - 1881259 . + It is here just to test the UI. + For now a language can be added multiple times. + + In the next bug we will maintain a local state of preferences. + When a language is added or removed, the user event updates the preferences in the Services, + This triggers the observer which compares the preferences in the local state and the + preferences in the Services and adds or removes the language in the local state and updates the + UI to reflect the updated Preferences in the Services. + */ + addLanguage( + event, + "translations-settings-always-translate-section", + deleteAlwaysLanguage + ); + }, + + /** + * Event handler when the user wants to add a language to + * Never translate settings list. + */ + addNeverLanguage(event) { + /* TODO: + The function addLanguage adds the HTML element. + It will be moved to the observer in the next Bug - 1881259 . + It is here just to test the UI. + For now a language can be added multiple times. + + In the next bug we will maintain a local state of preferences. + When a language is added or removed, the user event updates the preferences in the Services, + This triggers the observer which compares the preferences in the local state and the + preferences in the Services and adds or removes the language in the local state and updates the + UI to reflect the updated Preferences in the Services. + */ + addLanguage( + event, + "translations-settings-never-translate-section", + deleteNeverLanguage + ); }, }; + +/** + * Function to add a language selected by the user to the list of + * Always/Never translate settings list. + */ +async function addLanguage(event, listClass, delHandler) { + const translatePrefix = + listClass === "translations-settings-never-translate-section" + ? "never" + : "always"; + let translateSection = document.getElementById(listClass); + let languageList = translateSection.querySelector( + ".translations-settings-language-list" + ); + + // While adding the first language, add the Header and language List div + if (!languageList) { + let languageCard = document.createElement("div"); + languageCard.classList.add("translations-settings-languages-card"); + translateSection.appendChild(languageCard); + + let languageHeader = document.createElement("h3"); + languageCard.appendChild(languageHeader); + languageHeader.setAttribute( + "data-l10n-id", + "translations-settings-language-header" + ); + languageHeader.classList.add("translations-settings-language-header"); + + languageList = document.createElement("div"); + languageList.classList.add("translations-settings-language-list"); + languageCard.appendChild(languageList); + } + const languageElement = document.createElement("div"); + languageElement.classList.add("translations-settings-language"); + // Add the language after the Language Header + languageList.insertBefore(languageElement, languageList.firstChild); + + const languageLabel = document.createElement("label"); + languageLabel.textContent = event.target.getAttribute("label"); + languageLabel.setAttribute("value", event.target.getAttribute("value")); + // Using the language tag suffix to create unique id for each language + // add prefix for the always/never translate + languageLabel.id = + "translations-settings-language-" + + translatePrefix + + "-" + + event.target.getAttribute("value"); + + const delButton = document.createElement("moz-button"); + delButton.classList.add("translations-settings-delete-icon"); + delButton.setAttribute("type", "ghost icon"); + delButton.addEventListener("click", delHandler); + delButton.setAttribute("aria-label", languageLabel.id); + + languageElement.appendChild(delButton); + languageElement.appendChild(languageLabel); + + /* After a language is selected the menulist button display will be set to the + selected langauge. After processing the button event the + data-l10n-id of the menulist button is restored to "Add Language" */ + const menuList = translateSection.querySelector("menulist"); + await document.l10n.translateElements([menuList]); +} + +/** + * Event Handler to delete a language selected by the user from the list of + * Always translate settings list. + */ +function deleteAlwaysLanguage(event) { + /* TODO: + The function removeLanguage removes the HTML element. + It will be moved to the observer in the next Bug - 1881259 . + It is here just to test the UI. + + In the next bug we will maintain a local state of preferences. + When a language is added or removed, the user event updates the preferences in the Services, + This triggers the observer which compares the preferences in the local state and the + preferences in the Services and adds or removes the language in the local state and updates the + UI to reflect the updated Preferences in the Services. + */ + removeLanguage(event); +} + +/** + * Event Handler to delete a language selected by the user from the list of + * Never translate settings list. + */ +function deleteNeverLanguage(event) { + /* TODO: + The function removeLanguage removes the HTML element. + It will be moved to the observer in the next Bug - 1881259 . + It is here just to test the UI. + + In the next bug we will maintain a local state of preferences. + When a language is added or removed, the user event updates the preferences in the Services, + This triggers the observer which compares the preferences in the local state and the + preferences in the Services and adds or removes the language in the local state and updates the + UI to reflect the updated Preferences in the Services. + */ + removeLanguage(event); +} + +/** + * Function to delete a language selected by the user from the list of + * Always/Never translate settings list. + */ +function removeLanguage(event) { + /* Langauge section moz-card -parent of-> Language card -parent of-> + Language heading and Language list -parent of-> + Language Element -parent of-> language button and label + */ + let languageCard = event.target.parentNode.parentNode.parentNode; + event.target.parentNode.remove(); + if (languageCard.children[1].childElementCount === 0) { + // If there is no language in the list remove the + // Language Header and language list div + languageCard.remove(); + } +} + +/** + * Event Handler to install a language model selected by the user + */ +function installLanguage(event) { + event.target.classList.remove("translations-settings-download-icon"); + event.target.classList.add("translations-settings-delete-icon"); + event.target.removeEventListener("click", installLanguage); + event.target.addEventListener("click", unInstallLanguage); +} + +/** + * Event Handler to install a language model selected by the user + */ +function unInstallLanguage(event) { + event.target.classList.remove("translations-settings-delete-icon"); + event.target.classList.add("translations-settings-download-icon"); + event.target.removeEventListener("click", unInstallLanguage); + event.target.addEventListener("click", installLanguage); +} -- cgit v1.2.3