Rust模板引擎Tera中文英文對照官方文檔

來嘞早不如來的巧,剛翻譯好,你就來啦!翻譯完成php

要開發CMS(內容管理系統)得有個模板引擎,Tera是使用Rust編寫的模板引擎,語法跟JinJa2很像。css

引入Tera

要使用Tera只須要在 Cargo.toml中添加:html

tera = "1" 1

是否是很簡單_?
默認狀況下, Tera會引入一些依賴好比: truncatedatefilesizeformat slugifyurlencode 和 urlencode_strict ,這些依賴是某些過濾器(後面會講解)要用的. 若是你肯定不須要能夠在 Cargo.toml中這麼配置:git

[dependencies.tera] version = "1" default-features = false 123

若是你用的Rust不是2018版本的(你最好使用),你須要在lib.rs或者main.rs文件中寫上github

And add the following to your lib.rs or main.rs if you are not using Rust 2018:sql

extern crate tera; 1

2018版本就不須要這樣寫了,緣由能夠參考零基礎學新時代編程語言Rust
若是想了解Tera的API能夠看API文檔express

You can view everything Tera exports on the API docs.編程

使用方法

一般咱們使用Tera去解析一個目錄下的所有模板文件,仍是舉個例子更好理解,就好比咱們有下面這樣的一個目錄,用來保存模板文件:json

The primary method of using Tera is to load and parse all the templates in a given glob.api

Let’s take the following directory as example.

templates/   hello.html   index.html   products/     product.html     price.html 123456

假設這個templates文件夾,跟Rust項目的源碼文件夾src在同一個目錄裏,咱們就能夠像下面這樣去實例化Tera:

Assuming the Rust file is at the same level as the templates folder, we can get a Tera instance that way:

use tera::Tera; // 整個項目中就使用這一個tera就能夠了 let tera = match Tera::new("templates/**/*.html") {     Ok(t) => t,     Err(e) => {         println!("Parsing error(s): {}", e);         ::std::process::exit(1);     } }; 12345678910

實例化Tera對象解析編譯模板文件一次也就夠了,不用每次使用都從新建立個Tera實例,咱們可使用lazy_static去建立一個只解析一次模板實例化一次整個項目中都能用的Tera實例(懶漢單例模式)

Compiling templates is a step that is meant to only happen once: use something like lazy_static
to define a constant instance.

lazy_static! {     pub static ref TEMPLATES: Tera = {         let mut tera = match Tera::new("examples/basic/templates/**/*") {             Ok(t) => t,             Err(e) => {                 println!("Parsing error(s): {}", e);                 ::std::process::exit(1);             }         };         tera.autoescape_on(vec!["html", ".sql"]);         tera.register_filter("do_nothing", do_nothing_filter);         tera     }; } 1234567891011121314

使用Tera渲染一個模板文件須要倆個參數:一個是模板的名稱,另外一個是模板上下文對象

You need two things to render a template: a name and a context.

模板名稱能夠直接寫文件的名稱,不須要帶前面的共有路徑templates,好比要使用模板templates/hello.html只須要寫hello.html,固然你得是按照上面的方式實例化的tera

If you are using globs, Tera will automatically remove the glob prefix from the template names. To use our example from before,
the template name for the file located at templates/hello.html will be hello.html.

那咋子建立上下文對象呢?
上下文對象能夠是任何實現了serde_json提供的Serialize特徵的結構體對象也能夠是類型tera::Context的實例化對象。
實例化對象若是不會請右轉參考零基礎學新時代編程語言Rust

The context can either a be data structure that implements the Serialize trait from serde_json or an instance of tera::Context:

use tera::Context; //使用tera提供的Context結構體建立上下文對象 // Using the tera Context struct let mut context = Context::new(); context.insert("product", &product); context.insert("vat_rate", &0.20); tera.render("products/product.html", &context)?; //使用實現了Serialize特徵的結構體建立上下文對象 #[derive(Serialize)] struct Product {     name: String } // or a struct tera.render("products/product.html", &Context::from_serialize(&product)?)?; 1234567891011121314

自動轉義(Auto-escaping)

默認狀況下,Tera會對文件名稱結尾是.html.html.xml的文件中的內容進行轉義處理。若是想了解Tera處理的方式能夠看這裏OWASP.

By default, Tera will auto-escape all content in files ending with ".html"".htm" and ".xml".
Escaping follows the recommendations from OWASP.

若是想本身定義那些文件須要轉義可使用autoescape_on方法

You can override that or completely disable auto-escaping by calling the autoescape_onmethod:

//只轉義文件名結尾是.php.html的文件 // escape only files ending with `.php.html` tera.autoescape_on(vec![".php.html"]); //不轉義任何文件 // disable autoescaping completely tera.autoescape_on(vec![]); 123456

高級一點的用法(Advanced usage)

實例擴展(Extending another instance)

若是你使用的框架或者庫已經使用了tera,它定義了本身模板、過濾器、全局函數或者測試器,咱們能不能直接複用人家定義好的配置呢?
這就要用到extend方法了,使用它能夠用一個先前已經存在的tera實例去擴展咱們新建立的實例。

If you are using a framework or a library using Tera, chances are they provide their own Tera instance with some
built-in templates, filters, global functions or testers. Tera offers a extend method that will extend your own
instance with everything mentioned before:

let mut tera = Tera::new(&tpl_glob).chain_err(|| "Error parsing templates")?; //這裏的ZOLA_TERA是外部庫已經定義好的Tera實例 // ZOLA_TERA is an instance present in a library tera.extend(&ZOLA_TERA)?; 1234

若是在本身定義的Tera實例和擴展用的Tera實例存在同名的模板文件或過濾器什麼的會發生啥子?
若是有同名的會使用本身定義的。

If anything - templates, filters, etc - with the same name exists in both instances, Tera will only keep yours.

自動從新加載解析模板文件(Reloading)

怎麼作到模板文件夾中的文件一旦有變更(修改、新增、移動模板文件),就從新加載解析模板文件呢?
可使用Tera提供的full_reload方法

If you are watching a directory and want to reload templates on change (editing/adding/removing a template), Tera gives
the full_reload method:

tera.full_reload()?; 1

注意啦!
自動從新加載模板文件功能,只在使用全局tera加載模板文件的方式才能用哦!

Note that reloading is only available if you are loading templates with a glob.

直接使用字符串作爲模板(Loading templates from strings)

Tera不但支持前面顯示的把文件做爲模板,還支持把字符串做爲模板,很強很方便有木有?

Tera allows you load templates not only from files but also from plain strings.

//只使用字符串設置一個模板 // one template only let mut tera = Tera::default(); tera.add_raw_template("hello.html", "the body")?; //使用字符串設置多個模板 // many templates let mut tera = Tera::default(); tera.add_raw_templates(vec![     ("grandparent", "{% block hey %}hello{% endblock hey %}"),     ("parent", "{% extends \"grandparent\" %}{% block hey %}Parent{% endblock hey %}"), ])?; ```  若是模板間有集成關係,好比一個模板繼承於另外一個模板,這個時候你須要使用`add_raw_templates`把模板一塊兒加進來,否則Tera因爲找不到被依賴的模板文件就該報錯了。   **Tera:你說你想要吃個茶葉蛋,可只給俺幾片茶葉,你是幾個意思?** >If some templates are related, for example one extending the other, you will need to the `add_raw_templates` method as Tera will error if it find inconsistencies such as extending a template that Tera doesn't know about. ### 臨時渲染個模板(Render a one off template) 有些時候咱們須要臨時渲染個模板,好比用戶提交個模板讓臨時渲染下,這該咋辦呢?咱們先前的模板都是提交加載好的啊,能夠告訴用戶不能這麼玩,也可使用`one_off`函數 >Want to render a single template, for example one coming from a user? The `one_off` function is there for that. ```rs  //one_off函數的最後一個參數是設置是否須要對模板中的內容進行轉義的。 //若是不知道咋設置就直接設置成true,有99%的把握沒錯! // The last parameter is whether we want to autoescape the template or not. // Should be true in 99% of the cases for HTML let context = Context::new(); // add stuff to context let result = Tera::one_off(user_tpl, context, true); 1234567891011121314151617181920212223242526272829303132

模板(Templates)

(介紹一會兒)Introduction

先來點基礎(Tera Basics)

Tera模板就是一些包含變量和表達式的文本文件,這些變量和表達會在渲染的時候根據上下文中的數據替換掉。模板的語法跟Jinja2和Django模板很像。

A Tera template is just a text file where variables and expressions get replaced with values
when it is rendered. The syntax is based on Jinja2 and Django templates.

在模板文件中有三種特殊標記

There are 3 kinds of delimiter and those cannot be changed:

  • 用於表示裏面是表達式的{{}}
  • {{ and }} for expressions
  • {% or {%- and %} or -%} for statements
    用於標示裏面是註釋的 {##}
  • {# and #} for comments

原樣輸出(Raw)

那若是要渲染的內容中恰巧包含上面提到的3種特殊標記咋辦呢?
可使用raw塊輸出, Tera會把raw塊中的內容當成是字符串原樣輸出。

Tera will consider all text inside the raw block as a string and won’t try to
render what’s inside. Useful if you have text that contains Tera delimiters.

{% raw %}   Hello {{ name }} {% endraw %} 123

渲染的結果爲Hello {{name}}

would be rendered as Hello {{ name }}.

控制空白(Whitespace control)

使用Tera提供的{%--%}能夠很方便的分別去除內容左邊和右邊的空白。

Tera comes with easy to use whitespace control: use {%- if you want to remove all whitespace
before a statement and -%} if you want to remove all whitespace after.

仍是來個例子吧,好比有個模板像下面這樣寫的:

For example, let’s look at the following template:

{% set my_var = 2 %} {{ my_var }} 12

//渲染效果像下面這樣:

will have the following output:

 2 12

若是咱們須要去除內容右邊出現的空白行,就能夠像下面這樣寫:

If we want to get rid of the empty line, we can write the following:

{% set my_var = 2 -%} {{ my_var }} 12

註釋(Comments)

模板嘛也是代碼,代碼嘛總要有點註釋才完整嘛。在Tera模板中能夠把註釋寫在{##}之間。

To comment out part of the template, wrap it in {# #}. Anything in between those tags
will not be rendered.

{# A comment #} 1

數據相關(Data structures)

字面量(Literals)

Tera支持如下幾種字面量:

Tera has a few literals that can be used:

  • 布爾字面量:truefalse
  • booleans: true and false
  • 整型字面量(整型不是整形,一個是數字一個是要錢)
  • integers
  • 浮點數字面量
  • floats
  • 字符串字面量,就是包含在""或者''或者backticks中的
  • strings: text delimited by ""'' or backticks
  • 數組:就是把字面量包含在[]中,若是有多個就用逗號分開
  • arrays: a list of literals and/or idents by [ and ] and comma separated (trailing comma allowed)

變量(Variables)

變量是在渲染模板時由上下文提供的,若是你想在模板中定義變量能夠看下這裏

Variables are defined by the context given when rendering a template. If you’d like to define your own variables, see the Assignments section.

咱們能夠像下面這樣渲染變量:
{{name}}

You can render a variable by using the {{ name }}.

若是渲染的變量不存在就會報錯

Trying to access or render a variable that doesn’t exist will result in an error.

若是須要看下模板當前的上下文對象可使用一個神奇的變量:__tera_context

A magical variable is available in every template if you want to print the current context: __tera_context.

符號.(Dot notation):

可使用.訪問某個對象的某個屬性,好比要渲染出product的name屬性能夠這麼寫:
{{product.name}}
也可使用.索引編號的形式訪問數組或元組中的某個元素,索引編號從0開始,也就是數組或元組中的第1個元素的索引編號是0
Construct and attributes can be accessed by using the dot (.) like {{ product.name }}.
Specific members of an array or tuple are accessed by using the .i notation, where i is a zero-based index.

符號[](Square bracket notation):

使用[]能夠替代.用於獲取某個對象的某個屬性,好比上面提到獲取product的name屬性的例子,也能夠這樣寫:
{{product['name']}}
還能夠這樣寫:
`{{product[「name」]}}

A more powerful alternative to (.) is to use square brackets ([ ]).
Variables can be rendering using the notation {{product['name']}} or {{product["name"]}}.

那使用[]有沒有更強大的功能? 
有的,這也是[]存在的理由,否則直接用.不就好了。 
在有些時候咱們並不肯定須要具體訪問對象的那個屬性,也就是對象的屬性名稱是個變量。能夠考慮下使用.該怎麼寫?
使用[]就能夠先定義個變量用於存儲具體的屬性名稱,好比定義個my_field
my_field = "name" 
而後能夠在[]使用這個變量:
{{product[my_field]}}
這跟{{product.name}}實現的功能同樣。
注意:

若是在[]中使用變量,不須要使用'"

If the item is not in quotes it will be treated as a variable.
Assuming you have the following objects in your context product = Product{ name: "Fred" }
and my_field = "name", calling {{product[my_field]}} will resolve to: {{product.name}}.

另外若是是索引值必須是能轉換爲數字的字符串,若是不能轉換爲數字就該報錯了。

Only variables evaluating to String and Number can be used as index: anything else will be
an error.

表達式(Expressions)

在Tera中幾乎任何地方均可以使用表達式

Tera allows expressions almost everywhere.

數字計算表達式(Math)

你可使用Tera作一些基本的數字運行,可是不要亂用,好比像這麼寫+1,除了讓代碼難看了點沒啥用。 
須要注意的是隻能對數字進行數字運行,若是對其它類型的數據進行數字運行會報錯的哦!
Tera支持的數字運算符有:

You can do some basic math in Tera but it shouldn’t be abused other than the occasional + 1or similar.
Math operations are only allowed with numbers, using them on any other kind of values will result in an error.
You can use the following operators:

  • +: 把2個數字加起來,也就是求倆個數字的和,好比: {{ 1 + 1 }} 輸出結果是 2
  • +: adds 2 values together, {{ 1 + 1 }} will print 2
  • -: 求倆個數字的差,好比:{{ 2 - 1 }} 輸出結果是1
  • -: performs a substraction, {{ 2 - 1 }} will print 1
  • /: 用於執行除法運算,好比{{ 10 / 2 }} 輸出結果是 5
  • /: performs a division, {{ 10 / 2 }} will print 5
  • *:用於執行乘法運算, 好比{{ 5 * 2 }} 輸出結果是 10
  • *: performs a multiplication, {{ 5 * 2 }} will print 10
  • %: 用於執行取餘(取模)運行,好比{{ 2 % 2 }} 輸出結果是0
  • %: performs a modulo, {{ 2 % 2 }} will print 0
    運算符的執行優先級(從低到高):

The priority of operations is the following, from lowest to highest:

  • + 和 -
  • + and -
  • * 和 / 和 %
  • * and / and %

就是咱們讀小學背的先乘除後加減

比較運算符(Comparisons)

  • ==: 用於判斷倆個數據是否是相等的
  • !=: 用於判斷倆個數據是否是不相等的
  • >=: 大於等於判斷操做符
  • <=: 小於等於判斷操做符
  • >: 大於判斷操做符
  • <: 小於判斷操做符

邏輯運算操做符

  • and: 與操做符 只有兩邊都爲true時結果才爲true
  • or: 或操做符 只要倆邊有任意一個爲true結果就爲true
  • not: 非操做符 取反操做

字符串鏈接操做符

可使用~把多個字符串或標示符鏈接在一塊兒

You can concatenate several strings/idents using the ~ operator.

{{ "hello " ~ 'world' ~ `!` }} {{ an_ident ~ " and a string" ~ another_ident }} {{ an_ident ~ another_ident }} 12345

注意
若是標示符對應的值不是字符串就會報錯哦!

An ident resolving to something other than a string will raise an error.

是否包含判斷(in checking)

可使用in判斷右邊是否包含左邊

You can check whether a left side is contained in a right side using the in operator.

{{ some_var in [1, 2, 3] }} {{ 'index' in page.path }} {{ an_ident not in  an_obj }} 12345

注意
in的右邊只能是包含字面量、變量的數組或者是字符串或者對象,若是是其它類型就該報錯了哦!

Only literals/variables resulting in an array, a string and an object are supported in the right hand side: everything else
will raise an error.

數據處理(Manipulating data)

賦值(Assignments)

能夠在渲染的時候把一個值賦值給一個變量
在for循環和宏中的賦值只在其中有效,在其它地方的賦值全局有效

You can assign values to variables during the rendering.
Assignments in for loops and macros are scoped to their context but
assignments outside of those will be set in the global context.

{% set my_var = "hello" %} {% set my_var = 1 + 4 %} {% set my_var = some_var %} {% set my_var = macros::some_macro() %} {% set my_var = global_fn() %} {% set my_var = [1, true, some_var | round] %} 123456

若是須要在for循環中進行全局有效的賦值,可使用set_global

If you want to assign a value in the global context while in a for loop, you can use set_global:

{% set_global my_var = "hello" %} {% set_global my_var = 1 + 4 %} {% set_global my_var = some_var %} {% set_global my_var = macros::some_macro() %} {% set_global my_var = global_fn() %} {% set_global my_var = [1, true, some_var | round] %} 123456

在for循環外部使用set_global效果跟set同樣

Outside of a for loop, set_global is exactly the same as set.

過濾器(Filters)

可使用過濾器修改變量
在變量名稱後面添加一個|,再後面就能夠跟上過濾器名稱和參數(若是有)來使用過濾器了。
能夠一次使用多個過濾器,前面過濾器的輸出是後面過濾器的輸入.

You can modify variables using filters.
Filters are separated from the variable by a pipe symbol (|) and may have named arguments in parentheses.
Multiple filters can be chained: the output of one filter is applied to the next.

有沒有暈?接觸過AngularJS沒?仍是舉個例子吧:
{{ name | lower | replace(from="doctor", to="Dr.") }}  
把名稱全小寫,而後再把包含的"doctor"替換爲"Dr.";
若是name是"doctor ZhanSan" 那輸出的結果就是:Dr. zhansan
若是你不習慣又不能接受這種書寫風格,也能夠像下面這樣寫: 
replace(lower(name), from="doctor", to="Dr.") 
看着就跟函數調用似的.

For example, {{ name | lower | replace(from="doctor", to="Dr.") }} will take a variable called name, make it lowercase and then replace instances of doctor by Dr..
It is equivalent to replace(lower(name), from="doctor", to="Dr.") if we were to look at it as functions.

注意 
使用過濾器時要確保數據類型是符合當前過濾器須要的,若是不符合就會報錯哦!
好比在數組類型的數據上使用首字母大小過濾器,就會報錯!

Calling filters on a incorrect type like trying to capitalize an array or using invalid types for arguments will result in a error.

怎麼自定義過濾器呢?
能夠定義類型爲fn(Value, HashMap<String, Value>) -> Result<Value>的函數,再調用Tera實例的rigister_filter方法註冊下,就能夠在模板中
使用自定義的過濾器了

Filters are functions with the fn(Value, HashMap<String, Value>) -> Result<Value> definition and custom ones can be added like so:

tera.register_filter("upper", string::upper); 1

過濾器也能夠跟數字計算一塊兒使用,不過須要注意它的優先級比較低
舉個例子:

While filters can be used in math operations, they will have the lowest priority and therefore might not do what you expect:

{{ 1 + a | length }} // 上面這段代碼跟下面這段代碼等價 {{ (1 + a) | length }  // 若是你是想先對a進行過濾器處理,再對處理後的結果加1,你能夠像下面這樣寫 {{ a | length + 1 }} 123456

Tera內置了一些過濾器,若是你想了解下能夠看內置過濾器

Tera has many built-in filters that you can use.

過濾區域(Filter sections)

包含在 {% filter name %} 和 {% endfilter %}中的內容都會被對應過濾器處理,其中name就是過濾器名稱

Whole sections can also be processed by filters if they are encapsulated in {% filter name %}and {% endfilter %}
tags where name is the name of the filter:

{% filter upper %}     Hello {% endfilter %} 123

示例代碼是把Hello處理爲HELLO也就是把包含的全部字母大寫

This example transforms the text Hello in all upper-case (HELLO).

過濾器區域中還能夠包含 塊區域 就像這樣:

Filter sections can also contain block sections like this:

{% filter upper %}   {% block content_to_be_upper_cased %}     This will be upper-cased   {% endblock content_to_be_upper_cased %}  {% endfilter %} 12345

條件判斷(Tests)

可使用ifis判斷一個表達式是否符合某種條件,好比下面的代碼中判斷一個表達式的值是不是偶數:

Tests can be used against an expression to check some condition on it and
are made in if blocks using the is keyword.
For example, you would write the following to test if an expression is odd:

{% if my_number is odd %}  Odd {% endif %} 123

也可使用方向判斷,下面代碼中判斷一個表達式是不是奇數

Tests can also be negated:

{% if my_number is not odd %}  Even {% endif %} 123

怎麼自定義條件判斷呢?
能夠編寫一個fn(Option<Value>, Vec<Value>) -> Result<bool>類型的函數,而後調用Tera實例的register_tester方法註冊一會兒,就能夠在模板中使用了.

Tests are functions with the fn(Option<Value>, Vec<Value>) -> Result<bool> definition and custom ones can be added like so:

tera.register_tester("odd", testers::odd); 1

Tera也提供了些內置的條件判斷,若是你想了解下能夠看這裏 內置的條件判斷
Tera has many built-in tests that you can use.

函數(Functions)

可使用Rust定義返回值類型爲Result<Value> 函數定義能夠在模板中使用的函數.

Functions are Rust code that return a Result<Value> from the given params.

一般狀況下,函數都是須要額外參數的,好比全局函數url_for就須要個包含了url的列表做爲參數.

Quite often, functions will need to capture some external variables, such as a url_for global function needing
the list of URLs for example.

能夠定義個Box<Fn(HashMap<String, Value>) -> Result<Value> + Sync + Send>類型也就是GlobalFn類型的函數做爲全局函數.好比:

To make that work, the type of GlobalFn is a boxed closure: Box<Fn(HashMap<String, Value>) -> Result<Value> + Sync + Send>.

Here’s an example on how to implement a very basic function:

fn make_url_for(urls: BTreeMap<String, String>) -> GlobalFn {     Box::new(move |args| -> Result<Value> {         match args.get("name") {             Some(val) => match from_value::<String>(val.clone()) {                 Ok(v) =>  Ok(to_value(urls.get(&v).unwrap()).unwrap()),                 Err(_) => Err("oops".into()),             },             None => Err("oops".into()),         }     }) } 1234567891011

別忘了,還須要調用Tera實例的register_function方法註冊一會兒:

You then need to add it to Tera:

tera.register_function("url_for", make_url_for(urls)); 1

而後你就能夠在模板中使用這個函數了

And you can now call it from a template:

{{/* url_for(name="home") */}} 1

當前在模板中的倆個地方能夠調用函數:

Currently functions can be called in two places in templates:

  • 代碼塊: {{/* url_for(name="home") */}}
  • for循環: {% for i in range(end=5) %}

Tera也內置了些函數,有興趣能夠看這裏內置函數.
Tera comes with some built-in functions.

結構控制(Control structures)

If

在Tera模板中能夠像在Python中同樣使用If

Conditionals are fully supported and are identical to the ones in Python.

{% if price < 10 or always_show %}    Price is {{ price }}. {% elif price > 1000 and not rich %}    That's expensive! {% else %}     N/A {% endif %} 1234567

一樣的若是變量不存在就會報錯,你能夠像下面這樣判斷一個變量是否存在

Undefined variables are considered falsy. This means that you can test for the
presence of a variable in the current context by writing:

{% if my_var %}     {{ my_var }} {% else %}     Sorry, my_var isn't defined. {% endif %} 12345

還要記得每一個if語句都須要一個endif作爲結尾

Every if statement has to end with an endif tag.

For

循環遍歷數組中的元素:

Loop over items in a array:

{% for product in products %}   {{loop.index}}. {{product.name}} {% endfor %} 123

在循環中有一些特殊的變量可使用:

A few special variables are available inside for loops:

  • loop.index: 當前遍歷元素的索引值,從1開始計數
  • loop.index0: 當前變量元素的索引值,從0開始計數
  • loop.first: 當前元素是不是第一個元素
  • loop.last: 當前元素是不是最後一個元素

別忘了每一個for語句後面要有個endfor做爲結尾

Every for statement has to end with an endfor tag.

也可使用for循環變量map和struct類型的數據,例如:

You can also loop on maps and structs using the following syntax:

{% for key, value in products %}   {{loop.index}}. {{product.name}} {% endfor %} 123

keyvalue並非必需要這麼命名的,只要你開心,你能夠命名爲阿貓阿狗均可以,固然也須要顧及下看代碼人的感覺;

key and value can be named however you want, they just need to be separated with a comma.

在遍歷數組中的每一個元素的時候你還可使用過濾器對元素進行處理:

If you are iterating on an array, you can also apply filters to the container:

{% for product in products | reverse %}   {{loop.index}}. {{product.name}} {% endfor %} 123

固然你也能夠遍歷字面量形式的數組:

You can also iterate on array literals:

{% for a in [1,2,3,] %}   {{a}} {% endfor %} 123

另外,當遍歷的集合是空的時候,你也能夠另外設置要渲染的內容,就像下面這樣:

Lastly, you can set a default body to be rendered when the container is empty:

{% for product in products %}   {{loop.index}}. {{product.name}} {% else %}   No products.   {% endfor %} 12345

循環控制(Loop Controls)

在循環中可使用breakcontinue控制循環的執行.好比可使用break在找到了id爲target_id後就中止循環

Within a loop, break and continue may be used to control iteration.

To stop iterating when target_id is reached:

{% for product in products %}   {% if product.id == target_id %}{% break %}{% endif %}   {{loop.index}}. {{product.name}} {% endfor %} 1234

好比跳過奇數行:

To skip even-numbered items:

{% for product in products %}   {% if loop.index is even %}{% continue %}{% endif %}   {{loop.index}}. {{product.name}} {% endfor %} 1234

引入(Include)

可使用include引入另外一個模板文件.

You can include a template to be rendered using the current context with the include tag.

{% include "included.html" %} 1

使用include引入的模板跟當前模板使用同一個上下文渲染,若是你想爲引入的模板定義上下文可使用macros(宏) ,Rust也是支持宏的能夠參考零基礎學新時代編程語言Rust

Tera doesn’t offer passing a custom context to the include tag.
If you want to do that, use macros.

在被引入的模板中使用set賦值的變量在引入模板中是不能用的。

While you can set values in included templates, those values only exist while rendering
them: the template calling include doesn’t see them.

宏(Macros)

能夠把宏當成是函數或是組件,經過調用返回某些文本.

Think of macros as functions or components that you can call and return some text.

宏須要定義在一個單獨的文件中,在用的時候須要引入

Macros currently need to be defined in a separate file and imported to be useable.

好比能夠像下面這樣定義宏:

They are defined as follows:

{% macro input(label, type="text") %}     <label>         {{ label }}         <input type="{{type}}" />     </label> {% endmacro input %} 123456

像上面代碼演示的,宏的參數能夠設置字面量默認值。
As shown in the example above, macro arguments can have a default literal value.

在使用宏的時候把包含宏的文件導入就能夠了,就像下面這樣:

In order to use them, you need to import the file containing the macros:

{% import "macros.html" as macros %} 1

在導入的時候還能夠起個命名空間。

You can name that file namespace (macros in the example) anything you want.
A macro is called like this:

能夠像下面這樣使用宏:

// namespace::macro_name(**kwargs) {{ macros::input(label="Name", type="text") }} 12

注意 
調用宏時也須要正確類型的參數。
Do note that macros, like filters, require keyword arguments.

若是要調用當前文件中定義的宏可使用self命名空間.
須要注意self命名空間只能在宏中使用

If you are trying to call a macro defined in the same file or itself, you will need to use the selfnamespace.
The self namespace can only be used in macros.

能夠遞歸調用宏,因此在寫代碼時必定要適時的結束宏調用

Macros can be called recursively but there is no limit to recursion so make sure your macro ends.

這裏有個遞歸調用宏的例子:

Here’s an example of a recursive macro:

{% macro factorial(n) %}   {% if n > 1 %}{{ n }} - {{ self::factorial(n=n-1) }}{% else %}1{% endif %} {% endmacro factorial %} 123

在宏體內可使用經常使用的Tera語法除了宏定義、blockextends
Macros body can contain all normal Tera syntax with the exception of macros definition, block and extends.

集成(Inheritance)

Tera也支持相似Jinja2和Django模板的集成功能: 
也就是定義一個基模板而後其它模板能夠繼承擴展基模板。

Tera uses the same kind of inheritance as Jinja2 and Django templates:
you define a base template and extends it in child templates through blocks.

繼承支持多級繼承,好比A繼承B,B再集成C

There can be multiple levels of inheritance (i.e. A extends B that extends C).

基(父)模板(Base template)

基模板是包含基礎文檔結構的模板,一般是有幾個blocks組成

A base template typically contains the basic document structure as well as
several blocks that can have content.

好比:下面的base.html就是幾乎從Jinja2文檔中複製過來的。

For example, here’s a base.html almost copied from the Jinja2 documentation:

<!DOCTYPE html> <html> <head>     {% block head %}     <link rel="stylesheet" href="style.css" />     <title>{% block title %}{% endblock title %} - My Webpage</title>     {% endblock head %} </head> <body>     <div id="content">{% block content %}{% endblock content %}</div>     <div id="footer">         {% block footer %}         &copy; Copyright 2008 by <a href="http://domain.invalid/">you</a>.         {% endblock footer %}     </div> </body> </html> 1234567891011121314151617

跟Jinja2不同的是,在endblock中須要提供一個名稱。

The only difference with Jinja2 being that the endblock tags have to be named.

這個base.html模板定義了4個block,子模板能夠根據本身的使用須要覆蓋block。
其中headfooter塊在基模板中已經定義的內容,也能夠在子模板中從新定義.

This base.html template defines 4 block tag that child templates can override.
The head and footer block have some content already which will be rendered if they are not overridden.

子模板(Child template)

一樣的,子模板跟Jinja2裏用法也差很少:
Again, straight from Jinja2 docs:

{% extends "base.html" %} {% block title %}Index{% endblock title %} {% block head %}     {{/* super() */}}     <style type="text/css">         .important { color: #336699; }     </style> {% endblock head %} {% block content %}     <h1>Index</h1>     <p>       Welcome to my awesome homepage.     </p> {% endblock content %} 1234567891011121314

爲了實現繼承須要在模板文件的最上面使用extends標籤聲明要繼承的模板.
能夠在子模板中使用 {{/* super() */}}告訴Tera咱們想在這個地方渲染基模板的塊(block)
To indicate inheritance, you have use the extends tag as the first thing in the file followed by the name of the template you want
to extend.
The {{/* super() */}} variable call tells Tera to render the parent block there. 
在Tera中塊也是能夠嵌套使用的,像下面這樣:
Nested blocks also work in Tera. Consider the following templates:

// grandparent {% block hey %}hello{% endblock hey %} // parent {% extends "grandparent" %} {% block hey %}hi and grandma says {{/* super() */}} {% block ending %}sincerely{% endblock ending %}{% endblock hey %} // child {% extends "parent" %} {% block hey %}dad says {{/* super() */}}{% endblock hey %} {% block ending %}{{/* super() */}} with love{% endblock ending %} ```  塊`ending`嵌套在塊`hey`中。Tera在渲染模板`child`的過程是這個樣子地: The block `ending` is nested in the `hey` block. Rendering the `child` template will do the following: - 查找基模板: `grandparent` - 查看塊 `hey` 是否包含在模板`child` 和`parent` 中 - 在模板`child` 中找到了塊`hey`就渲染它, 在塊`hey`中調用了`super()`因此咱們須要渲染模板`parent`的塊 `hey` ,模板`parent`的塊 `hey`也調用了`super()`,因此咱們還須要渲染模板 `grandparent`的塊`hey` - 接下來在模板`child`中查找塊 `ending` 並渲染它,它裏面也調用了 `super()`因此還須要渲染模板`parent`的塊`ending`  最後執行結果(不包括空內容)就是:"dad says hi and grandma says hello sincerely with love". >The end result of that rendering (not counting whitespace) will be: "dad says hi and grandma says hello sincerely with love". ## 內置的那些事(Built-ins) ### 內置的過濾器(Built-in filters) Tera內置瞭如下過濾器: >Tera has the following filters built-in: #### lower 把字符串中的全部字符進行小寫 >Lowercase a string #### wordcount 計算字符串中的詞個數 >Returns number of words in a string #### capitalize  字符串的首字母大寫 >Returns the string with all its character lowercased apart from the first char which is uppercased. #### replace 字符串替換過濾器,過濾器有倆個參數`from`和`to`,也就是把字符串包含的from字符串替換爲to字符串。 >Takes 2 mandatory string named arguments: `from` and `to`. It will return a string with all instances of the `from` string with the `to` string. 好比: `{{ name | replace(from="Robert", to="Bob")}}` 若是name的值是"Hello Robert"結果就是"Hello Bob" #### addslashes 在引號前添加斜槓 >Adds slashes before quotes. 好比: `{{ value | addslashes }}` 若是value的值是 "I'm using Tera"那結果就是: "I\\'m using Tera". #### slugify 要使用這個過濾器須要啓用`builtins` feature >Only available if the `builtins` feature is enabled. 這個過濾器的效果是把字符串轉換爲ASCII碼而後再把全部字符小寫、去掉首未的空白字符、再把包含的空字符替換爲'-'  而後去除全部不是小寫字母又不是數字又不是`-`的字符; >Transform a string into ASCII, lowercase it, trim it, converts spaces to hyphens and >remove all characters that are not numbers, lowercase letters or hyphens. 好比: `{{ value | slugify }}` 若是value的值是 "-Hello world! "執行的結果就是:"hello-world". #### title  把字符串中包含的每一個詞的第一個字母轉換爲大寫的形式 >Capitalizes each word inside a sentence. 好比: `{{ value | title }}` 若是value的值是 "foo  bar", 執行結果就是"Foo  Bar". #### trim 移除字符串前面和後面的空白字符 >Remove leading and trailing whitespace if the variable is a string. #### trim_start 只移除字符串前面的空白字符 >Remove leading whitespace if the variable is a string. #### trim_end 只移除字符串後面的空白字符 >Remove trailing whitespace if the variable is a string. #### trim_start_matches 若是字符串的前面部分知足給定的模式就移除掉 >Remove leading characters that match the given pattern if the variable is a string. 好比: `{{ value | trim_start_matches(pat="//") }}` 若是value的值是"//a/b/c//"執行的結果就是"a/b/c//". #### trim_end_matches 若是字符串的後面部分知足給定模式就移除掉 >Remove trailing characters that match the given pattern if the variable is a string. 好比: `{{ value | trim_end_matches(pat="//") }}` 若是value的值是"//a/b/c//"執行結果就是"//a/b/c". #### truncate 要使用這個過濾器,須要啓用`builtins`feature >Only available if the `builtins` feature is enabled. 按照給定的長度截取字符串,若是字符串的長度還不到給定的長度就原樣返回. >Truncates a string to the indicated length. If the string has a smaller length than the `length` argument, the string is returned as is. 好比: `{{ value | truncate(length=10) }}` 默認狀況下被截取的字符串後面會添加'...',若是不想添加能夠指定end參數爲空字符串.  >By default, the filter will add an ellipsis at the end if the text was truncated. You can change the string appended by setting the `end` argument. 好比:`{{ value | truncate(length=10, end="") }}` 輸出的字符串後面就沒有'...'了  #### striptags 去掉字符中包含的HTML標籤。若是提供的字符串不是有效的HTML格式,不保證輸出的結果是正常顯示的。 Tries to remove HTML tags from input. Does not guarantee well formed output if input is not valid HTML. 好比: `{{ value | striptags}}` 若是value的值是 "&lt;b&gt;Joel&lt;/b&gt;"執行的結果就是: "Joel". *注意*  若是模板自己已經被自動轉義過了,你須要先調用`safe`過濾器,因此最好先調用safe過濾器再調用striptags過濾器. Note that if the template you using it in is automatically escaped, you will need to call the `safe` filter before `striptags`. #### first 返回數組中的第一個元素. 若是數組是空的就返回一個空字符串 >Returns the first element of an array. >If the array is empty, returns empty string. #### last 返回數組中的最後一個元素. 若是數組是空的就返回空字符串. >Returns the last element of an array. >If the array is empty, returns empty string. #### nth 返回數組中的第n個元素. 若是數組是空的就返回空字符串. 這個過濾器須要個參數n,用於指定元素索引值(從零開始計數) >Returns the nth element of an array.§ >If the array is empty, returns empty string. >It takes a required `n` argument, corresponding to the 0-based index you want to get. 例如: `{{ value | nth(n=2) }}` 是返回value中的第3個元素 #### join  使用一個字符串把數組中的元素連起來. Joins an array with a string. 例如: `{{ value | join(sep=" // ") }}` 若是value的值爲`['a', 'b', 'c']`執行結果就是: "a // b // c". #### length 返回一個數組或者對象或者字符串的長度. Returns the length of an array, an object, or a string. #### reverse 返回一個數組的倒排結果. Returns a reversed string or array. #### sort  對數組中的元素從小到大排序。 >Sorts an array into ascending order. **注意**  數組中的元素必須是可排序的: The values in the array must be a sortable type:  - 數字按照數字大小排序. - 字符串按照字母順序排序 - 數組按照長度排序. - 布爾值false在前true在後 若是要對結構體或者元組進行排序,能夠指定按那個屬性排序. >If you need to sort a list of structs or tuples, use the `attribute` argument to specify which field to sort by. 好比: 好比`people`是包含People的數組 ```rust struct Name(String, String); struct Person {     name: Name,     age: u32, } 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194

能夠經過指定參數attribute 使用last name進行排序:
The attribute argument can be used to sort by last name:

{{ people | sort(attribute="name.1") }} 1

也能夠指定按年齡排序:

{{ people | sort(attribute="age") }} 1

unique

刪除數組中的重複元素。可使用attribute參數指定用於去重的屬性.對於字符串還可使用case_sensitive指定是否區分大小寫,默認不區分大小寫.
Removes duplicate items from an array. The attribute argument can be used to select items based on the values of an inner attribute. For strings, the case_sensitive argument (default is false) can be used to control the comparison.

例如:
好比people是一個包含Person的數組

Given people is an array of Person

struct Name(String, String); struct Person {     name: Name,     age: u32, } 123456

可使用參數 attribute 按年齡對Person去重。
The attribute argument can be used to select one Person for each age:

{{ people | unique(attribute="age") }} 1

或者對last name去重

{{ people | unique(attribute="name.1", case_sensitive="true") }} 1

slice

Slice an array by the given start and end parameter. Both parameters are
optional and omitting them will return the same array.
Use the start argument to define where to start (inclusive, default to 0)
and end argument to define where to stop (exclusive, default to the length of the array).
start and end are 0-indexed.

{% for i in my_arr | slice(end=5) %} {% for i in my_arr | slice(start=1) %} {% for i in my_arr | slice(start=1, end=5) %} 123

group_by

Group an array using the required attribute argument. The filter takes an array and return
a map where the keys are the values of the attribute stringified and the values are all elements of
the initial array having that attribute. Values with missing attribute or where attribute is null
will be discarded.

Example:

Given posts is an array of Post

struct Author {     name: String, }; struct Post {     content: String,     year: u32,     author: Author, } 123456789

The attribute argument can be used to group posts by year:

{{ posts | group_by(attribute="year") }} 1

or by author name:

{{ posts | group_by(attribute="author.name") }} 1

filter

Filter the array values, returning only the values where the attribute is equal to the value.
Values with missing attribute or where attribute is null will be discarded.

attribute is mandatory.

Example:

Given posts is an array of Post

struct Author {     name: String, }; struct Post {     content: String,     year: u32,     author: Author,     draft: bool, } 12345678910

The attribute argument can be used to filter posts by draft value:

{{ posts | filter(attribute="draft", value=true) }} 1

or by author name:

{{ posts | filter(attribute="author.name", value="Vincent") }} 1

If value is not passed, it will drop any elements where the attribute is null.

map

Retrieves an attribute from each object in an array. The attribute argument is mandatory and specifies what to extract.

Example:

Given people is an array of Person

struct Name(String, String); struct Person {     name: Name,     age: u32, } 123456

The attribute argument is used to retrieve their ages.

{{ people | map(attribute="age") }} 1

concat

Appends values to an array.

{{ posts | concat(with=drafts) }} 1

The filter takes an array and returns a new array with the value(s) from the with parameter
added. If the with parameter is an array, all of its values will be appended one by one to the new array and
not as an array.

This filter can also be used to append a single value to an array if the value passed to with is not an array:

{% set pages_id = pages_id | concat(with=id) %} 1

The with attribute is mandatory.

urlencode

Only available if the builtins feature is enabled.

Percent-encodes all the characters in a string which are not included in
unreserved chars(according to RFC3986) with the exception of forward
slash(/).

Example: {{ value | urlencode }}

If value is /foo?a=b&c=d, the output will be /foo%3Fa%3Db%26c%3Dd/ is not escaped.

urlencode_strict

Only available if the builtins feature is enabled.

Similar to urlencode filter but encodes all non-alphanumeric characters in a string including forward slashes (/).

Example: {{ value | urlencode_strict }}

If value is /foo?a=b&c=d, the output will be %2Ffoo%3Fa%3Db%26c%3Dd/ is
also encoded.

pluralize

Returns a plural suffix if the value is not equal to ±1, or a singular suffix otherwise. The plural suffix defaults to s and the
singular suffix defaults to the empty string (i.e nothing).

Example: You have {{ num_messages }} message{{ num_messages | pluralize }}

If num_messages is 1, the output will be You have 1 message. If num_messages is 2 the output will be You have 2 messages. You can
also customize the singular and plural suffixes with the singular and plural arguments to the filter:

Example: {{ num_categories }} categor{{ num_categories | pluralize(singular="y", plural="ies") }}

round

Returns a number rounded following the method given. Default method is common which will round to the nearest integer.
ceil and floor are available as alternative methods.
Another optional argument, precision, is available to select the precision of the rounding. It defaults to 0, which will
round to the nearest integer for the given method.

Example: {{ num | round }} {{ num | round(method="ceil", precision=2) }}

filesizeformat

Only available if the builtins feature is enabled.

Returns a human-readable file size (i.e. ‘110 MB’) from an integer.

Example: {{ num | filesizeformat }}

date

Only available if the builtins feature is enabled.

Parse a timestamp into a date(time) string. Defaults to YYYY-MM-DD format.
Time formatting syntax is inspired from strftime and a full reference is available
on chrono docs.

Example: {{ ts | date }} {{ ts | date(format="%Y-%m-%d %H:%M") }}

If you are using ISO 8601 date strings you can optionally supply a timezone for the date to be rendered in.

Example:

{{ "2019-09-19T13:18:48.731Z" | date(timezone="America/New_York") }} {{ "2019-09-19T13:18:48.731Z" | date(format="%Y-%m-%d %H:%M", timezone="Asia/Shanghai") }} 123

escape

Escapes a string’s HTML. Specifically, it makes these replacements:

  • & is converted to &amp;
  • < is converted to &lt;
  • > is converted to &gt;
  • " (double quote) is converted to &quot;
  • ' (single quote) is converted to &#x27;
  • / is converted to &#x2F;

escape_xml

Escapes XML special characters. Specifically, it makes these replacements:

  • & is converted to &amp;
  • < is converted to &lt;
  • > is converted to &gt;
  • " (double quote) is converted to &quot;
  • ' (single quote) is converted to &apos;

safe

Mark a variable as safe: HTML will not be escaped anymore.
safe only works if it is the last filter of the expression:

  • {{ content | replace(from="Robert", to="Bob") | safe }} will not be escaped
  • {{ content | safe | replace(from="Robert", to="Bob") }} will be escaped

get

Access a value from an object when the key is not a Tera identifier.
Example: {{ sections | get(key="posts/content") }}

split

Split a string into an array of strings, separated by a pattern given.
Example: {{ path | split(pat="/") }}

int

Converts a value into an integer. The default argument can be used to specify the value to return on error, and the base argument can be used to specify how to interpret the number. Bases of 2, 8, and 16 understand the prefix 0b, 0o, 0x, respectively.

float

Converts a value into a float. The default argument can be used to specify the value to return on error.

json_encode

Transforms any value into a JSON representation. This filter is better used together with safe or when automatic escape is disabled.

Example: {{ value | json_encode() | safe }}

It accepts a parameter pretty (boolean) to print a formatted JSON instead of a one-liner.

Example: {{ value | json_encode(pretty=true) | safe }}

as_str

Returns a string representation of the given value.

Example: {{ value | as_str }}

default

Returns the default value given only if the variable evaluated is not present in the context
and is therefore meant to be at the beginning of a filter chain if there are several filters.

Example: {{ value | default(value=1) }}

This is in most cases a shortcut for:

{% if value %}{{ value }}{% else %}1{% endif %} 1

However, only the existence of the value in the context is checked. With a value that if would
evaluate to false (such as an empty string, or the number 0), the default filter will not attempt
replace it with the alternate value provided. For example, the following will produce
「I would like to read more !」:

I would like to read more {{ "" | default (value="Louise Michel") }}! 1

If you intend to use the default filter to deal with optional values, you should make sure those values
aren’t set! Otherwise, use a full if block. This is especially relevant for dealing with optional arguments
passed to a macro.

Built-in tests

Here are the currently built-in tests:

defined

Returns true if the given variable is defined.

undefined

Returns true if the given variable is undefined.

odd

Returns true if the given variable is an odd number.

even

Returns true if the given variable is an even number.

string

Returns true if the given variable is a string.

number

Returns true if the given variable is a number.

divisibleby

Returns true if the given expression is divisible by the arg given.

Example:

{% if rating is divisibleby(2) %}     Divisible {% endif %} 123

iterable

判斷變量是否能夠進行遍歷(迭代)
Returns true if the given variable can be iterated over in Tera (ie is an array/tuple or an object).

object

判斷一個變量是不是對象
Returns true if the given variable is an object (ie can be iterated over key, value).

starting_with

Returns true if the given variable is a string starts with the arg given.

Example:

{% if path is starting_with("x/") %}     In section x {% endif %} 123

ending_with

Returns true if the given variable is a string ends with the arg given.

containing

Returns true if the given variable contains the arg given.

The test works on:

  • strings: is the arg a substring?
  • arrays: is the arg given one of the member of the array?
  • maps: is the arg given a key of the map?

Example:

{% if username is containing("xXx") %}     Bad {% endif %} 123

matching

Returns true if the given variable is a string and matches the regex in the argument.

Example:

{% if name is matching("^[Qq]ueen") %}     Her Royal Highness, {{ name }} {% elif name is matching("^[Kk]ing") %}     His Royal Highness, {{ name }} {% else %}     {{ name }} {% endif %} 1234567

A comprehensive syntax description can be found in the regex crate documentation.

Built-in functions

Tera comes with some built-in global functions.

range

Returns an array of integers created using the arguments given.
There are 3 arguments, all integers:

  • end: where to stop, mandatory
  • start: where to start from, defaults to 0
  • step_by: with what number do we increment, defaults to 1

now

Only available if the builtins feature is enabled.

Returns the local datetime as string or the timestamp as integer if requested.

There are 2 arguments, both booleans:

  • timestamp: whether to return the timestamp instead of the datetime
  • utc: whether to return the UTC datetime instead of the local one

Formatting is not built-in the global function but you can use the date filter like so now() | date(format="%Y") if you
wanted to get the current year.

throw

The template rendering will error with the given message when encountered.

There is only one string argument:

  • message: the message to display as the error

get_random

Only available if the builtins feature is enabled.

Returns a random integer in the given range. There are 2 arguments, both integers:

  • start: defaults to 0 if not present
  • end: required

start is inclusive (i.e. can be returned) and end is exclusive.

get_env

獲取特定名稱的環境變量的值。若是獲取的環境變量不存在,就會報錯,不過也能夠設置一個默認值.

Returns the environment variable value for the name given. It will error if the environment variable is not found
but the call can also take a default value instead.

  • name: 用於指定環境變量名稱,必須提供
  • default: 用於設置默認值

若是環境變量存在就會返回一個字符串類型的值,默認值能夠是任何類型。

If the environment variable is found, it will always be a string while your default could be of any type.

相關文章
相關標籤/搜索