Filters are a powerful feature of Jinja taken from django which probably took it from UNIX. The idea is that you "pipe" a value through some filters to do something with it. For example convert it to upper case, escape it or replace a substring.
Jinja comes with some builtin filters explained in the designer documentation.
A filter basically is a factory function, a function that returns another function. We do this because filters can get an unlimited amount of positional arguments and aditionally should gain access to the environment, context and piped value. A simple filter looks like this:
def do_join(d=u''): def wrapped(env, context, value): tmp =  for item in value: tmp.append(env.to_unicode(item)) return d.join(tmp) return wrapped
Now you have to register that filter on an environment:
env.filters['join'] = do_join
In fact this filter is already bundled so you won't see any effect. But it should explain how such a filter looks like. The template designer can just trigger the outer code (i.e. call join with or without arguments). The returned function is then processed by the jinja template engine once all filters are created.
If you want to create filters that just operate on a string (in fact unicode objects) you can use the stringfilter decorator:
from jinja.filters import stringfilter @stringfilter def do_strip(value): return value.strip()
The wrapped function is created internally by the decorator, any positional arguments are forwarded to the filter function. The first argument is always the value already converted into a string.