mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 12:51:06 +00:00
Bug 1907591 - [translations] Display error messages using moz-message-bar. r=nordzilla,fluent-reviewers,settings-reviewers,desktop-theme-reviewers,translations-reviewers,bolsson,dao,mossop
Differential Revision: https://phabricator.services.mozilla.com/D220870
This commit is contained in:
parent
43c53ee1bc
commit
39d6046bd6
@ -270,6 +270,12 @@ let gTranslationsPane = {
|
||||
const eventNode = event.target;
|
||||
const eventNodeParent = eventNode.parentNode;
|
||||
const eventNodeClassList = eventNode.classList;
|
||||
for (const err of document.querySelectorAll(
|
||||
".translations-settings-language-error"
|
||||
)) {
|
||||
this.removeError(err);
|
||||
}
|
||||
|
||||
switch (event.type) {
|
||||
case "command":
|
||||
if (
|
||||
@ -838,6 +844,21 @@ let gTranslationsPane = {
|
||||
}
|
||||
},
|
||||
|
||||
showErrorMessage(parentNode, fluentId, language) {
|
||||
const errorElement = document.createElement("moz-message-bar");
|
||||
errorElement.setAttribute("type", "error");
|
||||
errorElement.setAttribute("data-l10n-attrs", "message");
|
||||
document.l10n.setAttributes(errorElement, fluentId, {
|
||||
name: language,
|
||||
});
|
||||
errorElement.classList.add("translations-settings-language-error");
|
||||
parentNode.appendChild(errorElement);
|
||||
},
|
||||
|
||||
removeError(errorNode) {
|
||||
errorNode?.remove();
|
||||
},
|
||||
|
||||
/**
|
||||
* Event Handler to download a language model selected by the user through HTML
|
||||
* @param {Event} event
|
||||
@ -859,6 +880,11 @@ let gTranslationsPane = {
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
this.showErrorMessage(
|
||||
eventButton.parentNode,
|
||||
"translations-settings-language-download-error",
|
||||
TranslationsParent.getLanguageDisplayName(langTag)
|
||||
);
|
||||
const hasAllFilesForLanguage =
|
||||
await TranslationsParent.hasAllFilesForLanguage(langTag);
|
||||
|
||||
@ -917,6 +943,11 @@ let gTranslationsPane = {
|
||||
} catch (error) {
|
||||
// The download phases are invalidated with the error and must be reloaded.
|
||||
console.error(error);
|
||||
this.showErrorMessage(
|
||||
eventButton.parentNode,
|
||||
"translations-settings-language-remove-error",
|
||||
TranslationsParent.getLanguageDisplayName(langTag)
|
||||
);
|
||||
const hasAllFilesForLanguage =
|
||||
await TranslationsParent.hasAllFilesForLanguage(langTag);
|
||||
if (hasAllFilesForLanguage) {
|
||||
@ -967,6 +998,11 @@ let gTranslationsPane = {
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
await this.reloadDownloadPhases();
|
||||
this.showErrorMessage(
|
||||
eventButton.parentNode,
|
||||
"translations-settings-language-download-error",
|
||||
"all"
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.changeButtonState({
|
||||
@ -995,6 +1031,11 @@ let gTranslationsPane = {
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
await this.reloadDownloadPhases();
|
||||
this.showErrorMessage(
|
||||
eventButton.parentNode,
|
||||
"translations-settings-language-remove-error",
|
||||
"all"
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.changeButtonState({
|
||||
|
@ -487,6 +487,481 @@ add_task(async function test_translations_settings_download_languages() {
|
||||
await cleanup();
|
||||
});
|
||||
|
||||
add_task(
|
||||
async function test_translations_settings_download_languages_error_handling() {
|
||||
const {
|
||||
cleanup,
|
||||
remoteClients,
|
||||
elements: { settingsButton },
|
||||
} = await setupAboutPreferences(LANGUAGE_PAIRS, {
|
||||
prefs: [["browser.translations.newSettingsUI.enable", true]],
|
||||
});
|
||||
|
||||
const frenchModels = [
|
||||
"lex.50.50.enfr.s2t.bin",
|
||||
"lex.50.50.fren.s2t.bin",
|
||||
"model.enfr.intgemm.alphas.bin",
|
||||
"model.fren.intgemm.alphas.bin",
|
||||
"vocab.enfr.spm",
|
||||
"vocab.fren.spm",
|
||||
];
|
||||
|
||||
const spainishModels = [
|
||||
"lex.50.50.enes.s2t.bin",
|
||||
"lex.50.50.esen.s2t.bin",
|
||||
"model.enes.intgemm.alphas.bin",
|
||||
"model.esen.intgemm.alphas.bin",
|
||||
"vocab.enes.spm",
|
||||
"vocab.esen.spm",
|
||||
];
|
||||
|
||||
const allModels = [
|
||||
"lex.50.50.enes.s2t.bin",
|
||||
"lex.50.50.enfr.s2t.bin",
|
||||
"lex.50.50.enuk.s2t.bin",
|
||||
"lex.50.50.esen.s2t.bin",
|
||||
"lex.50.50.fren.s2t.bin",
|
||||
"lex.50.50.uken.s2t.bin",
|
||||
"model.enes.intgemm.alphas.bin",
|
||||
"model.enfr.intgemm.alphas.bin",
|
||||
"model.enuk.intgemm.alphas.bin",
|
||||
"model.esen.intgemm.alphas.bin",
|
||||
"model.fren.intgemm.alphas.bin",
|
||||
"model.uken.intgemm.alphas.bin",
|
||||
"vocab.enes.spm",
|
||||
"vocab.enfr.spm",
|
||||
"vocab.enuk.spm",
|
||||
"vocab.esen.spm",
|
||||
"vocab.fren.spm",
|
||||
"vocab.uken.spm",
|
||||
];
|
||||
|
||||
assertVisibility({
|
||||
message: "Expect paneGeneral elements to be visible.",
|
||||
visible: { settingsButton },
|
||||
});
|
||||
|
||||
const { translateDownloadLanguagesList } =
|
||||
await TranslationsSettingsTestUtils.openAboutPreferencesTranslationsSettingsPane(
|
||||
settingsButton
|
||||
);
|
||||
|
||||
let langList = translateDownloadLanguagesList.querySelector(
|
||||
".translations-settings-language-list"
|
||||
);
|
||||
|
||||
info("Test French language model for download error");
|
||||
|
||||
let langFr = Array.from(langList.querySelectorAll("label")).find(
|
||||
el => el.getAttribute("value") === "fr"
|
||||
);
|
||||
|
||||
let clickButton = BrowserTestUtils.waitForEvent(
|
||||
langFr.parentNode.querySelector("moz-button"),
|
||||
"click"
|
||||
);
|
||||
langFr.parentNode.querySelector("moz-button").click();
|
||||
await clickButton;
|
||||
|
||||
await captureTranslationsError(() =>
|
||||
remoteClients.translationModels.rejectPendingDownloads(
|
||||
frenchModels.length
|
||||
)
|
||||
);
|
||||
|
||||
const errorElement = gBrowser.selectedBrowser.contentDocument.querySelector(
|
||||
".translations-settings-language-error"
|
||||
);
|
||||
|
||||
assertVisibility({
|
||||
message: "Moz-message-bar with error message is visible",
|
||||
visible: { errorElement },
|
||||
});
|
||||
is(
|
||||
document.l10n.getAttributes(errorElement).id,
|
||||
"translations-settings-language-download-error",
|
||||
"Error message correctly shows download error"
|
||||
);
|
||||
is(
|
||||
document.l10n.getAttributes(errorElement).args.name,
|
||||
"French",
|
||||
"Error message correctly shows download error for French language"
|
||||
);
|
||||
|
||||
if (
|
||||
!langFr.parentNode
|
||||
.querySelector("moz-button")
|
||||
.classList.contains("translations-settings-download-icon")
|
||||
) {
|
||||
await BrowserTestUtils.waitForMutationCondition(
|
||||
langFr.parentNode.querySelector("moz-button"),
|
||||
{ attributes: true, attributeFilter: ["class"] },
|
||||
() =>
|
||||
langFr.parentNode
|
||||
.querySelector("moz-button")
|
||||
.classList.contains("translations-settings-download-icon")
|
||||
);
|
||||
}
|
||||
ok(
|
||||
langFr.parentNode
|
||||
.querySelector("moz-button")
|
||||
.classList.contains("translations-settings-download-icon"),
|
||||
"Download icon is visible"
|
||||
);
|
||||
|
||||
remoteClients.translationsWasm.assertNoNewDownloads();
|
||||
|
||||
info("Download Spanish language model successfully.");
|
||||
|
||||
let langEs = Array.from(langList.querySelectorAll("label")).find(
|
||||
el => el.getAttribute("value") === "es"
|
||||
);
|
||||
|
||||
clickButton = BrowserTestUtils.waitForEvent(
|
||||
langEs.parentNode.querySelector("moz-button"),
|
||||
"click"
|
||||
);
|
||||
langEs.parentNode.querySelector("moz-button").click();
|
||||
await clickButton;
|
||||
|
||||
const errorElementEs =
|
||||
gBrowser.selectedBrowser.contentDocument.querySelector(
|
||||
".translations-settings-language-error"
|
||||
);
|
||||
|
||||
ok(
|
||||
!errorElementEs,
|
||||
"Previous error is remove when new action occured, i.e. click download Spanish button"
|
||||
);
|
||||
|
||||
Assert.deepEqual(
|
||||
await remoteClients.translationModels.resolvePendingDownloads(
|
||||
spainishModels.length
|
||||
),
|
||||
spainishModels,
|
||||
"Spanish models were downloaded."
|
||||
);
|
||||
|
||||
if (
|
||||
!langEs.parentNode
|
||||
.querySelector("moz-button")
|
||||
.classList.contains("translations-settings-remove-icon")
|
||||
) {
|
||||
await BrowserTestUtils.waitForMutationCondition(
|
||||
langEs.parentNode.querySelector("moz-button"),
|
||||
{ attributes: true, attributeFilter: ["class"] },
|
||||
() =>
|
||||
langEs.parentNode
|
||||
.querySelector("moz-button")
|
||||
.classList.contains("translations-settings-remove-icon")
|
||||
);
|
||||
}
|
||||
|
||||
ok(
|
||||
langEs.parentNode
|
||||
.querySelector("moz-button")
|
||||
.classList.contains("translations-settings-remove-icon"),
|
||||
"Delete icon is visible for Spanish language hence downloaded"
|
||||
);
|
||||
|
||||
info("Test All language models download error");
|
||||
// Download "All languages" is the first child
|
||||
let langAll = langList.children[0];
|
||||
|
||||
let clickButtonAll = BrowserTestUtils.waitForEvent(
|
||||
langAll.querySelector("moz-button"),
|
||||
"click"
|
||||
);
|
||||
langAll.querySelector("moz-button").click();
|
||||
await clickButtonAll;
|
||||
|
||||
await captureTranslationsError(() =>
|
||||
remoteClients.translationModels.rejectPendingDownloads(allModels.length)
|
||||
);
|
||||
|
||||
await captureTranslationsError(() =>
|
||||
remoteClients.translationsWasm.rejectPendingDownloads(allModels.length)
|
||||
);
|
||||
|
||||
remoteClients.translationsWasm.assertNoNewDownloads();
|
||||
|
||||
if (
|
||||
!langAll
|
||||
.querySelector("moz-button")
|
||||
.classList.contains("translations-settings-download-icon")
|
||||
) {
|
||||
await BrowserTestUtils.waitForMutationCondition(
|
||||
langAll.querySelector("moz-button"),
|
||||
{ attributes: true, attributeFilter: ["class"] },
|
||||
() =>
|
||||
langAll
|
||||
.querySelector("moz-button")
|
||||
.classList.contains("translations-settings-download-icon")
|
||||
);
|
||||
}
|
||||
langAll.querySelector("moz-button").classList;
|
||||
ok(
|
||||
langAll
|
||||
.querySelector("moz-button")
|
||||
.classList.contains("translations-settings-download-icon"),
|
||||
"Download icon is visible for 'all languages'"
|
||||
);
|
||||
|
||||
const errorElementAll =
|
||||
gBrowser.selectedBrowser.contentDocument.querySelector(
|
||||
".translations-settings-language-error"
|
||||
);
|
||||
|
||||
assertVisibility({
|
||||
message: "Moz-message-bar with error message is visible",
|
||||
visible: { errorElementAll },
|
||||
});
|
||||
is(
|
||||
document.l10n.getAttributes(errorElementAll).id,
|
||||
"translations-settings-language-download-error",
|
||||
"Error message correctly shows download error"
|
||||
);
|
||||
is(
|
||||
document.l10n.getAttributes(errorElementAll).args.name,
|
||||
"all",
|
||||
"Error message correctly shows download error for all language"
|
||||
);
|
||||
|
||||
await cleanup();
|
||||
}
|
||||
);
|
||||
|
||||
add_task(async function test_translations_settings_download_languages_all() {
|
||||
const {
|
||||
cleanup,
|
||||
remoteClients,
|
||||
elements: { settingsButton },
|
||||
} = await setupAboutPreferences(LANGUAGE_PAIRS, {
|
||||
prefs: [["browser.translations.newSettingsUI.enable", true]],
|
||||
});
|
||||
|
||||
const frenchModels = [
|
||||
"lex.50.50.enfr.s2t.bin",
|
||||
"lex.50.50.fren.s2t.bin",
|
||||
"model.enfr.intgemm.alphas.bin",
|
||||
"model.fren.intgemm.alphas.bin",
|
||||
"vocab.enfr.spm",
|
||||
"vocab.fren.spm",
|
||||
];
|
||||
|
||||
const spainishModels = [
|
||||
"lex.50.50.enes.s2t.bin",
|
||||
"lex.50.50.esen.s2t.bin",
|
||||
"model.enes.intgemm.alphas.bin",
|
||||
"model.esen.intgemm.alphas.bin",
|
||||
"vocab.enes.spm",
|
||||
"vocab.esen.spm",
|
||||
];
|
||||
|
||||
const ukrainianModels = [
|
||||
"lex.50.50.enuk.s2t.bin",
|
||||
"lex.50.50.uken.s2t.bin",
|
||||
"model.enuk.intgemm.alphas.bin",
|
||||
"model.uken.intgemm.alphas.bin",
|
||||
"vocab.enuk.spm",
|
||||
"vocab.uken.spm",
|
||||
];
|
||||
|
||||
assertVisibility({
|
||||
message: "Expect paneGeneral elements to be visible.",
|
||||
visible: { settingsButton },
|
||||
});
|
||||
|
||||
const { translateDownloadLanguagesList } =
|
||||
await TranslationsSettingsTestUtils.openAboutPreferencesTranslationsSettingsPane(
|
||||
settingsButton
|
||||
);
|
||||
|
||||
let langList = translateDownloadLanguagesList.querySelector(
|
||||
".translations-settings-language-list"
|
||||
);
|
||||
|
||||
info(
|
||||
"Install each language French, Spanish and Ukrainian and check if All language state changes to 'all language downloaded' by changing the all language button icon to 'remove icon'"
|
||||
);
|
||||
|
||||
info("Download French language model.");
|
||||
let langFr = Array.from(langList.querySelectorAll("label")).find(
|
||||
el => el.getAttribute("value") === "fr"
|
||||
);
|
||||
|
||||
let clickButton = BrowserTestUtils.waitForEvent(
|
||||
langFr.parentNode.querySelector("moz-button"),
|
||||
"click"
|
||||
);
|
||||
langFr.parentNode.querySelector("moz-button").click();
|
||||
await clickButton;
|
||||
|
||||
Assert.deepEqual(
|
||||
await remoteClients.translationModels.resolvePendingDownloads(
|
||||
frenchModels.length
|
||||
),
|
||||
frenchModels,
|
||||
"French models were downloaded."
|
||||
);
|
||||
|
||||
if (
|
||||
!langFr.parentNode
|
||||
.querySelector("moz-button")
|
||||
.classList.contains("translations-settings-remove-icon")
|
||||
) {
|
||||
await BrowserTestUtils.waitForMutationCondition(
|
||||
langFr.parentNode.querySelector("moz-button"),
|
||||
{ attributes: true, attributeFilter: ["class"] },
|
||||
() =>
|
||||
langFr.parentNode
|
||||
.querySelector("moz-button")
|
||||
.classList.contains("translations-settings-remove-icon")
|
||||
);
|
||||
}
|
||||
|
||||
ok(
|
||||
langFr.parentNode
|
||||
.querySelector("moz-button")
|
||||
.classList.contains("translations-settings-remove-icon"),
|
||||
"Delete icon is visible for French language hence downloaded"
|
||||
);
|
||||
|
||||
info("Download Spanish language model.");
|
||||
|
||||
let langEs = Array.from(langList.querySelectorAll("label")).find(
|
||||
el => el.getAttribute("value") === "es"
|
||||
);
|
||||
|
||||
clickButton = BrowserTestUtils.waitForEvent(
|
||||
langEs.parentNode.querySelector("moz-button"),
|
||||
"click"
|
||||
);
|
||||
langEs.parentNode.querySelector("moz-button").click();
|
||||
await clickButton;
|
||||
|
||||
Assert.deepEqual(
|
||||
await remoteClients.translationModels.resolvePendingDownloads(
|
||||
spainishModels.length
|
||||
),
|
||||
spainishModels,
|
||||
"Spanish models were downloaded."
|
||||
);
|
||||
|
||||
if (
|
||||
!langEs.parentNode
|
||||
.querySelector("moz-button")
|
||||
.classList.contains("translations-settings-remove-icon")
|
||||
) {
|
||||
await BrowserTestUtils.waitForMutationCondition(
|
||||
langEs.parentNode.querySelector("moz-button"),
|
||||
{ attributes: true, attributeFilter: ["class"] },
|
||||
() =>
|
||||
langEs.parentNode
|
||||
.querySelector("moz-button")
|
||||
.classList.contains("translations-settings-remove-icon")
|
||||
);
|
||||
}
|
||||
|
||||
ok(
|
||||
langEs.parentNode
|
||||
.querySelector("moz-button")
|
||||
.classList.contains("translations-settings-remove-icon"),
|
||||
"Delete icon is visible for Spanish language hence downloaded"
|
||||
);
|
||||
|
||||
info("Download Ukrainian language model.");
|
||||
|
||||
let langUk = Array.from(langList.querySelectorAll("label")).find(
|
||||
el => el.getAttribute("value") === "uk"
|
||||
);
|
||||
|
||||
clickButton = BrowserTestUtils.waitForEvent(
|
||||
langUk.parentNode.querySelector("moz-button"),
|
||||
"click"
|
||||
);
|
||||
langUk.parentNode.querySelector("moz-button").click();
|
||||
await clickButton;
|
||||
|
||||
Assert.deepEqual(
|
||||
await remoteClients.translationModels.resolvePendingDownloads(
|
||||
ukrainianModels.length
|
||||
),
|
||||
ukrainianModels,
|
||||
"Ukrainian models were downloaded."
|
||||
);
|
||||
|
||||
if (
|
||||
!langUk.parentNode
|
||||
.querySelector("moz-button")
|
||||
.classList.contains("translations-settings-remove-icon")
|
||||
) {
|
||||
await BrowserTestUtils.waitForMutationCondition(
|
||||
langUk.parentNode.querySelector("moz-button"),
|
||||
{ attributes: true, attributeFilter: ["class"] },
|
||||
() =>
|
||||
langUk.parentNode
|
||||
.querySelector("moz-button")
|
||||
.classList.contains("translations-settings-remove-icon")
|
||||
);
|
||||
}
|
||||
|
||||
ok(
|
||||
langUk.parentNode
|
||||
.querySelector("moz-button")
|
||||
.classList.contains("translations-settings-remove-icon"),
|
||||
"Delete icon is visible for Ukranian language hence downloaded."
|
||||
);
|
||||
|
||||
// Download "All languages" is the first child
|
||||
let langAll = langList.children[0];
|
||||
|
||||
ok(
|
||||
langAll
|
||||
.querySelector("moz-button")
|
||||
.classList.contains("translations-settings-remove-icon"),
|
||||
"Delete icon is visible for All Languages after all individual language models were downloaded."
|
||||
);
|
||||
|
||||
info(
|
||||
"Remove one language ensure that All Languages change state changes to 'removed' to indicate that all languages are not downloaded."
|
||||
);
|
||||
|
||||
info("Remove Spanish language model.");
|
||||
langEs.parentNode.querySelector("moz-button").click();
|
||||
await clickButton;
|
||||
|
||||
if (
|
||||
!langEs.parentNode
|
||||
.querySelector("moz-button")
|
||||
.classList.contains("translations-settings-download-icon")
|
||||
) {
|
||||
await BrowserTestUtils.waitForMutationCondition(
|
||||
langEs.parentNode.querySelector("moz-button"),
|
||||
{ attributes: true, attributeFilter: ["class"] },
|
||||
() =>
|
||||
langEs.parentNode
|
||||
.querySelector("moz-button")
|
||||
.classList.contains("translations-settings-download-icon")
|
||||
);
|
||||
}
|
||||
ok(
|
||||
langEs.parentNode
|
||||
.querySelector("moz-button")
|
||||
.classList.contains("translations-settings-download-icon"),
|
||||
"Download icon is visible for Spanish language hence removed"
|
||||
);
|
||||
|
||||
ok(
|
||||
langAll
|
||||
.querySelector("moz-button")
|
||||
.classList.contains("translations-settings-download-icon"),
|
||||
"Download icon is visible for all languages i.e. all languages are not downloaded since one language, Spainish was removed."
|
||||
);
|
||||
|
||||
await cleanup();
|
||||
});
|
||||
|
||||
const { PermissionTestUtils } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/PermissionTestUtils.sys.mjs"
|
||||
);
|
||||
|
@ -25,12 +25,19 @@ translations-settings-download-languages-link = Learn more about downloading lan
|
||||
# $size (number) - The size of the download in megabites
|
||||
translations-settings-download-size = ({ $size })
|
||||
translations-settings-language-header = Language
|
||||
|
||||
# Variables:
|
||||
# $name (string) - The language to be downloaded
|
||||
translations-settings-language-download-error =
|
||||
.heading = Download Error
|
||||
.message = Language download failed. Try again.
|
||||
.message = Could not download { $name } language. Please try again.
|
||||
|
||||
# Variables:
|
||||
# $name (string) - The language to be downloaded
|
||||
translations-settings-language-remove-error =
|
||||
.heading = Remove Error
|
||||
.message = Failed to remove language. Try again.
|
||||
.message = Could not remove { $name } language. Please try again.
|
||||
|
||||
# Variables:
|
||||
# $name (string) - The display name of the language that is to be downloaded
|
||||
translations-settings-download-button =
|
||||
|
@ -49,6 +49,7 @@
|
||||
|
||||
.translations-settings-language {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
padding: var(--space-small) 0;
|
||||
border-top: 1px solid var(--in-content-border-color);
|
||||
@ -57,7 +58,8 @@
|
||||
}
|
||||
}
|
||||
.translations-settings-language-error {
|
||||
flex: 100%;
|
||||
display: inline-block;
|
||||
flex: 0 1 100%;
|
||||
}
|
||||
.translations-settings-download-icon[type~="icon"]::part(button) {
|
||||
background-image: url(chrome://browser/skin/downloads/downloads.svg);
|
||||
|
Loading…
Reference in New Issue
Block a user