UGTK / Toolkit / Gameplay Systems / Language System Completed
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
UGTK.DesignPattern.Singleton(Mn_LanguageManager is a singleton)UGTK.UIModule.DropdownExtension(optional dropdown sync)
Setup
- Drop the
LanguageManagerprefab in EVERY scene (no DontDestroyOnLoad: one manager per scene). The choice survives scene changes through the sharedSO_LanguageSelectionasset (Data/SO_LanguageSelection.asset, already linked on the prefab): each manager reads it at Awake and writes it on every selection.
- Configure the languages list on
Mn_LanguageManager: each entry is anS_Language(id + display name +onLanguageSelectedevent, 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_LanguageEventsandMn_LanguageTextauto-sync their per-language entries from it (add a language and the matching row appears everywhere).
- To let the player change language with buttons, drop one
LanguageSelectorButtonprefab per language and set itsMn_LanguageSelector.languageId(the button OnClick is already wired toSelectLanguage()).
- Alternatively, a TMP/UGUI dropdown can be linked on the manager (optional path — the
DropdownLanguageprefab is ready for it): the dropdown always shows the current language as its first option and reorders itself after every selection. With theAuto Findflags 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:
- at
Start, for the language selected at startup; - every time that language gets selected afterwards.
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:
- 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.
- Switch while the editor is stopped, then again in Play Mode.
- 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
Used by 1
Measured from the repository: code references (asmdef) plus prefab and asset GUIDs. Importing this module alone brings in 9 modules in total.
UGTKengine within an engine

