261 lines
5.3 KiB
JavaScript
261 lines
5.3 KiB
JavaScript
/* 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;
|
|
}
|
|
}
|
|
|
|
get cfrFluentFileDir() {
|
|
return PathUtils.join(
|
|
Services.dirsvc.get("ProfLD", Ci.nsIFile).path,
|
|
"settings",
|
|
"main",
|
|
"ms-language-packs"
|
|
);
|
|
}
|
|
|
|
get cfrFluentFilePath() {
|
|
return PathUtils.join(
|
|
this.cfrFluentFileDir,
|
|
"browser",
|
|
"newtab",
|
|
"asrouter.ftl"
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
let cfrIndexedFileSource = new L10nFileSource(
|
|
"cfr",
|
|
"app",
|
|
[appLocale],
|
|
`${PathUtils.toFileURI(this.cfrFluentFileDir)}/`,
|
|
{
|
|
addResourceOptions: {
|
|
allowOverrides: true,
|
|
},
|
|
},
|
|
[PathUtils.toFileURI(this.cfrFluentFilePath)]
|
|
);
|
|
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",
|
|
"preview/termsOfUse.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();
|