mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 12:51:06 +00:00
Bug 1813777 - Display beta tags on beta languages for Firefox Translations r=gregtatum,fluent-reviewers,flod
Displays languages as being in beta in the selectors for both the about:translations page and for in-page translations. Differential Revision: https://phabricator.services.mozilla.com/D175440
This commit is contained in:
parent
6829a78aa2
commit
b6ddd10aad
@ -168,16 +168,32 @@ var TranslationsPanel = new (class {
|
||||
throw new Error("No translation languages were retrieved.");
|
||||
}
|
||||
|
||||
for (const { langTag, displayName } of fromLanguages) {
|
||||
for (const { langTag, isBeta, displayName } of fromLanguages) {
|
||||
const fromMenuItem = document.createXULElement("menuitem");
|
||||
fromMenuItem.setAttribute("label", displayName);
|
||||
fromMenuItem.setAttribute("value", langTag);
|
||||
if (isBeta) {
|
||||
document.l10n.setAttributes(
|
||||
fromMenuItem,
|
||||
"translations-panel-displayname-beta",
|
||||
{ language: displayName }
|
||||
);
|
||||
} else {
|
||||
fromMenuItem.setAttribute("label", displayName);
|
||||
}
|
||||
this.elements.fromMenuPopup.appendChild(fromMenuItem);
|
||||
}
|
||||
for (const { langTag, displayName } of toLanguages) {
|
||||
for (const { langTag, isBeta, displayName } of toLanguages) {
|
||||
const toMenuItem = document.createXULElement("menuitem");
|
||||
toMenuItem.setAttribute("label", displayName);
|
||||
toMenuItem.setAttribute("value", langTag);
|
||||
if (isBeta) {
|
||||
document.l10n.setAttributes(
|
||||
toMenuItem,
|
||||
"translations-panel-displayname-beta",
|
||||
{ language: displayName }
|
||||
);
|
||||
} else {
|
||||
toMenuItem.setAttribute("label", displayName);
|
||||
}
|
||||
this.elements.toMenuPopup.appendChild(toMenuItem);
|
||||
}
|
||||
this.#langListsPhase = "initialized";
|
||||
|
@ -4,10 +4,12 @@
|
||||
"use strict";
|
||||
|
||||
const languagePairs = [
|
||||
{ fromLang: "es", toLang: "en" },
|
||||
{ fromLang: "en", toLang: "es" },
|
||||
{ fromLang: "fr", toLang: "en" },
|
||||
{ fromLang: "en", toLang: "fr" },
|
||||
{ fromLang: "es", toLang: "en", isBeta: false },
|
||||
{ fromLang: "en", toLang: "es", isBeta: false },
|
||||
{ fromLang: "fr", toLang: "en", isBeta: false },
|
||||
{ fromLang: "en", toLang: "fr", isBeta: false },
|
||||
{ fromLang: "en", toLang: "uk", isBeta: true },
|
||||
{ fromLang: "uk", toLang: "en", isBeta: true },
|
||||
];
|
||||
|
||||
const spanishPageUrl = TRANSLATIONS_TESTER_ES;
|
||||
@ -226,3 +228,49 @@ add_task(async function test_translations_panel_switch_language() {
|
||||
|
||||
await cleanup();
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that languages are displayed correctly as being in beta or not.
|
||||
*/
|
||||
add_task(async function test_translations_panel_display_beta_languages() {
|
||||
const { cleanup } = await loadTestPage({
|
||||
page: spanishPageUrl,
|
||||
languagePairs,
|
||||
});
|
||||
|
||||
function assertBetaDisplay(selectElement) {
|
||||
const betaL10nId = "translations-panel-displayname-beta";
|
||||
const options = selectElement.firstChild.getElementsByTagName("menuitem");
|
||||
for (const option of options) {
|
||||
for (const languagePair of languagePairs) {
|
||||
if (
|
||||
languagePair.fromLang === option.value ||
|
||||
languagePair.toLang === option.value
|
||||
) {
|
||||
if (option.getAttribute("data-l10n-id") === betaL10nId) {
|
||||
is(
|
||||
languagePair.isBeta,
|
||||
true,
|
||||
`Since data-l10n-id was ${betaL10nId} for ${option.value}, then it must be part of a beta language pair, but it was not.`
|
||||
);
|
||||
}
|
||||
if (!languagePair.isBeta) {
|
||||
is(
|
||||
option.getAttribute("data-l10n-id") === betaL10nId,
|
||||
false,
|
||||
`Since the languagePair is non-beta, the language option ${option.value} should not have a data-l10-id of ${betaL10nId}, but it does.`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const fromSelect = document.getElementById("translations-panel-from");
|
||||
const toSelect = document.getElementById("translations-panel-to");
|
||||
|
||||
assertBetaDisplay(fromSelect);
|
||||
assertBetaDisplay(toSelect);
|
||||
|
||||
await cleanup();
|
||||
});
|
||||
|
@ -14,6 +14,12 @@ translations-panel-dual-from-label = Choose the current page language
|
||||
translations-panel-dual-to-label = Choose the language to translate into
|
||||
translations-panel-dual-translate-button = Translate
|
||||
|
||||
# Text displayed on a language dropdown when the language is in beta
|
||||
# Variables:
|
||||
# $language (string) - The localized display name of the detected language
|
||||
translations-panel-displayname-beta =
|
||||
.label = { $language } BETA
|
||||
|
||||
## 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.
|
||||
|
||||
|
@ -423,15 +423,17 @@ export class TranslationsParent extends JSWindowActorParent {
|
||||
}
|
||||
const records = await this.#getTranslationModelRecords();
|
||||
const languagePairKeys = new Set();
|
||||
for (const { fromLang, toLang } of records.values()) {
|
||||
languagePairKeys.add(fromLang + toLang);
|
||||
for (const { fromLang, toLang, version } of records.values()) {
|
||||
const isBeta = Services.vc.compare(version, "1.0") < 0;
|
||||
languagePairKeys.add({ key: fromLang + toLang, isBeta });
|
||||
}
|
||||
|
||||
const languagePairs = [];
|
||||
for (const key of languagePairKeys) {
|
||||
for (const { key, isBeta } of languagePairKeys) {
|
||||
languagePairs.push({
|
||||
fromLang: key[0] + key[1],
|
||||
toLang: key[2] + key[3],
|
||||
isBeta,
|
||||
});
|
||||
}
|
||||
|
||||
@ -447,14 +449,31 @@ export class TranslationsParent extends JSWindowActorParent {
|
||||
async getSupportedLanguages() {
|
||||
const languagePairs = await this.getLanguagePairs();
|
||||
|
||||
/** @type {Set<string>} */
|
||||
const fromLanguages = new Set();
|
||||
/** @type {Set<string>} */
|
||||
const toLanguages = new Set();
|
||||
/** @type {Map<string, boolean>} */
|
||||
const fromLanguages = new Map();
|
||||
/** @type {Map<string, boolean>} */
|
||||
const toLanguages = new Map();
|
||||
|
||||
for (const { fromLang, toLang } of languagePairs) {
|
||||
fromLanguages.add(fromLang);
|
||||
toLanguages.add(toLang);
|
||||
for (const { fromLang, toLang, isBeta } of languagePairs) {
|
||||
// [BetaLanguage, BetaLanguage] => isBeta == true,
|
||||
// [BetaLanguage, NonBetaLanguage] => isBeta == true,
|
||||
// [NonBetaLanguage, BetaLanguage] => isBeta == true,
|
||||
// [NonBetaLanguage, NonBetaLanguage] => isBeta == false,
|
||||
if (isBeta) {
|
||||
// If these languages are part of a beta languagePair, at least one of them is a beta language
|
||||
// but the other may not be, so only tentatively mark them as beta if there is no entry.
|
||||
if (!fromLanguages.has(fromLang)) {
|
||||
fromLanguages.set(fromLang, isBeta);
|
||||
}
|
||||
if (!toLanguages.has(toLang)) {
|
||||
toLanguages.set(toLang, isBeta);
|
||||
}
|
||||
} else {
|
||||
// If these languages are part of a non-beta languagePair, then they are both
|
||||
// guaranteed to be non-beta languages. Idempotently overwrite any previous entry.
|
||||
fromLanguages.set(fromLang, isBeta);
|
||||
toLanguages.set(toLang, isBeta);
|
||||
}
|
||||
}
|
||||
|
||||
// Build a map of the langTag to the display name.
|
||||
@ -466,7 +485,7 @@ export class TranslationsParent extends JSWindowActorParent {
|
||||
});
|
||||
|
||||
for (const langTagSet of [fromLanguages, toLanguages]) {
|
||||
for (const langTag of langTagSet) {
|
||||
for (const langTag of langTagSet.keys()) {
|
||||
if (displayNames.has(langTag)) {
|
||||
continue;
|
||||
}
|
||||
@ -475,8 +494,9 @@ export class TranslationsParent extends JSWindowActorParent {
|
||||
}
|
||||
}
|
||||
|
||||
const addDisplayName = langTag => ({
|
||||
const addDisplayName = ([langTag, isBeta]) => ({
|
||||
langTag,
|
||||
isBeta,
|
||||
displayName: displayNames.get(langTag),
|
||||
});
|
||||
|
||||
@ -484,8 +504,12 @@ export class TranslationsParent extends JSWindowActorParent {
|
||||
|
||||
return {
|
||||
languagePairs,
|
||||
fromLanguages: [...fromLanguages].map(addDisplayName).sort(sort),
|
||||
toLanguages: [...toLanguages].map(addDisplayName).sort(sort),
|
||||
fromLanguages: Array.from(fromLanguages.entries())
|
||||
.map(addDisplayName)
|
||||
.sort(sort),
|
||||
toLanguages: Array.from(toLanguages.entries())
|
||||
.map(addDisplayName)
|
||||
.sort(sort),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -286,9 +286,9 @@ class TranslationsState {
|
||||
({ langTag }) => langTag === languageLabel
|
||||
);
|
||||
if (entry) {
|
||||
const { displayName } = entry;
|
||||
const { displayName, isBeta } = entry;
|
||||
await this.setFromLanguage(languageLabel);
|
||||
this.ui.setDetectOptionTextContent(displayName);
|
||||
this.ui.setDetectOptionTextContent(displayName, isBeta);
|
||||
}
|
||||
}
|
||||
|
||||
@ -390,17 +390,41 @@ class TranslationsUI {
|
||||
const supportedLanguages = await this.state.supportedLanguages;
|
||||
|
||||
// Update the DOM elements with the display names.
|
||||
for (const { langTag, displayName } of supportedLanguages.toLanguages) {
|
||||
for (const {
|
||||
langTag,
|
||||
isBeta,
|
||||
displayName,
|
||||
} of supportedLanguages.toLanguages) {
|
||||
const option = document.createElement("option");
|
||||
option.value = langTag;
|
||||
option.text = displayName;
|
||||
if (isBeta) {
|
||||
document.l10n.setAttributes(
|
||||
option,
|
||||
"about-translations-displayname-beta",
|
||||
{ language: displayName }
|
||||
);
|
||||
} else {
|
||||
option.text = displayName;
|
||||
}
|
||||
this.languageTo.add(option);
|
||||
}
|
||||
|
||||
for (const { langTag, displayName } of supportedLanguages.fromLanguages) {
|
||||
for (const {
|
||||
langTag,
|
||||
isBeta,
|
||||
displayName,
|
||||
} of supportedLanguages.fromLanguages) {
|
||||
const option = document.createElement("option");
|
||||
option.value = langTag;
|
||||
option.text = displayName;
|
||||
if (isBeta) {
|
||||
document.l10n.setAttributes(
|
||||
option,
|
||||
"about-translations-displayname-beta",
|
||||
{ language: displayName }
|
||||
);
|
||||
} else {
|
||||
option.text = displayName;
|
||||
}
|
||||
this.languageFrom.add(option);
|
||||
}
|
||||
|
||||
@ -464,12 +488,14 @@ class TranslationsUI {
|
||||
*
|
||||
* @param {string} displayName
|
||||
*/
|
||||
setDetectOptionTextContent(displayName) {
|
||||
setDetectOptionTextContent(displayName, isBeta = false) {
|
||||
// Set the text to the fluent value that takes an arg to display the language name.
|
||||
if (displayName) {
|
||||
// Set the text to the fluent value that takes an arg to display the language name.
|
||||
document.l10n.setAttributes(
|
||||
this.#detectOption,
|
||||
"about-translations-detect-lang",
|
||||
isBeta
|
||||
? "about-translations-detect-lang-beta"
|
||||
: "about-translations-detect-lang",
|
||||
{ language: displayName }
|
||||
);
|
||||
} else {
|
||||
|
@ -82,14 +82,16 @@ add_task(async function test_about_translations_disabled() {
|
||||
});
|
||||
|
||||
add_task(async function test_about_translations_dropdowns() {
|
||||
let languagePairs = [
|
||||
{ fromLang: "en", toLang: "es", isBeta: false },
|
||||
{ fromLang: "es", toLang: "en", isBeta: false },
|
||||
// This is not a bi-directional translation.
|
||||
{ fromLang: "is", toLang: "en", isBeta: true },
|
||||
];
|
||||
await openAboutTranslations({
|
||||
languagePairs: [
|
||||
{ fromLang: "en", toLang: "es" },
|
||||
{ fromLang: "es", toLang: "en" },
|
||||
// This is not a bi-directional translation.
|
||||
{ fromLang: "is", toLang: "en" },
|
||||
],
|
||||
runInPage: async ({ selectors }) => {
|
||||
languagePairs,
|
||||
dataForContent: languagePairs,
|
||||
runInPage: async ({ dataForContent: languagePairs, selectors }) => {
|
||||
const { document } = content;
|
||||
|
||||
await ContentTaskUtils.waitForCondition(() => {
|
||||
@ -112,16 +114,38 @@ add_task(async function test_about_translations_dropdowns() {
|
||||
availableOptions,
|
||||
selectedValue,
|
||||
}) {
|
||||
const options = [...select.options]
|
||||
.filter(option => !option.hidden)
|
||||
.map(option => option.value);
|
||||
|
||||
const options = [...select.options];
|
||||
const betaL10nId = "about-translations-displayname-beta";
|
||||
for (const option of options) {
|
||||
for (const languagePair of languagePairs) {
|
||||
if (
|
||||
languagePair.fromLang === option.value ||
|
||||
languagePair.toLang === option.value
|
||||
) {
|
||||
if (option.getAttribute("data-l10n-id") === betaL10nId) {
|
||||
is(
|
||||
languagePair.isBeta,
|
||||
true,
|
||||
`Since data-l10n-id was ${betaL10nId} for ${option.value}, then it must be part of a beta language pair, but it was not.`
|
||||
);
|
||||
}
|
||||
if (!languagePair.isBeta) {
|
||||
is(
|
||||
option.getAttribute("data-l10n-id") === betaL10nId,
|
||||
false,
|
||||
`Since the languagePair is non-beta, the language option ${option.value} should not have a data-l10-id of ${betaL10nId}, but it does.`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
info(message);
|
||||
Assert.deepEqual(
|
||||
options,
|
||||
options.filter(option => !option.hidden).map(option => option.value),
|
||||
availableOptions,
|
||||
"The available options match."
|
||||
);
|
||||
|
||||
is(selectedValue, select.value, "The selected value matches.");
|
||||
}
|
||||
|
||||
@ -192,10 +216,10 @@ add_task(async function test_about_translations_dropdowns() {
|
||||
add_task(async function test_about_translations_translations() {
|
||||
await openAboutTranslations({
|
||||
languagePairs: [
|
||||
{ fromLang: "en", toLang: "fr" },
|
||||
{ fromLang: "fr", toLang: "en" },
|
||||
{ fromLang: "en", toLang: "fr", isBeta: false },
|
||||
{ fromLang: "fr", toLang: "en", isBeta: false },
|
||||
// This is not a bi-directional translation.
|
||||
{ fromLang: "is", toLang: "en" },
|
||||
{ fromLang: "is", toLang: "en", isBeta: true },
|
||||
],
|
||||
runInPage: async ({ selectors }) => {
|
||||
const { document, window } = content;
|
||||
@ -280,8 +304,8 @@ add_task(async function test_about_translations_language_directions() {
|
||||
await openAboutTranslations({
|
||||
languagePairs: [
|
||||
// English (en) is LTR and Arabic (ar) is RTL.
|
||||
{ fromLang: "en", toLang: "ar" },
|
||||
{ fromLang: "ar", toLang: "en" },
|
||||
{ fromLang: "en", toLang: "ar", isBeta: true },
|
||||
{ fromLang: "ar", toLang: "en", isBeta: true },
|
||||
],
|
||||
runInPage: async ({ selectors }) => {
|
||||
const { document, window } = content;
|
||||
@ -351,8 +375,8 @@ add_task(async function test_about_translations_language_directions() {
|
||||
add_task(async function test_about_translations_debounce() {
|
||||
await openAboutTranslations({
|
||||
languagePairs: [
|
||||
{ fromLang: "en", toLang: "fr" },
|
||||
{ fromLang: "fr", toLang: "en" },
|
||||
{ fromLang: "en", toLang: "fr", isBeta: false },
|
||||
{ fromLang: "fr", toLang: "en", isBeta: false },
|
||||
],
|
||||
runInPage: async ({ selectors }) => {
|
||||
const { document, window } = content;
|
||||
@ -431,8 +455,8 @@ add_task(async function test_about_translations_debounce() {
|
||||
add_task(async function test_about_translations_html() {
|
||||
await openAboutTranslations({
|
||||
languagePairs: [
|
||||
{ fromLang: "en", toLang: "fr" },
|
||||
{ fromLang: "fr", toLang: "en" },
|
||||
{ fromLang: "en", toLang: "fr", isBeta: false },
|
||||
{ fromLang: "fr", toLang: "en", isBeta: false },
|
||||
],
|
||||
prefs: [["browser.translations.useHTML", true]],
|
||||
runInPage: async ({ selectors }) => {
|
||||
@ -492,8 +516,8 @@ add_task(async function test_about_translations_language_identification() {
|
||||
detectedLanguageLabel: "en",
|
||||
detectedLanguageConfidence: "0.98",
|
||||
languagePairs: [
|
||||
{ fromLang: "en", toLang: "fr" },
|
||||
{ fromLang: "fr", toLang: "en" },
|
||||
{ fromLang: "en", toLang: "fr", isBeta: false },
|
||||
{ fromLang: "fr", toLang: "en", isBeta: false },
|
||||
],
|
||||
runInPage: async ({ selectors }) => {
|
||||
const { document, window } = content;
|
||||
|
@ -11,8 +11,8 @@ add_task(async function test_full_page_translation() {
|
||||
page: TRANSLATIONS_TESTER_ES,
|
||||
prefs: [["browser.translations.autoTranslate", true]],
|
||||
languagePairs: [
|
||||
{ fromLang: "es", toLang: "en" },
|
||||
{ fromLang: "en", toLang: "es" },
|
||||
{ fromLang: "es", toLang: "en", isBeta: false },
|
||||
{ fromLang: "en", toLang: "es", isBeta: false },
|
||||
],
|
||||
runInPage: async TranslationsTest => {
|
||||
const selectors = TranslationsTest.getSelectors();
|
||||
@ -65,8 +65,8 @@ add_task(async function test_about_translations_enabled() {
|
||||
page: TRANSLATIONS_TESTER_EN,
|
||||
prefs: [["browser.translations.autoTranslate", true]],
|
||||
languagePairs: [
|
||||
{ fromLang: "es", toLang: "en" },
|
||||
{ fromLang: "en", toLang: "es" },
|
||||
{ fromLang: "es", toLang: "en", isBeta: false },
|
||||
{ fromLang: "en", toLang: "es", isBeta: false },
|
||||
],
|
||||
runInPage: async () => {
|
||||
const { document } = content;
|
||||
@ -104,8 +104,8 @@ add_task(async function test_language_identification_for_page_translation() {
|
||||
detectedLanguageLabel: "es",
|
||||
detectedLanguageConfidence: 0.95,
|
||||
languagePairs: [
|
||||
{ fromLang: "es", toLang: "en" },
|
||||
{ fromLang: "en", toLang: "es" },
|
||||
{ fromLang: "es", toLang: "en", isBeta: false },
|
||||
{ fromLang: "en", toLang: "es", isBeta: false },
|
||||
],
|
||||
runInPage: async TranslationsTest => {
|
||||
const selectors = TranslationsTest.getSelectors();
|
||||
|
@ -19,13 +19,13 @@ add_task(async function test_pivot_language_behavior() {
|
||||
|
||||
const { actor, cleanup } = await setupActorTest({
|
||||
languagePairs: [
|
||||
{ fromLang: "en", toLang: "es" },
|
||||
{ fromLang: "es", toLang: "en" },
|
||||
{ fromLang: "en", toLang: "es", isBeta: false },
|
||||
{ fromLang: "es", toLang: "en", isBeta: false },
|
||||
// This is not a bi-directional translation.
|
||||
{ fromLang: "is", toLang: "en" },
|
||||
{ fromLang: "is", toLang: "en", isBeta: false },
|
||||
// These are non-pivot languages.
|
||||
{ fromLang: "zh", toLang: "ja" },
|
||||
{ fromLang: "ja", toLang: "zh" },
|
||||
{ fromLang: "zh", toLang: "ja", isBeta: true },
|
||||
{ fromLang: "ja", toLang: "zh", isBeta: true },
|
||||
],
|
||||
});
|
||||
|
||||
@ -34,9 +34,9 @@ add_task(async function test_pivot_language_behavior() {
|
||||
Assert.deepEqual(
|
||||
languagePairs,
|
||||
[
|
||||
{ fromLang: "en", toLang: "es" },
|
||||
{ fromLang: "es", toLang: "en" },
|
||||
{ fromLang: "is", toLang: "en" },
|
||||
{ fromLang: "en", toLang: "es", isBeta: false },
|
||||
{ fromLang: "es", toLang: "en", isBeta: false },
|
||||
{ fromLang: "is", toLang: "en", isBeta: false },
|
||||
],
|
||||
"Non-pivot languages were removed."
|
||||
);
|
||||
|
@ -45,7 +45,7 @@ const TRANSLATIONS_TESTER_NO_TAG =
|
||||
* This is the two-letter language label for the MockedLanguageIdEngine to return as
|
||||
* the mocked detected language.
|
||||
*
|
||||
* @param {Array<{ fromLang: string, toLang: string}>} options.languagePairs
|
||||
* @param {Array<{ fromLang: string, toLang: string, isBeta: boolean }>} options.languagePairs
|
||||
* The translation languages pairs to mock for the test.
|
||||
*
|
||||
* @param {Array<[string, string]>} options.prefs
|
||||
|
@ -301,6 +301,6 @@ export interface LanguagePair { fromLang: string, toLang: string };
|
||||
*/
|
||||
export interface SupportedLanguages {
|
||||
langPairs: LanguagePair[],
|
||||
fromLanguages: Array<{ langTag: string, displayName: string }>,
|
||||
toLanguages: Array<{ langTag: string, displayName: string }>,
|
||||
fromLanguages: Array<{ langTag: string, isBeta: boolean, displayName: string, }>,
|
||||
toLanguages: Array<{ langTag: string, isBeta: boolean, displayName: string }>,
|
||||
}
|
||||
|
@ -8,10 +8,18 @@ about-translations-header = { -translations-brand-name }
|
||||
about-translations-results-placeholder = Translation
|
||||
# Text displayed on from-language dropdown when no language is selected
|
||||
about-translations-detect = Detect language
|
||||
# Text displayed on a language dropdown when the language is in beta
|
||||
# Variables:
|
||||
# $language (string) - The localized display name of the language
|
||||
about-translations-displayname-beta = { $language } BETA
|
||||
# Text displayed on from-language dropdown when a language is detected
|
||||
# Variables:
|
||||
# $language (string) - The localized display name of the detected language
|
||||
about-translations-detect-lang = Detect language ({ $language })
|
||||
# Text displayed on from-language dropdown when a beta language is detected
|
||||
# Variables:
|
||||
# $language (string) - The localized display name of the detected language
|
||||
about-translations-detect-lang-beta = Detect language ({ $language } BETA)
|
||||
# Text displayed on to-language dropdown when no language is selected
|
||||
about-translations-select = Select language
|
||||
about-translations-textarea =
|
||||
|
Loading…
Reference in New Issue
Block a user