Become a member!

TemplatePro - Delphi Template Engine | Developer Guide

TemplatePro Logo - Delphi Template Engine

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

  1. Getting Started
  2. Template Syntax Overview
  3. Variables
  4. Expressions
  5. The Set Statement
  6. Conditionals
  7. Loops
  8. Filters
  9. Macros
  10. Template Composition
  11. Working with Datasets
  12. Output Configuration
  13. API Reference
  14. Best Practices
  15. Comments
  16. Flow Control
  17. Migration Notes
  18. FAQ
  19. Alternatives and Comparisons
  20. 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: true or false (case-insensitive)

Note: true and false are 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: @@last requires 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, @@last works 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

  1. Compile once, render many: Keep compiled templates for reuse.
  2. Use pre-compiled templates: Save .tpc files for production.
  3. Avoid complex logic in templates: Pre-process data in Delphi.
  4. Use appropriate data structures: TObjectList over arrays for large collections.

Security

  1. Escape user input: Be cautious with user-provided data in templates.
  2. Validate include paths: Don’t allow user-controlled template paths.
  3. 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 lists
  • TDataSet and 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


TemplatePro Version 0.9.0 - December 2025

Comments

comments powered by Disqus