Word templates
Template functions
Ten helpers are available in every command without an import.
| Name | Purpose |
|---|---|
_ | Lodash. Group and sort lists, create ranges |
pluralize | Language-dependent singular and plural forms |
imask | Format numbers and strings |
combine | Join values, with text before and after |
img | Load and render an image |
fdate | Format an ISO date |
fcheck | Switch field as text |
ffmt | Output a formatted field value (output formatter) |
ui | View settings (not a function, an object) |
deco | Carry field annotations over into the report |
_: Lodash
The complete Lodash . Often used: _.range, _.groupBy, _.sortBy, _.uniq.
{# FOR i IN _.range(0, eingang.length) #} … {# END-FOR i #} {#! gruppen = _.groupBy(objects, o => o[`RaumNr`] ?? `ohne Raum`) #}
pluralize(language, value, forms)
Chooses the form that fits the number. Registered languages: de and en.
{#$o[`Anzahl Teile`]#} {#pluralize(`de`, $o[`Anzahl Teile`], { one: `Teil`, other: `Teile` })#} {#objects.length#} {#pluralize(`de`, objects.length, { one: `Objekt`, other: `Objekte` })#}
imask(value, fieldDefinition?, customMask?)
Formats numbers and strings according to imask.js . For an empty value it returns null: a bare call then renders empty, never null or NaN in the document, and imask(…) ?? `-` applies.
The configuration is resolved in three levels:
| Level | Source | Remark |
|---|---|---|
| 1 | Custom mask (third parameter) | Always wins; it is laid over the field mask |
| 2 | Field definition from f[`Feld`] | The mask from the field configuration |
| 3 | Number format of the person exporting | From the view settings, two decimal places. If the field has a unit but no mask, the unit is appended |
{#imask($o[`Gewicht`], f[`Gewicht`]) ?? `-`#} {#imask($o[`Breite`], false, { mask: Number, scale: 2, thousandsSeparator: `.`, radix: `,` })#}
Level 3 depends on the user who exports. For reproducible templates use level 1 or 2. A faulty field mask never breaks the export; it falls back to level 3.
combine(value, options?)
Wraps a string or joins an array. For empty input it returns def.
| Option | Default | Meaning |
|---|---|---|
pre | '' | Text before |
post | '' | Text after |
def | '' | Result for empty input |
sep | ', ' | Separator between array elements |
filterEmpty | false | Leave out empty elements |
{#combine($o[`Inventarbemerkung`], { pre: `(`, post: `)`, def: `k. A.` })#} {#combine([$o[`Künstler`], $o[`Datierung`]], { sep: `, `, filterEmpty: true })#} {#combine([parseFloat($o[`Höhe`]), parseFloat($o[`Breite`])].filter(Boolean).join(` x `), { post: ` cm` })#}
The benefit: brackets and units disappear when there is no value, instead of a lonely ( ) or cm in
the document.
combine handles only strings. A number gives def, even inside an array. That is why the third example
does join first and then combine. To wrap a single number, write combine(String(value), …). The
option is called def, not default: an unknown option is silently ignored.
img(file, config)
Used in IMAGE commands; it produces an image for Word. file is a file object from $f or files, an
image field value ($o[`Titelbild`]) or a file ID as a string.
| Option | Meaning |
|---|---|
width, height | Bounding box in cm; the image is fitted with its aspect ratio kept. A single value acts as a square box; without either, 6 × 6 cm applies |
alt | Alternative text |
caption | Caption |
rotation | Rotation in degrees, only if render.rotation is not switched off |
render.crop | Apply the crop set in Moliri. Default true |
render.overlay | Draw in markings. Default true |
render.rotation | Take rotation into account. Default true |
So the default is the edited image, not the original:
{# IMAGE img($file, { width: 6 }) #} {# IMAGE img($file, { width: 6, render: { crop: false, overlay: false } }) #} {#IMAGE img(($o[`Titelbild`] ?? null), { width: 8, height: 6 })#}
The ?? null on an image field makes sure that objects without an image get a placeholder instead of an
error. If loading fails, a placeholder image appears as well. Moliri loads identical image requests only
once per export run.
The DPI are set on export, with a default of 220. Word itself compresses embedded images back to about 220 DPI when saving, unless automatic image compression is switched off. For print templates it is worth switching it off in Word after opening the file for the first time.
Filter files before img()
$f contains all files of the object, including PDFs and documents. Files that cannot be shown directly
get placeholders or generated previews, so a filter is not strictly necessary. If you want images only,
filter:
{# FOR file IN $f #} {# IF [`image`, `image_other`, `svg`].includes($file.kind) #} {# IMAGE img($file, { width: 6 }) #} {# END-IF #} {# END-FOR file #}
The valid values for kind are listed under Supported formats .
fdate(value, format?)
Formats ISO date values, including those with a time. The format is in the command, so the result is the same for all users.
| Format | Result for 2026-03-05 |
|---|---|
TT.MM.JJJJ (default) | 05.03.2026 |
JJJJ | 2026 |
MM.JJJJ | 03.2026 |
T. Monat JJJJ | 5. März 2026 |
JJJJ-MM-TT | 2026-03-05 |
TT/MM/JJJJ | 05/03/2026 |
MM/TT/JJJJ | 03/05/2026 |
auto | Date format from the view settings of the person exporting |
Behaviour at the edges:
- Empty values and
0000-00-00givenull. That renders empty, and??applies. - Incomplete dates are shortened:
2025-00-00becomes2025,2025-03-00becomes03.2025or März 2025. - Values that do not start with an ISO date (free text such as um 1900, “around 1900”) come back unchanged.
- An unknown format counts as
TT.MM.JJJJ.
{#fdate($o[`Eingangsdatum`])#} bis {#fdate($o[`Rückgabedatum`])#} {#fdate($o[`Datierung`], `JJJJ`) ?? `o. J.`#} {#fdate(p.start_date, `T. Monat JJJJ`)#}
fcheck(value, yes?, no?)
Outputs a switch field as text. An empty value counts as “no”, as does anything that looks like a
negation: 0, nein, no, false, aus, off, ❌ and similar. Everything else counts as “yes”. This
way fcheck also reads switches with custom stored values correctly.
Without further arguments, the labels come from the view settings of the person exporting:
{#fcheck($o[`Kurierbegleitung`])#} → view settings {#fcheck($o[`Kurierbegleitung`], `Ja`, `Nein`)#} → fixed label
In the view settings, ✅ and ❌ are preset. In Word, how they look depends on the font of the
paragraph. For print templates, Ja/Nein or X/- are the safe choice, that is the second form
above. Only when there is no view setting does Moliri itself use Ja and Nein.
ffmt(record, key)
Outputs the value of a field as its output formatter formats it. The first parameter is the record, $o or the loop variable of a loop:
{#ffmt($o, `Maße`) ?? ``#} {#ffmt($o, `Maße.Objekt`)#} {#ffmt($o, `Leihgeber`) ?? `-`#} {# FOR obj IN objects #}{#ffmt($obj, `Maße`)#}{# END-FOR obj #}
Without a formatted value it returns null, and ?? applies. Keys with an entry (.) and a variant
(#), and the built-in formatting for each field type, are described under Output formatters in templates .
ui: view settings
Not a call, an object. Keys and the warning are under Template variables .
{#$o[`Datierung`] ?? ui.null_replacement#} {#fdate($o[`Eingangsdatum`], `auto`)#}
deco(annotations, config)
Carries field annotations over into the report: a field’s colour marking as the background of the building block, comment and source as a Word comment.
You set this up in the template editor, not by hand. In the panel Moliri · Insert & edit, every field you insert and every building block you click has the section Additional details with the rows Colour, Comment and Source. There you choose which field provides the colour and which fields contribute comments and sources. Moliri saves the choice on the building block’s content control and inserts the matching call itself on export, in loops with the annotations of each object.
The generated call looks like this:
{# deco($m, { color: `RegNr`, comments: [`RegNr`], sources: [] }) #}
| Key | Meaning |
|---|---|
color | Field name whose colour marking appears as the background |
comments | Field names whose comments appear as a Word comment |
sources | Field names whose source references appear as a Word comment |
Without an annotation the call gives an empty string; no empty marking is created.
The post-processing that sets colour and comments only runs for building blocks set up this way in the
template editor. A deco call that sits in the template as plain text leaves an unreadable string of
characters in the report.
JavaScript in the command
Besides the helpers, simple expressions work directly:
{# INS [$o[`Feld A`], $o[`Feld B`]].filter(Boolean).join(`, `) #}
For more involved logic, a preparatory EXEC step at the start of the document is easier to follow than
nested one-liners. See Recipes .
Helpers and expressions run in isolation. They see only the helpers on this page and the data Moliri has
loaded for the export. They cannot reach the network (fetch, WebSocket, outside scripts), nor the
browser storage with the login; the check reports such a call as Not allowed: …. A run may take
60 seconds, not counting the time for loading images. The details are under Execution and errors .
Further reading
- Template syntax : the commands
- Template variables : the data context
- Output formatters in templates :
ffmtand$fmtin detail - Recipes : patterns to copy