Template:TranslationDef: Difference between revisions
obelisk-bot: uploading initial Cargo templates |
obelisk-bot: Pushing translation table rework |
||
| Line 1: | Line 1: | ||
<noinclude> | <noinclude> | ||
A single shared table for '''all per-entity i18n payloads''' | A single shared table for '''all per-entity i18n payloads''', stored in '''long format''' — one row per <code>(target, language)</code> pair rather than one row per target with a column per language. English is stored here too (<code>language=en</code>), so a language-aware query is a uniform <code>WHERE language=…</code> filter with no special-casing. | ||
<code> | |||
The bot never extracts <code>TranslationDef</code> rows on their own; each parent entity's emit function appends | The bot never extracts <code>TranslationDef</code> rows on their own; each parent entity's emit function appends one <code><nowiki>{{TranslationDef | … }}</nowiki></code> call '''per language''' to its own page, right after the entity's structural row. The <code><nowiki>{{TranslationDef}}</nowiki></code> MediaWiki template's job is to call <code>#cargo_store</code> on this table. | ||
<code><nowiki>{{TranslationDef}}</nowiki></code> MediaWiki template's job is to call <code>#cargo_store</code> | |||
on this table. | |||
== Schema == | == Schema == | ||
{{#cargo_declare:_table=Translation | {{#cargo_declare:_table=Translation | ||
| target_id = String | |||
| type = String | | type = String | ||
| | | subtype = String | ||
| | | variant = String | ||
| | | language = String | ||
| | | name = String | ||
| | | description = Wikitext | ||
| | | bonus_description = Wikitext | ||
}} | }} | ||
<pre><nowiki> | <pre><nowiki> | ||
{{TranslationDef | {{TranslationDef | ||
| target_id = String <!-- the parent entity's id (Unit.id, Faction.id, …); empty for catch-all rows keyed by subtype --> | |||
| target_id = String <!-- the parent entity's id (Unit.id, Faction.id, | | 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 --> | ||
| | |||
| | |||
| | |||
| | |||
}} | }} | ||
</nowiki></pre> | </nowiki></pre> | ||
== Field notes == | == Field notes == | ||
* '''Primary key is <code>(type, | * '''Primary key is <code>(target_id, type, subtype, variant, language)</code>''' as a tuple. <code>type</code> / <code>subtype</code> / <code>variant</code> are tiers of the same discriminator pyramid; <code>target_id</code> is the entity id and ''usually'' pairs with a <code>type</code>, but that coupling isn't enforced by the architecture. Most entities use only <code>target_id</code> + <code>type</code>; catch-all reference rows (the ones that used to live on <code>Entry</code>) use <code>type</code> + <code>subtype</code> + <code>variant</code> and leave <code>target_id</code> empty; per-level rows (spell ranks, law levels, skill levels) carry the level in <code>variant</code>. | ||
* '''English | * '''Joins from parent entities''' include the type discriminator and the language filter, e.g. <code>Unit.id = Translation.target_id WHERE Translation.type='unit' AND Translation.language='{{{lang|en}}}'</code>. | ||
* '''Language-code mapping''' (game directory → | * '''English is in this table''' as <code>language=en</code> — it is not a special case. Parent entity tables no longer carry inline English <code>name</code>/<code>description</code> columns; all display text for every language comes from here. | ||
* '''<code>name</code> is <code>String</code>, <code>description</code>/<code>bonus_description</code> are <code>Wikitext</code>''' — descriptions may carry HTML-bold/italic from the L10n corpus, which the bot's resolver converts to wiki markup (<code>'''</code> / <code>''</code>) 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 <code>name_sid</code>/<code>desc_sid</code> here.''' The source SIDs are language-independent and live on the parent entity's own row (or its thin <code>Entry</code>/<code>SpellRank</code> stub) for traceability. They are not part of the translation lookup path. | |||
* '''Language-code mapping''' (game directory → code): | |||
** <code>english</code> → <code>en</code> | |||
** <code>BRportugese</code> → <code>pt_br</code> | ** <code>BRportugese</code> → <code>pt_br</code> | ||
** <code>czech</code> → <code>cs</code>, <code>french</code> → <code>fr</code>, <code>german</code> → <code>de</code>, <code>hungarian</code> → <code>hu</code>, <code>italian</code> → <code>it</code>, <code>japanese</code> → <code>ja</code>, <code>korean</code> → <code>ko</code>, <code>polish</code> → <code>pl</code>, <code>russian</code> → <code>ru</code>, <code>spanish</code> → <code>es</code>, <code>turkish</code> → <code>tr</code>, <code>ukrainian</code> → <code>uk</code> | ** <code>czech</code> → <code>cs</code>, <code>french</code> → <code>fr</code>, <code>german</code> → <code>de</code>, <code>hungarian</code> → <code>hu</code>, <code>italian</code> → <code>it</code>, <code>japanese</code> → <code>ja</code>, <code>korean</code> → <code>ko</code>, <code>polish</code> → <code>pl</code>, <code>russian</code> → <code>ru</code>, <code>spanish</code> → <code>es</code>, <code>turkish</code> → <code>tr</code>, <code>ukrainian</code> → <code>uk</code> | ||
** <code>zhCN</code> → <code>zh_cn</code>, <code>zhTW</code> → <code>zh_tw</code> | ** <code>zhCN</code> → <code>zh_cn</code>, <code>zhTW</code> → <code>zh_tw</code> | ||
== | == Key-mapping examples == | ||
How different parent shapes map onto the key tiers: | |||
{| class="wikitable" | {| class="wikitable" | ||
! <code> | ! Parent !! <code>target_id</code> !! <code>type</code> !! <code>subtype</code> !! <code>variant</code> | ||
|- | |- | ||
| | | Unit || <code>Unit.id</code> || <code>unit</code> || || | ||
|- | |- | ||
| <code> | | Faction || <code>Faction.id</code> || <code>faction</code> || || | ||
|- | |- | ||
| <code> | | Hero || <code>Hero.id</code> || <code>hero</code> || || | ||
|- | |- | ||
| <code> | | Hero motto || <code>Hero.id</code> || <code>hero_motto</code> || || | ||
|- | |||
| Spell rank || <code>Spell.id</code> || <code>spell_rank</code> || || <code>level</code> (1-4) | |||
|- | |||
| Attack archetype || || <code>attack_archetype</code> || <code>melee</code> / <code>ranged</code> / … || | |||
|- | |||
| Law level || <code>Law.id</code> || <code>law_level</code> || || <code>level</code> | |||
|} | |} | ||
The precise mapping per parent type is owned by that entity's emit function — the schema just provides the columns. | |||
== Page layout == | == Page layout == | ||
Translation rows do '''not''' live on their own wiki pages. Each row is emitted as a <code><nowiki>{{TranslationDef | …}}</nowiki></code> invocation on the parent entity's data page, immediately after the entity's structural row. The | Translation rows do '''not''' live on their own wiki pages. Each row is emitted as a <code><nowiki>{{TranslationDef | … }}</nowiki></code> 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. | ||
a single table without page-naming collisions. | |||
[[Category:Cargo Definitions]] | [[Category:Cargo Definitions]] | ||
</noinclude><includeonly>{{#cargo_store:_table=Translation | </noinclude><includeonly>{{#cargo_store:_table=Translation | ||
| target_id = {{{target_id|}}} | |||
| type = {{{type|}}} | | type = {{{type|}}} | ||
| | | subtype = {{{subtype|}}} | ||
| | | variant = {{{variant|}}} | ||
| | | language = {{{language|}}} | ||
| | | name = {{{name|}}} | ||
| | | description = {{{description|}}} | ||
| | | bonus_description = {{{bonus_description|}}} | ||
}} | }} | ||
Created <code>Translation</code> entry: <code>{{{type|}}}/{{{ | Created <code>Translation</code> entry: <code>{{{target_id|}}}/{{{type|}}}/{{{subtype|}}}/{{{variant|}}} ({{{language|}}})</code></includeonly> | ||
Revision as of 20:48, 14 May 2026
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, …); empty for catch-all rows keyed by subtype -->
| 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 reference rows (the ones that used to live onEntry) usetype+subtype+variantand leavetarget_idempty; 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 | 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.


