forked from mirrors/gecko-dev
Bug 1428769 - Add intl/l10n to be covered by eslint. r=Pike
MozReview-Commit-ID: 6Mu1A8xkxn4 --HG-- extra : rebase_source : e62867d32b0062a6aa076572b85fb9cec7afb81a
This commit is contained in:
parent
aa92df7e1d
commit
c797a57c90
20 changed files with 432 additions and 424 deletions
|
|
@ -24,7 +24,6 @@ gfx/tests/chrome/**
|
|||
gfx/tests/mochitest/**
|
||||
gfx/tests/unit/**
|
||||
image/**
|
||||
intl/**
|
||||
layout/**
|
||||
memory/replace/dmd/test/**
|
||||
modules/**
|
||||
|
|
@ -303,6 +302,12 @@ dom/media/webvtt/**
|
|||
gfx/ots/**
|
||||
gfx/skia/**
|
||||
|
||||
# intl/ exclusions
|
||||
intl/icu/**
|
||||
intl/locale/**
|
||||
intl/strres/**
|
||||
intl/uconv/**
|
||||
|
||||
# Exclude everything but self-hosted JS
|
||||
js/ductwork/**
|
||||
js/examples/**
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
|
||||
|
||||
/* fluent@0.6.0 */
|
||||
/* fluent@0.6.3 */
|
||||
|
||||
const { Localization } =
|
||||
ChromeUtils.import("resource://gre/modules/Localization.jsm", {});
|
||||
|
|
@ -31,36 +31,36 @@ const reOverlay = /<|&#?\w+;/;
|
|||
* Source: https://www.w3.org/TR/html5/text-level-semantics.html
|
||||
*/
|
||||
const LOCALIZABLE_ELEMENTS = {
|
||||
'http://www.w3.org/1999/xhtml': [
|
||||
'a', 'em', 'strong', 'small', 's', 'cite', 'q', 'dfn', 'abbr', 'data',
|
||||
'time', 'code', 'var', 'samp', 'kbd', 'sub', 'sup', 'i', 'b', 'u',
|
||||
'mark', 'ruby', 'rt', 'rp', 'bdi', 'bdo', 'span', 'br', 'wbr'
|
||||
"http://www.w3.org/1999/xhtml": [
|
||||
"a", "em", "strong", "small", "s", "cite", "q", "dfn", "abbr", "data",
|
||||
"time", "code", "var", "samp", "kbd", "sub", "sup", "i", "b", "u",
|
||||
"mark", "ruby", "rt", "rp", "bdi", "bdo", "span", "br", "wbr"
|
||||
],
|
||||
};
|
||||
|
||||
const LOCALIZABLE_ATTRIBUTES = {
|
||||
'http://www.w3.org/1999/xhtml': {
|
||||
global: ['title', 'aria-label', 'aria-valuetext', 'aria-moz-hint'],
|
||||
a: ['download'],
|
||||
area: ['download', 'alt'],
|
||||
"http://www.w3.org/1999/xhtml": {
|
||||
global: ["title", "aria-label", "aria-valuetext", "aria-moz-hint"],
|
||||
a: ["download"],
|
||||
area: ["download", "alt"],
|
||||
// value is special-cased in isAttrNameLocalizable
|
||||
input: ['alt', 'placeholder'],
|
||||
menuitem: ['label'],
|
||||
menu: ['label'],
|
||||
optgroup: ['label'],
|
||||
option: ['label'],
|
||||
track: ['label'],
|
||||
img: ['alt'],
|
||||
textarea: ['placeholder'],
|
||||
th: ['abbr']
|
||||
input: ["alt", "placeholder"],
|
||||
menuitem: ["label"],
|
||||
menu: ["label"],
|
||||
optgroup: ["label"],
|
||||
option: ["label"],
|
||||
track: ["label"],
|
||||
img: ["alt"],
|
||||
textarea: ["placeholder"],
|
||||
th: ["abbr"]
|
||||
},
|
||||
'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul': {
|
||||
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul": {
|
||||
global: [
|
||||
'accesskey', 'aria-label', 'aria-valuetext', 'aria-moz-hint', 'label'
|
||||
"accesskey", "aria-label", "aria-valuetext", "aria-moz-hint", "label"
|
||||
],
|
||||
key: ['key', 'keycode'],
|
||||
textbox: ['placeholder'],
|
||||
toolbarbutton: ['tooltiptext'],
|
||||
key: ["key", "keycode"],
|
||||
textbox: ["placeholder"],
|
||||
toolbarbutton: ["tooltiptext"],
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ const LOCALIZABLE_ATTRIBUTES = {
|
|||
function overlayElement(targetElement, translation) {
|
||||
const value = translation.value;
|
||||
|
||||
if (typeof value === 'string') {
|
||||
if (typeof value === "string") {
|
||||
if (!reOverlay.test(value)) {
|
||||
// If the translation doesn't contain any markup skip the overlay logic.
|
||||
targetElement.textContent = value;
|
||||
|
|
@ -83,7 +83,8 @@ function overlayElement(targetElement, translation) {
|
|||
// Else parse the translation's HTML using an inert template element,
|
||||
// sanitize it and replace the targetElement's content.
|
||||
const templateElement = targetElement.ownerDocument.createElementNS(
|
||||
'http://www.w3.org/1999/xhtml', 'template');
|
||||
"http://www.w3.org/1999/xhtml", "template");
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
templateElement.innerHTML = value;
|
||||
targetElement.appendChild(
|
||||
// The targetElement will be cleared at the end of sanitization.
|
||||
|
|
@ -92,9 +93,9 @@ function overlayElement(targetElement, translation) {
|
|||
}
|
||||
}
|
||||
|
||||
const explicitlyAllowed = targetElement.hasAttribute('data-l10n-attrs')
|
||||
? targetElement.getAttribute('data-l10n-attrs')
|
||||
.split(',').map(i => i.trim())
|
||||
const explicitlyAllowed = targetElement.hasAttribute("data-l10n-attrs")
|
||||
? targetElement.getAttribute("data-l10n-attrs")
|
||||
.split(",").map(i => i.trim())
|
||||
: null;
|
||||
|
||||
// Remove localizable attributes which may have been set by a previous
|
||||
|
|
@ -182,7 +183,7 @@ function sanitizeUsing(translationFragment, sourceElement) {
|
|||
|
||||
// SourceElement might have been already modified by shiftNamedElement.
|
||||
// Let's clear it to make sure other code doesn't rely on random leftovers.
|
||||
sourceElement.textContent = '';
|
||||
sourceElement.textContent = "";
|
||||
|
||||
return translationFragment;
|
||||
}
|
||||
|
|
@ -274,10 +275,10 @@ function isAttrNameLocalizable(name, element, explicitlyAllowed = null) {
|
|||
}
|
||||
|
||||
// Special case for value on HTML inputs with type button, reset, submit
|
||||
if (element.namespaceURI === 'http://www.w3.org/1999/xhtml' &&
|
||||
elemName === 'input' && attrName === 'value') {
|
||||
if (element.namespaceURI === "http://www.w3.org/1999/xhtml" &&
|
||||
elemName === "input" && attrName === "value") {
|
||||
const type = element.type.toLowerCase();
|
||||
if (type === 'submit' || type === 'button' || type === 'reset') {
|
||||
if (type === "submit" || type === "button" || type === "reset") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -303,8 +304,8 @@ function shiftNamedElement(element, localName) {
|
|||
return null;
|
||||
}
|
||||
|
||||
const L10NID_ATTR_NAME = 'data-l10n-id';
|
||||
const L10NARGS_ATTR_NAME = 'data-l10n-args';
|
||||
const L10NID_ATTR_NAME = "data-l10n-id";
|
||||
const L10NARGS_ATTR_NAME = "data-l10n-args";
|
||||
|
||||
const L10N_ELEMENT_QUERY = `[${L10NID_ATTR_NAME}]`;
|
||||
|
||||
|
|
@ -430,7 +431,7 @@ class DOMLocalization extends Localization {
|
|||
if (root === newRoot ||
|
||||
root.contains(newRoot) ||
|
||||
newRoot.contains(root)) {
|
||||
throw new Error('Cannot add a root that overlaps with existing root.');
|
||||
throw new Error("Cannot add a root that overlaps with existing root.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -500,10 +501,10 @@ class DOMLocalization extends Localization {
|
|||
translateMutations(mutations) {
|
||||
for (const mutation of mutations) {
|
||||
switch (mutation.type) {
|
||||
case 'attributes':
|
||||
case "attributes":
|
||||
this.pendingElements.add(mutation.target);
|
||||
break;
|
||||
case 'childList':
|
||||
case "childList":
|
||||
for (const addedNode of mutation.addedNodes) {
|
||||
if (addedNode.nodeType === addedNode.ELEMENT_NODE) {
|
||||
if (addedNode.childElementCount) {
|
||||
|
|
@ -600,7 +601,7 @@ class DOMLocalization extends Localization {
|
|||
getTranslatables(element) {
|
||||
const nodes = Array.from(element.querySelectorAll(L10N_ELEMENT_QUERY));
|
||||
|
||||
if (typeof element.hasAttribute === 'function' &&
|
||||
if (typeof element.hasAttribute === "function" &&
|
||||
element.hasAttribute(L10NID_ATTR_NAME)) {
|
||||
nodes.push(element);
|
||||
}
|
||||
|
|
@ -625,4 +626,4 @@ class DOMLocalization extends Localization {
|
|||
}
|
||||
|
||||
this.DOMLocalization = DOMLocalization;
|
||||
this.EXPORTED_SYMBOLS = ['DOMLocalization'];
|
||||
this.EXPORTED_SYMBOLS = ["DOMLocalization"];
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
const { AppConstants } = ChromeUtils.import("resource://gre/modules/AppConstants.jsm", {});
|
||||
const { Services } = ChromeUtils.import('resource://gre/modules/Services.jsm', {});
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm", {});
|
||||
const { MessageContext } = ChromeUtils.import("resource://gre/modules/MessageContext.jsm", {});
|
||||
Components.utils.importGlobalProperties(["fetch"]); /* globals fetch */
|
||||
Cu.importGlobalProperties(["fetch"]);
|
||||
|
||||
/**
|
||||
* L10nRegistry is a localization resource management system for Gecko.
|
||||
|
|
@ -89,7 +89,7 @@ const L10nRegistry = {
|
|||
* @param {Array} resourceIds
|
||||
* @returns {AsyncIterator<MessageContext>}
|
||||
*/
|
||||
async * generateContexts(requestedLangs, resourceIds) {
|
||||
async* generateContexts(requestedLangs, resourceIds) {
|
||||
if (this.bootstrap !== null) {
|
||||
await this.bootstrap;
|
||||
}
|
||||
|
|
@ -167,8 +167,8 @@ const L10nRegistry = {
|
|||
* @returns {String}
|
||||
*/
|
||||
function generateContextID(locale, sourcesOrder, resourceIds) {
|
||||
const sources = sourcesOrder.join(',');
|
||||
const ids = resourceIds.join(',');
|
||||
const sources = sourcesOrder.join(",");
|
||||
const ids = resourceIds.join(",");
|
||||
return `${locale}|${sources}|${ids}`;
|
||||
}
|
||||
|
||||
|
|
@ -219,7 +219,7 @@ async function* generateContextsForLocale(locale, sourcesOrder, resourceIds, res
|
|||
}
|
||||
}
|
||||
|
||||
const MSG_CONTEXT_OPTIONS = {
|
||||
const MSG_CONTEXT_OPTIONS = {
|
||||
// Temporarily disable bidi isolation due to Microsoft not supporting FSI/PDI.
|
||||
// See bug 1439018 for details.
|
||||
useIsolating: Services.prefs.getBoolPref("intl.l10n.enable-bidi-marks", false),
|
||||
|
|
@ -242,7 +242,7 @@ const MSG_CONTEXT_OPTIONS = {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a single MessageContext by loading all resources
|
||||
|
|
@ -360,11 +360,9 @@ class FileSource {
|
|||
if (this.cache[fullPath].then) {
|
||||
return this.cache[fullPath];
|
||||
}
|
||||
} else {
|
||||
if (this.indexed) {
|
||||
} else if (this.indexed) {
|
||||
return Promise.reject(`The source has no resources for path "${fullPath}"`);
|
||||
}
|
||||
}
|
||||
return this.cache[fullPath] = L10nRegistry.load(fullPath).then(
|
||||
data => {
|
||||
return this.cache[fullPath] = data;
|
||||
|
|
@ -417,7 +415,7 @@ L10nRegistry.load = function(url) {
|
|||
if (!response.ok) {
|
||||
return Promise.reject(response.statusText);
|
||||
}
|
||||
return response.text()
|
||||
return response.text();
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -425,4 +423,4 @@ this.L10nRegistry = L10nRegistry;
|
|||
this.FileSource = FileSource;
|
||||
this.IndexedFileSource = IndexedFileSource;
|
||||
|
||||
this.EXPORTED_SYMBOLS = ['L10nRegistry', 'FileSource', 'IndexedFileSource'];
|
||||
this.EXPORTED_SYMBOLS = ["L10nRegistry", "FileSource", "IndexedFileSource"];
|
||||
|
|
|
|||
|
|
@ -16,15 +16,14 @@
|
|||
*/
|
||||
|
||||
|
||||
/* fluent@0.6.0 */
|
||||
/* fluent@0.6.3 */
|
||||
|
||||
/* eslint no-console: ["error", { allow: ["warn", "error"] }] */
|
||||
/* global console */
|
||||
|
||||
const { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm", {});
|
||||
const { L10nRegistry } = ChromeUtils.import("resource://gre/modules/L10nRegistry.jsm", {});
|
||||
const LocaleService = Cc["@mozilla.org/intl/localeservice;1"].getService(Ci.mozILocaleService);
|
||||
const ObserverService = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm", {});
|
||||
|
||||
/*
|
||||
* CachedIterable caches the elements yielded by an iterable.
|
||||
|
|
@ -45,7 +44,7 @@ class CachedIterable {
|
|||
} else if (Symbol.iterator in Object(iterable)) {
|
||||
this.iterator = iterable[Symbol.iterator]();
|
||||
} else {
|
||||
throw new TypeError('Argument must implement the iteration protocol.');
|
||||
throw new TypeError("Argument must implement the iteration protocol.");
|
||||
}
|
||||
|
||||
this.seen = [];
|
||||
|
|
@ -104,7 +103,7 @@ class CachedIterable {
|
|||
class L10nError extends Error {
|
||||
constructor(message) {
|
||||
super();
|
||||
this.name = 'L10nError';
|
||||
this.name = "L10nError";
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
|
|
@ -121,7 +120,7 @@ class L10nError extends Error {
|
|||
function defaultGenerateMessages(resourceIds) {
|
||||
const availableLocales = L10nRegistry.getAvailableLocales();
|
||||
|
||||
const appLocales = LocaleService.getAppLocalesAsLangTags();
|
||||
const appLocales = Services.locale.getAppLocalesAsLangTags();
|
||||
return L10nRegistry.generateContexts(appLocales, resourceIds);
|
||||
}
|
||||
|
||||
|
|
@ -162,7 +161,7 @@ class Localization {
|
|||
for await (let ctx of this.ctxs) {
|
||||
// This can operate on synchronous and asynchronous
|
||||
// contexts coming from the iterator.
|
||||
if (typeof ctx.then === 'function') {
|
||||
if (typeof ctx.then === "function") {
|
||||
ctx = await ctx;
|
||||
}
|
||||
const errors = keysFromContext(method, ctx, keys, translations);
|
||||
|
|
@ -254,14 +253,14 @@ class Localization {
|
|||
* Register weak observers on events that will trigger cache invalidation
|
||||
*/
|
||||
registerObservers() {
|
||||
ObserverService.addObserver(this, 'intl:app-locales-changed', true);
|
||||
Services.obs.addObserver(this, 'intl:app-locales-changed', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister observers on events that will trigger cache invalidation
|
||||
*/
|
||||
unregisterObservers() {
|
||||
ObserverService.removeObserver(this, 'intl:app-locales-changed');
|
||||
Services.obs.removeObserver(this, 'intl:app-locales-changed');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -273,7 +272,7 @@ class Localization {
|
|||
*/
|
||||
observe(subject, topic, data) {
|
||||
switch (topic) {
|
||||
case 'intl:app-locales-changed':
|
||||
case "intl:app-locales-changed":
|
||||
this.onLanguageChange();
|
||||
break;
|
||||
default:
|
||||
|
|
@ -435,4 +434,4 @@ function keysFromContext(method, ctx, keys, translations) {
|
|||
}
|
||||
|
||||
this.Localization = Localization;
|
||||
this.EXPORTED_SYMBOLS = ['Localization'];
|
||||
this.EXPORTED_SYMBOLS = ["Localization"];
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
|
||||
|
||||
/* fluent@0.6.0 */
|
||||
/* fluent@0.6.3 */
|
||||
|
||||
/* eslint no-magic-numbers: [0] */
|
||||
|
||||
|
|
@ -86,7 +86,7 @@ class RuntimeParser {
|
|||
// The index here should either be at the beginning of the file
|
||||
// or right after new line.
|
||||
if (this._index !== 0 &&
|
||||
this._source[this._index - 1] !== '\n') {
|
||||
this._source[this._index - 1] !== "\n") {
|
||||
throw this.error(`Expected an entry to start
|
||||
at the beginning of the file or on a new line.`);
|
||||
}
|
||||
|
|
@ -94,14 +94,14 @@ class RuntimeParser {
|
|||
const ch = this._source[this._index];
|
||||
|
||||
// We don't care about comments or sections at runtime
|
||||
if (ch === '/' ||
|
||||
(ch === '#' &&
|
||||
[' ', '#', '\n'].includes(this._source[this._index + 1]))) {
|
||||
if (ch === "/" ||
|
||||
(ch === "#" &&
|
||||
[" ", "#", "\n"].includes(this._source[this._index + 1]))) {
|
||||
this.skipComment();
|
||||
return;
|
||||
}
|
||||
|
||||
if (ch === '[') {
|
||||
if (ch === "[") {
|
||||
this.skipSection();
|
||||
return;
|
||||
}
|
||||
|
|
@ -116,7 +116,7 @@ class RuntimeParser {
|
|||
*/
|
||||
skipSection() {
|
||||
this._index += 1;
|
||||
if (this._source[this._index] !== '[') {
|
||||
if (this._source[this._index] !== "[") {
|
||||
throw this.error('Expected "[[" to open a section');
|
||||
}
|
||||
|
||||
|
|
@ -126,8 +126,8 @@ class RuntimeParser {
|
|||
this.getVariantName();
|
||||
this.skipInlineWS();
|
||||
|
||||
if (this._source[this._index] !== ']' ||
|
||||
this._source[this._index + 1] !== ']') {
|
||||
if (this._source[this._index] !== "]" ||
|
||||
this._source[this._index + 1] !== "]") {
|
||||
throw this.error('Expected "]]" to close a section');
|
||||
}
|
||||
|
||||
|
|
@ -145,7 +145,7 @@ class RuntimeParser {
|
|||
|
||||
this.skipInlineWS();
|
||||
|
||||
if (this._source[this._index] === '=') {
|
||||
if (this._source[this._index] === "=") {
|
||||
this._index++;
|
||||
}
|
||||
|
||||
|
|
@ -153,27 +153,27 @@ class RuntimeParser {
|
|||
|
||||
const val = this.getPattern();
|
||||
|
||||
if (id.startsWith('-') && val === null) {
|
||||
throw this.error('Expected term to have a value');
|
||||
if (id.startsWith("-") && val === null) {
|
||||
throw this.error("Expected term to have a value");
|
||||
}
|
||||
|
||||
let attrs = null;
|
||||
|
||||
if (this._source[this._index] === ' ') {
|
||||
if (this._source[this._index] === " ") {
|
||||
const lineStart = this._index;
|
||||
this.skipInlineWS();
|
||||
|
||||
if (this._source[this._index] === '.') {
|
||||
if (this._source[this._index] === ".") {
|
||||
this._index = lineStart;
|
||||
attrs = this.getAttributes();
|
||||
}
|
||||
}
|
||||
|
||||
if (attrs === null && typeof val === 'string') {
|
||||
if (attrs === null && typeof val === "string") {
|
||||
this.entries[id] = val;
|
||||
} else {
|
||||
if (val === null && attrs === null) {
|
||||
throw this.error('Expected message to have a value or attributes');
|
||||
throw this.error("Expected message to have a value or attributes");
|
||||
}
|
||||
|
||||
this.entries[id] = {};
|
||||
|
|
@ -195,7 +195,7 @@ class RuntimeParser {
|
|||
*/
|
||||
skipWS() {
|
||||
let ch = this._source[this._index];
|
||||
while (ch === ' ' || ch === '\n' || ch === '\t' || ch === '\r') {
|
||||
while (ch === " " || ch === "\n" || ch === "\t" || ch === "\r") {
|
||||
ch = this._source[++this._index];
|
||||
}
|
||||
}
|
||||
|
|
@ -207,7 +207,7 @@ class RuntimeParser {
|
|||
*/
|
||||
skipInlineWS() {
|
||||
let ch = this._source[this._index];
|
||||
while (ch === ' ' || ch === '\t') {
|
||||
while (ch === " " || ch === "\t") {
|
||||
ch = this._source[++this._index];
|
||||
}
|
||||
}
|
||||
|
|
@ -223,7 +223,7 @@ class RuntimeParser {
|
|||
|
||||
this.skipInlineWS();
|
||||
|
||||
if (this._source[this._index] === '\n') {
|
||||
if (this._source[this._index] === "\n") {
|
||||
this._index += 1;
|
||||
} else {
|
||||
this._index = ptr;
|
||||
|
|
@ -271,7 +271,7 @@ class RuntimeParser {
|
|||
* @private
|
||||
*/
|
||||
getVariantName() {
|
||||
let name = '';
|
||||
let name = "";
|
||||
|
||||
const start = this._index;
|
||||
let cc = this._source.charCodeAt(this._index);
|
||||
|
|
@ -281,7 +281,7 @@ class RuntimeParser {
|
|||
cc === 95 || cc === 32) { // _ <space>
|
||||
cc = this._source.charCodeAt(++this._index);
|
||||
} else {
|
||||
throw this.error('Expected a keyword (starting with [a-zA-Z_])');
|
||||
throw this.error("Expected a keyword (starting with [a-zA-Z_])");
|
||||
}
|
||||
|
||||
while ((cc >= 97 && cc <= 122) || // a-z
|
||||
|
|
@ -301,7 +301,7 @@ class RuntimeParser {
|
|||
|
||||
name += this._source.slice(start, this._index);
|
||||
|
||||
return { type: 'varname', name };
|
||||
return { type: "varname", name };
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -320,8 +320,8 @@ class RuntimeParser {
|
|||
break;
|
||||
}
|
||||
|
||||
if (ch === '\n') {
|
||||
throw this.error('Unterminated string expression');
|
||||
if (ch === "\n") {
|
||||
throw this.error("Unterminated string expression");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -343,7 +343,7 @@ class RuntimeParser {
|
|||
// Then, if either the line contains a placeable opening `{` or the
|
||||
// next line starts an indentation, we switch to complex pattern.
|
||||
const start = this._index;
|
||||
let eol = this._source.indexOf('\n', this._index);
|
||||
let eol = this._source.indexOf("\n", this._index);
|
||||
|
||||
if (eol === -1) {
|
||||
eol = this._length;
|
||||
|
|
@ -352,7 +352,7 @@ class RuntimeParser {
|
|||
const firstLineContent = start !== eol ?
|
||||
this._source.slice(start, eol) : null;
|
||||
|
||||
if (firstLineContent && firstLineContent.includes('{')) {
|
||||
if (firstLineContent && firstLineContent.includes("{")) {
|
||||
return this.getComplexPattern();
|
||||
}
|
||||
|
||||
|
|
@ -360,7 +360,7 @@ class RuntimeParser {
|
|||
|
||||
this.skipBlankLines();
|
||||
|
||||
if (this._source[this._index] !== ' ') {
|
||||
if (this._source[this._index] !== " ") {
|
||||
// No indentation means we're done with this message. Callers should check
|
||||
// if the return value here is null. It may be OK for messages, but not OK
|
||||
// for terms, attributes and variants.
|
||||
|
|
@ -371,7 +371,7 @@ class RuntimeParser {
|
|||
|
||||
this.skipInlineWS();
|
||||
|
||||
if (this._source[this._index] === '.') {
|
||||
if (this._source[this._index] === ".") {
|
||||
// The pattern is followed by an attribute. Rewind _index to the first
|
||||
// column of the current line as expected by getAttributes.
|
||||
this._index = lineStart;
|
||||
|
|
@ -398,7 +398,7 @@ class RuntimeParser {
|
|||
*/
|
||||
/* eslint-disable complexity */
|
||||
getComplexPattern() {
|
||||
let buffer = '';
|
||||
let buffer = "";
|
||||
const content = [];
|
||||
let placeables = 0;
|
||||
|
||||
|
|
@ -407,7 +407,7 @@ class RuntimeParser {
|
|||
while (this._index < this._length) {
|
||||
// This block handles multi-line strings combining strings separated
|
||||
// by new line.
|
||||
if (ch === '\n') {
|
||||
if (ch === "\n") {
|
||||
this._index++;
|
||||
|
||||
// We want to capture the start and end pointers
|
||||
|
|
@ -419,15 +419,15 @@ class RuntimeParser {
|
|||
const blankLinesEnd = this._index;
|
||||
|
||||
|
||||
if (this._source[this._index] !== ' ') {
|
||||
if (this._source[this._index] !== " ") {
|
||||
break;
|
||||
}
|
||||
this.skipInlineWS();
|
||||
|
||||
if (this._source[this._index] === '}' ||
|
||||
this._source[this._index] === '[' ||
|
||||
this._source[this._index] === '*' ||
|
||||
this._source[this._index] === '.') {
|
||||
if (this._source[this._index] === "}" ||
|
||||
this._source[this._index] === "[" ||
|
||||
this._source[this._index] === "*" ||
|
||||
this._source[this._index] === ".") {
|
||||
this._index = blankLinesEnd;
|
||||
break;
|
||||
}
|
||||
|
|
@ -435,17 +435,17 @@ class RuntimeParser {
|
|||
buffer += this._source.substring(blankLinesStart, blankLinesEnd);
|
||||
|
||||
if (buffer.length || content.length) {
|
||||
buffer += '\n';
|
||||
buffer += "\n";
|
||||
}
|
||||
ch = this._source[this._index];
|
||||
continue;
|
||||
} else if (ch === '\\') {
|
||||
} else if (ch === "\\") {
|
||||
const ch2 = this._source[this._index + 1];
|
||||
if (ch2 === '"' || ch2 === '{' || ch2 === '\\') {
|
||||
if (ch2 === '"' || ch2 === "{" || ch2 === "\\") {
|
||||
ch = ch2;
|
||||
this._index++;
|
||||
}
|
||||
} else if (ch === '{') {
|
||||
} else if (ch === "{") {
|
||||
// Push the buffer to content array right before placeable
|
||||
if (buffer.length) {
|
||||
content.push(buffer);
|
||||
|
|
@ -454,7 +454,7 @@ class RuntimeParser {
|
|||
throw this.error(
|
||||
`Too many placeables, maximum allowed is ${MAX_PLACEABLES}`);
|
||||
}
|
||||
buffer = '';
|
||||
buffer = "";
|
||||
content.push(this.getPlaceable());
|
||||
|
||||
this._index++;
|
||||
|
|
@ -495,13 +495,13 @@ class RuntimeParser {
|
|||
|
||||
this.skipWS();
|
||||
|
||||
if (this._source[this._index] === '*' ||
|
||||
(this._source[this._index] === '[' &&
|
||||
this._source[this._index + 1] !== ']')) {
|
||||
if (this._source[this._index] === "*" ||
|
||||
(this._source[this._index] === "[" &&
|
||||
this._source[this._index + 1] !== "]")) {
|
||||
const variants = this.getVariants();
|
||||
|
||||
return {
|
||||
type: 'sel',
|
||||
type: "sel",
|
||||
exp: null,
|
||||
vars: variants[0],
|
||||
def: variants[1]
|
||||
|
|
@ -518,31 +518,31 @@ class RuntimeParser {
|
|||
|
||||
const ch = this._source[this._index];
|
||||
|
||||
if (ch === '}') {
|
||||
if (selector.type === 'attr' && selector.id.name.startsWith('-')) {
|
||||
if (ch === "}") {
|
||||
if (selector.type === "attr" && selector.id.name.startsWith("-")) {
|
||||
throw this.error(
|
||||
'Attributes of private messages cannot be interpolated.'
|
||||
"Attributes of private messages cannot be interpolated."
|
||||
);
|
||||
}
|
||||
|
||||
return selector;
|
||||
}
|
||||
|
||||
if (ch !== '-' || this._source[this._index + 1] !== '>') {
|
||||
if (ch !== "-" || this._source[this._index + 1] !== ">") {
|
||||
throw this.error('Expected "}" or "->"');
|
||||
}
|
||||
|
||||
if (selector.type === 'ref') {
|
||||
throw this.error('Message references cannot be used as selectors.');
|
||||
if (selector.type === "ref") {
|
||||
throw this.error("Message references cannot be used as selectors.");
|
||||
}
|
||||
|
||||
if (selector.type === 'var') {
|
||||
throw this.error('Variants cannot be used as selectors.');
|
||||
if (selector.type === "var") {
|
||||
throw this.error("Variants cannot be used as selectors.");
|
||||
}
|
||||
|
||||
if (selector.type === 'attr' && !selector.id.name.startsWith('-')) {
|
||||
if (selector.type === "attr" && !selector.id.name.startsWith("-")) {
|
||||
throw this.error(
|
||||
'Attributes of public messages cannot be used as selectors.'
|
||||
"Attributes of public messages cannot be used as selectors."
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -551,8 +551,8 @@ class RuntimeParser {
|
|||
|
||||
this.skipInlineWS();
|
||||
|
||||
if (this._source[this._index] !== '\n') {
|
||||
throw this.error('Variants should be listed in a new line');
|
||||
if (this._source[this._index] !== "\n") {
|
||||
throw this.error("Variants should be listed in a new line");
|
||||
}
|
||||
|
||||
this.skipWS();
|
||||
|
|
@ -560,11 +560,11 @@ class RuntimeParser {
|
|||
const variants = this.getVariants();
|
||||
|
||||
if (variants[0].length === 0) {
|
||||
throw this.error('Expected members for the select expression');
|
||||
throw this.error("Expected members for the select expression");
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'sel',
|
||||
type: "sel",
|
||||
exp: selector,
|
||||
vars: variants[0],
|
||||
def: variants[1]
|
||||
|
|
@ -580,48 +580,48 @@ class RuntimeParser {
|
|||
getSelectorExpression() {
|
||||
const literal = this.getLiteral();
|
||||
|
||||
if (literal.type !== 'ref') {
|
||||
if (literal.type !== "ref") {
|
||||
return literal;
|
||||
}
|
||||
|
||||
if (this._source[this._index] === '.') {
|
||||
if (this._source[this._index] === ".") {
|
||||
this._index++;
|
||||
|
||||
const name = this.getIdentifier();
|
||||
this._index++;
|
||||
return {
|
||||
type: 'attr',
|
||||
type: "attr",
|
||||
id: literal,
|
||||
name
|
||||
};
|
||||
}
|
||||
|
||||
if (this._source[this._index] === '[') {
|
||||
if (this._source[this._index] === "[") {
|
||||
this._index++;
|
||||
|
||||
const key = this.getVariantKey();
|
||||
this._index++;
|
||||
return {
|
||||
type: 'var',
|
||||
type: "var",
|
||||
id: literal,
|
||||
key
|
||||
};
|
||||
}
|
||||
|
||||
if (this._source[this._index] === '(') {
|
||||
if (this._source[this._index] === "(") {
|
||||
this._index++;
|
||||
const args = this.getCallArgs();
|
||||
|
||||
if (!functionIdentifierRe.test(literal.name)) {
|
||||
throw this.error('Function names must be all upper-case');
|
||||
throw this.error("Function names must be all upper-case");
|
||||
}
|
||||
|
||||
this._index++;
|
||||
|
||||
literal.type = 'fun';
|
||||
literal.type = "fun";
|
||||
|
||||
return {
|
||||
type: 'call',
|
||||
type: "call",
|
||||
fun: literal,
|
||||
args
|
||||
};
|
||||
|
|
@ -642,7 +642,7 @@ class RuntimeParser {
|
|||
while (this._index < this._length) {
|
||||
this.skipInlineWS();
|
||||
|
||||
if (this._source[this._index] === ')') {
|
||||
if (this._source[this._index] === ")") {
|
||||
return args;
|
||||
}
|
||||
|
||||
|
|
@ -650,12 +650,12 @@ class RuntimeParser {
|
|||
|
||||
// MessageReference in this place may be an entity reference, like:
|
||||
// `call(foo)`, or, if it's followed by `:` it will be a key-value pair.
|
||||
if (exp.type !== 'ref') {
|
||||
if (exp.type !== "ref") {
|
||||
args.push(exp);
|
||||
} else {
|
||||
this.skipInlineWS();
|
||||
|
||||
if (this._source[this._index] === ':') {
|
||||
if (this._source[this._index] === ":") {
|
||||
this._index++;
|
||||
this.skipInlineWS();
|
||||
|
||||
|
|
@ -666,18 +666,18 @@ class RuntimeParser {
|
|||
//
|
||||
// We don't have to check here if the pattern is quote delimited
|
||||
// because that's the only type of string allowed in expressions.
|
||||
if (typeof val === 'string' ||
|
||||
if (typeof val === "string" ||
|
||||
Array.isArray(val) ||
|
||||
val.type === 'num') {
|
||||
val.type === "num") {
|
||||
args.push({
|
||||
type: 'narg',
|
||||
type: "narg",
|
||||
name: exp.name,
|
||||
val
|
||||
});
|
||||
} else {
|
||||
this._index = this._source.lastIndexOf(':', this._index) + 1;
|
||||
this._index = this._source.lastIndexOf(":", this._index) + 1;
|
||||
throw this.error(
|
||||
'Expected string in quotes, number.');
|
||||
"Expected string in quotes, number.");
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
@ -687,9 +687,9 @@ class RuntimeParser {
|
|||
|
||||
this.skipInlineWS();
|
||||
|
||||
if (this._source[this._index] === ')') {
|
||||
if (this._source[this._index] === ")") {
|
||||
break;
|
||||
} else if (this._source[this._index] === ',') {
|
||||
} else if (this._source[this._index] === ",") {
|
||||
this._index++;
|
||||
} else {
|
||||
throw this.error('Expected "," or ")"');
|
||||
|
|
@ -706,12 +706,12 @@ class RuntimeParser {
|
|||
* @private
|
||||
*/
|
||||
getNumber() {
|
||||
let num = '';
|
||||
let num = "";
|
||||
let cc = this._source.charCodeAt(this._index);
|
||||
|
||||
// The number literal may start with negative sign `-`.
|
||||
if (cc === 45) {
|
||||
num += '-';
|
||||
num += "-";
|
||||
cc = this._source.charCodeAt(++this._index);
|
||||
}
|
||||
|
||||
|
|
@ -744,7 +744,7 @@ class RuntimeParser {
|
|||
}
|
||||
|
||||
return {
|
||||
type: 'num',
|
||||
type: "num",
|
||||
val: num
|
||||
};
|
||||
}
|
||||
|
|
@ -759,12 +759,12 @@ class RuntimeParser {
|
|||
const attrs = {};
|
||||
|
||||
while (this._index < this._length) {
|
||||
if (this._source[this._index] !== ' ') {
|
||||
if (this._source[this._index] !== " ") {
|
||||
break;
|
||||
}
|
||||
this.skipInlineWS();
|
||||
|
||||
if (this._source[this._index] !== '.') {
|
||||
if (this._source[this._index] !== ".") {
|
||||
break;
|
||||
}
|
||||
this._index++;
|
||||
|
|
@ -773,7 +773,7 @@ class RuntimeParser {
|
|||
|
||||
this.skipInlineWS();
|
||||
|
||||
if (this._source[this._index] !== '=') {
|
||||
if (this._source[this._index] !== "=") {
|
||||
throw this.error('Expected "="');
|
||||
}
|
||||
this._index++;
|
||||
|
|
@ -783,10 +783,10 @@ class RuntimeParser {
|
|||
const val = this.getPattern();
|
||||
|
||||
if (val === null) {
|
||||
throw this.error('Expected attribute to have a value');
|
||||
throw this.error("Expected attribute to have a value");
|
||||
}
|
||||
|
||||
if (typeof val === 'string') {
|
||||
if (typeof val === "string") {
|
||||
attrs[key] = val;
|
||||
} else {
|
||||
attrs[key] = {
|
||||
|
|
@ -814,16 +814,16 @@ class RuntimeParser {
|
|||
while (this._index < this._length) {
|
||||
const ch = this._source[this._index];
|
||||
|
||||
if ((ch !== '[' || this._source[this._index + 1] === '[') &&
|
||||
ch !== '*') {
|
||||
if ((ch !== "[" || this._source[this._index + 1] === "[") &&
|
||||
ch !== "*") {
|
||||
break;
|
||||
}
|
||||
if (ch === '*') {
|
||||
if (ch === "*") {
|
||||
this._index++;
|
||||
defaultIndex = index;
|
||||
}
|
||||
|
||||
if (this._source[this._index] !== '[') {
|
||||
if (this._source[this._index] !== "[") {
|
||||
throw this.error('Expected "["');
|
||||
}
|
||||
|
||||
|
|
@ -836,7 +836,7 @@ class RuntimeParser {
|
|||
const val = this.getPattern();
|
||||
|
||||
if (val === null) {
|
||||
throw this.error('Expected variant to have a value');
|
||||
throw this.error("Expected variant to have a value");
|
||||
}
|
||||
|
||||
variants[index++] = {key, val};
|
||||
|
|
@ -865,7 +865,7 @@ class RuntimeParser {
|
|||
literal = this.getVariantName();
|
||||
}
|
||||
|
||||
if (this._source[this._index] !== ']') {
|
||||
if (this._source[this._index] !== "]") {
|
||||
throw this.error('Expected "]"');
|
||||
}
|
||||
|
||||
|
|
@ -885,7 +885,7 @@ class RuntimeParser {
|
|||
if (cc0 === 36) { // $
|
||||
this._index++;
|
||||
return {
|
||||
type: 'ext',
|
||||
type: "ext",
|
||||
name: this.getIdentifier()
|
||||
};
|
||||
}
|
||||
|
|
@ -899,7 +899,7 @@ class RuntimeParser {
|
|||
if ((cc1 >= 97 && cc1 <= 122) || // a-z
|
||||
(cc1 >= 65 && cc1 <= 90)) { // A-Z
|
||||
return {
|
||||
type: 'ref',
|
||||
type: "ref",
|
||||
name: this.getEntryIdentifier()
|
||||
};
|
||||
}
|
||||
|
|
@ -912,7 +912,7 @@ class RuntimeParser {
|
|||
return this.getString();
|
||||
}
|
||||
|
||||
throw this.error('Expected literal');
|
||||
throw this.error("Expected literal");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -923,15 +923,15 @@ class RuntimeParser {
|
|||
skipComment() {
|
||||
// At runtime, we don't care about comments so we just have
|
||||
// to parse them properly and skip their content.
|
||||
let eol = this._source.indexOf('\n', this._index);
|
||||
let eol = this._source.indexOf("\n", this._index);
|
||||
|
||||
while (eol !== -1 &&
|
||||
((this._source[eol + 1] === '/' && this._source[eol + 2] === '/') ||
|
||||
(this._source[eol + 1] === '#' &&
|
||||
[' ', '#'].includes(this._source[eol + 2])))) {
|
||||
((this._source[eol + 1] === "/" && this._source[eol + 2] === "/") ||
|
||||
(this._source[eol + 1] === "#" &&
|
||||
[" ", "#"].includes(this._source[eol + 2])))) {
|
||||
this._index = eol + 3;
|
||||
|
||||
eol = this._source.indexOf('\n', this._index);
|
||||
eol = this._source.indexOf("\n", this._index);
|
||||
|
||||
if (eol === -1) {
|
||||
break;
|
||||
|
|
@ -967,7 +967,7 @@ class RuntimeParser {
|
|||
let start = this._index;
|
||||
|
||||
while (true) {
|
||||
if (start === 0 || this._source[start - 1] === '\n') {
|
||||
if (start === 0 || this._source[start - 1] === "\n") {
|
||||
const cc = this._source.charCodeAt(start);
|
||||
|
||||
if ((cc >= 97 && cc <= 122) || // a-z
|
||||
|
|
@ -978,7 +978,7 @@ class RuntimeParser {
|
|||
}
|
||||
}
|
||||
|
||||
start = this._source.indexOf('\n', start);
|
||||
start = this._source.indexOf("\n", start);
|
||||
|
||||
if (start === -1) {
|
||||
this._index = this._length;
|
||||
|
|
@ -1044,13 +1044,13 @@ class FluentType {
|
|||
* @returns {string}
|
||||
*/
|
||||
toString() {
|
||||
throw new Error('Subclasses of FluentType must implement toString.');
|
||||
throw new Error("Subclasses of FluentType must implement toString.");
|
||||
}
|
||||
}
|
||||
|
||||
class FluentNone extends FluentType {
|
||||
toString() {
|
||||
return this.value || '???';
|
||||
return this.value || "???";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1119,7 +1119,7 @@ class FluentSymbol extends FluentType {
|
|||
match(ctx, other) {
|
||||
if (other instanceof FluentSymbol) {
|
||||
return this.value === other.value;
|
||||
} else if (typeof other === 'string') {
|
||||
} else if (typeof other === "string") {
|
||||
return this.value === other;
|
||||
} else if (other instanceof FluentNumber) {
|
||||
const pr = ctx._memoizeIntlObject(
|
||||
|
|
@ -1145,9 +1145,9 @@ class FluentSymbol extends FluentType {
|
|||
*/
|
||||
|
||||
const builtins = {
|
||||
'NUMBER': ([arg], opts) =>
|
||||
"NUMBER": ([arg], opts) =>
|
||||
new FluentNumber(arg.valueOf(), merge(arg.opts, opts)),
|
||||
'DATETIME': ([arg], opts) =>
|
||||
"DATETIME": ([arg], opts) =>
|
||||
new FluentDateTime(arg.valueOf(), merge(arg.opts, opts)),
|
||||
};
|
||||
|
||||
|
|
@ -1211,13 +1211,12 @@ function values(opts) {
|
|||
* This is used to prevent cyclic resolutions.
|
||||
*/
|
||||
|
||||
|
||||
// Prevent expansion of too long placeables.
|
||||
const MAX_PLACEABLE_LENGTH = 2500;
|
||||
|
||||
// Unicode bidi isolation characters.
|
||||
const FSI = '\u2068';
|
||||
const PDI = '\u2069';
|
||||
const FSI = "\u2068";
|
||||
const PDI = "\u2069";
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -1240,7 +1239,7 @@ function DefaultMember(env, members, def) {
|
|||
}
|
||||
|
||||
const { errors } = env;
|
||||
errors.push(new RangeError('No default'));
|
||||
errors.push(new RangeError("No default"));
|
||||
return new FluentNone();
|
||||
}
|
||||
|
||||
|
|
@ -1259,12 +1258,12 @@ function DefaultMember(env, members, def) {
|
|||
*/
|
||||
function MessageReference(env, {name}) {
|
||||
const { ctx, errors } = env;
|
||||
const message = name.startsWith('-')
|
||||
const message = name.startsWith("-")
|
||||
? ctx._terms.get(name)
|
||||
: ctx._messages.get(name);
|
||||
|
||||
if (!message) {
|
||||
const err = name.startsWith('-')
|
||||
const err = name.startsWith("-")
|
||||
? new ReferenceError(`Unknown term: ${name}`)
|
||||
: new ReferenceError(`Unknown message: ${name}`);
|
||||
errors.push(err);
|
||||
|
|
@ -1301,7 +1300,7 @@ function VariantExpression(env, {id, key}) {
|
|||
|
||||
function isVariantList(node) {
|
||||
return Array.isArray(node) &&
|
||||
node[0].type === 'sel' &&
|
||||
node[0].type === "sel" &&
|
||||
node[0].exp === null;
|
||||
}
|
||||
|
||||
|
|
@ -1418,7 +1417,7 @@ function SelectExpression(env, {exp, vars, def}) {
|
|||
function Type(env, expr) {
|
||||
// A fast-path for strings which are the most common case, and for
|
||||
// `FluentNone` which doesn't require any additional logic.
|
||||
if (typeof expr === 'string' || expr instanceof FluentNone) {
|
||||
if (typeof expr === "string" || expr instanceof FluentNone) {
|
||||
return expr;
|
||||
}
|
||||
|
||||
|
|
@ -1430,29 +1429,29 @@ function Type(env, expr) {
|
|||
|
||||
|
||||
switch (expr.type) {
|
||||
case 'varname':
|
||||
case "varname":
|
||||
return new FluentSymbol(expr.name);
|
||||
case 'num':
|
||||
case "num":
|
||||
return new FluentNumber(expr.val);
|
||||
case 'ext':
|
||||
case "ext":
|
||||
return ExternalArgument(env, expr);
|
||||
case 'fun':
|
||||
case "fun":
|
||||
return FunctionReference(env, expr);
|
||||
case 'call':
|
||||
case "call":
|
||||
return CallExpression(env, expr);
|
||||
case 'ref': {
|
||||
case "ref": {
|
||||
const message = MessageReference(env, expr);
|
||||
return Type(env, message);
|
||||
}
|
||||
case 'attr': {
|
||||
case "attr": {
|
||||
const attr = AttributeExpression(env, expr);
|
||||
return Type(env, attr);
|
||||
}
|
||||
case 'var': {
|
||||
case "var": {
|
||||
const variant = VariantExpression(env, expr);
|
||||
return Type(env, variant);
|
||||
}
|
||||
case 'sel': {
|
||||
case "sel": {
|
||||
const member = SelectExpression(env, expr);
|
||||
return Type(env, member);
|
||||
}
|
||||
|
|
@ -1463,7 +1462,7 @@ function Type(env, expr) {
|
|||
}
|
||||
|
||||
const { errors } = env;
|
||||
errors.push(new RangeError('No value'));
|
||||
errors.push(new RangeError("No value"));
|
||||
return new FluentNone();
|
||||
}
|
||||
default:
|
||||
|
|
@ -1500,11 +1499,11 @@ function ExternalArgument(env, {name}) {
|
|||
|
||||
// Convert the argument to a Fluent type.
|
||||
switch (typeof arg) {
|
||||
case 'string':
|
||||
case "string":
|
||||
return arg;
|
||||
case 'number':
|
||||
case "number":
|
||||
return new FluentNumber(arg);
|
||||
case 'object':
|
||||
case "object":
|
||||
if (arg instanceof Date) {
|
||||
return new FluentDateTime(arg);
|
||||
}
|
||||
|
|
@ -1539,7 +1538,7 @@ function FunctionReference(env, {name}) {
|
|||
return new FluentNone(`${name}()`);
|
||||
}
|
||||
|
||||
if (typeof func !== 'function') {
|
||||
if (typeof func !== "function") {
|
||||
errors.push(new TypeError(`Function ${name}() is not callable`));
|
||||
return new FluentNone(`${name}()`);
|
||||
}
|
||||
|
|
@ -1572,7 +1571,7 @@ function CallExpression(env, {fun, args}) {
|
|||
const keyargs = {};
|
||||
|
||||
for (const arg of args) {
|
||||
if (arg.type === 'narg') {
|
||||
if (arg.type === "narg") {
|
||||
keyargs[arg.name] = Type(env, arg.val);
|
||||
} else {
|
||||
posargs.push(Type(env, arg));
|
||||
|
|
@ -1601,7 +1600,7 @@ function Pattern(env, ptn) {
|
|||
const { ctx, dirty, errors } = env;
|
||||
|
||||
if (dirty.has(ptn)) {
|
||||
errors.push(new RangeError('Cyclic reference'));
|
||||
errors.push(new RangeError("Cyclic reference"));
|
||||
return new FluentNone();
|
||||
}
|
||||
|
||||
|
|
@ -1610,7 +1609,7 @@ function Pattern(env, ptn) {
|
|||
const result = [];
|
||||
|
||||
for (const elem of ptn) {
|
||||
if (typeof elem === 'string') {
|
||||
if (typeof elem === "string") {
|
||||
result.push(elem);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -1624,7 +1623,7 @@ function Pattern(env, ptn) {
|
|||
if (part.length > MAX_PLACEABLE_LENGTH) {
|
||||
errors.push(
|
||||
new RangeError(
|
||||
'Too many characters in placeable ' +
|
||||
"Too many characters in placeable " +
|
||||
`(${part.length}, max allowed is ${MAX_PLACEABLE_LENGTH})`
|
||||
)
|
||||
);
|
||||
|
|
@ -1639,7 +1638,7 @@ function Pattern(env, ptn) {
|
|||
}
|
||||
|
||||
dirty.delete(ptn);
|
||||
return result.join('');
|
||||
return result.join("");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1773,7 +1772,7 @@ class MessageContext {
|
|||
addMessages(source) {
|
||||
const [entries, errors] = parse(source);
|
||||
for (const id in entries) {
|
||||
if (id.startsWith('-')) {
|
||||
if (id.startsWith("-")) {
|
||||
// Identifiers starting with a dash (-) define terms. Terms are private
|
||||
// and cannot be retrieved from MessageContext.
|
||||
this._terms.set(id, entries[id]);
|
||||
|
|
@ -1817,12 +1816,12 @@ class MessageContext {
|
|||
*/
|
||||
format(message, args, errors) {
|
||||
// optimize entities which are simple strings with no attributes
|
||||
if (typeof message === 'string') {
|
||||
if (typeof message === "string") {
|
||||
return message;
|
||||
}
|
||||
|
||||
// optimize simple-string entities with attributes
|
||||
if (typeof message.val === 'string') {
|
||||
if (typeof message.val === "string") {
|
||||
return message.val;
|
||||
}
|
||||
|
||||
|
|
@ -1848,4 +1847,4 @@ class MessageContext {
|
|||
}
|
||||
|
||||
this.MessageContext = MessageContext;
|
||||
this.EXPORTED_SYMBOLS = ['MessageContext'];
|
||||
this.EXPORTED_SYMBOLS = ["MessageContext"];
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
const { DOMLocalization } =
|
||||
ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm", {});
|
||||
|
||||
/**
|
||||
* Polyfill for document.ready polyfill.
|
||||
|
|
@ -14,11 +14,11 @@
|
|||
* @returns {Promise}
|
||||
*/
|
||||
function documentReady(callback) {
|
||||
if (document.contentType === 'application/vnd.mozilla.xul+xml') {
|
||||
if (document.contentType === "application/vnd.mozilla.xul+xml") {
|
||||
// XUL
|
||||
return new Promise(
|
||||
resolve => document.addEventListener(
|
||||
'MozBeforeInitialXULLayout', () => {
|
||||
"MozBeforeInitialXULLayout", () => {
|
||||
resolve(callback());
|
||||
}, { once: true }
|
||||
)
|
||||
|
|
@ -27,12 +27,12 @@
|
|||
|
||||
// HTML
|
||||
const rs = document.readyState;
|
||||
if (rs === 'interactive' || rs === 'completed') {
|
||||
return Promise.resolve(callback());
|
||||
if (rs === "interactive" || rs === "completed") {
|
||||
return Promise.resolve(callback);
|
||||
}
|
||||
return new Promise(
|
||||
resolve => document.addEventListener(
|
||||
'readystatechange', () => {
|
||||
"readystatechange", () => {
|
||||
resolve(callback());
|
||||
}, { once: true }
|
||||
)
|
||||
|
|
@ -47,7 +47,7 @@
|
|||
*/
|
||||
function getResourceLinks(elem) {
|
||||
return Array.from(elem.querySelectorAll('link[rel="localization"]')).map(
|
||||
el => el.getAttribute('href')
|
||||
el => el.getAttribute("href")
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -60,7 +60,7 @@
|
|||
|
||||
document.l10n.ready = documentReady(() => {
|
||||
document.l10n.registerObservers();
|
||||
window.addEventListener('unload', () => {
|
||||
window.addEventListener("unload", () => {
|
||||
document.l10n.unregisterObservers();
|
||||
});
|
||||
document.l10n.connectRoot(document.documentElement);
|
||||
|
|
|
|||
8
intl/l10n/test/.eslintrc.js
Normal file
8
intl/l10n/test/.eslintrc.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"plugin:mozilla/xpcshell-test",
|
||||
"plugin:mozilla/browser-test"
|
||||
]
|
||||
};
|
||||
|
|
@ -10,10 +10,10 @@
|
|||
const { DOMLocalization } =
|
||||
ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm", {});
|
||||
|
||||
async function * mockGenerateMessages(locales, resourceIds) {
|
||||
async function* mockGenerateMessages(locales, resourceIds) {
|
||||
}
|
||||
|
||||
window.onload = async function () {
|
||||
window.onload = async function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const domLoc = new DOMLocalization(
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
);
|
||||
|
||||
|
||||
const frag = document.querySelectorAll('div')[0];
|
||||
const frag = document.querySelectorAll("div")[0];
|
||||
domLoc.connectRoot(frag);
|
||||
|
||||
is(domLoc.roots.has(frag), true);
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@
|
|||
const { DOMLocalization } =
|
||||
ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm", {});
|
||||
|
||||
async function * mockGenerateMessages(locales, resourceIds) {
|
||||
async function* mockGenerateMessages(locales, resourceIds) {
|
||||
}
|
||||
|
||||
window.onload = async function () {
|
||||
window.onload = async function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const domLoc = new DOMLocalization(
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
mockGenerateMessages
|
||||
);
|
||||
|
||||
const frag = document.querySelectorAll('div')[0];
|
||||
const frag = document.querySelectorAll("div")[0];
|
||||
|
||||
domLoc.connectRoot(frag);
|
||||
is(domLoc.roots.has(frag), true);
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@
|
|||
const { DOMLocalization } =
|
||||
ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm", {});
|
||||
|
||||
async function * mockGenerateMessages(locales, resourceIds) {}
|
||||
async function* mockGenerateMessages(locales, resourceIds) {}
|
||||
|
||||
window.onload = function () {
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const domLoc = new DOMLocalization(
|
||||
|
|
@ -21,9 +21,9 @@
|
|||
mockGenerateMessages
|
||||
);
|
||||
|
||||
const p1 = document.querySelectorAll('p')[0];
|
||||
const p2 = document.querySelectorAll('p')[1];
|
||||
const p3 = document.querySelectorAll('p')[2];
|
||||
const p1 = document.querySelectorAll("p")[0];
|
||||
const p2 = document.querySelectorAll("p")[1];
|
||||
const p3 = document.querySelectorAll("p")[2];
|
||||
const attrs1 = domLoc.getAttributes(p1);
|
||||
const attrs2 = domLoc.getAttributes(p2);
|
||||
const attrs3 = domLoc.getAttributes(p3);
|
||||
|
|
|
|||
|
|
@ -12,14 +12,14 @@
|
|||
const { MessageContext } =
|
||||
ChromeUtils.import("resource://gre/modules/MessageContext.jsm", {});
|
||||
|
||||
async function * mockGenerateMessages(locales, resourceIds) {
|
||||
async function* mockGenerateMessages(locales, resourceIds) {
|
||||
const mc = new MessageContext(locales);
|
||||
mc.addMessages('title = Hello World');
|
||||
mc.addMessages('title2 = Hello Another World');
|
||||
mc.addMessages("title = Hello World");
|
||||
mc.addMessages("title2 = Hello Another World");
|
||||
yield mc;
|
||||
}
|
||||
|
||||
window.onload = async function () {
|
||||
window.onload = async function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const domLoc = new DOMLocalization(
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
mockGenerateMessages
|
||||
);
|
||||
|
||||
const h1 = document.querySelectorAll('h1')[0];
|
||||
const h1 = document.querySelectorAll("h1")[0];
|
||||
|
||||
domLoc.connectRoot(document.body);
|
||||
|
||||
|
|
@ -45,7 +45,7 @@
|
|||
|
||||
mo.observe(h1, { childList: true, characterData: true });
|
||||
|
||||
domLoc.setAttributes(h1, 'title2');
|
||||
domLoc.setAttributes(h1, "title2");
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
|
|
|
|||
|
|
@ -12,14 +12,14 @@
|
|||
const { MessageContext } =
|
||||
ChromeUtils.import("resource://gre/modules/MessageContext.jsm", {});
|
||||
|
||||
async function * mockGenerateMessages(locales, resourceIds) {
|
||||
async function* mockGenerateMessages(locales, resourceIds) {
|
||||
const mc = new MessageContext(locales);
|
||||
mc.addMessages('title = <strong>Hello</strong> World');
|
||||
mc.addMessages('title2 = This is <a>a link</a>!');
|
||||
mc.addMessages("title = <strong>Hello</strong> World");
|
||||
mc.addMessages("title2 = This is <a>a link</a>!");
|
||||
yield mc;
|
||||
}
|
||||
|
||||
window.onload = async function () {
|
||||
window.onload = async function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const domLoc = new DOMLocalization(
|
||||
|
|
@ -28,20 +28,20 @@
|
|||
mockGenerateMessages
|
||||
);
|
||||
|
||||
const p1 = document.querySelectorAll('p')[0];
|
||||
const p2 = document.querySelectorAll('p')[1];
|
||||
const a = p2.querySelector('a');
|
||||
a.addEventListener('click', function() {
|
||||
const p1 = document.querySelectorAll("p")[0];
|
||||
const p2 = document.querySelectorAll("p")[1];
|
||||
const a = p2.querySelector("a");
|
||||
a.addEventListener("click", function() {
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
await domLoc.translateFragment(document.body);
|
||||
|
||||
|
||||
is(p1.querySelector('strong').textContent, "Hello");
|
||||
is(p1.querySelector("strong").textContent, "Hello");
|
||||
|
||||
is(p2.querySelector('a').getAttribute('href'), "http://www.mozilla.org");
|
||||
is(p2.querySelector('a').textContent, "a link");
|
||||
is(p2.querySelector("a").getAttribute("href"), "http://www.mozilla.org");
|
||||
is(p2.querySelector("a").textContent, "a link");
|
||||
|
||||
a.click();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,13 +12,13 @@
|
|||
const { MessageContext } =
|
||||
ChromeUtils.import("resource://gre/modules/MessageContext.jsm", {});
|
||||
|
||||
async function * mockGenerateMessages(locales, resourceIds) {
|
||||
async function* mockGenerateMessages(locales, resourceIds) {
|
||||
const mc = new MessageContext(locales);
|
||||
mc.addMessages('title = Visit <a>Mozilla</a> or <a>Firefox</a> website!');
|
||||
mc.addMessages("title = Visit <a>Mozilla</a> or <a>Firefox</a> website!");
|
||||
yield mc;
|
||||
}
|
||||
|
||||
window.onload = async function () {
|
||||
window.onload = async function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const domLoc = new DOMLocalization(
|
||||
|
|
@ -29,14 +29,14 @@
|
|||
|
||||
await domLoc.translateFragment(document.body);
|
||||
|
||||
const p1 = document.querySelectorAll('p')[0];
|
||||
const linkList = p1.querySelectorAll('a');
|
||||
const p1 = document.querySelectorAll("p")[0];
|
||||
const linkList = p1.querySelectorAll("a");
|
||||
|
||||
|
||||
is(linkList[0].getAttribute('href'), 'http://www.mozilla.org');
|
||||
is(linkList[0].textContent, 'Mozilla');
|
||||
is(linkList[1].getAttribute('href'), 'http://www.firefox.com');
|
||||
is(linkList[1].textContent, 'Firefox');
|
||||
is(linkList[0].getAttribute("href"), "http://www.mozilla.org");
|
||||
is(linkList[0].textContent, "Mozilla");
|
||||
is(linkList[1].getAttribute("href"), "http://www.firefox.com");
|
||||
is(linkList[1].textContent, "Firefox");
|
||||
|
||||
is(linkList.length, 2, "There should be exactly two links in the result.");
|
||||
|
||||
|
|
|
|||
|
|
@ -12,13 +12,13 @@
|
|||
const { MessageContext } =
|
||||
ChromeUtils.import("resource://gre/modules/MessageContext.jsm", {});
|
||||
|
||||
async function * mockGenerateMessages(locales, resourceIds) {
|
||||
async function* mockGenerateMessages(locales, resourceIds) {
|
||||
const mc = new MessageContext(locales);
|
||||
mc.addMessages('title = Visit <a>Mozilla</a> or <a>Firefox</a> website!');
|
||||
mc.addMessages("title = Visit <a>Mozilla</a> or <a>Firefox</a> website!");
|
||||
yield mc;
|
||||
}
|
||||
|
||||
window.onload = async function () {
|
||||
window.onload = async function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const domLoc = new DOMLocalization(
|
||||
|
|
@ -29,14 +29,14 @@
|
|||
|
||||
await domLoc.translateFragment(document.body);
|
||||
|
||||
const p1 = document.querySelectorAll('p')[0];
|
||||
const linkList = p1.querySelectorAll('a');
|
||||
const p1 = document.querySelectorAll("p")[0];
|
||||
const linkList = p1.querySelectorAll("a");
|
||||
|
||||
|
||||
is(linkList[0].getAttribute('href'), 'http://www.mozilla.org');
|
||||
is(linkList[0].textContent, 'Mozilla');
|
||||
is(linkList[1].getAttribute('href'), 'http://www.firefox.com');
|
||||
is(linkList[1].textContent, 'Firefox');
|
||||
is(linkList[0].getAttribute("href"), "http://www.mozilla.org");
|
||||
is(linkList[0].textContent, "Mozilla");
|
||||
is(linkList[1].getAttribute("href"), "http://www.firefox.com");
|
||||
is(linkList[1].textContent, "Firefox");
|
||||
|
||||
SimpleTest.finish();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@
|
|||
const { DOMLocalization } =
|
||||
ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm", {});
|
||||
|
||||
async function * mockGenerateMessages(locales, resourceIds) {}
|
||||
async function* mockGenerateMessages(locales, resourceIds) {}
|
||||
|
||||
window.onload = function () {
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const domLoc = new DOMLocalization(
|
||||
|
|
@ -21,14 +21,14 @@
|
|||
mockGenerateMessages
|
||||
);
|
||||
|
||||
const p1 = document.querySelectorAll('p')[0];
|
||||
const p1 = document.querySelectorAll("p")[0];
|
||||
|
||||
domLoc.setAttributes(p1, 'title');
|
||||
is(p1.getAttribute('data-l10n-id'), 'title');
|
||||
domLoc.setAttributes(p1, "title");
|
||||
is(p1.getAttribute("data-l10n-id"), "title");
|
||||
|
||||
domLoc.setAttributes(p1, 'title2', {userName: "John"});
|
||||
is(p1.getAttribute('data-l10n-id'), 'title2');
|
||||
is(p1.getAttribute('data-l10n-args'), JSON.stringify({userName: "John"}));
|
||||
domLoc.setAttributes(p1, "title2", {userName: "John"});
|
||||
is(p1.getAttribute("data-l10n-id"), "title2");
|
||||
is(p1.getAttribute("data-l10n-args"), JSON.stringify({userName: "John"}));
|
||||
|
||||
SimpleTest.finish();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,14 +12,14 @@
|
|||
const { MessageContext } =
|
||||
ChromeUtils.import("resource://gre/modules/MessageContext.jsm", {});
|
||||
|
||||
async function * mockGenerateMessages(locales, resourceIds) {
|
||||
async function* mockGenerateMessages(locales, resourceIds) {
|
||||
const mc = new MessageContext(locales);
|
||||
mc.addMessages('title = Hello World');
|
||||
mc.addMessages('link\n .title = Click me');
|
||||
mc.addMessages("title = Hello World");
|
||||
mc.addMessages("link\n .title = Click me");
|
||||
yield mc;
|
||||
}
|
||||
|
||||
window.onload = async function () {
|
||||
window.onload = async function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const domLoc = new DOMLocalization(
|
||||
|
|
@ -28,13 +28,13 @@
|
|||
mockGenerateMessages
|
||||
);
|
||||
|
||||
const p1 = document.querySelectorAll('p')[0];
|
||||
const link1 = document.querySelectorAll('a')[0];
|
||||
const p1 = document.querySelectorAll("p")[0];
|
||||
const link1 = document.querySelectorAll("a")[0];
|
||||
|
||||
await domLoc.translateElements([p1, link1]);
|
||||
|
||||
is(p1.textContent, "Hello World");
|
||||
is(link1.getAttribute('title'), "Click me");
|
||||
is(link1.getAttribute("title"), "Click me");
|
||||
|
||||
SimpleTest.finish();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,14 +12,14 @@
|
|||
const { MessageContext } =
|
||||
ChromeUtils.import("resource://gre/modules/MessageContext.jsm", {});
|
||||
|
||||
async function * mockGenerateMessages(locales, resourceIds) {
|
||||
async function* mockGenerateMessages(locales, resourceIds) {
|
||||
const mc = new MessageContext(locales);
|
||||
mc.addMessages('title = Hello World');
|
||||
mc.addMessages('subtitle = Welcome to Fluent');
|
||||
mc.addMessages("title = Hello World");
|
||||
mc.addMessages("subtitle = Welcome to Fluent");
|
||||
yield mc;
|
||||
}
|
||||
|
||||
window.onload = async function () {
|
||||
window.onload = async function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const domLoc = new DOMLocalization(
|
||||
|
|
@ -28,9 +28,9 @@
|
|||
mockGenerateMessages
|
||||
);
|
||||
|
||||
const frag = document.querySelectorAll('div')[0];
|
||||
const h1 = document.querySelectorAll('h1')[0];
|
||||
const p1 = document.querySelectorAll('p')[0];
|
||||
const frag = document.querySelectorAll("div")[0];
|
||||
const h1 = document.querySelectorAll("h1")[0];
|
||||
const p1 = document.querySelectorAll("p")[0];
|
||||
|
||||
await domLoc.translateFragment(frag);
|
||||
is(h1.textContent, "Hello World");
|
||||
|
|
|
|||
|
|
@ -12,14 +12,14 @@
|
|||
const { MessageContext } =
|
||||
ChromeUtils.import("resource://gre/modules/MessageContext.jsm", {});
|
||||
|
||||
async function * mockGenerateMessages(locales, resourceIds) {
|
||||
async function* mockGenerateMessages(locales, resourceIds) {
|
||||
const mc = new MessageContext(locales);
|
||||
mc.addMessages('title = Hello World');
|
||||
mc.addMessages('title2 = Hello Another World');
|
||||
mc.addMessages("title = Hello World");
|
||||
mc.addMessages("title2 = Hello Another World");
|
||||
yield mc;
|
||||
}
|
||||
|
||||
window.onload = async function () {
|
||||
window.onload = async function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const domLoc = new DOMLocalization(
|
||||
|
|
@ -28,10 +28,10 @@
|
|||
mockGenerateMessages
|
||||
);
|
||||
|
||||
const frag1 = document.querySelectorAll('div')[0];
|
||||
const frag2 = document.querySelectorAll('div')[1];
|
||||
const h1 = document.querySelectorAll('h1')[0];
|
||||
const h2 = document.querySelectorAll('h2')[0];
|
||||
const frag1 = document.querySelectorAll("div")[0];
|
||||
const frag2 = document.querySelectorAll("div")[1];
|
||||
const h1 = document.querySelectorAll("h1")[0];
|
||||
const h2 = document.querySelectorAll("h2")[0];
|
||||
|
||||
domLoc.connectRoot(frag1);
|
||||
domLoc.connectRoot(frag2);
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ ChromeUtils.import("resource://gre/modules/Timer.jsm");
|
|||
let fs;
|
||||
L10nRegistry.load = async function(url) {
|
||||
if (!fs.hasOwnProperty(url)) {
|
||||
return Promise.reject('Resource unavailable');
|
||||
return Promise.reject("Resource unavailable");
|
||||
}
|
||||
return fs[url];
|
||||
}
|
||||
};
|
||||
|
||||
add_task(function test_methods_presence() {
|
||||
equal(typeof L10nRegistry.generateContexts, "function");
|
||||
|
|
@ -29,17 +29,17 @@ add_task(function test_methods_presence() {
|
|||
*/
|
||||
add_task(async function test_methods_calling() {
|
||||
fs = {
|
||||
'/localization/en-US/browser/menu.ftl': 'key = Value',
|
||||
"/localization/en-US/browser/menu.ftl": "key = Value",
|
||||
};
|
||||
|
||||
const source = new FileSource('test', ['en-US'], '/localization/{locale}');
|
||||
const source = new FileSource("test", ["en-US"], "/localization/{locale}");
|
||||
L10nRegistry.registerSource(source);
|
||||
|
||||
const ctxs = L10nRegistry.generateContexts(['en-US'], ['/browser/menu.ftl']);
|
||||
const ctxs = L10nRegistry.generateContexts(["en-US"], ["/browser/menu.ftl"]);
|
||||
|
||||
const ctx = (await ctxs.next()).value;
|
||||
|
||||
equal(ctx.hasMessage('key'), true);
|
||||
equal(ctx.hasMessage("key"), true);
|
||||
|
||||
// cleanup
|
||||
L10nRegistry.sources.clear();
|
||||
|
|
@ -51,9 +51,9 @@ add_task(async function test_methods_calling() {
|
|||
* for the single source scenario
|
||||
*/
|
||||
add_task(async function test_has_one_source() {
|
||||
let oneSource = new FileSource('app', ['en-US'], './app/data/locales/{locale}/');
|
||||
let oneSource = new FileSource("app", ["en-US"], "./app/data/locales/{locale}/");
|
||||
fs = {
|
||||
'./app/data/locales/en-US/test.ftl': 'key = value en-US'
|
||||
"./app/data/locales/en-US/test.ftl": "key = value en-US"
|
||||
};
|
||||
L10nRegistry.registerSource(oneSource);
|
||||
|
||||
|
|
@ -61,21 +61,21 @@ add_task(async function test_has_one_source() {
|
|||
// has one source
|
||||
|
||||
equal(L10nRegistry.sources.size, 1);
|
||||
equal(L10nRegistry.sources.has('app'), true);
|
||||
equal(L10nRegistry.sources.has("app"), true);
|
||||
|
||||
|
||||
// returns a single context
|
||||
|
||||
let ctxs = L10nRegistry.generateContexts(['en-US'], ['test.ftl']);
|
||||
let ctxs = L10nRegistry.generateContexts(["en-US"], ["test.ftl"]);
|
||||
let ctx0 = (await ctxs.next()).value;
|
||||
equal(ctx0.hasMessage('key'), true);
|
||||
equal(ctx0.hasMessage("key"), true);
|
||||
|
||||
equal((await ctxs.next()).done, true);
|
||||
|
||||
|
||||
// returns no contexts for missing locale
|
||||
|
||||
ctxs = L10nRegistry.generateContexts(['pl'], ['test.ftl']);
|
||||
ctxs = L10nRegistry.generateContexts(["pl"], ["test.ftl"]);
|
||||
|
||||
equal((await ctxs.next()).done, true);
|
||||
|
||||
|
|
@ -89,50 +89,50 @@ add_task(async function test_has_one_source() {
|
|||
* for the dual source scenario.
|
||||
*/
|
||||
add_task(async function test_has_two_sources() {
|
||||
let oneSource = new FileSource('platform', ['en-US'], './platform/data/locales/{locale}/');
|
||||
let oneSource = new FileSource("platform", ["en-US"], "./platform/data/locales/{locale}/");
|
||||
L10nRegistry.registerSource(oneSource);
|
||||
|
||||
let secondSource = new FileSource('app', ['pl'], './app/data/locales/{locale}/');
|
||||
let secondSource = new FileSource("app", ["pl"], "./app/data/locales/{locale}/");
|
||||
L10nRegistry.registerSource(secondSource);
|
||||
fs = {
|
||||
'./platform/data/locales/en-US/test.ftl': 'key = platform value',
|
||||
'./app/data/locales/pl/test.ftl': 'key = app value'
|
||||
"./platform/data/locales/en-US/test.ftl": "key = platform value",
|
||||
"./app/data/locales/pl/test.ftl": "key = app value"
|
||||
};
|
||||
|
||||
|
||||
// has two sources
|
||||
|
||||
equal(L10nRegistry.sources.size, 2);
|
||||
equal(L10nRegistry.sources.has('app'), true);
|
||||
equal(L10nRegistry.sources.has('platform'), true);
|
||||
equal(L10nRegistry.sources.has("app"), true);
|
||||
equal(L10nRegistry.sources.has("platform"), true);
|
||||
|
||||
|
||||
// returns correct contexts for en-US
|
||||
|
||||
let ctxs = L10nRegistry.generateContexts(['en-US'], ['test.ftl']);
|
||||
let ctxs = L10nRegistry.generateContexts(["en-US"], ["test.ftl"]);
|
||||
let ctx0 = (await ctxs.next()).value;
|
||||
|
||||
equal(ctx0.hasMessage('key'), true);
|
||||
let msg = ctx0.getMessage('key');
|
||||
equal(ctx0.format(msg), 'platform value');
|
||||
equal(ctx0.hasMessage("key"), true);
|
||||
let msg = ctx0.getMessage("key");
|
||||
equal(ctx0.format(msg), "platform value");
|
||||
|
||||
equal((await ctxs.next()).done, true);
|
||||
|
||||
|
||||
// returns correct contexts for [pl, en-US]
|
||||
|
||||
ctxs = L10nRegistry.generateContexts(['pl', 'en-US'], ['test.ftl']);
|
||||
ctxs = L10nRegistry.generateContexts(["pl", "en-US"], ["test.ftl"]);
|
||||
ctx0 = (await ctxs.next()).value;
|
||||
equal(ctx0.locales[0], 'pl');
|
||||
equal(ctx0.hasMessage('key'), true);
|
||||
let msg0 = ctx0.getMessage('key');
|
||||
equal(ctx0.format(msg0), 'app value');
|
||||
equal(ctx0.locales[0], "pl");
|
||||
equal(ctx0.hasMessage("key"), true);
|
||||
let msg0 = ctx0.getMessage("key");
|
||||
equal(ctx0.format(msg0), "app value");
|
||||
|
||||
let ctx1 = (await ctxs.next()).value;
|
||||
equal(ctx1.locales[0], 'en-US');
|
||||
equal(ctx1.hasMessage('key'), true);
|
||||
let msg1 = ctx1.getMessage('key');
|
||||
equal(ctx1.format(msg1), 'platform value');
|
||||
equal(ctx1.locales[0], "en-US");
|
||||
equal(ctx1.hasMessage("key"), true);
|
||||
let msg1 = ctx1.getMessage("key");
|
||||
equal(ctx1.format(msg1), "platform value");
|
||||
|
||||
equal((await ctxs.next()).done, true);
|
||||
|
||||
|
|
@ -149,20 +149,20 @@ add_task(async function test_has_two_sources() {
|
|||
* missing files as `false` instead of `undefined`.
|
||||
*/
|
||||
add_task(async function test_indexed() {
|
||||
let oneSource = new IndexedFileSource('langpack-pl', ['pl'], '/data/locales/{locale}/', [
|
||||
'/data/locales/pl/test.ftl',
|
||||
let oneSource = new IndexedFileSource("langpack-pl", ["pl"], "/data/locales/{locale}/", [
|
||||
"/data/locales/pl/test.ftl",
|
||||
]);
|
||||
L10nRegistry.registerSource(oneSource);
|
||||
fs = {
|
||||
'/data/locales/pl/test.ftl': 'key = value'
|
||||
"/data/locales/pl/test.ftl": "key = value"
|
||||
};
|
||||
|
||||
equal(L10nRegistry.sources.size, 1);
|
||||
equal(L10nRegistry.sources.has('langpack-pl'), true);
|
||||
equal(L10nRegistry.sources.has("langpack-pl"), true);
|
||||
|
||||
equal(oneSource.getPath('pl', 'test.ftl'), '/data/locales/pl/test.ftl');
|
||||
equal(oneSource.hasFile('pl', 'test.ftl'), true);
|
||||
equal(oneSource.hasFile('pl', 'missing.ftl'), false);
|
||||
equal(oneSource.getPath("pl", "test.ftl"), "/data/locales/pl/test.ftl");
|
||||
equal(oneSource.hasFile("pl", "test.ftl"), true);
|
||||
equal(oneSource.hasFile("pl", "missing.ftl"), false);
|
||||
|
||||
// cleanup
|
||||
L10nRegistry.sources.clear();
|
||||
|
|
@ -174,34 +174,34 @@ add_task(async function test_indexed() {
|
|||
* scenarios where a new file source is added on top of the default one.
|
||||
*/
|
||||
add_task(async function test_override() {
|
||||
let fileSource = new FileSource('app', ['pl'], '/app/data/locales/{locale}/');
|
||||
let fileSource = new FileSource("app", ["pl"], "/app/data/locales/{locale}/");
|
||||
L10nRegistry.registerSource(fileSource);
|
||||
|
||||
let oneSource = new IndexedFileSource('langpack-pl', ['pl'], '/data/locales/{locale}/', [
|
||||
'/data/locales/pl/test.ftl'
|
||||
let oneSource = new IndexedFileSource("langpack-pl", ["pl"], "/data/locales/{locale}/", [
|
||||
"/data/locales/pl/test.ftl"
|
||||
]);
|
||||
L10nRegistry.registerSource(oneSource);
|
||||
|
||||
fs = {
|
||||
'/app/data/locales/pl/test.ftl': 'key = value',
|
||||
'/data/locales/pl/test.ftl': 'key = addon value'
|
||||
"/app/data/locales/pl/test.ftl": "key = value",
|
||||
"/data/locales/pl/test.ftl": "key = addon value"
|
||||
};
|
||||
|
||||
equal(L10nRegistry.sources.size, 2);
|
||||
equal(L10nRegistry.sources.has('langpack-pl'), true);
|
||||
equal(L10nRegistry.sources.has("langpack-pl"), true);
|
||||
|
||||
let ctxs = L10nRegistry.generateContexts(['pl'], ['test.ftl']);
|
||||
let ctxs = L10nRegistry.generateContexts(["pl"], ["test.ftl"]);
|
||||
let ctx0 = (await ctxs.next()).value;
|
||||
equal(ctx0.locales[0], 'pl');
|
||||
equal(ctx0.hasMessage('key'), true);
|
||||
let msg0 = ctx0.getMessage('key');
|
||||
equal(ctx0.format(msg0), 'addon value');
|
||||
equal(ctx0.locales[0], "pl");
|
||||
equal(ctx0.hasMessage("key"), true);
|
||||
let msg0 = ctx0.getMessage("key");
|
||||
equal(ctx0.format(msg0), "addon value");
|
||||
|
||||
let ctx1 = (await ctxs.next()).value;
|
||||
equal(ctx1.locales[0], 'pl');
|
||||
equal(ctx1.hasMessage('key'), true);
|
||||
let msg1 = ctx1.getMessage('key');
|
||||
equal(ctx1.format(msg1), 'value');
|
||||
equal(ctx1.locales[0], "pl");
|
||||
equal(ctx1.hasMessage("key"), true);
|
||||
let msg1 = ctx1.getMessage("key");
|
||||
equal(ctx1.format(msg1), "value");
|
||||
|
||||
equal((await ctxs.next()).done, true);
|
||||
|
||||
|
|
@ -215,33 +215,33 @@ add_task(async function test_override() {
|
|||
* after source update.
|
||||
*/
|
||||
add_task(async function test_updating() {
|
||||
let oneSource = new IndexedFileSource('langpack-pl', ['pl'], '/data/locales/{locale}/', [
|
||||
'/data/locales/pl/test.ftl',
|
||||
let oneSource = new IndexedFileSource("langpack-pl", ["pl"], "/data/locales/{locale}/", [
|
||||
"/data/locales/pl/test.ftl",
|
||||
]);
|
||||
L10nRegistry.registerSource(oneSource);
|
||||
fs = {
|
||||
'/data/locales/pl/test.ftl': 'key = value'
|
||||
"/data/locales/pl/test.ftl": "key = value"
|
||||
};
|
||||
|
||||
let ctxs = L10nRegistry.generateContexts(['pl'], ['test.ftl']);
|
||||
let ctxs = L10nRegistry.generateContexts(["pl"], ["test.ftl"]);
|
||||
let ctx0 = (await ctxs.next()).value;
|
||||
equal(ctx0.locales[0], 'pl');
|
||||
equal(ctx0.hasMessage('key'), true);
|
||||
let msg0 = ctx0.getMessage('key');
|
||||
equal(ctx0.format(msg0), 'value');
|
||||
equal(ctx0.locales[0], "pl");
|
||||
equal(ctx0.hasMessage("key"), true);
|
||||
let msg0 = ctx0.getMessage("key");
|
||||
equal(ctx0.format(msg0), "value");
|
||||
|
||||
|
||||
const newSource = new IndexedFileSource('langpack-pl', ['pl'], '/data/locales/{locale}/', [
|
||||
'/data/locales/pl/test.ftl'
|
||||
const newSource = new IndexedFileSource("langpack-pl", ["pl"], "/data/locales/{locale}/", [
|
||||
"/data/locales/pl/test.ftl"
|
||||
]);
|
||||
fs['/data/locales/pl/test.ftl'] = 'key = new value';
|
||||
fs["/data/locales/pl/test.ftl"] = "key = new value";
|
||||
L10nRegistry.updateSource(newSource);
|
||||
|
||||
equal(L10nRegistry.sources.size, 1);
|
||||
ctxs = L10nRegistry.generateContexts(['pl'], ['test.ftl']);
|
||||
ctxs = L10nRegistry.generateContexts(["pl"], ["test.ftl"]);
|
||||
ctx0 = (await ctxs.next()).value;
|
||||
msg0 = ctx0.getMessage('key');
|
||||
equal(ctx0.format(msg0), 'new value');
|
||||
msg0 = ctx0.getMessage("key");
|
||||
equal(ctx0.format(msg0), "new value");
|
||||
|
||||
// cleanup
|
||||
L10nRegistry.sources.clear();
|
||||
|
|
@ -253,60 +253,60 @@ add_task(async function test_updating() {
|
|||
* after sources are being removed.
|
||||
*/
|
||||
add_task(async function test_removing() {
|
||||
let fileSource = new FileSource('app', ['pl'], '/app/data/locales/{locale}/');
|
||||
let fileSource = new FileSource("app", ["pl"], "/app/data/locales/{locale}/");
|
||||
L10nRegistry.registerSource(fileSource);
|
||||
|
||||
let oneSource = new IndexedFileSource('langpack-pl', ['pl'], '/data/locales/{locale}/', [
|
||||
'/data/locales/pl/test.ftl'
|
||||
let oneSource = new IndexedFileSource("langpack-pl", ["pl"], "/data/locales/{locale}/", [
|
||||
"/data/locales/pl/test.ftl"
|
||||
]);
|
||||
L10nRegistry.registerSource(oneSource);
|
||||
|
||||
fs = {
|
||||
'/app/data/locales/pl/test.ftl': 'key = value',
|
||||
'/data/locales/pl/test.ftl': 'key = addon value'
|
||||
"/app/data/locales/pl/test.ftl": "key = value",
|
||||
"/data/locales/pl/test.ftl": "key = addon value"
|
||||
};
|
||||
|
||||
equal(L10nRegistry.sources.size, 2);
|
||||
equal(L10nRegistry.sources.has('langpack-pl'), true);
|
||||
equal(L10nRegistry.sources.has("langpack-pl"), true);
|
||||
|
||||
let ctxs = L10nRegistry.generateContexts(['pl'], ['test.ftl']);
|
||||
let ctxs = L10nRegistry.generateContexts(["pl"], ["test.ftl"]);
|
||||
let ctx0 = (await ctxs.next()).value;
|
||||
equal(ctx0.locales[0], 'pl');
|
||||
equal(ctx0.hasMessage('key'), true);
|
||||
let msg0 = ctx0.getMessage('key');
|
||||
equal(ctx0.format(msg0), 'addon value');
|
||||
equal(ctx0.locales[0], "pl");
|
||||
equal(ctx0.hasMessage("key"), true);
|
||||
let msg0 = ctx0.getMessage("key");
|
||||
equal(ctx0.format(msg0), "addon value");
|
||||
|
||||
let ctx1 = (await ctxs.next()).value;
|
||||
equal(ctx1.locales[0], 'pl');
|
||||
equal(ctx1.hasMessage('key'), true);
|
||||
let msg1 = ctx1.getMessage('key');
|
||||
equal(ctx1.format(msg1), 'value');
|
||||
equal(ctx1.locales[0], "pl");
|
||||
equal(ctx1.hasMessage("key"), true);
|
||||
let msg1 = ctx1.getMessage("key");
|
||||
equal(ctx1.format(msg1), "value");
|
||||
|
||||
equal((await ctxs.next()).done, true);
|
||||
|
||||
// Remove langpack
|
||||
|
||||
L10nRegistry.removeSource('langpack-pl');
|
||||
L10nRegistry.removeSource("langpack-pl");
|
||||
|
||||
equal(L10nRegistry.sources.size, 1);
|
||||
equal(L10nRegistry.sources.has('langpack-pl'), false);
|
||||
equal(L10nRegistry.sources.has("langpack-pl"), false);
|
||||
|
||||
ctxs = L10nRegistry.generateContexts(['pl'], ['test.ftl']);
|
||||
ctxs = L10nRegistry.generateContexts(["pl"], ["test.ftl"]);
|
||||
ctx0 = (await ctxs.next()).value;
|
||||
equal(ctx0.locales[0], 'pl');
|
||||
equal(ctx0.hasMessage('key'), true);
|
||||
msg0 = ctx0.getMessage('key');
|
||||
equal(ctx0.format(msg0), 'value');
|
||||
equal(ctx0.locales[0], "pl");
|
||||
equal(ctx0.hasMessage("key"), true);
|
||||
msg0 = ctx0.getMessage("key");
|
||||
equal(ctx0.format(msg0), "value");
|
||||
|
||||
equal((await ctxs.next()).done, true);
|
||||
|
||||
// Remove app source
|
||||
|
||||
L10nRegistry.removeSource('app');
|
||||
L10nRegistry.removeSource("app");
|
||||
|
||||
equal(L10nRegistry.sources.size, 0);
|
||||
|
||||
ctxs = L10nRegistry.generateContexts(['pl'], ['test.ftl']);
|
||||
ctxs = L10nRegistry.generateContexts(["pl"], ["test.ftl"]);
|
||||
equal((await ctxs.next()).done, true);
|
||||
|
||||
// cleanup
|
||||
|
|
@ -319,30 +319,30 @@ add_task(async function test_removing() {
|
|||
* file in the FileSource scenario.
|
||||
*/
|
||||
add_task(async function test_missing_file() {
|
||||
let oneSource = new FileSource('app', ['en-US'], './app/data/locales/{locale}/');
|
||||
let oneSource = new FileSource("app", ["en-US"], "./app/data/locales/{locale}/");
|
||||
L10nRegistry.registerSource(oneSource);
|
||||
let twoSource = new FileSource('platform', ['en-US'], './platform/data/locales/{locale}/');
|
||||
let twoSource = new FileSource("platform", ["en-US"], "./platform/data/locales/{locale}/");
|
||||
L10nRegistry.registerSource(twoSource);
|
||||
|
||||
fs = {
|
||||
'./app/data/locales/en-US/test.ftl': 'key = value en-US',
|
||||
'./platform/data/locales/en-US/test.ftl': 'key = value en-US',
|
||||
'./platform/data/locales/en-US/test2.ftl': 'key2 = value2 en-US'
|
||||
"./app/data/locales/en-US/test.ftl": "key = value en-US",
|
||||
"./platform/data/locales/en-US/test.ftl": "key = value en-US",
|
||||
"./platform/data/locales/en-US/test2.ftl": "key2 = value2 en-US"
|
||||
};
|
||||
|
||||
|
||||
// has two sources
|
||||
|
||||
equal(L10nRegistry.sources.size, 2);
|
||||
equal(L10nRegistry.sources.has('app'), true);
|
||||
equal(L10nRegistry.sources.has('platform'), true);
|
||||
equal(L10nRegistry.sources.has("app"), true);
|
||||
equal(L10nRegistry.sources.has("platform"), true);
|
||||
|
||||
|
||||
// returns a single context
|
||||
|
||||
let ctxs = L10nRegistry.generateContexts(['en-US'], ['test.ftl', 'test2.ftl']);
|
||||
let ctx0 = (await ctxs.next()).value;
|
||||
let ctx1 = (await ctxs.next()).value;
|
||||
let ctxs = L10nRegistry.generateContexts(["en-US"], ["test.ftl", "test2.ftl"]);
|
||||
(await ctxs.next());
|
||||
(await ctxs.next());
|
||||
|
||||
equal((await ctxs.next()).done, true);
|
||||
|
||||
|
|
@ -368,33 +368,33 @@ add_task(async function test_parallel_io() {
|
|||
}
|
||||
fetchIndex.set(url, fetchIndex.get(url) + 1);
|
||||
|
||||
if (url === '/en-US/slow-file.ftl') {
|
||||
if (url === "/en-US/slow-file.ftl") {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
// Despite slow-file being the first on the list,
|
||||
// by the time the it finishes loading, the other
|
||||
// two files are already fetched.
|
||||
equal(fetchIndex.get('/en-US/test.ftl'), 1);
|
||||
equal(fetchIndex.get('/en-US/test2.ftl'), 1);
|
||||
equal(fetchIndex.get("/en-US/test.ftl"), 1);
|
||||
equal(fetchIndex.get("/en-US/test2.ftl"), 1);
|
||||
|
||||
resolve('');
|
||||
resolve("");
|
||||
}, 10);
|
||||
});
|
||||
};
|
||||
return Promise.resolve('');
|
||||
}
|
||||
let oneSource = new FileSource('app', ['en-US'], '/{locale}/');
|
||||
}
|
||||
return Promise.resolve("");
|
||||
};
|
||||
let oneSource = new FileSource("app", ["en-US"], "/{locale}/");
|
||||
L10nRegistry.registerSource(oneSource);
|
||||
|
||||
fs = {
|
||||
'/en-US/test.ftl': 'key = value en-US',
|
||||
'/en-US/test2.ftl': 'key2 = value2 en-US',
|
||||
'/en-US/slow-file.ftl': 'key-slow = value slow en-US',
|
||||
"/en-US/test.ftl": "key = value en-US",
|
||||
"/en-US/test2.ftl": "key2 = value2 en-US",
|
||||
"/en-US/slow-file.ftl": "key-slow = value slow en-US",
|
||||
};
|
||||
|
||||
// returns a single context
|
||||
|
||||
let ctxs = L10nRegistry.generateContexts(['en-US'], ['slow-file.ftl', 'test.ftl', 'test2.ftl']);
|
||||
let ctxs = L10nRegistry.generateContexts(["en-US"], ["slow-file.ftl", "test.ftl", "test2.ftl"]);
|
||||
|
||||
equal(fetchIndex.size, 0);
|
||||
|
||||
|
|
@ -406,7 +406,7 @@ add_task(async function test_parallel_io() {
|
|||
|
||||
// When requested again, the cache should make the load operation not
|
||||
// increase the fetchedIndex count
|
||||
let ctxs2= L10nRegistry.generateContexts(['en-US'], ['test.ftl', 'test2.ftl', 'slow-file.ftl']);
|
||||
L10nRegistry.generateContexts(["en-US"], ["test.ftl", "test2.ftl", "slow-file.ftl"]);
|
||||
|
||||
// cleanup
|
||||
L10nRegistry.sources.clear();
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
const { AppConstants } = ChromeUtils.import("resource://gre/modules/AppConstants.jsm", {});
|
||||
const { Localization } = ChromeUtils.import("resource://gre/modules/Localization.jsm", {});
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm", {});
|
||||
|
||||
add_task(function test_methods_presence() {
|
||||
equal(typeof Localization.prototype.formatValues, "function");
|
||||
|
|
@ -13,58 +14,55 @@ add_task(function test_methods_presence() {
|
|||
add_task(async function test_methods_calling() {
|
||||
const { L10nRegistry, FileSource } =
|
||||
ChromeUtils.import("resource://gre/modules/L10nRegistry.jsm", {});
|
||||
const LocaleService =
|
||||
Components.classes["@mozilla.org/intl/localeservice;1"].getService(
|
||||
Components.interfaces.mozILocaleService);
|
||||
|
||||
const fs = {
|
||||
'/localization/de/browser/menu.ftl': 'key = [de] Value2',
|
||||
'/localization/en-US/browser/menu.ftl': 'key = [en] Value2\nkey2 = [en] Value3',
|
||||
"/localization/de/browser/menu.ftl": "key = [de] Value2",
|
||||
"/localization/en-US/browser/menu.ftl": "key = [en] Value2\nkey2 = [en] Value3",
|
||||
};
|
||||
const originalLoad = L10nRegistry.load;
|
||||
const originalRequested = LocaleService.getRequestedLocales();
|
||||
const originalRequested = Services.locale.getRequestedLocales();
|
||||
|
||||
L10nRegistry.load = async function(url) {
|
||||
return fs[url];
|
||||
}
|
||||
};
|
||||
|
||||
const source = new FileSource('test', ['de', 'en-US'], '/localization/{locale}');
|
||||
const source = new FileSource("test", ["de", "en-US"], "/localization/{locale}");
|
||||
L10nRegistry.registerSource(source);
|
||||
|
||||
async function* generateMessages(resIds) {
|
||||
yield * await L10nRegistry.generateContexts(['de', 'en-US'], resIds);
|
||||
yield * await L10nRegistry.generateContexts(["de", "en-US"], resIds);
|
||||
}
|
||||
|
||||
const l10n = new Localization([
|
||||
'/browser/menu.ftl'
|
||||
"/browser/menu.ftl"
|
||||
], generateMessages);
|
||||
|
||||
let values = await l10n.formatValues([['key'], ['key2']]);
|
||||
let values = await l10n.formatValues([["key"], ["key2"]]);
|
||||
|
||||
equal(values[0], '[de] Value2');
|
||||
equal(values[1], '[en] Value3');
|
||||
equal(values[0], "[de] Value2");
|
||||
equal(values[1], "[en] Value3");
|
||||
|
||||
L10nRegistry.sources.clear();
|
||||
L10nRegistry.load = originalLoad;
|
||||
LocaleService.setRequestedLocales(originalRequested);
|
||||
Services.locale.setRequestedLocales(originalRequested);
|
||||
});
|
||||
|
||||
add_task(async function test_builtins() {
|
||||
const { L10nRegistry, FileSource } =
|
||||
Components.utils.import("resource://gre/modules/L10nRegistry.jsm", {});
|
||||
ChromeUtils.import("resource://gre/modules/L10nRegistry.jsm", {});
|
||||
|
||||
const known_platforms = {
|
||||
'linux': 'linux',
|
||||
'win': 'windows',
|
||||
'macosx': 'macos',
|
||||
'android': 'android',
|
||||
"linux": "linux",
|
||||
"win": "windows",
|
||||
"macosx": "macos",
|
||||
"android": "android",
|
||||
};
|
||||
|
||||
const fs = {
|
||||
'/localization/en-US/test.ftl': `
|
||||
"/localization/en-US/test.ftl": `
|
||||
key = { PLATFORM() ->
|
||||
${ Object.values(known_platforms).map(
|
||||
name => ` [${ name }] ${ name.toUpperCase() } Value\n`).join('') }
|
||||
name => ` [${ name }] ${ name.toUpperCase() } Value\n`).join("") }
|
||||
*[other] OTHER Value
|
||||
}`,
|
||||
};
|
||||
|
|
@ -72,20 +70,20 @@ key = { PLATFORM() ->
|
|||
|
||||
L10nRegistry.load = async function(url) {
|
||||
return fs[url];
|
||||
}
|
||||
};
|
||||
|
||||
const source = new FileSource('test', ['en-US'], '/localization/{locale}');
|
||||
const source = new FileSource("test", ["en-US"], "/localization/{locale}");
|
||||
L10nRegistry.registerSource(source);
|
||||
|
||||
async function* generateMessages(resIds) {
|
||||
yield * await L10nRegistry.generateContexts(['en-US'], resIds);
|
||||
yield * await L10nRegistry.generateContexts(["en-US"], resIds);
|
||||
}
|
||||
|
||||
const l10n = new Localization([
|
||||
'/test.ftl'
|
||||
"/test.ftl"
|
||||
], generateMessages);
|
||||
|
||||
let values = await l10n.formatValues([['key']]);
|
||||
let values = await l10n.formatValues([["key"]]);
|
||||
|
||||
ok(values[0].includes(
|
||||
`${ known_platforms[AppConstants.platform].toUpperCase() } Value`));
|
||||
|
|
|
|||
Loading…
Reference in a new issue