Files
Print_server/template_syntax.md
2026-01-22 11:13:07 +01:00

15 KiB

Receipt Template Language (RTL) Syntax Documentation

This document describes the syntax for creating receipt templates used by the Epson thermal printer template engine.

Table of Contents

  1. Overview
  2. Basic Text
  3. Data Bindings
  4. Styled Text
  5. Separators
  6. Comments
  7. Conditionals
  8. Loops
  9. Rows and Columns
  10. Complete Example
  11. Printer Profiles

Overview

RTL is a line-based template language designed for thermal receipt printers. Templates are plain text files with embedded directives, bindings, and style markers that get transformed into printer commands.

File Extension: .template

Key Concepts:

  • Templates are processed line by line
  • Data is provided as JSON and accessed via bindings {path}
  • Styles are applied using #style# text # syntax
  • Control flow uses @directive syntax

Basic Text

Plain text is output directly to the printer.

Hello World
This is plain text

Output:

Hello World
This is plain text

Empty Lines

Empty lines in templates produce empty lines on the receipt.

Line 1

Line 3

Data Bindings

Bindings insert values from the JSON data into the output.

Simple Binding

{PropertyName}

JSON:

{"PropertyName": "Hello"}

Output:

Hello

Nested Properties

Use dot notation to access nested objects.

{Customer.Name}
{Order.Items.0.Name}

JSON:

{
  "Customer": {"Name": "John Doe"},
  "Order": {"Items": [{"Name": "Coffee"}]}
}

Output:

John Doe
Coffee

Format Specifiers

Add a format string after a colon to format numbers and dates.

Numeric Formats

Total: {Amount:F2}
Order #: {OrderNumber:D4}

JSON:

{"Amount": 19.5, "OrderNumber": 42}

Output:

Total: 19.50
Order #: 0042
Format Description Example Input Output
F2 Fixed-point, 2 decimals 19.5 19.50
F0 Fixed-point, no decimals 19.5 20
D4 Decimal, padded to 4 digits 42 0042
N2 Number with grouping 1234.5 1,234.50

Date/Time Formats

Date: {TransactionDateTime:dd-MMM-yy}
Time: {TransactionDateTime:HH:mm}
Full: {TransactionDateTime:yyyy-MM-dd HH:mm:ss}

JSON:

{"TransactionDateTime": "2024-03-15T14:30:00"}

Output:

Date: 15-Mar-24
Time: 14:30
Full: 2024-03-15 14:30:00
Format Description Example Output
dd-MMM-yy Day-Month-Year 15-Mar-24
dd/MM/yyyy European date 15/03/2024
MM/dd/yyyy US date 03/15/2024
HH:mm 24-hour time 14:30
hh:mm tt 12-hour time 02:30 PM

Array Count

Access the count/length of an array.

Items: {Items.count}

JSON:

{"Items": ["A", "B", "C"]}

Output:

Items: 3

Missing Values

If a binding path doesn't exist or is null, an empty string is output.

Name: {MissingProperty}

Output:

Name:

Styled Text

Apply formatting styles to text using the #styles# content # syntax.

Basic Syntax

#style1,style2# text content #

The styles are comma-separated and applied to all content between the markers.

Available Styles

Style Description PrintCommand Property
bold Bold text IsBold = true
big Double-width and double-height IsBig = true
tall Double-height only IsTall = true
red Red color (if printer supports) IsRed = true
center Center-align text Text padded with spaces
right Right-align text Text padded with spaces
left Left-align text (default) No padding
spacing:N Set line spacing to N SetLineSpacing = N

Examples

Bold Text

#bold# Important Notice #

Centered Title

#center# RECEIPT #

Combined Styles

#bold,big,center# RESTAURANT NAME #

Red Text (Impact Printers)

#red,bold# WARNING #

With Bindings

#bold,center# {Title} #
#big# Table: {TableNumber} #

Line Spacing

#spacing:50# Spaced text #

Style Scope

Styles apply only to content within the markers on the same line.

#bold# This is bold # but this is not

Separators

Create horizontal lines using repeated characters.

Dash Separator

---

Output: ------------------------------------------------ (full line width)

Equals Separator

===

Output: ================================================

Star Separator

***

Output: ************************************************

Tilde Separator

~~~

Output: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Note: Separator width automatically matches the printer's line width (48 chars for TM-T30III, 33 chars for TM-U220II).


Comments

Add comments to templates for documentation purposes. Comments are stripped during parsing and do not appear in the output.

Single-Line Comment

Use @* at the start of a line to comment out the entire line.

@* This is a single-line comment
Regular text here

Output:

Regular text here

Inline Comment

Use @* ... *@ to create a comment that can have content after it on the same line.

@* This is a comment *@
@* Header section *@
#bold,center# Title #

Output:


Title

Multi-Line Comment

Use @* on its own line to start a multi-line comment block, and *@ to close it.

@*
This is a multi-line comment.
All these lines are ignored.
Directives like @if are also ignored here.
*@
This text appears in output

Output:

This text appears in output

Use Cases

Document Template Sections

@* === HEADER SECTION === *@
#bold,center# {Title} #
---

@* === ITEMS SECTION === *@
@foreach item in Items
{item.Name}
@end

Temporarily Disable Code

@*
@if DebugMode
Debug info: {DebugData}
@end
*@

Add Notes for Maintainers

@* Note: This section only shows for orders over $100 *@
@if Total > 100
#bold# Large Order #
@end

Important Notes

  • Comments must start at the beginning of a line (after optional whitespace)
  • @* mid-line in content is treated as regular text, not a comment
  • Star separators (***) are not confused with comments
  • Unclosed multi-line comments produce a lexer error

Conditionals

Control which content is rendered based on data values.

Basic If

@if Condition
Content shown when true
@end

If-Else

@if HasDiscount
Discount Applied!
@else
No Discount
@end

If-ElseIf-Else

@if Status == "pending"
Order Pending
@elseif Status == "complete"
Order Complete
@else
Unknown Status
@end

Truthy/Falsy Values

The following are considered falsy:

  • null or missing property
  • false
  • Empty string ""
  • Number 0
  • Empty array []

Everything else is truthy.

Comparison Operators

Operator Description Example
== Equal Status == "active"
!= Not equal Type != "void"
> Greater than Amount > 100
< Less than Count < 5
>= Greater or equal Total >= 50
<= Less or equal Qty <= 10

Negation

@if !IsVoided
Valid Order
@end

String Literals

Use quotes for string comparisons.

@if Status == "active"
Active
@end

Numeric Comparisons

@if Amount > 100
Large Order
@end

@if Items.count > 0
Has Items
@end

Examples

Check for Optional Field

@if SpecialInstruction
#bold# Note: {SpecialInstruction} #
@end

Check Array Has Items

@if Modifications.count > 0
Modifications:
@foreach mod in Modifications
  - {mod}
@end
@end

Conditional Separator

@if Items.count > 0
---
@end

Loops

Iterate over arrays in the data.

Basic Foreach

@foreach item in Items
{item}
@end

JSON:

{"Items": ["Apple", "Banana", "Cherry"]}

Output:

Apple
Banana
Cherry

Object Properties

@foreach product in Products
{product.Name} - {product.Price:F2}
@end

JSON:

{
  "Products": [
    {"Name": "Coffee", "Price": 3.50},
    {"Name": "Tea", "Price": 2.50}
  ]
}

Output:

Coffee - 3.50
Tea - 2.50

Nested Loops

@foreach category in Categories
#bold# {category.Name} #
@foreach item in category.Items
  {item.Name}
@end
@end

Loop Metadata Variables

Inside a loop, these special variables are available:

Variable Description Example Value
_index Zero-based index 0, 1, 2, ...
_number One-based number 1, 2, 3, ...
_first True if first item true/false
_last True if last item true/false
_count Total items in collection 5

Examples

@foreach item in Items
{_number}. {item.Name}
@end

Output:

1. Apple
2. Banana
3. Cherry
@foreach item in Items
{item}
@if !_last
---
@end
@end

Output:

Apple
---
Banana
---
Cherry

Nested Path Collections

@foreach dish in Order.Kitchen.Dishes
{dish.Name}
@end

Rows and Columns

Create tabular layouts with fixed-width columns.

Basic Row

@row
|width|content|width|content
@endrow

Row Styles

Apply styles to an entire row by adding style names after @row:

@row bold
|width|content|width|content
@endrow

Multiple styles can be combined with commas:

@row bold, big
|width|content|width|content
@endrow

Available Row Styles

Style Description
bold Bold text for entire row
big Double-width and double-height
tall Double-height only
red Red color (if printer supports)
spacing:N Set line spacing to N

Row Style Examples

@row bold
|30|{Name}|10,right|{Price:F2}
@endrow
@row bold, big
|15|TOTAL|9,right|{Total:F2}
@endrow
@row red, bold
|40|*** WARNING ***
@endrow

Column Syntax

|width|content
|width,alignment|content
  • width: Number of characters for the column
  • alignment: left (default), right, or center

Examples

Two Columns

@row
|30|{Name}|10,right|{Price:F2}
@endrow

JSON:

{"Name": "Coffee", "Price": 3.50}

Output:

Coffee                        3.50

Three Columns

@row
|5,right|{Qty}|25|{Name}|10,right|{Total:F2}
@endrow

Output:

    2 Espresso                   7.00

Header Row

@row
|5|Qty|25|Item|10,right|Price
@endrow
===

Columns in Loops

@foreach item in Items
@row
|5,right|{item.Quantity}|25|{item.Name}|10,right|{item.Price:F2}
@endrow
@end

Text Truncation

If content exceeds the column width, it is truncated.

@row
|10|VeryLongProductNameHere
@endrow

Output:

VeryLongPr

Complete Example

Here's a complete kitchen receipt template:

#red,big,tall,center# {Title} #
---

#center# {TransactionDateTime:dd-MMM-yy HH:mm} Nr.:{ReceiptNumber} #
#center# {WaiterName} #
#center# {WaiterId} #
#big,bold,center# Tisch: {TableNumber} #

@if SpecialInstruction

#big,bold,center# {SpecialInstruction} #

@end
---
@foreach gang in Gangs
#red,big,tall,center# {gang.Id}. {gang.Name} #
@foreach dish in gang.Dishes
#tall# {dish.Number}x {dish.Name} #
@if dish.Modifications.Removed.count > 0
@foreach removed in dish.Modifications.Removed
#bold,tall#   - {removed} #
@end
@end
@if dish.Modifications.Added.count > 0
@foreach added in dish.Modifications.Added
#bold,tall#   + {added} #
@end
@end
@if dish.Comment
#bold,tall#   Comment: {dish.Comment} #
@end
@end
@end
@if Gangs.count > 0
---
@end
@foreach dish in Dishes
#tall# {dish.Number}x {dish.Name} #
@if dish.Modifications.Removed.count > 0
@foreach removed in dish.Modifications.Removed
#bold,tall#   - {removed} #
@end
@end
@if dish.Modifications.Added.count > 0
@foreach added in dish.Modifications.Added
#bold,tall#   + {added} #
@end
@end
@if dish.Comment
#bold,tall#   Comment: {dish.Comment} #
@end
@end
@if Dishes.count > 0

---

@end

Sample JSON:

{
  "Title": "Restaurant Kitchen",
  "TransactionDateTime": "2024-03-15T14:30:00",
  "ReceiptNumber": "12345",
  "WaiterName": "John Doe",
  "WaiterId": "W001",
  "TableNumber": "5",
  "SpecialInstruction": "Rush Order",
  "Gangs": [
    {
      "Id": 1,
      "Name": "Starters",
      "Dishes": [
        {
          "Number": 2,
          "Name": "Caesar Salad",
          "Modifications": {
            "Removed": ["Croutons"],
            "Added": ["Extra Dressing"]
          },
          "Comment": "No anchovies"
        }
      ]
    }
  ],
  "Dishes": []
}

Printer Profiles

Templates adapt to different printer capabilities using profiles.

Built-in Profiles

Printer Profile ID Line Width Big Width Red Support
TM-T30III tm-t30iii 48 24 No
TM-U220II tm-u220ii 33 20 Yes

How Profiles Affect Output

  1. Line Width: Separators and centered text use the profile's line width
  2. Big Width: When big style is applied, centering uses the reduced width
  3. Red Support: The red style only produces red output on supported printers

Template Assignment

Templates are assigned to receipt types and printer profiles in assignments.json:

{
  "assignments": [
    {
      "receiptType": 1,
      "profileId": "tm-t30iii",
      "template": "kitchen-default.template"
    },
    {
      "receiptType": 1,
      "profileId": "tm-u220ii",
      "template": "kitchen-u220.template"
    },
    {
      "receiptType": 1,
      "profileId": null,
      "template": "kitchen-default.template"
    }
  ],
  "fallbackTemplate": "fallback.template"
}

Resolution Priority:

  1. Exact match (receiptType + profileId)
  2. Type-only match (receiptType, no profileId)
  3. Fallback template

Quick Reference

Syntax Summary

Syntax Description
{path} Data binding
{path:format} Formatted binding
#style# text # Styled text
--- Dash separator
=== Equals separator
*** Star separator
~~~ Tilde separator
@* comment Single-line comment
@* comment *@ Inline comment
@* ... *@ Multi-line comment block
@if condition Start conditional
@elseif condition Else-if branch
@else Else branch
@end End block
@foreach var in collection Start loop
@row Start row
@row style1, style2 Start row with styles
@endrow End row
|width|content Column definition
|width,align|content Column with alignment

Style Reference

Style Effect
bold Bold text
big Double size
tall Double height
red Red color
center Center align
right Right align
spacing:N Line spacing

Loop Variables

Variable Value
_index 0, 1, 2, ...
_number 1, 2, 3, ...
_first true/false
_last true/false
_count total count