mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
Bug 1498960
- Update Fluent in Gecko to 0.9. r=stas
Differential Revision: https://phabricator.services.mozilla.com/D8689 --HG-- rename : intl/l10n/MessageContext.jsm => intl/l10n/Fluent.jsm extra : moz-landing-system : lando
This commit is contained in:
parent
3334b2af14
commit
56bbe2cfb3
@ -197,13 +197,13 @@ function getBundleForLocales(newLocales) {
|
||||
...Services.locale.requestedLocales,
|
||||
Services.locale.lastFallbackLocale,
|
||||
]));
|
||||
function generateContexts(resourceIds) {
|
||||
return L10nRegistry.generateContexts(locales, resourceIds);
|
||||
function generateBundles(resourceIds) {
|
||||
return L10nRegistry.generateBundles(locales, resourceIds);
|
||||
}
|
||||
return new Localization([
|
||||
"browser/preferences/preferences.ftl",
|
||||
"branding/brand.ftl",
|
||||
], generateContexts);
|
||||
], generateBundles);
|
||||
}
|
||||
|
||||
var gNodeToObjectMap = new WeakMap();
|
||||
|
@ -55,10 +55,10 @@ const AboutDebugging = {
|
||||
this.store = configureStore();
|
||||
this.actions = bindActionCreators(actions, this.store.dispatch);
|
||||
|
||||
const messageContexts = await this.createMessageContexts();
|
||||
const fluentBundles = await this.createFluentBundles();
|
||||
|
||||
render(
|
||||
Provider({ store: this.store }, App({ messageContexts })),
|
||||
Provider({ store: this.store }, App({ fluentBundles })),
|
||||
this.mount
|
||||
);
|
||||
|
||||
@ -73,7 +73,7 @@ const AboutDebugging = {
|
||||
this.onAdbAddonUpdated();
|
||||
},
|
||||
|
||||
async createMessageContexts() {
|
||||
async createFluentBundles() {
|
||||
// XXX Until the strings for the updated about:debugging stabilize, we
|
||||
// locate them outside the regular directory for locale resources so that
|
||||
// they don't get picked up by localization tools.
|
||||
@ -88,14 +88,14 @@ const AboutDebugging = {
|
||||
|
||||
const locales = Services.locale.appLocalesAsBCP47;
|
||||
const generator =
|
||||
L10nRegistry.generateContexts(locales, ["aboutdebugging.ftl"]);
|
||||
L10nRegistry.generateBundles(locales, ["aboutdebugging.ftl"]);
|
||||
|
||||
const contexts = [];
|
||||
for await (const context of generator) {
|
||||
contexts.push(context);
|
||||
const bundles = [];
|
||||
for await (const bundle of generator) {
|
||||
bundles.push(bundle);
|
||||
}
|
||||
|
||||
return contexts;
|
||||
return bundles;
|
||||
},
|
||||
|
||||
onAdbAddonUpdated() {
|
||||
|
@ -27,7 +27,7 @@ class App extends PureComponent {
|
||||
// From that point, components are responsible for forwarding the dispatch
|
||||
// property to all components who need to dispatch actions.
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
messageContexts: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
fluentBundles: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
networkLocations: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
networkRuntimes: PropTypes.arrayOf(Types.runtime).isRequired,
|
||||
selectedPage: PropTypes.string,
|
||||
@ -65,14 +65,14 @@ class App extends PureComponent {
|
||||
const {
|
||||
adbAddonStatus,
|
||||
dispatch,
|
||||
messageContexts,
|
||||
fluentBundles,
|
||||
networkRuntimes,
|
||||
selectedPage,
|
||||
usbRuntimes,
|
||||
} = this.props;
|
||||
|
||||
return LocalizationProvider(
|
||||
{ messages: messageContexts },
|
||||
{ messages: fluentBundles },
|
||||
dom.div(
|
||||
{ className: "app" },
|
||||
Sidebar(
|
||||
|
@ -52,23 +52,23 @@ window.Application = {
|
||||
this.updateDomain();
|
||||
await this.updateWorkers();
|
||||
|
||||
const messageContexts = await this.createMessageContexts();
|
||||
const fluentBundles = await this.createFluentBundles();
|
||||
|
||||
// Render the root Application component.
|
||||
const app = App({ client: this.client, messageContexts, serviceContainer });
|
||||
const app = App({ client: this.client, fluentBundles, serviceContainer });
|
||||
render(Provider({ store: this.store }, app), this.mount);
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve message contexts for the current locales, and return them as an array of
|
||||
* MessageContext elements.
|
||||
* FluentBundles elements.
|
||||
*/
|
||||
async createMessageContexts() {
|
||||
async createFluentBundles() {
|
||||
const locales = Services.locale.appLocalesAsBCP47;
|
||||
const generator =
|
||||
L10nRegistry.generateContexts(locales, ["devtools/application.ftl"]);
|
||||
L10nRegistry.generateBundles(locales, ["devtools/application.ftl"]);
|
||||
|
||||
// Return value of generateContexts is a generator and should be converted to
|
||||
// Return value of generateBundles is a generator and should be converted to
|
||||
// a sync iterable before using it with React.
|
||||
const contexts = [];
|
||||
for await (const message of generator) {
|
||||
|
@ -25,12 +25,12 @@ class App extends Component {
|
||||
workers: PropTypes.object.isRequired,
|
||||
serviceContainer: PropTypes.object.isRequired,
|
||||
domain: PropTypes.string.isRequired,
|
||||
messageContexts: PropTypes.array.isRequired,
|
||||
fluentBundles: PropTypes.array.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
let { workers, domain, client, serviceContainer, messageContexts } = this.props;
|
||||
let { workers, domain, client, serviceContainer, fluentBundles } = this.props;
|
||||
|
||||
// Filter out workers from other domains
|
||||
workers = workers.filter((x) => new URL(x.url).hostname === domain);
|
||||
@ -38,7 +38,7 @@ class App extends Component {
|
||||
|
||||
return (
|
||||
LocalizationProvider(
|
||||
{ messages: messageContexts },
|
||||
{ messages: fluentBundles },
|
||||
main(
|
||||
{ className: `application ${isEmpty ? "application--empty" : ""}` },
|
||||
isEmpty ? WorkerListEmpty({ serviceContainer })
|
||||
|
@ -15,8 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/* fluent-dom@cab517f (July 31, 2018) */
|
||||
/* fluent-dom@fa25466f (October 12, 2018) */
|
||||
|
||||
const { Localization } =
|
||||
ChromeUtils.import("resource://gre/modules/Localization.jsm", {});
|
||||
@ -176,7 +175,7 @@ function overlayAttributes(fromElement, toElement) {
|
||||
}
|
||||
|
||||
// fromElement might be a {value, attributes} object as returned by
|
||||
// Localization.messageFromContext. In which case attributes may be null to
|
||||
// Localization.messageFromBundle. In which case attributes may be null to
|
||||
// save GC cycles.
|
||||
if (!fromElement.attributes) {
|
||||
return;
|
||||
@ -406,13 +405,13 @@ const L10N_ELEMENT_QUERY = `[${L10NID_ATTR_NAME}]`;
|
||||
*/
|
||||
class DOMLocalization extends Localization {
|
||||
/**
|
||||
* @param {Array<String>} resourceIds - List of resource IDs
|
||||
* @param {Function} generateMessages - Function that returns a
|
||||
* generator over MessageContexts
|
||||
* @param {Array<String>} resourceIds - List of resource IDs
|
||||
* @param {Function} generateBundles - Function that returns a
|
||||
* generator over FluentBundles
|
||||
* @returns {DOMLocalization}
|
||||
*/
|
||||
constructor(resourceIds, generateMessages) {
|
||||
super(resourceIds, generateMessages);
|
||||
constructor(resourceIds, generateBundles) {
|
||||
super(resourceIds, generateBundles);
|
||||
|
||||
// A Set of DOM trees observed by the `MutationObserver`.
|
||||
this.roots = new Set();
|
||||
|
1370
intl/l10n/Fluent.jsm
Normal file
1370
intl/l10n/Fluent.jsm
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
const { AppConstants } = ChromeUtils.import("resource://gre/modules/AppConstants.jsm", {});
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm", {});
|
||||
const { MessageContext, FluentResource } = ChromeUtils.import("resource://gre/modules/MessageContext.jsm", {});
|
||||
const { FluentBundle, FluentResource } = ChromeUtils.import("resource://gre/modules/Fluent.jsm", {});
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["fetch"]);
|
||||
|
||||
@ -10,7 +10,7 @@ XPCOMUtils.defineLazyGlobalGetters(this, ["fetch"]);
|
||||
* It manages the list of resource sources provided with the app and allows
|
||||
* for additional sources to be added and updated.
|
||||
*
|
||||
* It's primary purpose is to allow for building an iterator over MessageContext objects
|
||||
* It's primary purpose is to allow for building an iterator over FluentBundle objects
|
||||
* that will be utilized by a localization API.
|
||||
*
|
||||
* The generator creates all possible permutations of locales and sources to allow for
|
||||
@ -33,7 +33,7 @@ XPCOMUtils.defineLazyGlobalGetters(this, ["fetch"]);
|
||||
* ]
|
||||
*
|
||||
* If the user will request:
|
||||
* L10nRegistry.generateContexts(['de', 'en-US'], [
|
||||
* L10nRegistry.generateBundles(['de', 'en-US'], [
|
||||
* '/browser/menu.ftl',
|
||||
* '/platform/toolkit.ftl'
|
||||
* ]);
|
||||
@ -69,7 +69,7 @@ XPCOMUtils.defineLazyGlobalGetters(this, ["fetch"]);
|
||||
* ]
|
||||
* }
|
||||
*
|
||||
* This allows the localization API to consume the MessageContext and lazily fallback
|
||||
* This allows the localization API to consume the FluentBundle and lazily fallback
|
||||
* on the next in case of a missing string or error.
|
||||
*
|
||||
* If during the life-cycle of the app a new source is added, the generator can be called again
|
||||
@ -86,9 +86,9 @@ const L10nRegistry = {
|
||||
*
|
||||
* @param {Array} requestedLangs
|
||||
* @param {Array} resourceIds
|
||||
* @returns {AsyncIterator<MessageContext>}
|
||||
* @returns {AsyncIterator<FluentBundle>}
|
||||
*/
|
||||
async* generateContexts(requestedLangs, resourceIds) {
|
||||
async* generateBundles(requestedLangs, resourceIds) {
|
||||
if (this.bootstrap !== null) {
|
||||
await this.bootstrap;
|
||||
}
|
||||
@ -96,7 +96,7 @@ const L10nRegistry = {
|
||||
const pseudoNameFromPref = Services.prefs.getStringPref("intl.l10n.pseudo", "");
|
||||
for (const locale of requestedLangs) {
|
||||
for await (const dataSets of generateResourceSetsForLocale(locale, sourcesOrder, resourceIds)) {
|
||||
const ctx = new MessageContext(locale, {
|
||||
const bundle = new FluentBundle(locale, {
|
||||
...MSG_CONTEXT_OPTIONS,
|
||||
transform: PSEUDO_STRATEGIES[pseudoNameFromPref],
|
||||
});
|
||||
@ -104,9 +104,9 @@ const L10nRegistry = {
|
||||
if (data === null) {
|
||||
return;
|
||||
}
|
||||
ctx.addResource(data);
|
||||
bundle.addResource(data);
|
||||
}
|
||||
yield ctx;
|
||||
yield bundle;
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -169,7 +169,7 @@ const L10nRegistry = {
|
||||
};
|
||||
|
||||
/**
|
||||
* This function generates an iterator over MessageContexts for a single locale
|
||||
* This function generates an iterator over FluentBundles for a single locale
|
||||
* for a given list of resourceIds for all possible combinations of sources.
|
||||
*
|
||||
* This function is called recursively to generate all possible permutations
|
||||
@ -180,7 +180,7 @@ const L10nRegistry = {
|
||||
* @param {Array} sourcesOrder
|
||||
* @param {Array} resourceIds
|
||||
* @param {Array} [resolvedOrder]
|
||||
* @returns {AsyncIterator<MessageContext>}
|
||||
* @returns {AsyncIterator<FluentBundle>}
|
||||
*/
|
||||
async function* generateResourceSetsForLocale(locale, sourcesOrder, resourceIds, resolvedOrder = []) {
|
||||
const resolvedLength = resolvedOrder.length;
|
||||
@ -343,7 +343,7 @@ const PSEUDO_STRATEGIES = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a single MessageContext by loading all resources
|
||||
* Generates a single FluentBundle by loading all resources
|
||||
* from the listed sources for a given locale.
|
||||
*
|
||||
* The function casts all error cases into a Promise that resolves with
|
||||
@ -354,7 +354,7 @@ const PSEUDO_STRATEGIES = {
|
||||
* @param {String} locale
|
||||
* @param {Array} sourcesOrder
|
||||
* @param {Array} resourceIds
|
||||
* @returns {Promise<MessageContext>}
|
||||
* @returns {Promise<FluentBundle>}
|
||||
*/
|
||||
async function generateResourceSet(locale, sourcesOrder, resourceIds) {
|
||||
return Promise.all(resourceIds.map((resourceId, i) => {
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
|
||||
/* fluent-dom@cab517f (July 31, 2018) */
|
||||
/* fluent-dom@fa25466f (October 12, 2018) */
|
||||
|
||||
/* eslint no-console: ["error", { allow: ["warn", "error"] }] */
|
||||
/* global console */
|
||||
@ -25,6 +25,9 @@ const { L10nRegistry } = ChromeUtils.import("resource://gre/modules/L10nRegistry
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm", {});
|
||||
const { AppConstants } = ChromeUtils.import("resource://gre/modules/AppConstants.jsm", {});
|
||||
|
||||
/*
|
||||
* Base CachedIterable class.
|
||||
*/
|
||||
class CachedIterable extends Array {
|
||||
/**
|
||||
* Create a `CachedIterable` instance from an iterable or, if another
|
||||
@ -43,6 +46,12 @@ class CachedIterable extends Array {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* CachedAsyncIterable caches the elements yielded by an async iterable.
|
||||
*
|
||||
* It can be used to iterate over an iterable many times without depleting the
|
||||
* iterable.
|
||||
*/
|
||||
class CachedAsyncIterable extends CachedIterable {
|
||||
/**
|
||||
* Create an `CachedAsyncIterable` instance.
|
||||
@ -97,7 +106,7 @@ class CachedAsyncIterable extends CachedIterable {
|
||||
return {
|
||||
async next() {
|
||||
if (cached.length <= cur) {
|
||||
cached.push(cached.iterator.next());
|
||||
cached.push(await cached.iterator.next());
|
||||
}
|
||||
return cached[cur++];
|
||||
},
|
||||
@ -114,10 +123,10 @@ class CachedAsyncIterable extends CachedIterable {
|
||||
let idx = 0;
|
||||
while (idx++ < count) {
|
||||
const last = this[this.length - 1];
|
||||
if (last && await (last).done) {
|
||||
if (last && last.done) {
|
||||
break;
|
||||
}
|
||||
this.push(this.iterator.next());
|
||||
this.push(await this.iterator.next());
|
||||
}
|
||||
// Return the last cached {value, done} object to allow the calling
|
||||
// code to decide if it needs to call touchNext again.
|
||||
@ -128,36 +137,36 @@ class CachedAsyncIterable extends CachedIterable {
|
||||
/**
|
||||
* The default localization strategy for Gecko. It comabines locales
|
||||
* available in L10nRegistry, with locales requested by the user to
|
||||
* generate the iterator over MessageContexts.
|
||||
* generate the iterator over FluentBundles.
|
||||
*
|
||||
* In the future, we may want to allow certain modules to override this
|
||||
* with a different negotitation strategy to allow for the module to
|
||||
* be localized into a different language - for example DevTools.
|
||||
*/
|
||||
function defaultGenerateMessages(resourceIds) {
|
||||
function defaultGenerateBundles(resourceIds) {
|
||||
const appLocales = Services.locale.appLocalesAsBCP47;
|
||||
return L10nRegistry.generateContexts(appLocales, resourceIds);
|
||||
return L10nRegistry.generateBundles(appLocales, resourceIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* The `Localization` class is a central high-level API for vanilla
|
||||
* JavaScript use of Fluent.
|
||||
* It combines language negotiation, MessageContext and I/O to
|
||||
* It combines language negotiation, FluentBundle and I/O to
|
||||
* provide a scriptable API to format translations.
|
||||
*/
|
||||
class Localization {
|
||||
/**
|
||||
* @param {Array<String>} resourceIds - List of resource IDs
|
||||
* @param {Function} generateMessages - Function that returns a
|
||||
* generator over MessageContexts
|
||||
* @param {Array<String>} resourceIds - List of resource IDs
|
||||
* @param {Function} generateBundles - Function that returns a
|
||||
* generator over FluentBundles
|
||||
*
|
||||
* @returns {Localization}
|
||||
*/
|
||||
constructor(resourceIds = [], generateMessages = defaultGenerateMessages) {
|
||||
constructor(resourceIds = [], generateBundles = defaultGenerateBundles) {
|
||||
this.resourceIds = resourceIds;
|
||||
this.generateMessages = generateMessages;
|
||||
this.ctxs = CachedAsyncIterable.from(
|
||||
this.generateMessages(this.resourceIds));
|
||||
this.generateBundles = generateBundles;
|
||||
this.bundles = CachedAsyncIterable.from(
|
||||
this.generateBundles(this.resourceIds));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -180,7 +189,7 @@ class Localization {
|
||||
/**
|
||||
* Format translations and handle fallback if needed.
|
||||
*
|
||||
* Format translations for `keys` from `MessageContext` instances on this
|
||||
* Format translations for `keys` from `FluentBundle` instances on this
|
||||
* DOMLocalization. In case of errors, fetch the next context in the
|
||||
* fallback chain.
|
||||
*
|
||||
@ -192,15 +201,15 @@ class Localization {
|
||||
async formatWithFallback(keys, method) {
|
||||
const translations = [];
|
||||
|
||||
for await (const ctx of this.ctxs) {
|
||||
const missingIds = keysFromContext(method, ctx, keys, translations);
|
||||
for await (const bundle of this.bundles) {
|
||||
const missingIds = keysFromBundle(method, bundle, keys, translations);
|
||||
|
||||
if (missingIds.size === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (AppConstants.NIGHTLY_BUILD || Cu.isInAutomation) {
|
||||
const locale = ctx.locales[0];
|
||||
const locale = bundle.locales[0];
|
||||
const ids = Array.from(missingIds).join(", ");
|
||||
if (Cu.isInAutomation) {
|
||||
throw new Error(`Missing translations in ${locale}: ${ids}`);
|
||||
@ -226,7 +235,10 @@ class Localization {
|
||||
*
|
||||
* // [
|
||||
* // { value: 'Hello, Mary!', attributes: null },
|
||||
* // { value: 'Welcome!', attributes: { title: 'Hello' } }
|
||||
* // {
|
||||
* // value: 'Welcome!',
|
||||
* // attributes: [ { name: "title", value: 'Hello' } ]
|
||||
* // }
|
||||
* // ]
|
||||
*
|
||||
* Returns a Promise resolving to an array of the translation strings.
|
||||
@ -236,7 +248,7 @@ class Localization {
|
||||
* @private
|
||||
*/
|
||||
formatMessages(keys) {
|
||||
return this.formatWithFallback(keys, messageFromContext);
|
||||
return this.formatWithFallback(keys, messageFromBundle);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -259,7 +271,7 @@ class Localization {
|
||||
* @returns {Promise<Array<string>>}
|
||||
*/
|
||||
formatValues(keys) {
|
||||
return this.formatWithFallback(keys, valueFromContext);
|
||||
return this.formatWithFallback(keys, valueFromBundle);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -327,8 +339,8 @@ class Localization {
|
||||
* @param {bool} eager - whether the I/O for new context should begin eagerly
|
||||
*/
|
||||
onChange(eager = false) {
|
||||
this.ctxs = CachedAsyncIterable.from(
|
||||
this.generateMessages(this.resourceIds));
|
||||
this.bundles = CachedAsyncIterable.from(
|
||||
this.generateBundles(this.resourceIds));
|
||||
if (eager) {
|
||||
// If the first app locale is the same as last fallback
|
||||
// it means that we have all resources in this locale, and
|
||||
@ -338,7 +350,7 @@ class Localization {
|
||||
const appLocale = Services.locale.appLocaleAsBCP47;
|
||||
const lastFallback = Services.locale.lastFallbackLocale;
|
||||
const prefetchCount = appLocale === lastFallback ? 1 : 2;
|
||||
this.ctxs.touchNext(prefetchCount);
|
||||
this.bundles.touchNext(prefetchCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -350,31 +362,31 @@ Localization.prototype.QueryInterface = ChromeUtils.generateQI([
|
||||
/**
|
||||
* Format the value of a message into a string.
|
||||
*
|
||||
* This function is passed as a method to `keysFromContext` and resolve
|
||||
* a value of a single L10n Entity using provided `MessageContext`.
|
||||
* This function is passed as a method to `keysFromBundle` and resolve
|
||||
* a value of a single L10n Entity using provided `FluentBundle`.
|
||||
*
|
||||
* If the function fails to retrieve the entity, it will return an ID of it.
|
||||
* If formatting fails, it will return a partially resolved entity.
|
||||
*
|
||||
* In both cases, an error is being added to the errors array.
|
||||
*
|
||||
* @param {MessageContext} ctx
|
||||
* @param {FluentBundle} bundle
|
||||
* @param {Array<Error>} errors
|
||||
* @param {string} id
|
||||
* @param {Object} args
|
||||
* @returns {string}
|
||||
* @private
|
||||
*/
|
||||
function valueFromContext(ctx, errors, id, args) {
|
||||
const msg = ctx.getMessage(id);
|
||||
return ctx.format(msg, args, errors);
|
||||
function valueFromBundle(bundle, errors, id, args) {
|
||||
const msg = bundle.getMessage(id);
|
||||
return bundle.format(msg, args, errors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format all public values of a message into a {value, attributes} object.
|
||||
*
|
||||
* This function is passed as a method to `keysFromContext` and resolve
|
||||
* a single L10n Entity using provided `MessageContext`.
|
||||
* This function is passed as a method to `keysFromBundle` and resolve
|
||||
* a single L10n Entity using provided `FluentBundle`.
|
||||
*
|
||||
* The function will return an object with a value and attributes of the
|
||||
* entity.
|
||||
@ -385,25 +397,25 @@ function valueFromContext(ctx, errors, id, args) {
|
||||
*
|
||||
* In both cases, an error is being added to the errors array.
|
||||
*
|
||||
* @param {MessageContext} ctx
|
||||
* @param {FluentBundle} bundle
|
||||
* @param {Array<Error>} errors
|
||||
* @param {String} id
|
||||
* @param {Object} args
|
||||
* @returns {Object}
|
||||
* @private
|
||||
*/
|
||||
function messageFromContext(ctx, errors, id, args) {
|
||||
const msg = ctx.getMessage(id);
|
||||
function messageFromBundle(bundle, errors, id, args) {
|
||||
const msg = bundle.getMessage(id);
|
||||
|
||||
const formatted = {
|
||||
value: ctx.format(msg, args, errors),
|
||||
value: bundle.format(msg, args, errors),
|
||||
attributes: null,
|
||||
};
|
||||
|
||||
if (msg.attrs) {
|
||||
formatted.attributes = [];
|
||||
for (const [name, attr] of Object.entries(msg.attrs)) {
|
||||
const value = ctx.format(attr, args, errors);
|
||||
const value = bundle.format(attr, args, errors);
|
||||
if (value !== null) {
|
||||
formatted.attributes.push({name, value});
|
||||
}
|
||||
@ -416,12 +428,12 @@ function messageFromContext(ctx, errors, id, args) {
|
||||
/**
|
||||
* This function is an inner function for `Localization.formatWithFallback`.
|
||||
*
|
||||
* It takes a `MessageContext`, list of l10n-ids and a method to be used for
|
||||
* key resolution (either `valueFromContext` or `messageFromContext`) and
|
||||
* optionally a value returned from `keysFromContext` executed against
|
||||
* another `MessageContext`.
|
||||
* It takes a `FluentBundle`, list of l10n-ids and a method to be used for
|
||||
* key resolution (either `valueFromBundle` or `messageFromBundle`) and
|
||||
* optionally a value returned from `keysFromBundle` executed against
|
||||
* another `FluentBundle`.
|
||||
*
|
||||
* The idea here is that if the previous `MessageContext` did not resolve
|
||||
* The idea here is that if the previous `FluentBundle` did not resolve
|
||||
* all keys, we're calling this function with the next context to resolve
|
||||
* the remaining ones.
|
||||
*
|
||||
@ -430,7 +442,7 @@ function messageFromContext(ctx, errors, id, args) {
|
||||
*
|
||||
* If it doesn't, it means that we have a good translation for this key and
|
||||
* we return it. If it does, we'll try to resolve the key using the passed
|
||||
* `MessageContext`.
|
||||
* `FluentBundle`.
|
||||
*
|
||||
* In the end, we fill the translations array, and return the Set with
|
||||
* missing ids.
|
||||
@ -438,14 +450,14 @@ function messageFromContext(ctx, errors, id, args) {
|
||||
* See `Localization.formatWithFallback` for more info on how this is used.
|
||||
*
|
||||
* @param {Function} method
|
||||
* @param {MessageContext} ctx
|
||||
* @param {FluentBundle} bundle
|
||||
* @param {Array<string>} keys
|
||||
* @param {{Array<{value: string, attributes: Object}>}} translations
|
||||
*
|
||||
* @returns {Set<string>}
|
||||
* @private
|
||||
*/
|
||||
function keysFromContext(method, ctx, keys, translations) {
|
||||
function keysFromBundle(method, bundle, keys, translations) {
|
||||
const messageErrors = [];
|
||||
const missingIds = new Set();
|
||||
|
||||
@ -454,9 +466,9 @@ function keysFromContext(method, ctx, keys, translations) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.hasMessage(id)) {
|
||||
if (bundle.hasMessage(id)) {
|
||||
messageErrors.length = 0;
|
||||
translations[i] = method(ctx, messageErrors, id, args);
|
||||
translations[i] = method(bundle, messageErrors, id, args);
|
||||
// XXX: Report resolver errors
|
||||
} else {
|
||||
missingIds.add(id);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,10 +1,9 @@
|
||||
The content of this directory is partially sourced from the fluent.js project.
|
||||
|
||||
The following files are affected:
|
||||
- MessageContext.jsm
|
||||
- Fluent.jsm
|
||||
- Localization.jsm
|
||||
- DOMLocalization.jsm
|
||||
- l10n.js
|
||||
|
||||
At the moment, the tool used to produce those files in fluent.js repository, doesn't
|
||||
fully align with how the code is structured here, so we perform a manual adjustments
|
||||
|
@ -492,7 +492,7 @@ At the moment Fluent supports two formatters that match JS Intl API counterparts
|
||||
|
||||
With time more formatters will be added.
|
||||
|
||||
__ http://projectfluent.org/fluent/guide/functions.html#partial-arguments
|
||||
__ https://projectfluent.org/fluent/guide/functions.html#partial-arguments
|
||||
__ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat
|
||||
__ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat
|
||||
|
||||
@ -668,10 +668,10 @@ since the class and file names may show up during debugging or profiling,
|
||||
below is a list of major components, each with a corresponding file in `/intl/l10n`
|
||||
modules in Gecko.
|
||||
|
||||
MessageContext
|
||||
FluentBundle
|
||||
--------------
|
||||
|
||||
MessageContext is the lowest level API. It's fully synchronous, contains a parser for the
|
||||
FluentBundle is the lowest level API. It's fully synchronous, contains a parser for the
|
||||
FTL file format and a resolver for the logic. It is not meant to be used by
|
||||
consumers directly.
|
||||
|
||||
@ -684,7 +684,7 @@ That part of the codebase is also the first that we'll be looking to port to Rus
|
||||
Localization
|
||||
------------
|
||||
|
||||
Localization is a higher level API which uses :js:`MessageContext` internally but
|
||||
Localization is a higher level API which uses :js:`FluentBundle` internally but
|
||||
provides a full layer of compound message formatting and robust error fall-backing.
|
||||
|
||||
It is intended for use in runtime code and contains all fundamental localization
|
||||
@ -714,11 +714,11 @@ L10nRegistry
|
||||
|
||||
L10nRegistry is our resource management service. It replaces :js:`ChromeRegistry` and
|
||||
maintains the state of resources packaged into the build and language packs,
|
||||
providing an asynchronous iterator of :js:`MessageContext` objects for a given locale set
|
||||
providing an asynchronous iterator of :js:`FluentBundle` objects for a given locale set
|
||||
and resources that the :js:`Localization` class uses.
|
||||
|
||||
|
||||
.. _Fluent: http://projectfluent.org/
|
||||
.. _Fluent: https://projectfluent.org/
|
||||
.. _DTD: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Tutorial/Localization
|
||||
.. _StringBundle: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Tutorial/Property_Files
|
||||
.. _Firefox Preferences: https://bugzilla.mozilla.org/show_bug.cgi?id=1415730
|
||||
@ -727,6 +727,6 @@ and resources that the :js:`Localization` class uses.
|
||||
.. _CLDR: http://cldr.unicode.org/
|
||||
.. _ICU: http://site.icu-project.org/
|
||||
.. _Unicode: https://www.unicode.org/
|
||||
.. _Fluent Syntax Guide: http://projectfluent.org/fluent/guide/
|
||||
.. _Fluent Syntax Guide: https://projectfluent.org/fluent/guide/
|
||||
.. _Pontoon: https://pontoon.mozilla.org/
|
||||
.. _Plural Rules: http://cldr.unicode.org/index/cldr-spec/plural-rules
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -6,9 +6,9 @@
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'DOMLocalization.jsm',
|
||||
'Fluent.jsm',
|
||||
'L10nRegistry.jsm',
|
||||
'Localization.jsm',
|
||||
'MessageContext.jsm',
|
||||
]
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
|
@ -13,12 +13,12 @@
|
||||
<![CDATA[
|
||||
const { DOMLocalization } =
|
||||
ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm", {});
|
||||
const { MessageContext } =
|
||||
ChromeUtils.import("resource://gre/modules/MessageContext.jsm", {});
|
||||
const { FluentBundle } =
|
||||
ChromeUtils.import("resource://gre/modules/Fluent.jsm", {});
|
||||
|
||||
async function * generateMessages(locales, resourceIds) {
|
||||
const mc = new MessageContext(locales);
|
||||
mc.addMessages(`
|
||||
const bundle = new FluentBundle(locales);
|
||||
bundle.addMessages(`
|
||||
file-menu =
|
||||
.label = File
|
||||
.accesskey = F
|
||||
@ -26,7 +26,7 @@ new-tab =
|
||||
.label = New Tab
|
||||
.accesskey = N
|
||||
`);
|
||||
yield mc;
|
||||
yield bundle;
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
@ -9,17 +9,17 @@
|
||||
"use strict";
|
||||
const { DOMLocalization } =
|
||||
ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm", {});
|
||||
const { MessageContext } =
|
||||
ChromeUtils.import("resource://gre/modules/MessageContext.jsm", {});
|
||||
const { FluentBundle } =
|
||||
ChromeUtils.import("resource://gre/modules/Fluent.jsm", {});
|
||||
|
||||
async function* mockGenerateMessages(locales, resourceIds) {
|
||||
const mc = new MessageContext(locales);
|
||||
mc.addMessages(`
|
||||
const bundle = new FluentBundle(locales);
|
||||
bundle.addMessages(`
|
||||
key1 = Value for Key 1
|
||||
|
||||
key2 = Value for <a>Key 2<a/>.
|
||||
`);
|
||||
yield mc;
|
||||
yield bundle;
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
@ -9,14 +9,14 @@
|
||||
"use strict";
|
||||
const { DOMLocalization } =
|
||||
ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm", {});
|
||||
const { MessageContext } =
|
||||
ChromeUtils.import("resource://gre/modules/MessageContext.jsm", {});
|
||||
const { FluentBundle } =
|
||||
ChromeUtils.import("resource://gre/modules/Fluent.jsm", {});
|
||||
|
||||
async function* mockGenerateMessages(locales, resourceIds) {
|
||||
const mc = new MessageContext(locales);
|
||||
mc.addMessages("title = Hello World");
|
||||
mc.addMessages("title2 = Hello Another World");
|
||||
yield mc;
|
||||
const bundle = new FluentBundle(locales);
|
||||
bundle.addMessages("title = Hello World");
|
||||
bundle.addMessages("title2 = Hello Another World");
|
||||
yield bundle;
|
||||
}
|
||||
|
||||
window.onload = async function() {
|
||||
|
@ -9,14 +9,14 @@
|
||||
"use strict";
|
||||
const { DOMLocalization } =
|
||||
ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm", {});
|
||||
const { MessageContext } =
|
||||
ChromeUtils.import("resource://gre/modules/MessageContext.jsm", {});
|
||||
const { FluentBundle } =
|
||||
ChromeUtils.import("resource://gre/modules/Fluent.jsm", {});
|
||||
|
||||
async function* mockGenerateMessages(locales, resourceIds) {
|
||||
const mc = new MessageContext(locales);
|
||||
mc.addMessages("title = <strong>Hello</strong> World");
|
||||
mc.addMessages(`title2 = This is <a data-l10n-name="link">a link</a>!`);
|
||||
yield mc;
|
||||
const bundle = new FluentBundle(locales);
|
||||
bundle.addMessages("title = <strong>Hello</strong> World");
|
||||
bundle.addMessages(`title2 = This is <a data-l10n-name="link">a link</a>!`);
|
||||
yield bundle;
|
||||
}
|
||||
|
||||
window.onload = async function() {
|
||||
|
@ -9,13 +9,13 @@
|
||||
"use strict";
|
||||
const { DOMLocalization } =
|
||||
ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm", {});
|
||||
const { MessageContext } =
|
||||
ChromeUtils.import("resource://gre/modules/MessageContext.jsm", {});
|
||||
const { FluentBundle } =
|
||||
ChromeUtils.import("resource://gre/modules/Fluent.jsm", {});
|
||||
|
||||
async function* mockGenerateMessages(locales, resourceIds) {
|
||||
const mc = new MessageContext(locales);
|
||||
const bundle = new FluentBundle(locales);
|
||||
// No translations!
|
||||
yield mc;
|
||||
yield bundle;
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
@ -9,13 +9,13 @@
|
||||
"use strict";
|
||||
const { DOMLocalization } =
|
||||
ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm", {});
|
||||
const { MessageContext } =
|
||||
ChromeUtils.import("resource://gre/modules/MessageContext.jsm", {});
|
||||
const { FluentBundle } =
|
||||
ChromeUtils.import("resource://gre/modules/Fluent.jsm", {});
|
||||
|
||||
async function* mockGenerateMessages(locales, resourceIds) {
|
||||
const mc = new MessageContext(locales);
|
||||
mc.addMessages(`title = Visit <a data-l10n-name="mozilla-link">Mozilla</a> or <a data-l10n-name="firefox-link">Firefox</a> website!`);
|
||||
yield mc;
|
||||
const bundle = new FluentBundle(locales);
|
||||
bundle.addMessages(`title = Visit <a data-l10n-name="mozilla-link">Mozilla</a> or <a data-l10n-name="firefox-link">Firefox</a> website!`);
|
||||
yield bundle;
|
||||
}
|
||||
|
||||
window.onload = async function() {
|
||||
|
@ -9,13 +9,13 @@
|
||||
"use strict";
|
||||
const { DOMLocalization } =
|
||||
ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm", {});
|
||||
const { MessageContext } =
|
||||
ChromeUtils.import("resource://gre/modules/MessageContext.jsm", {});
|
||||
const { FluentBundle } =
|
||||
ChromeUtils.import("resource://gre/modules/Fluent.jsm", {});
|
||||
|
||||
async function* mockGenerateMessages(locales, resourceIds) {
|
||||
const mc = new MessageContext(locales);
|
||||
mc.addMessages(`title = Visit <a data-l10n-name="mozilla-link">Mozilla</a> or <a data-l10n-name="firefox-link">Firefox</a> website!`);
|
||||
yield mc;
|
||||
const bundle = new FluentBundle(locales);
|
||||
bundle.addMessages(`title = Visit <a data-l10n-name="mozilla-link">Mozilla</a> or <a data-l10n-name="firefox-link">Firefox</a> website!`);
|
||||
yield bundle;
|
||||
}
|
||||
|
||||
window.onload = async function() {
|
||||
|
@ -9,19 +9,19 @@
|
||||
"use strict";
|
||||
const { DOMLocalization } =
|
||||
ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm", {});
|
||||
const { MessageContext } =
|
||||
ChromeUtils.import("resource://gre/modules/MessageContext.jsm", {});
|
||||
const { FluentBundle } =
|
||||
ChromeUtils.import("resource://gre/modules/Fluent.jsm", {});
|
||||
|
||||
async function* mockGenerateMessages(locales, resourceIds) {
|
||||
const mc = new MessageContext(locales);
|
||||
mc.addMessages(`
|
||||
const bundle = new FluentBundle(locales);
|
||||
bundle.addMessages(`
|
||||
key1 =
|
||||
.href = https://www.hacked.com
|
||||
|
||||
key2 =
|
||||
.href = https://pl.wikipedia.org
|
||||
`);
|
||||
yield mc;
|
||||
yield bundle;
|
||||
}
|
||||
|
||||
async function test() {
|
||||
|
@ -9,17 +9,17 @@
|
||||
"use strict";
|
||||
const { DOMLocalization } =
|
||||
ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm", {});
|
||||
const { MessageContext } =
|
||||
ChromeUtils.import("resource://gre/modules/MessageContext.jsm", {});
|
||||
const { FluentBundle } =
|
||||
ChromeUtils.import("resource://gre/modules/Fluent.jsm", {});
|
||||
|
||||
async function* mockGenerateMessages(locales, resourceIds) {
|
||||
const mc = new MessageContext(locales);
|
||||
mc.addMessages(`
|
||||
const bundle = new FluentBundle(locales);
|
||||
bundle.addMessages(`
|
||||
key1 = Translation For Key 1
|
||||
|
||||
key2 = Visit <a data-l10n-name="link">this link<a/>.
|
||||
`);
|
||||
yield mc;
|
||||
yield bundle;
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
@ -9,14 +9,14 @@
|
||||
"use strict";
|
||||
const { DOMLocalization } =
|
||||
ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm", {});
|
||||
const { MessageContext } =
|
||||
ChromeUtils.import("resource://gre/modules/MessageContext.jsm", {});
|
||||
const { FluentBundle } =
|
||||
ChromeUtils.import("resource://gre/modules/Fluent.jsm", {});
|
||||
|
||||
async function* mockGenerateMessages(locales, resourceIds) {
|
||||
const mc = new MessageContext(locales);
|
||||
mc.addMessages("title = Hello World");
|
||||
mc.addMessages("link =\n .title = Click me");
|
||||
yield mc;
|
||||
const bundle = new FluentBundle(locales);
|
||||
bundle.addMessages("title = Hello World");
|
||||
bundle.addMessages("link =\n .title = Click me");
|
||||
yield bundle;
|
||||
}
|
||||
|
||||
window.onload = async function() {
|
||||
|
@ -9,14 +9,14 @@
|
||||
"use strict";
|
||||
const { DOMLocalization } =
|
||||
ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm", {});
|
||||
const { MessageContext } =
|
||||
ChromeUtils.import("resource://gre/modules/MessageContext.jsm", {});
|
||||
const { FluentBundle } =
|
||||
ChromeUtils.import("resource://gre/modules/Fluent.jsm", {});
|
||||
|
||||
async function* mockGenerateMessages(locales, resourceIds) {
|
||||
const mc = new MessageContext(locales);
|
||||
mc.addMessages("title = Hello World");
|
||||
mc.addMessages("subtitle = Welcome to Fluent");
|
||||
yield mc;
|
||||
const bundle = new FluentBundle(locales);
|
||||
bundle.addMessages("title = Hello World");
|
||||
bundle.addMessages("subtitle = Welcome to FluentBundle");
|
||||
yield bundle;
|
||||
}
|
||||
|
||||
window.onload = async function() {
|
||||
@ -33,7 +33,7 @@
|
||||
|
||||
await domLoc.translateFragment(frag);
|
||||
is(h1.textContent, "Hello World");
|
||||
is(p1.textContent, "Welcome to Fluent");
|
||||
is(p1.textContent, "Welcome to FluentBundle");
|
||||
|
||||
SimpleTest.finish();
|
||||
};
|
||||
|
@ -9,14 +9,14 @@
|
||||
"use strict";
|
||||
const { DOMLocalization } =
|
||||
ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm", {});
|
||||
const { MessageContext } =
|
||||
ChromeUtils.import("resource://gre/modules/MessageContext.jsm", {});
|
||||
const { FluentBundle } =
|
||||
ChromeUtils.import("resource://gre/modules/Fluent.jsm", {});
|
||||
|
||||
async function* mockGenerateMessages(locales, resourceIds) {
|
||||
const mc = new MessageContext(locales);
|
||||
mc.addMessages("title = Hello World");
|
||||
mc.addMessages("title2 = Hello Another World");
|
||||
yield mc;
|
||||
const bundle = new FluentBundle(locales);
|
||||
bundle.addMessages("title = Hello World");
|
||||
bundle.addMessages("title2 = Hello Another World");
|
||||
yield bundle;
|
||||
}
|
||||
|
||||
window.onload = async function() {
|
||||
|
@ -17,7 +17,7 @@ L10nRegistry.load = async function(url) {
|
||||
};
|
||||
|
||||
add_task(function test_methods_presence() {
|
||||
equal(typeof L10nRegistry.generateContexts, "function");
|
||||
equal(typeof L10nRegistry.generateBundles, "function");
|
||||
equal(typeof L10nRegistry.getAvailableLocales, "function");
|
||||
equal(typeof L10nRegistry.registerSource, "function");
|
||||
equal(typeof L10nRegistry.updateSource, "function");
|
||||
@ -32,9 +32,9 @@ add_task(async function test_empty_resourceids() {
|
||||
const source = new FileSource("test", ["en-US"], "/localization/{locale}");
|
||||
L10nRegistry.registerSource(source);
|
||||
|
||||
const ctxs = L10nRegistry.generateContexts(["en-US"], []);
|
||||
const bundles = L10nRegistry.generateBundles(["en-US"], []);
|
||||
|
||||
const done = (await ctxs.next()).done;
|
||||
const done = (await bundles.next()).done;
|
||||
|
||||
equal(done, true);
|
||||
|
||||
@ -48,9 +48,9 @@ add_task(async function test_empty_resourceids() {
|
||||
add_task(async function test_empty_sources() {
|
||||
fs = {};
|
||||
|
||||
const ctxs = L10nRegistry.generateContexts(["en-US"], []);
|
||||
const bundles = L10nRegistry.generateBundles(["en-US"], []);
|
||||
|
||||
const done = (await ctxs.next()).done;
|
||||
const done = (await bundles.next()).done;
|
||||
|
||||
equal(done, true);
|
||||
|
||||
@ -70,11 +70,11 @@ add_task(async function test_methods_calling() {
|
||||
const source = new FileSource("test", ["en-US"], "/localization/{locale}");
|
||||
L10nRegistry.registerSource(source);
|
||||
|
||||
const ctxs = L10nRegistry.generateContexts(["en-US"], ["/browser/menu.ftl"]);
|
||||
const bundles = L10nRegistry.generateBundles(["en-US"], ["/browser/menu.ftl"]);
|
||||
|
||||
const ctx = (await ctxs.next()).value;
|
||||
const bundle = (await bundles.next()).value;
|
||||
|
||||
equal(ctx.hasMessage("key"), true);
|
||||
equal(bundle.hasMessage("key"), true);
|
||||
|
||||
// cleanup
|
||||
L10nRegistry.sources.clear();
|
||||
@ -100,18 +100,18 @@ add_task(async function test_has_one_source() {
|
||||
|
||||
// returns a single context
|
||||
|
||||
let ctxs = L10nRegistry.generateContexts(["en-US"], ["test.ftl"]);
|
||||
let ctx0 = (await ctxs.next()).value;
|
||||
equal(ctx0.hasMessage("key"), true);
|
||||
let bundles = L10nRegistry.generateBundles(["en-US"], ["test.ftl"]);
|
||||
let bundle0 = (await bundles.next()).value;
|
||||
equal(bundle0.hasMessage("key"), true);
|
||||
|
||||
equal((await ctxs.next()).done, true);
|
||||
equal((await bundles.next()).done, true);
|
||||
|
||||
|
||||
// returns no contexts for missing locale
|
||||
|
||||
ctxs = L10nRegistry.generateContexts(["pl"], ["test.ftl"]);
|
||||
bundles = L10nRegistry.generateBundles(["pl"], ["test.ftl"]);
|
||||
|
||||
equal((await ctxs.next()).done, true);
|
||||
equal((await bundles.next()).done, true);
|
||||
|
||||
// cleanup
|
||||
L10nRegistry.sources.clear();
|
||||
@ -142,32 +142,32 @@ add_task(async function test_has_two_sources() {
|
||||
|
||||
// returns correct contexts for en-US
|
||||
|
||||
let ctxs = L10nRegistry.generateContexts(["en-US"], ["test.ftl"]);
|
||||
let ctx0 = (await ctxs.next()).value;
|
||||
let bundles = L10nRegistry.generateBundles(["en-US"], ["test.ftl"]);
|
||||
let bundle0 = (await bundles.next()).value;
|
||||
|
||||
equal(ctx0.hasMessage("key"), true);
|
||||
let msg = ctx0.getMessage("key");
|
||||
equal(ctx0.format(msg), "platform value");
|
||||
equal(bundle0.hasMessage("key"), true);
|
||||
let msg = bundle0.getMessage("key");
|
||||
equal(bundle0.format(msg), "platform value");
|
||||
|
||||
equal((await ctxs.next()).done, true);
|
||||
equal((await bundles.next()).done, true);
|
||||
|
||||
|
||||
// returns correct contexts for [pl, en-US]
|
||||
|
||||
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");
|
||||
bundles = L10nRegistry.generateBundles(["pl", "en-US"], ["test.ftl"]);
|
||||
bundle0 = (await bundles.next()).value;
|
||||
equal(bundle0.locales[0], "pl");
|
||||
equal(bundle0.hasMessage("key"), true);
|
||||
let msg0 = bundle0.getMessage("key");
|
||||
equal(bundle0.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");
|
||||
let bundle1 = (await bundles.next()).value;
|
||||
equal(bundle1.locales[0], "en-US");
|
||||
equal(bundle1.hasMessage("key"), true);
|
||||
let msg1 = bundle1.getMessage("key");
|
||||
equal(bundle1.format(msg1), "platform value");
|
||||
|
||||
equal((await ctxs.next()).done, true);
|
||||
equal((await bundles.next()).done, true);
|
||||
|
||||
// cleanup
|
||||
L10nRegistry.sources.clear();
|
||||
@ -221,20 +221,20 @@ add_task(async function test_override() {
|
||||
equal(L10nRegistry.sources.size, 2);
|
||||
equal(L10nRegistry.sources.has("langpack-pl"), true);
|
||||
|
||||
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");
|
||||
let bundles = L10nRegistry.generateBundles(["pl"], ["test.ftl"]);
|
||||
let bundle0 = (await bundles.next()).value;
|
||||
equal(bundle0.locales[0], "pl");
|
||||
equal(bundle0.hasMessage("key"), true);
|
||||
let msg0 = bundle0.getMessage("key");
|
||||
equal(bundle0.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");
|
||||
let bundle1 = (await bundles.next()).value;
|
||||
equal(bundle1.locales[0], "pl");
|
||||
equal(bundle1.hasMessage("key"), true);
|
||||
let msg1 = bundle1.getMessage("key");
|
||||
equal(bundle1.format(msg1), "value");
|
||||
|
||||
equal((await ctxs.next()).done, true);
|
||||
equal((await bundles.next()).done, true);
|
||||
|
||||
// cleanup
|
||||
L10nRegistry.sources.clear();
|
||||
@ -253,12 +253,12 @@ add_task(async function test_updating() {
|
||||
"/data/locales/pl/test.ftl": "key = value",
|
||||
};
|
||||
|
||||
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");
|
||||
let bundles = L10nRegistry.generateBundles(["pl"], ["test.ftl"]);
|
||||
let bundle0 = (await bundles.next()).value;
|
||||
equal(bundle0.locales[0], "pl");
|
||||
equal(bundle0.hasMessage("key"), true);
|
||||
let msg0 = bundle0.getMessage("key");
|
||||
equal(bundle0.format(msg0), "value");
|
||||
|
||||
|
||||
const newSource = new IndexedFileSource("langpack-pl", ["pl"], "/data/locales/{locale}/", [
|
||||
@ -268,10 +268,10 @@ add_task(async function test_updating() {
|
||||
L10nRegistry.updateSource(newSource);
|
||||
|
||||
equal(L10nRegistry.sources.size, 1);
|
||||
ctxs = L10nRegistry.generateContexts(["pl"], ["test.ftl"]);
|
||||
ctx0 = (await ctxs.next()).value;
|
||||
msg0 = ctx0.getMessage("key");
|
||||
equal(ctx0.format(msg0), "new value");
|
||||
bundles = L10nRegistry.generateBundles(["pl"], ["test.ftl"]);
|
||||
bundle0 = (await bundles.next()).value;
|
||||
msg0 = bundle0.getMessage("key");
|
||||
equal(bundle0.format(msg0), "new value");
|
||||
|
||||
// cleanup
|
||||
L10nRegistry.sources.clear();
|
||||
@ -298,20 +298,20 @@ add_task(async function test_removing() {
|
||||
equal(L10nRegistry.sources.size, 2);
|
||||
equal(L10nRegistry.sources.has("langpack-pl"), true);
|
||||
|
||||
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");
|
||||
let bundles = L10nRegistry.generateBundles(["pl"], ["test.ftl"]);
|
||||
let bundle0 = (await bundles.next()).value;
|
||||
equal(bundle0.locales[0], "pl");
|
||||
equal(bundle0.hasMessage("key"), true);
|
||||
let msg0 = bundle0.getMessage("key");
|
||||
equal(bundle0.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");
|
||||
let bundle1 = (await bundles.next()).value;
|
||||
equal(bundle1.locales[0], "pl");
|
||||
equal(bundle1.hasMessage("key"), true);
|
||||
let msg1 = bundle1.getMessage("key");
|
||||
equal(bundle1.format(msg1), "value");
|
||||
|
||||
equal((await ctxs.next()).done, true);
|
||||
equal((await bundles.next()).done, true);
|
||||
|
||||
// Remove langpack
|
||||
|
||||
@ -320,14 +320,14 @@ add_task(async function test_removing() {
|
||||
equal(L10nRegistry.sources.size, 1);
|
||||
equal(L10nRegistry.sources.has("langpack-pl"), false);
|
||||
|
||||
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");
|
||||
bundles = L10nRegistry.generateBundles(["pl"], ["test.ftl"]);
|
||||
bundle0 = (await bundles.next()).value;
|
||||
equal(bundle0.locales[0], "pl");
|
||||
equal(bundle0.hasMessage("key"), true);
|
||||
msg0 = bundle0.getMessage("key");
|
||||
equal(bundle0.format(msg0), "value");
|
||||
|
||||
equal((await ctxs.next()).done, true);
|
||||
equal((await bundles.next()).done, true);
|
||||
|
||||
// Remove app source
|
||||
|
||||
@ -335,8 +335,8 @@ add_task(async function test_removing() {
|
||||
|
||||
equal(L10nRegistry.sources.size, 0);
|
||||
|
||||
ctxs = L10nRegistry.generateContexts(["pl"], ["test.ftl"]);
|
||||
equal((await ctxs.next()).done, true);
|
||||
bundles = L10nRegistry.generateBundles(["pl"], ["test.ftl"]);
|
||||
equal((await bundles.next()).done, true);
|
||||
|
||||
// cleanup
|
||||
L10nRegistry.sources.clear();
|
||||
@ -368,23 +368,23 @@ add_task(async function test_missing_file() {
|
||||
|
||||
// returns a single context
|
||||
|
||||
let ctxs = L10nRegistry.generateContexts(["en-US"], ["test.ftl", "test2.ftl"]);
|
||||
let bundles = L10nRegistry.generateBundles(["en-US"], ["test.ftl", "test2.ftl"]);
|
||||
|
||||
// First permutation:
|
||||
// [platform, platform] - both present
|
||||
let ctx1 = (await ctxs.next());
|
||||
equal(ctx1.value.hasMessage("key"), true);
|
||||
let bundle1 = (await bundles.next());
|
||||
equal(bundle1.value.hasMessage("key"), true);
|
||||
|
||||
// Second permutation skipped:
|
||||
// [platform, app] - second missing
|
||||
// Third permutation:
|
||||
// [app, platform] - both present
|
||||
let ctx2 = (await ctxs.next());
|
||||
equal(ctx2.value.hasMessage("key"), true);
|
||||
let bundle2 = (await bundles.next());
|
||||
equal(bundle2.value.hasMessage("key"), true);
|
||||
|
||||
// Fourth permutation skipped:
|
||||
// [app, app] - second missing
|
||||
equal((await ctxs.next()).done, true);
|
||||
equal((await bundles.next()).done, true);
|
||||
|
||||
// cleanup
|
||||
L10nRegistry.sources.clear();
|
||||
@ -432,19 +432,19 @@ add_task(async function test_parallel_io() {
|
||||
|
||||
// returns a single context
|
||||
|
||||
let ctxs = L10nRegistry.generateContexts(["en-US"], ["slow-file.ftl", "test.ftl", "test2.ftl"]);
|
||||
let bundles = L10nRegistry.generateBundles(["en-US"], ["slow-file.ftl", "test.ftl", "test2.ftl"]);
|
||||
|
||||
equal(fetchIndex.size, 0);
|
||||
|
||||
let ctx0 = await ctxs.next();
|
||||
let bundle0 = await bundles.next();
|
||||
|
||||
equal(ctx0.done, false);
|
||||
equal(bundle0.done, false);
|
||||
|
||||
equal((await ctxs.next()).done, true);
|
||||
equal((await bundles.next()).done, true);
|
||||
|
||||
// When requested again, the cache should make the load operation not
|
||||
// increase the fetchedIndex count
|
||||
L10nRegistry.generateContexts(["en-US"], ["test.ftl", "test2.ftl", "slow-file.ftl"]);
|
||||
L10nRegistry.generateBundles(["en-US"], ["test.ftl", "test2.ftl", "slow-file.ftl"]);
|
||||
|
||||
// cleanup
|
||||
L10nRegistry.sources.clear();
|
||||
|
@ -30,7 +30,7 @@ add_task(async function test_methods_calling() {
|
||||
L10nRegistry.registerSource(source);
|
||||
|
||||
async function* generateMessages(resIds) {
|
||||
yield * await L10nRegistry.generateContexts(["de", "en-US"], resIds);
|
||||
yield * await L10nRegistry.generateBundles(["de", "en-US"], resIds);
|
||||
}
|
||||
|
||||
const l10n = new Localization([
|
||||
@ -76,7 +76,7 @@ key = { PLATFORM() ->
|
||||
L10nRegistry.registerSource(source);
|
||||
|
||||
async function* generateMessages(resIds) {
|
||||
yield * await L10nRegistry.generateContexts(["en-US"], resIds);
|
||||
yield * await L10nRegistry.generateBundles(["en-US"], resIds);
|
||||
}
|
||||
|
||||
const l10n = new Localization([
|
||||
@ -111,7 +111,7 @@ add_task(async function test_add_remove_resourceIds() {
|
||||
L10nRegistry.registerSource(source);
|
||||
|
||||
async function* generateMessages(resIds) {
|
||||
yield * await L10nRegistry.generateContexts(["en-US"], resIds);
|
||||
yield * await L10nRegistry.generateBundles(["en-US"], resIds);
|
||||
}
|
||||
|
||||
const l10n = new Localization(["/browser/menu.ftl"], generateMessages);
|
||||
|
@ -2,32 +2,32 @@
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function run_test() {
|
||||
const { MessageContext } = ChromeUtils.import("resource://gre/modules/MessageContext.jsm", {});
|
||||
const { FluentBundle } = ChromeUtils.import("resource://gre/modules/Fluent.jsm", {});
|
||||
|
||||
test_methods_presence(MessageContext);
|
||||
test_methods_calling(MessageContext);
|
||||
test_methods_presence(FluentBundle);
|
||||
test_methods_calling(FluentBundle);
|
||||
|
||||
ok(true);
|
||||
}
|
||||
|
||||
function test_methods_presence(MessageContext) {
|
||||
const ctx = new MessageContext(["en-US", "pl"]);
|
||||
equal(typeof ctx.addMessages, "function");
|
||||
equal(typeof ctx.format, "function");
|
||||
function test_methods_presence(FluentBundle) {
|
||||
const bundle = new FluentBundle(["en-US", "pl"]);
|
||||
equal(typeof bundle.addMessages, "function");
|
||||
equal(typeof bundle.format, "function");
|
||||
}
|
||||
|
||||
function test_methods_calling(MessageContext) {
|
||||
const ctx = new MessageContext(["en-US", "pl"], {
|
||||
function test_methods_calling(FluentBundle) {
|
||||
const bundle = new FluentBundle(["en-US", "pl"], {
|
||||
useIsolating: false,
|
||||
});
|
||||
ctx.addMessages("key = Value");
|
||||
bundle.addMessages("key = Value");
|
||||
|
||||
const msg = ctx.getMessage("key");
|
||||
equal(ctx.format(msg), "Value");
|
||||
const msg = bundle.getMessage("key");
|
||||
equal(bundle.format(msg), "Value");
|
||||
|
||||
ctx.addMessages("key2 = Hello { $name }");
|
||||
bundle.addMessages("key2 = Hello { $name }");
|
||||
|
||||
const msg2 = ctx.getMessage("key2");
|
||||
equal(ctx.format(msg2, { name: "Amy" }), "Hello Amy");
|
||||
const msg2 = bundle.getMessage("key2");
|
||||
equal(bundle.format(msg2, { name: "Amy" }), "Hello Amy");
|
||||
ok(true);
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ key = This is a single message
|
||||
L10nRegistry.registerSource(source);
|
||||
|
||||
return async function* generateMessages(resIds) {
|
||||
yield * await L10nRegistry.generateContexts(["de"], resIds);
|
||||
yield * await L10nRegistry.generateBundles(["de"], resIds);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -120,16 +120,16 @@ add_task(async function() {
|
||||
|
||||
{
|
||||
// Toolkit string
|
||||
let ctxs = L10nRegistry.generateContexts(["und"], ["toolkit_test.ftl"]);
|
||||
let ctx0 = (await ctxs.next()).value;
|
||||
equal(ctx0.hasMessage("message-id1"), true);
|
||||
let bundles = L10nRegistry.generateBundles(["und"], ["toolkit_test.ftl"]);
|
||||
let bundle0 = (await bundles.next()).value;
|
||||
equal(bundle0.hasMessage("message-id1"), true);
|
||||
}
|
||||
|
||||
{
|
||||
// Browser string
|
||||
let ctxs = L10nRegistry.generateContexts(["und"], ["browser.ftl"]);
|
||||
let ctx0 = (await ctxs.next()).value;
|
||||
equal(ctx0.hasMessage("message-browser"), true);
|
||||
let bundles = L10nRegistry.generateBundles(["und"], ["browser.ftl"]);
|
||||
let bundle0 = (await bundles.next()).value;
|
||||
equal(bundle0.hasMessage("message-browser"), true);
|
||||
}
|
||||
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user