UGTK cat mascotUGTKengine within an engine Request access

UGTK / Toolkit / Gameplay Systems / Language System Completed

Gameplay Systems — UGTK

Language System

Summary

The Language System manages the current language of the application in an event-driven way: no dictionaries of translations, but structs with one UnityEvent per language, invoked at Start for the language selected at startup and again every time that language gets selected. The manager itself holds a list of S_Language (id + display name + event); scene objects can react locally with Mn_LanguageEvents (list of S_LanguageEvent).


Content


Modules Dependencies


Setup

  1. Drop the LanguageManager prefab in EVERY scene (no DontDestroyOnLoad: one manager per scene). The choice survives scene changes through the shared SO_LanguageSelection asset (Data/SO_LanguageSelection.asset, already linked on the prefab): each manager reads it at Awake and writes it on every selection.

  1. Configure the languages list on Mn_LanguageManager: each entry is an S_Language (id + display name + onLanguageSelected event, e.g. it / Italiano). The event of the startup language fires at Start, and each entry's event fires when its language is selected. This is the only list you edit: Mn_LanguageEvents and Mn_LanguageText auto-sync their per-language entries from it (add a language and the matching row appears everywhere).

  1. To let the player change language with buttons, drop one LanguageSelectorButton prefab per language and set its Mn_LanguageSelector.languageId (the button OnClick is already wired to SelectLanguage()).

  1. Alternatively, a TMP/UGUI dropdown can be linked on the manager (optional path — the DropdownLanguage prefab is ready for it): the dropdown always shows the current language as its first option and reorders itself after every selection. With the Auto Find flags the manager hooks a scene dropdown by itself.

How To Use

1. Localize a text:

Add Mn_LanguageText next to a TMP text (see the TextLanguage prefab): the target text is auto-filled and the entries list automatically shows one row per manager language — you only type the translation strings. The text updates at Start (startup language) and on every language change.

2. React to the selected language (sprites, objects, whatever):

Add Mn_LanguageEvents to a GameObject: it automatically shows one S_LanguageEvent entry per manager language (ids auto-synced, don't type them) and you only wire the events. Each entry's onLanguageSelected is invoked:

NOTE: UnityEvents are not invoked while the GameObject is inactive. If the object can be inactive when the language changes, forward the call from an active manager.

3. Change language from a button:

Mn_LanguageSelector.SelectLanguage() sets the language configured in languageId on the manager. The LanguageSelectorButton prefab has the Button OnClick already wired to it.

4. Change language from code:

Mn_LanguageManager.Instance.SetLanguageById("en");
Mn_LanguageManager.Instance.SetLanguageByIndex(1);

Runtime C# notification (non-Inspector listeners):

Mn_LanguageManager.Instance.OnLanguageChanged += languageId => { /* ... */ };

5. Preview a language in Edit Mode (no Play needed):

Select the manager: its custom inspector has a Selected popup, ◀ Prev / Next ▶ cycling buttons and read-only Active Id / Active Display fields — changing the selection updates every Mn_LanguageText of the scene live:


Testing Scene

Open LanguageScene in the module's Debug/ folder and select LanguageManager. Its Current Language block cycles the language with the editor stopped: Prev and Next walk the list, and Active Id / Active Display report where you ended up.

What to do, in order:

  1. Press Next a few times. The label in the scene, the dropdown and the two readouts all move together - the dropdown is kept in sync because Dropdown Sync is wired to it.
  2. Switch while the editor is stopped, then again in Play Mode.
  3. Add a label that has no entry for one of the languages and switch to it.

Step 3 is what you are really testing: a missing translation should degrade to something readable rather than to an empty label, and an empty label in a menu looks like a broken build rather than a missing string.


Technical Info

The following are the main scripts and workflow of the Language System:

Structs: - S_Language: id + displayName + UnityEvent onLanguageSelected. One per language, in the manager's languages list (the only list you edit). - S_LanguageEvent: languageId (auto-synced) + UnityEvent onLanguageSelected, in Mn_LanguageEvents on scene objects. - S_LanguageText: languageId (auto-synced) + text, in Mn_LanguageText.

ScriptableObjects: - SO_LanguageSelection: shared asset with the player's chosen language id; read at Awake and written on every selection by each per-scene manager, so the choice survives scene changes (Data/SO_LanguageSelection.asset).

Classes&Scripts: - Mn_LanguageManager: per-scene singleton (no DontDestroyOnLoad) holding the List<S_Language> and the current selection; restores/persists it on SO_LanguageSelection; invokes the entry's onLanguageSelected at Start (startup language) and on every selection; raises OnLanguageChanged(string languageId); re-syncs Mn_LanguageEvents/Mn_LanguageText in scene when its languages list changes in editor; optional dropdown sync. - Mn_LanguageEvents: auto-synced List<S_LanguageEvent>; subscribes to the manager and invokes the matching entry (at Start and on every selection). - Mn_LanguageText: auto-synced List<S_LanguageText> + auto-found TMP target; sets the matching text at Start and on every selection (with edit-mode preview from the manager inspector). - Mn_LanguageSelector: SelectLanguage() sets its serialized languageId on the manager; meant to be wired to a Button OnClick.

Prefabs: - LanguageManager: the manager, ready to drop in every scene (SO already linked). - LanguageSelectorButton: UGUI Button + label + Mn_LanguageSelector, OnClick wired. - TextLanguage: TMP text localized via Mn_LanguageText. - DropdownLanguage: optional dropdown variant synced with the manager.


© 2026 Marcello De Bonis. All rights reserved

Real dependenciesOpen in the map →

Measured from the repository: code references (asmdef) plus prefab and asset GUIDs. Importing this module alone brings in 9 modules in total.