mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
committed by
Aaron Bohy
parent
f07ec21a07
commit
2279dafbec
+1
-1
@@ -441,7 +441,7 @@ of an Owl application has to be created manually:
|
|||||||
```js
|
```js
|
||||||
class App extends owl.Component { ... }
|
class App extends owl.Component { ... }
|
||||||
|
|
||||||
const qweb = new owl.QWeb(TEMPLATES);
|
const qweb = new owl.QWeb({ templates: TEMPLATES });
|
||||||
const env = { qweb: qweb };
|
const env = { qweb: qweb };
|
||||||
const app = new App(env);
|
const app = new App(env);
|
||||||
app.mount(document.body);
|
app.mount(document.body);
|
||||||
|
|||||||
+1
-1
@@ -29,7 +29,7 @@ context, and add it to the environment:
|
|||||||
```js
|
```js
|
||||||
const deviceContext = new Context({ isMobile: true });
|
const deviceContext = new Context({ isMobile: true });
|
||||||
const env = {
|
const env = {
|
||||||
qweb: new QWeb(TEMPLATES),
|
qweb: new QWeb({ templates: TEMPLATES }),
|
||||||
deviceContext
|
deviceContext
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|||||||
+1
-1
@@ -89,7 +89,7 @@ class ClickCounter extends owl.Component {
|
|||||||
async function start() {
|
async function start() {
|
||||||
const templates = await owl.utils.loadFile("templates.xml");
|
const templates = await owl.utils.loadFile("templates.xml");
|
||||||
const env = {
|
const env = {
|
||||||
qweb: new owl.QWeb(templates)
|
qweb: new owl.QWeb({ templates })
|
||||||
};
|
};
|
||||||
const counter = new ClickCounter(env);
|
const counter = new ClickCounter(env);
|
||||||
const target = document.getElementById("main");
|
const target = document.getElementById("main");
|
||||||
|
|||||||
+65
-13
@@ -16,6 +16,7 @@
|
|||||||
- [Dynamic Attributes](#dynamic-attributes)
|
- [Dynamic Attributes](#dynamic-attributes)
|
||||||
- [Loops](#loops)
|
- [Loops](#loops)
|
||||||
- [Rendering Sub Templates](#rendering-sub-templates)
|
- [Rendering Sub Templates](#rendering-sub-templates)
|
||||||
|
- [Translations](#translations)
|
||||||
- [Debugging](#debugging)
|
- [Debugging](#debugging)
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
@@ -60,6 +61,7 @@ We present here a list of all standard QWeb directives:
|
|||||||
| `t-att`, `t-attf-*`, `t-att-*` | [Dynamic attributes](#dynamic-attributes) |
|
| `t-att`, `t-attf-*`, `t-att-*` | [Dynamic attributes](#dynamic-attributes) |
|
||||||
| `t-call` | [Rendering sub templates](#rendering-sub-templates) |
|
| `t-call` | [Rendering sub templates](#rendering-sub-templates) |
|
||||||
| `t-debug`, `t-log` | [Debugging](#debugging) |
|
| `t-debug`, `t-log` | [Debugging](#debugging) |
|
||||||
|
| `t-translation` | [Disabling the translation of a node](#translations) |
|
||||||
| `t-name` | [Defining a template (not really a directive)](#qweb-engine) |
|
| `t-name` | [Defining a template (not really a directive)](#qweb-engine) |
|
||||||
|
|
||||||
The component system in Owl requires additional directives, to express various
|
The component system in Owl requires additional directives, to express various
|
||||||
@@ -87,11 +89,14 @@ const qweb = new owl.QWeb();
|
|||||||
|
|
||||||
Its API is quite simple:
|
Its API is quite simple:
|
||||||
|
|
||||||
- **`constructor(data)`**: constructor. Takes an optional string to add initial
|
- **`constructor(config)`**: constructor. Takes an optional configuration object
|
||||||
templates (see `addTemplates` for more information on format of the string).
|
with an optional `templates` string to add initial
|
||||||
|
templates (see `addTemplates` for more information on format of the string)
|
||||||
|
and an optional `translateFn` translate function (see the section on
|
||||||
|
[translations](#translations)).
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const qweb = new owl.QWeb(TEMPLATES);
|
const qweb = new owl.QWeb({ templates: TEMPLATES, translateFn: _t });
|
||||||
```
|
```
|
||||||
|
|
||||||
- **`addTemplate(name, xmlStr, allowDuplicate)`**: add a specific template.
|
- **`addTemplate(name, xmlStr, allowDuplicate)`**: add a specific template.
|
||||||
@@ -201,7 +206,7 @@ root nodes.
|
|||||||
### Expression Evaluation
|
### Expression Evaluation
|
||||||
|
|
||||||
QWeb expressions are strings that will be processed at compile time. Each variable in
|
QWeb expressions are strings that will be processed at compile time. Each variable in
|
||||||
the javascript expression will be replaced by a lookup in the context (so, the
|
the javascript expression will be replaced with a lookup in the context (so, the
|
||||||
component). For example, `a + b.c(d)` will be converted into:
|
component). For example, `a + b.c(d)` will be converted into:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
@@ -234,14 +239,14 @@ It is useful to explain the various rules that apply on these expressions:
|
|||||||
3. it can use a few special operators to avoid using symbols such as `<`, `>`,
|
3. it can use a few special operators to avoid using symbols such as `<`, `>`,
|
||||||
`&` or `|`. This is useful to make sure that we still write valid XML.
|
`&` or `|`. This is useful to make sure that we still write valid XML.
|
||||||
|
|
||||||
| Word | will be replaced by |
|
| Word | replaced with |
|
||||||
| ----- | ------------------- |
|
| ----- | ------------- |
|
||||||
| `and` | `&&` |
|
| `and` | `&&` |
|
||||||
| `or` | `\|\|` |
|
| `or` | `\|\|` |
|
||||||
| `gt` | `>` |
|
| `gt` | `>` |
|
||||||
| `gte` | `>=` |
|
| `gte` | `>=` |
|
||||||
| `lt` | `<` |
|
| `lt` | `<` |
|
||||||
| `lte` | `<=` |
|
| `lte` | `<=` |
|
||||||
|
|
||||||
So, one can write this:
|
So, one can write this:
|
||||||
|
|
||||||
@@ -443,7 +448,7 @@ is equivalent to the previous example.
|
|||||||
or an object (the current item will be the current key).
|
or an object (the current item will be the current key).
|
||||||
|
|
||||||
In addition to the name passed via t-as, `t-foreach` provides a few other
|
In addition to the name passed via t-as, `t-foreach` provides a few other
|
||||||
variables for various data points (note: `$as` will be replaced by the name
|
variables for various data points (note: `$as` will be replaced with the name
|
||||||
passed to `t-as`):
|
passed to `t-as`):
|
||||||
|
|
||||||
- `$as_value`: the current iteration value, identical to `$as` for lists and
|
- `$as_value`: the current iteration value, identical to `$as` for lists and
|
||||||
@@ -522,6 +527,53 @@ will result in :
|
|||||||
</div>
|
</div>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Translations
|
||||||
|
|
||||||
|
If properly setup, Owl QWeb engine can translate all rendered templates. To do
|
||||||
|
so, it needs a translate function, which takes a string and returns a string.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const translations = {
|
||||||
|
hello: "bonjour",
|
||||||
|
yes: "oui",
|
||||||
|
no: "non"
|
||||||
|
};
|
||||||
|
const translateFn = str => translations[str] || str;
|
||||||
|
|
||||||
|
const qweb = new QWeb({ translateFn });
|
||||||
|
```
|
||||||
|
|
||||||
|
Once setup, all rendered templates will be translated using `translateFn`:
|
||||||
|
|
||||||
|
- each text node will be replaced with its translation,
|
||||||
|
- each of the following attribute values will be translated as well: `title`,
|
||||||
|
`placeholder`, `label` and `alt`,
|
||||||
|
- translating text nodes can be disabled with the special attribute `t-translation`,
|
||||||
|
if its value is `off`.
|
||||||
|
|
||||||
|
So, with the above `translateFn`, the following templates:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<div>hello</div>
|
||||||
|
<div t-translation="off">hello</div>
|
||||||
|
<div>Are you sure?</div>
|
||||||
|
<input placeholder="hello" other="yes"/>
|
||||||
|
```
|
||||||
|
|
||||||
|
will be rendered as:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<div>bonjour</div>
|
||||||
|
<div>hello</div>
|
||||||
|
<div>Are you sure?</div>
|
||||||
|
<input placeholder="bonjour" other="yes"/>
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that the translation is done during the compilation of the template, not
|
||||||
|
when it is rendered.
|
||||||
|
|
||||||
### Debugging
|
### Debugging
|
||||||
|
|
||||||
The javascript QWeb implementation provides two useful debugging directives:
|
The javascript QWeb implementation provides two useful debugging directives:
|
||||||
|
|||||||
+2
-2
@@ -20,7 +20,7 @@ argument, it executes it as soon as the DOM ready (or directly).
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
Promise.all([loadFile("templates.xml"), owl.utils.whenReady()]).then(function([templates]) {
|
Promise.all([loadFile("templates.xml"), owl.utils.whenReady()]).then(function([templates]) {
|
||||||
const qweb = new owl.QWeb(templates);
|
const qweb = new owl.QWeb({ templates });
|
||||||
const app = new App({ qweb });
|
const app = new App({ qweb });
|
||||||
app.mount(document.body);
|
app.mount(document.body);
|
||||||
});
|
});
|
||||||
@@ -62,7 +62,7 @@ initial usecase for this function is to load a template file. For example:
|
|||||||
```js
|
```js
|
||||||
async function makeEnv() {
|
async function makeEnv() {
|
||||||
const templates = await owl.utils.loadFile("templates.xml");
|
const templates = await owl.utils.loadFile("templates.xml");
|
||||||
const qweb = new owl.QWeb(templates);
|
const qweb = new owl.QWeb({ templates });
|
||||||
return { qweb };
|
return { qweb };
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
+9
-9
@@ -81,15 +81,15 @@ export function useContextWithCB(ctx: Context, component: Component<any, any>, m
|
|||||||
__owl__.observer.notifyCB = component.render.bind(component);
|
__owl__.observer.notifyCB = component.render.bind(component);
|
||||||
}
|
}
|
||||||
const currentCB = __owl__.observer.notifyCB;
|
const currentCB = __owl__.observer.notifyCB;
|
||||||
__owl__.observer.notifyCB = function () {
|
__owl__.observer.notifyCB = function() {
|
||||||
if (ctx.rev > mapping[id]) {
|
if (ctx.rev > mapping[id]) {
|
||||||
// in this case, the context has been updated since we were rendering
|
// in this case, the context has been updated since we were rendering
|
||||||
// last, and we do not need to render here with the observer. A
|
// last, and we do not need to render here with the observer. A
|
||||||
// rendering is coming anyway, with the correct props.
|
// rendering is coming anyway, with the correct props.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
currentCB();
|
currentCB();
|
||||||
}
|
};
|
||||||
|
|
||||||
mapping[id] = 0;
|
mapping[id] = 0;
|
||||||
const renderFn = __owl__.renderFn;
|
const renderFn = __owl__.renderFn;
|
||||||
|
|||||||
+2
-2
@@ -10,7 +10,7 @@ import { QWeb } from "./qweb/index";
|
|||||||
import * as _store from "./store";
|
import * as _store from "./store";
|
||||||
import * as _utils from "./utils";
|
import * as _utils from "./utils";
|
||||||
import * as _tags from "./tags";
|
import * as _tags from "./tags";
|
||||||
import {AsyncRoot} from "./misc/async_root";
|
import { AsyncRoot } from "./misc/async_root";
|
||||||
import * as _hooks from "./hooks";
|
import * as _hooks from "./hooks";
|
||||||
import * as _context from "./context";
|
import * as _context from "./context";
|
||||||
import { Link } from "./router/link";
|
import { Link } from "./router/link";
|
||||||
@@ -27,7 +27,7 @@ export const router = { Router, RouteComponent, Link };
|
|||||||
export const Store = _store.Store;
|
export const Store = _store.Store;
|
||||||
export const utils = _utils;
|
export const utils = _utils;
|
||||||
export const tags = _tags;
|
export const tags = _tags;
|
||||||
export const misc = { AsyncRoot};
|
export const misc = { AsyncRoot };
|
||||||
export const hooks = Object.assign({}, _hooks, {
|
export const hooks = Object.assign({}, _hooks, {
|
||||||
useContext: _context.useContext,
|
useContext: _context.useContext,
|
||||||
useDispatch: _store.useDispatch,
|
useDispatch: _store.useDispatch,
|
||||||
|
|||||||
+27
-5
@@ -57,12 +57,19 @@ export interface Directive {
|
|||||||
finalize?(info: CompilationInfo): void;
|
finalize?(info: CompilationInfo): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface QWebConfig {
|
||||||
|
templates?: string;
|
||||||
|
translateFn?(text: string): string;
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Const/global stuff/helpers
|
// Const/global stuff/helpers
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
const DISABLED_TAGS = ["input", "textarea", "button", "select", "option", "optgroup"];
|
const DISABLED_TAGS = ["input", "textarea", "button", "select", "option", "optgroup"];
|
||||||
|
|
||||||
|
const TRANSLATABLE_ATTRS = ["label", "title", "placeholder", "alt"];
|
||||||
|
|
||||||
const lineBreakRE = /[\r\n]/;
|
const lineBreakRE = /[\r\n]/;
|
||||||
const whitespaceRE = /\s+/g;
|
const whitespaceRE = /\s+/g;
|
||||||
|
|
||||||
@@ -134,6 +141,7 @@ function parseXML(xml: string): Document {
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// QWeb rendering engine
|
// QWeb rendering engine
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
export class QWeb extends EventBus {
|
export class QWeb extends EventBus {
|
||||||
templates: { [name: string]: Template };
|
templates: { [name: string]: Template };
|
||||||
static utils = UTILS;
|
static utils = UTILS;
|
||||||
@@ -143,7 +151,8 @@ export class QWeb extends EventBus {
|
|||||||
name: 1,
|
name: 1,
|
||||||
att: 1,
|
att: 1,
|
||||||
attf: 1,
|
attf: 1,
|
||||||
key: 1
|
key: 1,
|
||||||
|
translation: 1
|
||||||
};
|
};
|
||||||
static DIRECTIVES: Directive[] = [];
|
static DIRECTIVES: Directive[] = [];
|
||||||
|
|
||||||
@@ -166,12 +175,16 @@ export class QWeb extends EventBus {
|
|||||||
recursiveFns = {};
|
recursiveFns = {};
|
||||||
|
|
||||||
isUpdating: boolean = false;
|
isUpdating: boolean = false;
|
||||||
|
translateFn?: QWebConfig["translateFn"];
|
||||||
|
|
||||||
constructor(data?: string) {
|
constructor(config: QWebConfig = {}) {
|
||||||
super();
|
super();
|
||||||
this.templates = Object.create(QWeb.TEMPLATES);
|
this.templates = Object.create(QWeb.TEMPLATES);
|
||||||
if (data) {
|
if (config.templates) {
|
||||||
this.addTemplates(data);
|
this.addTemplates(config.templates);
|
||||||
|
}
|
||||||
|
if (config.translateFn) {
|
||||||
|
this.translateFn = config.translateFn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,6 +431,11 @@ export class QWeb extends EventBus {
|
|||||||
}
|
}
|
||||||
text = text.replace(whitespaceRE, " ");
|
text = text.replace(whitespaceRE, " ");
|
||||||
}
|
}
|
||||||
|
if (this.translateFn) {
|
||||||
|
if ((node.parentNode as any).getAttribute("t-translation") !== "off") {
|
||||||
|
text = this.translateFn(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (ctx.parentNode) {
|
if (ctx.parentNode) {
|
||||||
if (node.nodeType === 3) {
|
if (node.nodeType === 3) {
|
||||||
ctx.addLine(`c${ctx.parentNode}.push({text: \`${text}\`});`);
|
ctx.addLine(`c${ctx.parentNode}.push({text: \`${text}\`});`);
|
||||||
@@ -617,7 +635,11 @@ export class QWeb extends EventBus {
|
|||||||
|
|
||||||
for (let i = 0; i < attributes.length; i++) {
|
for (let i = 0; i < attributes.length; i++) {
|
||||||
let name = attributes[i].name;
|
let name = attributes[i].name;
|
||||||
const value = attributes[i].textContent!;
|
let value = attributes[i].textContent!;
|
||||||
|
|
||||||
|
if (this.translateFn && TRANSLATABLE_ATTRS.includes(name)) {
|
||||||
|
value = this.translateFn(value);
|
||||||
|
}
|
||||||
|
|
||||||
// regular attributes
|
// regular attributes
|
||||||
if (!name.startsWith("t-") && !(<Element>node).getAttribute("t-attf-" + name)) {
|
if (!name.startsWith("t-") && !(<Element>node).getAttribute("t-attf-" + name)) {
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ describe("Context", () => {
|
|||||||
|
|
||||||
expect(fixture.innerHTML).toBe("<div><p><span>1a</span></p></div>");
|
expect(fixture.innerHTML).toBe("<div><p><span>1a</span></p></div>");
|
||||||
testContext.state.key = "y";
|
testContext.state.key = "y";
|
||||||
testContext.state.y = {n: 2};
|
testContext.state.y = { n: 2 };
|
||||||
delete testContext.state.x;
|
delete testContext.state.x;
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
|
||||||
|
|||||||
@@ -2415,6 +2415,73 @@ exports[`t-set value priority 1`] = `
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`translation support can translate node content 1`] = `
|
||||||
|
"function anonymous(context,extra
|
||||||
|
) {
|
||||||
|
let sibling = null;
|
||||||
|
var h = this.h;
|
||||||
|
let c1 = [], p1 = {key:1};
|
||||||
|
var vn1 = h('div', p1, c1);
|
||||||
|
c1.push({text: \`mot\`});
|
||||||
|
return vn1;
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`translation support does not translate node content if disabled 1`] = `
|
||||||
|
"function anonymous(context,extra
|
||||||
|
) {
|
||||||
|
let sibling = null;
|
||||||
|
var h = this.h;
|
||||||
|
let c1 = [], p1 = {key:1};
|
||||||
|
var vn1 = h('div', p1, c1);
|
||||||
|
let c2 = [], p2 = {key:2};
|
||||||
|
var vn2 = h('span', p2, c2);
|
||||||
|
c1.push(vn2);
|
||||||
|
c2.push({text: \`mot\`});
|
||||||
|
let c3 = [], p3 = {key:3};
|
||||||
|
var vn3 = h('span', p3, c3);
|
||||||
|
c1.push(vn3);
|
||||||
|
c3.push({text: \`word\`});
|
||||||
|
return vn1;
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`translation support some attributes are translated 1`] = `
|
||||||
|
"function anonymous(context,extra
|
||||||
|
) {
|
||||||
|
let sibling = null;
|
||||||
|
var h = this.h;
|
||||||
|
let c1 = [], p1 = {key:1};
|
||||||
|
var vn1 = h('div', p1, c1);
|
||||||
|
var _2 = 'mot';
|
||||||
|
let c3 = [], p3 = {key:3,attrs:{label: _2}};
|
||||||
|
var vn3 = h('p', p3, c3);
|
||||||
|
c1.push(vn3);
|
||||||
|
c3.push({text: \`mot\`});
|
||||||
|
var _4 = 'mot';
|
||||||
|
let c5 = [], p5 = {key:5,attrs:{title: _4}};
|
||||||
|
var vn5 = h('p', p5, c5);
|
||||||
|
c1.push(vn5);
|
||||||
|
c5.push({text: \`mot\`});
|
||||||
|
var _6 = 'mot';
|
||||||
|
let c7 = [], p7 = {key:7,attrs:{placeholder: _6}};
|
||||||
|
var vn7 = h('p', p7, c7);
|
||||||
|
c1.push(vn7);
|
||||||
|
c7.push({text: \`mot\`});
|
||||||
|
var _8 = 'mot';
|
||||||
|
let c9 = [], p9 = {key:9,attrs:{alt: _8}};
|
||||||
|
var vn9 = h('p', p9, c9);
|
||||||
|
c1.push(vn9);
|
||||||
|
c9.push({text: \`mot\`});
|
||||||
|
var _10 = 'word';
|
||||||
|
let c11 = [], p11 = {key:11,attrs:{something: _10}};
|
||||||
|
var vn11 = h('p', p11, c11);
|
||||||
|
c1.push(vn11);
|
||||||
|
c11.push({text: \`mot\`});
|
||||||
|
return vn1;
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`whitespace handling consecutives whitespaces are condensed into a single space 1`] = `
|
exports[`whitespace handling consecutives whitespaces are condensed into a single space 1`] = `
|
||||||
"function anonymous(context,extra
|
"function anonymous(context,extra
|
||||||
) {
|
) {
|
||||||
|
|||||||
+53
-2
@@ -1305,12 +1305,12 @@ describe("t-ref", () => {
|
|||||||
|
|
||||||
describe("loading templates", () => {
|
describe("loading templates", () => {
|
||||||
test("can initialize qweb with a string", () => {
|
test("can initialize qweb with a string", () => {
|
||||||
const data = `
|
const templates = `
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<templates id="template" xml:space="preserve">
|
<templates id="template" xml:space="preserve">
|
||||||
<div t-name="hey">jupiler</div>
|
<div t-name="hey">jupiler</div>
|
||||||
</templates>`;
|
</templates>`;
|
||||||
const qweb = new QWeb(data);
|
const qweb = new QWeb({ templates });
|
||||||
expect(renderToString(qweb, "hey")).toBe("<div>jupiler</div>");
|
expect(renderToString(qweb, "hey")).toBe("<div>jupiler</div>");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1519,3 +1519,54 @@ describe("properly support svg", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("translation support", () => {
|
||||||
|
test("can translate node content", () => {
|
||||||
|
const translations = {
|
||||||
|
word: "mot"
|
||||||
|
};
|
||||||
|
const translateFn = expr => translations[expr] || expr;
|
||||||
|
const qweb = new QWeb({ translateFn });
|
||||||
|
qweb.addTemplate("test", "<div>word</div>");
|
||||||
|
expect(renderToString(qweb, "test")).toBe("<div>mot</div>");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("does not translate node content if disabled", () => {
|
||||||
|
const translations = {
|
||||||
|
word: "mot"
|
||||||
|
};
|
||||||
|
const translateFn = expr => translations[expr] || expr;
|
||||||
|
const qweb = new QWeb({ translateFn });
|
||||||
|
qweb.addTemplate(
|
||||||
|
"test",
|
||||||
|
`
|
||||||
|
<div>
|
||||||
|
<span>word</span>
|
||||||
|
<span t-translation="off">word</span>
|
||||||
|
</div>`
|
||||||
|
);
|
||||||
|
expect(renderToString(qweb, "test")).toBe("<div><span>mot</span><span>word</span></div>");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("some attributes are translated", () => {
|
||||||
|
const translations = {
|
||||||
|
word: "mot"
|
||||||
|
};
|
||||||
|
const translateFn = expr => translations[expr] || expr;
|
||||||
|
const qweb = new QWeb({ translateFn });
|
||||||
|
qweb.addTemplate(
|
||||||
|
"test",
|
||||||
|
`
|
||||||
|
<div>
|
||||||
|
<p label="word">word</p>
|
||||||
|
<p title="word">word</p>
|
||||||
|
<p placeholder="word">word</p>
|
||||||
|
<p alt="word">word</p>
|
||||||
|
<p something="word">word</p>
|
||||||
|
</div>`
|
||||||
|
);
|
||||||
|
expect(renderToString(qweb, "test")).toBe(
|
||||||
|
'<div><p label="mot">mot</p><p title="mot">mot</p><p placeholder="mot">mot</p><p alt="mot">mot</p><p something="word">mot</p></div>'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ class App extends owl.Component {
|
|||||||
async function start() {
|
async function start() {
|
||||||
const templates = await owl.utils.loadFile("templates.xml");
|
const templates = await owl.utils.loadFile("templates.xml");
|
||||||
const env = {
|
const env = {
|
||||||
qweb: new owl.QWeb(templates)
|
qweb: new owl.QWeb({ templates })
|
||||||
};
|
};
|
||||||
const app = new App(env);
|
const app = new App(env);
|
||||||
app.mount(document.body);
|
app.mount(document.body);
|
||||||
|
|||||||
@@ -435,7 +435,7 @@ async function start() {
|
|||||||
owl.utils.loadFile("templates.xml"),
|
owl.utils.loadFile("templates.xml"),
|
||||||
owl.utils.whenReady()
|
owl.utils.whenReady()
|
||||||
]);
|
]);
|
||||||
const qweb = new owl.QWeb(templates);
|
const qweb = new owl.QWeb({ templates });
|
||||||
const app = new App({ qweb });
|
const app = new App({ qweb });
|
||||||
app.mount(document.body);
|
app.mount(document.body);
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-11
@@ -17,7 +17,7 @@ App.components = { Greeter };
|
|||||||
|
|
||||||
// Application setup
|
// Application setup
|
||||||
// Note that the xml templates are injected into the global TEMPLATES variable.
|
// Note that the xml templates are injected into the global TEMPLATES variable.
|
||||||
const qweb = new owl.QWeb(TEMPLATES);
|
const qweb = new owl.QWeb({ templates: TEMPLATES});
|
||||||
const app = new App({ qweb });
|
const app = new App({ qweb });
|
||||||
app.mount(document.body);
|
app.mount(document.body);
|
||||||
`;
|
`;
|
||||||
@@ -70,7 +70,7 @@ class App extends Component {
|
|||||||
}
|
}
|
||||||
App.components = { Counter };
|
App.components = { Counter };
|
||||||
|
|
||||||
const qweb = new owl.QWeb(TEMPLATES);
|
const qweb = new owl.QWeb({ templates: TEMPLATES});
|
||||||
const app = new App({qweb});
|
const app = new App({qweb});
|
||||||
app.mount(document.body);
|
app.mount(document.body);
|
||||||
`;
|
`;
|
||||||
@@ -228,7 +228,7 @@ class App extends Component {
|
|||||||
}
|
}
|
||||||
App.components = { DemoComponent };
|
App.components = { DemoComponent };
|
||||||
|
|
||||||
const qweb = new owl.QWeb(TEMPLATES);
|
const qweb = new owl.QWeb({ templates: TEMPLATES});
|
||||||
const app = new App({ qweb });
|
const app = new App({ qweb });
|
||||||
app.mount(document.body);
|
app.mount(document.body);
|
||||||
`;
|
`;
|
||||||
@@ -298,7 +298,7 @@ class App extends owl.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Application setup
|
// Application setup
|
||||||
const qweb = new owl.QWeb(TEMPLATES);
|
const qweb = new owl.QWeb({ templates: TEMPLATES});
|
||||||
const app = new App({ qweb });
|
const app = new App({ qweb });
|
||||||
app.mount(document.body);
|
app.mount(document.body);
|
||||||
`;
|
`;
|
||||||
@@ -350,7 +350,7 @@ const themeContext = new Context({
|
|||||||
foreground: '#fff',
|
foreground: '#fff',
|
||||||
});
|
});
|
||||||
const env = {
|
const env = {
|
||||||
qweb: new owl.QWeb(TEMPLATES),
|
qweb: new owl.QWeb({ templates: TEMPLATES}),
|
||||||
themeContext: themeContext,
|
themeContext: themeContext,
|
||||||
};
|
};
|
||||||
const app = new App(env);
|
const app = new App(env);
|
||||||
@@ -548,7 +548,7 @@ function makeEnv() {
|
|||||||
const state = loadState();
|
const state = loadState();
|
||||||
const store = new owl.Store({ state, actions });
|
const store = new owl.Store({ state, actions });
|
||||||
store.on("update", null, () => saveState(store.state));
|
store.on("update", null, () => saveState(store.state));
|
||||||
const qweb = new owl.QWeb(TEMPLATES);
|
const qweb = new owl.QWeb({ templates: TEMPLATES});
|
||||||
return { qweb, store };
|
return { qweb, store };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1041,7 +1041,7 @@ function setupResponsivePlugin(env) {
|
|||||||
// Application Startup
|
// Application Startup
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
const env = {
|
const env = {
|
||||||
qweb: new owl.QWeb(TEMPLATES),
|
qweb: new owl.QWeb({ templates: TEMPLATES}),
|
||||||
};
|
};
|
||||||
setupResponsivePlugin(env);
|
setupResponsivePlugin(env);
|
||||||
|
|
||||||
@@ -1187,7 +1187,7 @@ class App extends Component {
|
|||||||
App.components = {Card, Counter};
|
App.components = {Card, Counter};
|
||||||
|
|
||||||
// Application setup
|
// Application setup
|
||||||
const qweb = new owl.QWeb(TEMPLATES);
|
const qweb = new owl.QWeb({ templates: TEMPLATES});
|
||||||
const app = new App({ qweb });
|
const app = new App({ qweb });
|
||||||
app.mount(document.body);`;
|
app.mount(document.body);`;
|
||||||
|
|
||||||
@@ -1303,7 +1303,7 @@ class App extends Component {
|
|||||||
}
|
}
|
||||||
App.components = {SlowComponent, NotificationList};
|
App.components = {SlowComponent, NotificationList};
|
||||||
|
|
||||||
const qweb = new owl.QWeb(TEMPLATES);
|
const qweb = new owl.QWeb({ templates: TEMPLATES});
|
||||||
const app = new App({ qweb });
|
const app = new App({ qweb });
|
||||||
app.mount(document.body);
|
app.mount(document.body);
|
||||||
`;
|
`;
|
||||||
@@ -1373,7 +1373,7 @@ class Form extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Application setup
|
// Application setup
|
||||||
const qweb = new owl.QWeb(TEMPLATES);
|
const qweb = new owl.QWeb({ templates: TEMPLATES});
|
||||||
const form = new Form({ qweb });
|
const form = new Form({ qweb });
|
||||||
form.mount(document.body);
|
form.mount(document.body);
|
||||||
`;
|
`;
|
||||||
@@ -1540,7 +1540,7 @@ class App extends Component {
|
|||||||
}
|
}
|
||||||
App.components = { WindowManager };
|
App.components = { WindowManager };
|
||||||
|
|
||||||
const qweb = new owl.QWeb(TEMPLATES);
|
const qweb = new owl.QWeb({ templates: TEMPLATES});
|
||||||
const windows = [
|
const windows = [
|
||||||
{
|
{
|
||||||
name: "Hello",
|
name: "Hello",
|
||||||
|
|||||||
Reference in New Issue
Block a user