Skip to main content

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 loadedStoryPlural'StoryPlural'ProjectFixed
BaseStoryStoriesProjectsNever Change
Base, ScrumBacklog ItemBacklog ItemsProjectsNever Change
Base, Scrum, CustomPBIPBIsProjectsNever 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.

en.Scrum.txt
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.

You cannot set a tag to the empty string this way

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:

TagSets sayOverride saysResult
StoryPBIBoneBone
Plural'Storyderived—Bones
Plural'ProjectProjects—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:

#ProviderSourcePresent when
1BaseStrings/<culture>.Base.txtAlways
2ExtendedTypesOffStrings/<culture>.ExtendedTypesOff.txtThe Defect asset type is not visible
3Edition setStrings/<culture>.<Edition>.txtThe instance is licensed for localization; the set is named for the configured meta edition
4CompanyStrings/<culture>.Company.txtAlways attempted; the file is customer-supplied
5RemoveNonEnglishTemplateProvider("AttributeDefinition")codeEvery culture except en
6Terminology overridesthe Localization database table, filtered to the culture — written by the terminology override API and by the Terminology admin screenAlways
7System valuescode — Runtime'MaxUploadMbAlways

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:

  • Company is the in-field override file, the equivalent of the README's Custom. 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 Company file, check the Localization table.
  • That table is reachable from the API. The Terminology screen and api/localization / api/localizations write 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.

  1. Something later in the stack overrides it. Check the Terminology admin screen before anything else.
  2. A more specific tag is winning. You overrode Plural, but Plural'Story is still defined. See Tag resolution.
  3. You edited the wrong culture's file. en.Company.txt does not affect fr-FR if fr-FR defines the tag.
  4. The file did not parse. Wrong encoding, or a missing =. See Template file format.
  5. A stale cache. See Hot reload and caching.