2. Statements

Capek supports a number of standard statements:

  • if and switch statements to generate text based on conditions,

  • for loops,

  • choice to support alternative wordings,

  • for_choice to support a sequence of alternatives,

  • set and capture to set variables to a certain value,

  • macro to define reusable templates.

2.1. Common properties

Statements are of two types:

  • a simple statement: {% ... %}; for example, {% set a = expression %}

  • a block: {% block %} and {% end_block %}; for example, {% for i in list %} ... {% end_for %}

For all statements, it is possible to control the surrounding whitespace:

  • trim leading whitespace: {%- tag %}

  • trim trailing whitespace: {% tag -%}

  • trim leading and trailing whitespace: {%- tag -%}

2.2. Conditions

For cases where the message content depends on data we use classic conditions directly in text:

{% if <condition> %} text {% endif %}
{% if <condition> %} text {% else %} text2 {% endif %}
{% if <condition> %} text {% elif <condition2> %} text2 {% else %} text3 {% endif %}
{% switch expression %}
    {% case 10 %}text1
    {% case 20 %}text2
    {% default %}text3
{% endswitch %}

2.3. Loops

To iterate over items in a sequence or a dictionary, we use a for loop.

A loop can iterate either over a list or a map.

For example, this template

{% for i in [1,2,3] %}
    i={{i}}: i²={{i*i}}
{% endfor %}

produces:

i=1: i²=1
i=2: i²=4
i=3: i²=9

while this template

{% for k,v in {1: "a", 2: "b", 3: "c"} %}
    {{k}} -> {{v}}
{% endfor %}

produces:

1 -> a
2 -> b
3 -> c

When combined with the unitNum filter:

{% for q,u in {5: "box", 1: "bottle", 30: "cup"} %}
    {{q|unitNum(u)}}
{% endfor %}

we can get the following for English:

five boxes
one bottle
30 cups

Inside loops, there is a special variable loop with information about the iteration.

  • loop.length - size of the iterated collection

  • loop.index - the current iteration of the loop. (1-indexed)

  • loop.index0 - the current iteration of the loop. (0-indexed)

  • loop.revindex - the number of iterations from the end of the loop (1-indexed)

  • loop.revindex0 - the number of iterations from the end of the loop (0-indexed)

  • loop.first – true if the first iteration

  • loop.last – true if the last iteration

2.4. Alternatives

A random choice between multiple alternatives is supported with the choose tag. For example, this template

{{% choose %}}
     {{% case %}}text1
     {{% case %}}text2
     {{% case %}}text3
{{% endchoose %}}

randomly outputs either text1, text2, or text3. All choices are equally probable. To influence the relative probability, we can use the ``weight` parameter:

{{% choose %}}
     {{% case weight=40 %}}text1
     {{% case weight=20 %}}text2
     {{% case %}}text3
{{% endchoose %}}

In this case, text1 will be twice as likely to be selected as text2, which in turn will be twice as likely as text3 (weight=10 is the default).

We can also add conditions blocking individual choices. So, for example, the following template

{{% choose %}}
     {{% case condition=(i>20) %}}text1
     {{% case %}}text2
{{% endchoose %}}

outputs text1 only if the variable i is greater than 20.

2.5. Looped alternatives

The for_choices tag combines the functionality of a for loop with a random choice of alternatives, similar to the choose tag:

{% for_choices i in [1,2,3,4,5] %}
    {% case %} The {{i | ord_numeral_in_words }} option is great.
    {% case %} Option {{i}} is a good option .
    {% case %} Let's not forget the option {{i|numeral}}.
{% endfor_choices %}

can generate for example:

Option 1 is a good option.
The second option is great.
Option 3 is a good option.
Let's not forget the option 4.
The fifth option is great.

Inside for_choices, it is possible to use the loop variable with information about the iteration in the same way as within a for loop.

The probability of generating a particular case can be influenced by the weight parameter:

{{% for_choices i in [1,2,3,4,5] %}}
     {{% case weight=40 %}}text1
     {{% case weight=20 %}}text2
     {{% case %}}text3
{{% endfor_choices %}}

In this case, text1 will be twice as probable as text2, which in turn will be twice as probable as text3 (weight=10 is the default).

We can also add conditions blocking individual choices. So, for example, the following template

{{% for_choices i in [1,2,3] %}}
     {{% case condition=(loop.first) %}}text1
     {{% case %}}text2
     {{% case %}}text3
     {{% case condition=(loop.last) %}}text4
{{% endfor_choices %}}

can produce text1 only in the first iteration, and text4 only in the last iteration, while text2 and text3 can be output in any iterations. Therefore, the result can be for example:

text1
text2
text4

or:

text2
text2
text2

or:

text1
text3
text2

2.6. Variables

A variable can be assigned a value by the set or capture statements. The set statement is used to assign the result of an expression. For example, the following template

{% set v = "abc" | upper %}
{{ v }}{{ v }}

produces:

ABCABC

The capture statement is used to capture the contents of the enclosed block into a variable. Therefore the following template

{% capture v %}some content{% endcapture %}
{{ v }} and {{ v }}

produces:

some content and some content

2.7. Macros

In cases when a certain template is used repeatedly, we can pre-define it as macro:

{% macro cmpAdverb(diff) %}
{% if diff > 0 %} less {% else %} more {% endif %}
{% endmacro %}

and then call the macro when necessary (it does not have to be in the beginning of the document, but it needs to be defined before it is used):

Year-to-year, gas costs {{region.price.diesel.y1Diff|abs}} cents {{cmpAdverb(region.price.diesel.y1Diff)}}.

  • Year-to-year, gas costs 30 cents less.

  • Year-to-year, gas costs 30 cents more.