← Back to portfolio
Unity Editor Tool

Language Translation Plugin

A ScriptableObject-based localization system with a dedicated editor for managing translations without touching code.

Unity C# ScriptableObject Custom Editor
Overview
Why this tool exists

Built after manually editing translation strings across scenes got tedious enough to be worth automating. All translations live in a single ScriptableObject asset, editable through a dedicated editor window — adding a language, adding a category, or updating a line never requires touching code.

Any UI text component references a translation by key. At runtime, a small lookup layer resolves that key to the currently selected language and keeps it updated if the language changes while the game is running.

Type
Editor Tool
Engine
Unity
Language
C#
Status
Used in production
Core
ScriptableObject
Editor
Custom window
System
Structure

Everything is stored in one asset: a list of language codes, a list of categories, and a list of keys. Each key holds a category and one phrase per language. Categories are purely organizational — they exist to filter and group keys in the editor, and carry no runtime meaning.

At startup, the data asset is compiled into a flat runtime dictionary keyed by translation key, with a phrase per language underneath. Text components look up their key against the currently selected language index and fall back to displaying the key itself if no translation is found, so a missing entry shows up as visibly wrong text rather than breaking the UI.

Runtime binding and language switching

A single component links a UI text element to a translation key: on start it resolves and displays the current phrase, and it subscribes to a language-changed event so it updates automatically whenever the active language is switched — including while in Play mode, with no reload required. Switching language is a single call and fires that event for every subscribed text element at once, so an entire scene's UI updates in one frame.

Editor Tools
Translation editor

The main editor window opens from the tools menu and also reacts to selecting a translation asset in the project view, auto-loading it. Its toolbar holds an asset picker, a live search field that matches against key, category, and phrase text, an add-key button, and a shortcut into the settings window.

Below the toolbar, a row of category toggles filters the key list — any combination can be active at once, and leaving all of them off shows every key. The key list itself is a scrollable set of entry blocks, one per key: a category dropdown, an editable key field that highlights in red on a duplicate, a delete button with a confirmation step, and one text area per language. Empty phrases are tinted so missing translations are visible at a glance while scanning the list, and fields lighten on hover to make the currently focused row easier to track.

Editing goes through Unity's standard undo and dirty-marking, so changes can be undone and are never lost on domain reload. The window also self-repaints at a modest fixed rate while the mouse moves or a field is being edited, keeping the highlighting responsive without repainting constantly when idle. A duplicate-key cache is kept up to date as entries change rather than being recomputed on every repaint.

Settings window

A separate window handles the two things that apply to the whole asset rather than to a single key: the language list and the category list. Each is shown as a reorderable list — entries can be renamed in place, moved up or down, removed, or added — and both changes propagate immediately: renaming or reordering languages resyncs every key's phrase list to match, and renaming a category updates every key that referenced it.

Whenever the asset is touched, a validation pass runs automatically: it guarantees at least one language and one category exist, resets any key left with an empty or deleted category back to a default, and fills in a blank phrase for any language a key doesn't yet have — so the data asset can never end up in a state the editor can't display.

Workflow
Putting it together

1. Create a translation data asset from the project menu.
2. Open the translation editor and, from settings, add the languages and categories the project needs.
3. Add keys from the editor's add-key button, or directly from a text component's context menu, which registers the key against the asset automatically.
4. Fill in a phrase per language for each key, directly in the editor.
5. Attach the binding component to any UI text element and set its key.
6. At runtime, switch languages with a single call — every bound text element updates immediately.

Extensibility
Adapting to a project

The core — the data asset, the runtime dictionary, and the language-changed event — is intentionally minimal and stays fixed regardless of project size. Everything project-specific hangs off that core rather than inside it. A new language or category is a one-line addition in settings; the system does not care how many of either exist.

The binding layer is a single small component following one pattern (hold a key, redraw on the language-changed event), so supporting a different UI text system, a custom text widget, or several bound elements sharing one key is a matter of writing an equivalent component rather than modifying the core. The same event is a natural hook for anything else that should react to language changes — swapping a font or TMP font asset per language, or playing a matching voice-over clip when a line is shown — without the core needing to know those features exist.

Because the data lives in one plain asset, importing or exporting it through an external format for outside translators, or pulling it from a different source such as a spreadsheet, only requires a conversion step that fills the same asset — the editor and runtime need no changes to support it.

Results & Source
Screenshots, video, code

— placeholder — add screenshots of the editor window, a short demo clip, and a link to the source repository here.