{{{#!div class="important" style="text-align: center; padding: 0em 2em; margin: 2em 0" ** Warning ** The following documentation corresponds to the [Proposals/Jinja Jinja] development proposal; it will be in Trac 1.3.x if all goes well \\ (Git branch: [log:cboos.git@jinja2] - [https://github.com/cboos/trac.git github mirror]). Track the integration progress in #12639. }}} [[PageOutline(2-4)]] = Porting Templates from Genshi to Jinja2 The following documentation is primarily targeted at plugin developers who wish to adapt their Genshi templates to the Jinja2 template engine that will be used in Trac 1.4. For migrating your own templates, a good way to start is to learn from examples. Compare the 'j...' Jinja templates found in source:cboos.git/trac/templates@jinja2 with their corresponding Genshi ones. In the first part of this document, we try to cover all the Genshi features used by Trac and present their Jinja2 equivalent. Whenever possible, we tried to minimize these differences by customizing the Jinja2 syntax. For example, we use `${...}` for variable expansion, like Genshi does, instead of `{{...}}`. Another aspect of our usage convention is that we favor [#ifthenelse line statements] over `{% ... %}`. So even someone familiar with the "default" Jinja2 syntax should glance through this document to see how "we" use Jinja2, as summarized in the table below. The last part of the document describes the Python code changes, focusing notably on how to replace the deprecated `ITemplateStreamFilter` interface. Note that Genshi will be supported concurrently with Jinja2 only for a short while, including the deprecated `ITemplateStreamFilter` interface, but probably only during the 1.3.x development period, and at most for the 1.4-stable period. If for some reason you're stuck to having to support Genshi templates, you'll have to stick to Trac 1.2.x or 1.3.x. But you really should make the transition effort as Jinja2 templates are 5-10x faster than their Genshi equivalent, for only a 1/5th of the cost in memory usage. == The Jinja2 syntax The Jinja2 template engine is quite flexible and its syntax can be customized to some extent. We took this opportunity to make it as close as possible to the Genshi template syntax, in particular for the variable expansion. We use the following configuration: || key || value || example / explanation || extensions || jinja2.ext.with_ jinja2.ext.i18n || `with` directive can be used ([#with more]) || block_start_string || {% || \ {{{#!td rowspan=2 `{% if cond %} value {% endif %}` possible (but discouraged) }}} |-- || block_end_string || %} || || variable_start_string || ${ || \ {{{#!td rowspan=2 `${the_variable}` (but not `$the_variable`) ([#expandavariable more]) }}} |-- || variable_end_string || } || || line_statement_prefix || # || \ {{{#!td {{{ # if cond: value # endif }}} (preferred form) ([#if more]) }}} |-- || line_comment_prefix || ## || `## comments are good` || trim_blocks || yes || whitespace removal after a block || lstrip_blocks || yes || whitespace removal before a block || newstyle_gettext || yes || i.e. like the Trac `gettext` == Changes in the HTML We took the opportunity to switch to HTML5 while performing this template overhaul. You should probably do the same. This usually won't change anything for your templates, except for a few details. The doctype and the element should be changed from Genshi's: {{{#!html+genshi }}} to the somewhat simpler: {{{#!xml }}} Special care should be taken when dealing with //void elements//. In XHTML, it's fine to write: {{{#!xml
}}} However, when going to HTML5, you should use instead: {{{#!xml }}} The valid [https://www.w3.org/TR/html-markup/syntax.html#void-elements void elements] in HTML5 are limited to the following list: - area, base, br, col, command, embed, hr, img, input, keygen, link, meta, param, source, track, wbr == Changes in the template syntax Most of the time, the porting is a straightforward operation. === expand a variable - Genshi [[html+genshi($the_variable)]] - Jinja2 [[html+jinja(${the_variable})]] Note that Jinja2 doesn't support the `$the_variable` style, the curly braces are mandatory. Tip: {{{#!shell sed -i -e 's,\$\([a-z_][a-z._]*\),${\1},g' template.html }}} === expand a simple computation - Genshi [[html+genshi(${the_variable + 1})]] - Jinja2 [[html+jinja(${the_variable + 1})]] However, Jinja2 expressions are only //similar// to Python expressions, there are a few differences and limitations, see [http://jinja.pocoo.org/docs/dev/templates/#expressions expressions] doc. See also [#set set complex variables] below for more involved examples. === include another template #include - Genshi [[xml(Otherwise, please ${create_ticket(tracker)} a new bug report describing the problem and explain how to reproduce it.
}}} - Jinja2: {{{#!html+jinja# trans create = create_ticket(tracker) Otherwise, please ${create} a new bug report describing the problem and explain how to reproduce it. # endtrans
}}} another example, without assignment: {{{#!html+jinja # trans formatted In the default time zone, this would be displayed as ${formatted}. # endtrans }}} last example, two expanded variables, with and without assignment: {{{#!html+jinja # trans tz = nowtz.tzname(), formatted In your time zone ${tz}, this would be displayed as ${formatted}. # endtrans }}} See [http://jinja.pocoo.org/docs/dev/templates/#i18n i18n] doc. Note that only direct variable expansions are supported in `trans` blocks, nothing more complex. So one way to deal with complex translatable content is to factor out the complex parts in variable blocks. See [http://jinja.pocoo.org/docs/dev/templates/#block-assignments block assignments] doc. - Genshi: {{{#!html+genshiThere was an internal error in Trac. It is recommended that you notify your local Trac administrator with the information needed to reproduce the issue.
}}} - Jinja2: {{{#!html+jinja# set trac_admin = _("Trac administrator") # set project_admin # if project.admin: ${trac_admin} # else: ${trac_admin} # endif # endset # trans project_admin = project_admin|safe There was an internal error in Trac. It is recommended that you notify your local ${project_admin} with the information needed to reproduce the issue. # endtrans
}}} (the need for the `|safe` filter in the above might go away once the following issue //[https://github.com/mitsuhiko/jinja2/issues/490 Should set blocks be safe by default]// gets fixed) Note that another tricky case is when you want to use `gettext` and one of the variables is Markup. Using `|safe` is also needed, but that's not enough, as currently `gettext()` doesn't support Markup, you need to use `tgettext()` which is available with the `tag_` shortcut: {{{#!html+jinja # set preferences_link ${ _("Preferences")} # endset ${tag_("Set your email in %(preferences_link)s", preferences_link=preferences_link|safe)} }}} == Examples === Standalone template Let's first take a simple full-contained example from the Trac source, the simple index.html / jindex.html templates. - Genshi [source:sandbox/genshi/templates/index.html@3728 index.html]: {{{#!html+genshi