Version 1 (modified by 8 years ago) ( diff ) | ,
---|
Conversion example
Here we detail the conversion process of a sample Genshi template (wiki_view.html) into the corresponding Jinja2 template (jwiki_view.html).
As will become apparent, we mainly use line statements for the Jinja2 control structures. Note that we have reformatted the Genshi template to use shorter line widths, so that both columns of the table below stay visible (a wide screen also helps).
wiki_view.html (Genshi template) | jwiki_view.html (Jinja2 template) |
---|---|
<!--! Copyright (C) 2006-2014 Edgewall Software This software is licensed as described in the file COPYING, which you should have received as part of this distribution. The terms are also available at http://trac.edgewall.com/license.html. This software consists of voluntary contributions made by many individuals. For the exact contribution history, see the revision history and logs, available at http://trac.edgewall.org/. --> | {# Copyright (C) 2006-2014 Edgewall Software This software is licensed as described in the file COPYING, which you should have received as part of this distribution. The terms are also available at http://trac.edgewall.com/license.html. This software consists of voluntary contributions made by many individuals. For the exact contribution history, see the revision history and logs, available at http://trac.edgewall.org/. #} |
Block comments | |
# extends "jlayout.html" | |
This is the equivalent of Genshi's <py:include href="layout.html" /> . We have to do the extends before outputing any content on our own, otherwise it would show up in the final result. Once we made the extends , only the content written within blocks will matter.
| |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | <!DOCTYPE html>
|
Let's directly make the jump to HTML5, while we're at it (I'm not sure what is the current state of the HTML5 support in Genshi, but it no longer matters) | |
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://genshi.edgewall.org/" xmlns:i18n="http://genshi.edgewall.org/i18n" xmlns:xi="http://www.w3.org/2001/XInclude" py:with="modify_perm = 'WIKI_MODIFY' in perm(page.resource); create_perm = 'WIKI_CREATE' in perm(page.resource); admin_perm = 'WIKI_ADMIN' in perm(page.resource); is_not_latest = page.exists and page.version != latest_version"> | <html> |
No need for exotic namespace declarations.
Note that we can't use a | |
<xi:include href="layout.html" /> | |
See above, this will be converted to an initial extends statement.
| |
<head> <title py:if="title">$title</title> | <head> <title> # block title # if title: ${title} ${ super() } # endif # endblock title </title> # block head # set modify_perm = 'WIKI_MODIFY' in perm(page.resource) # set is_not_latest = page.exists and page.version != latest_version ${ super() } |
The content of the <title> element is placed in the title block,
followed by the content of the parent title block ( Note that while the only thing that really matters in an extending template is the content of the blocks, we try hard to keep a correct HTML structure for the whole template page, so that its HTML content can be validated in a standalone way (cf. #jinjachecker). This is why we add the <html>, <head> and <title> tags.
We explained earlier why the title block has to be outside of the head block:
to avoid appearing twice, once as part of the head block, and the second time
when we call
Finally, we define some variables at the beginning of the block (corresponding to
some which were part of the | |
<meta py:if="version or page.author == 'trac'" name="ROBOTS" content="NOINDEX, NOFOLLOW" /> <link py:if="modify_perm" rel="alternate" type="application/x-wiki" href="${href.wiki(page.name, action='edit', version=page.version if is_not_latest else None)}" title="${_('Revert page to this version') if is_not_latest else _('Edit this page')}"/> | # if version or page.author == 'trac': <meta name="ROBOTS" content="NOINDEX, NOFOLLOW" /> # endif # if modify_perm: <link rel="alternate" type="application/x-wiki" href="${href.wiki(page.name, action='edit', version=page.version if is_not_latest)}" title="${_("Revert page to this version") if is_not_latest else _("Edit this page")}"/> # endif |
With Jinja2, the logic is now clearly distinct from the content. | |
<script type="text/javascript"> jQuery(document).ready(function($) { $("#content").find("h1,h2,h3,h4,h5,h6") .addAnchor(_("Link to this section")); $("#content").find(".wikianchor").each(function() { $(this).addAnchor(babel.format(_("Link to #%(id)s"), {id: $(this).attr('id')})); }); $(".foldable").enableFolding(true, true); }); </script> | <script type="text/javascript"> jQuery(document).ready(function($) { $("#content").find("h1,h2,h3,h4,h5,h6") .addAnchor(_("Link to this section")); $("#content").find(".wikianchor").each(function() { $(this).addAnchor(babel.format(_("Link to #%(id)s"), { id: $(this).attr('id')})); }); $(".foldable").enableFolding(true, true); }); </script> |
No changes here, except for some reformatting (we try to stay below 80 chars for nicer future side-by-side diffs). | |
</head> | # endblock head </head> |
We close the head block. | |
<body> <div id="content" class="${classes('wiki', create=not page.exists)}"> | <body> # block content # set modify_perm = 'WIKI_MODIFY' in perm(page.resource) # set create_perm = 'WIKI_CREATE' in perm(page.resource) # set admin_perm = 'WIKI_ADMIN' in perm(page.resource) # set is_not_latest = page.exists and page.version != latest_version <div id="content" class="${classes('wiki', create=not page.exists)}"> |
We start the content block. As before with the header block, we define some variables at the beginning of the block. | |
<py:if test="version"> <br /> <table id="info" summary="Revision info"> <tr><th scope="row" i18n:msg="version, author, date"> Version $page.version (modified by ${authorinfo(page.author)}, ${pretty_dateinfo(page.time)}) (<a href="${href.wiki(page.name, action='diff', version=page.version)}">diff</a>) </th></tr> <tr><td class="message" xml:space="preserve"> ${wiki_to_html(context, page.comment or '--')} </td></tr> </table> </py:if> | # if version: <br /> <table id="info" summary="${_("Revision info")}"> <tr><th scope="row"> # with # set version = page.version # set author = authorinfo(page.author) # set date = pretty_dateinfo(page.time) # set hef = href.wiki(page.name, action='diff', version=page.version) # trans version, author, date, href Version ${version} (modified by ${author}, ${date}) (<a href="${href}">diff</a>) # endtrans # endwith </th></tr> <tr><td class="message"> ${wiki_to_html(context, page.comment or '--')} </td></tr> </table> # endif |
Here we illustrate the i18n changes. First, any sentence that corresponds to visible end-user text that should be translated has to be marked somehow.
One way is to use the standard i18n calls,
The other way is to use
Note that one can use a | |
<div class="wikipage searchable" py:choose="" xml:space="preserve"> <py:when test="page.exists"> <div id="wikipage" class="trac-content" py:content="wiki_to_html(context, text)" /> <?python last_modification = (page.comment and _('Version %(version)s by %(author)s: %(comment)s', version=page.version, author=format_author(page.author), comment=page.comment) or _('Version %(version)s by %(author)s', version=page.version, author=format_author(page.author))) ?> <div py:if="not version" class="trac-modifiedby"> <span i18n:msg="reldate"> <a href="${href.wiki(page.name, action='diff', version=page.version)}" title="$last_modification">Last modified</a> ${pretty_dateinfo(page.time)} </span> <span class="trac-print" i18n:msg="date">Last modified on ${format_datetime(page.time)}</span> </div> </py:when> <py:otherwise> <p i18n:msg="name">The page <strong>${name_of(page.resource)}</strong> does not exist. You can create it here.</p> </py:otherwise> </div> | <div class="wikipage searchable"> # if page.exists: <div id="wikipage" class="trac-content">${ wiki_to_html(context, text) }</div> # set last_modification = (page.comment and _('Version %(version)s by %(author)s: %(comment)s', version=page.version, author=format_author(page.author), comment=page.comment) or _('Version %(version)s by %(author)s', version=page.version, author=format_author(page.author))) # if not version: <div class="trac-modifiedby"> <span> # with # set href = href.wiki(page.name, action='diff', version=page.version), # set date = pretty_dateinfo(page.time) # trans href, last_modification, date <a href="${href}" title="${last_modification}">Last modified</a> ${date} # endtrans # endwith </span> <span class="trac-print"> ${_("Last modified on %(date)s", date=format_datetime(page.time))} </span> </div> # endif # else: <p> # trans name = name_of(page.resource) The page <strong>${name}</strong> does not exist. You can create it here. # endtrans </p> # endif </div> |
<xi:include href="list_of_attachments.html" py:with="alist = attachments; compact = True; foldable = True"/> | # with # set alist = attachments # set compact = True # set foldable = True # include "jlist_of_attachments.html" # endwith |
Jinja2 includes also know about their context, so that make them kind of parametric. | |
<py:with vars="delete_perm = 'WIKI_DELETE' in perm(page.resource); rename_perm = 'WIKI_RENAME' in perm(page.resource)"> <py:if test="modify_perm or create_perm or delete_perm"> <div class="buttons"> <py:if test="modify_perm or create_perm"> | # with # set delete_perm = 'WIKI_DELETE' in perm(page.resource) # set rename_perm = 'WIKI_RENAME' in perm(page.resource) # if modify_perm or create_perm or delete_perm: <div class="buttons"> # if modify_perm or create_perm: |
Again, even when there's a lot of control lines, it's a bit easier to immediately spot the actual content in Jinja2 templates, due to the clearer syntactic difference. | |
<form method="get" action="${href.wiki(page.name)}" id="modifypage"> <div> <input type="hidden" name="action" value="edit" /> <py:choose> <py:when test="is_not_latest and modify_perm"> <input type="hidden" name="version" value="${page.version}"/> <input type="submit" value="${_('Revert to this version')}"/> </py:when> <py:when test="page.exists and modify_perm"> <input type="submit" value="${_('Edit this page')}" accesskey="e" /> </py:when> <py:when test="not page.exists and create_perm"> <input type="submit" value="${_('Create this page')}" accesskey="e" /> <div py:if="templates" id="template"> <label for="template">using the template:</label> <select name="template"> <option selected="${not default_template in templates or None}" value="">(blank page)</option> <option py:for="t in sorted(templates)" value="$t" selected="${t == default_template or None}" >$t</option> </select> </div> </py:when> </py:choose> </div> </form> | <form method="get" action="${href.wiki(page.name)}" id="modifypage"> <div> <input type="hidden" name="action" value="edit" /> # if is_not_latest and modify_perm: <input type="hidden" name="version" value="${page.version}"/> <input type="submit" value="${_('Revert to this version')}"/> # elif page.exists and modify_perm: <input type="submit" value="${_('Edit this page')}" accesskey="e" /> # elif not page.exists and create_perm: <input type="submit" value="${_('Create this page')}" accesskey="e" /> # if templates: <div id="template"> <label for="template">${_("using the template:")}</label> <select name="template"> <option ${{'selected': not default_template in templates }|htmlattr} value="">${_("(blank page)")}</option> # for t in sorted(templates): <option value="${t}" ${{'selected': t == default_template }|htmlattr}>${t}</option> # endfor </select> </div> # endif # endif </div> </form> |
A
Special care should be taken when producing attributes dynamically, as it's the
case here for | |
<py:if test="page.exists"> <xi:include href="attach_file_form.html" py:with="alist = attachments"/> </py:if> </py:if> | # if page.exists: # with alist = attachments # include "jattach_file_form.html" # endwith # endif # endif |
We pass attachments as alist to the included template (a j... template, obviously).
| |
<form method="get" action="${href.wiki(page.name)}" id="rename" py:if="page.exists and rename_perm"> <div> <input type="hidden" name="action" value="rename" /> <input type="submit" value="${_('Rename page')}" /> </div> </form> <form method="get" action="${href.wiki(page.name)}" id="delete" py:if="page.exists and delete_perm"> <div> <input type="hidden" name="action" value="delete" /> <input type="hidden" name="version" value="$page.version" /> <py:if test="page.version == latest_version"> <input type="submit" name="delete_version" value="${_('Delete this version')}" /> </py:if> <input type="submit" value="${_('Delete page')}" /> </div> </form> </div> </py:if> </py:with> | # if page.exists and rename_perm: <form method="get" action="${href.wiki(page.name)}" id="rename"> <div> <input type="hidden" name="action" value="rename" /> <input type="submit" value="${_('Rename page')}" /> </div> </form> # endif # if page.exists and delete_perm: <form method="get" action="${href.wiki(page.name)}" id="delete"> <div> <input type="hidden" name="action" value="delete" /> <input type="hidden" name="version" value="${page.version}" /> # if page.version == latest_version: <input type="submit" name="delete_version" value="${_('Delete this version')}" /> # endif <input type="submit" value="${_('Delete page')}" /> </div> </form> # endif </div> # endif # endwith |
<div class="wikipage searchable" py:if="not page.exists and higher"> <p>You could also create the same page higher in the hierarchy:</p> <ul> <li py:for="markup in higher">${markup}</li> </ul> </div> | # if not page.exists and higher: <div class="wikipage searchable"> <p>You could also create the same page higher in the hierarchy:</p> <ul> # for markup in higher: <li>${markup}</li> # endfor </ul> </div> # endif |
Here's the first use of the for statement. Straightforward.
| |
<div class="wikipage searchable" py:if="not page.exists and related"> <p>The following pages have a name similar to this page, and may be related:</p> <ul> <li py:for="markup in related">${markup}</li> </ul> </div> | # if not page.exists and related: <div class="wikipage searchable"> <p>${_("The following pages have a name similar to this page, and may be related:")}</p> <ul> # for markup in related: <li>${markup}</li> # endif </ul> </div> # endif |
</div> </body> </html> | </div> ${ super() } # endblock content </body> </html> |
Once we're done with the <div id="content"> , we also call ${ super() } to re-insert the parent content of the content block, i.e. the altlinks div and the late_links/late_scripts logic.
| |