Bug 1642423: document.l10n.formatValues should accept simple strings as well as L10nKeys. r=zbraniecki

Differential Revision: https://phabricator.services.mozilla.com/D77857
This commit is contained in:
Dave Townsend 2020-06-05 19:57:05 +00:00
parent 31e8efe4c0
commit 67bca5c4f4
9 changed files with 95 additions and 30 deletions

View File

@ -92,7 +92,7 @@ interface DOMLocalization : Localization {
* let l10nAttrs = document.l10n.getAttributes(h1);
* assert.deepEqual(l10nAttrs, {id: "key1", args: { emailCount: 5});
*/
[Throws] L10nKey getAttributes(Element aElement);
[Throws] L10nIdArgs getAttributes(Element aElement);
/**
* Triggers translation of a subtree rooted at aNode.

View File

@ -4,7 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* L10nKey is an object used to carry localization tuple for message
* L10nIdArgs is an object used to carry localization tuple for message
* translation.
*
* Fields:
@ -13,11 +13,17 @@
* The argument will be converted to/from JSON, and the API
* will only handle strings and numbers.
*/
dictionary L10nKey {
UTF8String? id = null;
dictionary L10nIdArgs {
required UTF8String id;
L10nArgs? args = null;
};
/**
* When no arguments are required to format a message a simple string can be
* used instead.
*/
typedef (UTF8String or L10nIdArgs) L10nKey;
/**
* L10nMessage is a compound translation unit from Fluent which
* encodes the value and (optionally) a list of attributes used

View File

@ -147,7 +147,7 @@ void DOMLocalization::SetAttributes(
}
}
void DOMLocalization::GetAttributes(Element& aElement, L10nKey& aResult,
void DOMLocalization::GetAttributes(Element& aElement, L10nIdArgs& aResult,
ErrorResult& aRv) {
nsAutoString l10nId;
nsAutoString l10nArgs;
@ -290,8 +290,8 @@ already_AddRefed<Promise> DOMLocalization::TranslateElements(
const Sequence<OwningNonNull<Element>>& aElements,
nsXULPrototypeDocument* aProto, ErrorResult& aRv) {
JS::RootingContext* rcx = RootingCx();
Sequence<L10nKey> l10nKeys;
SequenceRooter<L10nKey> rooter(rcx, &l10nKeys);
Sequence<OwningUTF8StringOrL10nIdArgs> l10nKeys;
SequenceRooter<OwningUTF8StringOrL10nIdArgs> rooter(rcx, &l10nKeys);
RefPtr<ElementTranslationHandler> nativeHandler =
new ElementTranslationHandler(this, aProto);
nsTArray<nsCOMPtr<Element>>& domElements = nativeHandler->Elements();
@ -309,13 +309,13 @@ already_AddRefed<Promise> DOMLocalization::TranslateElements(
continue;
}
L10nKey* key = l10nKeys.AppendElement(fallible);
OwningUTF8StringOrL10nIdArgs* key = l10nKeys.AppendElement(fallible);
if (!key) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return nullptr;
}
GetAttributes(*domElement, *key, aRv);
GetAttributes(*domElement, key->SetAsL10nIdArgs(), aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}

View File

@ -52,7 +52,7 @@ class DOMLocalization : public intl::Localization {
void SetAttributes(JSContext* aCx, Element& aElement, const nsAString& aId,
const Optional<JS::Handle<JSObject*>>& aArgs,
ErrorResult& aRv);
void GetAttributes(Element& aElement, L10nKey& aResult, ErrorResult& aRv);
void GetAttributes(Element& aElement, L10nIdArgs& aResult, ErrorResult& aRv);
already_AddRefed<Promise> TranslateFragment(nsINode& aNode, ErrorResult& aRv);

View File

@ -273,7 +273,7 @@ already_AddRefed<Promise> Localization::FormatValue(
void Localization::SetIsSync(const bool aIsSync) { mIsSync = aIsSync; }
already_AddRefed<Promise> Localization::FormatValues(
JSContext* aCx, const Sequence<L10nKey>& aKeys, ErrorResult& aRv) {
JSContext* aCx, const Sequence<OwningUTF8StringOrL10nIdArgs>& aKeys, ErrorResult& aRv) {
if (!mLocalization) {
Activate(false);
}
@ -300,7 +300,7 @@ already_AddRefed<Promise> Localization::FormatValues(
}
already_AddRefed<Promise> Localization::FormatMessages(
JSContext* aCx, const Sequence<L10nKey>& aKeys, ErrorResult& aRv) {
JSContext* aCx, const Sequence<OwningUTF8StringOrL10nIdArgs>& aKeys, ErrorResult& aRv) {
if (!mLocalization) {
Activate(false);
}
@ -354,7 +354,7 @@ void Localization::FormatValueSync(JSContext* aCx, const nsACString& aId,
}
void Localization::FormatValuesSync(JSContext* aCx,
const Sequence<L10nKey>& aKeys,
const Sequence<OwningUTF8StringOrL10nIdArgs>& aKeys,
nsTArray<nsCString>& aRetVal,
ErrorResult& aRv) {
if (!mIsSync) {
@ -382,7 +382,7 @@ void Localization::FormatValuesSync(JSContext* aCx,
}
void Localization::FormatMessagesSync(JSContext* aCx,
const Sequence<L10nKey>& aKeys,
const Sequence<OwningUTF8StringOrL10nIdArgs>& aKeys,
nsTArray<Nullable<L10nMessage>>& aRetVal,
ErrorResult& aRv) {
if (!mIsSync) {

View File

@ -66,22 +66,24 @@ class Localization : public nsIObserver,
const Optional<L10nArgs>& aArgs,
ErrorResult& aRv);
already_AddRefed<Promise> FormatValues(JSContext* aCx,
const Sequence<L10nKey>& aKeys,
ErrorResult& aRv);
already_AddRefed<Promise> FormatValues(
JSContext* aCx, const Sequence<OwningUTF8StringOrL10nIdArgs>& aKeys,
ErrorResult& aRv);
already_AddRefed<Promise> FormatMessages(JSContext* aCx,
const Sequence<L10nKey>& aKeys,
ErrorResult& aRv);
already_AddRefed<Promise> FormatMessages(
JSContext* aCx, const Sequence<OwningUTF8StringOrL10nIdArgs>& 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,
void FormatValuesSync(JSContext* aCx,
const Sequence<OwningUTF8StringOrL10nIdArgs>& aKeys,
nsTArray<nsCString>& aRetVal, ErrorResult& aRv);
void FormatMessagesSync(JSContext* aCx, const Sequence<L10nKey>& aKeys,
void FormatMessagesSync(JSContext* aCx,
const Sequence<OwningUTF8StringOrL10nIdArgs>& aKeys,
nsTArray<Nullable<L10nMessage>>& aRetVal,
ErrorResult& aRv);

View File

@ -228,7 +228,7 @@ const Localization = {
* @param {Array<String>} resourceIds - List of resource ids used by this
* localization.
* @param {Iter<FluentBundle>} bundles - Iterator over bundles.
* @param {Array<Object>} keys - Translation keys to format.
* @param {Array<string|Object>} keys - Translation keys to format.
* @param {Function} method - Formatting function.
* @returns {Promise<Array<string?|Object?>>}
* @private
@ -271,7 +271,7 @@ const Localization = {
* @param {Array<String>} resourceIds - List of resource ids used by this
* localization.
* @param {Iter<FluentBundle>} bundles - Iterator over bundles.
* @param {Array<Object>} keys - Translation keys to format.
* @param {Array<string|Object>} keys - Translation keys to format.
* @param {Function} method - Formatting function.
* @returns {Array<string|Object>}
* @private
@ -330,7 +330,7 @@ const Localization = {
* @param {Array<String>} resourceIds - List of resource ids used by this
* localization.
* @param {Iter<FluentBundle>} bundles - Iterator over bundles.
* @param {Array<Object>} keys - Translation keys to format.
* @param {Array<string|Object>} keys - Translation keys to format.
* @returns {Promise<Array<{value: string, attributes: Object}?>>}
* @private
*/
@ -346,7 +346,7 @@ const Localization = {
* @param {Array<String>} resourceIds - List of resource ids used by this
* localization.
* @param {Iter<FluentBundle>} bundles - Iterator over bundles.
* @param {Array<Object>} keys - Translation keys to format.
* @param {Array<string|Object>} keys - Translation keys to format.
* @returns {Array<{value: string, attributes: Object}?>}
* @private
*/
@ -373,7 +373,7 @@ const Localization = {
* @param {Array<String>} resourceIds - List of resource ids used by this
* localization.
* @param {Iter<FluentBundle>} bundles - Iterator over bundles.
* @param {Array<Object>} keys - Translation keys to format.
* @param {Array<string|Object>} keys - Translation keys to format.
* @returns {Promise<Array<string?>>}
*/
formatValues(resourceIds, bundles, keys) {
@ -388,7 +388,7 @@ const Localization = {
* @param {Array<String>} resourceIds - List of resource ids used by this
* localization.
* @param {Iter<FluentBundle>} bundles - Iterator over bundles.
* @param {Array<Object>} keys - Translation keys to format.
* @param {Array<string|Object>} keys - Translation keys to format.
* @returns {Array<string?>}
* @private
*/
@ -563,7 +563,7 @@ function messageFromBundle(bundle, errors, message, args) {
*
* @param {Function} method
* @param {FluentBundle} bundle
* @param {Array<string>} keys
* @param {Array<string|Object>} keys
* @param {{Array<{value: string, attributes: Object}>}} translations
*
* @returns {Set<string>}
@ -573,7 +573,16 @@ function keysFromBundle(method, bundle, keys, translations) {
const messageErrors = [];
const missingIds = new Set();
keys.forEach(({id, args}, i) => {
keys.forEach((key, i) => {
let id;
let args = undefined;
if (typeof key == "object" && "id" in key) {
id = String(key.id);
args = key.args;
} else {
id = String(key);
}
if (translations[i] !== null) {
return;
}

View File

@ -57,6 +57,20 @@ key-attr =
strictEqual(values[3], null);
}
{
let values = await l10n.formatValues([
"key-value1",
"key-value2",
"key-missing",
"key-attr"
]);
strictEqual(values[0], "[de] Value2");
strictEqual(values[1], "[en] Value3");
strictEqual(values[2], null);
strictEqual(values[3], null);
}
{
strictEqual(await l10n.formatValue("key-missing"), null);
strictEqual(await l10n.formatValue("key-value1"), "[de] Value2");
@ -164,6 +178,16 @@ add_task(async function test_add_remove_resourceIds() {
strictEqual(values[0], "Value1");
strictEqual(values[1], "Value2");
values = await l10n.formatValues(["key1", {id: "key2"}]);
strictEqual(values[0], "Value1");
strictEqual(values[1], "Value2");
values = await l10n.formatValues([{id: "key1"}, "key2"]);
strictEqual(values[0], "Value1");
strictEqual(values[1], "Value2");
l10n.removeResourceIds(["/browser/menu.ftl"]);
values = await l10n.formatValues([{id: "key1"}, {id: "key2"}]);

View File

@ -52,6 +52,20 @@ key-attr =
strictEqual(values[3], null);
}
{
let values = l10n.formatValuesSync([
"key-value1",
"key-value2",
"key-missing",
"key-attr"
]);
strictEqual(values[0], "[de] Value2");
strictEqual(values[1], "[en] Value3");
strictEqual(values[2], null);
strictEqual(values[3], null);
}
{
strictEqual(l10n.formatValueSync("key-missing"), null);
strictEqual(l10n.formatValueSync("key-value1"), "[de] Value2");
@ -159,6 +173,16 @@ add_task(function test_add_remove_resourceIds() {
strictEqual(values[0], "Value1");
strictEqual(values[1], "Value2");
values = l10n.formatValuesSync(["key1", {id: "key2"}]);
strictEqual(values[0], "Value1");
strictEqual(values[1], "Value2");
values = l10n.formatValuesSync([{id: "key1"}, "key2"]);
strictEqual(values[0], "Value1");
strictEqual(values[1], "Value2");
l10n.removeResourceIds(["/browser/menu.ftl"]);
values = l10n.formatValuesSync([{id: "key1"}, {id: "key2"}]);