en:authors_main:task_editor:advanced:edit_templates

Templates

Templates are dynamic expressions evaluated on the server before the page is sent to the players. In the browser, only the result of the expression for their specific team is shown. The template code itself is NOT visible, even in the page source code.

Classic applications of templates:

Templates can be written in regular editor mode or in Source mode in the task description, hint text, or bonus text. Templates can be nested.

To make it easier to write template syntax, you can copy and use a special spreadsheet: QEng Template Generation Google Sheet.

Various Types of Templates

{% match line }:{ 
  {%= 688 /*comment: lineup name*/}:{
Text for lineup with ID 688
  %}
 
  {%= 643 }:{
Text for lineup with ID 643
  %}
  {%= 653,655 }:{
Text for lineup with ID 653 or 655
  %}
 
  {%= ?}:{ 
Text for any other lineup
  %}
%}
{% match team }:{ 
  {%= 688 /*comment: team name*/}:{
Text for team with ID 688
  %}
 
  {%= 643 }:{
Text for team with ID 643
  %}
  {%= 653,655 }:{
Text for team with ID 653 or 655
  %}
 
  {%= ?}:{ 
Text for any other team
  %}
%}

Example in game

Useful for releasing codes or hints at a specific absolute time. To convert date/time, use Unix Time Converter.

{% unix_time 1639999296/*date in unix time*/, Opens, Left}:{
This text will be shown after the specified time.
%}

Example in game

*(Replace `code_1` with the required code index, e.g. `code_5` for the fifth code)*

{% match code_1 }:{ 
  {%= abc}:{
The answer "abc" is submitted for the first code.
  %}
 
  {%= bac, cba}:{
The answer "bac" or "cba" is submitted for the first code.
  %}
 
  {%= !no_answer!}:{
No correct answer has been submitted for the first code yet.
  %}
 
  {%= ?}:{ 
Some other answer synonym has been submitted.
  %}
%}
{% match code_first_2 }:{ 
  {%= abc}:{
The first answer submitted for this code was "abc".
  %}
  {%= !no_answer!}:{
The code has not been submitted yet.
  %}
  {%= ?}:{
Another answer was submitted.
  %}
%}

Besides specific answers, a branch may hold:

  • !no_answer! — the correct answer has not been submitted yet.
  • !any_answer! — any answer has been submitted. Unlike ?, it does not match when there is no answer yet. Handy when a code has synonyms and all you care about is that it is solved.
  • ? — any value, including !no_answer!. Put this branch last: everything listed after it is never checked.
{% match bonus_3 }:{
  {%= !any_answer!}:{
The bonus is solved — no matter which synonym was used.
  %}
  {%= !no_answer!}:{
The bonus is not solved yet.
  %}
%}

Just like codes, you can check answers for bonuses:

  • bonus_1 / bonus_first_1 — last or first answer submitted for bonus 1 on the current task.
  • gbonus_1 / gbonus_first_1 — last or first answer submitted for spanning (global) bonus 1. Spanning bonuses can be checked even on levels where they are not displayed.

Example in game

You can prepend who_ to answer checks to find out who in the team submitted the answer. Possible values:

  • me — code was submitted by the current logged-in user.
  • other — code was submitted by another team member.
  • !no_answer! — not submitted yet.

*(Anonymous players without registration are treated as the same user).*

{% match who_code_1 }:{ 
  {%= me}:{
I submitted the first code.
  %}
  {%= other}:{
My teammate submitted the first code.
  %}
  {%= !no_answer!}:{
Nobody has submitted the code yet.
  %}
%}

Prepend who_team_ to check which team solved a spanning/shared task: Possible values:

  • me — my team solved the code.
  • other — an opponent team solved the code.
  • !no_answer! — not solved yet.
{% match who_team_code_1 }:{ 
  {%= me}:{
Our team solved this code first!
  %}
  {%= other}:{
Opponent team solved this code first.
  %}
%}
{% match lang }:{ 
  {%= ru}:{
Russian interface language selected.
  %}
  {%= uk }:{
Ukrainian interface language selected (uk).
  %}
  {%= en }:{
English interface language selected.
  %}
  {%= ?}:{
Some other language.
  %}
%}
There is an easier way now - for translating text, links and pictures. A multilingual game is made with translations: Multilingual Game (Translations). The task stays one text, the translations live beside it, and the editor shows what is still untranslated. The template below keeps working and nothing has to be changed in existing games, and for a new game it stays the right choice where a language does not need a different version of the same text (that is exactly what translation is for) but a genuinely different structure: its own set of html blocks that other languages do not have, its own logic in the level script rather than just a different string in it, or branching by language combined with another template - by code, by team, by bonus. If you just need a translation - see translations above.

This template lets one game run in several languages at once: a player sees only their own branch, and the other translations never reach the page source.

Players pick the language in the site menu; it can also be set with a parameter in the page address — ?lang=de, ?lang=uk and so on. The choice is remembered in cookies. If the player has never chosen, the language is detected from their browser settings.

lang returns a two-letter language code. The current list of languages is always visible in the language menu on the site; at the time of writing it is de, en, es, et, fi, fr, it, lt, lv, nl, pl, ru, uk.

Things worth remembering:

  • Always add the ? branch and put it last. It fires when the player's language has no branch of its own — otherwise such a player sees an empty task. It usually holds the text in the game's main language.
  • You do not have to translate into every language. Branches for your audience's languages plus the fallback branch are enough.
  • One branch may cover several languages — list the codes separated by commas: {%= ru, uk}:{ … %}.
  • The technique works everywhere templates work: task text, hints, bonuses, texts shown after solving.
  • Keep the answer codes the same for all languages — otherwise you have to make sure the task branches and the level answers do not drift apart. If an answer really is language-dependent (a word found on location, say), put all the variants into the code separated by commas.
  • Templates do not translate the game name, its description in the game list, or invitation emails — write those in a language the whole audience understands, or give both variants separated by a slash.

The easy way to check a translation is to open the game with an explicit language parameter — https://qeng.org/game/1234/?lang=lt. Look at the ? branch too: just pick a language that has no branch of its own.

To give the player a language switcher inside the task itself, put a plain select into the text and its handler into the Task script:

<select id="lang_select">
<option value="en">English (en)</option>
<option value="uk">Українська (uk)</option>
</select>
var select = document.getElementById('lang_select');
if (select) {
  // document.documentElement.lang is the CONTENT language, which gets
  // overridden if the game itself also has translations turned on (see
  // above). The interface language the player actually picked is more
  // reliably read from the lang cookie.
  var match = document.cookie.match(/(?:^|; )lang=([^;]*)/);
  select.value = match ? decodeURIComponent(match[1]) : document.documentElement.lang;
  select.onchange = function () {
    var url = new URL(window.location.href);
    url.searchParams.set('lang', this.value);
    window.location.href = url.toString();
  };
}

Example in game

How to create a product, place a payment button and test the whole thing without real money is described in Paid Content (Paywall). What follows here is only the template that closes off the paid content.

If your game uses paid levels or paid hints, you can check the purchase status:

  • product_KEY — where KEY is the product key from settings.

Possible values:

  • yes — product purchased by the team.
  • pending — payment started but not yet finalized.
  • no — not purchased.
{% match product_level_5 }:{ 
  {%= yes}:{
The team purchased access to level 5.
  %}
  {%= pending}:{
Payment is pending. Please wait and refresh the page.
  %}
  {%= no}:{
Access closed. Price is $1. Click to purchase:
%pay_button level_5%
  %}
%}

When a template sits in the middle of javascript code, the code editor complains about the {% %} syntax — for javascript it is a syntax error. To avoid that, the service lines of the template may be commented out with a double slash . The engine strips those before evaluating the template, so the code inside the template becomes live.

A is stripped only when it is immediately followed (spaces aside) by {% or %}. A space after is optional, and the indent before is preserved. <code JavaScript> show_money(); {% match gbonus_141}:{ {%= some_code}:{ enter_silent('the whole game is done'); %} {%= ?}:{ play_sound('limit'); %} %} </code> A team that entered some_code into global bonus 141 gets: <code JavaScript> show_money(); enter_silent('the whole game is done'); </code> Closing brackets may share a line — %} %} — and a short template can be written on a single line:

// {% match team}:{ {%= 172}:{ var boss = true; %} {%= ?}:{ var boss = false; %} %}

Regular comments are not affected: in the line see {% match team}:{ {%= 172}:{ here %} %} the is followed by text rather than by the start of a template, so the stays and the line remains a comment ( see here).

  • en/authors_main/task_editor/advanced/edit_templates.txt
  • Last modified: 2026/08/19 09:33
  • (external edit)