Tina4

Frond (Twig) Templates#

Tip

TTina4Twig is a Twig-compatible template engine for server-side rendering, supporting variables, control structures, filters, functions, template inheritance, and macros.

Basic Usage#

pascal
var  Twig: TTina4Twig;  Variables: TStringDict;begin  Twig := TTina4Twig.Create('C:\templates');  Variables := TStringDict.Create;  try    Variables.Add('name', 'Andre');    Variables.Add('items', TValue.From<TArray<String>>(['Apple', 'Banana', 'Cherry']));    Memo1.Lines.Text := Twig.Render('hello.html', Variables);  finally    Variables.Free;    Twig.Free;  end;end;

Variables#

Output variables with double curly braces:

{{ name }}{{ user.email }}

Setting Variables#

{% set greeting = 'Hello' %}{% set items = ['Apple', 'Banana'] %}{% set total = price * quantity %}

Control Structures#

if / elseif / else#

{% if users|length > 0 %}  <ul>    {% for user in users %}      <li>{{ user.name }}</li>    {% endfor %}  </ul>{% elseif guests|length > 0 %}  <p>Guests only</p>{% else %}  <p>No users found</p>{% endif %}

for loops#

{% for item in items %}  <p>{{ item }}</p>{% endfor %}{% for key, value in pairs %}  <p>{{ key }}: {{ value }}</p>{% endfor %}{% for i in 0..10 %}  <p>{{ i }}</p>{% endfor %}

with#

Scopes variables to a block:

{% with { title: 'Hello' } %}  <h1>{{ title }}</h1>{% endwith %}

Template Inheritance#

extends and block#

base.html:

<html><head><title>{% block title %}Default{% endblock %}</title></head><body>  {% block content %}{% endblock %}</body></html>

page.html:

{% extends 'base.html' %}{% block title %}My Page{% endblock %}{% block content %}  <h1>Hello World</h1>{% endblock %}

include#

{% include 'header.html' %}{% include 'sidebar.html' with { menu: items } %}

Set the template path so includes resolve correctly:

pascal
Twig := TTina4Twig.Create('C:\MyApp\templates');

Macros#

Define reusable template fragments:

{% macro input(name, value, type) %}  <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value }}">{% endmacro %}{{ input('username', '', 'text') }}{{ input('password', '', 'password') }}

Filters#

Filters transform values using the pipe | operator. They can be chained:

{{ name|upper|length }}

String Filters#

FilterDescriptionExample
upperUppercase<span v-pre>{{ 'hello'\|upper }}</span> &rarr; HELLO
lowerLowercase<span v-pre>{{ 'HELLO'\|lower }}</span> &rarr; hello
capitalizeCapitalize first letter<span v-pre>{{ 'hello'\|capitalize }}</span> &rarr; Hello
titleTitle case<span v-pre>{{ 'hello world'\|title }}</span> &rarr; Hello World
trimRemove whitespace<span v-pre>{{ ' hi '\|trim }}</span> &rarr; hi
nl2brNewlines to <br><span v-pre>{{ text\|nl2br }}</span>
striptagsRemove HTML tags<span v-pre>{{ html\|striptags }}</span>
replaceReplace values<span v-pre>{{ 'hello'\|replace({'e': 'a'}) }}</span>
splitSplit into array<span v-pre>{{ 'a,b,c'\|split(',') }}</span>
slugURL-friendly slug<span v-pre>{{ 'Hello World'\|slug }}</span> &rarr; hello-world
spacelessRemove whitespace between tags<span v-pre>{{ html\|spaceless }}</span>
uUnicode string<span v-pre>{{ text\|u }}</span>

Number Filters#

FilterDescriptionExample
absAbsolute value<span v-pre>{{ -5\|abs }}</span> &rarr; 5
number_formatFormat number<span v-pre>{{ 1234.5\|number_format(2, '.', ',') }}</span>
format_numberFormat with decimals<span v-pre>{{ 1234\|format_number }}</span>
format_currencyFormat as currency<span v-pre>{{ 1234\|format_currency('USD') }}</span>

Array Filters#

FilterDescriptionExample
lengthLength of array/string<span v-pre>{{ items\|length }}</span>
firstFirst element<span v-pre>{{ items\|first }}</span>
lastLast element<span v-pre>{{ items\|last }}</span>
joinJoin into string<span v-pre>{{ items\|join(', ') }}</span>
keysGet array keys<span v-pre>{{ obj\|keys }}</span>
mergeMerge arrays<span v-pre>{{ arr1\|merge(arr2) }}</span>
sortSort array<span v-pre>{{ items\|sort }}</span>
reverseReverse array/string<span v-pre>{{ items\|reverse }}</span>
shuffleRandomize order<span v-pre>{{ items\|shuffle }}</span>
sliceExtract portion<span v-pre>{{ items\|slice(1, 3) }}</span>
batchSplit into chunks<span v-pre>{{ items\|batch(3) }}</span>
columnExtract column<span v-pre>{{ users\|column('name') }}</span>
filterFilter with callback<span v-pre>{{ items\|filter }}</span>
findFind value<span v-pre>{{ items\|find }}</span>
mapMap with callback<span v-pre>{{ items\|map }}</span>
reduceReduce to single value<span v-pre>{{ items\|reduce }}</span>
minMinimum value<span v-pre>{{ items\|min }}</span>
maxMaximum value<span v-pre>{{ items\|max }}</span>

Date Filters#

FilterDescriptionExample
dateFormat date<span v-pre>{{ post.created\|date('Y-m-d') }}</span>
date_modifyModify date<span v-pre>{{ date\|date_modify('+1 day') }}</span>
format_dateFormat date (alias)<span v-pre>{{ date\|format_date }}</span>
format_datetimeFormat datetime (alias)<span v-pre>{{ date\|format_datetime }}</span>
format_timeFormat time<span v-pre>{{ date\|format_time }}</span>

Date format uses PHP-style specifiers that are automatically converted:

SpecifierMeaningExample
Y4-digit year2026
y2-digit year26
mMonth (zero-padded)03
nMonth (no padding)3
dDay (zero-padded)01
jDay (no padding)1
HHour 24h (zero-padded)14
hHour 12h (zero-padded)02
iMinutes30
sSeconds05
AAM/PMPM
DShort day nameMon
lFull day nameMonday
MShort month nameJan
FFull month nameJanuary

Encoding Filters#

FilterDescriptionExample
escape / eEscape HTML entities<span v-pre>{{ html\|escape }}</span>
rawNo escaping<span v-pre>{{ html\|raw }}</span>
url_encodeURL encode<span v-pre>{{ text\|url_encode }}</span>
json_encodeEncode to JSON<span v-pre>{{ data\|json_encode }}</span>
json_decodeDecode from JSON<span v-pre>{{ json\|json_decode }}</span>
convert_encodingConvert charset<span v-pre>{{ text\|convert_encoding('UTF-8') }}</span>
data_uriCreate data URI<span v-pre>{{ content\|data_uri }}</span>

Other Filters#

FilterDescription
defaultFallback value: <span v-pre>{{ name\|default('Guest') }}</span>
formatString formatting: <span v-pre>{{ 'Hi %s'\|format(name) }}</span>
pluralPlural form
singularSingular form

Functions#

FunctionDescriptionExample
rangeGenerate number/letter sequence{% for i in range(1, 10) %}
dumpDebug output<span v-pre>{{ dump(variable) }}</span>
dateCreate/format dates<span v-pre>{{ date('now', 'Y-m-d') }}</span>

Operators#

CategoryOperators
Comparison==, !=, <, >, <=, >=
Logicaland, or, not
String~ (concatenation), in, starts with, ends with, matches
Math+, -, *, /, %, **
Range.. (e.g., 1..10, 'a'..'z')

Integration with TTina4HTMLRender#

The HTML renderer has built-in Twig support via its Twig property:

pascal
Tina4HTMLRender1.SetTwigVariable('title', 'Hello');Tina4HTMLRender1.Twig.Text := '<h1>{{ title }}</h1>';

See HTML Renderer - Twig Integration for details.