TemplatePro - Delphi Template Engine | Developer Guide
Version 0.9.0 | GitHub Repository | Apache 2.0 License
TemplatePro is a powerful template engine for Delphi, designed for generating HTML pages, emails, reports, and any text-based output. Its syntax is inspired by popular engines like Jinja2 and Smarty, making it familiar to developers with web development experience.
What is TemplatePro?
TemplatePro is an open-source template engine for Delphi and Object Pascal that separates presentation logic from business logic. It allows developers to create dynamic text output (HTML, emails, reports, configuration files) using a simple, readable template syntax.
Key Features at a Glance
| Feature | Description |
|---|---|
| Jinja2-like Syntax | Familiar {{:variable}} and {{if}}...{{endif}} syntax |
| Expressions | Full arithmetic and logical expressions with @(...) |
| Filters | 30+ built-in filters for formatting and transformation |
| Loops | Iterate over lists, datasets, and JSON arrays |
| Conditionals | if, else, elif with complex conditions |
| Macros | Reusable template fragments with parameters |
| Template Inheritance | extends, block, and inherited for layouts |
| Multi-level Inheritance | Unlimited inheritance depth (A → B → C) |
| Dataset Support | Native TDataSet and field iteration |
| Compiled Templates | Parse once, render many times for performance |
| Cross-Platform | Windows, Linux, macOS via FireMonkey/FMX |
Why Choose TemplatePro?
- Fast: Compiled templates with minimal runtime overhead
- Safe: No code execution in templates, just data binding
- Familiar: If you know Jinja2, Twig, or Smarty, you already know TemplatePro
- Integrated: Works seamlessly with DMVCFramework and standalone Delphi projects
- Maintained: Active development with regular updates
Table of Contents
- Getting Started
- Template Syntax Overview
- Variables
- Expressions
- The Set Statement
- Conditionals
- Loops
- Filters
- Macros
- Template Composition
- Working with Datasets
- Output Configuration
- API Reference
- Best Practices
- Comments
- Flow Control
- Migration Notes
- FAQ
- Alternatives and Comparisons
- Links
Getting Started
Installation
Add the TemplatePro unit to your project:
uses
TemplatePro;
Basic Usage
The workflow is simple: compile a template, set data, render output.
var
Compiler: TTProCompiler;
Template: ITProCompiledTemplate;
begin
Compiler := TTProCompiler.Create;
try
Template := Compiler.Compile('Hello, {{:name}}!');
finally
Compiler.Free;
end;
Template.SetData('name', 'World');
WriteLn(Template.Render); // Output: Hello, World!
end;
Important: Always free the compiler after use. The compiled template (
ITProCompiledTemplate) is reference-counted and managed automatically.
One-Line Rendering
For simple cases where you don’t need to reuse the template, use the static method:
var
Output: string;
begin
Output := TTProCompiler.CompileAndRender(
'Hello, {{:name}}!',
['name'],
['World']
);
// Output: Hello, World!
end;
This method handles compiler creation and cleanup internally.
Compiled Template Caching
For better performance in production, save compiled templates to disk:
// Save compiled template
Template.SaveToFile('order_email.tpc');
// Load pre-compiled template (faster startup)
Template := TTProCompiledTemplate.CreateFromFile('order_email.tpc');
Note: Compiled templates are version-specific. Recompile when upgrading TemplatePro.
Template Syntax Overview
TemplatePro uses double curly braces {{ }} for all directives:
| Syntax | Purpose | Example |
|---|---|---|
{{:var}} |
Output a variable | {{:customer.name}} |
{{@expr}} |
Evaluate an expression | {{@price * quantity}} |
{{if}}...{{endif}} |
Conditional block | {{if is_active}}...{{endif}} |
{{for}}...{{endfor}} |
Loop block | {{for item in items}}...{{endfor}} |
{{set var := value}} |
Set a variable | {{set total := 0}} |
{{include "file"}} |
Include another template | {{include "header.tpro"}} |
{{macro name()}} |
Define a macro | {{macro button(text)}}...{{endmacro}} |
{{>name()}} |
Call a macro | {{>button("Click")}} |
{{# comment #}} |
Comment (not rendered) | {{# TODO: fix this #}} |
Note: Since version 0.7.0, TemplatePro is case insensitive for both variable names and directives.
Variables
Simple Variables
Output variable values using the colon prefix:
Customer: {{:customer_name}}
Order Total: {{:order_total}}
Delphi code:
Template.SetData('customer_name', 'John Smith');
Template.SetData('order_total', 149.99);
Object Properties
Access nested properties using dot notation:
Customer: {{:order.customer.name}}
Address: {{:order.customer.address.city}}, {{:order.customer.address.country}}
Delphi code:
Template.SetData('order', OrderObject); // TOrder with nested TCustomer
Array Elements
Access array elements by index (zero-based):
First item: {{:items[0].name}}
Second item: {{:items[1].name}}
Missing Variables
Missing or null variables render as empty strings without errors:
Middle name: {{:customer.middle_name}}
If middle_name is not set, nothing is rendered. Use the default filter for fallback values:
Middle name: {{:customer.middle_name|default,"(none)"}}
Expressions
Expressions allow calculations and function calls directly in templates. Use the @ prefix.
Arithmetic Operations
Subtotal: ${{@quantity * unit_price}}
Tax (10%): ${{@quantity * unit_price * 0.10}}
Total: ${{@quantity * unit_price * 1.10}}
Supported operators: +, -, *, /, div (integer division), mod, ^ (power)
Operator Precedence
Use parentheses to control evaluation order:
Without parentheses: {{@2 + 3 * 4}} outputs 14
With parentheses: {{@(2 + 3) * 4}} outputs 20
Built-in Functions
Math functions:
| Function | Description | Example |
|---|---|---|
sqrt(x) |
Square root | {{@sqrt(16)}} → 4 |
abs(x) |
Absolute value | {{@abs(-5)}} → 5 |
floor(x) |
Round down | {{@floor(3.7)}} → 3 |
ceil(x) |
Round up | {{@ceil(3.2)}} → 4 |
round(x, n) |
Round to n decimals | {{@round(3.456, -2)}} → 3.46 |
min(a, b) |
Minimum value | {{@min(5, 3)}} → 3 |
max(a, b) |
Maximum value | {{@max(5, 3)}} → 5 |
String functions:
| Function | Description | Example |
|---|---|---|
length(s) |
String length | {{@length("hello")}} → 5 |
upper(s) |
Uppercase | {{@upper("hello")}} → HELLO |
lower(s) |
Lowercase | {{@lower("HELLO")}} → hello |
trim(s) |
Remove whitespace | {{@trim(" hi ")}} → hi |
left(s, n) |
Left n characters | {{@left("hello", 2)}} → he |
right(s, n) |
Right n characters | {{@right("hello", 2)}} → lo |
Conversion functions:
| Function | Description | Example |
|---|---|---|
tostring(x) |
Convert to string | {{@tostring(42)}} → “42” |
tointeger(s) |
Convert to integer | {{@tointeger("42")}} → 42 |
Expressions in Conditionals
Use @(condition) for complex boolean logic:
{{if @(age >= 18 and has_license)}}
You can rent a car.
{{endif}}
{{if @(total > 100 or is_premium_member)}}
Free shipping!
{{endif}}
The Set Statement
Define or modify variables within templates using {{set}}.
Syntax
{{set variable_name := value}}
Important: Use
:=(not=) for assignment, consistent with Delphi/Pascal syntax.
Literal Values
Supported literal types:
- Strings: enclosed in double quotes
"text" - Integers:
42,-10 - Floats:
3.14,-0.5 - Booleans:
trueorfalse(case-insensitive)
Note:
trueandfalseare reserved words and cannot be used as variable names.
{{set tax_rate := 0.10}}
{{set greeting := "Welcome!"}}
{{set is_active := true}}
{{set max_items := 100}}
Copying Variables
Copy an existing variable to a new one:
{{set backup_name := customer.name}}
Expression Values
Calculate values using expressions:
{{set subtotal := @(quantity * unit_price)}}
{{set tax := @(subtotal * tax_rate)}}
{{set total := @(subtotal + tax)}}
Order Summary:
Subtotal: ${{:subtotal}}
Tax: ${{:tax}}
Total: ${{:total}}
Filtered Values
Apply filters to the assigned value:
{{set upper_name := customer.name|uppercase}}
{{set formatted_date := order.date|datetostr,"dd/mm/yyyy"}}
Accumulators in Loops
Build running totals:
{{set order_total := 0}}
{{for item in order.items}}
{{:item.name}}: ${{:item.price}}
{{set order_total := @(order_total + item.price)}}
{{endfor}}
Grand Total: ${{:order_total}}
Conditionals
Basic If/Else
{{if user.is_logged_in}}
Welcome back, {{:user.name}}!
{{else}}
Please log in to continue.
{{endif}}
Truthiness Rules
TemplatePro evaluates values as follows:
| Type | Truthy | Falsy |
|---|---|---|
| Boolean | true |
false |
| String | Non-empty | Empty string "" |
| Number | Non-zero | Zero 0 |
| Object | Not nil | nil |
| Dataset | Has records | Empty (EOF) |
Comparison Filters
Use filters for comparisons in conditions:
{{if order.total|gt,100}}
Free shipping included!
{{endif}}
{{if stock_count|eq,0}}
Out of stock
{{endif}}
{{if user.age|ge,18}}
Adult content available
{{endif}}
Available comparison filters: eq, ne, gt, ge, lt, le, contains, icontains
Expression Conditions
For complex logic, use expression syntax:
{{if @(quantity > 0 and quantity <= stock)}}
<button>Add to Cart</button>
{{else}}
<button disabled>Unavailable</button>
{{endif}}
{{if @(is_member or total > 50)}}
You qualify for free shipping!
{{endif}}
{{if @(status = "active" and days_remaining > 0)}}
Subscription active
{{endif}}
Negation
Use ! to negate a condition:
{{if !user.email_verified}}
Please verify your email address.
{{endif}}
Loops
Basic Loop
Iterate over collections with for...in:
<ul>
{{for product in products}}
<li>{{:product.name}} - ${{:product.price}}</li>
{{endfor}}
</ul>
Pseudo-Variables
Access loop metadata using @@ prefix:
| Variable | Description |
|---|---|
@@index |
Current iteration (1-based) |
@@odd |
True for odd iterations (1, 3, 5…) |
@@even |
True for even iterations (2, 4, 6…) |
@@first |
True for the first iteration |
@@last |
True for the last iteration (requires known count) |
<table>
{{for item in items}}
<tr class="{{if item.@@odd}}odd-row{{else}}even-row{{endif}}{{if item.@@first}} first{{endif}}{{if item.@@last}} last{{endif}}">
<td>{{:item.@@index}}</td>
<td>{{:item.name}}</td>
</tr>
{{endfor}}
</table>
Note:
@@lastrequires the collection to have a known count. For TDataSet record iteration, this requires the dataset to be fully fetched (RecordCount must be available). For field iteration, object lists, and JSON arrays,@@lastworks automatically.
Continue Statement
Skip iterations conditionally:
{{for product in products}}
{{if product.is_hidden}}
{{continue}}
{{endif}}
<div>{{:product.name}}</div>
{{endfor}}
Nested Loops
{{for category in categories}}
<h2>{{:category.name}}</h2>
<ul>
{{for product in category.products}}
<li>{{:product.name}}</li>
{{endfor}}
</ul>
{{endfor}}
Empty Collections
Check if a collection has items before looping:
{{if orders}}
{{for order in orders}}
Order #{{:order.id}}: ${{:order.total}}
{{endfor}}
{{else}}
No orders found.
{{endif}}
Filters
Filters transform values using the pipe | syntax.
Basic Usage
{{customer.name|uppercase}}
{{:product.description|trunc,100}}
{{order.date|datetostr,"dd/mm/yyyy"}}
Chained Filters
Apply multiple filters in sequence:
{{:user.email|lowercase|default,"no-email@example.com"}}
{{:product.code|uppercase|lpad,10,"0"}}
Built-in Filters Reference
Text Transformation:
| Filter | Description | Example |
|---|---|---|
uppercase |
Convert to uppercase | {{:name|uppercase}} |
lowercase |
Convert to lowercase | {{:email|lowercase}} |
capitalize |
Capitalize words | {{:title|capitalize}} |
trunc,n |
Truncate with ellipsis | {{:text|trunc,50}} |
Padding:
| Filter | Description | Example |
|---|---|---|
lpad,n[,char] |
Left-pad to length | {{:id|lpad,6,"0"}} → 000042 |
rpad,n[,char] |
Right-pad to length | {{:code|rpad,10,"-"}} |
Date/Time:
| Filter | Description | Example |
|---|---|---|
datetostr[,format] |
Format date | {{:date|datetostr,"yyyy-mm-dd"}} |
datetimetostr[,format] |
Format datetime | {{:timestamp|datetimetostr}} |
formatdatetime,format |
Custom format | {{:dt|formatdatetime,"dddd, mmmm d"}} |
Numeric:
| Filter | Description | Example |
|---|---|---|
round,decimals |
Round number | {{:price|round,-2}} → 19.99 |
formatfloat,format |
Format number | {{:amount|formatfloat,"#,##0.00"}} |
mod,n |
Modulo operation | {{:num|mod,2}} |
Default & Comparison:
| Filter | Description | Example |
|---|---|---|
default,value |
Fallback if empty/zero | {{:nickname|default,"Guest"}} |
eq,value |
Equal (for conditions) | {{if status|eq,"active"}} |
ne,value |
Not equal | {{if type|ne,"admin"}} |
gt,value |
Greater than | {{if age|gt,17}} |
ge,value |
Greater or equal | {{if score|ge,60}} |
lt,value |
Less than | {{if stock|lt,10}} |
le,value |
Less or equal | {{if items|le,5}} |
contains,text |
Contains substring | {{if name|contains,"Jr"}} |
icontains,text |
Contains (case-insensitive) | {{if email|icontains,"gmail"}} |
Utility:
| Filter | Description | Example |
|---|---|---|
totrue |
Always returns true | {{if var|totrue}} |
tofalse |
Always returns false | {{if var|tofalse}} |
Functions (applied to empty value):
| Filter | Description | Example |
|---|---|---|
version |
TemplatePro version | {{:|version}} |
Custom Filters
Register custom transformation functions:
// Define the filter function
function CurrencyFilter(const Value: TValue;
const Params: TArray<TFilterParameter>): TValue;
begin
Result := Format('$%.2f', [Value.AsExtended]);
end;
// Register after compilation
Template.AddFilter('currency', CurrencyFilter);
Template usage:
Price: {{:product.price|currency}}
Filter with parameters:
function RepeatFilter(const Value: TValue;
const Params: TArray<TFilterParameter>): TValue;
var
i, Count: Integer;
S: string;
begin
Count := Params[0].ParIntValue;
S := '';
for i := 1 to Count do
S := S + Value.AsString;
Result := S;
end;
Template.AddFilter('repeat', RepeatFilter);
Usage:
{{:"-"|repeat,20}} outputs: --------------------
Macros
Macros are reusable template fragments with parameters.
Definition
{{macro alert(message, type)}}
<div class="alert alert-{{:type}}">
{{:message}}
</div>
{{endmacro}}
Calling Macros
Use the {{>}} syntax to invoke macros:
{{>alert("Operation successful!", "success")}}
{{>alert("Please check your input.", "warning")}}
{{>alert("An error occurred.", "error")}}
Macros Without Parameters
{{macro divider()}}
<hr class="section-divider">
{{endmacro}}
{{>divider()}}
Macros with Variables
Pass template variables as arguments:
{{macro user_card(user)}}
<div class="user-card">
<h3>{{:user.name}}</h3>
<p>{{:user.email}}</p>
</div>
{{endmacro}}
{{for u in users}}
{{>user_card(u)}}
{{endfor}}
Nested Macros
Macros can call other macros:
{{macro icon(name)}}
<i class="icon icon-{{:name}}"></i>
{{endmacro}}
{{macro button(text, icon_name)}}
<button class="btn">
{{>icon(icon_name)}} {{:text}}
</button>
{{endmacro}}
{{>button("Save", "check")}}
{{>button("Delete", "trash")}}
Template Composition
Include
Include external template files:
{{include "partials/header.tpro"}}
<main>
<h1>{{:page_title}}</h1>
{{:content}}
</main>
{{include "partials/footer.tpro"}}
Include with Variable Mappings
Pass variables to included templates:
{{include "components/product_card.tpro", product = :item, show_price = true}}
product_card.tpro:
<div class="product-card">
<h3>{{:product.name}}</h3>
{{if show_price}}
<p class="price">${{:product.price}}</p>
{{endif}}
</div>
You can pass different types:
{{include "alert.tpro", message = "Success!", type = "success"}}
{{include "alert.tpro", message = :error_message, type = "error"}}
{{include "counter.tpro", count = @(items_count * 2)}}
Dynamic Include
Include templates based on variables:
{{include :template_name}}
Template Inheritance
Create a base layout with replaceable blocks:
base.tpro:
<!DOCTYPE html>
<html>
<head>
<title>{{block "title"}}My Site{{endblock}}</title>
</head>
<body>
<nav>{{block "navigation"}}Default nav{{endblock}}</nav>
<main>
{{block "content"}}{{endblock}}
</main>
<footer>{{block "footer"}}Copyright 2025{{endblock}}</footer>
</body>
</html>
page.tpro:
{{extends "base.tpro"}}
{{block "title"}}{{:page_title}} - My Site{{endblock}}
{{block "content"}}
<h1>{{:page_title}}</h1>
<p>{{:content}}</p>
{{endblock}}
Inheritance rules:
- Child templates can only extend one parent
- Blocks not defined in the child use the parent’s content
- Content outside blocks in child templates is ignored
The inherited Keyword
Use {{inherited}} to include parent block content while adding your own:
base.tpro:
<head>
{{block "head"}}
<meta charset="UTF-8">
<title>My Site</title>
{{endblock}}
</head>
page.tpro:
{{extends "base.tpro"}}
{{block "head"}}
{{inherited}}
<link rel="stylesheet" href="page.css">
<script src="page.js"></script>
{{endblock}}
Output:
<head>
<meta charset="UTF-8">
<title>My Site</title>
<link rel="stylesheet" href="page.css">
<script src="page.js"></script>
</head>
Multi-level Inheritance
Templates can extend other templates that themselves extend other templates, creating unlimited inheritance chains:
level1_base.tpro:
<html>
{{block "content"}}Base Content{{endblock}}
</html>
level2_section.tpro:
{{extends "level1_base.tpro"}}
{{block "content"}}Section: {{inherited}}{{endblock}}
level3_page.tpro:
{{extends "level2_section.tpro"}}
{{block "content"}}Page -> {{inherited}}{{endblock}}
Output:
<html>
Page -> Section: Base Content
</html>
Multi-level inheritance features:
{{inherited}}includes content from the immediate parent at each level- Circular inheritance is detected and raises a clear error
- Self-inheritance (a template extending itself) is also detected
- Works correctly with partial block overrides at any level
Working with Datasets
TemplatePro integrates seamlessly with Delphi TDataSet components.
Iterating Records
<table>
<tr><th>Code</th><th>Name</th><th>Price</th></tr>
{{for product in products}}
<tr>
<td>{{:product.Code}}</td>
<td>{{:product.Name}}</td>
<td>{{:product.Price|formatfloat,"0.00"}}</td>
</tr>
{{endfor}}
</table>
Delphi code:
Template.SetData('products', ProductsDataSet);
Field Iteration
Iterate over dataset fields for dynamic form generation:
<form>
{{for field in customers.fields}}
<div class="form-group">
<label>{{:field.DisplayLabel}}{{if field.Required}} *{{endif}}</label>
<input type="text"
name="{{:field.FieldName}}"
value="{{:field}}"
{{if field.ReadOnly}}readonly{{endif}}>
</div>
{{endfor}}
</form>
Field Properties
Available properties when iterating fields:
| Property | Description |
|---|---|
FieldName |
Internal field name |
DisplayLabel |
User-friendly label |
DataType |
Field data type |
Size |
Field size |
Required |
Is field required |
ReadOnly |
Is field read-only |
Visible |
Is field visible |
Index |
Field index (0-based) |
Using field value: Access the current record’s value with just {{:field}}.
Expression Conditions with Fields
Use expressions to check field properties:
{{for f in customers.fields}}
{{if @(f.Index = 0)}}
<th>{{:f.DisplayLabel}}</th> {{# First field as header #}}
{{else}}
<td>{{:f}}</td>
{{endif}}
{{endfor}}
Output Configuration
Line Endings
TemplatePro provides cross-platform control over output line endings.
Input: Templates with any line ending style (CRLF, LF, CR) are automatically recognized.
Output: Configure the output line ending style:
Template.OutputLineEnding := lesLF; // Unix-style (default)
Template.OutputLineEnding := lesCRLF; // Windows-style
Template.OutputLineEnding := lesCR; // Classic Mac
Template.OutputLineEnding := lesNative; // Platform default
Available values:
| Value | Description | Characters |
|---|---|---|
lesLF |
Unix/Linux/Modern Mac | #10 |
lesCRLF |
Windows | #13#10 |
lesCR |
Classic Mac | #13 |
lesNative |
Current platform default | varies |
Tip: Use
lesLF(the default) for maximum portability. Most modern systems handle LF correctly.
API Reference
TTProCompiler
The template compiler.
var
Compiler: TTProCompiler;
begin
Compiler := TTProCompiler.Create;
try
// Compile from string
Template := Compiler.Compile(TemplateString);
// Compile from string with file path reference (for includes)
Template := Compiler.Compile(TemplateString, 'templates/page.tpro');
finally
Compiler.Free;
end;
end;
Static methods:
// Compile and render in one call
Output := TTProCompiler.CompileAndRender(
'Hello {{:name}}!',
['name'],
['World']
);
ITProCompiledTemplate
The compiled template interface.
Setting data:
Template.SetData('name', 'John'); // String
Template.SetData('age', 30); // Integer
Template.SetData('price', 19.99); // Float
Template.SetData('is_active', True); // Boolean
Template.SetData('user', UserObject); // Object
Template.SetData('items', ItemsList); // TObjectList
Template.SetData('customers', CustomersDataSet); // TDataSet
Adding filters:
Template.AddFilter('myfilter', MyFilterFunction);
Template.AddFilter('myfilter',
function(const Value: TValue; const Params: TArray<TFilterParameter>): TValue
begin
Result := '[' + Value.AsString + ']';
end
);
Rendering:
Output := Template.Render;
Persistence:
Template.SaveToFile('template.tpc');
Template := TTProCompiledTemplate.CreateFromFile('template.tpc');
Properties:
Template.OutputLineEnding := lesLF;
Template.FormatSettings := @MyFormatSettings;
Exceptions
try
Template := Compiler.Compile(TemplateString);
Output := Template.Render;
except
on E: ETProCompilerException do
// Syntax errors, missing end tags, invalid directives
ShowMessage('Compilation error: ' + E.Message);
on E: ETProRenderException do
// Runtime errors: missing variables, type mismatches
ShowMessage('Render error: ' + E.Message);
on E: ETProException do
// General TemplatePro errors
ShowMessage('Template error: ' + E.Message);
end;
Best Practices
Template Organization
templates/
layouts/
base.tpro
admin.tpro
partials/
header.tpro
footer.tpro
navigation.tpro
components/
alert.tpro
card.tpro
form_field.tpro
pages/
home.tpro
products.tpro
checkout.tpro
emails/
order_confirmation.tpro
password_reset.tpro
Performance Tips
- Compile once, render many: Keep compiled templates for reuse.
- Use pre-compiled templates: Save
.tpcfiles for production. - Avoid complex logic in templates: Pre-process data in Delphi.
- Use appropriate data structures: TObjectList over arrays for large collections.
Security
- Escape user input: Be cautious with user-provided data in templates.
- Validate include paths: Don’t allow user-controlled template paths.
- Limit template complexity: Set reasonable limits on nesting depth.
Debugging
// Dump compiled tokens for debugging
Template.DumpToFile('debug_output.txt');
// Use the OnGetValue event for custom variable resolution
Template.OnGetValue := procedure(const DataSource, Members: string;
var Value: TValue; var Handled: Boolean)
begin
WriteLn('Accessing: ', DataSource, '.', Members);
end;
Comments
Add comments that won’t appear in output:
{{# This is a single-line comment #}}
{{#
This is a multi-line comment.
It can span several lines.
#}}
Flow Control
Exit Statement
Stop rendering the template:
{{if critical_error}}
<p>A critical error occurred.</p>
{{exit}}
{{endif}}
{{# This content won't render if there's an error #}}
<p>Normal content here.</p>
Migration Notes
From Version 0.8.x
Set syntax change:
{{# Old syntax (0.8.x) #}}
{{set myvar = 42}}
{{# New syntax (0.9.0) #}}
{{set myvar := 42}}
And/Or filters removed:
{{# Old syntax (deprecated) #}}
{{if value1|and,value2}}
{{# New syntax #}}
{{if @(value1 and value2)}}
New features in 0.9.0:
{{inherited}}keyword for including parent block content- Multi-level template inheritance (A extends B extends C)
- Circular inheritance detection
Frequently Asked Questions (FAQ)
What is the difference between TemplatePro and other Delphi template engines?
TemplatePro offers a Jinja2/Smarty-inspired syntax that is familiar to web developers, while being specifically optimized for Delphi. Unlike simpler string replacement engines, TemplatePro supports:
- Full expression evaluation
- Template inheritance
- Macros with parameters
- Native TDataSet support
- Compiled template caching
Can I use TemplatePro with DMVCFramework?
Yes! TemplatePro is the default template engine for DMVCFramework. It integrates seamlessly for server-side HTML rendering in web applications.
Is TemplatePro thread-safe?
Yes. Compiled templates (ITProCompiledTemplate) are thread-safe for rendering. You can compile once and render from multiple threads simultaneously.
What data types can I pass to templates?
TemplatePro supports:
- Simple types (string, integer, float, boolean)
- Objects with published properties
TObjectList<T>and other generic listsTDataSetand descendants- JSON objects (
TJDOJsonObject) - Nullable types from
MVCFramework.Nullables
How do I handle HTML escaping?
By default, variable output is not escaped. Use the htmlencode filter for user-provided content:
{{:user_input|htmlencode}}
Can I extend TemplatePro with custom filters?
Yes! Register custom filters using TTProConfiguration.OnContextConfiguration:
TTProConfiguration.OnContextConfiguration :=
procedure(const Template: ITProCompiledTemplate)
begin
Template.AddTemplateFunction('myfilter', MyFilterFunction);
end;
What’s the performance like?
TemplatePro compiles templates to an internal token representation. Rendering is very fast:
- Compilation: ~1ms for typical templates
- Rendering: ~0.1ms for simple templates, scales linearly with complexity
- Memory: Minimal footprint, compiled templates are lightweight
Does TemplatePro support internationalization (i18n)?
TemplatePro provides locale-aware formatting through FormatSettings. For full i18n, combine with your localization framework and pass translated strings as variables.
Alternatives and Comparisons
If you’re evaluating template engines for Delphi, here’s how TemplatePro compares:
| Engine | Syntax Style | Expression Support | Template Inheritance | Dataset Support |
|---|---|---|---|---|
| TemplatePro | Jinja2/Smarty | Full expressions | Yes | Native |
| StringReplace | Simple | No | No | No |
| DWScript Templates | Pascal-like | Full | No | No |
| Mustache (Delphi) | Mustache | Limited | Partials only | Manual |
Links
TemplatePro Version 0.9.0 - December 2025
Comments
comments powered by Disqus