commit 19ce23f408bb2eebf6646004f420aa7cef66d28d parent add0e3b257912fc6760b8858ce7985f4f30bda06 Author: Erik Nordin <enordin@mozilla.com> Date: Thu, 18 Dec 2025 01:17:28 +0000 Bug 2002127 - Part 15: Use Button Pattern for ATL r=translations-reviewers,fluent-reviewers,bolsson,gregtatum,hjones This commit updates the Always Translate Languages section of the Translations settings the moz-select with button pattern, similar to the download section. Differential Revision: https://phabricator.services.mozilla.com/D274827 Diffstat:
10 files changed, 212 insertions(+), 62 deletions(-)
diff --git a/browser/components/preferences/main.js b/browser/components/preferences/main.js @@ -749,6 +749,10 @@ Preferences.addSetting({ }); Preferences.addSetting({ + id: "translationsAlwaysTranslateLanguagesButton", +}); + +Preferences.addSetting({ id: "translationsNeverTranslateLanguagesNoneRow", }); @@ -3877,6 +3881,16 @@ SettingGroupManager.registerGroups({ }, ], }, + { + id: "translationsAlwaysTranslateLanguagesButton", + l10nId: "settings-translations-subpage-language-add-button", + control: "moz-button", + controlAttrs: { + slot: "actions", + type: "icon", + iconsrc: "chrome://global/skin/icons/plus.svg", + }, + }, ], }, { diff --git a/browser/components/preferences/translations.d.ts b/browser/components/preferences/translations.d.ts @@ -19,6 +19,7 @@ export interface SupportedLanguages { export interface TranslationsSettingsElements { alwaysTranslateLanguagesGroup: HTMLElement; alwaysTranslateLanguagesSelect: HTMLSelectElement; + alwaysTranslateLanguagesButton: HTMLButtonElement; alwaysTranslateLanguagesNoneRow: HTMLElement; neverTranslateLanguagesGroup: HTMLElement; neverTranslateLanguagesSelect: HTMLSelectElement; diff --git a/browser/components/preferences/translations.js b/browser/components/preferences/translations.js @@ -28,9 +28,11 @@ const TOPIC_TRANSLATIONS_PREF_CHANGED = "translations:pref-changed"; const TRANSLATIONS_PERMISSION = "translations"; /** @type {string} */ -const ALWAYS_LANGUAGE_ITEM_CLASS = "translations-always-language-item"; +const ALWAYS_TRANSLATE_LANGUAGE_ITEM_CLASS = + "translations-always-translate-language-item"; /** @type {string} */ -const ALWAYS_LANGUAGE_REMOVE_BUTTON_CLASS = "translations-always-remove-button"; +const ALWAYS_TRANSLATE_LANGUAGE_REMOVE_BUTTON_CLASS = + "translations-always-translate-remove-button"; /** @type {string} */ const NEVER_LANGUAGE_ITEM_CLASS = "translations-never-language-item"; @@ -142,7 +144,7 @@ const TranslationsSettings = { * * @type {Set<string>} */ - alwaysLanguageTags: new Set(), + alwaysTranslateLanguageTags: new Set(), /** * Current never-translate language tags. @@ -214,9 +216,7 @@ const TranslationsSettings = { break; case "change": if (event.target === this.elements?.alwaysTranslateLanguagesSelect) { - await this.onAlwaysLanguageChosen( - /** @type {HTMLSelectElement} */ (event.target).value - ); + this.onAlwaysTranslateLanguageSelectionChanged(); } else if ( event.target === this.elements?.neverTranslateLanguagesSelect ) { @@ -230,6 +230,16 @@ const TranslationsSettings = { case "click": { const target = /** @type {HTMLElement} */ (event.target); if ( + target === this.elements?.alwaysTranslateLanguagesButton || + target.closest?.("#translationsAlwaysTranslateLanguagesButton") + ) { + await this.onAlwaysTranslateLanguageChosen( + this.elements?.alwaysTranslateLanguagesSelect?.value ?? "" + ); + break; + } + + if ( target === this.elements?.downloadLanguagesButton || target.closest?.("#translationsDownloadLanguagesButton") ) { @@ -272,10 +282,12 @@ const TranslationsSettings = { } const alwaysRemoveButton = /** @type {HTMLElement|null} */ ( - target.closest?.(`.${ALWAYS_LANGUAGE_REMOVE_BUTTON_CLASS}`) + target.closest?.(`.${ALWAYS_TRANSLATE_LANGUAGE_REMOVE_BUTTON_CLASS}`) ); if (alwaysRemoveButton?.dataset.langTag) { - this.removeAlwaysLanguage(alwaysRemoveButton.dataset.langTag); + this.removeAlwaysTranslateLanguage( + alwaysRemoveButton.dataset.langTag + ); break; } @@ -311,7 +323,7 @@ const TranslationsSettings = { observe(subject, topic, data) { if (topic === TOPIC_TRANSLATIONS_PREF_CHANGED) { if (data === ALWAYS_TRANSLATE_LANGS_PREF) { - this.refreshAlwaysLanguages().catch(console.error); + this.refreshAlwaysTranslateLanguages().catch(console.error); } else if (data === NEVER_TRANSLATE_LANGS_PREF) { this.refreshNeverLanguages().catch(console.error); } @@ -333,7 +345,7 @@ const TranslationsSettings = { if (this.initPromise) { await this.initPromise; - await this.refreshAlwaysLanguages(); + await this.refreshAlwaysTranslateLanguages(); await this.refreshNeverLanguages(); this.refreshNeverSites(); await this.refreshDownloadedLanguages(); @@ -342,7 +354,7 @@ const TranslationsSettings = { } if (this.initialized) { - await this.refreshAlwaysLanguages(); + await this.refreshAlwaysTranslateLanguages(); await this.refreshNeverLanguages(); this.refreshNeverSites(); await this.refreshDownloadedLanguages(); @@ -407,6 +419,7 @@ const TranslationsSettings = { if ( !this.elements?.alwaysTranslateLanguagesGroup || !this.elements?.alwaysTranslateLanguagesSelect || + !this.elements?.alwaysTranslateLanguagesButton || !this.elements?.alwaysTranslateLanguagesNoneRow || !this.elements?.neverTranslateLanguagesGroup || !this.elements?.neverTranslateLanguagesSelect || @@ -435,6 +448,7 @@ const TranslationsSettings = { } catch (error) { console.error("Failed to initialize translations settings UI", error); this.elements.alwaysTranslateLanguagesSelect.disabled = true; + this.elements.alwaysTranslateLanguagesButton.disabled = true; this.elements.neverTranslateLanguagesSelect.disabled = true; this.elements.downloadLanguagesSelect.disabled = true; this.setDownloadButtonDisabledState(true); @@ -443,11 +457,12 @@ const TranslationsSettings = { } this.elements.alwaysTranslateLanguagesSelect.disabled = false; + this.elements.alwaysTranslateLanguagesButton.disabled = true; this.elements.neverTranslateLanguagesSelect.disabled = false; this.elements.downloadLanguagesSelect.disabled = false; this.resetDownloadSelect(); this.setDownloadButtonDisabledState(true); - await this.buildAlwaysSelectOptions(); + await this.buildAlwaysTranslateSelectOptions(); await this.buildNeverSelectOptions(); await this.buildDownloadSelectOptions(); await this.renderDownloadLanguages(); @@ -456,6 +471,10 @@ const TranslationsSettings = { "change", this ); + this.elements.alwaysTranslateLanguagesButton.addEventListener( + "click", + this + ); this.elements.alwaysTranslateLanguagesGroup.addEventListener("click", this); this.elements.neverTranslateLanguagesSelect.addEventListener( "change", @@ -470,7 +489,7 @@ const TranslationsSettings = { Services.obs.addObserver(this, "perm-changed"); window.addEventListener("unload", this); - await this.refreshAlwaysLanguages(); + await this.refreshAlwaysTranslateLanguages(); await this.refreshNeverLanguages(); this.refreshNeverSites(); this.initialized = true; @@ -500,6 +519,9 @@ const TranslationsSettings = { alwaysTranslateLanguagesSelect: /** @type {HTMLSelectElement} */ ( document.getElementById("translationsAlwaysTranslateLanguagesSelect") ), + alwaysTranslateLanguagesButton: /** @type {HTMLButtonElement} */ ( + document.getElementById("translationsAlwaysTranslateLanguagesButton") + ), alwaysTranslateLanguagesNoneRow: /** @type {HTMLElement} */ ( document.getElementById("translationsAlwaysTranslateLanguagesNoneRow") ), @@ -725,8 +747,14 @@ const TranslationsSettings = { * * @param {string} langTag */ - async onAlwaysLanguageChosen(langTag) { + async onAlwaysTranslateLanguageChosen(langTag) { if (!langTag) { + this.updateAlwaysTranslateAddButtonDisabledState(); + return; + } + + if (this.shouldDisableAlwaysTranslateAddButton()) { + this.updateAlwaysTranslateAddButtonDisabledState(); return; } @@ -735,7 +763,66 @@ const TranslationsSettings = { langTag, NEVER_TRANSLATE_LANGS_PREF ); - await this.resetAlwaysSelect(); + await this.resetAlwaysTranslateSelect(); + }, + + /** + * Handle a selection change in the always-translate dropdown. + */ + onAlwaysTranslateLanguageSelectionChanged() { + this.updateAlwaysTranslateAddButtonDisabledState(); + }, + + /** + * Whether the add button for always-translate languages should be disabled. + * + * @returns {boolean} + */ + shouldDisableAlwaysTranslateAddButton() { + const select = this.elements?.alwaysTranslateLanguagesSelect; + if (!select || select.disabled) { + return true; + } + + const langTag = select.value; + if (!langTag) { + return true; + } + + const option = /** @type {HTMLElement|null} */ ( + select.querySelector(`moz-option[value="${langTag}"]`) + ); + return option?.hasAttribute("disabled") ?? false; + }, + + /** + * Set the add button enabled state for always-translate languages. + * + * @param {boolean} isDisabled + */ + setAlwaysTranslateAddButtonDisabledState(isDisabled) { + if (!this.elements?.alwaysTranslateLanguagesButton) { + return; + } + + const wasDisabled = this.elements.alwaysTranslateLanguagesButton.disabled; + this.elements.alwaysTranslateLanguagesButton.disabled = isDisabled; + if (wasDisabled !== isDisabled) { + dispatchTestEvent( + isDisabled + ? "AlwaysTranslateLanguagesAddButtonDisabled" + : "AlwaysTranslateLanguagesAddButtonEnabled" + ); + } + }, + + /** + * Update the add button enabled state for always-translate languages. + */ + updateAlwaysTranslateAddButtonDisabledState() { + this.setAlwaysTranslateAddButtonDisabledState( + this.shouldDisableAlwaysTranslateAddButton() + ); }, /** @@ -743,7 +830,7 @@ const TranslationsSettings = { * * @param {string} langTag */ - removeAlwaysLanguage(langTag) { + removeAlwaysTranslateLanguage(langTag) { TranslationsParent.removeLangTagFromPref( langTag, ALWAYS_TRANSLATE_LANGS_PREF @@ -777,17 +864,18 @@ const TranslationsSettings = { /** * Reset the dropdown back to the placeholder value and underlying setting state. */ - async resetAlwaysSelect() { + async resetAlwaysTranslateSelect() { await this.resetSelect( this.elements?.alwaysTranslateLanguagesSelect, "translationsAlwaysTranslateLanguagesSelect" ); + this.updateAlwaysTranslateAddButtonDisabledState(); }, /** * Refresh the rendered list of always-translate languages to match prefs. */ - async refreshAlwaysLanguages() { + async refreshAlwaysTranslateLanguages() { if (!this.elements?.alwaysTranslateLanguagesGroup) { return; } @@ -796,9 +884,9 @@ const TranslationsSettings = { TranslationsParent.getAlwaysTranslateLanguages?.() ?? [] ); - if (this.alwaysLanguageTags) { + if (this.alwaysTranslateLanguageTags) { for (const langTag of langTags) { - if (this.alwaysLanguageTags.has(langTag)) { + if (this.alwaysTranslateLanguageTags.has(langTag)) { continue; } TranslationsParent.removeLangTagFromPref( @@ -808,10 +896,10 @@ const TranslationsSettings = { } } - this.alwaysLanguageTags = new Set(langTags); + this.alwaysTranslateLanguageTags = new Set(langTags); - this.renderAlwaysLanguages(langTags); - await this.updateAlwaysSelectOptionState(); + this.renderAlwaysTranslateLanguages(langTags); + await this.updateAlwaysTranslateSelectOptionState(); }, /** @@ -819,12 +907,12 @@ const TranslationsSettings = { * * @param {string[]} langTags */ - renderAlwaysLanguages(langTags) { + renderAlwaysTranslateLanguages(langTags) { const { alwaysTranslateLanguagesGroup, alwaysTranslateLanguagesNoneRow } = this.elements; for (const item of alwaysTranslateLanguagesGroup.querySelectorAll( - `.${ALWAYS_LANGUAGE_ITEM_CLASS}` + `.${ALWAYS_TRANSLATE_LANGUAGE_ITEM_CLASS}` )) { item.remove(); } @@ -868,12 +956,12 @@ const TranslationsSettings = { "iconsrc", "chrome://global/skin/icons/delete.svg" ); - removeButton.classList.add(ALWAYS_LANGUAGE_REMOVE_BUTTON_CLASS); + removeButton.classList.add(ALWAYS_TRANSLATE_LANGUAGE_REMOVE_BUTTON_CLASS); removeButton.dataset.langTag = langTag; removeButton.setAttribute("aria-label", label); const item = document.createElement("moz-box-item"); - item.classList.add(ALWAYS_LANGUAGE_ITEM_CLASS); + item.classList.add(ALWAYS_TRANSLATE_LANGUAGE_ITEM_CLASS); item.setAttribute("label", label); item.dataset.langTag = langTag; item.appendChild(removeButton); @@ -891,7 +979,7 @@ const TranslationsSettings = { } } - dispatchTestEvent("AlwaysLanguagesRendered", { + dispatchTestEvent("AlwaysTranslateLanguagesRendered", { languages: langTags, count: langTags.length, }); @@ -924,7 +1012,7 @@ const TranslationsSettings = { /** * Populate the select options for the supported source languages. */ - async buildAlwaysSelectOptions() { + async buildAlwaysTranslateSelectOptions() { const select = this.elements?.alwaysTranslateLanguagesSelect; if (!select || !this.supportedLanguages?.sourceLanguages?.length) { return; @@ -955,13 +1043,13 @@ const TranslationsSettings = { select.appendChild(option); } - await this.resetAlwaysSelect(); + await this.resetAlwaysTranslateSelect(); }, /** * Disable already-added languages in the select so they cannot be re-added. */ - async updateAlwaysSelectOptionState() { + async updateAlwaysTranslateSelectOptionState() { const select = this.elements?.alwaysTranslateLanguagesSelect; if (!select) { return; @@ -972,10 +1060,10 @@ const TranslationsSettings = { if (!value) { continue; } - option.disabled = this.alwaysLanguageTags.has(value); + option.disabled = this.alwaysTranslateLanguageTags.has(value); } - await this.resetAlwaysSelect(); + await this.resetAlwaysTranslateSelect(); dispatchTestEvent("AlwaysTranslateLanguagesSelectOptionsUpdated"); }, @@ -1879,6 +1967,10 @@ const TranslationsSettings = { "click", this ); + this.elements?.alwaysTranslateLanguagesButton?.removeEventListener( + "click", + this + ); this.elements?.neverTranslateLanguagesSelect?.removeEventListener( "change", this diff --git a/browser/components/translations/tests/browser/browser_translations_about_settings_subpage_always_translate_langs_a11y.js b/browser/components/translations/tests/browser/browser_translations_about_settings_subpage_always_translate_langs_a11y.js @@ -47,7 +47,7 @@ add_task(async function test_always_translate_languages_keyboard_activation() { info("Getting first remove button"); const firstRemoveButton = document.querySelector( - ".translations-always-remove-button" + ".translations-always-translate-remove-button" ); ok(firstRemoveButton, "First remove button should exist"); @@ -63,7 +63,7 @@ add_task(async function test_always_translate_languages_keyboard_activation() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.AlwaysLanguagesRendered], + [TranslationsSettingsTestUtils.Events.AlwaysTranslateLanguagesRendered], ], }, async () => { @@ -135,12 +135,14 @@ add_task(async function test_always_translate_languages_accessibility() { }); info("Getting language items and remove buttons"); - const items = document.querySelectorAll(".translations-always-language-item"); + const items = document.querySelectorAll( + ".translations-always-translate-language-item" + ); is(items.length, 2, "Should have 2 language items"); info("Verifying remove buttons have accessible labels"); const removeButtons = document.querySelectorAll( - ".translations-always-remove-button" + ".translations-always-translate-remove-button" ); is(removeButtons.length, 2, "Should have 2 remove buttons"); diff --git a/browser/components/translations/tests/browser/browser_translations_about_settings_subpage_always_translate_langs_basic.js b/browser/components/translations/tests/browser/browser_translations_about_settings_subpage_always_translate_langs_basic.js @@ -123,7 +123,7 @@ add_task(async function test_always_translate_languages_dropdown_state() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.AlwaysLanguagesRendered], + [TranslationsSettingsTestUtils.Events.AlwaysTranslateLanguagesRendered], [ TranslationsSettingsTestUtils.Events .AlwaysTranslateLanguagesSelectOptionsUpdated, diff --git a/browser/components/translations/tests/browser/browser_translations_about_settings_subpage_always_translate_langs_modify.js b/browser/components/translations/tests/browser/browser_translations_about_settings_subpage_always_translate_langs_modify.js @@ -49,7 +49,7 @@ add_task(async function test_always_translate_languages_add_and_remove() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.AlwaysLanguagesRendered], + [TranslationsSettingsTestUtils.Events.AlwaysTranslateLanguagesRendered], [ TranslationsSettingsTestUtils.Events .AlwaysTranslateLanguagesEmptyStateHidden, @@ -78,7 +78,7 @@ add_task(async function test_always_translate_languages_add_and_remove() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.AlwaysLanguagesRendered], + [TranslationsSettingsTestUtils.Events.AlwaysTranslateLanguagesRendered], ], }, async () => { @@ -100,7 +100,7 @@ add_task(async function test_always_translate_languages_add_and_remove() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.AlwaysLanguagesRendered], + [TranslationsSettingsTestUtils.Events.AlwaysTranslateLanguagesRendered], ], }, async () => { @@ -122,7 +122,7 @@ add_task(async function test_always_translate_languages_add_and_remove() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.AlwaysLanguagesRendered], + [TranslationsSettingsTestUtils.Events.AlwaysTranslateLanguagesRendered], ], }, async () => { @@ -147,7 +147,7 @@ add_task(async function test_always_translate_languages_add_and_remove() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.AlwaysLanguagesRendered], + [TranslationsSettingsTestUtils.Events.AlwaysTranslateLanguagesRendered], ], }, async () => { @@ -172,7 +172,7 @@ add_task(async function test_always_translate_languages_add_and_remove() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.AlwaysLanguagesRendered], + [TranslationsSettingsTestUtils.Events.AlwaysTranslateLanguagesRendered], [ TranslationsSettingsTestUtils.Events .AlwaysTranslateLanguagesEmptyStateShown, @@ -248,7 +248,7 @@ add_task(async function test_always_translate_languages_invalid_tags() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.AlwaysLanguagesRendered], + [TranslationsSettingsTestUtils.Events.AlwaysTranslateLanguagesRendered], ], }, async () => { @@ -333,7 +333,7 @@ add_task(async function test_always_translate_languages_stealing() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.AlwaysLanguagesRendered], + [TranslationsSettingsTestUtils.Events.AlwaysTranslateLanguagesRendered], [ TranslationsSettingsTestUtils.Events .AlwaysTranslateLanguagesEmptyStateHidden, @@ -368,7 +368,7 @@ add_task(async function test_always_translate_languages_stealing() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.AlwaysLanguagesRendered], + [TranslationsSettingsTestUtils.Events.AlwaysTranslateLanguagesRendered], ], }, async () => { @@ -398,7 +398,7 @@ add_task(async function test_always_translate_languages_stealing() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.AlwaysLanguagesRendered], + [TranslationsSettingsTestUtils.Events.AlwaysTranslateLanguagesRendered], ], }, async () => { diff --git a/browser/components/translations/tests/browser/browser_translations_about_settings_subpage_always_translate_langs_observe.js b/browser/components/translations/tests/browser/browser_translations_about_settings_subpage_always_translate_langs_observe.js @@ -49,7 +49,7 @@ add_task(async function test_always_translate_languages_observe_pref_changes() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.AlwaysLanguagesRendered], + [TranslationsSettingsTestUtils.Events.AlwaysTranslateLanguagesRendered], [ TranslationsSettingsTestUtils.Events .AlwaysTranslateLanguagesEmptyStateHidden, @@ -71,7 +71,7 @@ add_task(async function test_always_translate_languages_observe_pref_changes() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.AlwaysLanguagesRendered], + [TranslationsSettingsTestUtils.Events.AlwaysTranslateLanguagesRendered], ], }, async () => { @@ -89,7 +89,7 @@ add_task(async function test_always_translate_languages_observe_pref_changes() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.AlwaysLanguagesRendered], + [TranslationsSettingsTestUtils.Events.AlwaysTranslateLanguagesRendered], ], }, async () => { @@ -107,7 +107,7 @@ add_task(async function test_always_translate_languages_observe_pref_changes() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.AlwaysLanguagesRendered], + [TranslationsSettingsTestUtils.Events.AlwaysTranslateLanguagesRendered], [ TranslationsSettingsTestUtils.Events .AlwaysTranslateLanguagesEmptyStateShown, @@ -181,7 +181,7 @@ add_task(async function test_always_translate_languages_simulated_stealing() { { expected: [ [TranslationsSettingsTestUtils.Events.NeverLanguagesRendered], - [TranslationsSettingsTestUtils.Events.AlwaysLanguagesRendered], + [TranslationsSettingsTestUtils.Events.AlwaysTranslateLanguagesRendered], [ TranslationsSettingsTestUtils.Events .AlwaysTranslateLanguagesEmptyStateHidden, @@ -217,7 +217,7 @@ add_task(async function test_always_translate_languages_simulated_stealing() { TranslationsSettingsTestUtils.Events .NeverTranslateLanguagesEmptyStateShown, ], - [TranslationsSettingsTestUtils.Events.AlwaysLanguagesRendered], + [TranslationsSettingsTestUtils.Events.AlwaysTranslateLanguagesRendered], ], }, async () => { diff --git a/browser/components/translations/tests/browser/browser_translations_about_settings_subpage_never_translate_langs_observe.js b/browser/components/translations/tests/browser/browser_translations_about_settings_subpage_never_translate_langs_observe.js @@ -181,7 +181,7 @@ add_task(async function test_never_translate_languages_simulated_stealing() { TranslationsSettingsTestUtils.Events .NeverTranslateLanguagesEmptyStateHidden, ], - [TranslationsSettingsTestUtils.Events.AlwaysLanguagesRendered], + [TranslationsSettingsTestUtils.Events.AlwaysTranslateLanguagesRendered], ], }, async () => { @@ -209,7 +209,7 @@ add_task(async function test_never_translate_languages_simulated_stealing() { { expected: [ [TranslationsSettingsTestUtils.Events.NeverLanguagesRendered], - [TranslationsSettingsTestUtils.Events.AlwaysLanguagesRendered], + [TranslationsSettingsTestUtils.Events.AlwaysTranslateLanguagesRendered], [ TranslationsSettingsTestUtils.Events .AlwaysTranslateLanguagesEmptyStateShown, diff --git a/browser/locales/en-US/browser/preferences/preferences.ftl b/browser/locales/en-US/browser/preferences/preferences.ftl @@ -459,6 +459,10 @@ settings-translations-subpage-never-translate-sites-description = settings-translations-subpage-language-select-option = .label = Add language +settings-translations-subpage-language-add-button = + .aria-label = Add language + .title = Add language + settings-translations-subpage-download-languages-header = .label = Download languages diff --git a/toolkit/components/translations/tests/browser/shared-head.js b/toolkit/components/translations/tests/browser/shared-head.js @@ -441,8 +441,8 @@ class TranslationsSettingsTestUtils { * Static Events class for event name constants. */ static Events = class Events { - static AlwaysLanguagesRendered = - "TranslationsSettingsTest:AlwaysLanguagesRendered"; + static AlwaysTranslateLanguagesRendered = + "TranslationsSettingsTest:AlwaysTranslateLanguagesRendered"; static NeverLanguagesRendered = "TranslationsSettingsTest:NeverLanguagesRendered"; static NeverSitesRendered = "TranslationsSettingsTest:NeverSitesRendered"; @@ -465,6 +465,10 @@ class TranslationsSettingsTestUtils { "TranslationsSettingsTest:DownloadedLanguagesEmptyStateShown"; static DownloadedLanguagesEmptyStateHidden = "TranslationsSettingsTest:DownloadedLanguagesEmptyStateHidden"; + static AlwaysTranslateLanguagesAddButtonEnabled = + "TranslationsSettingsTest:AlwaysTranslateLanguagesAddButtonEnabled"; + static AlwaysTranslateLanguagesAddButtonDisabled = + "TranslationsSettingsTest:AlwaysTranslateLanguagesAddButtonDisabled"; static AlwaysTranslateLanguagesSelectOptionsUpdated = "TranslationsSettingsTest:AlwaysTranslateLanguagesSelectOptionsUpdated"; @@ -720,6 +724,17 @@ class TranslationsSettingsTestUtils { } /** + * Gets the always-translate languages add button. + * + * @returns {HTMLButtonElement|null} + */ + getAlwaysTranslateLanguagesAddButton() { + return this.document.getElementById( + "translationsAlwaysTranslateLanguagesButton" + ); + } + + /** * Gets the never-translate languages select element. * * @returns {HTMLSelectElement|null} @@ -1122,6 +1137,28 @@ class TranslationsSettingsTestUtils { const dropdown = this.getAlwaysTranslateLanguagesSelect(); dropdown.value = langTag; dropdown.dispatchEvent(new Event("change", { bubbles: true })); + + const addButton = await waitForCondition( + () => this.getAlwaysTranslateLanguagesAddButton(), + "Waiting for always-translate add button" + ); + if (addButton.disabled) { + const addButtonEnabled = this.waitForEvent( + TranslationsSettingsTestUtils.Events + .AlwaysTranslateLanguagesAddButtonEnabled + ); + await addButtonEnabled; + } + addButton.click(); + + const addedLanguage = this.waitForAlwaysTranslateLanguageItem(langTag); + const addButtonDisabledPromise = addButton.disabled + ? Promise.resolve() + : this.waitForEvent( + TranslationsSettingsTestUtils.Events + .AlwaysTranslateLanguagesAddButtonDisabled + ); + await Promise.all([addedLanguage, addButtonDisabledPromise]); } /** @@ -1132,7 +1169,7 @@ class TranslationsSettingsTestUtils { */ async removeAlwaysTranslateLanguage(langTag) { const removeButton = this.document.querySelector( - `[data-lang-tag="${langTag}"].translations-always-remove-button` + `[data-lang-tag="${langTag}"].translations-always-translate-remove-button` ); if (!removeButton) { throw new Error(`Remove button not found for language: ${langTag}`); @@ -1154,7 +1191,7 @@ class TranslationsSettingsTestUtils { return TestUtils.waitForCondition( () => this.document.querySelector( - `[data-lang-tag="${langTag}"].translations-always-language-item` + `[data-lang-tag="${langTag}"].translations-always-translate-language-item` ), `Waiting for always-translate language item: ${langTag}` ); @@ -1170,7 +1207,7 @@ class TranslationsSettingsTestUtils { */ async assertAlwaysTranslateLanguages({ languages, count }) { const items = this.document.querySelectorAll( - ".translations-always-language-item" + ".translations-always-translate-language-item" ); if (count !== undefined) { @@ -1202,7 +1239,7 @@ class TranslationsSettingsTestUtils { */ async assertAlwaysTranslateLanguagesOrder({ languages }) { const items = this.document.querySelectorAll( - ".translations-always-language-item" + ".translations-always-translate-language-item" ); const actualLanguages = Array.from(items).map(item => item.dataset.langTag); Assert.deepEqual(