Open Bug 1440969 Opened 6 years ago Updated 1 year ago

Introduce separate requestedlocales for extensions


(Core :: Internationalization, enhancement, P3)





(Reporter: zbraniecki, Unassigned)


(Blocks 2 open bugs)


One of the common scenarios when working on addons is that the developer either manually or in a test wants to test how the addon works in different locales.

Currently, the addons locale negotiation is chained to the firefox locale negotiation in order to make sure the locale stays in sync with Firefox.

But when testing, it means that the user has to mock Firefox locales to test addon locales.

I think it's a right time to slowly start introducing the concept of separate requested locale lists for separate components, starting with addons.

Since the code is internal and we have a good way to search&replace it at will, I think we don't have to overthink it and try to get the API or IDs final, and can start with a simple:


where an empty value of course means the main component.

I imagine the implementation to be sth like this:

GetRequestedLocales(component) {
  switch (component) {
      if (Services.prefs.hasPref("intl.locale.requested.extensions")) {
        return Services.prefs.getPref("intl.locale.requested.extensions");
      return mRequestedLocales;
Blocks: 1346877
Priority: -- → P3
The more I think about it the more uncertain I am which direction we should take.

The general direction is fairly clear. We want to be able to product separate list of locales for separate `contexts`.
A couple example of contexts:

 - Firefox UI
 - DevTools
 - Extensions
 - A particular extension A

In each case we may have separate lists of available locales (we could package Firefox with ["it", "fr"], and devtools in ["it", "en-US"] and then each extension will come with its own list of available locales) and we want to allow the user to also pick different lists of requested locales (I want Firefox in ["it"], DevTools in ["en-US"] and am testing my extension A in ["ko-KR"]).

That will result in multiple different resolved locale lists - one for Firefox, one for DevTools, one for extension A.

The two main ways to handle this is:

A) Centralized

We could try to get LocaleService to be a service that can handle requested/available/result locale lists for different `contexts`.

An example may look like this:

let fxAvLocales = Services.locale.getAvailableLocales(`firefox`);
let fxReqLocales = Services.locale.getRequestedLocales(`firefox`);

let fxLocales = Services.locale.getAppLocales(`firefox`);

let myExtAvLocales = Services.locale.getAvailableLocales(`my-extension-id`);
let myExtReqLocales = Services.locale.getRequestedLocales(`my-extension-id`);

let myExtLocales = Services.locale.getAppLocales(`my-extension-id`);

The benefit of this approach is that we can centralize the selection and also overlays - for example you could have `intl.locale.requested` pref set for your requested locales, and override with `intl.locale.requested.extensions` for different list for extensions, and then maybe `` for a different list for this particular extension.

We could then smartly match when to link the extension locales to firefox locales, and when to allow the developer to test a particular locale irrelevant of Firefox locale.

B) Decentralized

We could keep the LocaleService as a central API for the main Gecko application and let all components perform the negotiation on their own.

This is closer to what's currently going on and it has the benefit of us not having to cram more code into LocaleService.

The downside is that now each part of the code has to figure out their own negotiation strategy and if we'd want to have separate locale list for each extension we'd have to use AddonsManager to negotiate separately for `intl.locale.requested.extensions` pref being set or not. (or `extensions.intl.locale.requested`?).

Would love to get some input from others
Flags: needinfo?(stas)
Flags: needinfo?(l10n)
Flags: needinfo?(jfkthame)
Flags: needinfo?(francesco.lodolo)
So, I think we need to provide the general language negotiation code in a central piece. Let's not ask people to impl intl, just like we don't ask them to impl crypto ;-)

I wonder if there's an existing gecko artifact that sandboxes stuff, that we could use. How do we sandbox different addons from each other?

To slice this a bit (sorry, rambling):

Services.locale.negotiateLanguages is one central part.
Services.locale.getAvailableLocales also seems to be something we should centrally provide, if we find the right argument? We could do chrome://global as one aspect.

Services.locale.getRequested is effectively the storage location, right? That's an interesting question, in particular if we take into account that this would be runtime-dependent. Thinking about the prefs stuff, but that got also wontfixed.

Yeah, sorry, rambling. More thoughts than opinions.
Flags: needinfo?(l10n)
Depends on: 1358653
Not sure I have a great understanding of the topic, but I think that locale negotiation should be centralized.

In my head it would work like this:
* Extensions would provide the list of supported locales in their manifest.
* During installation/update, a context is created for the extension, registering the list of available locales.
* Services.locale.getAppLocales(`my-extension-id`) would find the best match, taking into consideration a) a specific list of requested locales defined for the add-on, b) Services.locale.getAppLocales(`firefox`) if a) is not defined.

Requesting each component to perform this work would mean asking them to reinvent the wheel, likely with different results depending on the component (I think we already experience that, at some point, with Activity Stream).
Flags: needinfo?(francesco.lodolo)

Clearing old needinfos.

Flags: needinfo?(smalolepszy)
Flags: needinfo?(jfkthame)
Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.