Use the Smartcat template engine

Learn to create custom document templates using Smartcats Template Engine, featuring markup elements, data models, and C# syntax.

Using Smartcat Template Engine technology, you can create your own templates which the system will use for generating documentation. For example, you can create unique templates of invoices and quotes for this or that client.

How it works

Templates will be formed according to special markup elements and a data model that you set in the system for the corresponding type of documents.

What is the data model? A data model is a set of fields containing information about model elements. For example, let's take a model based on which the system generates documents for work done. The model will have the following fields:

Field name

Description

Name

The project name

Price

The cost of work

Words

Translated words

Date

Due date

Executive.FirstName

A linguist's name

Executive.LastName

A linguist's surname

Executive.Price

A linguist's rate

A template contains text and tags, which used specifically for displaying model elements. For getting the output from a model, use the following syntax <<[Field1]>>, where Field1 is the name of an element.

The following example shows some information about a particular job :

Template

Output

Project: <<[Name]>>

Deadline: <<[Date]>>

Assignee: <<[Executive.FirstName + “ ” + Executive.LastName]>>

Rate: <<[Executive.Price \* Words]>>

Project: PRESS\_RELEASE\_APR2020

Deadline: 02.04.2020

Assignee: Oliver Cross

Rate: 0.44

Smartcat Template Engine allows performing arithmetic operations like Addition (+), Subtraction (-), Multiplication (\*), and Division (/) right within a template. You may use each operation for numeric values such as rates, words, etc. Other fields that contain string-type values can be operated upon via the operators too though in a different way, for example, FirstName and LastName form the full name as output by using the plus sign.

Advanced features

Loops

The template engine also allows using loops, which is espeically good for forming an extensive list of data. The loop feature has the following form:

<<foreach [item in Items]>>

<<[item]>>

<</foreach>>

Where Items — an array, item — a single element of an array, аnd [item] — printing out an element.

Loop examples

Let's say the array Items contains string values item1, item2, and item3. The output of the template will look like the table below.

Template

Output

<<foreach [item in items]>>

<<[item]>>

<</foreach>>

item1

item2

item3

Let's display the elements in the form of a numbered list:

Template

Output

1. <<foreach [item in items]>><<[item]>>

<</foreach>>

  1. item1

  2. item2

  3. item3

How loops help to output data

Let's say we have the data model Contracts with a list of contracts. Each contract contains information about the price, client, and manager. Here are descriptions of the fields for the model:

Name

Description

Clients.Name

A client's company name

Price

The quote for a job

Managers.Name

A manager's name

The template for the model will be the following:

Client

Manager

Price

<<foreach [

    c in Contracts

]>><<[c.Clients.Name]>>

<<[c.Managers.Name]>>

<<[c.Price]>><</foreach>>

Total:

<<[Contracts.Sum(c => c.Price)]>>

Possible output:

Client

Manager

Price

A Company

John Smith

1200000

B Ltd.

John Smith

750000

C & D

John Smith

350000

E Corp.

Tony Anderson

650000

F & Partners

Tony Anderson

550000

G & Co.

July James

350000

H Group

July James

250000

I & Sons

July James

100000

J Ent.

July James

100000

Total:

4300000

Let's change a bit of the previous data model, so now we have a list of managers where each one leads a list of contracts, and each contract relates to a client.

Template:

Manager/Client

Price

<<foreach [

    m in Managers

]>><<[m.Name]>>

<<[m.Contracts.Sum(c => c.Price)]>>

<<foreach [

    c in m.Contracts

]>>  <<[c.Clients.Name]>>

<<[c.Price]>><</foreach>><</foreach>>

Total:

<<[Contracts.Sum(c => c.Price)]>>

Output:

Manager/Client

Price

John Smith

2300000

A Company

1200000

B Ltd.

750000

C & D

350000

Tony Anderson

1200000

E Corp.

650000

F & Partners

550000

July James

800000

G & Co.

350000

H Group

250000

I & Sons

100000

J Ent.

100000

Total:

4300000

Let's form the client list for each manager now.

Template:

Manager

Clients

<<foreach [

    m in Managers

]>><<[m.Name]>>

<<foreach [
    c in m.Contracts
]>><<[c.Clients.Name]>>

<</foreach>><</foreach>>

Output:

Manager

Clients

John Smith

A Company
B Ltd.
C & D

Tony Anderson

E Corp.
F & Partners

July James

G & Co.
H Group
I & SonsJ
Ent.

The template with the manager column can be set by using -greedy.

Template:

Managers

<<foreach [m in ds.Managers]>><<[m.Name]>><</foreach -greedy>>

Output:

Managers

John Smith

Tony Anderson

July James

Conditional operators

If you want the outout matchs speciffc conditions, the best way to do it is to use conditional operators.

<<if [conditional_expression1]>>
template_option1
<<elseif [conditional_expression2]>>
template_option2
...
<<else>>
default_template_option
<</if>>

Conditional\_expression is a condition check returning either true or false.

Let's say we have the data model Items with the following strings — item1, item2, and item3.

The template below checks whether the elements of the array ([!items.Any()]) exist. If they do — the template will display the number of elements, otherwise, no items message will pop up.

Template

Output

You have chosen <<if [!items.Any()]>>no items<<else>><<[items.Count()]>> item(s)<</if>>.

You have chosen 3 item(s).

The funcation IndexOf() marks even elements with yellow color:

Template

Output

<<foreach [item in items]>><<if [IndexOf() % 2 == 0]>><<[item]>>
<<else>><<[item]>>
<</if>><</foreach>>

item1
item2
item3

Here we output elements of an array or No data in case no element exists.

<<if [!items.Any()]>>No data.
<<else>><<foreach [item in items]>><<[item]>>
<</foreach>><</if>>

Tables and conditional operators

Using conditional operators, it's possible to display some data or even apply styles to rows of a table depending on conditions. The rows in the table below colored according to a specific conditional expression.

<<if ...>> ...

...

...

...

...

...

<<elseif ...>> ...

...

...

...

...

...

<<else>> ...

...

...

...

...

...

...

...

... <</if>>

To showcase how it works, let's use the model Client with the following fields:

Name

Description

Name

self-explanatory

Country

self-explanatory

LocalAddress

self-explanatory

The template below will output data related to all clients. New Zealand clients are marked with green color, and columns for such clients will be merged and contain only LocalAddress values.

...

...

...

<<foreach [in clients]>><<if [Country == “New Zealand”]>><<[Name]>>

<<[LocalAddress]>>

<<else>><<[Name]>>

<<[Country]>>

<<[LocalAddress]>><><>

...

...

...

Output:

A Company

Australia

219-241 Cleveland StSTRAWBERRY HILLS NSW 1427

B Ltd.

Brazil

Avenida João Jorge, 112, ap. 31

Vila Industrial

Campinas — SP

13035-680

C & D

Canada

101-3485 RUE DE LA MONTAGNE

MONTRÉAL (QUÉBEC) H3G 2A6

E Corp.

445 Mount Eden Road

Mount Eden

Auckland 1024

F & Partners

20 Greens Road

Tuahiwi

Kaiapoi 7691

G & Co.

Greece

Karkisias 6

GR-111 42  ATHINA

GRÉCE

H Group

Hungary

Budapest

Fiktív utca 82., IV. em./28.

2806

I & Sons

43 Vogel Street

Roslyn

Palmerston North 4414

This template displays the No data message if no data is found.

Client

Country

Local Address

<<if [!clients.Any()]>>No data

<<else>><<foreach [in clients]>><<[Name]>>

<<[Country]>>

<<[LocalAddress]>><</foreach>><</if>>

Output:

Client

Country

Local Address

No data

Template:

Template

Output

Header

<<if [false]>>Content to remove<</if>>

Footer

Header

Footer

Here we use -greedy :

Template

Output

Header

<<if [false]>>Content to remove<</if -greedy>>

Footer

Header

Footer

Auxiliary methods for arrays

Smartcat Template Engine also allows working flexibly with arrays applying auxiliary methods.

Let's say we have a data model containing the field persons, that is, the list of employees.

The description of the data model Person :

Name

Name

Age

Subordinates

Salary

This template displays employees' names older than 50 years old:

Template

Output

<<foreach [person in persons.All(p => p.Age > 50)]>>

<<[person.Name]>>

<</foreach>>

Joe Black

Ivan Lock

Jane Wood

Now, let's get a total of employees' salaries:

Template

Output

<<[persons.Sum( p => p.Salary)]>>

490000

In the table below, you may find the description of all available methods with the examples got from two arrays: persons and otherPersons. Both have information about the company's employees.

Method

Template

All(Predicate)

persons.All(p => p.Age < 50)

Any()

persons.Any()

Average(Selector)

persons.Average(p => p.Age)

Concat(IEnumerable)

persons.Concat(otherPersons)

Contains(Object)

persons.Contains(otherPersons.First())

Count()

persons.Count()

Count(Predicate)

persons.Count(p => p.Age > 30)

Distinct()

persons.Distinct()

First()

persons.First()

First(Predicate)

persons.First(p => p.Age > 30)

FirstOrDefault()

persons.FirstOrDefault()

FirstOrDefault(Predicate)

persons.FirstOrDefault(p => p.Age > 30)

GroupBy(Selector)

persons.GroupBy(p => p.Age) 

Or

persons.GroupBy(

    p => new

    {

        Age = p.Age,

        Count = p.Children.Count()

    })

Last()

persons.Last()

Last(Predicate)

persons.Last(p => p.Age > 100)

LastOrDefault()

persons.LastOrDefault()

LastOrDefault(Predicate)

persons.LastOrDefault(p => p.Age > 100)

Max(ComparableSelector)

persons.Max(p => p.Age)

Min(ComparableSelector)

persons.Min(p => p.Age)

OrderBy(ComparableSelector)

persons.OrderBy(p => p.Age)

Or

persons.OrderBy(p => p.Age)

    .ThenByDescending(p => p.Name)

Or

persons.OrderBy(p => p.Age)

    .ThenByDescending(p => p.Name)

    .ThenBy(p => p.Children.Count())

OrderByDescending(ComparableSelector)

persons.OrderByDescending(p => p.Age)

Or

persons.OrderByDescending(p => p.Age)

    .ThenByDescending(p => p.Name)

Or

persons.OrderByDescending(p => p.Age)

    .ThenByDescending(p => p.Name)

    .ThenBy(p => p.Children.Count())

Single()

persons.Single()

Single(Predicate)

persons.Single(

    p => p.Name == "John Smith")

SingleOrDefault()

persons.SingleOrDefault()

SingleOrDefault(Predicate)

persons.SingleOrDefault(

    p => p.Name == "John Smith")

Skip(int)

persons.Skip(10)

SkipWhile(Predicate)

persons.SkipWhile(p => p.Age < 21)

Sum(Selector)

persons.Sum(p => p.Children.Count())

Take(int)

persons.Take(5)

TakeWhile(Predicate)

persons.TakeWhile(p => p.Age < 50)

Union(IEnumerable)

persons.Union(otherPersons)

Where(Predicate)

persons.Where(p => p.Age > 18)

Appendix for developers

Smartcat Template Engine uses the subset of C# syntax ( C# Language Specification 5.0 ) in templates. For all primitive data types, for example, strings, it's possible to employ BCL methods. The methods mentioned in the Auxiliary methods section are taken from LINQ.