mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-26 12:20:56 +00:00
Bug 1829687 - Apply UX feedback to consolidate translation panel views; r=nordzilla,fluent-reviewers,flod
UX changed their mind on how the default translation panel should work. I originally pushed back against getting this done for MVP, but the logic is much easier when the translation panel can be manually invoked by the user. Differential Revision: https://phabricator.services.mozilla.com/D179087
This commit is contained in:
parent
7ce36dd8a6
commit
d729409e1b
@ -10,18 +10,16 @@
|
||||
noautofocus="true"
|
||||
aria-labelledby="translations-panel-main-header-label"
|
||||
orient="vertical">
|
||||
<panelmultiview id="translations-panel-multiview">
|
||||
<!-- Default page -->
|
||||
<panelmultiview id="translations-panel-multiview"
|
||||
mainViewId="translations-panel-view-default">
|
||||
<panelview id="translations-panel-view-default"
|
||||
class="PanelUI-subView translations-panel-view"
|
||||
role="document"
|
||||
showheader="true">
|
||||
<hbox class="panel-header translations-panel-header">
|
||||
<html:h1>
|
||||
<html:span data-l10n-id="translations-panel-default-header"></html:span>
|
||||
<html:span id="translations-panel-header"></html:span>
|
||||
</html:h1>
|
||||
<!-- The "toolbarbutton#translations-panel-settings" will get cloned into other
|
||||
.panel-header elements. -->
|
||||
<toolbarbutton id="translations-panel-settings" class="panel-info-button"
|
||||
data-l10n-id="translations-panel-settings-button"
|
||||
closemenu="none"
|
||||
@ -47,9 +45,6 @@
|
||||
autocheck="false"
|
||||
oncommand="TranslationsPanel.onNeverTranslateSite()"/>
|
||||
<menuseparator/>
|
||||
<menuitem data-l10n-id="translations-panel-settings-change-source-language"
|
||||
class="translations-panel-change-source"
|
||||
oncommand="TranslationsPanel.showDualView()"/>
|
||||
<menuitem data-l10n-id="translations-panel-settings-manage-languages"
|
||||
oncommand="TranslationsPanel.openManageLanguages()"/>
|
||||
</menupopup>
|
||||
@ -57,129 +52,94 @@
|
||||
</hbox>
|
||||
|
||||
<vbox class="translations-panel-content">
|
||||
<description id="translations-panel-default-description"></description>
|
||||
<label data-l10n-id="translations-panel-default-translate-to-label"></label>
|
||||
<menulist id="translations-panel-default-to"
|
||||
flex="1"
|
||||
value="detect"
|
||||
size="large">
|
||||
<menupopup id="translations-panel-default-to-menupopup"
|
||||
class="translations-panel-language-menupopup-to">
|
||||
<!-- The list of <menuitem> will be dynamically inserted. -->
|
||||
</menupopup>
|
||||
</menulist>
|
||||
<vbox id="translations-panel-lang-selection">
|
||||
<label data-l10n-id="translations-panel-from-label"></label>
|
||||
<menulist id="translations-panel-from"
|
||||
flex="1"
|
||||
value="detect"
|
||||
size="large"
|
||||
oncommand="TranslationsPanel.onChangeLanguages(event)">
|
||||
<menupopup id="translations-panel-from-menupopup"
|
||||
class="translations-panel-language-menupopup-from">
|
||||
<menuitem data-l10n-id="translations-panel-choose-language" value=""></menuitem>
|
||||
<!-- The list of <menuitem> will be dynamically inserted. -->
|
||||
</menupopup>
|
||||
</menulist>
|
||||
|
||||
<label data-l10n-id="translations-panel-to-label"></label>
|
||||
<menulist id="translations-panel-to"
|
||||
flex="1"
|
||||
value="detect"
|
||||
size="large"
|
||||
oncommand="TranslationsPanel.onChangeLanguages(event)">
|
||||
<menupopup id="translations-panel-to-menupopup"
|
||||
class="translations-panel-language-menupopup-to">
|
||||
<menuitem data-l10n-id="translations-panel-choose-language" value=""></menuitem>
|
||||
<!-- The list of <menuitem> will be dynamically inserted. -->
|
||||
</menupopup>
|
||||
</menulist>
|
||||
</vbox>
|
||||
|
||||
<vbox id="translations-panel-error">
|
||||
<hbox class="translations-panel-error-header">
|
||||
<image class="translations-panel-error-icon translations-panel-error-header-icon" />
|
||||
<description id="translations-panel-error-message"></description>
|
||||
</hbox>
|
||||
<hbox id="translations-panel-error-message-hint"></hbox>
|
||||
<hbox pack="end">
|
||||
<button id="translations-panel-translate-hint-action" />
|
||||
</hbox>
|
||||
</vbox>
|
||||
</vbox>
|
||||
|
||||
<hbox class="panel-footer translations-panel-footer">
|
||||
<hbox id="translations-panel-error">
|
||||
<image class="translations-panel-error-icon" />
|
||||
<description id="translations-panel-error-message"></description>
|
||||
</hbox>
|
||||
<button class="subviewbutton panel-subview-footer-button"
|
||||
id="translations-panel-not-now"
|
||||
oncommand="TranslationsPanel.onCancel(event);"
|
||||
data-l10n-id="translations-panel-default-translate-cancel"
|
||||
tabindex="0">
|
||||
</button>
|
||||
<button default="true"
|
||||
<button id="translations-panel-restore-button"
|
||||
class="subviewbutton panel-subview-footer-button"
|
||||
oncommand="TranslationsPanel.onDefaultTranslate(event);"
|
||||
data-l10n-id="translations-panel-default-translate-button"
|
||||
oncommand="TranslationsPanel.onRestore(event);"
|
||||
data-l10n-id="translations-panel-restore-button"
|
||||
tabindex="0">
|
||||
</button>
|
||||
</hbox>
|
||||
</panelview>
|
||||
|
||||
<!-- Dual language selection view -->
|
||||
<panelview id="translations-panel-view-dual"
|
||||
class="PanelUI-subView translations-panel-view"
|
||||
role="document"
|
||||
data-l10n-id="translations-panel-dual-header">
|
||||
<vbox class="translations-panel-content">
|
||||
<label data-l10n-id="translations-panel-dual-from-label"></label>
|
||||
<menulist id="translations-panel-dual-from"
|
||||
flex="1"
|
||||
value="detect"
|
||||
size="large"
|
||||
oncommand="TranslationsPanel.onChangeDualLanguages(event)">
|
||||
<menupopup id="translations-panel-dual-from-menupopup"
|
||||
class="translations-panel-language-menupopup-from">
|
||||
<menuitem data-l10n-id="translations-panel-choose-language" value=""></menuitem>
|
||||
<!-- The list of <menuitem> will be dynamically inserted. -->
|
||||
</menupopup>
|
||||
</menulist>
|
||||
|
||||
<label data-l10n-id="translations-panel-dual-to-label"></label>
|
||||
<menulist id="translations-panel-dual-to"
|
||||
flex="1"
|
||||
value="detect"
|
||||
size="large"
|
||||
oncommand="TranslationsPanel.onChangeDualLanguages(event)">
|
||||
<menupopup id="translations-panel-dual-to-menupopup"
|
||||
class="translations-panel-language-menupopup-to">
|
||||
<!-- The list of <menuitem> will be dynamically inserted. -->
|
||||
</menupopup>
|
||||
</menulist>
|
||||
</vbox>
|
||||
|
||||
<hbox class="panel-footer translations-panel-footer">
|
||||
<button class="subviewbutton panel-subview-footer-button"
|
||||
id="translations-panel-not-now"
|
||||
<button id="translations-panel-not-now"
|
||||
class="subviewbutton panel-subview-footer-button"
|
||||
oncommand="TranslationsPanel.onCancel(event);"
|
||||
data-l10n-id="translations-panel-dual-cancel-button"
|
||||
data-l10n-id="translations-panel-translate-cancel"
|
||||
tabindex="0">
|
||||
</button>
|
||||
<button id="translations-panel-dual-translate"
|
||||
<button id="translations-panel-translate"
|
||||
class="subviewbutton panel-subview-footer-button"
|
||||
oncommand="TranslationsPanel.onTranslate(event);"
|
||||
data-l10n-id="translations-panel-translate-button"
|
||||
default="true"
|
||||
class="subviewbutton panel-subview-footer-button"
|
||||
oncommand="TranslationsPanel.onDualTranslate(event);"
|
||||
data-l10n-id="translations-panel-default-translate-button"
|
||||
tabindex="0">
|
||||
</button>
|
||||
</hbox>
|
||||
</panelview>
|
||||
|
||||
<!-- Revisit the translations panel -->
|
||||
<panelview id="translations-panel-view-revisit"
|
||||
<panelview id="translations-panel-view-unsupported-language"
|
||||
class="PanelUI-subView translations-panel-view"
|
||||
role="document"
|
||||
showheader="true">
|
||||
<hbox class="panel-header translations-panel-header">
|
||||
<image class="translations-panel-error-icon" />
|
||||
<html:h1>
|
||||
<html:span id="translations-panel-revisit-header">
|
||||
<!-- The "to" and "from" languages will be set here -->
|
||||
</html:span>
|
||||
<html:span data-l10n-id="translations-panel-error-unsupported"></html:span>
|
||||
</html:h1>
|
||||
<!-- The "toolbarbutton#translations-panel-settings" gets cloned here. -->
|
||||
</hbox>
|
||||
|
||||
<vbox class="translations-panel-content">
|
||||
<label id="translations-panel-revisit-label"
|
||||
data-l10n-id="translations-panel-revisit-label">
|
||||
</label>
|
||||
<menulist id="translations-panel-revisit-to"
|
||||
flex="1"
|
||||
value="detect"
|
||||
size="large"
|
||||
oncommand="TranslationsPanel.onChangeRevisitTo(event)">
|
||||
<menupopup class="translations-panel-language-menupopup-to">
|
||||
<menuitem data-l10n-id="translations-panel-choose-language" value=""></menuitem>
|
||||
<!-- The list of <menuitem> will be dynamically inserted. -->
|
||||
</menupopup>
|
||||
</menulist>
|
||||
<description id="translations-panel-error-unsupported-hint"></description>
|
||||
</vbox>
|
||||
|
||||
<hbox class="panel-footer translations-panel-footer">
|
||||
<button class="subviewbutton panel-subview-footer-button"
|
||||
oncommand="TranslationsPanel.onRestore(event);"
|
||||
data-l10n-id="translations-panel-revisit-restore-button"
|
||||
oncommand="TranslationsPanel.onChangeSourceLanguage(event);"
|
||||
data-l10n-id="translations-panel-error-change-button"
|
||||
tabindex="0">
|
||||
</button>
|
||||
<button id="translations-panel-revisit-translate"
|
||||
<button class="subviewbutton panel-subview-footer-button"
|
||||
oncommand="TranslationsPanel.onCancel(event);"
|
||||
data-l10n-id="translations-panel-error-dismiss-button"
|
||||
default="true"
|
||||
class="subviewbutton panel-subview-footer-button"
|
||||
oncommand="TranslationsPanel.onRevisitTranslate(event);"
|
||||
data-l10n-id="translations-panel-revisit-translate-button"
|
||||
tabindex="0">
|
||||
</button>
|
||||
</hbox>
|
||||
|
@ -100,26 +100,69 @@ var TranslationsPanel = new (class {
|
||||
});
|
||||
};
|
||||
|
||||
getter("appMenuButton", "PanelUI-menu-button");
|
||||
getter("button", "translations-button");
|
||||
getter("buttonLocale", "translations-button-locale");
|
||||
getter("buttonCircleArrows", "translations-button-circle-arrows");
|
||||
getter("defaultDescription", "translations-panel-default-description");
|
||||
getter("defaultToMenuList", "translations-panel-default-to");
|
||||
getter("dualFromMenuList", "translations-panel-dual-from");
|
||||
getter("dualToMenuList", "translations-panel-dual-to");
|
||||
getter("dualTranslate", "translations-panel-dual-translate");
|
||||
getter("defaultTranslate", "translations-panel-translate");
|
||||
getter("error", "translations-panel-error");
|
||||
getter("errorMessage", "translations-panel-error-message");
|
||||
getter("errorMessageHint", "translations-panel-error-message-hint");
|
||||
getter("errorHintAction", "translations-panel-translate-hint-action");
|
||||
getter("fromMenuList", "translations-panel-from");
|
||||
getter("header", "translations-panel-header");
|
||||
getter("langSelection", "translations-panel-lang-selection");
|
||||
getter("multiview", "translations-panel-multiview");
|
||||
getter("notNow", "translations-panel-not-now");
|
||||
getter("revisitHeader", "translations-panel-revisit-header");
|
||||
getter("revisitMenuList", "translations-panel-revisit-to");
|
||||
getter("revisitTranslate", "translations-panel-revisit-translate");
|
||||
getter("notNowButton", "translations-panel-not-now");
|
||||
getter("restoreButton", "translations-panel-restore-button");
|
||||
getter("toMenuList", "translations-panel-to");
|
||||
getter("unsupportedHint", "translations-panel-error-unsupported-hint");
|
||||
}
|
||||
|
||||
return this.#lazyElements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache the last command used for error hints so that it can be later removed.
|
||||
*/
|
||||
#lastHintCommand = null;
|
||||
|
||||
/**
|
||||
* @param {object} options
|
||||
* @param {string} options.message - l10n id
|
||||
* @param {string} options.hint - l10n id
|
||||
* @param {string} options.actionText - l10n id
|
||||
* @param {Function} options.actionCommand - The action to perform.
|
||||
*/
|
||||
#showError({
|
||||
message,
|
||||
hint,
|
||||
actionText: hintCommandText,
|
||||
actionCommand: hintCommand,
|
||||
}) {
|
||||
const { error, errorMessage, errorMessageHint, errorHintAction } =
|
||||
this.elements;
|
||||
error.hidden = false;
|
||||
document.l10n.setAttributes(errorMessage, message);
|
||||
|
||||
if (hint) {
|
||||
errorMessageHint.hidden = false;
|
||||
document.l10n.setAttributes(errorMessageHint, hint);
|
||||
} else {
|
||||
errorMessageHint.hidden = true;
|
||||
}
|
||||
|
||||
if (hintCommand && hintCommandText) {
|
||||
errorHintAction.removeEventListener("command", this.#lastHintCommand);
|
||||
this.#lastHintCommand = hintCommand;
|
||||
errorHintAction.addEventListener("command", hintCommand);
|
||||
errorHintAction.hidden = false;
|
||||
document.l10n.setAttributes(errorHintAction, hintCommandText);
|
||||
} else {
|
||||
errorHintAction.hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {TranslationsParent}
|
||||
*/
|
||||
@ -250,101 +293,111 @@ var TranslationsPanel = new (class {
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to the dual language view of choosing a source and target language.
|
||||
* Show the default view of choosing a source and target language.
|
||||
*
|
||||
* @param {boolean} force - Force the page to show translation options.
|
||||
*/
|
||||
showDualView() {
|
||||
async #showDefaultView(force = false) {
|
||||
const {
|
||||
dualTranslate,
|
||||
dualFromMenuList,
|
||||
dualToMenuList,
|
||||
fromMenuList,
|
||||
multiview,
|
||||
defaultToMenuList,
|
||||
panel,
|
||||
error,
|
||||
toMenuList,
|
||||
defaultTranslate,
|
||||
langSelection,
|
||||
} = this.elements;
|
||||
|
||||
// Remove any old selected values synchronously before asking for new ones.
|
||||
dualFromMenuList.value = "";
|
||||
dualToMenuList.value = defaultToMenuList.value;
|
||||
// Disable this button since the user must choose a new "from" language.
|
||||
dualTranslate.disabled = true;
|
||||
if (this.#langListsPhase === "error") {
|
||||
// There was an error, display it in the view rather than the language
|
||||
// dropdowns.
|
||||
const { restoreButton, notNowButton, header, errorHintAction } =
|
||||
this.elements;
|
||||
|
||||
multiview.showSubView("translations-panel-view-dual");
|
||||
this.#showError({
|
||||
message: "translations-panel-error-load-languages",
|
||||
hint: "translations-panel-error-load-languages-hint",
|
||||
actionText: "translations-panel-error-load-languages-hint-button",
|
||||
actionCommand: () => this.#reloadLangList(),
|
||||
});
|
||||
|
||||
document.l10n.setAttributes(header, "translations-panel-header");
|
||||
defaultTranslate.disabled = true;
|
||||
restoreButton.hidden = true;
|
||||
notNowButton.hidden = false;
|
||||
langSelection.hidden = true;
|
||||
errorHintAction.disabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove any old selected values synchronously before asking for new ones.
|
||||
fromMenuList.value = "";
|
||||
error.hidden = true;
|
||||
langSelection.hidden = false;
|
||||
|
||||
/** @type {null | LangTags} */
|
||||
const langTags = await this.#fetchDetectedLanguages();
|
||||
if (langTags?.isDocLangTagSupported || force) {
|
||||
// Show the default view with the language selection
|
||||
const { header, restoreButton, notNowButton } = this.elements;
|
||||
document.l10n.setAttributes(header, "translations-panel-header");
|
||||
|
||||
if (langTags?.isDocLangTagSupported) {
|
||||
fromMenuList.value = langTags?.docLangTag ?? "";
|
||||
} else {
|
||||
fromMenuList.value = "";
|
||||
}
|
||||
toMenuList.value = langTags?.userLangTag ?? "";
|
||||
|
||||
this.onChangeLanguages();
|
||||
|
||||
restoreButton.hidden = true;
|
||||
notNowButton.hidden = false;
|
||||
multiview.setAttribute("mainViewId", "translations-panel-view-default");
|
||||
} else {
|
||||
// Show the "unsupported language" view.
|
||||
const { unsupportedHint } = this.elements;
|
||||
multiview.setAttribute(
|
||||
"mainViewId",
|
||||
"translations-panel-view-unsupported-language"
|
||||
);
|
||||
let language;
|
||||
if (langTags?.docLangTag) {
|
||||
const displayNames = new Intl.DisplayNames(undefined, {
|
||||
type: "language",
|
||||
fallback: "none",
|
||||
});
|
||||
language = displayNames.of(langTags.docLangTag);
|
||||
}
|
||||
if (language) {
|
||||
document.l10n.setAttributes(
|
||||
unsupportedHint,
|
||||
"translations-panel-error-unsupported-hint-known",
|
||||
{ language }
|
||||
);
|
||||
} else {
|
||||
document.l10n.setAttributes(
|
||||
unsupportedHint,
|
||||
"translations-panel-error-unsupported-hint-unknown"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Focus the "from" language, as it is the only field not set.
|
||||
panel.addEventListener(
|
||||
"ViewShown",
|
||||
() => {
|
||||
dualFromMenuList.focus();
|
||||
if (!fromMenuList.value) {
|
||||
fromMenuList.focus();
|
||||
}
|
||||
if (!toMenuList.value) {
|
||||
toMenuList.focus();
|
||||
}
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the <menulist> of languages for both the "from" and "to". This can be
|
||||
* called every time the popup is shown, as it will retry when there is an error
|
||||
* (such as a network error) or be a noop if it's already initialized.
|
||||
*/
|
||||
async #showDefaultView() {
|
||||
await this.#ensureLangListsBuilt();
|
||||
const actor = this.#getTranslationsActor();
|
||||
|
||||
const { defaultToMenuList, defaultDescription, multiview } = this.elements;
|
||||
|
||||
multiview.setAttribute("mainViewId", "translations-panel-view-default");
|
||||
|
||||
// Remove any old selected values synchronously before asking for new ones.
|
||||
defaultToMenuList.value = "";
|
||||
|
||||
// TODO(Bug 1825801) - There is a race condition, we may download the languages, and
|
||||
// later trigger the subview to be shown after opening the popup again. We need to
|
||||
// properly handle this.
|
||||
|
||||
// TODO(Bug 1825801) - This could potentially be a bad pause, as we aren't showing
|
||||
// the panel until the language list is ready. It's probably fine for a prototype,
|
||||
// but should be handled for the MVP. We might want design direction here, as we need
|
||||
// a subview for when the language list is still being retrieved.
|
||||
|
||||
/** @type {null | LangTags} */
|
||||
const langTags = await actor.getLangTagsForTranslation();
|
||||
|
||||
if (langTags) {
|
||||
const { docLangTag, appLangTag } = langTags;
|
||||
defaultToMenuList.value = appLangTag;
|
||||
this.#docLangTag = docLangTag;
|
||||
} else {
|
||||
// TODO(Bug 1829687): Handle the case when we don't have the document langauge tag
|
||||
// which can only be triggered when the panel is shown manually. Currently
|
||||
// this will never be shown.
|
||||
this.#docLangTag = "en";
|
||||
this.console.error("No language tags for translation were found.");
|
||||
}
|
||||
|
||||
// Show the default view.
|
||||
const displayNames = new Services.intl.DisplayNames(undefined, {
|
||||
type: "language",
|
||||
});
|
||||
document.l10n.setAttributes(
|
||||
defaultDescription,
|
||||
"translations-panel-default-description",
|
||||
{
|
||||
pageLanguage: displayNames.of(this.#docLangTag),
|
||||
}
|
||||
);
|
||||
|
||||
if (!this.#wasPanelShown) {
|
||||
// Note if a profile has used translations before, we may want to include additional
|
||||
// messaging for first time users.
|
||||
this.#wasPanelShown = true;
|
||||
Services.prefs.setBoolPref("browser.translations.panel.wasShown", true);
|
||||
}
|
||||
|
||||
for (const menuitem of defaultToMenuList.querySelectorAll("menuitem")) {
|
||||
// It is not valid to translate into the original doc language.
|
||||
menuitem.disabled = menuitem.value === this.#docLangTag;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the checked states of the settings menu checkboxes that
|
||||
* pertain to languages.
|
||||
@ -482,31 +535,24 @@ var TranslationsPanel = new (class {
|
||||
* @param {TranslationPair} translationPair
|
||||
*/
|
||||
async #showRevisitView({ fromLanguage, toLanguage }) {
|
||||
const { multiview, revisitHeader, revisitMenuList, revisitTranslate } =
|
||||
const { header, fromMenuList, toMenuList, restoreButton, notNowButton } =
|
||||
this.elements;
|
||||
|
||||
await this.#ensureLangListsBuilt();
|
||||
fromMenuList.value = fromLanguage;
|
||||
toMenuList.value = toLanguage;
|
||||
this.onChangeLanguages();
|
||||
|
||||
revisitMenuList.value = "";
|
||||
revisitTranslate.disabled = true;
|
||||
multiview.setAttribute("mainViewId", "translations-panel-view-revisit");
|
||||
restoreButton.hidden = false;
|
||||
notNowButton.hidden = true;
|
||||
|
||||
const displayNames = new Services.intl.DisplayNames(undefined, {
|
||||
type: "language",
|
||||
});
|
||||
|
||||
for (const menuitem of revisitMenuList.querySelectorAll("menuitem")) {
|
||||
menuitem.disabled = menuitem.value === toLanguage;
|
||||
}
|
||||
|
||||
document.l10n.setAttributes(
|
||||
revisitHeader,
|
||||
"translations-panel-revisit-header",
|
||||
{
|
||||
fromLanguage: displayNames.of(fromLanguage),
|
||||
toLanguage: displayNames.of(toLanguage),
|
||||
}
|
||||
);
|
||||
document.l10n.setAttributes(header, "translations-panel-revisit-header", {
|
||||
fromLanguage: displayNames.of(fromLanguage),
|
||||
toLanguage: displayNames.of(toLanguage),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -522,13 +568,43 @@ var TranslationsPanel = new (class {
|
||||
* When changing the "dual" view's language, handle cases where the translate button
|
||||
* should be disabled.
|
||||
*/
|
||||
onChangeDualLanguages() {
|
||||
const { dualTranslate, dualToMenuList, dualFromMenuList } = this.elements;
|
||||
dualTranslate.disabled =
|
||||
onChangeLanguages() {
|
||||
const { defaultTranslate, toMenuList, fromMenuList } = this.elements;
|
||||
defaultTranslate.disabled =
|
||||
// The translation languages are the same, don't allow this translation.
|
||||
dualToMenuList.value === dualFromMenuList.value ||
|
||||
toMenuList.value === fromMenuList.value ||
|
||||
// No "to" language was provided.
|
||||
!toMenuList.value ||
|
||||
// No "from" language was provided.
|
||||
!dualFromMenuList.value;
|
||||
!fromMenuList.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* When a language is not supported and the menu is manually invoked, an error message
|
||||
* is shown. This method switches the panel back to the language selection view.
|
||||
* Note that this bypasses the showSubView method since the main view doesn't support
|
||||
* a subview.
|
||||
*/
|
||||
async onChangeSourceLanguage(event) {
|
||||
const { panel } = this.elements;
|
||||
panel.addEventListener("popuphidden", async () => {}, { once: true });
|
||||
PanelMultiView.hidePopup(panel);
|
||||
|
||||
await this.#showDefaultView(true /* force this view to be shown */);
|
||||
|
||||
PanelMultiView.openPopup(panel, this.elements.appMenuButton, {
|
||||
position: "bottomright topright",
|
||||
triggeringEvent: event,
|
||||
}).catch(error => this.console.error(error));
|
||||
}
|
||||
|
||||
async #reloadLangList() {
|
||||
try {
|
||||
await this.#ensureLangListsBuilt();
|
||||
await this.#showDefaultView();
|
||||
} catch (error) {
|
||||
this.elements.errorHintAction.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -539,6 +615,8 @@ var TranslationsPanel = new (class {
|
||||
async open(event) {
|
||||
const { panel, button } = this.elements;
|
||||
|
||||
await this.#ensureLangListsBuilt();
|
||||
|
||||
const { requestedTranslationPair } =
|
||||
this.#getTranslationsActor().languageState;
|
||||
|
||||
@ -553,7 +631,12 @@ var TranslationsPanel = new (class {
|
||||
}
|
||||
|
||||
this.#populateSettingsMenuItems();
|
||||
PanelMultiView.openPopup(panel, button, {
|
||||
|
||||
const targetButton = button.contains(event.target)
|
||||
? button
|
||||
: this.elements.appMenuButton;
|
||||
|
||||
PanelMultiView.openPopup(panel, targetButton, {
|
||||
position: "bottomright topright",
|
||||
triggerEvent: event,
|
||||
}).catch(error => this.console.error(error));
|
||||
@ -581,42 +664,19 @@ var TranslationsPanel = new (class {
|
||||
return requestedTranslationPair !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the translation button being clicked on the default view.
|
||||
*/
|
||||
async onDefaultTranslate() {
|
||||
PanelMultiView.hidePopup(this.elements.panel);
|
||||
|
||||
const actor = this.#getTranslationsActor();
|
||||
const docLangTag = await this.#getDocLangTag();
|
||||
actor.translate(docLangTag, this.elements.defaultToMenuList.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the translation button being clicked when there are two language options.
|
||||
*/
|
||||
async onDualTranslate() {
|
||||
async onTranslate() {
|
||||
PanelMultiView.hidePopup(this.elements.panel);
|
||||
|
||||
const actor = this.#getTranslationsActor();
|
||||
actor.translate(
|
||||
this.elements.dualFromMenuList.value,
|
||||
this.elements.dualToMenuList.value
|
||||
this.elements.fromMenuList.value,
|
||||
this.elements.toMenuList.value
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the translation button being clicked when the page has already been
|
||||
* translated.
|
||||
*/
|
||||
async onRevisitTranslate() {
|
||||
PanelMultiView.hidePopup(this.elements.panel);
|
||||
|
||||
const actor = this.#getTranslationsActor();
|
||||
const docLangTag = await this.#getDocLangTag();
|
||||
actor.translate(docLangTag, this.elements.revisitMenuList.value);
|
||||
}
|
||||
|
||||
onCancel() {
|
||||
PanelMultiView.hidePopup(this.elements.panel);
|
||||
}
|
||||
@ -656,7 +716,7 @@ var TranslationsPanel = new (class {
|
||||
this.#updateSettingsMenuLanguageCheckboxStates();
|
||||
|
||||
if (toggledOn && !translationsActive) {
|
||||
await this.onDefaultTranslate();
|
||||
await this.onTranslate();
|
||||
} else if (!toggledOn && translationsActive) {
|
||||
await this.onRestore();
|
||||
}
|
||||
@ -796,18 +856,18 @@ var TranslationsPanel = new (class {
|
||||
switch (error) {
|
||||
case null:
|
||||
this.elements.error.hidden = true;
|
||||
this.elements.notNow.hidden = false;
|
||||
break;
|
||||
case "engine-load-failure":
|
||||
this.elements.error.hidden = false;
|
||||
this.elements.notNow.hidden = true;
|
||||
document.l10n.setAttributes(
|
||||
this.elements.errorMessage,
|
||||
"translations-panel-error-translating"
|
||||
);
|
||||
this.#showError({
|
||||
message: "translations-panel-error-translating",
|
||||
});
|
||||
const targetButton = button.hidden
|
||||
? this.elements.appMenuButton
|
||||
: button;
|
||||
|
||||
// Re-open the menu on an error.
|
||||
PanelMultiView.openPopup(panel, button, {
|
||||
PanelMultiView.openPopup(panel, targetButton, {
|
||||
position: "bottomright topright",
|
||||
}).catch(panelError => this.console.error(panelError));
|
||||
|
||||
|
@ -19,34 +19,9 @@ translations-panel-displayname-beta =
|
||||
|
||||
translations-panel-settings-manage-languages =
|
||||
.label = Manage languages
|
||||
translations-panel-settings-change-source-language =
|
||||
.label = Change source language
|
||||
# TODO(Bug 1831341): We still need the link for this menu item.
|
||||
translations-panel-settings-about = About translations in { -brand-shorter-name }
|
||||
|
||||
## The translation panel appears from the url bar, and this view is the default
|
||||
## translation view.
|
||||
|
||||
translations-panel-default-header = Translate this page?
|
||||
|
||||
# If your language requires declining the language name, a possible solution
|
||||
# is to adapt the structure of the phrase, or use a support noun, e.g.
|
||||
# `Looks like this page is in another language ({ $pageLanguage }). Want to translate it?`
|
||||
# Variables:
|
||||
# $pageLanguage (string) - The localized display name of the page's language
|
||||
translations-panel-default-description = Looks like this page is in { $pageLanguage }. Want to translate it?
|
||||
|
||||
# This label is followed, on a new line, by a dropdown list of language names.
|
||||
# If this structure is problematic for your locale, an alternative way is to
|
||||
# translate this as `Target language:`
|
||||
translations-panel-default-translate-to-label = Translate to
|
||||
translations-panel-default-translate-button = Translate
|
||||
translations-panel-default-translate-cancel = Not now
|
||||
|
||||
translations-panel-error-translating = There was a problem translating. Please try again.
|
||||
translations-panel-error-load-languages = Couldn’t load languages
|
||||
translations-panel-error-load-languages-hint = Check your internet connection and try again.
|
||||
|
||||
# Text displayed for the option to always translate a given language
|
||||
# Variables:
|
||||
# $language (string) - The localized display name of the detected language
|
||||
@ -67,19 +42,36 @@ translations-panel-settings-never-translate-unknown-language =
|
||||
translations-panel-settings-never-translate-site =
|
||||
.label = Never translate this site
|
||||
|
||||
## The translation panel appears from the url bar, and this view is the "dual" translate
|
||||
## view that lets you choose a source language and target language for translation
|
||||
## The translation panel appears from the url bar, and this view is the default
|
||||
## translation view.
|
||||
|
||||
translations-panel-dual-header =
|
||||
.title = Translate this page?
|
||||
translations-panel-dual-cancel-button = Cancel
|
||||
translations-panel-header = Translate this page?
|
||||
translations-panel-translate-button = Translate
|
||||
translations-panel-translate-cancel = Cancel
|
||||
|
||||
translations-panel-error-translating = There was a problem translating. Please try again.
|
||||
translations-panel-error-load-languages = Couldn’t load languages
|
||||
translations-panel-error-load-languages-hint = Check your internet connection and try again.
|
||||
translations-panel-error-load-languages-hint-button = Try again
|
||||
|
||||
translations-panel-error-unsupported = Translation isn’t available for this page
|
||||
translations-panel-error-dismiss-button = Got it
|
||||
translations-panel-error-change-button = Change source language
|
||||
# If your language requires declining the language name, a possible solution
|
||||
# is to adapt the structure of the phrase, or use a support noun, e.g.
|
||||
# `Sorry, we don't support the language yet: { $language }
|
||||
#
|
||||
# Variables:
|
||||
# $language (string) - The language of the document.
|
||||
translations-panel-error-unsupported-hint-known = Sorry, we don’t support { $language } yet.
|
||||
translations-panel-error-unsupported-hint-unknown = Sorry, we don’t support this language yet.
|
||||
|
||||
## Each label is followed, on a new line, by a dropdown list of language names.
|
||||
## If this structure is problematic for your locale, an alternative way is to
|
||||
## translate them as `Source language:` and `Target language:`
|
||||
|
||||
translations-panel-dual-from-label = Translate from
|
||||
translations-panel-dual-to-label = Translate to
|
||||
translations-panel-from-label = Translate from
|
||||
translations-panel-to-label = Translate to
|
||||
|
||||
## The translation panel appears from the url bar, and this view is the "restore" view
|
||||
## that lets a user restore a page to the original language, or translate into another
|
||||
@ -92,12 +84,10 @@ translations-panel-dual-to-label = Translate to
|
||||
# Variables:
|
||||
# $fromLanguage (string) - The original language of the document.
|
||||
# $toLanguage (string) - The target language of the translation.
|
||||
translations-panel-revisit-header = The page is translated from { $fromLanguage } to { $toLanguage }
|
||||
translations-panel-revisit-label = Want to try another language?
|
||||
translations-panel-revisit-header = This page is translated from { $fromLanguage } to { $toLanguage }
|
||||
translations-panel-choose-language =
|
||||
.label = Choose a language
|
||||
translations-panel-revisit-restore-button = Show original
|
||||
translations-panel-revisit-translate-button = Translate
|
||||
translations-panel-restore-button = Show original
|
||||
|
||||
## Firefox Translations language management in about:preferences.
|
||||
|
||||
|
@ -23,16 +23,15 @@ image.translations-panel-gear-icon {
|
||||
}
|
||||
|
||||
.translations-panel-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: var(--arrowpanel-padding);
|
||||
gap: var(--arrowpanel-padding);
|
||||
}
|
||||
|
||||
.translations-panel-content > label:first-child {
|
||||
#translations-panel-lang-selection > label:first-child {
|
||||
margin-block-start: 0;
|
||||
}
|
||||
|
||||
.translations-panel-content > label {
|
||||
#translations-panel-lang-selection > label {
|
||||
margin-block: var(--arrowpanel-padding) 6px;
|
||||
}
|
||||
|
||||
@ -43,18 +42,35 @@ image.translations-panel-gear-icon {
|
||||
background-color: var(--button-primary-bgcolor);
|
||||
}
|
||||
|
||||
#translations-panel-error {
|
||||
color: #e22850;
|
||||
/* Align the error icon to the start. */
|
||||
align-items: start;
|
||||
#translations-panel-translate-hint-action {
|
||||
appearance: none;
|
||||
background-color: var(--button-bgcolor);
|
||||
border-radius: 4px;
|
||||
color: var(--button-color);
|
||||
padding: 8px 16px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
@media (-moz-platform: windows) {
|
||||
#translations-panel-error {
|
||||
/* On windows the default button in the panel-footer is flipped with the order
|
||||
property. In order to keep the error on the flex-start, it also needs a -1 order. */
|
||||
order: -1;
|
||||
}
|
||||
#translations-panel-translate-hint-action:hover {
|
||||
background-color: var(--button-hover-bgcolor);
|
||||
}
|
||||
|
||||
#translations-panel-translate-hint-action:hover:active {
|
||||
background-color: var(--button-active-bgcolor);
|
||||
}
|
||||
|
||||
#translations-panel-translate-hint-action:focus-visible {
|
||||
outline: var(--focus-outline);
|
||||
outline-offset: var(--focus-outline-offset);
|
||||
}
|
||||
|
||||
#translations-panel-error-message-hint {
|
||||
margin-inline-start: 21px;
|
||||
margin-block: 8px;
|
||||
}
|
||||
|
||||
#translations-panel-error-message {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.translations-panel-error-icon {
|
||||
@ -62,10 +78,15 @@ image.translations-panel-gear-icon {
|
||||
fill: currentColor;
|
||||
list-style-image: url(chrome://global/skin/icons/error.svg);
|
||||
margin-inline-end: 5px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
#translations-panel-error {
|
||||
color: #ff9aa2;
|
||||
}
|
||||
.translations-panel-error-header {
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
#translations-panel-error {
|
||||
border: 1px solid currentColor;
|
||||
border-radius: 4px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user