Localization
Localization is a runtime translation helper for Valheim mods. It intercepts text right before it is displayed and replaces it with values from JSON rule files.
This mod is meant to help translate hardcoded mod UI text. It does not generate translations by itself; you provide the translation rules.
What this mod does
- Intercepts final UI text assignments for
TMPro.TMP_Text.text, TMPro.TMP_Text.SetText(string, bool), and UnityEngine.UI.Text.text.
- Applies
exact rules for full-string matches and templates rules for placeholder-based matches.
- Loads rule files from
BepInEx/config/com.paxton0505.localization/<LanguageCode>/*.json.
- Uses
English/*.json as an optional shared baseline.
- Reloads rules when the active game language changes.
- Supports session-only ServerSync overlays when both server and client run the mod.
- Keeps server-synced rules in memory only and does not write them into the client's local JSON files.
What this mod does not do
- It does not machine-translate text for you.
- It does not modify the source files of other mods.
- It does not save server overlays to disk after the session ends.
- On a dedicated server it does not run local UI translation patches, because there is no local UI to patch.
Before / After


Install
- Install the mod from Thunderstore. The declared dependencies are installed automatically:
BepInExPack_Valheim, Jotunn, and JsonDotNET.
- If you install manually, place
Localization.dll in BepInEx/plugins.
- Launch the game once so the config folders are created.
- Create one or more rule files under
BepInEx/config/com.paxton0505.localization/<LanguageCode>/.
- If you want server-provided overlays, install the mod on both server and clients.
Localization.dll already bundles the ServerSync implementation used by this mod. You do not need to add a separate ServerSync DLL for this plugin.
Folder layout
Example structure:
BepInEx/
config/
com.paxton0505.localization/
English/
Common.json
Chinese_Trad/
MyMod.json
English is optional and can be used as a shared baseline.
- The active language folder should match the game's language name, for example
Chinese_Trad.
- Files inside each language folder are loaded in alphabetical order by file name.
Rule file format
Each JSON file contains two top-level arrays: exact and templates.
{
"exact": [
{
"match": "Item is favorited and won't be stored",
"replace": "物品已被收藏,不會被存放"
},
{
"match": "Slot is favorited and won't be stored",
"replace": "格位已被收藏,不會被存放"
}
],
"templates": [
{
"match": "Stored {{$total}} items from your inventory into nearby containers",
"replace": "已將 {{$total}} 個物品從你的背包存放到附近容器中"
},
{
"match": "<color=red>{{$itemName}} is not in nearby containers</color>",
"replace": "<color=red>附近容器中沒有 {{localize($itemName)}}</color>"
}
]
}
Rule behavior
exact rules are full-string lookups and are the cheapest match type.
templates match full displayed strings with placeholders such as {{$itemName}} or {{$count}}.
- Template matching is exact on the surrounding text. Color tags, punctuation, spacing, and line breaks must match what the game displays.
- Use
\n inside JSON strings for line breaks.
- If no rule matches, the original text is left unchanged.
localize() inside templates
You can call {{localize($name)}} inside a template replacement.
When this happens, the plugin resolves the value in this order:
- Exact rules loaded by this plugin.
- Valheim's own localization table.
- The original value if nothing matches.
This is useful when a template contains an item name or label that should be translated through your existing exact rules.
Load order and precedence
When a non-English language is active, the layers are applied from baseline to highest override in this order:
- Local
English files.
- Synced
English files from the server.
- Local active-language files.
- Synced active-language files from the server.
If the active language is English, only the English layers are used.
Client and dedicated server behavior
Client
- Applies runtime translation to intercepted UI text.
- Reloads compiled rules when the game language changes.
- Applies synced server snapshots immediately when ServerSync values change.
Dedicated server
- Runs in sync-only mode.
- Initializes ServerSync and watches the local config folder.
- Does not run the local translation runtime or UI Harmony patches.
- Publishes local rule changes to connected clients when it is the ServerSync source of truth.
Hot reload
- Local config changes are watched under
BepInEx/config/com.paxton0505.localization.
- On the source-of-truth side, repeated file events are debounced for about 500ms before a snapshot is published.
- On the receiving side, synced snapshots are applied when they arrive; that path is not debounced by the file watcher.
From v1.1.0, the dedicated server logs when hot reload is active and when a new snapshot is published. Example messages:
ServerSync source-of-truth enabled; local config hot reload is active.
Published local translation snapshot after debounced local config change: 2 language folder(s), 12 file(s).
Troubleshooting
- If a translation does not appear, first verify that the folder name matches the current in-game language.
- If a template does not match, compare the full rendered text, including tags, spaces, punctuation, and line breaks.
- If you expect a server overlay, make sure both server and client have this mod installed.
- Invalid JSON files or invalid template rules are logged and skipped.
- The client log will also report how many exact rules and templates were loaded for the active language.
Good use cases
- Translating hardcoded UI strings from other mods.
- Sharing a server-side translation overlay with clients for the current session.
- Reusing exact-rule translations inside templates with
localize().