CalmUI
Localization

Translate Your UI

Declare text defaults, inspect project translations and check languages without changing the game.

Add text with a default

Open a View in Studio. In a text prop, type $loc or use / → Localization → Text…. Choose an existing key or New translation, then enter its key and default. A key identifies the same text everywhere in the project.

Studio highlights $loc as a compiler expression, even inside a quoted attribute: the call is purple, the translation key cyan, and the default text uses the normal string color. Interpolations and bound props use the same highlighting.

For a component that exposes label and description, use:

<Button
  label="$loc('GameUI::MainMenu.Continue', 'Kontynuuj')"
  description="$loc('GameUI::MainMenu.ContinueDescription', 'Wróć na swoją wyspę')"
/>

Inside Button, display ordinary props:

<span>{{ props.label }}</span>
<span>{{ props.description }}</span>

Use props for text. Keep slots for icons and nested components. The same declaration works without a component:

<p>{{ $loc('GameUI::MainMenu.LastGame', 'Ostatnia gra') }}</p>
<input placeholder="$loc('GameUI::Search', 'Szukaj')" />

Both arguments must be literal strings. Dynamic keys are not supported, and $loc is compiler syntax, not JavaScript. A script's loc() (below) accepts the same literal key/default and adds runtime {name} parameters; pluralization is still not supported anywhere in CalmUI. Use single quotes inside a double-quoted attribute. Escape an apostrophe with \'; an embedded double quote can be written as \u0022.

Without a translation or compatible Unreal connection, the authored default appears immediately. The key is never used as replacement text. These declarations do not create or update Unreal assets.

Localize text from a script

Inside <script lang="ts">, call loc('GameUI::MainMenu.LastSave', 'Last save: {minutes} min ago', { minutes }) instead of $loc. The key and fallback must still be literal strings; the optional third argument supplies {name} values substituted into the resolved text. It resolves through the same translation, and the same Localization Test pseudo-localization mode, as a template $loc expression, so a computed built from loc() and a <span>{{ $loc(...) }}</span> in the same View stay consistent under every culture and preview mode.

Review the project's required texts

Open Languages in Studio's left activity bar. The list includes unopened Views and components. Search keys or defaults, or filter missing translations and conflicting defaults. A key declared only inside a script's loc() call is listed the same way, badged script, next to any $loc declarations for the same key; a different default between the two is a conflict like any other.

Select a row to see its key, default and references. Click a reference to open the originating declaration in the editor, including when a prop passes through several components.

Editing a key or default and choosing Apply to all … references updates all occurrences in one source-edit batch. Unsaved buffers are included. Use Undo to reverse the batch. Save the affected files normally afterward. If references changed since selection, select the row again before applying.

Different defaults for one key are a conflict. Choose the common default before applying. Renaming to an already existing key is rejected instead of silently merging unrelated entries.

Prepare translations in Unreal

For GameUI::MainMenu.Continue, load/register the Unreal String Table with ID GameUI and an entry named MainMenu.Continue. In Unreal's Localization Dashboard, include those source texts in the game localization target, gather the texts, provide translations and compile the target.

Set the native language of that target to match your source text. GameUI uses Polish; its calmui.config.json contains "sourceCulture": "pl". Other projects default to en when that setting is omitted.

Make the String Tables available when the screen loads. Keep compiled localization resources in the project's configured localization paths. Select the required languages under Unreal's packaging settings, and include fonts that cover their characters. Preparing these resources is an Unreal workflow; Languages does not edit them.

Check Culture without changing the game

Connect Studio to a compatible Unreal plugin. Localization Culture in Languages and Studio Culture in Preview use the same selection. The list contains project resource languages, configured packaging languages and the source language, not every language known by the engine. Languages without compiled resources are marked in the list.

The selection changes the Studio canvas only. It does not change the game or Editor language, even temporarily. An Unreal-rendered preview continues to use the game's current language.

StatusMeaning
Translation existsA translation exists for the selected culture
Inherited translationA parent culture supplies it; the origin is shown
Source textSource text/default, not a found translation
Missing translationThe connected catalog has no matching translation
Not checkedDisconnected, incompatible plugin, or failed query

A translation identical to its default is still a translation. Unreal's fallback display string is not evidence that a translation exists.

After compiling translation resources, click Refresh translations. Results are cached for the connection, culture and observed text revision. Disconnecting clears the results and returns Preview to its defaults.

Use Localization Test → Expanded Text or Pseudo-localized to find text that no longer fits. These modes transform defaults for layout checks; they do not create translations.

Expected result

Offline, the button shows Kontynuuj. After connecting and selecting a culture with a compiled translation, Studio displays that translation and Languages shows its status and value. Selecting another culture does not change Unreal's current language.

If a value is missing, check the exact String Table ID and entry, whether the table is loaded, whether resources are compiled and whether the requested culture was packaged. For old source syntax, see project migration.

On this page