Template Sets and Override Order
The Stacking Rule
A culture's template map is built by applying several template sets in
order. Each set is a flat list of tag=value templates. A tag defined in a
later set replaces the same tag from an earlier one; tags a set does not mention
are left alone.
Base ──┐
edition set ├─ applied in order, later wins
Company ──┘
Using the library's fixtures, where Base defines Story implicitly (no
template, so it resolves to itself), Scrum renames it and Custom renames it
again:
| Sets loaded | Story | Plural'Story | Plural'Project | Fixed |
|---|---|---|---|---|
Base | Story | Stories | Projects | Never Change |
Base, Scrum | Backlog Item | Backlog Items | Projects | Never Change |
Base, Scrum, Custom | PBI | PBIs | Projects | Never Change |
Note the third column: overriding Story did not touch Project. And the
fourth: a set that never mentions Fixed leaves it exactly as it was, however
many sets are stacked on top.
An Empty Value Deletes, It Does Not Blank
This is the sharpest edge in the whole system.
Story=Backlog Item
; Deliberately remove the definition of Plural'Story
Plural'Story=
A template whose value is empty removes that tag from the map. It does not set it to the empty string. Removal re-exposes whatever the term-stack walk would have found next.
So after that set is applied, Plural'Story no longer has a specific entry, the
walk falls back to the generic Plural={1}s, term 1 is Story, which now
resolves to Backlog Item — and the answer is Backlog Items, not Stories
and not an empty string.
An empty translation is not stored as an empty string — it removes the tag from the culture's map.
If you genuinely want a label to render as nothing, you cannot express it in a template file — an empty value is a deletion. Removal only affects the culture whose map is being built, so a deleted tag can still be answered by the fallback culture.
Sets Are per-Culture
Sets are loaded per culture, so fr-FR is assembled from fr-FR's sets only,
then chained to fr, then to en. A Company override written for en does
not apply to fr-FR unless fr-FR has nothing of its own to say about that tag
— which is just the ordinary culture fallback
rule.
If no set at all exists for a culture, the whole culture defers to its fallback.
Instance-Wide Overrides Sit on Top of Everything
LocalizationManager also accepts a dictionary of overrides that is applied to
the default culture's localizer after every set has been loaded. Those
override the final result of the whole set stack:
| Tag | Sets say | Override says | Result |
|---|---|---|---|
Story | PBI | Bone | Bone |
Plural'Story | derived | — | Bones |
Plural'Project | Projects | — | Projects |
Because they land on the default localizer, overrides are inherited by every culture that does not override the tag itself.
The Set Stack Agility Actually Uses
The Base / Custom pair described in the localization engine's own
documentation is the sample application's configuration, not Agility's. Agility builds a
longer stack, in this order:
| # | Provider | Source | Present when |
|---|---|---|---|
| 1 | Base | Strings/<culture>.Base.txt | Always |
| 2 | ExtendedTypesOff | Strings/<culture>.ExtendedTypesOff.txt | The Defect asset type is not visible |
| 3 | Edition set | Strings/<culture>.<Edition>.txt | The instance is licensed for localization; the set is named for the configured meta edition |
| 4 | Company | Strings/<culture>.Company.txt | Always attempted; the file is customer-supplied |
| 5 | RemoveNonEnglishTemplateProvider("AttributeDefinition") | code | Every culture except en |
| 6 | Terminology overrides | the Localization database table, filtered to the culture — written by the terminology override API and by the Terminology admin screen | Always |
| 7 | System values | code — Runtime'MaxUploadMb | Always |
Editions shipped in the box include Scrum, XP, AgileUP, Catalyst,
DSDM and Team; the English files ship as Strings/en.*.txt in the web
application.
Two consequences worth internalising:
Companyis the in-field override file, the equivalent of the README'sCustom. It ships empty (in fact, absent) and is the supported place to rename terminology on disk.- The Terminology admin screen wins over every file. It is applied at
position 6, after all four file sets. If a rename appears to ignore your
Companyfile, check theLocalizationtable. - That table is reachable from the API. The Terminology screen and
api/localization/api/localizationswrite the same store, so a terminology change made through the API takes precedence over every file for exactly the same reason. This is the supported way to re-term Agility programmatically.
Debugging an Override That Is Not Taking Effect
Work down this list; it is ordered by how often each cause is the real one.
- Something later in the stack overrides it. Check the Terminology admin screen before anything else.
- A more specific tag is winning. You overrode
Plural, butPlural'Storyis still defined. See Tag resolution. - You edited the wrong culture's file.
en.Company.txtdoes not affectfr-FRiffr-FRdefines the tag. - The file did not parse. Wrong encoding, or a missing
=. See Template file format. - A stale cache. See Hot reload and caching.
Related Topics
- Template file format — the syntax of a set file
- Hot reload and caching — making an edit take effect
- Tag resolution
- Culture fallback