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.
| Encoding | Result |
|---|---|
| UTF-8 without BOM | Works |
| UTF-8 with BOM | Works |
| ANSI / code page | Throws DecoderFallbackException |
Syntax
One template per line, tag=value.
;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
Localizationdatabase table (Language,Key,Value), filtered to the requested culture. Rows with an emptyValueare 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.
Related Topics
- Template sets and override order
- Hot reload and caching — making an edited file take effect
- Nested tag substitution