зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1552714 - Migrate all remaining callsites to use WebIDL DOMLocalization and remove mozIDOMLocalization and DOMLocalization.jsm. r=smaug
Differential Revision: https://phabricator.services.mozilla.com/D33200 --HG-- rename : intl/l10n/test/dom_overlays/test_same_id.html => dom/l10n/tests/mochitest/domoverlays/test_same_id.html rename : intl/l10n/test/dom_overlays/test_same_id_args.html => dom/l10n/tests/mochitest/domoverlays/test_same_id_args.html extra : moz-landing-system : lando
This commit is contained in:
Родитель
65d6e98550
Коммит
0075d6e610
|
@ -3,8 +3,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "DOMLocalization",
|
||||
"resource://gre/modules/DOMLocalization.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "FxAccounts",
|
||||
"resource://gre/modules/FxAccounts.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Services",
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
"use strict";
|
||||
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const {DOMLocalization} = ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["fetch"]);
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"plugin:mozilla/browser-test",
|
||||
],
|
||||
"globals": {
|
||||
"DOMLocalization": false,
|
||||
}
|
||||
};
|
|
@ -3,6 +3,8 @@
|
|||
[domoverlays/test_text_children.html]
|
||||
[domoverlays/test_extra_text_markup.html]
|
||||
[domoverlays/test_domoverlays.xul]
|
||||
[domoverlays/test_same_id.html]
|
||||
[domoverlays/test_same_id_args.html]
|
||||
|
||||
[mutations/test_append_content_post_dcl.html]
|
||||
[mutations/test_append_content_pre_dcl.html]
|
||||
|
|
|
@ -1,467 +0,0 @@
|
|||
/* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
|
||||
|
||||
/* Copyright 2017 Mozilla Foundation and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* Based on fluent-dom@fa25466f (October 12, 2018) */
|
||||
/* global DOMOverlays */
|
||||
|
||||
const { Localization } =
|
||||
ChromeUtils.import("resource://gre/modules/Localization.jsm");
|
||||
const { Services } =
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const L10NID_ATTR_NAME = "data-l10n-id";
|
||||
const L10NARGS_ATTR_NAME = "data-l10n-args";
|
||||
|
||||
const L10N_ELEMENT_QUERY = `[${L10NID_ATTR_NAME}]`;
|
||||
|
||||
function reportDOMOverlayErrors(errors) {
|
||||
for (let error of errors) {
|
||||
switch (error.code) {
|
||||
case DOMOverlays.ERROR_FORBIDDEN_TYPE: {
|
||||
console.warn(
|
||||
`An element of forbidden type "${error.translatedElementName}" was found in ` +
|
||||
"the translation. Only safe text-level elements and elements with " +
|
||||
"data-l10n-name are allowed."
|
||||
);
|
||||
break;
|
||||
}
|
||||
case DOMOverlays.ERROR_NAMED_ELEMENT_MISSING: {
|
||||
console.warn(
|
||||
`An element named "${error.l10nName}" wasn't found in the source.`
|
||||
);
|
||||
break;
|
||||
}
|
||||
case DOMOverlays.ERROR_NAMED_ELEMENT_TYPE_MISMATCH: {
|
||||
console.warn(
|
||||
`An element named "${error.l10nName}" was found in the translation ` +
|
||||
`but its type ${error.translatedElementName} didn't match the ` +
|
||||
`element found in the source (${error.sourceElementName}).`
|
||||
);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
console.warn(`Unknown error ${error.code} happend while translation an element.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `DOMLocalization` class is responsible for fetching resources and
|
||||
* formatting translations.
|
||||
*
|
||||
* It implements the fallback strategy in case of errors encountered during the
|
||||
* formatting of translations and methods for observing DOM
|
||||
* trees with a `MutationObserver`.
|
||||
*/
|
||||
class DOMLocalization extends Localization {
|
||||
/**
|
||||
* @param {Array<String>} resourceIds - List of resource IDs
|
||||
* @param {Function} generateBundles - Function that returns a
|
||||
* generator over FluentBundles
|
||||
* @returns {DOMLocalization}
|
||||
*/
|
||||
constructor(resourceIds, generateBundles) {
|
||||
super(resourceIds, generateBundles);
|
||||
|
||||
// A Set of DOM trees observed by the `MutationObserver`.
|
||||
this.roots = new Set();
|
||||
// requestAnimationFrame handler.
|
||||
this.pendingrAF = null;
|
||||
// list of elements pending for translation.
|
||||
this.pendingElements = new Set();
|
||||
this.windowElement = null;
|
||||
this.mutationObserver = null;
|
||||
|
||||
this.observerConfig = {
|
||||
attribute: true,
|
||||
characterData: false,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
attributeFilter: [L10NID_ATTR_NAME, L10NARGS_ATTR_NAME],
|
||||
};
|
||||
}
|
||||
|
||||
onChange(eager = false) {
|
||||
super.onChange(eager);
|
||||
this.translateRoots();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the `data-l10n-id` and `data-l10n-args` attributes on DOM elements.
|
||||
* FluentDOM makes use of mutation observers to detect changes
|
||||
* to `data-l10n-*` attributes and translate elements asynchronously.
|
||||
* `setAttributes` is a convenience method which allows to translate
|
||||
* DOM elements declaratively.
|
||||
*
|
||||
* You should always prefer to use `data-l10n-id` on elements (statically in
|
||||
* HTML or dynamically via `setAttributes`) over manually retrieving
|
||||
* translations with `format`. The use of attributes ensures that the
|
||||
* elements can be retranslated when the user changes their language
|
||||
* preferences.
|
||||
*
|
||||
* ```javascript
|
||||
* localization.setAttributes(
|
||||
* document.querySelector('#welcome'), 'hello', { who: 'world' }
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* This will set the following attributes on the `#welcome` element.
|
||||
* The MutationObserver will pick up this change and will localize the element
|
||||
* asynchronously.
|
||||
*
|
||||
* ```html
|
||||
* <p id='welcome'
|
||||
* data-l10n-id='hello'
|
||||
* data-l10n-args='{"who": "world"}'>
|
||||
* </p>
|
||||
* ```
|
||||
*
|
||||
* @param {Element} element - Element to set attributes on
|
||||
* @param {string} id - l10n-id string
|
||||
* @param {Object<string, string>} args - KVP list of l10n arguments
|
||||
* @returns {Element}
|
||||
*/
|
||||
setAttributes(element, id, args = null) {
|
||||
if (element.getAttribute(L10NID_ATTR_NAME) !== id) {
|
||||
element.setAttribute(L10NID_ATTR_NAME, id);
|
||||
}
|
||||
if (args) {
|
||||
let argsString = JSON.stringify(args);
|
||||
if (argsString !== element.getAttribute(L10NARGS_ATTR_NAME)) {
|
||||
element.setAttribute(L10NARGS_ATTR_NAME, argsString);
|
||||
}
|
||||
} else {
|
||||
element.removeAttribute(L10NARGS_ATTR_NAME);
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the `data-l10n-*` attributes from DOM elements.
|
||||
*
|
||||
* ```javascript
|
||||
* localization.getAttributes(
|
||||
* document.querySelector('#welcome')
|
||||
* );
|
||||
* // -> { id: 'hello', args: { who: 'world' } }
|
||||
* ```
|
||||
*
|
||||
* @param {Element} element - HTML element
|
||||
* @returns {{id: string, args: Object}}
|
||||
*/
|
||||
getAttributes(element) {
|
||||
return {
|
||||
id: element.getAttribute(L10NID_ATTR_NAME),
|
||||
args: JSON.parse(element.getAttribute(L10NARGS_ATTR_NAME) || null),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Add `newRoot` to the list of roots managed by this `DOMLocalization`.
|
||||
*
|
||||
* Additionally, if this `DOMLocalization` has an observer, start observing
|
||||
* `newRoot` in order to translate mutations in it.
|
||||
*
|
||||
* @param {Element} newRoot - Root to observe.
|
||||
*/
|
||||
connectRoot(newRoot) {
|
||||
// Sometimes we connect the root while the document is already in the
|
||||
// process of being closed. Bail out gracefully.
|
||||
// See bug 1532712 for details.
|
||||
if (!newRoot.ownerGlobal) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const root of this.roots) {
|
||||
if (root === newRoot ||
|
||||
root.contains(newRoot) ||
|
||||
newRoot.contains(root)) {
|
||||
throw new Error("Cannot add a root that overlaps with existing root.");
|
||||
}
|
||||
}
|
||||
|
||||
if (this.windowElement) {
|
||||
if (this.windowElement !== newRoot.ownerGlobal) {
|
||||
throw new Error(`Cannot connect a root:
|
||||
DOMLocalization already has a root from a different window.`);
|
||||
}
|
||||
} else {
|
||||
this.windowElement = newRoot.ownerGlobal;
|
||||
this.mutationObserver = new this.windowElement.MutationObserver(
|
||||
mutations => this.translateMutations(mutations)
|
||||
);
|
||||
}
|
||||
|
||||
this.roots.add(newRoot);
|
||||
this.mutationObserver.observe(newRoot, this.observerConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove `root` from the list of roots managed by this `DOMLocalization`.
|
||||
*
|
||||
* Additionally, if this `DOMLocalization` has an observer, stop observing
|
||||
* `root`.
|
||||
*
|
||||
* Returns `true` if the root was the last one managed by this
|
||||
* `DOMLocalization`.
|
||||
*
|
||||
* @param {Element} root - Root to disconnect.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
disconnectRoot(root) {
|
||||
this.roots.delete(root);
|
||||
// Pause the mutation observer to stop observing `root`.
|
||||
this.pauseObserving();
|
||||
|
||||
if (this.roots.size === 0) {
|
||||
this.mutationObserver = null;
|
||||
this.windowElement = null;
|
||||
this.pendingrAF = null;
|
||||
this.pendingElements.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Resume observing all other roots.
|
||||
this.resumeObserving();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate all roots associated with this `DOMLocalization`.
|
||||
*
|
||||
* @returns {Promise}
|
||||
*/
|
||||
translateRoots() {
|
||||
if (this.resourceIds.length === 0) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const roots = Array.from(this.roots);
|
||||
return Promise.all(
|
||||
roots.map(async root => {
|
||||
// We want to first retranslate the UI, and
|
||||
// then (potentially) flip the directionality.
|
||||
//
|
||||
// This means that the DOM alternations and directionality
|
||||
// are set in the same microtask.
|
||||
await this.translateFragment(root);
|
||||
let primaryLocale = Services.locale.appLocaleAsBCP47;
|
||||
let direction = Services.locale.isAppLocaleRTL ? "rtl" : "ltr";
|
||||
root.setAttribute("lang", primaryLocale);
|
||||
root.setAttribute(root.namespaceURI ===
|
||||
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
? "localedir" : "dir", direction);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses the `MutationObserver`.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
pauseObserving() {
|
||||
if (!this.mutationObserver) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.translateMutations(this.mutationObserver.takeRecords());
|
||||
this.mutationObserver.disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes the `MutationObserver`.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
resumeObserving() {
|
||||
if (!this.mutationObserver) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const root of this.roots) {
|
||||
this.mutationObserver.observe(root, this.observerConfig);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate mutations detected by the `MutationObserver`.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
translateMutations(mutations) {
|
||||
for (const mutation of mutations) {
|
||||
switch (mutation.type) {
|
||||
case "attributes":
|
||||
if (mutation.target.hasAttribute("data-l10n-id")) {
|
||||
this.pendingElements.add(mutation.target);
|
||||
}
|
||||
break;
|
||||
case "childList":
|
||||
for (const addedNode of mutation.addedNodes) {
|
||||
if (addedNode.nodeType === addedNode.ELEMENT_NODE) {
|
||||
if (addedNode.childElementCount) {
|
||||
for (const element of this.getTranslatables(addedNode)) {
|
||||
this.pendingElements.add(element);
|
||||
}
|
||||
} else if (addedNode.hasAttribute(L10NID_ATTR_NAME)) {
|
||||
this.pendingElements.add(addedNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// This fragment allows us to coalesce all pending translations
|
||||
// into a single requestAnimationFrame.
|
||||
if (this.pendingElements.size > 0) {
|
||||
if (this.pendingrAF === null) {
|
||||
this.pendingrAF = this.windowElement.requestAnimationFrame(() => {
|
||||
// We need to filter for elements that lost their l10n-id while
|
||||
// waiting for the animation frame.
|
||||
this.translateElements(Array.from(this.pendingElements)
|
||||
.filter(elem => elem.hasAttribute("data-l10n-id")));
|
||||
this.pendingElements.clear();
|
||||
this.pendingrAF = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a DOM element or fragment asynchronously using this
|
||||
* `DOMLocalization` object.
|
||||
*
|
||||
* Manually trigger the translation (or re-translation) of a DOM fragment.
|
||||
* Use the `data-l10n-id` and `data-l10n-args` attributes to mark up the DOM
|
||||
* with information about which translations to use.
|
||||
*
|
||||
* Returns a `Promise` that gets resolved once the translation is complete.
|
||||
*
|
||||
* @param {DOMFragment} frag - Element or DocumentFragment to be translated
|
||||
* @returns {Promise}
|
||||
*/
|
||||
async translateFragment(frag) {
|
||||
if (frag.ownerDocument.l10n) {
|
||||
// We use DocumentL10n's version of this API.
|
||||
let errors = await frag.ownerDocument.l10n.translateFragment(frag);
|
||||
if (errors) {
|
||||
reportDOMOverlayErrors(errors);
|
||||
}
|
||||
} else {
|
||||
await this.translateElements(this.getTranslatables(frag));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a list of DOM elements asynchronously using this
|
||||
* `DOMLocalization` object.
|
||||
*
|
||||
* Manually trigger the translation (or re-translation) of a list of elements.
|
||||
* Use the `data-l10n-id` and `data-l10n-args` attributes to mark up the DOM
|
||||
* with information about which translations to use.
|
||||
*
|
||||
* Returns a `Promise` that gets resolved once the translation is complete.
|
||||
*
|
||||
* @param {Array<Element>} elements - List of elements to be translated
|
||||
* @returns {Promise}
|
||||
*/
|
||||
async translateElements(elements) {
|
||||
if (!elements.length) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Remove elements from the pending list since
|
||||
// their translations will get applied below.
|
||||
for (let element of elements) {
|
||||
this.pendingElements.delete(element);
|
||||
}
|
||||
|
||||
const keys = elements.map(this.getKeysForElement);
|
||||
const translations = await this.formatMessages(keys);
|
||||
return this.applyTranslations(elements, translations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies translations onto elements.
|
||||
*
|
||||
* @param {Array<Element>} elements
|
||||
* @param {Array<Object>} translations
|
||||
* @private
|
||||
*/
|
||||
applyTranslations(elements, translations) {
|
||||
this.pauseObserving();
|
||||
|
||||
const errors = [];
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
if (translations[i] !== undefined) {
|
||||
const translationErrors = DOMOverlays.translateElement(elements[i], translations[i]);
|
||||
if (translationErrors) {
|
||||
errors.push(...translationErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (errors.length) {
|
||||
reportDOMOverlayErrors(errors);
|
||||
}
|
||||
|
||||
this.resumeObserving();
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects all translatable child elements of the element.
|
||||
*
|
||||
* @param {Element} element
|
||||
* @returns {Array<Element>}
|
||||
* @private
|
||||
*/
|
||||
getTranslatables(element) {
|
||||
const nodes = Array.from(element.querySelectorAll(L10N_ELEMENT_QUERY));
|
||||
|
||||
if (typeof element.hasAttribute === "function" &&
|
||||
element.hasAttribute(L10NID_ATTR_NAME)) {
|
||||
nodes.push(element);
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the `data-l10n-*` attributes from DOM elements as a two-element
|
||||
* array.
|
||||
*
|
||||
* @param {Element} element
|
||||
* @returns {Object}
|
||||
* @private
|
||||
*/
|
||||
getKeysForElement(element) {
|
||||
return {
|
||||
id: element.getAttribute(L10NID_ATTR_NAME),
|
||||
args: JSON.parse(element.getAttribute(L10NARGS_ATTR_NAME) || null),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function which allows us to construct a new
|
||||
* DOMLocalization from DocumentL10n.
|
||||
*/
|
||||
var getDOMLocalization = () => new DOMLocalization();
|
||||
|
||||
var EXPORTED_SYMBOLS = ["DOMLocalization", "getDOMLocalization"];
|
|
@ -248,7 +248,7 @@ class Localization {
|
|||
* Format translations and handle fallback if needed.
|
||||
*
|
||||
* Format translations for `keys` from `FluentBundle` instances on this
|
||||
* DOMLocalization. In case of errors, fetch the next context in the
|
||||
* Localization. In case of errors, fetch the next context in the
|
||||
* fallback chain.
|
||||
*
|
||||
* @param {Array<Object>} keys - Translation keys to format.
|
||||
|
@ -313,7 +313,7 @@ class Localization {
|
|||
/**
|
||||
* Retrieve translations corresponding to the passed keys.
|
||||
*
|
||||
* A generalized version of `DOMLocalization.formatValue`. Keys can
|
||||
* A generalized version of `Localization.formatValue`. Keys can
|
||||
* either be simple string identifiers or `[id, args]` arrays.
|
||||
*
|
||||
* docL10n.formatValues([
|
||||
|
@ -583,7 +583,7 @@ function keysFromBundle(method, bundle, keys, translations) {
|
|||
|
||||
/**
|
||||
* Helper function which allows us to construct a new
|
||||
* Localization from DOMLocalization.
|
||||
* Localization from Localization.
|
||||
*/
|
||||
var getLocalization = (resourceIds) => {
|
||||
return new Localization(resourceIds);
|
||||
|
|
|
@ -3,7 +3,6 @@ The content of this directory is partially sourced from the fluent.js project.
|
|||
The following files are affected:
|
||||
- Fluent.jsm
|
||||
- Localization.jsm
|
||||
- DOMLocalization.jsm
|
||||
|
||||
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
|
||||
|
|
|
@ -701,7 +701,7 @@ DocumentL10n
|
|||
------------
|
||||
|
||||
DocumentL10n implements the DocumentL10n WebIDL API and allows Document to
|
||||
communicate with mozDOMLocalization.
|
||||
communicate with DOMLocalization.
|
||||
|
||||
L10nRegistry
|
||||
------------
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -5,7 +5,6 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'DOMLocalization.jsm',
|
||||
'Fluent.jsm',
|
||||
'L10nRegistry.jsm',
|
||||
'Localization.jsm',
|
||||
|
@ -16,7 +15,6 @@ TESTING_JS_MODULES += [
|
|||
]
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'mozIDOMLocalization.idl',
|
||||
'mozILocalization.idl',
|
||||
]
|
||||
|
||||
|
@ -28,8 +26,6 @@ LOCAL_INCLUDES += [
|
|||
|
||||
XPCSHELL_TESTS_MANIFESTS += ['test/xpcshell.ini']
|
||||
|
||||
MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
|
||||
|
||||
SPHINX_TREES['l10n'] = 'docs'
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
webidl Document;
|
||||
webidl Element;
|
||||
webidl Node;
|
||||
|
||||
[scriptable, uuid(7c468500-541f-4fe0-98c9-92a53b63ec8d)]
|
||||
interface mozIDOMLocalization : nsISupports
|
||||
{
|
||||
unsigned long addResourceIds(in Array<AString> resourceIds, in bool aEager);
|
||||
unsigned long removeResourceIds(in Array<AString> resourceIds);
|
||||
void onChange();
|
||||
|
||||
Promise formatMessages(in Array<jsval> aKeys);
|
||||
Promise formatValues(in Array<jsval> aKeys);
|
||||
Promise formatValue(in AString aId, [optional] in jsval aArgs);
|
||||
|
||||
Promise translateElements(in Array<Element> aElements);
|
||||
|
||||
void connectRoot(in Element aElement);
|
||||
void disconnectRoot(in Element aElement);
|
||||
|
||||
void pauseObserving();
|
||||
void resumeObserving();
|
||||
|
||||
Promise translateRoots();
|
||||
readonly attribute Promise ready;
|
||||
};
|
||||
|
||||
[scriptable, uuid(96532d26-2422-11e9-a1ce-9bb586acd241)]
|
||||
interface mozIDOMLocalizationJSM : nsISupports
|
||||
{
|
||||
mozIDOMLocalization getDOMLocalization();
|
||||
};
|
|
@ -3,6 +3,5 @@
|
|||
module.exports = {
|
||||
"extends": [
|
||||
"plugin:mozilla/xpcshell-test",
|
||||
"plugin:mozilla/browser-test"
|
||||
]
|
||||
};
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
[dom/test_mozdom_translateElements.html]
|
||||
[dom/test_mozdom_translateFragment.html]
|
||||
[dom/test_mozdom_translateRoots.html]
|
||||
|
||||
[dom_overlays/test_same_id.html]
|
||||
[dom_overlays/test_same_id_args.html]
|
|
@ -1,61 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test mozIDOMLocalization.translateElements</title>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
<script type="application/javascript">
|
||||
"use strict";
|
||||
const { getDOMLocalization } =
|
||||
ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm");
|
||||
const domLocalization = getDOMLocalization();
|
||||
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { L10nRegistry, FileSource } =
|
||||
ChromeUtils.import("resource://gre/modules/L10nRegistry.jsm");
|
||||
|
||||
const fs = {
|
||||
"/localization/en-US/browser/menu.ftl": `
|
||||
title = Hello World
|
||||
link =
|
||||
.title = Click me
|
||||
`,
|
||||
};
|
||||
const originalLoad = L10nRegistry.load;
|
||||
const originalRequested = Services.locale.requestedLocales;
|
||||
|
||||
L10nRegistry.load = async function(url) {
|
||||
return fs.hasOwnProperty(url) ? fs[url] : false;
|
||||
};
|
||||
|
||||
const source = new FileSource("test", ["en-US"], "/localization/{locale}");
|
||||
L10nRegistry.registerSource(source);
|
||||
|
||||
window.onload = async function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
domLocalization.addResourceIds(["/browser/menu.ftl"], false);
|
||||
|
||||
const p1 = document.querySelectorAll("p")[0];
|
||||
const link1 = document.querySelectorAll("a")[0];
|
||||
|
||||
await domLocalization.translateElements([p1, link1], 2);
|
||||
|
||||
is(p1.textContent, "Hello World");
|
||||
is(link1.getAttribute("title"), "Click me");
|
||||
|
||||
// Cleanup
|
||||
L10nRegistry.removeSource(source.name);
|
||||
L10nRegistry.load = originalLoad;
|
||||
Services.locale.requestedLocales = originalRequested;
|
||||
|
||||
SimpleTest.finish();
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p data-l10n-id="title" />
|
||||
<a data-l10n-id="link" />
|
||||
</body>
|
||||
</html>
|
|
@ -1,62 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test mozIDOMLocalization.translateFragment</title>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
<script type="application/javascript">
|
||||
"use strict";
|
||||
const { getDOMLocalization } =
|
||||
ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm");
|
||||
const domLocalization = getDOMLocalization();
|
||||
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { L10nRegistry, FileSource } =
|
||||
ChromeUtils.import("resource://gre/modules/L10nRegistry.jsm");
|
||||
|
||||
const fs = {
|
||||
"/localization/en-US/browser/menu.ftl": `
|
||||
title = Hello World
|
||||
subtitle = Welcome to Fluent
|
||||
`,
|
||||
};
|
||||
const originalLoad = L10nRegistry.load;
|
||||
const originalRequested = Services.locale.requestedLocales;
|
||||
|
||||
L10nRegistry.load = async function(url) {
|
||||
return fs.hasOwnProperty(url) ? fs[url] : false;
|
||||
};
|
||||
|
||||
const source = new FileSource("test", ["en-US"], "/localization/{locale}");
|
||||
L10nRegistry.registerSource(source);
|
||||
|
||||
window.onload = async function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
domLocalization.addResourceIds(["/browser/menu.ftl"], false);
|
||||
|
||||
const frag = document.querySelectorAll("div")[0];
|
||||
const h1 = document.querySelectorAll("h1")[0];
|
||||
const p1 = document.querySelectorAll("p")[0];
|
||||
|
||||
await domLocalization.translateFragment(frag);
|
||||
is(h1.textContent, "Hello World");
|
||||
is(p1.textContent, "Welcome to Fluent");
|
||||
|
||||
// Cleanup
|
||||
L10nRegistry.removeSource(source.name);
|
||||
L10nRegistry.load = originalLoad;
|
||||
Services.locale.requestedLocales = originalRequested;
|
||||
|
||||
SimpleTest.finish();
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<h1 data-l10n-id="title" />
|
||||
<p data-l10n-id="subtitle" />
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,69 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test mozIDOMLocalization.connectRoot and translateRoots</title>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
<script type="application/javascript">
|
||||
"use strict";
|
||||
const { getDOMLocalization } =
|
||||
ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm");
|
||||
const domLocalization = getDOMLocalization();
|
||||
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { L10nRegistry, FileSource } =
|
||||
ChromeUtils.import("resource://gre/modules/L10nRegistry.jsm");
|
||||
|
||||
const fs = {
|
||||
"/localization/en-US/browser/menu.ftl": `
|
||||
title = Hello World
|
||||
title2 = Hello Another World
|
||||
`,
|
||||
};
|
||||
const originalLoad = L10nRegistry.load;
|
||||
const originalRequested = Services.locale.requestedLocales;
|
||||
|
||||
L10nRegistry.load = async function(url) {
|
||||
return fs.hasOwnProperty(url) ? fs[url] : false;
|
||||
};
|
||||
|
||||
const source = new FileSource("test", ["en-US"], "/localization/{locale}");
|
||||
L10nRegistry.registerSource(source);
|
||||
|
||||
window.onload = async function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
domLocalization.addResourceIds(["/browser/menu.ftl"], false);
|
||||
|
||||
const frag1 = document.querySelectorAll("div")[0];
|
||||
const frag2 = document.querySelectorAll("div")[1];
|
||||
const h1 = document.querySelectorAll("h1")[0];
|
||||
const h2 = document.querySelectorAll("h2")[0];
|
||||
|
||||
domLocalization.connectRoot(frag1);
|
||||
domLocalization.connectRoot(frag2);
|
||||
|
||||
await domLocalization.translateRoots();
|
||||
|
||||
is(h1.textContent, "Hello World");
|
||||
is(h2.textContent, "Hello Another World");
|
||||
|
||||
// Cleanup
|
||||
L10nRegistry.removeSource(source.name);
|
||||
L10nRegistry.load = originalLoad;
|
||||
Services.locale.requestedLocales = originalRequested;
|
||||
|
||||
SimpleTest.finish();
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<h1 data-l10n-id="title"></h1>
|
||||
</div>
|
||||
<div>
|
||||
<h2 data-l10n-id="title2"></h2>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,15 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const { DOMLocalization } =
|
||||
ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm");
|
||||
|
||||
add_task(function test_methods_presence() {
|
||||
equal(typeof DOMLocalization.prototype.getAttributes, "function");
|
||||
equal(typeof DOMLocalization.prototype.setAttributes, "function");
|
||||
equal(typeof DOMLocalization.prototype.translateFragment, "function");
|
||||
equal(typeof DOMLocalization.prototype.translateElements, "function");
|
||||
equal(typeof DOMLocalization.prototype.connectRoot, "function");
|
||||
equal(typeof DOMLocalization.prototype.disconnectRoot, "function");
|
||||
equal(typeof DOMLocalization.prototype.translateRoots, "function");
|
||||
});
|
|
@ -1,7 +1,6 @@
|
|||
[DEFAULT]
|
||||
head =
|
||||
|
||||
[test_domlocalization.js]
|
||||
[test_l10nregistry.js]
|
||||
[test_l10nregistry_sync.js]
|
||||
[test_localization.js]
|
||||
|
|
Загрузка…
Ссылка в новой задаче