Localization and codename mapping
Question
Internal data uses codenames like hero_inferno and upgrade_ammo_scavenger. Where do human-readable names and descriptions come from, and how do they join back to the vdata?
Summary
- Localization ships as loose plain-text files on disk — no VPK extraction, no decompilation needed. This is the easiest win in the whole pipeline.
- Files live under
citadel/resource/localization/<bundle>/<bundle>_<lang>.txtin Valve's KeyValues format. - Item codenames map 1:1 to a token:
upgrade_ammo_scavenger→"Ammo Scavenger". - Hero name tokens carry a grammatical suffix:
hero_warden:n→"Warden". - Descriptions contain HTML markup and
{s:Token}interpolation referencing stat fields from the vdata — joining names is easy, rendering descriptions is not.
Findings
Bundles (English, build 6679)
| bundle | size | contents |
|---|---|---|
citadel_generated_vo | 3,036 KB | voice line subtitles |
citadel_heroes | 391 KB | hero-facing strings, ability names/descriptions |
citadel_main | 301 KB | UI chrome |
citadel_attributes | 126 KB | stat/attribute labels |
citadel_mods | 68 KB | item descriptions and stat labels |
citadel_gc_mod_names | 21 KB | item display names |
citadel_gc | 18 KB | game-coordinator strings |
citadel_patch_notes | 16 KB | patch notes |
citadel_gc_hero_names | 6 KB | hero display names |
Empty at this build: citadel_dev, citadel_vdata, citadel_override_hero_names, citadel_override_mod_names. The override_* bundles existing but empty suggests a live-ops rename mechanism — unconfirmed.
Format
Standard Valve KeyValues:
"lang"
{
"Language" "english"
"Tokens"
{
"upgrade_clip_size" "Extended Magazine"
"upgrade_ammo_scavenger" "Ammo Scavenger"
"upgrade_rapid_rounds" "Rapid Rounds"
}
}
The join
Items — the vdata entry key is the token:
| vdata key | bundle | token | value |
|---|---|---|---|
upgrade_ammo_scavenger | citadel_gc_mod_names | upgrade_ammo_scavenger | "Ammo Scavenger" |
upgrade_ammo_scavenger | citadel_mods | upgrade_ammo_scavenger_desc | description |
A parallel _search token exists for every name (upgrade_ammo_scavenger_search), presumably to feed the in-game shop search box.
Heroes — the token is the vdata key plus :n:
// Hero names (tokens match the hero name directly)
"hero_warden:n" "Warden"
"hero_warden_search:n" "Warden"
The :n suffix is a grammatical case/gender marker used by Valve's localization system; other suffixes are expected in inflected languages.
Descriptions are templated
"upgrade_lifestrike_gauntlets_desc" "Your next <span class=\"highlight\">Melee</span>
attack <span class=\"highlight\">heals you</span>. <span class=\"diminish\"><br><br>This
heal is {s:NonHeroHealPct}% effective vs non-heroes.<br>Cooldown is
{s:LightMeleeCooldownMult}x as long for Light Melee hits.</span>"
{s:Name} resolves against the entry's m_mapAbilityProperties in the vdata. Stat labels themselves come from citadel_mods too — AmmoPerSoul_label, AmmoPerSoul_prefix, AmmoPerSoul_postfix.
Inferred: producing a correct human-readable item tooltip requires all three of (a) the vdata entry, (b) the _desc token, and (c) the per-stat label/prefix/postfix tokens — plus scale-function evaluation from note 0002.
Unreleased content leaks here
citadel_gc_hero_names contains names with no live counterpart: Vampire, Sapper, Glider, Gunner, Cowboy, Phoenix. Localization is a leading indicator of upcoming content.
Reproduce
GAME=$(python tools/find_game.py --json | python -c 'import json,sys;print(json.load(sys.stdin)["game_dir"])')
L="$GAME/citadel/resource/localization"
ls -la "$L"
head -20 "$L/citadel_gc_hero_names/citadel_gc_hero_names_english.txt"
sed -n '5,20p' "$L/citadel_mods/citadel_mods_english.txt"
# confirm an item codename joins to a display name
grep -n 'upgrade_ammo_scavenger' "$L/citadel_gc_mod_names/citadel_gc_mod_names_english.txt"
No decompilation step is required for any of the above.
Gotchas
- Do not key anything on display names. They are localized and they change. Codenames are the stable identifier.
- Codename ≠ marketing name.
hero_infernois Infernus,hero_gigawattis Seven. There is no algorithmic mapping; the localization file is the mapping. - Escaped quotes and embedded HTML are common in description values. A naive KeyValues parser that splits on
"will corrupt them. - English is base content, not an overlay. There is no
citadel_english/directory; other languages getcitadel_<lang>/VPKs. Do not assume symmetry. citadel_generated_voalso exists as a 2.5 MB.datinside the VPK. The loose.txtis the one to read.- Empty bundles are not errors. Four bundles legitimately ship empty at this build.
Open questions
- Not checked: what suffixes other than
:nappear, and in which languages. - Not checked: whether the
citadel_<lang>/VPKs override any of these loose files, or only add audio. - Not checked: the full
{s:...}interpolation grammar — only{s:Name}was observed. - Not checked: whether
citadel_heroescontains ability names keyed the same way as items. - The purpose of the empty
override_*bundles is inferred, not confirmed.
Sources
Derived entirely from the local install at build 6679. No external sources used.