commit 580540cbec4f4dc49864ea96d575f9c89092e4b1
parent ffc2589ee135246568c4fb813952977f50cad773
Author: Erik Nordin <enordin@mozilla.com>
Date: Tue, 23 Dec 2025 16:05:28 +0000
Bug 1992232 - Part 5/6: Implement Copy Button Enabled States r=translations-reviewers,gregtatum
This commit introduces the logic for when the target-section copy button
should be enabled or disabled on the about:translations page.
At this point the button has no functionality when clicked.
This will be added in the next commit.
Differential Revision: https://phabricator.services.mozilla.com/D276137
Diffstat:
4 files changed, 226 insertions(+), 2 deletions(-)
diff --git a/toolkit/components/translations/content/about-translations.mjs b/toolkit/components/translations/content/about-translations.mjs
@@ -739,6 +739,23 @@ class AboutTranslations {
}
/**
+ * Updates the enabled state of the copy button.
+ *
+ * @param {boolean} shouldEnable
+ */
+ #setCopyButtonEnabled(shouldEnable) {
+ const { copyButton } = this.elements;
+
+ copyButton.disabled = !shouldEnable;
+
+ const eventName = shouldEnable
+ ? "AboutTranslationsTest:CopyButtonEnabled"
+ : "AboutTranslationsTest:CopyButtonDisabled";
+
+ document.dispatchEvent(new CustomEvent(eventName));
+ }
+
+ /**
* If the currently selected language pair is determined to be swappable,
* swaps the active source language with the active target language,
* and moves the translated output to be the new source text.
@@ -830,8 +847,11 @@ class AboutTranslations {
* Sets the value of the target <textarea>.
*
* @param {string} value
+ * @param {object} [options]
+ * @param {boolean} [options.isTranslationResult=false]
+ * True if the value is the result of a translation request, otherwise false.
*/
- #setTargetText(value) {
+ #setTargetText(value, { isTranslationResult = false } = {}) {
this.elements.targetSectionTextArea.value = value;
if (!value) {
@@ -842,6 +862,7 @@ class AboutTranslations {
this.#updateTargetScriptDirection();
this.#ensureSectionHeightsMatch({ scheduleCallback: false });
+ this.#setCopyButtonEnabled(Boolean(value) && isTranslationResult);
}
/**
@@ -1151,7 +1172,7 @@ class AboutTranslations {
}
);
- this.#setTargetText(translatedText);
+ this.#setTargetText(translatedText, { isTranslationResult: true });
this.#updateSwapLanguagesButtonEnabledState();
document.dispatchEvent(
new CustomEvent("AboutTranslationsTest:TranslationComplete", {
diff --git a/toolkit/components/translations/tests/browser/browser.toml b/toolkit/components/translations/tests/browser/browser.toml
@@ -24,6 +24,8 @@ support-files = [
"translations-text-cleaning.html",
]
+["browser_about_translations_copy_button_enabled_states.js"]
+
["browser_about_translations_debounce.js"]
skip-if = [
"os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11'", # Bug 1821461
diff --git a/toolkit/components/translations/tests/browser/browser_about_translations_copy_button_enabled_states.js b/toolkit/components/translations/tests/browser/browser_about_translations_copy_button_enabled_states.js
@@ -0,0 +1,187 @@
+/* Any copyright is dedicated to the Public Domain.
+ https://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const languagePairs = [
+ { fromLang: "en", toLang: "fr" },
+ { fromLang: "fr", toLang: "en" },
+ { fromLang: "en", toLang: "de" },
+ { fromLang: "de", toLang: "en" },
+];
+
+add_task(
+ async function test_copy_button_disabled_until_translation_completes() {
+ const { aboutTranslationsTestUtils, cleanup } = await openAboutTranslations(
+ {
+ languagePairs,
+ autoDownloadFromRemoteSettings: false,
+ }
+ );
+
+ await aboutTranslationsTestUtils.setSourceLanguageSelectorValue("en");
+ await aboutTranslationsTestUtils.setTargetLanguageSelectorValue("fr");
+
+ await aboutTranslationsTestUtils.assertEvents(
+ {
+ expected: [
+ [
+ AboutTranslationsTestUtils.Events.TranslationRequested,
+ { translationId: 1 },
+ ],
+ [AboutTranslationsTestUtils.Events.ShowTranslatingPlaceholder],
+ ],
+ unexpected: [AboutTranslationsTestUtils.Events.CopyButtonEnabled],
+ },
+ async () => {
+ await aboutTranslationsTestUtils.setSourceTextAreaValue("Hello world");
+ }
+ );
+
+ await aboutTranslationsTestUtils.assertTranslatingPlaceholder();
+ await aboutTranslationsTestUtils.assertCopyButton({ enabled: false });
+
+ await aboutTranslationsTestUtils.assertEvents(
+ {
+ expected: [
+ [
+ AboutTranslationsTestUtils.Events.TranslationComplete,
+ { translationId: 1 },
+ ],
+ [AboutTranslationsTestUtils.Events.CopyButtonEnabled],
+ ],
+ },
+ async () => {
+ await aboutTranslationsTestUtils.resolveDownloads(1);
+ }
+ );
+
+ await aboutTranslationsTestUtils.assertCopyButton({ enabled: true });
+
+ await aboutTranslationsTestUtils.assertTranslatedText({
+ sourceLanguage: "en",
+ targetLanguage: "fr",
+ sourceText: "Hello world",
+ });
+
+ await cleanup();
+ }
+);
+
+add_task(async function test_copy_button_disables_when_translation_cleared() {
+ const { aboutTranslationsTestUtils, cleanup } = await openAboutTranslations({
+ languagePairs,
+ autoDownloadFromRemoteSettings: false,
+ });
+
+ await aboutTranslationsTestUtils.setSourceLanguageSelectorValue("en");
+ await aboutTranslationsTestUtils.setTargetLanguageSelectorValue("fr");
+
+ await aboutTranslationsTestUtils.assertEvents(
+ {
+ expected: [
+ [
+ AboutTranslationsTestUtils.Events.TranslationRequested,
+ { translationId: 1 },
+ ],
+ [AboutTranslationsTestUtils.Events.ShowTranslatingPlaceholder],
+ ],
+ unexpected: [AboutTranslationsTestUtils.Events.CopyButtonEnabled],
+ },
+ async () => {
+ await aboutTranslationsTestUtils.setSourceTextAreaValue("Hello again");
+ }
+ );
+
+ await aboutTranslationsTestUtils.assertTranslatingPlaceholder();
+ await aboutTranslationsTestUtils.assertCopyButton({ enabled: false });
+
+ await aboutTranslationsTestUtils.assertEvents(
+ {
+ expected: [
+ [
+ AboutTranslationsTestUtils.Events.TranslationComplete,
+ { translationId: 1 },
+ ],
+ [AboutTranslationsTestUtils.Events.CopyButtonEnabled],
+ ],
+ },
+ async () => {
+ await aboutTranslationsTestUtils.resolveDownloads(1);
+ }
+ );
+
+ await aboutTranslationsTestUtils.assertCopyButton({ enabled: true });
+
+ await aboutTranslationsTestUtils.assertTranslatedText({
+ sourceLanguage: "en",
+ targetLanguage: "fr",
+ sourceText: "Hello again",
+ });
+
+ await aboutTranslationsTestUtils.assertEvents(
+ {
+ expected: [
+ [AboutTranslationsTestUtils.Events.CopyButtonDisabled],
+ [
+ AboutTranslationsTestUtils.Events.TranslationRequested,
+ { translationId: 2 },
+ ],
+ [AboutTranslationsTestUtils.Events.ShowTranslatingPlaceholder],
+ ],
+ unexpected: [AboutTranslationsTestUtils.Events.CopyButtonEnabled],
+ },
+ async () => {
+ await aboutTranslationsTestUtils.setTargetLanguageSelectorValue("de");
+ }
+ );
+
+ await aboutTranslationsTestUtils.assertTranslatingPlaceholder();
+ await aboutTranslationsTestUtils.assertCopyButton({ enabled: false });
+
+ await aboutTranslationsTestUtils.assertEvents(
+ {
+ expected: [
+ [
+ AboutTranslationsTestUtils.Events.TranslationComplete,
+ { translationId: 2 },
+ ],
+ [AboutTranslationsTestUtils.Events.CopyButtonEnabled],
+ ],
+ },
+ async () => {
+ await aboutTranslationsTestUtils.resolveDownloads(1);
+ }
+ );
+
+ await aboutTranslationsTestUtils.assertCopyButton({ enabled: true });
+
+ await aboutTranslationsTestUtils.assertTranslatedText({
+ sourceLanguage: "en",
+ targetLanguage: "de",
+ sourceText: "Hello again",
+ });
+
+ await aboutTranslationsTestUtils.assertEvents(
+ {
+ expected: [
+ [AboutTranslationsTestUtils.Events.CopyButtonDisabled],
+ [AboutTranslationsTestUtils.Events.ClearTargetText],
+ ],
+ unexpected: [
+ AboutTranslationsTestUtils.Events.CopyButtonEnabled,
+ AboutTranslationsTestUtils.Events.TranslationRequested,
+ ],
+ },
+ async () => {
+ await aboutTranslationsTestUtils.setTargetLanguageSelectorValue("");
+ }
+ );
+
+ await aboutTranslationsTestUtils.assertTargetTextArea({
+ showsPlaceholder: true,
+ });
+ await aboutTranslationsTestUtils.assertCopyButton({ enabled: false });
+
+ await cleanup();
+});
diff --git a/toolkit/components/translations/tests/browser/shared-head.js b/toolkit/components/translations/tests/browser/shared-head.js
@@ -4108,6 +4108,20 @@ class AboutTranslationsTestUtils {
static TranslationComplete = "AboutTranslationsTest:TranslationComplete";
/**
+ * Event fired when the copy button becomes enabled.
+ *
+ * @type {string}
+ */
+ static CopyButtonEnabled = "AboutTranslationsTest:CopyButtonEnabled";
+
+ /**
+ * Event fired when the copy button becomes disabled.
+ *
+ * @type {string}
+ */
+ static CopyButtonDisabled = "AboutTranslationsTest:CopyButtonDisabled";
+
+ /**
* Event fired when the page layout changes.
*
* @type {string}