commit 2a168f62ddf5d6dd9664d8b33fb0ae24cdca1421
parent 9981cd676ae09c7a0e662f86911c1ba01e85fe6c
Author: Mike Conley <mconley@mozilla.com>
Date: Mon, 20 Oct 2025 17:05:32 +0000
Bug 1994642 - Use Services.locales.availableLanguages for dynamic newtab.ftl registration for train-hops. r=eemeli,home-newtab-reviewers,thecount
This registers the newtab.ftl Fluent files in a train-hopped XPI _just_ for the
base application's availableLocales. If that set changes (for example, if the
user installs a new language pack in the base app), then the we update the
registration, always using the intersection of the available languages from
the base app and the list of locales included with the XPI.
Differential Revision: https://phabricator.services.mozilla.com/D269093
Diffstat:
1 file changed, 65 insertions(+), 10 deletions(-)
diff --git a/browser/components/newtab/AboutNewTabResourceMapping.sys.mjs b/browser/components/newtab/AboutNewTabResourceMapping.sys.mjs
@@ -18,6 +18,10 @@ export const TRAINHOP_SCHEDULED_UPDATE_STATE_DELAY_PREF =
export const TRAINHOP_SCHEDULED_UPDATE_STATE_TIMEOUT_PREF =
"browser.newtabpage.trainhopAddon.scheduledUpdateState.timeout";
+const FLUENT_SOURCE_NAME = "newtab";
+const TOPIC_LOCALES_CHANGED = "intl:app-locales-changed";
+const TOPIC_SHUTDOWN = "profile-before-change";
+
const lazy = XPCOMUtils.declareLazy({
AddonManager: "resource://gre/modules/AddonManager.sys.mjs",
AddonSettings: "resource://gre/modules/addons/AddonSettings.sys.mjs",
@@ -82,6 +86,7 @@ export var AboutNewTabResourceMapping = {
_addonListener: null,
_builtinVersion: null,
_updateAddonStateDeferredTask: null,
+ _supportedLocales: null,
/**
* Returns the version string for whichever version of New Tab is currently
@@ -291,17 +296,20 @@ export var AboutNewTabResourceMapping = {
*/
async registerFluentSources(rootURI) {
try {
- const SUPPORTED_LOCALES = await fetch(
- rootURI.resolve("/locales/supported-locales.json")
- ).then(r => r.json());
- const newtabFileSource = new L10nFileSource(
- "newtab",
- "app",
- SUPPORTED_LOCALES,
- `resource://newtab/locales/{locale}/`
+ // Read in the list of locales included with the XPI. This will prevent
+ // us from accidentally registering a L10nFileSource that wasn't included.
+ this._supportedLocales = new Set(
+ await fetch(rootURI.resolve("/locales/supported-locales.json")).then(
+ r => r.json()
+ )
);
- this._l10nFileSource = newtabFileSource;
- L10nRegistry.getInstance().registerSources([newtabFileSource]);
+
+ // Set up observers so that if the user changes the list of available
+ // locales, we'll re-register.
+ Services.obs.addObserver(this, TOPIC_LOCALES_CHANGED);
+ Services.obs.addObserver(this, TOPIC_SHUTDOWN);
+ // Now actually do the registration.
+ this._updateFluentSourcesRegistration();
} catch (e) {
// TODO: consider if we should collect this in telemetry.
this.logger.error(
@@ -312,6 +320,53 @@ export var AboutNewTabResourceMapping = {
},
/**
+ * Sets up the L10nFileSource for the newtab Fluent files included in the
+ * XPI that are in the available locales for the app. If a pre-existing
+ * registration exists, it will be updated.
+ */
+ _updateFluentSourcesRegistration() {
+ let availableLocales = new Set(Services.locale.availableLocales);
+ let availableSupportedLocales =
+ this._supportedLocales.intersection(availableLocales);
+
+ const newtabFileSource = new L10nFileSource(
+ FLUENT_SOURCE_NAME,
+ "app",
+ [...availableSupportedLocales],
+ `resource://newtab/locales/{locale}/`
+ );
+
+ let registry = L10nRegistry.getInstance();
+ if (registry.hasSource(FLUENT_SOURCE_NAME)) {
+ registry.updateSources([newtabFileSource]);
+ this.logger.debug(
+ "Newtab strings updated for ",
+ availableSupportedLocales
+ );
+ } else {
+ registry.registerSources([newtabFileSource]);
+ this.logger.debug(
+ "Newtab strings registered for ",
+ availableSupportedLocales
+ );
+ }
+ },
+
+ observe(_subject, topic, _data) {
+ switch (topic) {
+ case TOPIC_LOCALES_CHANGED: {
+ this._updateFluentSourcesRegistration();
+ break;
+ }
+ case TOPIC_SHUTDOWN: {
+ Services.obs.removeObserver(this, TOPIC_LOCALES_CHANGED);
+ Services.obs.removeObserver(this, TOPIC_SHUTDOWN);
+ break;
+ }
+ }
+ },
+
+ /**
* Registers any dynamic Glean metrics that have been included with the XPI
* version of the add-on.
*/