QWeb is the primary templating engine used by Odoo. The QWeb class in the OWL project is an implementation of that specification with a few interesting points:
- it compiles templates into functions that output a virtual DOM instead of a string. This is necessary for the component system.
- it has a few extra directives:
t-component
,t-on
, ...
We present in this section the engine, not the templating language.
This section is about the javascript code that implements the QWeb
specification.
Owl exports a QWeb
class in owl.QWeb
. To use it, it just needs to be
instantiated:
const qweb = new owl.QWeb();
Its API is quite simple:
-
constructor(config)
: constructor. Takes an optional configuration object with an optionaltemplates
string to add initial templates (seeaddTemplates
for more information on format of the string) and an optionaltranslateFn
translate function (see the section on translations).const qweb = new owl.QWeb({ templates: TEMPLATES, translateFn: _t });
-
addTemplate(name, xmlStr, allowDuplicate)
: add a specific template.qweb.addTemplate("mytemplate", "<div>hello</div>");
If the optional
allowDuplicate
is set totrue
, thenQWeb
will simply ignore templates added for a second time. Otherwise,QWeb
will crash. -
addTemplates(xmlStr)
: add a list of templates (identified byt-name
attribute).const TEMPLATES = ` <templates> <div t-name="App" class="main">main</div> <div t-name="OtherComponent">other component</div> </templates>`; qweb.addTemplates(TEMPLATES);
-
render(name, context, extra)
: renders a template. This returns avnode
, which is a virtual representation of the DOM (see vdom doc).const vnode = qweb.render("App", component);
-
renderToString(name, context)
: renders a template, but returns an html string.const str = qweb.renderToString("someTemplate", somecontext);
-
registerTemplate(name, template)
: static function to register a global QWeb template. This is useful for commonly used components accross the application, and for making a template available to an application without having a reference to the actual QWeb instance.QWeb.registerTemplate("mytemplate", `<div>some template</div>`);
-
registerComponent(name, Component)
: static function to register an OWL Component to QWeb's global registry. Globally registered Components can be used in templates (see thet-component
directive). This is useful for commonly used components accross the application.class Dialog extends owl.Component { ... } QWeb.registerComponent("Dialog", Dialog); ... class ParentComponent extends owl.Component { ... } qweb.addTemplate("ParentComponent", "<div><Dialog/></div>");
In some way, a QWeb
instance is the core of an Owl application. It is the only
mandatory element of an environment. As such, it
has an extra responsibility: it can act as an event bus for internal communication
between Owl classes. This is the reason why QWeb
actually extends EventBus.
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:
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
andalt
, - translating text nodes can be disabled with the special attribute
t-translation
, if its value isoff
.
So, with the above translateFn
, the following templates:
<div>hello</div>
<div t-translation="off">hello</div>
<div>Are you sure?</div>
<input placeholder="hello" other="yes"/>
will be rendered as:
<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.