Compare commits

..

3 Commits

Author SHA1 Message Date
Romeo Fragomeli 871dad6a13 [REL] v2.8.0
# v2.8.0

 - [FIX] parser: t-esc/t-out vs t-translation*
 - [IMP] compiler: make human-readable ARIA attributes translatable
2025-06-30 14:46:16 +02:00
Mathieu Duckerts-Antoine b620502a0f [FIX] parser: t-esc/t-out vs t-translation*
The directives t-esc/t-out both discard the ASTs that are not of DomNode
type. Since the directives t-translation and t-translation-context both
creates AST wrappers of type TTranslation and TTranslationContext
respectively, mix t-esc/t-out and t-translation/t-translation-context
does not work. For example parse

<span t-esc="'Hello'" t-translation="off"/>

gives the AST

{
    type: ASTType.TEsc,
    expr: "'Hello'",
    defaultValue: "",
}

This makes the span not been rendered in the end.

We fix that problem.
2025-06-24 16:03:56 +02:00
Louis Wicket (wil) 89cb00cc83 [IMP] compiler: make human-readable ARIA attributes translatable
ARIA attributes containing human-readable text should be translated.
This commit adds human-readable ARIA attributes to the list of the
attributes translated by OWL.
2025-04-03 21:40:27 +02:00
7 changed files with 128 additions and 12 deletions
+15 -6
View File
@@ -3850,7 +3850,16 @@ class CodeTarget {
return key;
}
}
const TRANSLATABLE_ATTRS = ["label", "title", "placeholder", "alt"];
const TRANSLATABLE_ATTRS = [
"alt",
"aria-label",
"aria-placeholder",
"aria-roledescription",
"aria-valuetext",
"label",
"placeholder",
"title",
];
const translationRE = /^(\s*)([\s\S]+?)(\s*)$/;
class CodeGenerator {
constructor(ast, options) {
@@ -4968,11 +4977,11 @@ function parseNode(node, ctx) {
parseTPortal(node, ctx) ||
parseTCall(node, ctx) ||
parseTCallBlock(node) ||
parseTTranslation(node, ctx) ||
parseTTranslationContext(node, ctx) ||
parseTEscNode(node, ctx) ||
parseTOutNode(node, ctx) ||
parseTKey(node, ctx) ||
parseTTranslation(node, ctx) ||
parseTTranslationContext(node, ctx) ||
parseTSlot(node, ctx) ||
parseComponent(node, ctx) ||
parseDOMNode(node, ctx) ||
@@ -5758,7 +5767,7 @@ function compile(template, options = {
}
// do not modify manually. This file is generated by the release script.
const version = "2.7.0";
const version = "2.8.0";
// -----------------------------------------------------------------------------
// Scheduler
@@ -6229,6 +6238,6 @@ TemplateSet.prototype._compileTemplate = function _compileTemplate(name, templat
export { App, Component, EventBus, OwlError, __info__, batched, blockDom, htmlEscape, loadFile, markRaw, markup, mount, onError, onMounted, onPatched, onRendered, onWillDestroy, onWillPatch, onWillRender, onWillStart, onWillUnmount, onWillUpdateProps, reactive, status, toRaw, useChildSubEnv, useComponent, useEffect, useEnv, useExternalListener, useRef, useState, useSubEnv, validate, validateType, whenReady, xml };
__info__.date = '2025-03-26T12:58:40.935Z';
__info__.hash = 'e788e36';
__info__.date = '2025-06-30T12:46:06.424Z';
__info__.hash = 'b620502';
__info__.url = 'https://github.com/odoo/owl';
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@odoo/owl",
"version": "2.7.0",
"version": "2.8.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@odoo/owl",
"version": "2.7.0",
"version": "2.8.0",
"description": "Odoo Web Library (OWL)",
"main": "dist/owl.cjs.js",
"module": "dist/owl.es.js",
+10 -1
View File
@@ -254,7 +254,16 @@ class CodeTarget {
}
}
const TRANSLATABLE_ATTRS = ["label", "title", "placeholder", "alt"];
const TRANSLATABLE_ATTRS = [
"alt",
"aria-label",
"aria-placeholder",
"aria-roledescription",
"aria-valuetext",
"label",
"placeholder",
"title",
];
const translationRE = /^(\s*)([\s\S]+?)(\s*)$/;
export class CodeGenerator {
+2 -2
View File
@@ -253,11 +253,11 @@ function parseNode(node: Node, ctx: ParsingContext): AST | null {
parseTPortal(node, ctx) ||
parseTCall(node, ctx) ||
parseTCallBlock(node, ctx) ||
parseTTranslation(node, ctx) ||
parseTTranslationContext(node, ctx) ||
parseTEscNode(node, ctx) ||
parseTOutNode(node, ctx) ||
parseTKey(node, ctx) ||
parseTTranslation(node, ctx) ||
parseTTranslationContext(node, ctx) ||
parseTSlot(node, ctx) ||
parseComponent(node, ctx) ||
parseDOMNode(node, ctx) ||
+1 -1
View File
@@ -1,2 +1,2 @@
// do not modify manually. This file is generated by the release script.
export const version = "2.7.0";
export const version = "2.8.0";
+98
View File
@@ -1971,6 +1971,54 @@ describe("qweb parser", () => {
});
});
test('t-translation="off": interaction with t-esc', async () => {
expect(parse(`<span t-esc="a" t-translation="off"/>`)).toEqual({
type: ASTType.TTranslation,
content: {
attrs: null,
attrsTranslationCtx: null,
content: [
{
defaultValue: "",
expr: "a",
type: ASTType.TEsc,
},
],
dynamicTag: null,
model: null,
ns: null,
on: null,
ref: null,
tag: "span",
type: ASTType.DomNode,
},
});
});
test('t-translation="off": interaction with t-out', async () => {
expect(parse(`<span t-out="a" t-translation="off"/>`)).toEqual({
type: ASTType.TTranslation,
content: {
attrs: null,
attrsTranslationCtx: null,
content: [
{
body: null,
expr: "a",
type: ASTType.TOut,
},
],
dynamicTag: null,
model: null,
ns: null,
on: null,
ref: null,
tag: "span",
type: ASTType.DomNode,
},
});
});
// ---------------------------------------------------------------------------
// t-translation-context
// ---------------------------------------------------------------------------
@@ -2008,6 +2056,56 @@ describe("qweb parser", () => {
});
});
test("t-translation-context: interaction with t-esc", async () => {
expect(parse(`<span t-esc="a" t-translation-context="fr"/>`)).toEqual({
type: ASTType.TTranslationContext,
content: {
attrs: null,
attrsTranslationCtx: null,
content: [
{
defaultValue: "",
expr: "a",
type: ASTType.TEsc,
},
],
dynamicTag: null,
model: null,
ns: null,
on: null,
ref: null,
tag: "span",
type: ASTType.DomNode,
},
translationCtx: "fr",
});
});
test("t-translation-context: interaction with t-out", async () => {
expect(parse(`<span t-out="a" t-translation-context="fr"/>`)).toEqual({
type: ASTType.TTranslationContext,
content: {
attrs: null,
attrsTranslationCtx: null,
content: [
{
body: null,
expr: "a",
type: ASTType.TOut,
},
],
dynamicTag: null,
model: null,
ns: null,
on: null,
ref: null,
tag: "span",
type: ASTType.DomNode,
},
translationCtx: "fr",
});
});
// ---------------------------------------------------------------------------
// t-translation-context-attr
// ---------------------------------------------------------------------------