Use the Smartcat template engine
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>> |
|
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 [ |
Output:
Manager | Clients |
John Smith | A Company |
Tony Anderson | E Corp. |
July James | G & Co. |
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]>> | item1 |
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.