You are viewing a potentially older version of this package. View all versions.
Paxton0505-Localization-1.2.0 icon

Localization

Runtime translation/localization helper for Valheim mods.

Date uploaded 2 months ago
Version 1.2.0
Download link Paxton0505-Localization-1.2.0.zip
Downloads 24
Dependency string Paxton0505-Localization-1.2.0

This mod requires the following mods to function

denikson-BepInExPack_Valheim-5.4.2333 icon
denikson-BepInExPack_Valheim

BepInEx pack for Valheim. Preconfigured with the correct entry point for mods and preferred defaults for the community.

Preferred version: 5.4.2333
ValheimModding-Jotunn-2.29.0 icon
ValheimModding-Jotunn

Jötunn (/ˈjɔːtʊn/, 'giant'), the Valheim Library was created with the goal of making the lives of mod developers easier. It enables you to create mods for Valheim using an abstracted API so you can focus on the actual content creation.

Preferred version: 2.29.0
ValheimModding-JsonDotNET-13.0.4 icon
ValheimModding-JsonDotNET

Shared version 13.0.3 of Json.NET from Newtonsoft, net45 package for use in Valheim mods. Maintained by the ValheimModding team.

Preferred version: 13.0.4

README

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.
  • Re-runs rewritten text through the rule engine so an English baseline alias can normalize non-English hardcoded text before the active language translation is applied.
  • 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

Before

After

Install

  1. Install the mod from Thunderstore. The declared dependencies are installed automatically: BepInExPack_Valheim, Jotunn, and JsonDotNET.
  2. If you install manually, place Localization.dll in BepInEx/plugins.
  3. Launch the game once so the config folders are created.
  4. Create one or more rule files under BepInEx/config/com.paxton0505.localization/<LanguageCode>/.
  5. 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}}.
  • If a rule rewrites the full string into another matchable string, the plugin evaluates the rewritten result again until it stabilizes.
  • 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:

  1. Exact rules loaded by this plugin, including chained exact aliases.
  2. Valheim's own localization table.
  3. The rewritten result is checked against the plugin's exact rules again.
  4. 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.

Chained normalization through English

The runtime can safely apply more than one translation pass to the same intercepted string.

This means you can use the optional English layer as a normalization step for hardcoded text from another language, then let the active language layer translate that normalized English text into the final target language.

Example with Chinese_Trad active:

BepInEx/config/com.paxton0505.localization/English/core.json

{
  "exact": [
    {
      "match": "Packesel",
      "replace": "Pack horse"
    }
  ],
  "templates": []
}

BepInEx/config/com.paxton0505.localization/Chinese_Trad/core.json

{
  "exact": [
    {
      "match": "Pack horse",
      "replace": "馱馬"
    }
  ],
  "templates": []
}

The displayed string can now flow as Packesel -> Pack horse -> 馱馬 in one UI interception pass.

Looped mappings are cut off safely, so the chain stops if rules start cycling.

Load order and precedence

When a non-English language is active, the layers are applied from baseline to highest override in this order:

  1. Local English files.
  2. Synced English files from the server.
  3. Local active-language files.
  4. 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().

CHANGELOG

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[v2.0.1] - 2026-05-16

Fixed

  • Fixed the devtools Playground rebuild flow so rebuilding the page clears stale UI references instead of reusing dead controls, and clicking a scrollable input field now re-activates the underlying InputField so text entry keeps working after scrolling.

[v2.0.0] - 2026-05-16

Added

  • Added the built-in in-game Localization devtools overlay with Plugin, Performance, Trace, Browser, and Playground pages for live inspection and rule drafting.
  • Added root-level plugin localization catalogs (Localization-English.json and Localization-Chinese_Trad.json) with hot reload so overlay labels, plugin-owned UI strings, and fallback log text can be localized separately from mod translation rules.
  • Added runtime performance metrics, translation-analysis views, and rule-browser snapshots for loaded local and ServerSync rule files.
  • Added trace_feed_max_entries, devtools_enabled, and devtools_toggle_shortcut to BepInEx/config/com.paxton0505.localization/config.yaml, with Ctrl + F1 as the default devtools toggle in the UI.

Changed

  • config.yaml hot reload now also updates trace-feed capacity and the devtools overlay enable/shortcut state without restarting the game.
  • Root-level plugin localization files are now auto-generated and hot-reloaded alongside the language rule folders.
  • Updated the repository README and Thunderstore README to document the built-in devtools overlay, plugin-owned localization files, live runtime settings, and current Thunderstore packaging output.

Removed

  • Removed the unused DevToolsSectionedPage scaffold left over from earlier devtools layout experiments.

[v1.3.0] - 2026-05-14

Added

  • Added translation_enabled: true as the top-most runtime setting in BepInEx/config/com.paxton0505.localization/config.yaml.
  • Added deterministic validate-artifact workflow support for the translation agent, plus restored Python/runtime checks around sanitizer and artifact validation behavior.
  • Added an optional runtime settings file at BepInEx/config/com.paxton0505.localization/config.yaml with debug: false by default.
  • Added configurable whole-string longest-match exact replacement restrictions through whole_string_longest_match_mode and whole_string_longest_match_min_length in config.yaml.
  • Added constrained template placeholders for word, words(...), int(...), float(...), and oneof(...), including numeric where= predicates such as >0 && <10.

Changed

  • When translation_enabled: false, the runtime now bypasses UI translation and skips rule reloads until translation is enabled again.
  • Clarified that translation_enabled, debug, and other runtime knobs remain local client-side settings even when translation rules are synced through ServerSync.
  • Restored rich-text tag stripping for exact, template, and whole-string longest-match exact replacement while keeping OrdinalIgnoreCase behavior.
  • Normalized exact and template matches now re-apply only the outer tags immediately wrapping the matched visible span. Whole-string longest-match exact replacement keeps only the full string's outermost tags; internal word-level tag positions are not remapped.
  • Whole-string longest-match exact replacement now defaults to per_word mode, and runtime changes to its restriction settings immediately clear translation caches.
  • Updated the repository README and Thunderstore README to document tag-stripped matching with outer-tag reapplication.
  • Refreshed the repository README and Thunderstore README to document the current project layout, validation commands, runtime toggle behavior, and ServerSync hot reload semantics.
  • Signed int and float constrained placeholders now accept optional leading + or - by default, with further numeric filtering available through where= predicates.
  • When debug: true is enabled, the plugin now logs intercepted UI strings before translation, rule-file load details, cache hits and miss-cache hits, winning match stages, placeholder resolution, and loop or duplicate diagnostics.

[v1.2.3] - 2026-05-13

Added

  • Added normalized exact-rule matching for all translation hops by stripping rich-text tags from match input and comparing exact rules with OrdinalIgnoreCase.
  • Added normalized template matching so template literals also compare against tag-stripped input case-insensitively.

Changed

  • Matched output now always comes from the rule replace value, so intercepted source tags are not re-applied after translation.
  • Active-language translation hops now participate in the same relaxed normalized matching instead of limiting ignore-case behavior to the English bridge layer.
  • Updated the repository README and Thunderstore README to document normalized matching, tag stripping, and replace-first rendering behavior.

[v1.2.1] - 2026-05-13

Added

  • Added an English-only OrdinalIgnoreCase exact-rule fallback so English baseline normalization can still bridge casing variants such as PACKHORSE -> PackHorse -> 馱馬.

Changed

  • Kept active-language exact rules and all template matching case-sensitive, limiting ignore-case behavior to the English exact normalization layer.
  • Updated the repository README and Thunderstore README to document the new English-only ignore-case fallback and its scope.

[v1.2.0] - 2026-05-13

Added

  • Added chained runtime translation passes so one intercepted string can flow through multiple rule matches, such as German hardcoded text -> English baseline alias -> Chinese_Trad active translation.
  • Added chained exact-rule resolution for {{localize(...)}} template placeholders so placeholder values can also normalize through English aliases before landing on the final target language.

Changed

  • Updated the repository README and Thunderstore README to document chained translation behavior, English normalization patterns, and the new placeholder resolution flow.

[v1.1.1] - 2026-05-13

Changed

  • Lowered duplicate exact-rule and template-rule diagnostics from error level to debug level. Later duplicate definitions are still ignored, but they no longer surface as load errors.
  • Expanded the Thunderstore README into a fuller usage guide covering installation, config layout, rule format, load precedence, server/client behavior, and hot-reload details.
  • Reformatted this changelog to the Keep a Changelog structure.

[v1.1.0] - 2026-05-13

Added

  • Server-side hot reload logs so dedicated server config updates now show when a debounced snapshot is republished.
  • Debounced config file watcher reloads so rapid JSON saves only publish one local snapshot.
  • ServerSync-based session overlays so clients can receive the server's localization JSON tree without rewriting local files.
  • Remote/local layered rule merging so synced rules can override the local English and active-language files in a predictable order.

Changed

  • Dedicated servers now run in sync-only mode and skip the local translation runtime plus UI Harmony patches.
  • Bundled ServerSync into the plugin build and updated the release/docs for the new sync flow.

[v1.0.4] - 2026-05-13

Fixed

  • Fixed the release zip output and cleaned up the Thunderstore packaging flow.

Changed

  • Polished release metadata and trimmed package assets/docs for distribution.

[v1.0.3] - 2026-05-13

Changed

  • Optimized template rule dispatch and loading performance.

Added

  • GitHub Copilot-assisted translation workflow, prompts, agents, and Python tooling.
  • Recorded mod version metadata in the translation workflow and reorganized Thunderstore release files.

[v1.0.2] - 2026-05-10

Added

  • Thunderstore packaging basics including manifest and icon assets.

Changed

  • Refined the project/build setup and refreshed the README for initial release packaging.

[v1.0.1] - 2026-05-10

Added

  • Split the initial implementation into focused runtime, loader, template, and interception components.
  • Added exact/template rule loading, placeholder handling, and final UI text interception.

[v1.0.0] - 2026-05-10

Added

  • Initial project scaffolding, BepInEx plugin entry point, build file, and README.
  • First working prototype of the runtime localization plugin.