ABP Framework provides a simple, yet efficient text template system. Text templating is used to dynamically render contents based on a template and a model (a data object):
TEMPLATE + MODEL => RENDERED CONTENT
It is very similar to an ASP.NET Core Razor View (or Page):
RAZOR VIEW (or PAGE) + MODEL => HTML CONTENT
### Example
Here, a simple template:
````
Hello {{model.name}} :)
````
You can define a class with a `Name` property to render this template:
````csharp
public class HelloModel
{
public string Name { get; set; }
}
````
If you render the template with a `HelloModel` with the `Name` is `John`, the rendered output is will be:
````
Hello John :)
````
Template rendering engine is very powerful;
* It is based on the [Scriban](https://github.com/lunet-io/scriban) library, so it supports **conditional logics**, **loops** and much more.
* Template content **can be localized**.
* You can define **layout templates** to be used as the layout while rendering other templates.
* You can pass arbitrary objects to the template context (beside the model) for advanced scenarios.
Before rendering a template, you should define it. Create a class inheriting from the `TemplateDefinitionProvider` base class:
````csharp
public class DemoTemplateDefinitionProvider : TemplateDefinitionProvider
{
public override void Define(ITemplateDefinitionContext context)
{
context.Add(
new TemplateDefinition("Hello") //template name: "Hello"
.WithVirtualFilePath(
"/Demos/Hello/Hello.tpl", //template content path
isInlineLocalized: true
)
);
}
}
````
*`context` object is used to add new templates or get the templates defined by depended modules. Used `context.Add(...)` to define a new template.
*`TemplateDefinition` is the class represents a template. Each template must have a unique name (that will be used while you are rendering the template).
*`/Demos/Hello/Hello.tpl` is the path of the template file.
*`isInlineLocalized` is used to declare if you are using a single template for all languages (`true`) or different templates for each language (`false`). See the Localization section below for more.
### The Template Content
`WithVirtualFilePath` indicates that we are using the [Virtual File System](Virtual-File-System.md) to store the template content. Create a `Hello.tpl` file inside your project and mark it as "**embedded resource**" on the properties window:
![hello-template](images/hello-template.png)
Example `Hello.tpl` content is shown below:
````
Hello {{model.name}} :)
````
The [Virtual File System](Virtual-File-System.md) requires to add your files in the `ConfigureServices` method of your [module](Module-Development-Basics.md) class:
Template Definition is an object that contains some information about your text templates. Template Definition object contains the following properties.
An inline localized text template is using only one content resource, and it is using the [Abp.Localization](Localization.md) to get content in different languages/cultures.
First of all, create a class that inherited from `TemplateDefinitionProvider` abstract class and create `Define` method that derived from the base class.
`Define` method requires a context that is `ITemplateDefinitionContext`. This `context` is a storage for template definitions and we will add our template definitions to the context.
> **NOTE!** For default, ABP uses **Virtual File System** for text templates. Do not forget to register your files as an `Embedded Resource`. Please check the [Virtual File System Documentation](Virtual-File-System.md) for more details.
> All given examples are for `Virtual File Text Template Definitions`.
As you see in the given example, all Text Templates are added with `(ITemplateDefinitionContext)context.Add` method. This method requires a `TemplateDefinition` object. Then we call `WithVirtualFilePath` method with chaining for the describe where is the virtual files.
`WithVirtualFilePath` is requires one `tpl` file path for the `Inline Localized` Text Templates. If your Text Tempalte is `Multi Localized` you should create a folder and store each different culture files under that. So you can send the folder path as a parameter to `WithVirtualFilePath`.
> Inline Localized File
```
/ Folder / ForgotPasswordEmail.tpl
```
> Multi Content Localization
```
/ Folder / ForgotPasswordEmail / en.tpl
/ Folder / ForgotPasswordEmail / tr.tpl
```
## Rendering
When one template is registered, it is easy to render and get the result with `ITemplateRenderer` service.
`model` is a dynamic object. This is using to put dynamic data into template. For more information, please look at [Scriban Documentation](https://github.com/lunet-io/scriban).
> Example: If you try to render content with _"es-MX"_ it will search your template with _"es-MX"_ culture, when it fails to find, it will try to render _"es"_ culture content. If still can't find it will render the default culture content that you defined.
When you want to get your stored template content you can use `ITemplateContentProvider`.
`ITemplateContentProvider` has one method that named `GetContentOrNullAsync` with two different overriding, and it returns you a string of template content or null. (**without rendering**)
-`templateName` (_string_) or `templateDefinition` (_`TemplateDefinition`_)
-`cultureName` (_string_)
-`tryDefaults` (_bool_)
-`useCurrentCultureIfCultureNameIsNull` (_bool_)
### Usage
First parametres of `GetContentOrNullAsync` (`templateName` or `templateDefinition`) are required, the other three parametres can be null.
If you want to get exact culture content, set `tryDefaults` and `useCurrentCultureIfCultureNameIsNull` as a `false`. Because the `GetContentOrNullAsync` tries to return content of template.
> Example Scenario
> If you have a template content that culture "`es`", when you try to get template content with "`es-MX`" it will try to return first "`es-MX`", if it fails it will return "`es`" content. If you set `tryDefaults` and `useCurrentCultureIfCultureNameIsNull` as `false` it will return `null`.
`Get` and `GetOrNull` requires a string parameter that name of template definition. `Get` will throw error when it is not exist but `GetOrNull` returns `null`.
`ITemplateContentContributor` has a one method that named `GetOrNullAsync`. This method must return content **without rendering** if that is exist in your resource or must return `null`.