Template:TranslationDef
A single shared table for all per-entity i18n payloads, stored in long format — one row per (target, language) pair rather than one row per target with a column per language. English is stored here too (language=en), so a language-aware query is a uniform WHERE language=… filter with no special-casing.
The bot never extracts TranslationDef rows on their own; each parent entity's emit function appends one {{TranslationDef | … }} call per language to its own page, right after the entity's structural row. The {{TranslationDef}} MediaWiki template's job is to call #cargo_store on this table.
Schema
This template defines the table "Translation". View table.
{{TranslationDef
| target_id = String <!-- the parent entity's id (Unit.id, Faction.id, …); for catch-all Entry rows (attack_archetype, ui, …) duplicates subtype so the join column is uniformly non-null -->
| type = String <!-- e.g. unit, faction, hero, attack_archetype, spell_rank -->
| subtype = String <!-- secondary key component; sparse -->
| variant = String <!-- tertiary key component; sparse -->
| language = String <!-- en, pt_br, cs, fr, de, hu, it, ja, ko, pl, ru, es, tr, uk, zh_cn, zh_tw -->
| name = String
| description = Wikitext
| bonus_description = Wikitext <!-- sparse: only spell-rank rows populate this -->
}}
Field notes
- Primary key is
(target_id, type, subtype, variant, language)as a tuple.type/subtype/variantare tiers of the same discriminator pyramid;target_idis the entity id and usually pairs with atype, but that coupling isn't enforced by the architecture. Most entities use onlytarget_id+type; catch-all Entry rows are identified by(type, subtype, variant)conceptually, but the emitter duplicatessubtypeintotarget_idso self-joins across languages work uniformly (Cargo stores blank parameter values as SQLNULL, andNULL = NULLdoesn't match in a join); per-level rows (spell ranks, law levels, skill levels) carry the level invariant. - Joins from parent entities include the type discriminator and the language filter, e.g.
Unit.id = Translation.target_id WHERE Translation.type='unit' AND Translation.language='en'. - English is in this table as
language=en— it is not a special case. Parent entity tables no longer carry inline Englishname/descriptioncolumns; all display text for every language comes from here. nameisString,description/bonus_descriptionareWikitext' — descriptions may carry HTML-bold/italic from the L10n corpus, which the bot's resolver converts to wiki markup (/) before storing. Names are plain.- Sparse output: any value column the bot couldn't resolve is omitted. A missing translation is an absent row, not an empty column.
- No
name_sid/desc_sidhere. The source SIDs are language-independent and live on the parent entity's own row (or its thinEntry/SpellRankstub) for traceability. They are not part of the translation lookup path. - Language-code mapping (game directory → code):
english→enBRportugese→pt_brczech→cs,french→fr,german→de,hungarian→hu,italian→it,japanese→ja,korean→ko,polish→pl,russian→ru,spanish→es,turkish→tr,ukrainian→ukzhCN→zh_cn,zhTW→zh_tw
Key-mapping examples
How different parent shapes map onto the key tiers:
| Parent | target_id |
type |
subtype |
variant
|
|---|---|---|---|---|
| Unit | Unit.id |
unit |
||
| Faction | Faction.id |
faction |
||
| Hero | Hero.id |
hero |
||
| Hero motto | Hero.id |
hero_motto |
||
| Spell rank | Spell.id |
spell_rank |
level (1-4)
| |
| Attack archetype | melee / ranged / … (= subtype) |
attack_archetype |
melee / ranged / … |
|
| Law level | Law.id |
law_level |
level
|
The precise mapping per parent type is owned by that entity's emit function — the schema just provides the columns.
Page layout
Translation rows do not live on their own wiki pages. Each row is emitted as a {{TranslationDef | … }} invocation on the parent entity's data page, immediately after the entity's structural row — one invocation per language. The key tuple means Cargo can store many rows in a single table without page-naming collisions.


