Creating Word Freemarker based templates#

A Freemarker based Word template is an ordinary Word document (.docx) that contains Freemarker expressions. You design the document in MS Word, with its own styles, headers, footers, and tables, and type the expressions wherever item data should appear. On export, Allegra fills in the expressions and returns a Word document.

Unlike legacy templates (see Creating Word Legacy templates), you do not need a Word plug-in or content controls. The template controls the whole layout of the document.

Turning a Word document into a Freemarker template#

Allegra uses the Freemarker engine only for Word templates that ask for it. You set this up with custom document properties:

  1. In MS Word, open the document you want to use as a template.

  2. Go to File > Info > Properties > Advanced Properties and open the Custom tab.

  3. Add a property named allegraTemplateEngine of type Text with the value freemarker.

  4. Add any other settings you need from the list below.

  5. Save the document and upload it under Administration > Templates > Export templates.

A Word template without allegraTemplateEngine=freemarker is treated as a legacy template.

Note

Allegra removes its own allegra… properties from the exported document. Custom properties that you define yourself are kept.

Template settings#

These settings match the HTML template settings (see Creating HTML templates), with an allegra prefix added. For yes/no settings, you can use the Word property type Yes or no, or enter true, yes, or 1 as text.

Property

Default

Description

allegraTemplateEngine

Must be freemarker.

allegraTemplateTarget

(none)

1 - Wiki document export, 2 - item export. If this property is not set, the template is offered for every kind of export.

allegraIncludeHistory

yes

Loads the item history, comments, and internal comments.

allegraIncludeCosts

yes

Loads the booked costs.

allegraIncludeBudgetPlan

yes

Loads the budget and planned value entries.

allegraIncludeLinks

no

Loads the linked items. item.links is empty unless this is set.

allegraIncludeChildren

no

Adds the child items of the exported items to item.children.

allegraOpenChildrenOnly

no

With allegraIncludeChildren, only child items that are not closed are added.

allegraFullHierarchy

no

With allegraIncludeChildren, all descendants are added, not only direct children.

Loading history, costs, and budget makes the export slower. If your template does not use them, set these properties to no.

Writing expressions in Word#

Word templates use Freemarker’s square bracket syntax for directives, because Word escapes the angle brackets that you type:

[#list items as item]
  ${item.no} ${item.synopsis}
[/#list]

[#if item.fields["Status"] == "closed"]closed[/#if]

[#-- a comment --]

Interpolations still use ${...}. You can type expressions straight into the document text, and you can format them with any Word formatting. Allegra fixes the typographic quotes and dashes that Word’s AutoCorrect puts into expressions, so you do not have to turn AutoCorrect off.

Paragraphs and table rows#

  • If a paragraph contains only directives such as [#list ...] or [/#if], Allegra removes the paragraph itself. As a result, a directive on its own line does not leave an empty line in the output.

  • A paragraph with at least one ${...} interpolation is kept. So [#if item.project??]Project: ${item.project}[/#if] on its own line becomes a line that appears only when the condition is true.

  • To repeat a table row, put the opening [#list ...] in a row of its own above it and the closing [/#list] in a row of its own below it. Allegra removes these directive-only rows, and the row between them is repeated once per entry.

| Type                          | Item            | Title           |
| [#list item.links as link]    |                 |                 |
| ${link.type}                  | ${link.itemNo}  | ${link.title}   |
| [/#list]                      |                 |                 |

Important

Every directive must open and close within the same structure. A loop that opens inside a table cell and closes outside the table produces an invalid document, and the export fails with the message “The rendered template is not valid WordprocessingML”.

Headers and footers#

Expressions also work in headers and footers, for example Exported by ${exportedBy} on ${exportedOnText}. For page numbers, use Word’s own page number fields.

Rich text#

Item descriptions, comments, and history differences are HTML. Write them with the html() function, which converts the HTML into Word content and embeds any images it contains:

${html(item.description)}

Written as ${item.description}, the description shows its HTML markup as text.

The converted text uses the template’s default font (the Normal style font), unless the rich text sets a font of its own.

You can also pass your own HTML to html(). This is how you create a clickable link to an item:

${html('<a href="' + item.url + '">' + item.no + '</a>')}

${item.url} on its own is only the address as plain text. item.url is empty if the server URL is not configured in Allegra.

To show a person’s avatar, embed it as an image and always give it a size. Without a size, the avatar is shown at full size:

[#if comment.avatar??]${html('<img src="' + comment.avatar + '" style="width:18pt;height:18pt"/>')}[/#if]

Freemarker variables#

The template receives the following top-level variables:

Variable

Description

items

The exported items (a list of items, see below). In a Wiki document export, these are the items that make up the document.

document

The exported Wiki document as an item, or null in an item export. Check it with [#if document??].

html(text)

Converts rich text (HTML) into Word content. See Rich text.

text(key)

Returns the localized text of an Allegra resource key in the exporting user’s language. If the key is not found, the key itself is shown.

exportedBy

The name of the person who runs the export.

exportedOn

The export time as a date value, which you can format with Freemarker, e.g. ${exportedOn?string["yyyy-MM-dd"]}.

exportedOnText

The export time, already formatted for the user’s locale.

locale

The user’s language code, e.g. en or de.

serverUrl

The configured server URL of Allegra.

licenseHolder

The license holder.

Dates in the model (created, lastModified, createdOn, and so on) are already formatted for the exporting user’s locale. You can print them as they are.

Item#

Attribute

Description

id

The internal item ID.

no

The item number as shown in Allegra.

url

The absolute link to the item, or empty if no server URL is configured.

synopsis

The title.

description

The description as HTML, with Allegra macros already expanded. Use ${html(item.description)}.

project

The project name.

projectTypeId

The ID of the project type.

created, lastModified

Creation and last change time.

currencyName, currencySymbol

The project’s currency, e.g. “Euro” and “EUR”. Empty if the project has none.

wiki

true for a Wiki document, false for a regular item.

fields

All field values by field name, e.g. ${item.fields["Status"]}. You can find the field names under Administration > Customize > Item attributes.

fieldsById

All field values by f + field ID, e.g. ${item.fieldsById["f17"]}.

links

Linked items (see below). Requires allegraIncludeLinks.

children

Child items, with the same structure. Requires allegraIncludeChildren.

history

Field changes, newest first. Requires allegraIncludeHistory.

comments, internalComments

Comments and internal comments. Require allegraIncludeHistory.

costs

Booked costs. Requires allegraIncludeCosts.

budget

Budget and planned value entries. Requires allegraIncludeBudgetPlan.

Comment#

Attribute

Description

author, authorId

The author’s name and ID.

createdOn

When the comment was written.

text

The comment as HTML. Use ${html(comment.text)}.

avatar

The author’s avatar as an embedded image (data URI), or null.

History entry#

Attribute

Description

changedBy, changedById

The name and ID of the person who made the change.

changedOn

When the change was made.

field

The name of the changed field.

diff

The old and new value as HTML, as on the history tab. Use ${html(entry.diff)}.

avatar

The avatar of the person who made the change, or null.

Cost#

effortDate, person, subject, description, hours, cost, currency.

Budget entry#

changedOn, changedBy, description, estimatedHours, estimatedCost, currency, and plannedValue (true for a planned value entry, false for a budget entry).

Note

Freemarker stops with an error when an expression is null. For values that may be missing, such as document or avatar, use [#if x??] or a default value like ${x!""}.

Examples#

Items with their fields and description:

[#list items as item]
${item.no} ${item.synopsis}
Project: ${item.project}    Status: ${item.fields["Status"]!""}
${html(item.description)}
[/#list]

Item hierarchy with a recursive macro (requires allegraIncludeChildren):

[#macro render item]
${item.no} ${item.synopsis}
${html(item.description)}
[#list item.children as child][@render child/][/#list]
[/#macro]
[#list items as item][@render item/][/#list]

Comments:

[#if item.comments?has_content]
Comments
[#list item.comments as comment]
${comment.author}, ${comment.createdOn}
${html(comment.text)}
[/#list]
[/#if]

Wiki document title, falling back to the first item:

[#if document??]${document.synopsis}[#else]${items[0].synopsis}[/#if]

Troubleshooting#

If a template cannot be processed, the export shows Freemarker’s error message, including the expression that caused it. For other errors, the message contains a short reference code. Give this code to your administrator, who can use it to find the cause in the server log.

  • An expression appears literally in the output: check the spelling and that the directive uses square brackets ([#if], not <#if>).

  • The export fails with “not valid WordprocessingML”: a directive opens and closes in different paragraphs or tables. See Paragraphs and table rows.

  • A list is empty: check that the corresponding allegraInclude… property is set.