Backed out 3 changesets (bug 1621674) for newtab perma failures. CLOSED TREE

Backed out changeset f197d83fd8a1 (bug 1621674)
Backed out changeset 939beec809c1 (bug 1621674)
Backed out changeset a657cda5467e (bug 1621674)
This commit is contained in:
Razvan Maries
2020-04-07 21:00:15 +03:00
parent 5c96b9521c
commit e353ccf904
42 changed files with 227 additions and 332 deletions

View File

@@ -45,7 +45,7 @@ class _BookmarkPanelHub {
this._handleMessageRequest = handleMessageRequest;
this._addImpression = addImpression;
this._dispatch = dispatch;
this._l10n = new DOMLocalization([]);
this._l10n = new DOMLocalization();
this._initialized = true;
}

View File

@@ -69,10 +69,9 @@ class _RemoteL10n {
"browser/branding/sync-brand.ftl",
"branding/brand.ftl",
],
false,
Services.prefs.getBoolPref(USE_REMOTE_L10N_PREF, true)
? { generateBundles }
: {}
? generateBundles
: undefined
);
}

View File

@@ -249,8 +249,7 @@ function getBundleForLocales(newLocales) {
}
return new Localization(
["browser/preferences/preferences.ftl", "branding/brand.ftl"],
false,
{ generateBundles }
generateBundles
);
}

View File

@@ -3857,7 +3857,7 @@ bool Document::GetAllowPlugins() {
return true;
}
void Document::InitializeLocalization(Sequence<nsString>& aResourceIds) {
void Document::InitializeLocalization(nsTArray<nsString>& aResourceIds) {
MOZ_ASSERT(!mDocumentL10n, "mDocumentL10n should not be initialized yet");
RefPtr<DocumentL10n> l10n = new DocumentL10n(this);
@@ -3891,18 +3891,14 @@ void Document::LocalizationLinkAdded(Element* aLinkElement) {
// If the link is added after the DocumentL10n instance
// has been initialized, just pass the resource ID to it.
if (mDocumentL10n) {
Sequence<nsString> resourceIds;
if (NS_WARN_IF(!resourceIds.AppendElement(href, fallible))) {
return;
}
AutoTArray<nsString, 1> resourceIds;
resourceIds.AppendElement(href);
mDocumentL10n->AddResourceIds(resourceIds, false);
} else if (mReadyState >= READYSTATE_INTERACTIVE) {
// Otherwise, if the document has already been parsed
// we need to lazily initialize the localization.
Sequence<nsString> resourceIds;
if (NS_WARN_IF(!resourceIds.AppendElement(href, fallible))) {
return;
}
AutoTArray<nsString, 1> resourceIds;
resourceIds.AppendElement(href);
InitializeLocalization(resourceIds);
mDocumentL10n->TriggerInitialDocumentTranslation();
} else {
@@ -3910,9 +3906,7 @@ void Document::LocalizationLinkAdded(Element* aLinkElement) {
// In that case, add it to the pending list. This list
// will be resolved once the end of l10n resource
// container is reached.
if (NS_WARN_IF(!mL10nResources.AppendElement(href, fallible))) {
return;
}
mL10nResources.AppendElement(href);
if (!mPendingInitialTranslation) {
// Our initial translation is going to block layout start. Make sure we

View File

@@ -3734,7 +3734,7 @@ class Document : public nsINode,
private:
bool IsErrorPage() const;
void InitializeLocalization(Sequence<nsString>& aResourceIds);
void InitializeLocalization(nsTArray<nsString>& aResourceIds);
// Takes the bits from mStyleUseCounters if appropriate, and sets them in
// mUseCounters.
@@ -3760,7 +3760,7 @@ class Document : public nsINode,
FlashClassification DocumentFlashClassificationInternal();
Sequence<nsString> mL10nResources;
nsTArray<nsString> mL10nResources;
// The application cache that this document is associated with, if
// any. This can change during the lifetime of the document.

View File

@@ -459,7 +459,7 @@ DOMInterfaces = {
},
'Localization': {
'implicitJSContext': [ 'formatValue', 'formatValues', 'formatMessages', 'formatValueSync', 'formatValuesSync', 'formatMessagesSync' ],
'implicitJSContext': [ 'formatValue', 'formatValues', 'formatMessages' ],
'nativeType': 'mozilla::intl::Localization',
},

View File

@@ -31,19 +31,13 @@ interface DOMLocalization : Localization {
* - aResourceids - a list of localization resource URIs
* which will provide messages for this
* Localization instance.
* - aSync - Specifies if the initial state of the DOMLocalization
* and the underlying Localization API is synchronous.
* This enables a number of synchronous methods on the
* Localization API and uses it for `TranslateElements`
* making the method return a synchronusly resolved promise.
* - aBundleGenerator - an object with two methods - `generateBundles` and
* `generateBundlesSync` allowing consumers to overload the
* default generators provided by Gecko.
* - aGenerateMessages - a callback function which will be
* used to generate an iterator
* over FluentBundle instances.
*/
[Throws]
constructor(sequence<DOMString> aResourceIds,
optional boolean aSync = false,
optional BundleGenerator aBundleGenerator = {});
constructor(optional sequence<DOMString> aResourceIds,
optional GenerateMessages aGenerateMessages);
/**
* Adds a node to nodes observed for localization

View File

@@ -42,18 +42,7 @@ dictionary L10nMessage {
* and produces an iterator over FluentBundle objects used for
* localization with fallbacks.
*/
callback GenerateBundles = Promise<any> (sequence<DOMString> aResourceIds);
callback GenerateBundlesSync = any (sequence<DOMString> aResourceIds);
/**
* The structure provides custom methods for the Localization API that
* will be used to generate the `FluentBundle` iterator.
* This allows the consumer to overload the default Gecko generator.
*/
dictionary BundleGenerator {
GenerateBundles generateBundles;
GenerateBundlesSync generateBundlesSync;
};
callback GenerateMessages = Promise<any> (sequence<DOMString> aResourceIds);
/**
* Localization is an implementation of the Fluent Localization API.
@@ -75,20 +64,16 @@ dictionary BundleGenerator {
interface Localization {
/**
* Constructor arguments:
* - aResourceids - a list of localization resource URIs
* which will provide messages for this
* Localization instance.
* - aSync - Specifies if the initial state of the Localization API is synchronous.
* This enables a number of synchronous methods on the
* Localization API.
* - aBundleGenerator - an object with two methods - `generateBundles` and
* `generateBundlesSync` allowing consumers to overload the
* default generators provided by Gecko.
* - aResourceids - a list of localization resource URIs
* which will provide messages for this
* Localization instance.
* - aGenerateMessages - a callback function which will be
* used to generate an iterator
* over FluentBundle instances.
*/
[Throws]
constructor(sequence<DOMString> aResourceIds,
optional boolean aSync = false,
optional BundleGenerator aBundleGenerator = {});
constructor(optional sequence<DOMString> aResourceIds,
optional GenerateMessages aGenerateMessages);
/**
* A method for adding resources to the localization context.
@@ -152,15 +137,6 @@ interface Localization {
* ]);
*/
[NewObject] Promise<sequence<L10nMessage>> formatMessages(sequence<L10nKey> aKeys);
void setIsSync(boolean aIsSync);
[NewObject, Throws]
UTF8String? formatValueSync(UTF8String aId, optional L10nArgs aArgs);
[NewObject, Throws]
sequence<UTF8String?> formatValuesSync(sequence<L10nKey> aKeys);
[NewObject, Throws]
sequence<L10nMessage?> formatMessagesSync(sequence<L10nKey> aKeys);
};
/**

View File

@@ -38,8 +38,9 @@ DOMLocalization::DOMLocalization(nsIGlobalObject* aGlobal)
}
already_AddRefed<DOMLocalization> DOMLocalization::Constructor(
const GlobalObject& aGlobal, const Sequence<nsString>& aResourceIds,
const bool aSync, const BundleGenerator& aBundleGenerator,
const GlobalObject& aGlobal,
const Optional<Sequence<nsString>>& aResourceIds,
const Optional<OwningNonNull<GenerateMessages>>& aGenerateMessages,
ErrorResult& aRv) {
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
if (!global) {
@@ -48,7 +49,20 @@ already_AddRefed<DOMLocalization> DOMLocalization::Constructor(
}
RefPtr<DOMLocalization> domLoc = new DOMLocalization(global);
domLoc->Init(aResourceIds, aSync, aBundleGenerator, aRv);
nsTArray<nsString> resourceIds;
if (aResourceIds.WasPassed()) {
resourceIds = aResourceIds.Value();
}
if (aGenerateMessages.WasPassed()) {
GenerateMessages& generateMessages = aGenerateMessages.Value();
JS::Rooted<JS::Value> generateMessagesJS(
aGlobal.Context(), JS::ObjectValue(*generateMessages.CallbackOrNull()));
domLoc->Init(resourceIds, generateMessagesJS, aRv);
} else {
domLoc->Init(resourceIds, aRv);
}
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
@@ -177,7 +191,7 @@ class ElementTranslationHandler : public PromiseNativeHandler {
JS::Handle<JS::Value> aValue) override {
ErrorResult rv;
nsTArray<Nullable<L10nMessage>> l10nData;
nsTArray<L10nMessage> l10nData;
if (aValue.isObject()) {
JS::ForOfIterator iter(aCx);
if (!iter.init(aValue, JS::ForOfIterator::AllowNonIterable)) {
@@ -201,18 +215,15 @@ class ElementTranslationHandler : public PromiseNativeHandler {
break;
}
Nullable<L10nMessage>* slotPtr =
l10nData.AppendElement(mozilla::fallible);
L10nMessage* slotPtr = l10nData.AppendElement(mozilla::fallible);
if (!slotPtr) {
mReturnValuePromise->MaybeRejectWithUndefined();
return;
}
if (!temp.isNull()) {
if (!slotPtr->SetValue().Init(aCx, temp)) {
mReturnValuePromise->MaybeRejectWithUndefined();
return;
}
if (!slotPtr->Init(aCx, temp)) {
mReturnValuePromise->MaybeRejectWithUndefined();
return;
}
}
}
@@ -314,11 +325,39 @@ already_AddRefed<Promise> DOMLocalization::TranslateElements(
}
if (mIsSync) {
nsTArray<Nullable<L10nMessage>> l10nMessages;
nsTArray<JS::Value> jsKeys;
SequenceRooter<JS::Value> keysRooter(cx, &jsKeys);
for (auto& key : l10nKeys) {
JS::RootedValue jsKey(cx);
if (!ToJSValue(cx, key, &jsKey)) {
aRv.NoteJSContextException(cx);
return nullptr;
}
jsKeys.AppendElement(jsKey);
}
FormatMessagesSync(cx, l10nKeys, l10nMessages, aRv);
nsTArray<JS::Value> messages;
SequenceRooter<JS::Value> messagesRooter(cx, &messages);
mLocalization->FormatMessagesSync(jsKeys, messages);
nsTArray<L10nMessage> l10nData;
SequenceRooter<L10nMessage> l10nDataRooter(cx, &l10nData);
ApplyTranslations(domElements, l10nMessages, aProto, aRv);
for (auto& msg : messages) {
JS::Rooted<JS::Value> rootedMsg(cx);
rootedMsg.set(msg);
L10nMessage* slotPtr = l10nData.AppendElement(mozilla::fallible);
if (!slotPtr) {
promise->MaybeRejectWithUndefined();
return MaybeWrapPromise(promise);
}
if (!slotPtr->Init(cx, rootedMsg)) {
promise->MaybeRejectWithUndefined();
return MaybeWrapPromise(promise);
}
}
ApplyTranslations(domElements, l10nData, aProto, aRv);
if (NS_WARN_IF(aRv.Failed())) {
promise->MaybeRejectWithUndefined();
return MaybeWrapPromise(promise);
@@ -442,10 +481,10 @@ void DOMLocalization::SetRootInfo(Element* aElement) {
aElement->SetAttr(kNameSpaceID_None, dirAtom, dir, true);
}
void DOMLocalization::ApplyTranslations(
nsTArray<nsCOMPtr<Element>>& aElements,
nsTArray<Nullable<L10nMessage>>& aTranslations,
nsXULPrototypeDocument* aProto, ErrorResult& aRv) {
void DOMLocalization::ApplyTranslations(nsTArray<nsCOMPtr<Element>>& aElements,
nsTArray<L10nMessage>& aTranslations,
nsXULPrototypeDocument* aProto,
ErrorResult& aRv) {
if (aElements.Length() != aTranslations.Length()) {
aRv.Throw(NS_ERROR_FAILURE);
return;
@@ -460,11 +499,7 @@ void DOMLocalization::ApplyTranslations(
nsTArray<L10nOverlaysError> errors;
for (size_t i = 0; i < aTranslations.Length(); ++i) {
Element* elem = aElements[i];
if (aTranslations[i].IsNull()) {
continue;
}
L10nOverlays::TranslateElement(*elem, aTranslations[i].Value(), errors,
aRv);
L10nOverlays::TranslateElement(*elem, aTranslations[i], errors, aRv);
if (NS_WARN_IF(aRv.Failed())) {
aRv.Throw(NS_ERROR_FAILURE);
return;
@@ -472,8 +507,7 @@ void DOMLocalization::ApplyTranslations(
if (aProto) {
// We only need to rebuild deep if the translation has a value.
// Otherwise we'll only rebuild the attributes.
aProto->RebuildL10nPrototype(elem,
!aTranslations[i].Value().mValue.IsVoid());
aProto->RebuildL10nPrototype(elem, !aTranslations[i].mValue.IsVoid());
}
}

View File

@@ -26,8 +26,9 @@ class DOMLocalization : public intl::Localization {
explicit DOMLocalization(nsIGlobalObject* aGlobal);
static already_AddRefed<DOMLocalization> Constructor(
const GlobalObject& aGlobal, const Sequence<nsString>& aResourceIds,
const bool aSync, const BundleGenerator& aBundleGenerator,
const GlobalObject& aGlobal,
const Optional<Sequence<nsString>>& aResourceIds,
const Optional<OwningNonNull<GenerateMessages>>& aGenerateMessages,
ErrorResult& aRv);
virtual JSObject* WrapObject(JSContext* aCx,
@@ -86,7 +87,7 @@ class DOMLocalization : public intl::Localization {
* the localized elements.
*/
void ApplyTranslations(nsTArray<nsCOMPtr<Element>>& aElements,
nsTArray<Nullable<L10nMessage>>& aTranslations,
nsTArray<L10nMessage>& aTranslations,
nsXULPrototypeDocument* aProto, ErrorResult& aRv);
bool SubtreeRootInRoots(nsINode* aSubtreeRoot) {

View File

@@ -41,12 +41,11 @@ DocumentL10n::DocumentL10n(Document* aDocument)
}
}
void DocumentL10n::Init(Sequence<nsString>& aResourceIds, ErrorResult& aRv) {
DOMLocalization::Init(aResourceIds, mIsSync, {}, aRv);
void DocumentL10n::Init(nsTArray<nsString>& aResourceIds, ErrorResult& aRv) {
DOMLocalization::Init(aResourceIds, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
mReady = Promise::Create(mGlobal, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;

View File

@@ -35,7 +35,7 @@ class DocumentL10n final : public DOMLocalization {
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DocumentL10n, DOMLocalization)
explicit DocumentL10n(Document* aDocument);
void Init(Sequence<nsString>& aResourceIds, ErrorResult& aRv);
void Init(nsTArray<nsString>& aResourceIds, ErrorResult& aRv);
protected:
virtual ~DocumentL10n() = default;

View File

@@ -7,7 +7,7 @@
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript">
"use strict";
async function* generateBundles(resourceIds) {
async function* mockGenerateMessages(resourceIds) {
const bundle = new FluentBundle("en-US");
bundle.addResource(new FluentResource(`
key1 = Value for Key 1
@@ -21,8 +21,7 @@ key2 = Value for <a>Key 2<a/>.
addLoadEvent(async () => {
const domLoc = new DOMLocalization(
[],
false,
{ generateBundles },
mockGenerateMessages
);
await domLoc.translateFragment(document.body);

View File

@@ -7,7 +7,7 @@
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript">
"use strict";
async function* generateBundles(resourceIds) {
async function* mockGenerateMessages(resourceIds) {
const bundle = new FluentBundle("en-US");
bundle.addResource(new FluentResource(`
key1 = Value for Key 1
@@ -22,8 +22,7 @@ key1 = Value for Key 1
const domLoc = new DOMLocalization(
[],
false,
{ generateBundles },
mockGenerateMessages
);
await domLoc.translateRoots();

View File

@@ -44,7 +44,7 @@
</script>
<script type="application/javascript">
"use strict";
async function* generateBundles(resourceIds) {
async function* mockGenerateMessages(resourceIds) {
const bundle = new FluentBundle("en-US");
bundle.addResource(new FluentResource(`
key1 = Value for Key 1
@@ -54,8 +54,7 @@ key1 = Value for Key 1
document.domLoc = new DOMLocalization(
[],
false,
{ generateBundles }
mockGenerateMessages
);
</script>
</head>

View File

@@ -7,7 +7,7 @@
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript">
"use strict";
async function* generateBundles(resourceIds) {
async function* mockGenerateMessages(resourceIds) {
const bundle = new FluentBundle("en-US");
bundle.addResource(new FluentResource(`
key1 = Value for Key 1
@@ -23,8 +23,7 @@ key2 = Value for Key 2
const domLoc = new DOMLocalization(
[],
false,
{ generateBundles },
mockGenerateMessages
);
await domLoc.translateRoots();

View File

@@ -10,7 +10,7 @@
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
<script type="application/javascript">
<![CDATA[
async function* generateBundles(resourceIds) {
async function * generateMessages(resourceIds) {
const bundle = new FluentBundle("en-US");
bundle.addResource(new FluentResource(`
file-menu =
@@ -29,8 +29,7 @@ container = Some text with an <image data-l10n-name="foo"> inside it.
const domLoc = new DOMLocalization(
[],
false,
{ generateBundles },
generateMessages
);
async function foo() {

View File

@@ -8,15 +8,14 @@
<script type="application/javascript">
"use strict";
async function* generateBundles(resourceIds) {}
async function* mockGenerateMessages(resourceIds) {}
window.onload = function() {
SimpleTest.waitForExplicitFinish();
const domLoc = new DOMLocalization(
[],
false,
{ generateBundles },
mockGenerateMessages
);
const p1 = document.querySelectorAll("p")[0];

View File

@@ -7,7 +7,7 @@
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript">
"use strict";
async function* generateBundles(resourceIds) {
async function* mockGenerateMessages(resourceIds) {
const bundle = new FluentBundle("en-US");
bundle.addResource(new FluentResource("title = Hello World"));
bundle.addResource(new FluentResource("title2 = Hello Another World"));
@@ -19,8 +19,7 @@
const domLoc = new DOMLocalization(
[],
false,
{ generateBundles },
mockGenerateMessages
);
const h1 = document.querySelectorAll("h1")[0];

View File

@@ -7,7 +7,7 @@
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript">
"use strict";
async function* generateBundles(resourceIds) {
async function* mockGenerateMessages(resourceIds) {
const bundle = new FluentBundle("en-US");
bundle.addResource(new FluentResource("title = <strong>Hello</strong> World"));
bundle.addResource(new FluentResource(`title2 = This is <a data-l10n-name="link">a link</a>!`));
@@ -19,8 +19,7 @@
const domLoc = new DOMLocalization(
[],
false,
{ generateBundles },
mockGenerateMessages
);
const p1 = document.querySelectorAll("p")[0];

View File

@@ -7,7 +7,7 @@
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript">
"use strict";
async function* generateBundles(resourceIds) {
async function* mockGenerateMessages(resourceIds) {
const bundle = new FluentBundle("en-US");
// No translations!
yield bundle;
@@ -17,8 +17,7 @@
addLoadEvent(async () => {
const domLoc = new DOMLocalization(
[],
false,
{ generateBundles },
mockGenerateMessages
);
await domLoc.translateFragment(document.body).then(() => {

View File

@@ -7,7 +7,7 @@
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript">
"use strict";
async function* generateBundles(resourceIds) {
async function* mockGenerateMessages(resourceIds) {
const bundle = new FluentBundle("en-US");
bundle.addResource(new FluentResource(`title = Visit <a data-l10n-name="mozilla-link">Mozilla</a> or <a data-l10n-name="firefox-link">Firefox</a> website!`));
yield bundle;
@@ -18,8 +18,7 @@
const domLoc = new DOMLocalization(
[],
false,
{ generateBundles },
mockGenerateMessages
);
await domLoc.translateFragment(document.body);

View File

@@ -7,7 +7,7 @@
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript">
"use strict";
async function* generateBundles(resourceIds) {
async function* mockGenerateMessages(resourceIds) {
const bundle = new FluentBundle("en-US");
bundle.addResource(new FluentResource(`title = Visit <a data-l10n-name="mozilla-link">Mozilla</a> or <a data-l10n-name="firefox-link">Firefox</a> website!`));
yield bundle;
@@ -18,8 +18,7 @@
const domLoc = new DOMLocalization(
[],
false,
{ generateBundles },
mockGenerateMessages
);
await domLoc.translateFragment(document.body);

View File

@@ -7,7 +7,7 @@
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript">
"use strict";
async function* generateBundles(resourceIds) {
async function* mockGenerateMessages(resourceIds) {
const bundle = new FluentBundle("en-US");
bundle.addResource(new FluentResource(`
key1 =
@@ -22,8 +22,7 @@ key2 =
async function test() {
const domLoc = new DOMLocalization(
[],
false,
{ generateBundles },
mockGenerateMessages
);
await domLoc.translateFragment(document.body);

View File

@@ -7,7 +7,7 @@
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript">
"use strict";
async function* generateBundles(resourceIds) {
async function* mockGenerateMessages(resourceIds) {
const bundle = new FluentBundle("en-US");
bundle.addResource(new FluentResource(`
key1 = Translation For Key 1
@@ -21,8 +21,7 @@ key2 = Visit <a data-l10n-name="link">this link<a/>.
addLoadEvent(async () => {
const domLoc = new DOMLocalization(
[],
false,
{ generateBundles },
mockGenerateMessages
);
await domLoc.translateFragment(document.body);

View File

@@ -8,15 +8,14 @@
<script type="application/javascript">
"use strict";
async function* generateBundles(resourceIds) {}
async function* mockGenerateMessages(resourceIds) {}
window.onload = function() {
SimpleTest.waitForExplicitFinish();
const domLoc = new DOMLocalization(
[],
false,
{ generateBundles },
mockGenerateMessages
);
const p1 = document.querySelectorAll("p")[0];

View File

@@ -7,7 +7,7 @@
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript">
"use strict";
async function* generateBundles(resourceIds) {
async function* mockGenerateMessages(resourceIds) {
const bundle = new FluentBundle("en-US");
bundle.addResource(new FluentResource("title = Hello World"));
bundle.addResource(new FluentResource("link =\n .title = Click me"));
@@ -19,8 +19,7 @@
const domLoc = new DOMLocalization(
[],
false,
{ generateBundles },
mockGenerateMessages
);
const p1 = document.querySelectorAll("p")[0];

View File

@@ -7,7 +7,7 @@
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript">
"use strict";
async function* generateBundles(resourceIds) {
async function* mockGenerateMessages(resourceIds) {
const bundle = new FluentBundle("en-US");
bundle.addResource(new FluentResource("title = Hello World"));
bundle.addResource(new FluentResource("subtitle = Welcome to FluentBundle"));
@@ -19,8 +19,7 @@
const domLoc = new DOMLocalization(
[],
false,
{ generateBundles },
mockGenerateMessages
);
const frag = document.querySelectorAll("div")[0];

View File

@@ -7,7 +7,7 @@
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript">
"use strict";
async function* generateBundles(resourceIds) {
async function* mockGenerateMessages(resourceIds) {
const bundle = new FluentBundle("en-US");
bundle.addResource(new FluentResource("title = Hello World"));
bundle.addResource(new FluentResource("title2 = Hello Another World"));
@@ -19,8 +19,7 @@
const domLoc = new DOMLocalization(
[],
false,
{ generateBundles },
mockGenerateMessages
);
const frag1 = document.querySelectorAll("div")[0];

View File

@@ -7,7 +7,7 @@
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript">
"use strict";
async function* generateBundles(resourceIds) {
async function* mockGenerateMessages(resourceIds) {
const bundle = new FluentBundle("en-US");
bundle.addResource(new FluentResource(`
key1 = Key 1
@@ -20,8 +20,7 @@ key4 = Key 4
document.domLoc = new DOMLocalization(
[],
false,
{ generateBundles }
mockGenerateMessages
);
document.domLoc.connectRoot(document.documentElement);
</script>

View File

@@ -45,42 +45,36 @@ NS_INTERFACE_MAP_END
Localization::Localization(nsIGlobalObject* aGlobal)
: mGlobal(aGlobal), mIsSync(false) {}
void Localization::Init(const Sequence<nsString>& aResourceIds,
const bool aSync,
const BundleGenerator& aBundleGenerator,
void Localization::Init(nsTArray<nsString>& aResourceIds, ErrorResult& aRv) {
nsCOMPtr<mozILocalizationJSM> jsm =
do_ImportModule("resource://gre/modules/Localization.jsm");
MOZ_RELEASE_ASSERT(jsm);
Unused << jsm->GetLocalization(aResourceIds, mIsSync,
getter_AddRefs(mLocalization));
MOZ_RELEASE_ASSERT(mLocalization);
RegisterObservers();
}
void Localization::Init(nsTArray<nsString>& aResourceIds,
JS::Handle<JS::Value> aGenerateMessages,
ErrorResult& aRv) {
nsCOMPtr<mozILocalizationJSM> jsm =
do_ImportModule("resource://gre/modules/Localization.jsm");
MOZ_RELEASE_ASSERT(jsm);
Unused << jsm->GetLocalization(aResourceIds, getter_AddRefs(mLocalization));
Unused << jsm->GetLocalizationWithCustomGenerateMessages(
aResourceIds, aGenerateMessages, getter_AddRefs(mLocalization));
MOZ_RELEASE_ASSERT(mLocalization);
mLocalization->SetIsSync(aSync);
AutoJSContext cx;
if (aBundleGenerator.mGenerateBundles.WasPassed()) {
GenerateBundles& generateBundles =
aBundleGenerator.mGenerateBundles.Value();
JS::Rooted<JS::Value> generateBundlesJS(
cx, JS::ObjectValue(*generateBundles.CallbackOrNull()));
mLocalization->SetGenerateBundles(generateBundlesJS);
}
if (aBundleGenerator.mGenerateBundlesSync.WasPassed()) {
GenerateBundlesSync& generateBundlesSync =
aBundleGenerator.mGenerateBundlesSync.Value();
JS::Rooted<JS::Value> generateBundlesSyncJS(
cx, JS::ObjectValue(*generateBundlesSync.CallbackOrNull()));
mLocalization->SetGenerateBundlesSync(generateBundlesSyncJS);
}
mLocalization->Init(true);
RegisterObservers();
}
already_AddRefed<Localization> Localization::Constructor(
const GlobalObject& aGlobal, const Sequence<nsString>& aResourceIds,
const bool aSync, const BundleGenerator& aBundleGenerator,
const GlobalObject& aGlobal,
const Optional<Sequence<nsString>>& aResourceIds,
const Optional<OwningNonNull<GenerateMessages>>& aGenerateMessages,
ErrorResult& aRv) {
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
if (!global) {
@@ -89,8 +83,20 @@ already_AddRefed<Localization> Localization::Constructor(
}
RefPtr<Localization> loc = new Localization(global);
nsTArray<nsString> resourceIds;
loc->Init(aResourceIds, aSync, aBundleGenerator, aRv);
if (aResourceIds.WasPassed()) {
resourceIds = aResourceIds.Value();
}
if (aGenerateMessages.WasPassed()) {
GenerateMessages& generateMessages = aGenerateMessages.Value();
JS::Rooted<JS::Value> generateMessagesJS(
aGlobal.Context(), JS::ObjectValue(*generateMessages.CallbackOrNull()));
loc->Init(resourceIds, generateMessagesJS, aRv);
} else {
loc->Init(resourceIds, aRv);
}
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
@@ -146,7 +152,7 @@ Localization::Observe(nsISupports* aSubject, const char* aTopic,
void Localization::OnChange() {
if (mLocalization) {
mLocalization->OnChange(false);
mLocalization->OnChange();
}
}
@@ -197,10 +203,6 @@ already_AddRefed<Promise> Localization::FormatValue(
return MaybeWrapPromise(promise);
}
void Localization::SetIsSync(const bool aIsSync) {
mLocalization->SetIsSync(aIsSync);
}
already_AddRefed<Promise> Localization::FormatValues(
JSContext* aCx, const Sequence<L10nKey>& aKeys, ErrorResult& aRv) {
nsTArray<JS::Value> jsKeys;
@@ -245,81 +247,6 @@ already_AddRefed<Promise> Localization::FormatMessages(
return MaybeWrapPromise(promise);
}
void Localization::FormatValueSync(JSContext* aCx, const nsACString& aId,
const Optional<L10nArgs>& aArgs,
nsACString& aRetVal, ErrorResult& aRv) {
JS::Rooted<JS::Value> args(aCx);
if (aArgs.WasPassed()) {
ConvertL10nArgsToJSValue(aCx, aArgs.Value(), &args, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
} else {
args = JS::UndefinedValue();
}
aRv = mLocalization->FormatValueSync(aId, args, aRetVal);
}
void Localization::FormatValuesSync(JSContext* aCx,
const Sequence<L10nKey>& aKeys,
nsTArray<nsCString>& aRetVal,
ErrorResult& aRv) {
nsTArray<JS::Value> jsKeys;
SequenceRooter<JS::Value> rooter(aCx, &jsKeys);
for (auto& key : aKeys) {
JS::RootedValue jsKey(aCx);
if (!ToJSValue(aCx, key, &jsKey)) {
aRv.NoteJSContextException(aCx);
return;
}
jsKeys.AppendElement(jsKey);
}
aRv = mLocalization->FormatValuesSync(jsKeys, aRetVal);
}
void Localization::FormatMessagesSync(JSContext* aCx,
const Sequence<L10nKey>& aKeys,
nsTArray<Nullable<L10nMessage>>& aRetVal,
ErrorResult& aRv) {
nsTArray<JS::Value> jsKeys;
SequenceRooter<JS::Value> rooter(aCx, &jsKeys);
for (auto& key : aKeys) {
JS::RootedValue jsKey(aCx);
if (!ToJSValue(aCx, key, &jsKey)) {
aRv.NoteJSContextException(aCx);
return;
}
jsKeys.AppendElement(jsKey);
}
nsTArray<JS::Value> messages;
SequenceRooter<JS::Value> messagesRooter(aCx, &messages);
aRv = mLocalization->FormatMessagesSync(jsKeys, messages);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
for (auto& msg : messages) {
JS::Rooted<JS::Value> rootedMsg(aCx);
rootedMsg.set(msg);
Nullable<L10nMessage>* slotPtr = aRetVal.AppendElement(mozilla::fallible);
if (!slotPtr) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
if (!msg.isNull()) {
if (!slotPtr->SetValue().Init(aCx, rootedMsg)) {
aRv.NoteJSContextException(aCx);
return;
}
}
}
}
/**
* PromiseResolver is a PromiseNativeHandler used
* by MaybeWrapPromise method.

View File

@@ -33,12 +33,14 @@ class Localization : public nsIObserver,
NS_DECL_NSIOBSERVER
explicit Localization(nsIGlobalObject* aGlobal);
void Init(const Sequence<nsString>& aResourceIds, const bool aSync,
const BundleGenerator& aBundleGenerator, ErrorResult& aRv);
void Init(nsTArray<nsString>& aResourceIds, ErrorResult& aRv);
void Init(nsTArray<nsString>& aResourceIds,
JS::Handle<JS::Value> aGenerateMessages, ErrorResult& aRv);
static already_AddRefed<Localization> Constructor(
const GlobalObject& aGlobal, const Sequence<nsString>& aResourceIds,
const bool aSync, const BundleGenerator& aBundleGenerator,
const GlobalObject& aGlobal,
const Optional<Sequence<nsString>>& aResourceIds,
const Optional<OwningNonNull<GenerateMessages>>& aGenerateMessages,
ErrorResult& aRv);
nsIGlobalObject* GetParentObject() const;
@@ -67,17 +69,6 @@ class Localization : public nsIObserver,
const Sequence<L10nKey>& aKeys,
ErrorResult& aRv);
void SetIsSync(const bool aIsSync);
void FormatValueSync(JSContext* aCx, const nsACString& aId,
const Optional<L10nArgs>& aArgs, nsACString& aRetVal,
ErrorResult& aRv);
void FormatValuesSync(JSContext* aCx, const Sequence<L10nKey>& aKeys,
nsTArray<nsCString>& aRetVal, ErrorResult& aRv);
void FormatMessagesSync(JSContext* aCx, const Sequence<L10nKey>& aKeys,
nsTArray<Nullable<L10nMessage>>& aRetVal,
ErrorResult& aRv);
protected:
virtual ~Localization();
void RegisterObservers();

View File

@@ -212,29 +212,19 @@ function maybeReportErrorToGecko(error) {
class Localization {
/**
* @param {Array<String>} resourceIds - List of resource IDs
* @param {Function} generateBundles - Function that returns an async
* generator over FluentBundles
* @param {Function} generateBundlesSync - Function that returns a sync
* generator over FluentBundles
*
* @returns {Localization}
*/
constructor(resourceIds = []) {
constructor(resourceIds = [], sync = false, generateBundles = defaultGenerateBundles, generateBundlesSync = defaultGenerateBundlesSync) {
this.isSync = sync;
this.resourceIds = resourceIds;
this.generateBundles = defaultGenerateBundles;
this.generateBundlesSync = defaultGenerateBundlesSync;
}
setGenerateBundles(generateBundles) {
this.generateBundles = generateBundles;
}
setGenerateBundlesSync(generateBundlesSync) {
this.generateBundlesSync = generateBundlesSync;
}
setIsSync(isSync) {
this.isSync = isSync;
}
init(eager = false) {
this.onChange(eager);
this.onChange(true);
}
cached(iterable) {
@@ -510,6 +500,11 @@ class Localization {
this.bundles.touchNext(prefetchCount);
}
}
setIsSync(isSync) {
this.isSync = isSync;
this.onChange();
}
}
Localization.prototype.QueryInterface = ChromeUtils.generateQI([
@@ -639,9 +634,13 @@ function keysFromBundle(method, bundle, keys, translations) {
* Helper function which allows us to construct a new
* Localization from Localization.
*/
var getLocalization = (resourceIds) => {
return new Localization(resourceIds);
var getLocalization = (resourceIds, sync = false) => {
return new Localization(resourceIds, sync);
};
var getLocalizationWithCustomGenerateMessages = (resourceIds, generateMessages) => {
return new Localization(resourceIds, false, generateMessages);
};
this.Localization = Localization;
var EXPORTED_SYMBOLS = ["Localization", "getLocalization"];
var EXPORTED_SYMBOLS = ["Localization", "getLocalization", "getLocalizationWithCustomGenerateMessages"];

View File

@@ -14,28 +14,21 @@
[scriptable, uuid(7d468600-551f-4fe0-98c9-92a53b63ec8d)]
interface mozILocalization : nsISupports
{
void setGenerateBundles(in jsval generateBundles);
void setGenerateBundlesSync(in jsval generateBundlesSync);
void setIsSync(in boolean isSync);
void init(in boolean aEager);
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 AUTF8String aId, [optional] in jsval aArgs);
AUTF8String formatValueSync(in AUTF8String aId, [optional] in jsval aArgs);
Array<AUTF8String> formatValuesSync(in Array<jsval> aKeys);
Array<jsval> formatMessagesSync(in Array<jsval> aKeys);
void onChange(in boolean aEager);
void setIsSync(in boolean isSync);
};
[scriptable, uuid(96632d26-1422-12e9-b1ce-9bb586acd241)]
interface mozILocalizationJSM : nsISupports
{
mozILocalization getLocalization(in Array<AString> resourceIds);
mozILocalization getLocalization(in Array<AString> resourceIds, in bool sync);
mozILocalization getLocalizationWithCustomGenerateMessages(in Array<AString> resourceIds, in jsval generateMessages);
};

View File

@@ -8,7 +8,7 @@
<script type="application/javascript">
"use strict";
async function* generateBundles(resourceIds) {
async function* mockGenerateMessages(resourceIds) {
const bundle = new FluentBundle("en-US", {
useIsolating: false,
});
@@ -31,8 +31,7 @@ key2 =
const loc = new Localization(
['mock.ftl'],
false,
{ generateBundles },
mockGenerateMessages,
);
{

View File

@@ -7,7 +7,7 @@
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript">
"use strict";
async function* generateBundles(resourceIds) {
async function* mockGenerateMessages(resourceIds) {
const bundle = new FluentBundle("en-US", {
useIsolating: false,
});
@@ -24,8 +24,7 @@ key3 = Value { $count }
const loc = new Localization(
['mock.ftl'],
false,
{ generateBundles },
mockGenerateMessages,
);
{

View File

@@ -7,7 +7,7 @@
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript">
"use strict";
async function* generateBundles(resourceIds) {
async function* mockGenerateMessages(resourceIds) {
const bundle = new FluentBundle("en-US",
{
useIsolating: false,
@@ -25,8 +25,7 @@ key3 = Value { $count }
const loc = new Localization(
['mock.ftl'],
false,
{ generateBundles },
mockGenerateMessages,
);
{

View File

@@ -2,6 +2,7 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
const { AppConstants } = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
const { Localization } = ChromeUtils.import("resource://gre/modules/Localization.jsm");
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
add_task(function test_methods_presence() {
@@ -28,13 +29,13 @@ add_task(async function test_methods_calling() {
const source = new FileSource("test", ["de", "en-US"], "/localization/{locale}");
L10nRegistry.registerSource(source);
async function* generateBundles(resIds) {
async function* generateMessages(resIds) {
yield * await L10nRegistry.generateBundles(["de", "en-US"], resIds);
}
const l10n = new Localization([
"/browser/menu.ftl",
], false, { generateBundles });
], false, generateMessages);
let values = await l10n.formatValues([{id: "key"}, {id: "key2"}]);
@@ -74,13 +75,13 @@ key = { PLATFORM() ->
const source = new FileSource("test", ["en-US"], "/localization/{locale}");
L10nRegistry.registerSource(source);
async function* generateBundles(resIds) {
async function* generateMessages(resIds) {
yield * await L10nRegistry.generateBundles(["en-US"], resIds);
}
const l10n = new Localization([
"/test.ftl",
], false, { generateBundles });
], false, generateMessages);
let values = await l10n.formatValues([{id: "key"}]);
@@ -109,11 +110,11 @@ add_task(async function test_add_remove_resourceIds() {
const source = new FileSource("test", ["en-US"], "/localization/{locale}");
L10nRegistry.registerSource(source);
async function* generateBundles(resIds) {
async function* generateMessages(resIds) {
yield * await L10nRegistry.generateBundles(["en-US"], resIds);
}
const l10n = new Localization(["/browser/menu.ftl"], false, { generateBundles });
const l10n = new Localization(["/browser/menu.ftl"], false, generateMessages);
let values = await l10n.formatValues([{id: "key1"}, {id: "key2"}]);
@@ -167,15 +168,15 @@ add_task(async function test_switch_to_async() {
const source = new FileSource("test", ["en-US"], "/localization/{locale}");
L10nRegistry.registerSource(source);
async function* generateBundles(resIds) {
async function* generateMessages(resIds) {
yield * await L10nRegistry.generateBundles(["en-US"], resIds);
}
function* generateBundlesSync(resIds) {
function* generateMessagesSync(resIds) {
yield * L10nRegistry.generateBundlesSync(["en-US"], resIds);
}
const l10n = new Localization(["/browser/menu.ftl"], false, { generateBundles, generateBundlesSync });
const l10n = new Localization(["/browser/menu.ftl"], false, generateMessages, generateMessagesSync);
let values = await l10n.formatValues([{id: "key1"}, {id: "key2"}]);

View File

@@ -2,6 +2,7 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
const { AppConstants } = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
const { Localization } = ChromeUtils.import("resource://gre/modules/Localization.jsm");
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
add_task(function test_methods_calling() {
@@ -22,13 +23,13 @@ add_task(function test_methods_calling() {
const source = new FileSource("test", ["de", "en-US"], "/localization/{locale}");
L10nRegistry.registerSource(source);
function* generateBundlesSync(resIds) {
function* generateMessagesSync(resIds) {
yield * L10nRegistry.generateBundlesSync(["de", "en-US"], resIds);
}
const l10n = new Localization([
"/browser/menu.ftl",
], true, { generateBundlesSync });
], true, null, generateMessagesSync);
let values = l10n.formatValuesSync([{id: "key"}, {id: "key2"}]);
@@ -68,13 +69,13 @@ key = { PLATFORM() ->
const source = new FileSource("test", ["en-US"], "/localization/{locale}");
L10nRegistry.registerSource(source);
function* generateBundlesSync(resIds) {
function* generateMessagesSync(resIds) {
yield * L10nRegistry.generateBundlesSync(["en-US"], resIds);
}
const l10n = new Localization([
"/test.ftl",
], true, { generateBundlesSync });
], true, null, generateMessagesSync);
let values = l10n.formatValuesSync([{id: "key"}]);
@@ -103,11 +104,11 @@ add_task(function test_add_remove_resourceIds() {
const source = new FileSource("test", ["en-US"], "/localization/{locale}");
L10nRegistry.registerSource(source);
function* generateBundlesSync(resIds) {
function* generateMessagesSync(resIds) {
yield * L10nRegistry.generateBundlesSync(["en-US"], resIds);
}
const l10n = new Localization(["/browser/menu.ftl"], true, { generateBundlesSync });
const l10n = new Localization(["/browser/menu.ftl"], true, null, generateMessagesSync);
let values = l10n.formatValuesSync([{id: "key1"}, {id: "key2"}]);

View File

@@ -1,6 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const { Localization } = ChromeUtils.import("resource://gre/modules/Localization.jsm");
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { L10nRegistry, FileSource } =
ChromeUtils.import("resource://gre/modules/L10nRegistry.jsm");
@@ -45,11 +46,12 @@ function getAttributeByName(attributes, name) {
add_task(async function test_accented_works() {
Services.prefs.setStringPref("intl.l10n.pseudo", "");
let generateBundles = addMockFileSource();
let generateMessages = addMockFileSource();
const l10n = new Localization([
"/browser/menu.ftl",
], false, { generateBundles });
], false, generateMessages);
l10n.registerObservers();
{
// 1. Start with no pseudo
@@ -114,11 +116,12 @@ add_task(async function test_accented_works() {
add_task(async function test_unavailable_strategy_works() {
Services.prefs.setStringPref("intl.l10n.pseudo", "");
let generateBundles = addMockFileSource();
let generateMessages = addMockFileSource();
const l10n = new Localization([
"/browser/menu.ftl",
], false, { generateBundles });
], false, generateMessages);
l10n.registerObservers();
{
// 1. Set unavailable pseudo strategy

View File

@@ -61,6 +61,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
FileSource: "resource://gre/modules/L10nRegistry.jsm",
L10nRegistry: "resource://gre/modules/L10nRegistry.jsm",
LightweightThemeManager: "resource://gre/modules/LightweightThemeManager.jsm",
Localization: "resource://gre/modules/Localization.jsm",
Log: "resource://gre/modules/Log.jsm",
MessageChannel: "resource://gre/modules/MessageChannel.jsm",
NetUtil: "resource://gre/modules/NetUtil.jsm",

View File

@@ -3,6 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { Localization } = ChromeUtils.import(
"resource://gre/modules/Localization.jsm",
null
);
const mozIntlHelper = Cc["@mozilla.org/mozintlhelper;1"].getService(
Ci.mozIMozIntlHelper