diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js
index af9c34967156..2b611eb48e0c 100644
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -2174,8 +2174,6 @@ pref("app.normandy.onsync_skew_sec", 600);
// live reloading when switching between LTR and RTL languages.
pref("intl.multilingual.liveReload", false);
pref("intl.multilingual.liveReloadBidirectional", false);
-// Suggest to change the language on about:welcome when there is a mismatch with the OS.
-pref("intl.multilingual.aboutWelcome.languageMismatchEnabled", false);
// Simulate conditions that will happen when the browser
diff --git a/browser/components/newtab/aboutwelcome/AboutWelcomeChild.jsm b/browser/components/newtab/aboutwelcome/AboutWelcomeChild.jsm
index 2a71a282cdc2..f6e22ca6162b 100644
--- a/browser/components/newtab/aboutwelcome/AboutWelcomeChild.jsm
+++ b/browser/components/newtab/aboutwelcome/AboutWelcomeChild.jsm
@@ -162,22 +162,6 @@ class AboutWelcomeChild extends JSWindowActorChild {
Cu.exportFunction(this.AWFinish.bind(this), window, {
defineAs: "AWFinish",
});
-
- Cu.exportFunction(this.AWEnsureLangPackInstalled.bind(this), window, {
- defineAs: "AWEnsureLangPackInstalled",
- });
-
- Cu.exportFunction(
- this.AWNegotiateLangPackForLanguageMismatch.bind(this),
- window,
- {
- defineAs: "AWNegotiateLangPackForLanguageMismatch",
- }
- );
-
- Cu.exportFunction(this.AWSetRequestedLocales.bind(this), window, {
- defineAs: "AWSetRequestedLocales",
- });
}
/**
@@ -189,20 +173,6 @@ class AboutWelcomeChild extends JSWindowActorChild {
);
}
- /**
- * Clones the result of the query into the content window.
- */
- sendQueryAndCloneForContent(...sendQueryArgs) {
- return this.wrapPromise(
- (async () => {
- return Cu.cloneInto(
- await this.sendQuery(...sendQueryArgs),
- this.contentWindow
- );
- })()
- );
- }
-
AWSelectTheme(data) {
return this.wrapPromise(
this.sendQuery("AWPage:SELECT_THEME", data.toUpperCase())
@@ -236,11 +206,6 @@ class AboutWelcomeChild extends JSWindowActorChild {
let featureConfig = NimbusFeatures.aboutwelcome.getAllVariables();
featureConfig.needDefault = await this.sendQuery("AWPage:NEED_DEFAULT");
featureConfig.needPin = await this.sendQuery("AWPage:DOES_APP_NEED_PIN");
- if (featureConfig.languageMismatchEnabled) {
- featureConfig.appAndSystemLocaleInfo = await this.sendQuery(
- "AWPage:GET_APP_AND_SYSTEM_LOCALE_INFO"
- );
- }
let defaults = AboutWelcomeDefaults.getDefaults();
// FeatureConfig (from prefs or experiments) has higher precendence
// to defaults. But the `screens` property isn't defined we shouldn't
@@ -312,27 +277,6 @@ class AboutWelcomeChild extends JSWindowActorChild {
this.contentWindow.location.href = "about:home";
}
- AWEnsureLangPackInstalled(langPack) {
- return this.sendQueryAndCloneForContent(
- "AWPage:ENSURE_LANG_PACK_INSTALLED",
- langPack
- );
- }
-
- AWSetRequestedLocales(requestSystemLocales) {
- return this.sendQueryAndCloneForContent(
- "AWPage:SET_REQUESTED_LOCALES",
- requestSystemLocales
- );
- }
-
- AWNegotiateLangPackForLanguageMismatch(appAndSystemLocaleInfo) {
- return this.sendQueryAndCloneForContent(
- "AWPage:NEGOTIATE_LANGPACK",
- appAndSystemLocaleInfo
- );
- }
-
/**
* @param {{type: string, detail?: any}} event
* @override
diff --git a/browser/components/newtab/aboutwelcome/AboutWelcomeParent.jsm b/browser/components/newtab/aboutwelcome/AboutWelcomeParent.jsm
index 1f4fb31053ed..8a5ddfbf7c28 100644
--- a/browser/components/newtab/aboutwelcome/AboutWelcomeParent.jsm
+++ b/browser/components/newtab/aboutwelcome/AboutWelcomeParent.jsm
@@ -25,7 +25,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
PromiseUtils: "resource://gre/modules/PromiseUtils.jsm",
Region: "resource://gre/modules/Region.jsm",
ShellService: "resource:///modules/ShellService.jsm",
- LangPackMatcher: "resource://gre/modules/LangPackMatcher.jsm",
});
XPCOMUtils.defineLazyGetter(this, "log", () => {
@@ -305,14 +304,6 @@ class AboutWelcomeParent extends JSWindowActorParent {
}
})
);
- case "AWPage:GET_APP_AND_SYSTEM_LOCALE_INFO":
- return LangPackMatcher.getAppAndSystemLocaleInfo();
- case "AWPage:NEGOTIATE_LANGPACK":
- return LangPackMatcher.negotiateLangPackForLanguageMismatch(data);
- case "AWPage:ENSURE_LANG_PACK_INSTALLED":
- return LangPackMatcher.ensureLangPackInstalled(data);
- case "AWPage:SET_REQUESTED_LOCALES":
- return LangPackMatcher.setRequestedAppLocales(data);
default:
log.debug(`Unexpected event ${type} was not handled.`);
}
diff --git a/browser/components/newtab/aboutwelcome/content/aboutwelcome.bundle.js b/browser/components/newtab/aboutwelcome/content/aboutwelcome.bundle.js
index 5f58c18863cc..621c2bf92bbb 100644
--- a/browser/components/newtab/aboutwelcome/content/aboutwelcome.bundle.js
+++ b/browser/components/newtab/aboutwelcome/content/aboutwelcome.bundle.js
@@ -101,7 +101,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _components_MultiStageAboutWelcome__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3);
-/* harmony import */ var _components_ReturnToAMO__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(11);
+/* harmony import */ var _components_ReturnToAMO__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(10);
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
/* This Source Code Form is subject to the terms of the Mozilla Public
@@ -191,8 +191,7 @@ class AboutWelcome extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComp
metricsFlowUri: this.state.metricsFlowUri,
utm_term: props.UTMTerm,
transitions: props.transitions,
- backdrop: props.backdrop,
- appAndSystemLocaleInfo: props.appAndSystemLocaleInfo
+ backdrop: props.backdrop
});
}
@@ -277,8 +276,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
/* harmony import */ var _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5);
/* harmony import */ var _MultiStageProtonScreen__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6);
-/* harmony import */ var _LanguageSwitcher__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(9);
-/* harmony import */ var _asrouter_templates_FirstRun_addUtmParams__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(10);
+/* harmony import */ var _asrouter_templates_FirstRun_addUtmParams__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(9);
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
@@ -286,18 +284,14 @@ __webpack_require__.r(__webpack_exports__);
-
// Amount of milliseconds for all transitions to complete (including delays).
const TRANSITION_OUT_TIME = 1000;
const MultiStageAboutWelcome = props => {
- let {
- screens
- } = props;
const [index, setScreenIndex] = Object(react__WEBPACK_IMPORTED_MODULE_0__["useState"])(0);
Object(react__WEBPACK_IMPORTED_MODULE_0__["useEffect"])(() => {
// Send impression ping when respective screen first renders
- screens.forEach((screen, order) => {
+ props.screens.forEach((screen, order) => {
if (index === order) {
_lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_2__["AboutWelcomeUtils"].sendImpressionTelemetry(`${props.message_id}_${order}_${screen.id}`);
}
@@ -313,7 +307,7 @@ const MultiStageAboutWelcome = props => {
// button from about:home
const handler = ({
state
- }) => setScreenIndex(Math.min(state, screens.length - 1)); // Handle page load, e.g., going back to about:welcome from about:home
+ }) => setScreenIndex(Math.min(state, props.screens.length - 1)); // Handle page load, e.g., going back to about:welcome from about:home
handler(window.history); // Watch for browser back/forward button navigation events
@@ -351,7 +345,7 @@ const MultiStageAboutWelcome = props => {
setTransition(props.transitions ? "out" : ""); // Actually move forwards after all transitions finish.
setTimeout(() => {
- if (index < screens.length - 1) {
+ if (index < props.screens.length - 1) {
setTransition(props.transitions ? "in" : "");
setScreenIndex(prevState => prevState + 1);
} else {
@@ -406,24 +400,18 @@ const MultiStageAboutWelcome = props => {
})();
}, [useImportable, region]);
const centeredScreens = props.screens.filter(s => s.content.position !== "corner");
- const {
- negotiatedLanguage,
- langPackInstallPhase,
- languageFilteredScreens
- } = Object(_LanguageSwitcher__WEBPACK_IMPORTED_MODULE_4__["useLanguageSwitcher"])(props.appAndSystemLocaleInfo, screens, index, setScreenIndex);
- screens = languageFilteredScreens;
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_0___default.a.Fragment, null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
className: `outer-wrapper onboardingContainer proton transition-${transition}`,
style: props.backdrop ? {
background: props.backdrop
} : {}
- }, screens.map((screen, order) => {
+ }, props.screens.map((screen, order) => {
const isFirstCenteredScreen = screen.content.position !== "corner" && screen.order === centeredScreens[0].order;
const isLastCenteredScreen = screen.content.position !== "corner" && screen.order === centeredScreens[centeredScreens.length - 1].order;
return index === order ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(WelcomeScreen, {
key: screen.id + order,
id: screen.id,
- totalNumberOfScreens: screens.length,
+ totalNumberOfScreens: props.screens.length,
isFirstCenteredScreen: isFirstCenteredScreen,
isLastCenteredScreen: isLastCenteredScreen,
order: order,
@@ -436,9 +424,7 @@ const MultiStageAboutWelcome = props => {
activeTheme: activeTheme,
initialTheme: initialTheme,
setActiveTheme: setActiveTheme,
- autoAdvance: screen.auto_advance,
- negotiatedLanguage: negotiatedLanguage,
- langPackInstallPhase: langPackInstallPhase
+ autoAdvance: screen.auto_advance
}) : null;
})));
};
@@ -482,7 +468,7 @@ class WelcomeScreen extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureCom
} = action;
if (type === "SHOW_FIREFOX_ACCOUNTS") {
- let params = { ..._asrouter_templates_FirstRun_addUtmParams__WEBPACK_IMPORTED_MODULE_5__["BASE_PARAMS"],
+ let params = { ..._asrouter_templates_FirstRun_addUtmParams__WEBPACK_IMPORTED_MODULE_4__["BASE_PARAMS"],
utm_term: `aboutwelcome-${UTMTerm}-screen`
};
@@ -497,7 +483,7 @@ class WelcomeScreen extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureCom
};
} else if (type === "OPEN_URL") {
let url = new URL(data.args);
- Object(_asrouter_templates_FirstRun_addUtmParams__WEBPACK_IMPORTED_MODULE_5__["addUtmParams"])(url, `aboutwelcome-${UTMTerm}-screen`);
+ Object(_asrouter_templates_FirstRun_addUtmParams__WEBPACK_IMPORTED_MODULE_4__["addUtmParams"])(url, `aboutwelcome-${UTMTerm}-screen`);
if (action.addFlowParams && flowParams) {
url.searchParams.append("device_id", flowParams.deviceId);
@@ -523,7 +509,7 @@ class WelcomeScreen extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureCom
let {
value
} = event.currentTarget;
- let targetContent = props.content[value] || props.content.tiles || props.content.languageSwitcher;
+ let targetContent = props.content[value] || props.content.tiles;
if (!(targetContent && targetContent.action)) {
return;
@@ -565,11 +551,7 @@ class WelcomeScreen extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureCom
order: this.props.order,
activeTheme: this.props.activeTheme,
totalNumberOfScreens: this.props.totalNumberOfScreens - 1,
- appAndSystemLocaleInfo: this.props.appAndSystemLocaleInfo,
- negotiatedLanguage: this.props.negotiatedLanguage,
- langPackInstallPhase: this.props.langPackInstallPhase,
handleAction: this.handleAction,
- messageId: this.props.messageId,
isFirstCenteredScreen: this.props.isFirstCenteredScreen,
isLastCenteredScreen: this.props.isLastCenteredScreen,
autoAdvance: this.props.autoAdvance
@@ -790,7 +772,6 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Colorways__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(7);
/* harmony import */ var _Themes__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8);
/* harmony import */ var _MultiStageAboutWelcome__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(3);
-/* harmony import */ var _LanguageSwitcher__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(9);
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
@@ -799,7 +780,6 @@ __webpack_require__.r(__webpack_exports__);
-
const MultiStageProtonScreen = props => {
const {
autoAdvance,
@@ -832,10 +812,7 @@ const MultiStageProtonScreen = props => {
autoAdvance: props.autoAdvance,
isRtamo: props.isRtamo,
isTheme: props.isTheme,
- iconURL: props.iconURL,
- messageId: props.messageId,
- negotiatedLanguage: props.negotiatedLanguage,
- langPackInstallPhase: props.langPackInstallPhase
+ iconURL: props.iconURL
});
};
class ProtonScreen extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComponent {
@@ -892,19 +869,7 @@ class ProtonScreen extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComp
}) : null);
}
- renderLanguageSwitcher() {
- return this.props.content.languageSwitcher ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_LanguageSwitcher__WEBPACK_IMPORTED_MODULE_5__["LanguageSwitcher"], {
- content: this.props.content,
- handleAction: this.props.handleAction,
- negotiatedLanguage: this.props.negotiatedLanguage,
- langPackInstallPhase: this.props.langPackInstallPhase,
- messageId: this.props.messageId
- }) : null;
- }
-
render() {
- var _this$props$appAndSys, _content$primary_butt;
-
const {
autoAdvance,
content,
@@ -975,15 +940,13 @@ class ProtonScreen extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComp
text: content.subtitle
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("h2", {
"data-l10n-args": JSON.stringify({
- "addon-name": this.props.addonName,
- ...((_this$props$appAndSys = this.props.appAndSystemLocaleInfo) === null || _this$props$appAndSys === void 0 ? void 0 : _this$props$appAndSys.displayNames)
+ "addon-name": this.props.addonName
})
- })) : null), this.renderContentTiles(), this.renderLanguageSwitcher(), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__["Localized"], {
+ })) : null), this.renderContentTiles(), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__["Localized"], {
text: content.primary_button ? content.primary_button.label : null
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("button", {
className: "primary",
value: "primary_button",
- disabled: ((_content$primary_butt = content.primary_button) === null || _content$primary_butt === void 0 ? void 0 : _content$primary_butt.disabled) === true,
onClick: this.props.handleAction
})), content.secondary_button ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_MultiStageAboutWelcome__WEBPACK_IMPORTED_MODULE_4__["SecondaryCTA"], {
content: content,
@@ -1251,259 +1214,6 @@ const Themes = props => {
/* 9 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "useLanguageSwitcher", function() { return useLanguageSwitcher; });
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LanguageSwitcher", function() { return LanguageSwitcher; });
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
-/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
-/* harmony import */ var _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5);
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-
-
-/**
- * The language switcher implements a hook that should be placed at a higher level
- * than the actual language switcher component, as it needs to preemptively fetch
- * and install langpacks for the user if there is a language mismatch screen.
- */
-
-function useLanguageSwitcher(appAndSystemLocaleInfo, screens, screenIndex, setScreenIndex) {
- const languageMismatchScreenIndex = screens.findIndex(({
- id
- }) => id === "AW_LANGUAGE_MISMATCH");
- const screen = screens[languageMismatchScreenIndex]; // If there is a mismatch, then Firefox can negotiate a better langpack to offer
- // the user.
-
- const [negotiatedLanguage, setNegotiatedLanguage] = Object(react__WEBPACK_IMPORTED_MODULE_0__["useState"])(null);
- Object(react__WEBPACK_IMPORTED_MODULE_0__["useEffect"])(function getNegotiatedLanguage() {
- if (!appAndSystemLocaleInfo) {
- return;
- }
-
- if (appAndSystemLocaleInfo.matchType !== "language-mismatch") {
- // There is no language mismatch, so there is no need to negotiate a langpack.
- return;
- }
-
- (async () => {
- const langPack = await window.AWNegotiateLangPackForLanguageMismatch(appAndSystemLocaleInfo);
-
- if (langPack) {
- // Convert the BCP 47 identifiers into the proper display names.
- // e.g. "fr-CA" -> "Canadian French".
- const displayNames = new Intl.DisplayNames(appAndSystemLocaleInfo.appLocaleRaw, {
- type: "language"
- });
- setNegotiatedLanguage({
- displayName: displayNames.of(langPack.target_locale),
- langPack,
- requestSystemLocales: [langPack.target_locale, appAndSystemLocaleInfo.appLocaleRaw]
- });
- } else {
- setNegotiatedLanguage({
- displayName: null,
- langPack: null,
- requestSystemLocales: null
- });
- }
- })();
- }, [appAndSystemLocaleInfo]);
- /**
- * @type {
- * "before-installation"
- * | "installing"
- * | "installed"
- * | "installation-error"
- * | "none-available"
- * }
- */
-
- const [langPackInstallPhase, setLangPackInstallPhase] = Object(react__WEBPACK_IMPORTED_MODULE_0__["useState"])("before-installation");
- Object(react__WEBPACK_IMPORTED_MODULE_0__["useEffect"])(function ensureLangPackInstalled() {
- if (!negotiatedLanguage) {
- // There are no negotiated languages to download yet.
- return;
- }
-
- setLangPackInstallPhase("installing");
- window.AWEnsureLangPackInstalled(negotiatedLanguage.langPack).then(() => {
- setLangPackInstallPhase("installed");
- }, error => {
- console.error(error);
- setLangPackInstallPhase("installation-error");
- });
- }, [negotiatedLanguage]);
- const shouldHideLanguageSwitcher = screen && (appAndSystemLocaleInfo === null || appAndSystemLocaleInfo === void 0 ? void 0 : appAndSystemLocaleInfo.matchType) !== "language-mismatch";
- const [languageFilteredScreens, setLanguageFilteredScreens] = Object(react__WEBPACK_IMPORTED_MODULE_0__["useState"])(screens);
- Object(react__WEBPACK_IMPORTED_MODULE_0__["useEffect"])(function filterScreen() {
- if (shouldHideLanguageSwitcher || (negotiatedLanguage === null || negotiatedLanguage === void 0 ? void 0 : negotiatedLanguage.langPack) === null) {
- if (screenIndex > languageMismatchScreenIndex) {
- setScreenIndex(screenIndex - 1);
- }
-
- setLanguageFilteredScreens(screens.filter(s => s.id !== "AW_LANGUAGE_MISMATCH"));
- } else {
- setLanguageFilteredScreens(screens);
- }
- }, [screens, negotiatedLanguage]);
- return {
- negotiatedLanguage,
- langPackInstallPhase,
- languageFilteredScreens
- };
-}
-/**
- * The language switcher is a separate component as it needs to perform some asynchronous
- * network actions such as retrieving the list of langpacks available, and downloading
- * a new langpack. On a fast connection, this won't be noticeable, but on slow or unreliable
- * internet this may fail for a user.
- */
-
-function LanguageSwitcher(props) {
- const {
- content,
- handleAction,
- negotiatedLanguage,
- langPackInstallPhase,
- messageId
- } = props;
- const [isAwaitingLangpack, setIsAwaitingLangpack] = Object(react__WEBPACK_IMPORTED_MODULE_0__["useState"])(false); // Determine the status of the langpack installation.
-
- Object(react__WEBPACK_IMPORTED_MODULE_0__["useEffect"])(() => {
- if (isAwaitingLangpack && langPackInstallPhase !== "installing") {
- window.AWSetRequestedLocales(negotiatedLanguage.requestSystemLocales);
- requestAnimationFrame(() => {
- handleAction( // Simulate the click event.
- {
- currentTarget: {
- value: "download_complete"
- }
- });
- });
- }
- }, [isAwaitingLangpack, langPackInstallPhase]);
- console.log(`!!! render`, {
- negotiatedLanguage
- }); // The message args are the localized language names.
-
- const withMessageArgs = obj => {
- console.log(`!!! withMessageArgs`, {
- negotiatedLanguage
- });
- const displayName = negotiatedLanguage === null || negotiatedLanguage === void 0 ? void 0 : negotiatedLanguage.displayName;
-
- if (displayName) {
- return { ...obj,
- args: { ...obj.args,
- negotiatedLanguage: displayName
- }
- };
- }
-
- return obj;
- };
-
- let showWaitingScreen = false;
- let showPreloadingScreen = false;
- let showReadyScreen = false;
-
- if (isAwaitingLangpack && langPackInstallPhase !== "installed") {
- showWaitingScreen = true;
- } else if (langPackInstallPhase === "before-installation") {
- showPreloadingScreen = true;
- } else {
- showReadyScreen = true;
- } // Use {display: "none"} rather than if statements to prevent layout thrashing with
- // the localized text elements rendering as blank, then filling in the text.
-
-
- return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_0___default.a.Fragment, null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
- style: {
- display: showPreloadingScreen ? "block" : "none"
- }
- }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("button", {
- className: "primary",
- value: "primary_button",
- disabled: true,
- type: "button"
- }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("img", {
- className: "language-loader",
- src: "chrome://browser/skin/tabbrowser/tab-connecting.png",
- alt: ""
- }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__["Localized"], {
- text: content.languageSwitcher.waiting
- })), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
- className: "secondary-cta"
- }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__["Localized"], {
- text: content.languageSwitcher.skip
- }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("button", {
- value: "decline_waiting",
- type: "button",
- className: "secondary text-link",
- onClick: handleAction
- })))), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
- style: {
- display: showWaitingScreen ? "block" : "none"
- }
- }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("button", {
- className: "primary",
- value: "primary_button",
- disabled: true,
- type: "button"
- }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("img", {
- className: "language-loader",
- src: "chrome://browser/skin/tabbrowser/tab-connecting.png",
- alt: ""
- }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__["Localized"], {
- text: withMessageArgs(content.languageSwitcher.downloading)
- })), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
- className: "secondary-cta"
- }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__["Localized"], {
- text: content.languageSwitcher.cancel
- }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("button", {
- type: "button",
- className: "secondary text-link",
- onClick: () => {
- setIsAwaitingLangpack(false);
- handleAction({
- currentTarget: {
- value: "cancel_waiting"
- }
- });
- }
- })))), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
- style: {
- display: showReadyScreen ? "block" : "none"
- }
- }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__["Localized"], {
- text: withMessageArgs(content.languageSwitcher.switch)
- }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("button", {
- className: "primary",
- value: "primary_button",
- onClick: () => {
- _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_2__["AboutWelcomeUtils"].sendActionTelemetry(messageId, "download_langpack");
- setIsAwaitingLangpack(true);
- }
- }))), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
- className: "secondary-cta"
- }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__["Localized"], {
- text: content.languageSwitcher.not_now
- }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("button", {
- type: "button",
- className: "secondary text-link",
- value: "decline",
- onClick: handleAction
- })))));
-}
-
-/***/ }),
-/* 10 */
-/***/ (function(module, __webpack_exports__, __webpack_require__) {
-
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BASE_PARAMS", function() { return BASE_PARAMS; });
@@ -1542,7 +1252,7 @@ function addUtmParams(url, utmTerm) {
}
/***/ }),
-/* 11 */
+/* 10 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -1552,7 +1262,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
/* harmony import */ var _MultiStageProtonScreen__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6);
-/* harmony import */ var _asrouter_templates_FirstRun_addUtmParams__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(10);
+/* harmony import */ var _asrouter_templates_FirstRun_addUtmParams__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(9);
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
diff --git a/browser/components/newtab/aboutwelcome/content/aboutwelcome.css b/browser/components/newtab/aboutwelcome/content/aboutwelcome.css
index 643cce7c7e96..32081d30a154 100644
--- a/browser/components/newtab/aboutwelcome/content/aboutwelcome.css
+++ b/browser/components/newtab/aboutwelcome/content/aboutwelcome.css
@@ -211,20 +211,6 @@ body[lwt-newtab-brighttext] {
.onboardingContainer .welcomeZap .zap.long::after {
background-image: url("chrome://activity-stream/content/data/content/assets/long-zap.svg");
}
-.onboardingContainer .language-loader {
- filter: invert(1);
- margin-inline-end: 10px;
- position: relative;
- top: 3px;
- width: 16px;
- height: 16px;
- margin-top: -6px;
-}
-@media (prefers-color-scheme: dark) {
- .onboardingContainer .language-loader {
- filter: invert(0);
- }
-}
.onboardingContainer .tiles-theme-container {
display: flex;
flex-direction: column;
diff --git a/browser/components/newtab/aboutwelcome/lib/AboutWelcomeDefaults.jsm b/browser/components/newtab/aboutwelcome/lib/AboutWelcomeDefaults.jsm
index 3c0f0b78160c..bd0ac6cbb270 100644
--- a/browser/components/newtab/aboutwelcome/lib/AboutWelcomeDefaults.jsm
+++ b/browser/components/newtab/aboutwelcome/lib/AboutWelcomeDefaults.jsm
@@ -101,37 +101,9 @@ const DEFAULT_WELCOME_CONTENT = {
},
},
},
- {
- id: "AW_LANGUAGE_MISMATCH",
- order: 2,
- content: {
- title: { string_id: "onboarding-live-language-header" },
- subtitle: { string_id: "onboarding-live-language-subtitle" },
- has_noodles: true,
- languageSwitcher: {
- switch: {
- string_id: "onboarding-live-language-switch-button-label",
- },
- downloading: {
- string_id: "onboarding-live-language-button-label-downloading",
- },
- cancel: {
- string_id: "onboarding-live-language-secondary-cancel-download",
- },
- not_now: {
- string_id: "onboarding-live-language-not-now-button-label",
- },
- waiting: { string_id: "onboarding-live-language-waiting-button" },
- skip: { string_id: "onboarding-live-language-skip-button-label" },
- action: {
- navigate: true,
- },
- },
- },
- },
{
id: "AW_IMPORT_SETTINGS",
- order: 3,
+ order: 2,
content: {
title: {
string_id: "mr1-onboarding-import-header",
@@ -163,7 +135,7 @@ const DEFAULT_WELCOME_CONTENT = {
},
{
id: "AW_CHOOSE_THEME",
- order: 4,
+ order: 3,
content: {
title: {
string_id: "mr1-onboarding-theme-header",
@@ -439,25 +411,6 @@ async function prepareContentForReact(content) {
)?.content.help_text.text;
}
- if (content.languageMismatchEnabled) {
- const screen = content?.screens?.find(s => s.id === "AW_LANGUAGE_MISMATCH");
- if (screen) {
- // Add the display names for the OS and Firefox languages, like "American English".
- const { appAndSystemLocaleInfo } = content;
- function addMessageArgs(obj) {
- for (const value of Object.values(obj)) {
- if (value?.string_id) {
- value.args = appAndSystemLocaleInfo.displayNames;
- }
- }
- }
- addMessageArgs(screen.content.languageSwitcher);
- addMessageArgs(screen.content);
- }
- } else {
- removeScreens(screen => screen.id === "AW_LANGUAGE_MISMATCH");
- }
-
return content;
}
diff --git a/browser/components/newtab/content-src/aboutwelcome/aboutwelcome.jsx b/browser/components/newtab/content-src/aboutwelcome/aboutwelcome.jsx
index c6875a5499a4..4084548a1c94 100644
--- a/browser/components/newtab/content-src/aboutwelcome/aboutwelcome.jsx
+++ b/browser/components/newtab/content-src/aboutwelcome/aboutwelcome.jsx
@@ -79,7 +79,6 @@ class AboutWelcome extends React.PureComponent {
utm_term={props.UTMTerm}
transitions={props.transitions}
backdrop={props.backdrop}
- appAndSystemLocaleInfo={props.appAndSystemLocaleInfo}
/>
);
}
diff --git a/browser/components/newtab/content-src/aboutwelcome/aboutwelcome.scss b/browser/components/newtab/content-src/aboutwelcome/aboutwelcome.scss
index b3b235c192e4..4425b19df152 100644
--- a/browser/components/newtab/content-src/aboutwelcome/aboutwelcome.scss
+++ b/browser/components/newtab/content-src/aboutwelcome/aboutwelcome.scss
@@ -230,22 +230,6 @@ body {
}
}
- .language-loader {
- filter: invert(1);
- margin-inline-end: 10px;
- position: relative;
- top: 3px;
- width: 16px;
- height: 16px;
- margin-top: -6px;
- }
-
- @media (prefers-color-scheme: dark) {
- .language-loader {
- filter: invert(0);
- }
- }
-
.tiles-theme-container {
display: flex;
flex-direction: column;
diff --git a/browser/components/newtab/content-src/aboutwelcome/components/LanguageSwitcher.jsx b/browser/components/newtab/content-src/aboutwelcome/components/LanguageSwitcher.jsx
deleted file mode 100644
index 1dc7f868d906..000000000000
--- a/browser/components/newtab/content-src/aboutwelcome/components/LanguageSwitcher.jsx
+++ /dev/null
@@ -1,277 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-import React, { useState, useEffect } from "react";
-import { Localized } from "./MSLocalized";
-import { AboutWelcomeUtils } from "../../lib/aboutwelcome-utils";
-
-/**
- * The language switcher implements a hook that should be placed at a higher level
- * than the actual language switcher component, as it needs to preemptively fetch
- * and install langpacks for the user if there is a language mismatch screen.
- */
-export function useLanguageSwitcher(
- appAndSystemLocaleInfo,
- screens,
- screenIndex,
- setScreenIndex
-) {
- const languageMismatchScreenIndex = screens.findIndex(
- ({ id }) => id === "AW_LANGUAGE_MISMATCH"
- );
- const screen = screens[languageMismatchScreenIndex];
-
- // If there is a mismatch, then Firefox can negotiate a better langpack to offer
- // the user.
- const [negotiatedLanguage, setNegotiatedLanguage] = useState(null);
- useEffect(
- function getNegotiatedLanguage() {
- if (!appAndSystemLocaleInfo) {
- return;
- }
- if (appAndSystemLocaleInfo.matchType !== "language-mismatch") {
- // There is no language mismatch, so there is no need to negotiate a langpack.
- return;
- }
-
- (async () => {
- const langPack = await window.AWNegotiateLangPackForLanguageMismatch(
- appAndSystemLocaleInfo
- );
- if (langPack) {
- // Convert the BCP 47 identifiers into the proper display names.
- // e.g. "fr-CA" -> "Canadian French".
- const displayNames = new Intl.DisplayNames(
- appAndSystemLocaleInfo.appLocaleRaw,
- { type: "language" }
- );
-
- setNegotiatedLanguage({
- displayName: displayNames.of(langPack.target_locale),
- langPack,
- requestSystemLocales: [
- langPack.target_locale,
- appAndSystemLocaleInfo.appLocaleRaw,
- ],
- });
- } else {
- setNegotiatedLanguage({
- displayName: null,
- langPack: null,
- requestSystemLocales: null,
- });
- }
- })();
- },
- [appAndSystemLocaleInfo]
- );
-
- /**
- * @type {
- * "before-installation"
- * | "installing"
- * | "installed"
- * | "installation-error"
- * | "none-available"
- * }
- */
- const [langPackInstallPhase, setLangPackInstallPhase] = useState(
- "before-installation"
- );
- useEffect(
- function ensureLangPackInstalled() {
- if (!negotiatedLanguage) {
- // There are no negotiated languages to download yet.
- return;
- }
- setLangPackInstallPhase("installing");
- window.AWEnsureLangPackInstalled(negotiatedLanguage.langPack).then(
- () => {
- setLangPackInstallPhase("installed");
- },
- error => {
- console.error(error);
- setLangPackInstallPhase("installation-error");
- }
- );
- },
- [negotiatedLanguage]
- );
-
- const shouldHideLanguageSwitcher =
- screen && appAndSystemLocaleInfo?.matchType !== "language-mismatch";
-
- const [languageFilteredScreens, setLanguageFilteredScreens] = useState(
- screens
- );
- useEffect(
- function filterScreen() {
- if (shouldHideLanguageSwitcher || negotiatedLanguage?.langPack === null) {
- if (screenIndex > languageMismatchScreenIndex) {
- setScreenIndex(screenIndex - 1);
- }
- setLanguageFilteredScreens(
- screens.filter(s => s.id !== "AW_LANGUAGE_MISMATCH")
- );
- } else {
- setLanguageFilteredScreens(screens);
- }
- },
- [screens, negotiatedLanguage]
- );
-
- return {
- negotiatedLanguage,
- langPackInstallPhase,
- languageFilteredScreens,
- };
-}
-
-/**
- * The language switcher is a separate component as it needs to perform some asynchronous
- * network actions such as retrieving the list of langpacks available, and downloading
- * a new langpack. On a fast connection, this won't be noticeable, but on slow or unreliable
- * internet this may fail for a user.
- */
-export function LanguageSwitcher(props) {
- const {
- content,
- handleAction,
- negotiatedLanguage,
- langPackInstallPhase,
- messageId,
- } = props;
-
- const [isAwaitingLangpack, setIsAwaitingLangpack] = useState(false);
-
- // Determine the status of the langpack installation.
- useEffect(() => {
- if (isAwaitingLangpack && langPackInstallPhase !== "installing") {
- window.AWSetRequestedLocales(negotiatedLanguage.requestSystemLocales);
- requestAnimationFrame(() => {
- handleAction(
- // Simulate the click event.
- { currentTarget: { value: "download_complete" } }
- );
- });
- }
- }, [isAwaitingLangpack, langPackInstallPhase]);
-
- // The message args are the localized language names.
- const withMessageArgs = obj => {
- const displayName = negotiatedLanguage?.displayName;
- if (displayName) {
- return {
- ...obj,
- args: {
- ...obj.args,
- negotiatedLanguage: displayName,
- },
- };
- }
- return obj;
- };
-
- let showWaitingScreen = false;
- let showPreloadingScreen = false;
- let showReadyScreen = false;
-
- if (isAwaitingLangpack && langPackInstallPhase !== "installed") {
- showWaitingScreen = true;
- } else if (langPackInstallPhase === "before-installation") {
- showPreloadingScreen = true;
- } else {
- showReadyScreen = true;
- }
-
- // Use {display: "none"} rather than if statements to prevent layout thrashing with
- // the localized text elements rendering as blank, then filling in the text.
- return (
- <>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >
- );
-}
diff --git a/browser/components/newtab/content-src/aboutwelcome/components/MultiStageAboutWelcome.jsx b/browser/components/newtab/content-src/aboutwelcome/components/MultiStageAboutWelcome.jsx
index 825fc50726e8..8afba1a15cef 100644
--- a/browser/components/newtab/content-src/aboutwelcome/components/MultiStageAboutWelcome.jsx
+++ b/browser/components/newtab/content-src/aboutwelcome/components/MultiStageAboutWelcome.jsx
@@ -6,7 +6,6 @@ import React, { useState, useEffect, useRef } from "react";
import { Localized } from "./MSLocalized";
import { AboutWelcomeUtils } from "../../lib/aboutwelcome-utils";
import { MultiStageProtonScreen } from "./MultiStageProtonScreen";
-import { useLanguageSwitcher } from "./LanguageSwitcher";
import {
BASE_PARAMS,
addUtmParams,
@@ -16,12 +15,10 @@ import {
const TRANSITION_OUT_TIME = 1000;
export const MultiStageAboutWelcome = props => {
- let { screens } = props;
-
const [index, setScreenIndex] = useState(0);
useEffect(() => {
// Send impression ping when respective screen first renders
- screens.forEach((screen, order) => {
+ props.screens.forEach((screen, order) => {
if (index === order) {
AboutWelcomeUtils.sendImpressionTelemetry(
`${props.message_id}_${order}_${screen.id}`
@@ -40,7 +37,7 @@ export const MultiStageAboutWelcome = props => {
// or last screen index if a user navigates by pressing back
// button from about:home
const handler = ({ state }) =>
- setScreenIndex(Math.min(state, screens.length - 1));
+ setScreenIndex(Math.min(state, props.screens.length - 1));
// Handle page load, e.g., going back to about:welcome from about:home
handler(window.history);
@@ -84,7 +81,7 @@ export const MultiStageAboutWelcome = props => {
// Actually move forwards after all transitions finish.
setTimeout(
() => {
- if (index < screens.length - 1) {
+ if (index < props.screens.length - 1) {
setTransition(props.transitions ? "in" : "");
setScreenIndex(prevState => prevState + 1);
} else {
@@ -143,26 +140,13 @@ export const MultiStageAboutWelcome = props => {
s => s.content.position !== "corner"
);
- const {
- negotiatedLanguage,
- langPackInstallPhase,
- languageFilteredScreens,
- } = useLanguageSwitcher(
- props.appAndSystemLocaleInfo,
- screens,
- index,
- setScreenIndex
- );
-
- screens = languageFilteredScreens;
-
return (
- {screens.map((screen, order) => {
+ {props.screens.map((screen, order) => {
const isFirstCenteredScreen =
screen.content.position !== "corner" &&
screen.order === centeredScreens[0].order;
@@ -173,7 +157,7 @@ export const MultiStageAboutWelcome = props => {
{
initialTheme={initialTheme}
setActiveTheme={setActiveTheme}
autoAdvance={screen.auto_advance}
- negotiatedLanguage={negotiatedLanguage}
- langPackInstallPhase={langPackInstallPhase}
/>
) : null;
})}
@@ -266,11 +248,7 @@ export class WelcomeScreen extends React.PureComponent {
async handleAction(event) {
let { props } = this;
let { value } = event.currentTarget;
- let targetContent =
- props.content[value] ||
- props.content.tiles ||
- props.content.languageSwitcher;
-
+ let targetContent = props.content[value] || props.content.tiles;
if (!(targetContent && targetContent.action)) {
return;
}
@@ -317,11 +295,7 @@ export class WelcomeScreen extends React.PureComponent {
order={this.props.order}
activeTheme={this.props.activeTheme}
totalNumberOfScreens={this.props.totalNumberOfScreens - 1}
- appAndSystemLocaleInfo={this.props.appAndSystemLocaleInfo}
- negotiatedLanguage={this.props.negotiatedLanguage}
- langPackInstallPhase={this.props.langPackInstallPhase}
handleAction={this.handleAction}
- messageId={this.props.messageId}
isFirstCenteredScreen={this.props.isFirstCenteredScreen}
isLastCenteredScreen={this.props.isLastCenteredScreen}
autoAdvance={this.props.autoAdvance}
diff --git a/browser/components/newtab/content-src/aboutwelcome/components/MultiStageProtonScreen.jsx b/browser/components/newtab/content-src/aboutwelcome/components/MultiStageProtonScreen.jsx
index 972bb958b62c..0862b1dc6e28 100644
--- a/browser/components/newtab/content-src/aboutwelcome/components/MultiStageProtonScreen.jsx
+++ b/browser/components/newtab/content-src/aboutwelcome/components/MultiStageProtonScreen.jsx
@@ -7,7 +7,6 @@ import { Localized } from "./MSLocalized";
import { Colorways } from "./Colorways";
import { Themes } from "./Themes";
import { SecondaryCTA, StepsIndicator } from "./MultiStageAboutWelcome";
-import { LanguageSwitcher } from "./LanguageSwitcher";
export const MultiStageProtonScreen = props => {
const { autoAdvance, handleAction, order } = props;
@@ -39,9 +38,6 @@ export const MultiStageProtonScreen = props => {
isRtamo={props.isRtamo}
isTheme={props.isTheme}
iconURL={props.iconURL}
- messageId={props.messageId}
- negotiatedLanguage={props.negotiatedLanguage}
- langPackInstallPhase={props.langPackInstallPhase}
/>
);
};
@@ -118,18 +114,6 @@ export class ProtonScreen extends React.PureComponent {
);
}
- renderLanguageSwitcher() {
- return this.props.content.languageSwitcher ? (
-
- ) : null;
- }
-
render() {
const {
autoAdvance,
@@ -217,14 +201,12 @@ export class ProtonScreen extends React.PureComponent {
) : null}
{this.renderContentTiles()}
- {this.renderLanguageSwitcher()}
diff --git a/browser/components/newtab/karma.mc.config.js b/browser/components/newtab/karma.mc.config.js
index 3d09c8ac7ac1..5a811c4cc7cb 100644
--- a/browser/components/newtab/karma.mc.config.js
+++ b/browser/components/newtab/karma.mc.config.js
@@ -188,13 +188,6 @@ module.exports = function(config) {
functions: 96,
branches: 70,
},
- "content-src/aboutwelcome/components/LanguageSwitcher.jsx": {
- // This file is covered by the mochitest: browser_aboutwelcome_multistage_languageSwitcher.js
- statements: 0,
- lines: 0,
- functions: 0,
- branches: 0,
- },
"content-src/aboutwelcome/**/*.jsx": {
statements: 62,
lines: 60,
diff --git a/browser/components/newtab/test/browser/browser.ini b/browser/components/newtab/test/browser/browser.ini
index 9e587bd4a601..4a2a79e92102 100644
--- a/browser/components/newtab/test/browser/browser.ini
+++ b/browser/components/newtab/test/browser/browser.ini
@@ -16,14 +16,12 @@ prefs =
browser.newtabpage.activity-stream.feeds.section.topstories=true
browser.newtabpage.activity-stream.feeds.section.topstories.options={"provider_name":""}
messaging-system.log=all
- intl.multilingual.aboutWelcome.languageMismatchEnabled=false
[browser_aboutwelcome_configurable_ui.js]
[browser_aboutwelcome_focus.js]
[browser_aboutwelcome_multistage_default.js]
[browser_aboutwelcome_multistage_primary.js]
[browser_aboutwelcome_multistage_experimentAPI.js]
-[browser_aboutwelcome_multistage_languageSwitcher.js]
[browser_aboutwelcome_rtamo.js]
skip-if = (os == "linux") # Test setup only implemented for OSX and Windows
[browser_aboutwelcome_attribution.js]
diff --git a/browser/components/newtab/test/browser/browser_aboutwelcome_multistage_languageSwitcher.js b/browser/components/newtab/test/browser/browser_aboutwelcome_multistage_languageSwitcher.js
deleted file mode 100644
index 87f958d5a932..000000000000
--- a/browser/components/newtab/test/browser/browser_aboutwelcome_multistage_languageSwitcher.js
+++ /dev/null
@@ -1,572 +0,0 @@
-"use strict";
-
-const { getAddonAndLocalAPIsMocker } = ChromeUtils.import(
- "resource://testing-common/LangPackMatcherTestUtils.jsm"
-);
-
-const sandbox = sinon.createSandbox();
-const mockAddonAndLocaleAPIs = getAddonAndLocalAPIsMocker(this, sandbox);
-add_task(function initSandbox() {
- registerCleanupFunction(() => {
- sandbox.restore();
- });
-});
-
-/**
- * Spy specifically on the button click telemetry.
- *
- * The returned function flushes the spy of all of the matching button click events, and
- * returns the events.
- * @returns {() => TelemetryEvents[]}
- */
-async function spyOnTelemetryButtonClicks(browser) {
- let aboutWelcomeActor = await getAboutWelcomeParent(browser);
- sandbox.spy(aboutWelcomeActor, "onContentMessage");
- return () => {
- const result = aboutWelcomeActor.onContentMessage
- .getCalls()
- .filter(
- call =>
- call.args[0] === "AWPage:TELEMETRY_EVENT" &&
- call.args[1]?.event === "CLICK_BUTTON"
- )
- // The second argument is the telemetry event.
- .map(call => call.args[1]);
-
- aboutWelcomeActor.onContentMessage.resetHistory();
- return result;
- };
-}
-
-async function openAboutWelcome() {
- await pushPrefs([
- "intl.multilingual.aboutWelcome.languageMismatchEnabled",
- true,
- ]);
- await setAboutWelcomePref(true);
-
- // Stub out the doesAppNeedPin to false so the about:welcome pages do not attempt
- // to pin the app.
- const { ShellService } = ChromeUtils.import(
- "resource:///modules/ShellService.jsm"
- );
- sandbox.stub(ShellService, "doesAppNeedPin").returns(false);
-
- info("Opening about:welcome");
- let tab = await BrowserTestUtils.openNewForegroundTab(
- gBrowser,
- "about:welcome",
- true
- );
-
- registerCleanupFunction(async () => {
- BrowserTestUtils.removeTab(tab);
- });
-
- return {
- browser: tab.linkedBrowser,
- flushClickTelemetry: await spyOnTelemetryButtonClicks(tab.linkedBrowser),
- };
-}
-
-async function clickVisibleButton(browser, selector) {
- // eslint-disable-next-line no-shadow
- await ContentTask.spawn(browser, { selector }, async ({ selector }) => {
- function getVisibleElement() {
- for (const el of content.document.querySelectorAll(selector)) {
- if (el.offsetParent !== null) {
- return el;
- }
- }
- return null;
- }
-
- await ContentTaskUtils.waitForCondition(getVisibleElement, selector);
- getVisibleElement().click();
- });
-}
-
-/**
- * Test that selectors are present and visible.
- */
-async function testScreenContent(
- browser,
- name,
- expectedSelectors = [],
- unexpectedSelectors = []
-) {
- await ContentTask.spawn(
- browser,
- { expectedSelectors, name, unexpectedSelectors },
- async ({
- expectedSelectors: expected,
- name: experimentName,
- unexpectedSelectors: unexpected,
- }) => {
- function selectorIsVisible(selector) {
- const el = content.document.querySelector(selector);
- // The offsetParent will be null if element is hidden through "display: none;"
- return el && el.offsetParent !== null;
- }
-
- for (let selector of expected) {
- await ContentTaskUtils.waitForCondition(
- () => selectorIsVisible(selector),
- `Should render ${selector} in ${experimentName}`
- );
- }
- for (let selector of unexpected) {
- ok(
- !selectorIsVisible(selector),
- `Should not render ${selector} in ${experimentName}`
- );
- }
- }
- );
-}
-
-/**
- * Report telemetry mismatches nicely.
- */
-function eventsMatch(
- actualEvents,
- expectedEvents,
- message = "Telemetry events match"
-) {
- if (actualEvents.length !== expectedEvents.length) {
- console.error("Events do not match");
- console.error("Actual: ", JSON.stringify(actualEvents, null, 2));
- console.error("Expected: ", JSON.stringify(expectedEvents, null, 2));
- }
- for (let i = 0; i < actualEvents.length; i++) {
- const actualEvent = JSON.stringify(actualEvents[i], null, 2);
- const expectedEvent = JSON.stringify(expectedEvents[i], null, 2);
- if (actualEvent !== expectedEvent) {
- console.error("Events do not match");
- dump(`Actual: ${actualEvent}`);
- dump("\n");
- dump(`Expected: ${expectedEvent}`);
- dump("\n");
- }
- ok(actualEvent === expectedEvent, message);
- }
-}
-
-const liveLanguageSwitchSelectors = [
- ".screen-1",
- `[data-l10n-id*="onboarding-live-language"]`,
- `[data-l10n-id="onboarding-live-language-header"]`,
-];
-
-/**
- * Accept the about:welcome offer to change the Firefox language when
- * there is a mismatch between the operating system language and the Firefox
- * language.
- */
-add_task(async function test_aboutwelcome_languageSwitcher_accept() {
- sandbox.restore();
- const { resolveLangPacks, resolveInstaller } = mockAddonAndLocaleAPIs({
- systemLocale: "es-ES",
- appLocale: "en-US",
- });
-
- const { browser, flushClickTelemetry } = await openAboutWelcome();
-
- info("Clicking the primary button to start the onboarding process.");
- await clickVisibleButton(browser, "button.primary");
-
- await testScreenContent(
- browser,
- "Live language switching (waiting for languages)",
- // Expected selectors:
- [
- ...liveLanguageSwitchSelectors,
- `[data-l10n-id="onboarding-live-language-header"]`,
- `button[disabled] [data-l10n-id="onboarding-live-language-waiting-button"]`,
- `[data-l10n-id="onboarding-live-language-skip-button-label"]`,
- ],
- // Unexpected selectors:
- []
- );
-
- // Ignore the telemetry of the initial welcome screen.
- flushClickTelemetry();
-
- resolveLangPacks(["es-MX", "es-ES", "fr-FR"]);
-
- await testScreenContent(
- browser,
- "Live language switching, asking for a language",
- // Expected selectors:
- [
- ...liveLanguageSwitchSelectors,
- `[data-l10n-id="onboarding-live-language-switch-button-label"]`,
- `[data-l10n-id="onboarding-live-language-not-now-button-label"]`,
- ],
- // Unexpected selectors:
- [
- `button[disabled] [data-l10n-id="onboarding-live-language-waiting-button"]`,
- `[data-l10n-id="onboarding-live-language-skip-button-label"]`,
- ]
- );
-
- info("Clicking the primary button to view language switching page.");
- await clickVisibleButton(browser, "button.primary");
-
- await testScreenContent(
- browser,
- "Live language switching, waiting for langpack to download",
- // Expected selectors:
- [
- ...liveLanguageSwitchSelectors,
- `[data-l10n-id="onboarding-live-language-button-label-downloading"]`,
- `[data-l10n-id="onboarding-live-language-secondary-cancel-download"]`,
- ],
- // Unexpected selectors:
- [
- `button[disabled] [data-l10n-id="onboarding-live-language-waiting-button"]`,
- ]
- );
-
- eventsMatch(flushClickTelemetry(), [
- {
- event: "CLICK_BUTTON",
- event_context: {
- source: "download_langpack",
- page: "about:welcome",
- },
- message_id: "DEFAULT_ABOUTWELCOME_PROTON_1_AW_LANGUAGE_MISMATCH",
- },
- ]);
-
- await resolveInstaller();
-
- await testScreenContent(
- browser,
- "Language selection declined",
- // Expected selectors:
- [`.screen-2`],
- // Unexpected selectors:
- liveLanguageSwitchSelectors
- );
-
- eventsMatch(flushClickTelemetry(), [
- {
- event: "CLICK_BUTTON",
- event_context: {
- source: "download_complete",
- page: "about:welcome",
- },
- message_id: "DEFAULT_ABOUTWELCOME_PROTON_1_AW_LANGUAGE_MISMATCH",
- },
- ]);
-});
-
-/**
- * Accept the about:welcome offer to change the Firefox language when
- * there is a mismatch between the operating system language and the Firefox
- * language.
- */
-add_task(async function test_aboutwelcome_languageSwitcher_accept() {
- sandbox.restore();
- const { resolveLangPacks, resolveInstaller } = mockAddonAndLocaleAPIs({
- systemLocale: "es-ES",
- appLocale: "en-US",
- });
-
- const { browser, flushClickTelemetry } = await openAboutWelcome();
-
- info("Clicking the primary button to start the onboarding process.");
- await clickVisibleButton(browser, "button.primary");
-
- await testScreenContent(
- browser,
- "Live language switching (waiting for languages)",
- // Expected selectors:
- [
- ...liveLanguageSwitchSelectors,
- `[data-l10n-id="onboarding-live-language-header"]`,
- `button[disabled] [data-l10n-id="onboarding-live-language-waiting-button"]`,
- `[data-l10n-id="onboarding-live-language-skip-button-label"]`,
- ],
- // Unexpected selectors:
- []
- );
-
- // Ignore the telemetry of the initial welcome screen.
- flushClickTelemetry();
-
- resolveLangPacks(["es-MX", "es-ES", "fr-FR"]);
-
- await testScreenContent(
- browser,
- "Live language switching, asking for a language",
- // Expected selectors:
- [
- ...liveLanguageSwitchSelectors,
- `[data-l10n-id="onboarding-live-language-switch-button-label"]`,
- `[data-l10n-id="onboarding-live-language-not-now-button-label"]`,
- ],
- // Unexpected selectors:
- [
- `button[disabled] [data-l10n-id="onboarding-live-language-waiting-button"]`,
- `[data-l10n-id="onboarding-live-language-skip-button-label"]`,
- ]
- );
-
- info("Clicking the primary button to view language switching page.");
- await clickVisibleButton(browser, "button.primary");
-
- await testScreenContent(
- browser,
- "Live language switching, waiting for langpack to download",
- // Expected selectors:
- [
- ...liveLanguageSwitchSelectors,
- `[data-l10n-id="onboarding-live-language-button-label-downloading"]`,
- `[data-l10n-id="onboarding-live-language-secondary-cancel-download"]`,
- ],
- // Unexpected selectors:
- [
- `button[disabled] [data-l10n-id="onboarding-live-language-waiting-button"]`,
- ]
- );
-
- eventsMatch(flushClickTelemetry(), [
- {
- event: "CLICK_BUTTON",
- event_context: {
- source: "download_langpack",
- page: "about:welcome",
- },
- message_id: "DEFAULT_ABOUTWELCOME_PROTON_1_AW_LANGUAGE_MISMATCH",
- },
- ]);
-
- await resolveInstaller();
-
- await testScreenContent(
- browser,
- "Language selection declined",
- // Expected selectors:
- [`.screen-2`],
- // Unexpected selectors:
- liveLanguageSwitchSelectors
- );
-});
-
-/**
- * Test declining the about:welcome offer to change the Firefox language when
- * there is a mismatch between the operating system language and the Firefox
- * language.
- */
-add_task(async function test_aboutwelcome_languageSwitcher_decline() {
- sandbox.restore();
- const { resolveLangPacks, resolveInstaller } = mockAddonAndLocaleAPIs({
- systemLocale: "es-ES",
- appLocale: "en-US",
- });
-
- const { browser, flushClickTelemetry } = await openAboutWelcome();
-
- info("Clicking the primary button to view language switching page.");
- await clickVisibleButton(browser, "button.primary");
-
- await testScreenContent(
- browser,
- "Live language switching (waiting for languages)",
- // Expected selectors:
- [
- ...liveLanguageSwitchSelectors,
- `[data-l10n-id="onboarding-live-language-header"]`,
- `button[disabled] [data-l10n-id="onboarding-live-language-waiting-button"]`,
- `[data-l10n-id="onboarding-live-language-skip-button-label"]`,
- ],
- // Unexpected selectors:
- []
- );
-
- // Ignore the telemetry of the initial welcome screen.
- flushClickTelemetry();
-
- resolveLangPacks(["es-MX", "es-ES", "fr-FR"]);
- resolveInstaller();
-
- await testScreenContent(
- browser,
- "Live language switching, asking for a language",
- // Expected selectors:
- [
- ...liveLanguageSwitchSelectors,
- `[data-l10n-id="onboarding-live-language-switch-button-label"]`,
- `[data-l10n-id="onboarding-live-language-not-now-button-label"]`,
- ],
- // Unexpected selectors:
- [
- `button[disabled] [data-l10n-id="onboarding-live-language-waiting-button"]`,
- `[data-l10n-id="onboarding-live-language-skip-button-label"]`,
- ]
- );
-
- info("Clicking the secondary button to skip installing the langpack.");
- await clickVisibleButton(browser, "button.secondary");
-
- await testScreenContent(
- browser,
- "Language selection declined",
- // Expected selectors:
- [`.screen-2`],
- // Unexpected selectors:
- liveLanguageSwitchSelectors
- );
-
- eventsMatch(flushClickTelemetry(), [
- {
- event: "CLICK_BUTTON",
- event_context: {
- source: "decline",
- page: "about:welcome",
- },
- message_id: "DEFAULT_ABOUTWELCOME_PROTON_1_AW_LANGUAGE_MISMATCH",
- },
- ]);
-});
-
-/**
- * Ensure the langpack can be installed before the user gets to the language screen.
- */
-add_task(async function test_aboutwelcome_languageSwitcher_asyncCalls() {
- sandbox.restore();
- const {
- resolveLangPacks,
- resolveInstaller,
- mockable,
- } = mockAddonAndLocaleAPIs({
- systemLocale: "es-ES",
- appLocale: "en-US",
- });
-
- await openAboutWelcome();
-
- info("Waiting for getAvailableLangpacks to be called.");
- await TestUtils.waitForCondition(
- () => mockable.getAvailableLangpacks.called,
- "getAvailableLangpacks called once"
- );
- ok(mockable.installLangPack.notCalled);
-
- resolveLangPacks(["es-MX", "es-ES", "fr-FR"]);
-
- await TestUtils.waitForCondition(
- () => mockable.installLangPack.called,
- "installLangPack was called once"
- );
- ok(mockable.getAvailableLangpacks.called);
-
- resolveInstaller();
-});
-
-/**
- * Test when AMO does not have a matching language.
- */
-add_task(async function test_aboutwelcome_languageSwitcher_noMatch() {
- sandbox.restore();
- const { resolveLangPacks } = mockAddonAndLocaleAPIs({
- systemLocale: "tlh", // Klingon
- appLocale: "en-US",
- });
-
- const { browser } = await openAboutWelcome();
-
- info("Clicking the primary button to start installing the langpack.");
- await clickVisibleButton(browser, "button.primary");
-
- // Klingon is not supported.
- resolveLangPacks(["es-MX", "es-ES", "fr-FR"]);
-
- await testScreenContent(
- browser,
- "Language selection skipped",
- // Expected selectors:
- [`.screen-1`],
- // Unexpected selectors:
- [
- `[data-l10n-id*="onboarding-live-language"]`,
- `[data-l10n-id="onboarding-live-language-header"]`,
- ]
- );
-});
-
-/**
- * Test hitting the cancel button when waiting on a langpack.
- */
-add_task(async function test_aboutwelcome_languageSwitcher_cancelWaiting() {
- sandbox.restore();
- const { resolveLangPacks, resolveInstaller } = mockAddonAndLocaleAPIs({
- systemLocale: "es-ES",
- appLocale: "en-US",
- });
-
- const { browser, flushClickTelemetry } = await openAboutWelcome();
-
- info("Clicking the primary button to start the onboarding process.");
- await clickVisibleButton(browser, "button.primary");
- resolveLangPacks(["es-MX", "es-ES", "fr-FR"]);
-
- await testScreenContent(
- browser,
- "Live language switching, asking for a language",
- // Expected selectors:
- liveLanguageSwitchSelectors,
- // Unexpected selectors:
- []
- );
-
- info("Clicking the primary button to view language switching page.");
- await clickVisibleButton(browser, "button.primary");
-
- await testScreenContent(
- browser,
- "Live language switching, waiting for langpack to download",
- // Expected selectors:
- [
- ...liveLanguageSwitchSelectors,
- `[data-l10n-id="onboarding-live-language-button-label-downloading"]`,
- `[data-l10n-id="onboarding-live-language-secondary-cancel-download"]`,
- ],
- // Unexpected selectors:
- [
- `button[disabled] [data-l10n-id="onboarding-live-language-waiting-button"]`,
- ]
- );
-
- // Ignore all the telemetry up to this point.
- flushClickTelemetry();
-
- info("Cancel the request for the language");
- await clickVisibleButton(browser, "button.secondary");
-
- await testScreenContent(
- browser,
- "Language selection declined waiting",
- // Expected selectors:
- [`.screen-2`],
- // Unexpected selectors:
- liveLanguageSwitchSelectors
- );
-
- eventsMatch(flushClickTelemetry(), [
- {
- event: "CLICK_BUTTON",
- event_context: {
- source: "cancel_waiting",
- page: "about:welcome",
- },
- message_id: "DEFAULT_ABOUTWELCOME_PROTON_1_AW_LANGUAGE_MISMATCH",
- },
- ]);
-
- await resolveInstaller();
-
- is(flushClickTelemetry().length, 0);
-});
diff --git a/browser/components/newtab/test/unit/aboutwelcome/MultiStageAWProton.test.jsx b/browser/components/newtab/test/unit/aboutwelcome/MultiStageAWProton.test.jsx
index 4dc9c198702b..7a797e913a8c 100644
--- a/browser/components/newtab/test/unit/aboutwelcome/MultiStageAWProton.test.jsx
+++ b/browser/components/newtab/test/unit/aboutwelcome/MultiStageAWProton.test.jsx
@@ -74,28 +74,28 @@ describe("MultiStageAboutWelcomeProton module", () => {
);
assert.propertyVal(data.screens[0], "id", "AW_PIN_FIREFOX");
assert.propertyVal(data.screens[1], "id", "AW_SET_DEFAULT");
- assert.lengthOf(data.screens, getData().screens.length - 1);
+ assert.lengthOf(data.screens, getData().screens.length);
});
it("should keep 'pin' and remove 'default' if already default", async () => {
const data = await prepConfig({ needPin: true });
assert.propertyVal(data.screens[0], "id", "AW_PIN_FIREFOX");
assert.propertyVal(data.screens[1], "id", "AW_IMPORT_SETTINGS");
- assert.lengthOf(data.screens, getData().screens.length - 2);
+ assert.lengthOf(data.screens, getData().screens.length - 1);
});
it("should switch to 'default' if already pinned", async () => {
const data = await prepConfig({ needDefault: true });
assert.propertyVal(data.screens[0], "id", "AW_ONLY_DEFAULT");
assert.propertyVal(data.screens[1], "id", "AW_IMPORT_SETTINGS");
- assert.lengthOf(data.screens, getData().screens.length - 2);
+ assert.lengthOf(data.screens, getData().screens.length - 1);
});
it("should switch to 'start' if already pinned and default", async () => {
const data = await prepConfig();
assert.propertyVal(data.screens[0], "id", "AW_GET_STARTED");
assert.propertyVal(data.screens[1], "id", "AW_IMPORT_SETTINGS");
- assert.lengthOf(data.screens, getData().screens.length - 2);
+ assert.lengthOf(data.screens, getData().screens.length - 1);
});
it("should have a FxA button", async () => {
const data = await prepConfig();
diff --git a/browser/locales/en-US/browser/newtab/onboarding.ftl b/browser/locales/en-US/browser/newtab/onboarding.ftl
index 265c4c2cacf7..015f19522367 100644
--- a/browser/locales/en-US/browser/newtab/onboarding.ftl
+++ b/browser/locales/en-US/browser/newtab/onboarding.ftl
@@ -222,24 +222,3 @@ mr2-onboarding-default-theme-label = Explore default themes.
mr2-onboarding-thank-you-header = Thank you for choosing us
mr2-onboarding-thank-you-text = { -brand-short-name } is an independent browser backed by a non-profit. Together, we’re making the web safer, healthier, and more private.
mr2-onboarding-start-browsing-button-label = Start browsing
-
-## Multistage live language reloading onboarding strings (about:welcome pages)
-##
-## The following language names are generated by the browser's Intl.DisplayNames API.
-##
-## Variables:
-## $appLanguage (String) - The name of Firefox's language, e.g. "American English"
-## $systemLanguage (String) - The name of the OS's language, e.g. "European Spanish"
-## $negotiatedLanguage (String) - The name of the langpack's language, e.g. "European Spanish"
-
-onboarding-live-language-header = Choose Your Language
-onboarding-live-language-subtitle = { -brand-short-name } is using { $appLanguage } while your system is using { $systemLanguage }.
-
-onboarding-live-language-switch-button-label = Switch to { $negotiatedLanguage }
-onboarding-live-language-button-label-downloading = Downloading the language pack for { $negotiatedLanguage }…
-onboarding-live-language-waiting-subtitle = It looks like your system and { -brand-short-name } are using different languages.
-onboarding-live-language-waiting-button = Getting available languages…
-onboarding-live-language-installing = Installing the language pack for { $negotiatedLanguage }…
-onboarding-live-language-secondary-cancel-download = Cancel
-onboarding-live-language-not-now-button-label = Not now
-onboarding-live-language-skip-button-label = Skip
diff --git a/intl/locale/LangPackMatcher.jsm b/intl/locale/LangPackMatcher.jsm
deleted file mode 100644
index ea30b4f0589e..000000000000
--- a/intl/locale/LangPackMatcher.jsm
+++ /dev/null
@@ -1,311 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-const { XPCOMUtils } = ChromeUtils.import(
- "resource://gre/modules/XPCOMUtils.jsm"
-);
-
-XPCOMUtils.defineLazyModuleGetters(this, {
- AddonRepository: "resource://gre/modules/addons/AddonRepository.jsm",
- AddonManager: "resource://gre/modules/AddonManager.jsm",
- Services: "resource://gre/modules/Services.jsm",
-});
-
-if (Services.appinfo.processType !== Services.appinfo.PROCESS_TYPE_DEFAULT) {
- // This check ensures that the `mockable` API calls can be consisently mocked in tests.
- // If this requirement needs to be eased, please ensure the test logic remains valid.
- throw new Error("This code is assumed to run in the parent process.");
-}
-
-/**
- * Attempts to find an appropriate langpack for a given language. The async function
- * is infallible, but may not return a langpack.
- *
- * @returns {LangPack | null}
- */
-async function negotiateLangPackForLanguageMismatch() {
- const localeInfo = getAppAndSystemLocaleInfo();
- if (!localeInfo.systemLocale) {
- // The system locale info was not valid.
- return null;
- }
-
- /**
- * Fetch the available langpacks from AMO.
- *
- * @type {Array}
- */
- const availableLangpacks = await mockable.getAvailableLangpacks();
- if (!availableLangpacks) {
- return null;
- }
-
- /**
- * Figure out a langpack to recommend.
- * @type {LangPack | null}
- */
- return (
- // First look for a langpack that matches the baseName.
- // e.g. system "fr-FR" matches langpack "fr-FR"
- // system "en-GB" matches langpack "en-GB".
- availableLangpacks.find(
- ({ target_locale }) => target_locale === localeInfo.systemLocale.baseName
- ) ||
- // Next look for langpacks that just match the language.
- // e.g. system "fr-FR" matches langpack "fr".
- // system "en-AU" matches langpack "en".
- availableLangpacks.find(
- ({ target_locale }) => target_locale === localeInfo.systemLocale.language
- ) ||
- // Next look for a langpack that matches the language, but not the region.
- // e.g. "es-CL" (Chilean Spanish) as a system language matching
- // "es-ES" (European Spanish)
- availableLangpacks.find(({ target_locale }) =>
- target_locale.startsWith(`${localeInfo.systemLocale.language}-`)
- ) ||
- null
- );
-}
-
-// If a langpack is being installed, allow blocking on that.
-let installingLangpack = new Map();
-
-/**
- * @typedef {LangPack}
- * @type {object}
- * @property {string} target_locale
- * @property {string} url
- * @property {string} hash
- */
-
-/**
- * Ensure that a given lanpack is installed.
- *
- * @param {LangPack} langPack
- * @returns {Promise} Success or failure.
- */
-function ensureLangPackInstalled(langPack) {
- if (!langPack) {
- throw new Error("Expected a LangPack to install.");
- }
- // Make sure any outstanding calls get resolved before attempting another call.
- // This guards against any quick page refreshes attempting to install the langpack
- // twice.
- const inProgress = installingLangpack.get(langPack.hash);
- if (inProgress) {
- return inProgress;
- }
- const promise = _ensureLangPackInstalledImpl(langPack);
- installingLangpack.set(langPack.hash, promise);
- promise.finally(() => {
- installingLangpack.delete(langPack.hash);
- });
- return promise;
-}
-
-/**
- * @param {LangPack} langPack
- * @returns {boolean} Success or failure.
- */
-async function _ensureLangPackInstalledImpl(langPack) {
- if (mockable.getAvailableLocales().includes(langPack.target_locale)) {
- // The langpack is already installed.
- return true;
- }
-
- return mockable.installLangPack(langPack);
-}
-
-/**
- * These are all functions with side effects or configuration options that should be
- * mockable for tests.
- */
-const mockable = {
- /**
- * @returns {LangPack[] | null}
- */
- async getAvailableLangpacks() {
- try {
- return AddonRepository.getAvailableLangpacks();
- } catch (error) {
- Cu.reportError(
- `Failed to get the list of available language packs: ${error?.message}`
- );
- return null;
- }
- },
-
- /**
- * Use the AddonManager to install an addon from the URL.
- * @param {LangPack} langPack
- */
- async installLangPack(langPack) {
- let install;
- try {
- install = await AddonManager.getInstallForURL(langPack.url, {
- hash: langPack.hash,
- telemetryInfo: {
- source: "about:welcome",
- },
- });
- } catch (error) {
- Cu.reportError(error);
- return false;
- }
-
- try {
- await install.install();
- } catch (error) {
- Cu.reportError(error);
- return false;
- }
- return true;
- },
-
- /**
- * @returns {string[]}
- */
- getAvailableLocales() {
- return Services.locale.availableLocales;
- },
-
- /**
- * @returns {string}
- */
- getAppLocaleAsBCP47() {
- return Services.locale.appLocaleAsBCP47;
- },
-
- /**
- * @returns {string}
- */
- getSystemLocale() {
- // Allow the system locale to be overridden for manual testing.
- const systemLocaleOverride = Services.prefs.getCharPref(
- "intl.multilingual.aboutWelcome.systemLocaleOverride",
- null
- );
- if (systemLocaleOverride) {
- try {
- // If the locale can't be parsed, ignore the pref.
- new Services.intl.Locale(systemLocaleOverride);
- return systemLocaleOverride;
- } catch (_error) {}
- }
-
- const osPrefs = Cc["@mozilla.org/intl/ospreferences;1"].getService(
- Ci.mozIOSPreferences
- );
- return osPrefs.systemLocale;
- },
-
- /**
- * @param {string[]} locales The BCP 47 locale identifiers.
- */
- setRequestedAppLocales(locales) {
- Services.locale.requestedLocales = locales;
- },
-};
-
-/**
- * This function is really only setting `Services.locale.requestedLocales`, but it's
- * using the `mockable` object to allow this behavior to be mocked in tests.
- *
- * @param {string[]} locales The BCP 47 locale identifiers.
- */
-function setRequestedAppLocales(locales) {
- mockable.setRequestedAppLocales(locales);
-}
-
-/**
- * A serializable Intl.Locale.
- *
- * @typedef StructuredLocale
- * @type {object}
- * @property {string} baseName
- * @property {string} language
- * @property {string} region
- */
-
-/**
- * In telemetry data, some of the system locales show up as blank. Guard against this
- * and any other malformed locale information provided by the system by wrapping the call
- * into a catch/try.
- *
- * @param {string} locale
- * @returns {StructuredLocale | null}
- */
-function getStructuredLocaleOrNull(localeString) {
- try {
- const locale = new Services.intl.Locale(localeString);
- return {
- baseName: locale.baseName,
- language: locale.language,
- region: locale.region,
- };
- } catch (_err) {
- return null;
- }
-}
-
-/**
- * Determine the system and app locales, and how much the locales match.
- *
- * @returns {{
- * systemLocale: StructuredLocale,
- * appLocale: StructuredLocale,
- * matchType: "unknown" | "language-mismatch" | "region-mismatch" | "match",
- * }}
- */
-function getAppAndSystemLocaleInfo() {
- // Convert locale strings into structured locale objects.
- const systemLocaleRaw = mockable.getSystemLocale();
- const appLocaleRaw = mockable.getAppLocaleAsBCP47();
-
- const systemLocale = getStructuredLocaleOrNull(systemLocaleRaw);
- const appLocale = getStructuredLocaleOrNull(appLocaleRaw);
-
- let matchType = "unknown";
- if (systemLocale && appLocale) {
- if (systemLocale.language !== appLocale.language) {
- matchType = "language-mismatch";
- } else if (systemLocale.region !== appLocale.region) {
- matchType = "region-mismatch";
- } else {
- matchType = "match";
- }
- }
-
- const displayNames = new Services.intl.DisplayNames(appLocaleRaw, {
- type: "language",
- });
-
- return {
- // Return the Intl.Locale in a serializable form.
- systemLocaleRaw,
- systemLocale,
- appLocaleRaw,
- appLocale,
- matchType,
-
- // These can be used as Fluent message args.
- displayNames: {
- systemLanguage: systemLocale
- ? displayNames.of(systemLocale.baseName)
- : null,
- appLanguage: appLocale ? displayNames.of(appLocale.baseName) : null,
- },
- };
-}
-
-var LangPackMatcher = {
- negotiateLangPackForLanguageMismatch,
- ensureLangPackInstalled,
- getAppAndSystemLocaleInfo,
- setRequestedAppLocales,
- mockable,
-};
-
-var EXPORTED_SYMBOLS = ["LangPackMatcher"];
diff --git a/intl/locale/moz.build b/intl/locale/moz.build
index 232e40007659..0a58e2964b91 100644
--- a/intl/locale/moz.build
+++ b/intl/locale/moz.build
@@ -6,10 +6,6 @@
XPCSHELL_TESTS_MANIFESTS += ["tests/unit/xpcshell.ini"]
-TESTING_JS_MODULES += [
- "tests/LangPackMatcherTestUtils.jsm",
-]
-
toolkit = CONFIG["MOZ_WIDGET_TOOLKIT"]
if toolkit == "windows":
@@ -51,7 +47,6 @@ UNIFIED_SOURCES += [
]
EXTRA_JS_MODULES += [
- "LangPackMatcher.jsm",
"PluralForm.jsm",
]
diff --git a/intl/locale/tests/LangPackMatcherTestUtils.jsm b/intl/locale/tests/LangPackMatcherTestUtils.jsm
deleted file mode 100644
index 7a90e6c21e8d..000000000000
--- a/intl/locale/tests/LangPackMatcherTestUtils.jsm
+++ /dev/null
@@ -1,119 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-var EXPORTED_SYMBOLS = ["getAddonAndLocalAPIsMocker"];
-
-const { LangPackMatcher } = ChromeUtils.import(
- "resource://gre/modules/LangPackMatcher.jsm"
-);
-
-/**
- * LangPackMatcher.jsm calls out to to the addons store, which involves network requests.
- * Other tests create a fake addons server, and install mock XPIs. At the time of this
- * writing that infrastructure is not available for mochitests.
- *
- * Instead, this test mocks out APIs that have a side-effect, so the addons of the browser
- * are never modified.
- *
- * The calls to get the app's locale and system's locale are also mocked so that the
- * different language mismatch scenarios can be run through.
- *
- * The locales are BCP 47 identifiers:
- *
- * @param {{
- * sandbox: SinonSandbox,
- * systemLocale: string,
- * appLocale, string,
- * }}
- */
-function getAddonAndLocalAPIsMocker(testScope, sandbox) {
- const { info } = testScope;
- return function mockAddonAndLocaleAPIs({ systemLocale, appLocale }) {
- info("Mocking LangPackMatcher.jsm APIs");
-
- let resolveLangPacks;
- const langPackPromise = new Promise(resolve => {
- resolveLangPacks = availableLangpacks => {
- info(
- `Resolving which langpacks are available for download: ${JSON.stringify(
- availableLangpacks
- )}`
- );
- resolve(
- availableLangpacks.map(locale => ({
- guid: `langpack-${locale}@firefox.mozilla.org`,
- type: "language",
- target_locale: locale,
- current_compatible_version: {
- files: [
- {
- platform: "all",
- url: `http://example.com/${locale}.langpack.xpi`,
- },
- ],
- },
- }))
- );
- };
- });
-
- let resolveInstaller;
- const installerPromise = new Promise(resolve => {
- resolveInstaller = () => {
- info("LangPack install finished.");
- resolve();
- };
- });
-
- const { mockable } = LangPackMatcher;
- if (appLocale) {
- sandbox.stub(mockable, "getAvailableLocales").returns([appLocale]);
- sandbox.stub(mockable, "getAppLocaleAsBCP47").returns(appLocale);
- }
- if (systemLocale) {
- sandbox.stub(mockable, "getSystemLocale").returns(systemLocale);
- }
-
- sandbox.stub(mockable, "getAvailableLangpacks").callsFake(() => {
- info("Requesting which langpacks are available for download");
- return langPackPromise;
- });
-
- sandbox.stub(mockable, "installLangPack").callsFake(langPack => {
- info(`LangPack install started, but pending: ${langPack.target_locale}`);
- return installerPromise;
- });
-
- sandbox.stub(mockable, "setRequestedAppLocales").callsFake(locales => {
- info(
- `Changing the browser's requested locales to: ${JSON.stringify(
- locales
- )}`
- );
- });
-
- return {
- /**
- * Resolves the addons API call with available langpacks. Call with a list
- * of BCP 47 identifiers.
- *
- * @type {(availableLangpacks: string[]) => {}}
- */
- resolveLangPacks,
-
- /**
- * Resolves the pending call to install a langpack.
- *
- * @type {() => {}}
- */
- resolveInstaller,
-
- /**
- * The mocked APIs.
- */
- mockable,
- };
- };
-}
diff --git a/intl/locale/tests/unit/test_langPackMatcher.js b/intl/locale/tests/unit/test_langPackMatcher.js
deleted file mode 100644
index 7b05d19191b2..000000000000
--- a/intl/locale/tests/unit/test_langPackMatcher.js
+++ /dev/null
@@ -1,201 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const { getAddonAndLocalAPIsMocker } = ChromeUtils.import(
- "resource://testing-common/LangPackMatcherTestUtils.jsm"
-);
-const { LangPackMatcher } = ChromeUtils.import(
- "resource://gre/modules/LangPackMatcher.jsm"
-);
-const { sinon } = ChromeUtils.import("resource://testing-common/Sinon.jsm");
-
-const sandbox = sinon.createSandbox();
-const mockAddonAndLocaleAPIs = getAddonAndLocalAPIsMocker(this, sandbox);
-
-add_task(function initSandbox() {
- registerCleanupFunction(() => {
- sandbox.restore();
- });
-});
-
-add_task(function test_appLocaleLanguageMismatch() {
- sandbox.restore();
- mockAddonAndLocaleAPIs({
- systemLocale: "es-ES",
- appLocale: "en-US",
- });
-
- deepEqual(LangPackMatcher.getAppAndSystemLocaleInfo(), {
- systemLocaleRaw: "es-ES",
- systemLocale: { baseName: "es-ES", language: "es", region: "ES" },
- appLocaleRaw: "en-US",
- appLocale: { baseName: "en-US", language: "en", region: "US" },
- matchType: "language-mismatch",
- displayNames: {
- systemLanguage: "European Spanish",
- appLanguage: "American English",
- },
- });
-});
-
-add_task(function test_appLocaleRegionMismatch() {
- sandbox.restore();
- mockAddonAndLocaleAPIs({
- sandbox,
- systemLocale: "en-CA",
- appLocale: "en-US",
- });
-
- deepEqual(LangPackMatcher.getAppAndSystemLocaleInfo(), {
- systemLocaleRaw: "en-CA",
- systemLocale: { baseName: "en-CA", language: "en", region: "CA" },
- appLocaleRaw: "en-US",
- appLocale: { baseName: "en-US", language: "en", region: "US" },
- matchType: "region-mismatch",
- displayNames: {
- systemLanguage: "Canadian English",
- appLanguage: "American English",
- },
- });
-});
-
-add_task(function test_appLocaleScriptMismatch() {
- sandbox.restore();
- // Script mismatch:
- mockAddonAndLocaleAPIs({
- sandbox,
- systemLocale: "zh-Hans-CN",
- appLocale: "zh-CN",
- });
-
- deepEqual(LangPackMatcher.getAppAndSystemLocaleInfo(), {
- systemLocaleRaw: "zh-Hans-CN",
- systemLocale: { baseName: "zh-Hans-CN", language: "zh", region: "CN" },
- appLocaleRaw: "zh-CN",
- appLocale: { baseName: "zh-CN", language: "zh", region: "CN" },
- matchType: "match",
- displayNames: {
- systemLanguage: "简体中文(中国)",
- appLanguage: "中文(中国)",
- },
- });
-});
-
-add_task(function test_appLocaleInvalidSystem() {
- sandbox.restore();
- // Script mismatch:
- mockAddonAndLocaleAPIs({
- sandbox,
- systemLocale: "Not valid",
- appLocale: "en-US",
- });
-
- deepEqual(LangPackMatcher.getAppAndSystemLocaleInfo(), {
- systemLocaleRaw: "Not valid",
- systemLocale: null,
- appLocaleRaw: "en-US",
- appLocale: { baseName: "en-US", language: "en", region: "US" },
- matchType: "unknown",
- displayNames: { systemLanguage: null, appLanguage: "American English" },
- });
-});
-
-function shuffle(array) {
- return array
- .map(value => ({ value, sort: Math.random() }))
- .sort((a, b) => a.sort - b.sort)
- .map(({ value }) => value);
-}
-
-add_task(async function test_negotiateLangPacks() {
- const negotiations = [
- {
- // Exact match found.
- systemLocale: "en-US",
- availableLangPacks: ["en", "en-US", "zh", "zh-CN", "zh-Hans-CN"],
- expected: "en-US",
- },
- {
- // Region-less match.
- systemLocale: "en-CA",
- availableLangPacks: ["en", "en-US", "zh", "zh-CN", "zh-Hans-CN"],
- expected: "en",
- },
- {
- // Fallback to a different region.
- systemLocale: "en-CA",
- availableLangPacks: ["en-US", "zh", "zh-CN", "zh-Hans-CN"],
- expected: "en-US",
- },
- {
- // Match with a script. zh-Hans-CN is the locale used with simplified
- // Chinese scripts, while zh-CN uses the Latin script.
- systemLocale: "zh-Hans-CN",
- availableLangPacks: ["en", "en-US", "zh", "zh-CN", "zh-Hans-CN"],
- expected: "zh-Hans-CN",
- },
- {
- // No reasonable match could be found.
- systemLocale: "tlh", // Klingon
- availableLangPacks: ["en", "en-US", "zh", "zh-CN", "zh-Hans-CN"],
- expected: null,
- },
- {
- // Weird, but valid locale identifiers.
- systemLocale: "en-US-u-hc-h23-ca-islamic-civil-ss-true",
- availableLangPacks: ["en", "en-US", "zh", "zh-CN", "zh-Hans-CN"],
- expected: "en-US",
- },
- {
- // Invalid system locale
- systemLocale: "Not valid",
- availableLangPacks: ["en", "en-US", "zh", "zh-CN", "zh-Hans-CN"],
- expected: null,
- },
- ];
-
- for (const { systemLocale, availableLangPacks, expected } of negotiations) {
- sandbox.restore();
- const { resolveLangPacks } = mockAddonAndLocaleAPIs({
- sandbox,
- systemLocale,
- });
-
- const promise = LangPackMatcher.negotiateLangPackForLanguageMismatch();
- // Shuffle the order to ensure that this test doesn't require on ordering of the
- // langpack responses.
- resolveLangPacks(shuffle(availableLangPacks));
- const actual = (await promise)?.target_locale;
- equal(
- actual,
- expected,
- `Resolve the systemLocale "${systemLocale}" with available langpacks: ${JSON.stringify(
- availableLangPacks
- )}`
- );
- }
-});
-
-add_task(async function test_ensureLangPackInstalled() {
- sandbox.restore();
- const { resolveLangPacks, resolveInstaller } = mockAddonAndLocaleAPIs({
- sandbox,
- systemLocale: "es-ES",
- appLocale: "en-US",
- });
-
- const negotiatePromise = LangPackMatcher.negotiateLangPackForLanguageMismatch();
- resolveLangPacks(["es-ES"]);
- const langPack = await negotiatePromise;
-
- const installPromise1 = LangPackMatcher.ensureLangPackInstalled(langPack);
- const installPromise2 = LangPackMatcher.ensureLangPackInstalled(langPack);
-
- resolveInstaller(["fake langpack"]);
-
- info("Ensure both installers resolve when called twice in a row.");
- await installPromise1;
- await installPromise2;
- ok(true, "Both were called.");
-});
diff --git a/intl/locale/tests/unit/xpcshell.ini b/intl/locale/tests/unit/xpcshell.ini
index 1b213949a151..75ab01343430 100644
--- a/intl/locale/tests/unit/xpcshell.ini
+++ b/intl/locale/tests/unit/xpcshell.ini
@@ -10,7 +10,7 @@ skip-if = toolkit != "windows" && toolkit != "cocoa"
[test_bug1086527.js]
[test_intl_on_workers.js]
skip-if = toolkit == "android" # bug 1309447
-[test_langPackMatcher.js]
+
[test_pluralForm.js]
[test_pluralForm_english.js]
[test_pluralForm_makeGetter.js]
diff --git a/toolkit/components/nimbus/FeatureManifest.yaml b/toolkit/components/nimbus/FeatureManifest.yaml
index b59b72f420e2..6d042be90af3 100644
--- a/toolkit/components/nimbus/FeatureManifest.yaml
+++ b/toolkit/components/nimbus/FeatureManifest.yaml
@@ -125,12 +125,6 @@ aboutwelcome:
description: >-
Should the urlbar should be focused when users first land on
about:welcome?
- languageMismatchEnabled:
- type: boolean
- fallbackPref: intl.multilingual.aboutWelcome.languageMismatchEnabled
- description: >-
- Suggest to change the language on about:welcome when there is a mismatch with
- the OS.
transitions:
type: boolean
description: Enable transition effect between screens