Skip to main content

Template File Format

File Naming​

<culture>.<setname>.txt

Both parts are matched exactly against the culture name and the set name, so fr-FR.Base.txt serves the fr-FR culture and fr.Base.txt serves fr. A missing file is not an error — the set simply contributes nothing for that culture.

In Agility these live in the web application's Strings folder, alongside the shipped en.Base.txt, en.Scrum.txt and friends. The set names Agility looks for are listed in Template sets.

Encoding​

Files must be UTF-8. A byte-order mark is optional, but any other encoding is a hard failure — the reader is constructed with throw-on-invalid-bytes, so a Latin-1 file raises a decoder exception rather than silently mangling accented characters.

EncodingResult
UTF-8 without BOMWorks
UTF-8 with BOMWorks
ANSI / code pageThrows DecoderFallbackException

Syntax​

One template per line, tag=value.

Every rule in one file
;Comment=Lines starting with semicolon are ignored
LongText=First line_
Second line
Plural={1}s
Plural'Story=Stories
Command={1} {2}
Fixed=Never Change
This==has==equal==signs=Equal-sign free
Deleted=

Comments​

A line whose first character is ; is skipped entirely. There are no end-of-line comments — a ; anywhere else is ordinary text.

Because the sample line above is a comment, the tag Comment is never defined, and resolving it returns Comment.

The Separator​

The tag ends at the first = that is not doubled. Everything after it, to the end of the line, is the value — including further = characters, which need no escaping on the value side.

A line with no = at all is skipped, which is how blank lines are tolerated.

Escaping = In a Tag​

Double it. == in the tag portion means a literal =.

This==has==equal==signs=Equal-sign free

defines the tag This=has=equal=signs.

Multi-Line Values​

A trailing underscore continues the value onto the next line, and the line break is preserved in the output.

LongText=First line_
Second line

resolves to:

First line
Second line

Continuations chain: each line that ends with _ pulls in one more. Note the consequence — a value cannot end with a literal underscore.

Empty Values Delete​

Plural'Story=

removes Plural'Story from this culture's map rather than setting it to an empty string. This is covered in detail, with the reason it matters, in Template sets.

Braces in Values​

{ and } introduce nested tags. To emit a literal brace, double it: {{ and }}.

Whitespace​

Neither the tag nor the value is trimmed at parse time, so leading whitespace before a tag becomes part of the tag and will not match. Trailing whitespace on a value is harmless because resolution trims the finished string — but only at its edges. Keep lines flush-left.

Ordering Within a File​

Order does not matter for lookup: the file is loaded into a map, and tag resolution is driven by tag specificity, not file position. Order only matters between files, per the set stack. A duplicate tag later in the same file simply wins.

Templates That Do Not Come from Files​

Two of Agility's template sources are not files at all and therefore have no file format:

  • Terminology overrides are rows in the Localization database table (Language, Key, Value), filtered to the requested culture. Rows with an empty Value are excluded by the query, so the delete-by-empty-value trick is not available there.
  • System values are computed in code — the only one is Runtime'MaxUploadMb.

They obey the same override rules as files; only the storage differs.