commit fe9a7f0ec0e7364f02813905230f8b3808e9b4e9 parent 19ce23f408bb2eebf6646004f420aa7cef66d28d Author: Erik Nordin <enordin@mozilla.com> Date: Thu, 18 Dec 2025 01:17:28 +0000 Bug 2002127 - Part 16: Use Button Pattern for NTL r=translations-reviewers,hjones This commit updates the Never 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/D274828 Diffstat:
11 files changed, 258 insertions(+), 95 deletions(-)
diff --git a/browser/components/preferences/main.js b/browser/components/preferences/main.js @@ -757,6 +757,10 @@ Preferences.addSetting({ }); Preferences.addSetting({ + id: "translationsNeverTranslateLanguagesButton", +}); + +Preferences.addSetting({ id: "translationsNeverTranslateLanguagesGroup", }); @@ -3933,6 +3937,16 @@ SettingGroupManager.registerGroups({ }, ], }, + { + id: "translationsNeverTranslateLanguagesButton", + 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 @@ -23,6 +23,7 @@ export interface TranslationsSettingsElements { alwaysTranslateLanguagesNoneRow: HTMLElement; neverTranslateLanguagesGroup: HTMLElement; neverTranslateLanguagesSelect: HTMLSelectElement; + neverTranslateLanguagesButton: HTMLButtonElement; neverTranslateLanguagesNoneRow: HTMLElement; neverTranslateSitesGroup: HTMLElement; neverTranslateSitesRow: HTMLElement; diff --git a/browser/components/preferences/translations.js b/browser/components/preferences/translations.js @@ -35,13 +35,17 @@ const ALWAYS_TRANSLATE_LANGUAGE_REMOVE_BUTTON_CLASS = "translations-always-translate-remove-button"; /** @type {string} */ -const NEVER_LANGUAGE_ITEM_CLASS = "translations-never-language-item"; +const NEVER_TRANSLATE_LANGUAGE_ITEM_CLASS = + "translations-never-translate-language-item"; /** @type {string} */ -const NEVER_LANGUAGE_REMOVE_BUTTON_CLASS = "translations-never-remove-button"; +const NEVER_TRANSLATE_LANGUAGE_REMOVE_BUTTON_CLASS = + "translations-never-translate-remove-button"; /** @type {string} */ -const NEVER_SITE_ITEM_CLASS = "translations-never-site-item"; +const NEVER_TRANSLATE_SITE_ITEM_CLASS = + "translations-never-translate-site-item"; /** @type {string} */ -const NEVER_SITE_REMOVE_BUTTON_CLASS = "translations-never-site-remove-button"; +const NEVER_TRANSLATE_SITE_REMOVE_BUTTON_CLASS = + "translations-never-translate-site-remove-button"; /** @type {string} */ const DOWNLOAD_LANGUAGE_ITEM_CLASS = "translations-download-language-item"; @@ -151,14 +155,14 @@ const TranslationsSettings = { * * @type {Set<string>} */ - neverLanguageTags: new Set(), + neverTranslateLanguageTags: new Set(), /** * Current never-translate site origins. * * @type {Set<string>} */ - neverSiteOrigins: new Set(), + neverTranslateSiteOrigins: new Set(), /** * Language tags with downloaded translation models. @@ -220,9 +224,7 @@ const TranslationsSettings = { } else if ( event.target === this.elements?.neverTranslateLanguagesSelect ) { - await this.onNeverLanguageChosen( - /** @type {HTMLSelectElement} */ (event.target).value - ); + this.onNeverTranslateLanguageSelectionChanged(); } else if (event.target === this.elements?.downloadLanguagesSelect) { this.onDownloadSelectionChanged(); } @@ -238,6 +240,15 @@ const TranslationsSettings = { ); break; } + if ( + target === this.elements?.neverTranslateLanguagesButton || + target.closest?.("#translationsNeverTranslateLanguagesButton") + ) { + await this.onNeverTranslateLanguageChosen( + this.elements?.neverTranslateLanguagesSelect?.value ?? "" + ); + break; + } if ( target === this.elements?.downloadLanguagesButton || @@ -292,18 +303,18 @@ const TranslationsSettings = { } const neverRemoveButton = /** @type {HTMLElement|null} */ ( - target.closest?.(`.${NEVER_LANGUAGE_REMOVE_BUTTON_CLASS}`) + target.closest?.(`.${NEVER_TRANSLATE_LANGUAGE_REMOVE_BUTTON_CLASS}`) ); if (neverRemoveButton?.dataset.langTag) { - this.removeNeverLanguage(neverRemoveButton.dataset.langTag); + this.removeNeverTranslateLanguage(neverRemoveButton.dataset.langTag); break; } const neverSiteRemoveButton = /** @type {HTMLElement|null} */ ( - target.closest?.(`.${NEVER_SITE_REMOVE_BUTTON_CLASS}`) + target.closest?.(`.${NEVER_TRANSLATE_SITE_REMOVE_BUTTON_CLASS}`) ); if (neverSiteRemoveButton?.dataset.origin) { - this.removeNeverSite(neverSiteRemoveButton.dataset.origin); + this.removeNeverTranslateSite(neverSiteRemoveButton.dataset.origin); } break; } @@ -325,7 +336,7 @@ const TranslationsSettings = { if (data === ALWAYS_TRANSLATE_LANGS_PREF) { this.refreshAlwaysTranslateLanguages().catch(console.error); } else if (data === NEVER_TRANSLATE_LANGS_PREF) { - this.refreshNeverLanguages().catch(console.error); + this.refreshNeverTranslateLanguages().catch(console.error); } } else if (topic === "perm-changed") { this.handlePermissionChange(subject, data); @@ -346,8 +357,8 @@ const TranslationsSettings = { if (this.initPromise) { await this.initPromise; await this.refreshAlwaysTranslateLanguages(); - await this.refreshNeverLanguages(); - this.refreshNeverSites(); + await this.refreshNeverTranslateLanguages(); + this.refreshNeverTranslateSites(); await this.refreshDownloadedLanguages(); this.dispatchInitializedTestEvent(); return; @@ -355,8 +366,8 @@ const TranslationsSettings = { if (this.initialized) { await this.refreshAlwaysTranslateLanguages(); - await this.refreshNeverLanguages(); - this.refreshNeverSites(); + await this.refreshNeverTranslateLanguages(); + this.refreshNeverTranslateSites(); await this.refreshDownloadedLanguages(); this.dispatchInitializedTestEvent(); return; @@ -423,6 +434,7 @@ const TranslationsSettings = { !this.elements?.alwaysTranslateLanguagesNoneRow || !this.elements?.neverTranslateLanguagesGroup || !this.elements?.neverTranslateLanguagesSelect || + !this.elements?.neverTranslateLanguagesButton || !this.elements?.neverTranslateLanguagesNoneRow || !this.elements?.neverTranslateSitesGroup || !this.elements?.downloadLanguagesGroup || @@ -450,6 +462,7 @@ const TranslationsSettings = { this.elements.alwaysTranslateLanguagesSelect.disabled = true; this.elements.alwaysTranslateLanguagesButton.disabled = true; this.elements.neverTranslateLanguagesSelect.disabled = true; + this.elements.neverTranslateLanguagesButton.disabled = true; this.elements.downloadLanguagesSelect.disabled = true; this.setDownloadButtonDisabledState(true); this.dispatchInitializedTestEvent(); @@ -459,11 +472,12 @@ const TranslationsSettings = { this.elements.alwaysTranslateLanguagesSelect.disabled = false; this.elements.alwaysTranslateLanguagesButton.disabled = true; this.elements.neverTranslateLanguagesSelect.disabled = false; + this.elements.neverTranslateLanguagesButton.disabled = true; this.elements.downloadLanguagesSelect.disabled = false; this.resetDownloadSelect(); this.setDownloadButtonDisabledState(true); await this.buildAlwaysTranslateSelectOptions(); - await this.buildNeverSelectOptions(); + await this.buildNeverTranslateSelectOptions(); await this.buildDownloadSelectOptions(); await this.renderDownloadLanguages(); @@ -480,6 +494,7 @@ const TranslationsSettings = { "change", this ); + this.elements.neverTranslateLanguagesButton.addEventListener("click", this); this.elements.neverTranslateLanguagesGroup.addEventListener("click", this); this.elements.neverTranslateSitesGroup.addEventListener("click", this); this.elements.downloadLanguagesSelect.addEventListener("change", this); @@ -490,8 +505,8 @@ const TranslationsSettings = { window.addEventListener("unload", this); await this.refreshAlwaysTranslateLanguages(); - await this.refreshNeverLanguages(); - this.refreshNeverSites(); + await this.refreshNeverTranslateLanguages(); + this.refreshNeverTranslateSites(); this.initialized = true; this.dispatchInitializedTestEvent(); @@ -531,6 +546,9 @@ const TranslationsSettings = { neverTranslateLanguagesSelect: /** @type {HTMLSelectElement} */ ( document.getElementById("translationsNeverTranslateLanguagesSelect") ), + neverTranslateLanguagesButton: /** @type {HTMLButtonElement} */ ( + document.getElementById("translationsNeverTranslateLanguagesButton") + ), neverTranslateLanguagesNoneRow: /** @type {HTMLElement} */ ( document.getElementById("translationsNeverTranslateLanguagesNoneRow") ), @@ -1073,8 +1091,14 @@ const TranslationsSettings = { * * @param {string} langTag */ - async onNeverLanguageChosen(langTag) { + async onNeverTranslateLanguageChosen(langTag) { if (!langTag) { + this.updateNeverTranslateAddButtonDisabledState(); + return; + } + + if (this.shouldDisableNeverTranslateAddButton()) { + this.updateNeverTranslateAddButtonDisabledState(); return; } @@ -1083,7 +1107,66 @@ const TranslationsSettings = { langTag, ALWAYS_TRANSLATE_LANGS_PREF ); - await this.resetNeverSelect(); + await this.resetNeverTranslateSelect(); + }, + + /** + * Handle a selection change in the never-translate dropdown. + */ + onNeverTranslateLanguageSelectionChanged() { + this.updateNeverTranslateAddButtonDisabledState(); + }, + + /** + * Whether the add button for never-translate languages should be disabled. + * + * @returns {boolean} + */ + shouldDisableNeverTranslateAddButton() { + const select = this.elements?.neverTranslateLanguagesSelect; + 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 never-translate languages. + * + * @param {boolean} isDisabled + */ + setNeverTranslateAddButtonDisabledState(isDisabled) { + if (!this.elements?.neverTranslateLanguagesButton) { + return; + } + + const wasDisabled = this.elements.neverTranslateLanguagesButton.disabled; + this.elements.neverTranslateLanguagesButton.disabled = isDisabled; + if (wasDisabled !== isDisabled) { + dispatchTestEvent( + isDisabled + ? "NeverTranslateLanguagesAddButtonDisabled" + : "NeverTranslateLanguagesAddButtonEnabled" + ); + } + }, + + /** + * Update the add button enabled state for never-translate languages. + */ + updateNeverTranslateAddButtonDisabledState() { + this.setNeverTranslateAddButtonDisabledState( + this.shouldDisableNeverTranslateAddButton() + ); }, /** @@ -1091,7 +1174,7 @@ const TranslationsSettings = { * * @param {string} langTag */ - removeNeverLanguage(langTag) { + removeNeverTranslateLanguage(langTag) { TranslationsParent.removeLangTagFromPref( langTag, NEVER_TRANSLATE_LANGS_PREF @@ -1101,17 +1184,18 @@ const TranslationsSettings = { /** * Reset the dropdown back to the placeholder value and underlying setting state. */ - async resetNeverSelect() { + async resetNeverTranslateSelect() { await this.resetSelect( this.elements?.neverTranslateLanguagesSelect, "translationsNeverTranslateLanguagesSelect" ); + this.updateNeverTranslateAddButtonDisabledState(); }, /** * Refresh the rendered list of never-translate languages to match prefs. */ - async refreshNeverLanguages() { + async refreshNeverTranslateLanguages() { if (!this.elements?.neverTranslateLanguagesGroup) { return; } @@ -1119,10 +1203,10 @@ const TranslationsSettings = { const langTags = Array.from( TranslationsParent.getNeverTranslateLanguages?.() ?? [] ); - this.neverLanguageTags = new Set(langTags); + this.neverTranslateLanguageTags = new Set(langTags); - this.renderNeverLanguages(langTags); - await this.updateNeverSelectOptionState(); + this.renderNeverTranslateLanguages(langTags); + await this.updateNeverTranslateSelectOptionState(); }, /** @@ -1130,12 +1214,12 @@ const TranslationsSettings = { * * @param {string[]} langTags */ - renderNeverLanguages(langTags) { + renderNeverTranslateLanguages(langTags) { const { neverTranslateLanguagesGroup, neverTranslateLanguagesNoneRow } = this.elements; for (const item of neverTranslateLanguagesGroup.querySelectorAll( - `.${NEVER_LANGUAGE_ITEM_CLASS}` + `.${NEVER_TRANSLATE_LANGUAGE_ITEM_CLASS}` )) { item.remove(); } @@ -1175,12 +1259,12 @@ const TranslationsSettings = { "iconsrc", "chrome://global/skin/icons/delete.svg" ); - removeButton.classList.add(NEVER_LANGUAGE_REMOVE_BUTTON_CLASS); + removeButton.classList.add(NEVER_TRANSLATE_LANGUAGE_REMOVE_BUTTON_CLASS); removeButton.dataset.langTag = langTag; removeButton.setAttribute("aria-label", label); const item = document.createElement("moz-box-item"); - item.classList.add(NEVER_LANGUAGE_ITEM_CLASS); + item.classList.add(NEVER_TRANSLATE_LANGUAGE_ITEM_CLASS); item.setAttribute("label", label); item.dataset.langTag = langTag; item.appendChild(removeButton); @@ -1198,7 +1282,7 @@ const TranslationsSettings = { } } - dispatchTestEvent("NeverLanguagesRendered", { + dispatchTestEvent("NeverTranslateLanguagesRendered", { languages: langTags, count: langTags.length, }); @@ -1215,7 +1299,7 @@ const TranslationsSettings = { /** * Populate the select options for the supported source languages. */ - async buildNeverSelectOptions() { + async buildNeverTranslateSelectOptions() { const select = this.elements?.neverTranslateLanguagesSelect; if (!select || !this.supportedLanguages?.sourceLanguages?.length) { return; @@ -1246,13 +1330,13 @@ const TranslationsSettings = { select.appendChild(option); } - await this.resetNeverSelect(); + await this.resetNeverTranslateSelect(); }, /** * Disable already-added languages in the select so they cannot be re-added. */ - async updateNeverSelectOptionState() { + async updateNeverTranslateSelectOptionState() { const select = this.elements?.neverTranslateLanguagesSelect; if (!select) { return; @@ -1263,10 +1347,10 @@ const TranslationsSettings = { if (!value) { continue; } - option.disabled = this.neverLanguageTags.has(value); + option.disabled = this.neverTranslateLanguageTags.has(value); } - await this.resetNeverSelect(); + await this.resetNeverTranslateSelect(); dispatchTestEvent("NeverTranslateLanguagesSelectOptionsUpdated"); }, @@ -1274,7 +1358,7 @@ const TranslationsSettings = { /** * Refresh the rendered list of never-translate sites. */ - refreshNeverSites() { + refreshNeverTranslateSites() { if (!this.elements?.neverTranslateSitesGroup) { return; } @@ -1287,8 +1371,8 @@ const TranslationsSettings = { console.error("Failed to list never translate sites", error); } - this.neverSiteOrigins = new Set(siteOrigins); - this.renderNeverSites(siteOrigins); + this.neverTranslateSiteOrigins = new Set(siteOrigins); + this.renderNeverTranslateSites(siteOrigins); }, /** @@ -1296,7 +1380,7 @@ const TranslationsSettings = { * * @param {string[]} siteOrigins */ - renderNeverSites(siteOrigins) { + renderNeverTranslateSites(siteOrigins) { const { neverTranslateSitesGroup, neverTranslateSitesNoneRow } = this.elements ?? {}; if (!neverTranslateSitesGroup) { @@ -1304,7 +1388,7 @@ const TranslationsSettings = { } for (const item of neverTranslateSitesGroup.querySelectorAll( - `.${NEVER_SITE_ITEM_CLASS}` + `.${NEVER_TRANSLATE_SITE_ITEM_CLASS}` )) { item.remove(); } @@ -1337,12 +1421,12 @@ const TranslationsSettings = { "iconsrc", "chrome://global/skin/icons/delete.svg" ); - removeButton.classList.add(NEVER_SITE_REMOVE_BUTTON_CLASS); + removeButton.classList.add(NEVER_TRANSLATE_SITE_REMOVE_BUTTON_CLASS); removeButton.dataset.origin = origin; removeButton.setAttribute("aria-label", origin); const item = document.createElement("moz-box-item"); - item.classList.add(NEVER_SITE_ITEM_CLASS); + item.classList.add(NEVER_TRANSLATE_SITE_ITEM_CLASS); item.setAttribute("label", origin); item.dataset.origin = origin; item.appendChild(removeButton); @@ -1356,7 +1440,7 @@ const TranslationsSettings = { } } - dispatchTestEvent("NeverSitesRendered", { + dispatchTestEvent("NeverTranslateSitesRendered", { sites: siteOrigins, count: siteOrigins.length, }); @@ -1375,8 +1459,8 @@ const TranslationsSettings = { * * @param {string} origin */ - removeNeverSite(origin) { - if (!origin || !this.neverSiteOrigins.has(origin)) { + removeNeverTranslateSite(origin) { + if (!origin || !this.neverTranslateSiteOrigins.has(origin)) { return; } @@ -1387,7 +1471,7 @@ const TranslationsSettings = { return; } - this.refreshNeverSites(); + this.refreshNeverTranslateSites(); }, /** @@ -1934,8 +2018,8 @@ const TranslationsSettings = { */ handlePermissionChange(subject, data) { if (data === "cleared") { - this.neverSiteOrigins = new Set(); - this.renderNeverSites([]); + this.neverTranslateSiteOrigins = new Set(); + this.renderNeverTranslateSites([]); return; } @@ -1944,7 +2028,7 @@ const TranslationsSettings = { return; } - this.refreshNeverSites(); + this.refreshNeverTranslateSites(); }, /** @@ -1975,6 +2059,10 @@ const TranslationsSettings = { "change", this ); + this.elements?.neverTranslateLanguagesButton?.removeEventListener( + "click", + this + ); this.elements?.neverTranslateLanguagesGroup?.removeEventListener( "click", this 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 @@ -180,7 +180,7 @@ add_task(async function test_always_translate_languages_simulated_stealing() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.NeverLanguagesRendered], + [TranslationsSettingsTestUtils.Events.NeverTranslateLanguagesRendered], [TranslationsSettingsTestUtils.Events.AlwaysTranslateLanguagesRendered], [ TranslationsSettingsTestUtils.Events @@ -212,7 +212,7 @@ add_task(async function test_always_translate_languages_simulated_stealing() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.NeverLanguagesRendered], + [TranslationsSettingsTestUtils.Events.NeverTranslateLanguagesRendered], [ TranslationsSettingsTestUtils.Events .NeverTranslateLanguagesEmptyStateShown, diff --git a/browser/components/translations/tests/browser/browser_translations_about_settings_subpage_never_translate_langs_a11y.js b/browser/components/translations/tests/browser/browser_translations_about_settings_subpage_never_translate_langs_a11y.js @@ -47,7 +47,7 @@ add_task(async function test_never_translate_languages_keyboard_activation() { info("Getting first remove button"); const firstRemoveButton = document.querySelector( - ".translations-never-remove-button" + ".translations-never-translate-remove-button" ); ok(firstRemoveButton, "First remove button should exist"); @@ -62,7 +62,9 @@ add_task(async function test_never_translate_languages_keyboard_activation() { info("Pressing Enter to remove first language"); await translationsSettingsTestUtils.assertEvents( { - expected: [[TranslationsSettingsTestUtils.Events.NeverLanguagesRendered]], + expected: [ + [TranslationsSettingsTestUtils.Events.NeverTranslateLanguagesRendered], + ], }, async () => { const prefChanged = TestUtils.waitForPrefChange( @@ -133,12 +135,14 @@ add_task(async function test_never_translate_languages_accessibility() { }); info("Getting language items and remove buttons"); - const items = document.querySelectorAll(".translations-never-language-item"); + const items = document.querySelectorAll( + ".translations-never-translate-language-item" + ); is(items.length, 2, "Should have 2 language items"); info("Verifying remove buttons have accessible labels"); const removeButtons = document.querySelectorAll( - ".translations-never-remove-button" + ".translations-never-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_never_translate_langs_basic.js b/browser/components/translations/tests/browser/browser_translations_about_settings_subpage_never_translate_langs_basic.js @@ -123,7 +123,7 @@ add_task(async function test_never_translate_languages_dropdown_state() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.NeverLanguagesRendered], + [TranslationsSettingsTestUtils.Events.NeverTranslateLanguagesRendered], [ TranslationsSettingsTestUtils.Events .NeverTranslateLanguagesSelectOptionsUpdated, diff --git a/browser/components/translations/tests/browser/browser_translations_about_settings_subpage_never_translate_langs_modify.js b/browser/components/translations/tests/browser/browser_translations_about_settings_subpage_never_translate_langs_modify.js @@ -49,7 +49,7 @@ add_task(async function test_never_translate_languages_add_and_remove() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.NeverLanguagesRendered], + [TranslationsSettingsTestUtils.Events.NeverTranslateLanguagesRendered], [ TranslationsSettingsTestUtils.Events .NeverTranslateLanguagesEmptyStateHidden, @@ -77,7 +77,9 @@ add_task(async function test_never_translate_languages_add_and_remove() { info("Adding French (fr) via dropdown"); await translationsSettingsTestUtils.assertEvents( { - expected: [[TranslationsSettingsTestUtils.Events.NeverLanguagesRendered]], + expected: [ + [TranslationsSettingsTestUtils.Events.NeverTranslateLanguagesRendered], + ], }, async () => { const prefChanged = TestUtils.waitForPrefChange( @@ -97,7 +99,9 @@ add_task(async function test_never_translate_languages_add_and_remove() { info("Adding Ukrainian (uk) via dropdown"); await translationsSettingsTestUtils.assertEvents( { - expected: [[TranslationsSettingsTestUtils.Events.NeverLanguagesRendered]], + expected: [ + [TranslationsSettingsTestUtils.Events.NeverTranslateLanguagesRendered], + ], }, async () => { const prefChanged = TestUtils.waitForPrefChange( @@ -117,7 +121,9 @@ add_task(async function test_never_translate_languages_add_and_remove() { info("Removing middle item (French)"); await translationsSettingsTestUtils.assertEvents( { - expected: [[TranslationsSettingsTestUtils.Events.NeverLanguagesRendered]], + expected: [ + [TranslationsSettingsTestUtils.Events.NeverTranslateLanguagesRendered], + ], }, async () => { const prefChanged = TestUtils.waitForPrefChange( @@ -140,7 +146,9 @@ add_task(async function test_never_translate_languages_add_and_remove() { info("Removing Ukrainian"); await translationsSettingsTestUtils.assertEvents( { - expected: [[TranslationsSettingsTestUtils.Events.NeverLanguagesRendered]], + expected: [ + [TranslationsSettingsTestUtils.Events.NeverTranslateLanguagesRendered], + ], }, async () => { const prefChanged = TestUtils.waitForPrefChange( @@ -164,7 +172,7 @@ add_task(async function test_never_translate_languages_add_and_remove() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.NeverLanguagesRendered], + [TranslationsSettingsTestUtils.Events.NeverTranslateLanguagesRendered], [ TranslationsSettingsTestUtils.Events .NeverTranslateLanguagesEmptyStateShown, @@ -239,7 +247,9 @@ add_task(async function test_never_translate_languages_invalid_tags() { info("Adding invalid tags via pref change"); await translationsSettingsTestUtils.assertEvents( { - expected: [[TranslationsSettingsTestUtils.Events.NeverLanguagesRendered]], + expected: [ + [TranslationsSettingsTestUtils.Events.NeverTranslateLanguagesRendered], + ], }, async () => { Services.prefs.setCharPref( @@ -323,7 +333,7 @@ add_task(async function test_never_translate_languages_stealing() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.NeverLanguagesRendered], + [TranslationsSettingsTestUtils.Events.NeverTranslateLanguagesRendered], [ TranslationsSettingsTestUtils.Events .NeverTranslateLanguagesEmptyStateHidden, @@ -360,7 +370,9 @@ add_task(async function test_never_translate_languages_stealing() { info("Adding French to never-translate via UI"); await translationsSettingsTestUtils.assertEvents( { - expected: [[TranslationsSettingsTestUtils.Events.NeverLanguagesRendered]], + expected: [ + [TranslationsSettingsTestUtils.Events.NeverTranslateLanguagesRendered], + ], }, async () => { const neverPrefChanged = TestUtils.waitForPrefChange( @@ -388,7 +400,9 @@ add_task(async function test_never_translate_languages_stealing() { info("Verifying stealing also works via UI for Ukrainian"); await translationsSettingsTestUtils.assertEvents( { - expected: [[TranslationsSettingsTestUtils.Events.NeverLanguagesRendered]], + expected: [ + [TranslationsSettingsTestUtils.Events.NeverTranslateLanguagesRendered], + ], }, async () => { const neverPrefChanged = TestUtils.waitForPrefChange( 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 @@ -49,7 +49,7 @@ add_task(async function test_never_translate_languages_observe_pref_changes() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.NeverLanguagesRendered], + [TranslationsSettingsTestUtils.Events.NeverTranslateLanguagesRendered], [ TranslationsSettingsTestUtils.Events .NeverTranslateLanguagesEmptyStateHidden, @@ -70,7 +70,9 @@ add_task(async function test_never_translate_languages_observe_pref_changes() { info("Adding more languages via pref (es,fr,uk)"); await translationsSettingsTestUtils.assertEvents( { - expected: [[TranslationsSettingsTestUtils.Events.NeverLanguagesRendered]], + expected: [ + [TranslationsSettingsTestUtils.Events.NeverTranslateLanguagesRendered], + ], }, async () => { Services.prefs.setCharPref(NEVER_TRANSLATE_LANGS_PREF, "es,fr,uk"); @@ -86,7 +88,9 @@ add_task(async function test_never_translate_languages_observe_pref_changes() { info("Removing French via pref (es,uk)"); await translationsSettingsTestUtils.assertEvents( { - expected: [[TranslationsSettingsTestUtils.Events.NeverLanguagesRendered]], + expected: [ + [TranslationsSettingsTestUtils.Events.NeverTranslateLanguagesRendered], + ], }, async () => { Services.prefs.setCharPref(NEVER_TRANSLATE_LANGS_PREF, "es,uk"); @@ -103,7 +107,7 @@ add_task(async function test_never_translate_languages_observe_pref_changes() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.NeverLanguagesRendered], + [TranslationsSettingsTestUtils.Events.NeverTranslateLanguagesRendered], [ TranslationsSettingsTestUtils.Events .NeverTranslateLanguagesEmptyStateShown, @@ -176,7 +180,7 @@ add_task(async function test_never_translate_languages_simulated_stealing() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.NeverLanguagesRendered], + [TranslationsSettingsTestUtils.Events.NeverTranslateLanguagesRendered], [ TranslationsSettingsTestUtils.Events .NeverTranslateLanguagesEmptyStateHidden, @@ -208,7 +212,7 @@ add_task(async function test_never_translate_languages_simulated_stealing() { await translationsSettingsTestUtils.assertEvents( { expected: [ - [TranslationsSettingsTestUtils.Events.NeverLanguagesRendered], + [TranslationsSettingsTestUtils.Events.NeverTranslateLanguagesRendered], [TranslationsSettingsTestUtils.Events.AlwaysTranslateLanguagesRendered], [ TranslationsSettingsTestUtils.Events diff --git a/browser/components/translations/tests/browser/browser_translations_about_settings_subpage_never_translate_sites_basic.js b/browser/components/translations/tests/browser/browser_translations_about_settings_subpage_never_translate_sites_basic.js @@ -41,7 +41,7 @@ add_task(async function test_never_translate_sites_prepopulated() { { expected: [ [ - TranslationsSettingsTestUtils.Events.NeverSitesRendered, + TranslationsSettingsTestUtils.Events.NeverTranslateSitesRendered, { sites: expectedSites, count: expectedSites.length }, ], [ @@ -110,7 +110,7 @@ add_task(async function test_never_translate_sites_delete_and_empty_state() { { expected: [ [ - TranslationsSettingsTestUtils.Events.NeverSitesRendered, + TranslationsSettingsTestUtils.Events.NeverTranslateSitesRendered, { sites: expectedInitialSites, count: expectedInitialSites.length, @@ -142,7 +142,7 @@ add_task(async function test_never_translate_sites_delete_and_empty_state() { { expected: [ [ - TranslationsSettingsTestUtils.Events.NeverSitesRendered, + TranslationsSettingsTestUtils.Events.NeverTranslateSitesRendered, { sites: [remainingOrigin], count: 1 }, ], ], @@ -168,7 +168,7 @@ add_task(async function test_never_translate_sites_delete_and_empty_state() { { expected: [ [ - TranslationsSettingsTestUtils.Events.NeverSitesRendered, + TranslationsSettingsTestUtils.Events.NeverTranslateSitesRendered, { sites: [], count: 0 }, ], [ @@ -234,7 +234,7 @@ add_task(async function test_never_translate_sites_sorted_ignoring_scheme() { { expected: [ [ - TranslationsSettingsTestUtils.Events.NeverSitesRendered, + TranslationsSettingsTestUtils.Events.NeverTranslateSitesRendered, { sites: expectedSites, count: expectedSites.length }, ], [ diff --git a/browser/components/translations/tests/browser/browser_translations_about_settings_subpage_never_translate_sites_observe.js b/browser/components/translations/tests/browser/browser_translations_about_settings_subpage_never_translate_sites_observe.js @@ -33,7 +33,7 @@ add_task( { expected: [ [ - TranslationsSettingsTestUtils.Events.NeverSitesRendered, + TranslationsSettingsTestUtils.Events.NeverTranslateSitesRendered, { sites: [], count: 0 }, ], [TranslationsSettingsTestUtils.Events.Initialized], @@ -54,7 +54,7 @@ add_task( { expected: [ [ - TranslationsSettingsTestUtils.Events.NeverSitesRendered, + TranslationsSettingsTestUtils.Events.NeverTranslateSitesRendered, { sites: [exampleComOrigin], count: 1 }, ], [ @@ -89,7 +89,7 @@ add_task( { expected: [ [ - TranslationsSettingsTestUtils.Events.NeverSitesRendered, + TranslationsSettingsTestUtils.Events.NeverTranslateSitesRendered, { sites: expectedSites, count: expectedSites.length }, ], ], diff --git a/toolkit/components/translations/tests/browser/shared-head.js b/toolkit/components/translations/tests/browser/shared-head.js @@ -443,9 +443,10 @@ class TranslationsSettingsTestUtils { static Events = class Events { static AlwaysTranslateLanguagesRendered = "TranslationsSettingsTest:AlwaysTranslateLanguagesRendered"; - static NeverLanguagesRendered = - "TranslationsSettingsTest:NeverLanguagesRendered"; - static NeverSitesRendered = "TranslationsSettingsTest:NeverSitesRendered"; + static NeverTranslateLanguagesRendered = + "TranslationsSettingsTest:NeverTranslateLanguagesRendered"; + static NeverTranslateSitesRendered = + "TranslationsSettingsTest:NeverTranslateSitesRendered"; static DownloadedLanguagesRendered = "TranslationsSettingsTest:DownloadedLanguagesRendered"; @@ -476,6 +477,10 @@ class TranslationsSettingsTestUtils { "TranslationsSettingsTest:NeverTranslateLanguagesSelectOptionsUpdated"; static DownloadedLanguagesSelectOptionsUpdated = "TranslationsSettingsTest:DownloadedLanguagesSelectOptionsUpdated"; + static NeverTranslateLanguagesAddButtonEnabled = + "TranslationsSettingsTest:NeverTranslateLanguagesAddButtonEnabled"; + static NeverTranslateLanguagesAddButtonDisabled = + "TranslationsSettingsTest:NeverTranslateLanguagesAddButtonDisabled"; static DownloadStarted = "TranslationsSettingsTest:DownloadStarted"; static DownloadProgress = "TranslationsSettingsTest:DownloadProgress"; @@ -746,6 +751,17 @@ class TranslationsSettingsTestUtils { } /** + * Gets the never-translate languages add button. + * + * @returns {HTMLButtonElement|null} + */ + getNeverTranslateLanguagesAddButton() { + return this.document.getElementById( + "translationsNeverTranslateLanguagesButton" + ); + } + + /** * Gets the download languages select element. * * @returns {HTMLSelectElement|null} @@ -1283,6 +1299,28 @@ class TranslationsSettingsTestUtils { const dropdown = this.getNeverTranslateLanguagesSelect(); dropdown.value = langTag; dropdown.dispatchEvent(new Event("change", { bubbles: true })); + + const addButton = await waitForCondition( + () => this.getNeverTranslateLanguagesAddButton(), + "Waiting for never-translate add button" + ); + if (addButton.disabled) { + const addButtonEnabled = this.waitForEvent( + TranslationsSettingsTestUtils.Events + .NeverTranslateLanguagesAddButtonEnabled + ); + await addButtonEnabled; + } + addButton.click(); + + const addedLanguage = this.waitForNeverTranslateLanguageItem(langTag); + const addButtonDisabledPromise = addButton.disabled + ? Promise.resolve() + : this.waitForEvent( + TranslationsSettingsTestUtils.Events + .NeverTranslateLanguagesAddButtonDisabled + ); + await Promise.all([addedLanguage, addButtonDisabledPromise]); } /** @@ -1293,7 +1331,7 @@ class TranslationsSettingsTestUtils { */ async removeNeverTranslateLanguage(langTag) { const removeButton = this.document.querySelector( - `[data-lang-tag="${langTag}"].translations-never-remove-button` + `[data-lang-tag="${langTag}"].translations-never-translate-remove-button` ); if (!removeButton) { throw new Error(`Remove button not found for language: ${langTag}`); @@ -1315,7 +1353,7 @@ class TranslationsSettingsTestUtils { return TestUtils.waitForCondition( () => this.document.querySelector( - `[data-lang-tag="${langTag}"].translations-never-language-item` + `[data-lang-tag="${langTag}"].translations-never-translate-language-item` ), `Waiting for never-translate language item: ${langTag}` ); @@ -1331,7 +1369,7 @@ class TranslationsSettingsTestUtils { */ async assertNeverTranslateLanguages({ languages, count }) { const items = this.document.querySelectorAll( - ".translations-never-language-item" + ".translations-never-translate-language-item" ); if (count !== undefined) { @@ -1363,7 +1401,7 @@ class TranslationsSettingsTestUtils { */ async assertNeverTranslateLanguagesOrder({ languages }) { const items = this.document.querySelectorAll( - ".translations-never-language-item" + ".translations-never-translate-language-item" ); const actualLanguages = Array.from(items).map(item => item.dataset.langTag); Assert.deepEqual( @@ -1416,7 +1454,7 @@ class TranslationsSettingsTestUtils { return waitForCondition( () => this.document.querySelector( - `[data-origin="${origin}"].translations-never-site-item` + `[data-origin="${origin}"].translations-never-translate-site-item` ), `Waiting for never-translate site item: ${origin}` ); @@ -1432,7 +1470,7 @@ class TranslationsSettingsTestUtils { const removeButton = await waitForCondition( () => this.document.querySelector( - `[data-origin="${origin}"].translations-never-site-remove-button` + `[data-origin="${origin}"].translations-never-translate-site-remove-button` ), `Waiting for remove button for ${origin}` ); @@ -1453,7 +1491,7 @@ class TranslationsSettingsTestUtils { */ async assertNeverTranslateSites({ sites, count }) { const items = this.document.querySelectorAll( - ".translations-never-site-item" + ".translations-never-translate-site-item" ); if (count !== undefined) { @@ -1479,7 +1517,7 @@ class TranslationsSettingsTestUtils { */ async assertNeverTranslateSitesOrder({ sites }) { const items = this.document.querySelectorAll( - ".translations-never-site-item" + ".translations-never-translate-site-item" ); const actualSites = Array.from(items).map(item => item.dataset.origin); Assert.deepEqual(actualSites, sites, "Never-translate sites order matches");