Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions fluent-dom/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ can install it from the npm registry or use it as a standalone script (as the

The `DOMLocalization` constructor provides the core functionality of
full-fallback ready message formatting. It uses a lazy-resolved
`MessageContext` objects from the `fluent` package to format messages.
`FluentBundle` objects from the `fluent` package to format messages.

On top of that, `DOMLocalization` can localize any DOMFragment by
identifying localizable elements with `data-l10n-id` and translating them.
Expand All @@ -27,7 +27,7 @@ import { DOMLocalization } from 'fluent-dom'
const l10n = new DOMLocalization(MutationObserver, [
'/browser/main.ftl',
'/toolkit/menu.ftl'
], generateMessages);
], generateBundles);

l10n.connectRoot(document.documentElement);

Expand All @@ -47,15 +47,15 @@ class that provides just the API needed to format messages in the running code.
```javascript
import { Localization } from 'fluent-dom'

function *generateMessages() {
// Some lazy logic for yielding MessageContexts.
yield *[ctx1, ctx2];
function *generateBundles() {
// Some lazy logic for yielding FluentBundles.
yield *[bundle1, bundle2];
}

const l10n = new Localization(document, [
'/browser/main.ftl',
'/toolkit/menu.ftl'
], generateMessages);
], generateBundles);

async function main() {
const msg = await l10n.formatValue('welcome', { name: 'Anna' });
Expand Down
10 changes: 5 additions & 5 deletions fluent-dom/src/dom_localization.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ const L10N_ELEMENT_QUERY = `[${L10NID_ATTR_NAME}]`;
*/
export default 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();
Expand Down
80 changes: 40 additions & 40 deletions fluent-dom/src/localization.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@ import { CachedAsyncIterable } from "cached-iterable";
/**
* 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.
*/
export default 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) {
constructor(resourceIds = [], generateBundles) {
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));
}

addResourceIds(resourceIds) {
Expand All @@ -39,7 +39,7 @@ export default 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.
*
Expand All @@ -51,15 +51,15 @@ export default 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 (typeof console !== "undefined") {
const locale = ctx.locales[0];
const locale = bundle.locales[0];
const ids = Array.from(missingIds).join(", ");
console.warn(`Missing translations in ${locale}: ${ids}`);
}
Expand Down Expand Up @@ -92,7 +92,7 @@ export default class Localization {
* @private
*/
formatMessages(keys) {
return this.formatWithFallback(keys, messageFromContext);
return this.formatWithFallback(keys, messageFromBundle);
}

/**
Expand All @@ -115,7 +115,7 @@ export default class Localization {
* @returns {Promise<Array<string>>}
*/
formatValues(keys) {
return this.formatWithFallback(keys, valueFromContext);
return this.formatWithFallback(keys, valueFromBundle);
}

/**
Expand Down Expand Up @@ -154,40 +154,40 @@ export default class Localization {
* that language negotiation or available resources changed.
*/
onChange() {
this.ctxs = CachedAsyncIterable.from(
this.generateMessages(this.resourceIds));
this.ctxs.touchNext(2);
this.bundles = CachedAsyncIterable.from(
this.generateBundles(this.resourceIds));
this.bundles.touchNext(2);
}
}

/**
* 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.
Expand All @@ -198,25 +198,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});
}
Expand All @@ -229,12 +229,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.
*
Expand All @@ -243,22 +243,22 @@ 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.
*
* 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();

Expand All @@ -267,9 +267,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);
Expand Down
2 changes: 1 addition & 1 deletion fluent-dom/src/overlay.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,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;
Expand Down
8 changes: 4 additions & 4 deletions fluent-dom/test/dom_localization_test.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import assert from "assert";
import { MessageContext } from "../../fluent/src/index";
import { FluentBundle } from "../../fluent/src/index";
import DOMLocalization from "../src/dom_localization";

async function* mockGenerateMessages(resourceIds) {
const mc = new MessageContext(["en-US"]);
mc.addMessages("key1 = Key 1");
yield mc;
const bundle = new FluentBundle(["en-US"]);
bundle.addMessages("key1 = Key 1");
yield bundle;
}

suite("translateFragment", function() {
Expand Down
8 changes: 4 additions & 4 deletions fluent-dom/test/localization_test.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import assert from "assert";
import { MessageContext } from "../../fluent/src/index";
import { FluentBundle } from "../../fluent/src/index";
import Localization from "../src/localization";

async function* mockGenerateMessages(resourceIds) {
const mc = new MessageContext(["en-US"]);
mc.addMessages("key1 = Key 1");
yield mc;
const bundle = new FluentBundle(["en-US"]);
bundle.addMessages("key1 = Key 1");
yield bundle;
}

suite("formatMessages", function() {
Expand Down
2 changes: 1 addition & 1 deletion fluent-gecko/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ natural language.
The `fluent-gecko` build system produces `*.jsm` files which are ready to be
used as Gecko modules.

`Fluent.jsm` exports the `MessageContext` constructor which provides the
`Fluent.jsm` exports the `FluentBundle` constructor which provides the
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zbraniecki Do we have a Fluent.jsm in fluent-gecko?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we have MessageContext.jsm

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, of course not. Why would we? :( Sorry, Yeah, we have MessageContext.jsm, and I'm happy to rename it to FluentBundle.jsm

core functionality of formatting translations from FTL files. See the
[README][] of the main `fluent` package for more information.

Expand Down
6 changes: 3 additions & 3 deletions fluent-gecko/makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ PACKAGE := fluent-gecko

include ../common.mk

build: MessageContext.jsm Localization.jsm DOMLocalization.jsm l10n.js
build: Fluent.jsm Localization.jsm DOMLocalization.jsm l10n.js

MessageContext.jsm: $(SOURCES)
Fluent.jsm: $(SOURCES)
@rollup $(CURDIR)/src/message_context.js \
--config ./xpcom_config.js \
--output.file ./dist/$@
Expand All @@ -29,7 +29,7 @@ l10n.js: $(SOURCES)
@echo -e " $(OK) $@ built"

clean:
@rm -f ./dist/MessageContext.jsm
@rm -f ./dist/FluentBundle.jsm
@rm -f ./dist/Localization.jsm
@rm -f ./dist/DOMLocalization.jsm
@rm -f ./dist/l10n.js
Expand Down
8 changes: 4 additions & 4 deletions fluent-gecko/src/dom_localization.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import DOMLocalization from "../../fluent-dom/src/dom_localization";
/**
* 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 requestedLocales = Services.locale.getRequestedLocales();
const availableLocales = L10nRegistry.getAvailableLocales();
const defaultLocale = Services.locale.defaultLocale;
Expand All @@ -25,9 +25,9 @@ class GeckoDOMLocalization extends DOMLocalization {
constructor(
windowElement,
resourceIds,
generateMessages = defaultGenerateMessages
generateBundles = defaultGenerateBundles
) {
super(windowElement, resourceIds, generateMessages);
super(windowElement, resourceIds, generateBundles);
}
}

Expand Down
2 changes: 1 addition & 1 deletion fluent-gecko/src/l10n.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
document.l10n = new DOMLocalization(window, resourceIds);

// trigger first context to be fetched eagerly
document.l10n.ctxs.touchNext();
document.l10n.bundles.touchNext();

document.l10n.ready = documentReady().then(() => {
document.l10n.registerObservers();
Expand Down
Loading