Jinja2tt2 Logo

Jinja2tt2

License: LGPL v2.1 Perl Version CPAN

Jinja2 to Template Toolkit Transpiler

A Perl transpiler that converts Jinja2 templates to Template Toolkit 2 (TT2) syntax.

Description

Jinja2 is deeply integrated with Python, making a direct port impractical. However, since TT2 and Jinja2 share similar concepts and syntax patterns, this transpiler performs a mechanical translation between the two template languages.

Why TT2?

TT2 and Jinja2 share:

Installation

No external dependencies beyond core Perl 5.20+.

git clone https://github.com/lucianofedericopereira/jinja2tt2
cd jinja2tt2

Usage

Command Line

# Transpile a file to stdout
./bin/jinja2tt2 template.j2

# Transpile with output to file
./bin/jinja2tt2 template.j2 -o template.tt

# Transpile in-place (creates .tt file)
./bin/jinja2tt2 -i template.j2

# From stdin
echo '{{ name|upper }}' | ./bin/jinja2tt2

# Debug mode (shows tokens and AST)
./bin/jinja2tt2 --debug template.j2

Programmatic Usage

use Jinja2::TT2;

my $transpiler = Jinja2::TT2->new();

# From string
my $tt2 = $transpiler->transpile('{{ user.name|upper }}');
# Result: [% user.name.upper %]

# From file
my $tt2 = $transpiler->transpile_file('template.j2');

Supported Constructs

Variables

{{ foo }}           →  [% foo %]
{{ user.name }}     →  [% user.name %]
{{ items[0] }}      →  [% items.0 %]

Filters

{{ name|upper }}              →  [% name.upper %]
{{ name|lower|trim }}         →  [% name.lower.trim %]
{{ items|join(", ") }}        →  [% items.join(', ') %]
{{ name|default("Guest") }}   →  [% (name || 'Guest') %]

Conditionals

{% if user %}          →  [% IF user %]
{% elif admin %}       →  [% ELSIF admin %]
{% else %}             →  [% ELSE %]
{% endif %}            →  [% END %]

Loops

{% for item in items %}    →  [% FOREACH item IN items %]
{{ loop.index }}           →  [% loop.count %]
{{ loop.first }}           →  [% loop.first %]
{{ loop.last }}            →  [% loop.last %]
{% endfor %}               →  [% END %]

Blocks and Macros

{% block content %}        →  [% BLOCK content %]
{% endblock %}             →  [% END %]

{% macro btn(text) %}      →  [% MACRO btn(text) BLOCK %]
{% endmacro %}             →  [% END %]

Comments

{# This is a comment #}    →  [%# This is a comment %]

Whitespace Control

{{- name -}}               →  [%- name -%]
{%- if x -%}               →  [%- IF x -%]

Other Constructs

Filter Mapping

| Jinja2 | TT2 Equivalent | |--------|----------------| | upper | .upper | | lower | .lower | | trim | .trim | | first | .first | | last | .last | | length | .size | | join | .join | | reverse | .reverse | | sort | .sort | | escape / e | \| html_entity | | default | \|\| operator | | replace | .replace |

Some filters require TT2 plugins (e.g., tojson needs Template::Plugin::JSON).

Loop Variable Mapping

| Jinja2 | TT2 | |--------|-----| | loop.index | loop.count | | loop.index0 | loop.index | | loop.first | loop.first | | loop.last | loop.last | | loop.length | loop.size |

Limitations

Running Tests

prove -l t/

Project Structure

jinja2tt2/
├── assets/
│   └── jinja2tt2.png       # Logo
├── bin/
│   └── jinja2tt2           # CLI tool
├── lib/Jinja2/
│   ├── TT2.pm              # Main module
│   └── TT2/
│       ├── Tokenizer.pm    # Lexical analysis
│       ├── Parser.pm       # Syntax analysis → AST
│       ├── Emitter.pm      # AST → TT2 code
│       └── Filters.pm      # Filter mapping table
├── t/                      # Test suite
└── examples/               # Example templates

Architecture

  1. Tokenizer: Splits Jinja2 source into tokens (text, variables, statements, comments)
  2. Parser: Builds an Abstract Syntax Tree (AST) from the token stream
  3. Emitter: Walks the AST and generates equivalent TT2 code

Credits

License

This is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) version 2.1 as published by the Free Software Foundation.

See the LICENSE file for the full license text.