mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[REL] v2.6.0
# v2.6.0 - [IMP] translation contexts
This commit is contained in:
+107
-22
@@ -3738,6 +3738,7 @@ function createContext(parentCtx, params) {
|
||||
index: 0,
|
||||
forceNewBlock: true,
|
||||
translate: parentCtx.translate,
|
||||
translationCtx: parentCtx.translationCtx,
|
||||
tKeyExpr: null,
|
||||
nameSpace: parentCtx.nameSpace,
|
||||
tModelSelectedExpr: parentCtx.tModelSelectedExpr,
|
||||
@@ -3840,6 +3841,7 @@ class CodeGenerator {
|
||||
forceNewBlock: false,
|
||||
isLast: true,
|
||||
translate: true,
|
||||
translationCtx: "",
|
||||
tKeyExpr: null,
|
||||
});
|
||||
// define blocks and utility functions
|
||||
@@ -3977,9 +3979,9 @@ class CodeGenerator {
|
||||
})
|
||||
.join("");
|
||||
}
|
||||
translate(str) {
|
||||
translate(str, translationCtx) {
|
||||
const match = translationRE.exec(str);
|
||||
return match[1] + this.translateFn(match[2]) + match[3];
|
||||
return match[1] + this.translateFn(match[2], translationCtx) + match[3];
|
||||
}
|
||||
/**
|
||||
* @returns the newly created block name, if any
|
||||
@@ -4020,7 +4022,9 @@ class CodeGenerator {
|
||||
return this.compileTSlot(ast, ctx);
|
||||
case 16 /* TTranslation */:
|
||||
return this.compileTTranslation(ast, ctx);
|
||||
case 17 /* TPortal */:
|
||||
case 17 /* TTranslationContext */:
|
||||
return this.compileTTranslationContext(ast, ctx);
|
||||
case 18 /* TPortal */:
|
||||
return this.compileTPortal(ast, ctx);
|
||||
}
|
||||
}
|
||||
@@ -4058,7 +4062,7 @@ class CodeGenerator {
|
||||
let { block, forceNewBlock } = ctx;
|
||||
let value = ast.value;
|
||||
if (value && ctx.translate !== false) {
|
||||
value = this.translate(value);
|
||||
value = this.translate(value, ctx.translationCtx);
|
||||
}
|
||||
if (!ctx.inPreTag) {
|
||||
value = value.replace(whitespaceRE, " ");
|
||||
@@ -4093,6 +4097,7 @@ class CodeGenerator {
|
||||
return `[${modifiersCode}${this.captureExpression(handler)}, ctx]`;
|
||||
}
|
||||
compileTDomNode(ast, ctx) {
|
||||
var _a;
|
||||
let { block, forceNewBlock } = ctx;
|
||||
const isNewBlock = !block || forceNewBlock || ast.dynamicTag !== null || ast.ns;
|
||||
let codeIdx = this.target.code.length;
|
||||
@@ -4148,7 +4153,8 @@ class CodeGenerator {
|
||||
}
|
||||
}
|
||||
else if (this.translatableAttributes.includes(key)) {
|
||||
attrs[key] = this.translateFn(ast.attrs[key]);
|
||||
const attrTranslationCtx = ((_a = ast.attrsTranslationCtx) === null || _a === void 0 ? void 0 : _a[key]) || ctx.translationCtx;
|
||||
attrs[key] = this.translateFn(ast.attrs[key], attrTranslationCtx);
|
||||
}
|
||||
else {
|
||||
expr = `"${ast.attrs[key]}"`;
|
||||
@@ -4592,7 +4598,7 @@ class CodeGenerator {
|
||||
else {
|
||||
let value;
|
||||
if (ast.defaultValue) {
|
||||
const defaultValue = toStringExpression(ctx.translate ? this.translate(ast.defaultValue) : ast.defaultValue);
|
||||
const defaultValue = toStringExpression(ctx.translate ? this.translate(ast.defaultValue, ctx.translationCtx) : ast.defaultValue);
|
||||
if (ast.value) {
|
||||
value = `withDefault(${expr}, ${defaultValue})`;
|
||||
}
|
||||
@@ -4626,9 +4632,10 @@ class CodeGenerator {
|
||||
* "some-prop" "state" "'some-prop': ctx['state']"
|
||||
* "onClick.bind" "onClick" "onClick: bind(ctx, ctx['onClick'])"
|
||||
*/
|
||||
formatProp(name, value) {
|
||||
formatProp(name, value, attrsTranslationCtx, translationCtx) {
|
||||
if (name.endsWith(".translate")) {
|
||||
value = toStringExpression(this.translateFn(value));
|
||||
const attrTranslationCtx = (attrsTranslationCtx === null || attrsTranslationCtx === void 0 ? void 0 : attrsTranslationCtx[name]) || translationCtx;
|
||||
value = toStringExpression(this.translateFn(value, attrTranslationCtx));
|
||||
}
|
||||
else {
|
||||
value = this.captureExpression(value);
|
||||
@@ -4650,8 +4657,8 @@ class CodeGenerator {
|
||||
name = /^[a-z_]+$/i.test(name) ? name : `'${name}'`;
|
||||
return `${name}: ${value || undefined}`;
|
||||
}
|
||||
formatPropObject(obj) {
|
||||
return Object.entries(obj).map(([k, v]) => this.formatProp(k, v));
|
||||
formatPropObject(obj, attrsTranslationCtx, translationCtx) {
|
||||
return Object.entries(obj).map(([k, v]) => this.formatProp(k, v, attrsTranslationCtx, translationCtx));
|
||||
}
|
||||
getPropString(props, dynProps) {
|
||||
let propString = `{${props.join(",")}}`;
|
||||
@@ -4664,7 +4671,9 @@ class CodeGenerator {
|
||||
let { block } = ctx;
|
||||
// props
|
||||
const hasSlotsProp = "slots" in (ast.props || {});
|
||||
const props = ast.props ? this.formatPropObject(ast.props) : [];
|
||||
const props = ast.props
|
||||
? this.formatPropObject(ast.props, ast.propsTranslationCtx, ctx.translationCtx)
|
||||
: [];
|
||||
// slots
|
||||
let slotDef = "";
|
||||
if (ast.slots) {
|
||||
@@ -4687,7 +4696,7 @@ class CodeGenerator {
|
||||
params.push(`__scope: "${scope}"`);
|
||||
}
|
||||
if (ast.slots[slotName].attrs) {
|
||||
params.push(...this.formatPropObject(ast.slots[slotName].attrs));
|
||||
params.push(...this.formatPropObject(ast.slots[slotName].attrs, ast.slots[slotName].attrsTranslationCtx, ctx.translationCtx));
|
||||
}
|
||||
const slotInfo = `{${params.join(", ")}}`;
|
||||
slotStr.push(`'${slotName}': ${slotInfo}`);
|
||||
@@ -4800,7 +4809,9 @@ class CodeGenerator {
|
||||
if (isMultiple) {
|
||||
key = this.generateComponentKey(key);
|
||||
}
|
||||
const props = ast.attrs ? this.formatPropObject(ast.attrs) : [];
|
||||
const props = ast.attrs
|
||||
? this.formatPropObject(ast.attrs, ast.attrsTranslationCtx, ctx.translationCtx)
|
||||
: [];
|
||||
const scope = this.getPropString(props, dynProps);
|
||||
if (ast.defaultContent) {
|
||||
const name = this.compileInNewTarget("defaultContent", ast.defaultContent, ctx);
|
||||
@@ -4833,6 +4844,12 @@ class CodeGenerator {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
compileTTranslationContext(ast, ctx) {
|
||||
if (ast.content) {
|
||||
return this.compileAST(ast.content, Object.assign({}, ctx, { translationCtx: ast.translationCtx }));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
compileTPortal(ast, ctx) {
|
||||
if (!this.staticDefs.find((d) => d.id === "Portal")) {
|
||||
this.staticDefs.push({ id: "Portal", expr: `app.Portal` });
|
||||
@@ -4902,6 +4919,7 @@ function parseNode(node, ctx) {
|
||||
parseTOutNode(node, ctx) ||
|
||||
parseTKey(node, ctx) ||
|
||||
parseTTranslation(node, ctx) ||
|
||||
parseTTranslationContext(node, ctx) ||
|
||||
parseTSlot(node, ctx) ||
|
||||
parseComponent(node, ctx) ||
|
||||
parseDOMNode(node, ctx) ||
|
||||
@@ -5010,6 +5028,7 @@ function parseDOMNode(node, ctx) {
|
||||
node.removeAttribute("t-ref");
|
||||
const nodeAttrsNames = node.getAttributeNames();
|
||||
let attrs = null;
|
||||
let attrsTranslationCtx = null;
|
||||
let on = null;
|
||||
let model = null;
|
||||
for (let attr of nodeAttrsNames) {
|
||||
@@ -5070,6 +5089,11 @@ function parseDOMNode(node, ctx) {
|
||||
else if (attr === "xmlns") {
|
||||
ns = value;
|
||||
}
|
||||
else if (attr.startsWith("t-translation-context-")) {
|
||||
const attrName = attr.slice(22);
|
||||
attrsTranslationCtx = attrsTranslationCtx || {};
|
||||
attrsTranslationCtx[attrName] = value;
|
||||
}
|
||||
else if (attr !== "t-name") {
|
||||
if (attr.startsWith("t-") && !attr.startsWith("t-att")) {
|
||||
throw new OwlError(`Unknown QWeb directive: '${attr}'`);
|
||||
@@ -5091,6 +5115,7 @@ function parseDOMNode(node, ctx) {
|
||||
tag: tagName,
|
||||
dynamicTag,
|
||||
attrs,
|
||||
attrsTranslationCtx,
|
||||
on,
|
||||
ref,
|
||||
content: children,
|
||||
@@ -5231,7 +5256,15 @@ function parseTCall(node, ctx) {
|
||||
if (ast && ast.type === 11 /* TComponent */) {
|
||||
return {
|
||||
...ast,
|
||||
slots: { default: { content: tcall, scope: null, on: null, attrs: null } },
|
||||
slots: {
|
||||
default: {
|
||||
content: tcall,
|
||||
scope: null,
|
||||
on: null,
|
||||
attrs: null,
|
||||
attrsTranslationCtx: null,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -5346,9 +5379,15 @@ function parseComponent(node, ctx) {
|
||||
node.removeAttribute("t-slot-scope");
|
||||
let on = null;
|
||||
let props = null;
|
||||
let propsTranslationCtx = null;
|
||||
for (let name of node.getAttributeNames()) {
|
||||
const value = node.getAttribute(name);
|
||||
if (name.startsWith("t-")) {
|
||||
if (name.startsWith("t-translation-context-")) {
|
||||
const attrName = name.slice(22);
|
||||
propsTranslationCtx = propsTranslationCtx || {};
|
||||
propsTranslationCtx[attrName] = value;
|
||||
}
|
||||
else if (name.startsWith("t-")) {
|
||||
if (name.startsWith("t-on-")) {
|
||||
on = on || {};
|
||||
on[name.slice(5)] = value;
|
||||
@@ -5392,6 +5431,7 @@ function parseComponent(node, ctx) {
|
||||
const slotAst = parseNode(slotNode, ctx);
|
||||
let on = null;
|
||||
let attrs = null;
|
||||
let attrsTranslationCtx = null;
|
||||
let scope = null;
|
||||
for (let attributeName of slotNode.getAttributeNames()) {
|
||||
const value = slotNode.getAttribute(attributeName);
|
||||
@@ -5399,6 +5439,11 @@ function parseComponent(node, ctx) {
|
||||
scope = value;
|
||||
continue;
|
||||
}
|
||||
else if (attributeName.startsWith("t-translation-context-")) {
|
||||
const attrName = attributeName.slice(22);
|
||||
attrsTranslationCtx = attrsTranslationCtx || {};
|
||||
attrsTranslationCtx[attrName] = value;
|
||||
}
|
||||
else if (attributeName.startsWith("t-on-")) {
|
||||
on = on || {};
|
||||
on[attributeName.slice(5)] = value;
|
||||
@@ -5409,17 +5454,32 @@ function parseComponent(node, ctx) {
|
||||
}
|
||||
}
|
||||
slots = slots || {};
|
||||
slots[name] = { content: slotAst, on, attrs, scope };
|
||||
slots[name] = { content: slotAst, on, attrs, attrsTranslationCtx, scope };
|
||||
}
|
||||
// default slot
|
||||
const defaultContent = parseChildNodes(clone, ctx);
|
||||
slots = slots || {};
|
||||
// t-set-slot="default" has priority over content
|
||||
if (defaultContent && !slots.default) {
|
||||
slots.default = { content: defaultContent, on, attrs: null, scope: defaultSlotScope };
|
||||
slots.default = {
|
||||
content: defaultContent,
|
||||
on,
|
||||
attrs: null,
|
||||
attrsTranslationCtx: null,
|
||||
scope: defaultSlotScope,
|
||||
};
|
||||
}
|
||||
}
|
||||
return { type: 11 /* TComponent */, name, isDynamic, dynamicProps, props, slots, on };
|
||||
return {
|
||||
type: 11 /* TComponent */,
|
||||
name,
|
||||
isDynamic,
|
||||
dynamicProps,
|
||||
props,
|
||||
propsTranslationCtx,
|
||||
slots,
|
||||
on,
|
||||
};
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
// Slots
|
||||
@@ -5431,6 +5491,7 @@ function parseTSlot(node, ctx) {
|
||||
const name = node.getAttribute("t-slot");
|
||||
node.removeAttribute("t-slot");
|
||||
let attrs = null;
|
||||
let attrsTranslationCtx = null;
|
||||
let on = null;
|
||||
for (let attributeName of node.getAttributeNames()) {
|
||||
const value = node.getAttribute(attributeName);
|
||||
@@ -5438,6 +5499,11 @@ function parseTSlot(node, ctx) {
|
||||
on = on || {};
|
||||
on[attributeName.slice(5)] = value;
|
||||
}
|
||||
else if (attributeName.startsWith("t-translation-context-")) {
|
||||
const attrName = attributeName.slice(22);
|
||||
attrsTranslationCtx = attrsTranslationCtx || {};
|
||||
attrsTranslationCtx[attrName] = value;
|
||||
}
|
||||
else {
|
||||
attrs = attrs || {};
|
||||
attrs[attributeName] = value;
|
||||
@@ -5447,10 +5513,14 @@ function parseTSlot(node, ctx) {
|
||||
type: 14 /* TSlot */,
|
||||
name,
|
||||
attrs,
|
||||
attrsTranslationCtx,
|
||||
on,
|
||||
defaultContent: parseChildNodes(node, ctx),
|
||||
};
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
// Translation
|
||||
// -----------------------------------------------------------------------------
|
||||
function parseTTranslation(node, ctx) {
|
||||
if (node.getAttribute("t-translation") !== "off") {
|
||||
return null;
|
||||
@@ -5462,6 +5532,21 @@ function parseTTranslation(node, ctx) {
|
||||
};
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
// Translation Context
|
||||
// -----------------------------------------------------------------------------
|
||||
function parseTTranslationContext(node, ctx) {
|
||||
const translationCtx = node.getAttribute("t-translation-context");
|
||||
if (!translationCtx) {
|
||||
return null;
|
||||
}
|
||||
node.removeAttribute("t-translation-context");
|
||||
return {
|
||||
type: 17 /* TTranslationContext */,
|
||||
content: parseNode(node, ctx),
|
||||
translationCtx,
|
||||
};
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
// Portal
|
||||
// -----------------------------------------------------------------------------
|
||||
function parseTPortal(node, ctx) {
|
||||
@@ -5478,7 +5563,7 @@ function parseTPortal(node, ctx) {
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: 17 /* TPortal */,
|
||||
type: 18 /* TPortal */,
|
||||
target,
|
||||
content,
|
||||
};
|
||||
@@ -5620,7 +5705,7 @@ function compile(template, options = {
|
||||
}
|
||||
|
||||
// do not modify manually. This file is generated by the release script.
|
||||
const version = "2.5.3";
|
||||
const version = "2.6.0";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Scheduler
|
||||
@@ -6098,6 +6183,6 @@ TemplateSet.prototype._compileTemplate = function _compileTemplate(name, templat
|
||||
export { App, Component, EventBus, OwlError, __info__, batched, blockDom, 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-01-10T10:10:53.709Z';
|
||||
__info__.hash = 'b31fa81';
|
||||
__info__.date = '2025-01-15T10:40:24.184Z';
|
||||
__info__.hash = 'a9be149';
|
||||
__info__.url = 'https://github.com/odoo/owl';
|
||||
|
||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@odoo/owl",
|
||||
"version": "2.5.3",
|
||||
"version": "2.6.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@odoo/owl",
|
||||
"version": "2.5.3",
|
||||
"version": "2.6.0",
|
||||
"description": "Odoo Web Library (OWL)",
|
||||
"main": "dist/owl.cjs.js",
|
||||
"module": "dist/owl.es.js",
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
// do not modify manually. This file is generated by the release script.
|
||||
export const version = "2.5.3";
|
||||
export const version = "2.6.0";
|
||||
|
||||
Reference in New Issue
Block a user