Source code

Revision control

Copy as Markdown

Other Tools

/* 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 downloaded Fluent file is located in this sub-directory of the local
* profile directory.
*/
const USE_REMOTE_L10N_PREF =
"browser.newtabpage.activity-stream.asrouter.useRemoteL10n";
/**
* All supported locales for remote l10n
*
* This is used by ASRouter.sys.mjs to check if the locale is supported before
* issuing the request for remote fluent files to RemoteSettings.
*
* Note:
* * this is generated based on "browser/locales/all-locales" as l10n doesn't
* provide an API to fetch that list
*
* * this list doesn't include "en-US", though "en-US" is well supported and
* `_RemoteL10n.isLocaleSupported()` will handle it properly
*/
const ALL_LOCALES = new Set([
"ach",
"af",
"an",
"ar",
"ast",
"az",
"be",
"bg",
"bn",
"bo",
"br",
"brx",
"bs",
"ca",
"ca-valencia",
"cak",
"ckb",
"cs",
"cy",
"da",
"de",
"dsb",
"el",
"en-CA",
"en-GB",
"eo",
"es-AR",
"es-CL",
"es-ES",
"es-MX",
"et",
"eu",
"fa",
"ff",
"fi",
"fr",
"fy-NL",
"ga-IE",
"gd",
"gl",
"gn",
"gu-IN",
"he",
"hi-IN",
"hr",
"hsb",
"hu",
"hy-AM",
"hye",
"ia",
"id",
"is",
"it",
"ja",
"ja-JP-mac",
"ka",
"kab",
"kk",
"km",
"kn",
"ko",
"lij",
"lo",
"lt",
"ltg",
"lv",
"meh",
"mk",
"mr",
"ms",
"my",
"nb-NO",
"ne-NP",
"nl",
"nn-NO",
"oc",
"pa-IN",
"pl",
"pt-BR",
"pt-PT",
"rm",
"ro",
"ru",
"scn",
"si",
"sk",
"sl",
"son",
"sq",
"sr",
"sv-SE",
"szl",
"ta",
"te",
"th",
"tl",
"tr",
"trs",
"uk",
"ur",
"uz",
"vi",
"wo",
"xh",
"zh-CN",
"zh-TW",
]);
export class _RemoteL10n {
constructor() {
this._l10n = null;
}
createElement(doc, elem, options = {}) {
let node;
if (options.content && options.content.string_id) {
node = doc.createElement("remote-text");
} else {
node = doc.createElementNS("http://www.w3.org/1999/xhtml", elem);
}
if (options.classList) {
node.classList.add(options.classList);
}
this.setString(node, options);
return node;
}
// If `string_id` is present it means we are relying on fluent for translations.
// Otherwise, we have a vanilla string.
setString(el, { content, attributes = {} }) {
if (content && content.string_id) {
for (let [fluentId, value] of Object.entries(attributes)) {
el.setAttribute(`fluent-variable-${fluentId}`, value);
}
el.setAttribute("fluent-remote-id", content.string_id);
} else {
el.textContent = content;
}
}
/**
* Creates a new DOMLocalization instance with the Fluent file from Remote Settings.
*
* Note: it will use the local Fluent file in any of following cases:
* * the remote Fluent file is not available
* * it was told to use the local Fluent file
*/
_createDOML10n() {
/* istanbul ignore next */
let useRemoteL10n = Services.prefs.getBoolPref(USE_REMOTE_L10N_PREF, true);
if (useRemoteL10n && !L10nRegistry.getInstance().hasSource("cfr")) {
const appLocale = Services.locale.appLocaleAsBCP47;
const l10nFluentDir = PathUtils.join(
Services.dirsvc.get("ProfLD", Ci.nsIFile).path,
"settings",
"main",
"ms-language-packs"
);
let cfrIndexedFileSource = new L10nFileSource(
"cfr",
"app",
[appLocale],
`file://${l10nFluentDir}/`,
{
addResourceOptions: {
allowOverrides: true,
},
},
[`file://${l10nFluentDir}/browser/newtab/asrouter.ftl`]
);
L10nRegistry.getInstance().registerSources([cfrIndexedFileSource]);
} else if (!useRemoteL10n && L10nRegistry.getInstance().hasSource("cfr")) {
L10nRegistry.getInstance().removeSources(["cfr"]);
}
return new DOMLocalization(
[
"branding/brand.ftl",
"browser/defaultBrowserNotification.ftl",
"browser/newtab/asrouter.ftl",
"toolkit/branding/brandings.ftl",
],
false
);
}
get l10n() {
if (!this._l10n) {
this._l10n = this._createDOML10n();
}
return this._l10n;
}
reloadL10n() {
this._l10n = null;
}
isLocaleSupported(locale) {
return locale === "en-US" || ALL_LOCALES.has(locale);
}
/**
* Format given `localizableText`.
*
* Format `localizableText` if it is an object using any `string_id` field,
* otherwise return `localizableText` unmodified.
*
* @param {object|string} `localizableText` to format.
* @return {string} formatted text.
*/
async formatLocalizableText(localizableText) {
if (typeof localizableText !== "string") {
// It's more useful to get an error than passing through an object without
// a `string_id` field.
let value = await this.l10n.formatValue(localizableText.string_id);
return value;
}
return localizableText;
}
}
export const RemoteL10n = new _RemoteL10n();