Functions and filters
Everything a template can call, and the closing line that nothing else exists
Provided by sqzass
Two functions. That is the whole list.
asset(path)
Returns the URL a static file was written to, hash and subpath included.
The argument is the logical path under static/, with or without a leading
slash. A name that was not collected is a build error listing every name that
was — a renamed stylesheet fails the build instead of 404ing for every visitor.
t(key)
Looks a UI string up in i18n/<language>.toml, for the language of the page
being rendered.
{{ t("skip_to_content") }}
One argument. The language is never passed in — see Languages for why that is deliberate. A key missing from the current language is a build error.
Warning
Do not name a loop variable t. {% for t in page.translations %} shadows
the function inside that block, and the first person to add a label there gets
an error a long way from its cause.
From minijinja
Standard Jinja2 syntax works: {% if %}, {% for %}, {% extends %},
{% block %}, {% include %}, {% macro %}, {% from … import … %}, {% set %},
and the usual filters — safe, escape, length, join, default, upper,
lower, replace, trim, first, last, reverse, sort, map,
select, selectattr, batch, slice, int, float, abs, round,
indent.
Our own templates use {% macro %} and {% from "partials/sidebar.html" import nav %},
so those two are exercised on every build.
Three filters a Jinja2 habit reaches for are not here: tojson,
urlencode and striptags. Each is behind a minijinja feature we leave off,
and each is a dependency for something already covered — a {% for %} loop, a
URL that arrives ready to use, or markup you did not have to strip because you
wrote it. Calling one is a build error, not an empty string, so you find out at
build time rather than in the page.
Nothing else exists
There is no url_for, no markdownify, no date, no now(), no env(), no
custom tests. Some of those are absences with reasons rather than gaps:
now() and env() would break the guarantee that two builds of the same input
produce identical bytes, which CI checks on every push. A template that can read
the clock cannot be reproducible.
url_for would wrap a comparison that is already one line. Page and section
URLs arrive ready to use, and they already carry the subpath.
Reading a name that does not exist is a build error, not an empty string — so if you call something from another generator by habit, you find out at build time rather than from a page with a hole in it.
Marking the current page
There is no helper for this, and none is needed. Exact match for a page:
{{ p.title }}
Ancestor match for a section, using page.section:
{{ s.title }}
For a prefix test use startingwith, but be careful with the root: every URL
starts with /, so the home link must be compared exactly and never as an
ancestor.