Type: localization
Runtime text entries per namespace and culture, overriding existing texts by source string, and culture matching.
The Localization stage runs after GameTags/Assets and before CDOChanges. Its entries key is
entries, a map from key to either a scalar or a block map with source and text fields.
Simple key entries: new text
Section titled “Simple key entries: new text”The scalar form registers a brand new localized text under namespace: and key. This works for
your own content’s FText keys, or anyone else’s, as long as the namespace and key match:
type: localizationnamespace: MyPackculture: de # prefix-matched: also applies for de-DE, de-AT, …entries: MySuperIngot_Name: 'Superbarren' MySuperIngot_Desc: 'Ein weit überlegener Barren.'source + text map: overriding an EXISTING text
Section titled “source + text map: overriding an EXISTING text”The map form overrides a text that already exists (vanilla or modded) by its original source string:
type: localizationnamespace: MyPackculture: deentries: IronIngot_Renamed: source: 'Iron Ingot' text: 'Eisenbarren (überarbeitet)' SchematicOverride: source: 'Super Ingot Smelting' text: 'Superbarren-Verhüttung'⚠️ Source-hash matching. UE identifies a localized text by its namespace/key plus a hash of the original source string. The
source:you give must be byte-identical to the current original text: spacing, punctuation, and capitalisation all matter. If a game update changes the source string, the override silently stops matching. Copy the exact string from the game, don’t retype it. Omittingsource:usestext:as the source too, which only works for new keys. The scalar form above is the same thing written shorter.
How it’s applied
Section titled “How it’s applied”Localization entries are applied through the same mechanism the engine’s own localization system
uses to load .locres files, so there is nothing KDataForge-specific for the game to special-case.
Bidirectional prefix matching for culture:
Section titled “Bidirectional prefix matching for culture:”culture: de # matches current language de, de-DE, de-AT, …culture: pt-BR # matches only pt-BR (a more specific prefix than pt)# omit culture: # entries apply for EVERY languageThe match is bidirectional prefix matching: either the current language starts with culture:,
or culture: starts with the current language. culture: de applies when the running game is set
to de-DE, and culture: de-DE would also apply if the game were set to plain de. Whichever
side is the shorter prefix wins the comparison. In practice, prefer the shortest culture code that
covers your translation, de rather than de-DE, unless you specifically need a regional variant.
Documents whose culture: doesn’t match the current language are skipped with an Info
diagnostic. This is not a warning: it’s expected, not an error.
Loading changes
Section titled “Loading changes”Localization changes are loaded on the next session start.
A complete worked translation (item + schematic + German locale file, applied together) is part of the end-to-end pack in End-to-End Pack.
Localizing configuration text
Section titled “Localizing configuration text”The name, description, tooltip and option label of a
pack configuration field can use the localized text
form, exactly like a text property:
name: key: Config_IronSpeed_Name ns: KDFSample source: Iron smelting speedsource is the text shown when no translation exists. Translate it with a localization document
that uses the same namespace and key (the source of the map form must equal the text in the
definition):
type: localizationnamespace: KDFSampleculture: deentries: Config_IronSpeed_Name: source: Iron smelting speed text: Eisen-SchmelzgeschwindigkeitThe same works for a pack’s description in pack.yml and for category class names.
Config values and templates in text entries
Section titled “Config values and templates in text entries”Text entries are string values, so templates work in them. The
pre-pass providers (cfg, session, ags, option) are replaced before the entries are
registered, which lets a translation show the player’s current settings:
type: localizationnamespace: KDFSampleculture: enentries: Config_Summary: 'Iron smelts at {cfg:balance.ironSpeed}x, milestone in tier {cfg:features.tier}.' Config_Literal: 'Write \{cfg:balance.ironSpeed} to show the speed.'{0}-style text arguments are not templates and pass through unchanged. Apply-time providers
such as {item:...} are not expanded in localization entries; they work in operation values (an
item description, for example), see Templates. Localization
documents are one of the places where a hot field is allowed
(Hot and cold values): the text is
rebuilt every time KDataForge loads.
Troubleshooting
Section titled “Troubleshooting”- My override isn’t taking effect. This is almost always the source-hash mismatch described above. Copy the original string straight out of the game, or the base-game source if you have it, rather than retyping it from memory. A single missing period or extra space is enough to break the match silently.
- Translation shows in one culture but not another. Check for a stray
culture:on the file. Omitting it entirely is usually what you want, unless you’re intentionally splitting translations per locale across files. - New key works, but overriding an existing key doesn’t. New keys, using the scalar form,
don’t need
source:to match anything since there’s nothing to match yet. Overrides, using the map form, do need it. If you’re not sure which one you need, ask yourself: does this text already exist in the game?
