Localization
Localization is how your project ships in more than one language. Every project has a source locale (the language you write in) and any number of target locales you’re translating into. The editor gives you one place to see what’s translated, what’s stale, and what’s missing, and to send translation files out to a translator and merge them back in.
Two kinds of things get localized: custom strings and entity fields. Custom strings are text_* keys you define yourself; entity fields already live on a node, scene, character, or other entity. Both show up in the same view.
If your project uses ICU plurals, selects, or variable interpolation, the grammar reference lives on ICU format. Every locked term on this page is defined in the glossary.
Locales, source, and target
You configure the source locale and the list of target locales in Project Settings. Every target locale gets its own overlay. The Locale switcher in the menu bar sets the locale the editor renders in. Data View, Node Graph, Inspector, and Simulator all follow it.
The Localization Data View
Open the Data mode and pick the Localization tab.
- Coverage % column shows how much of a row is translated across all target locales.
- CUSTOM STRINGS section header groups the writer-defined
text_*keys. The Add Custom string button in the top-right creates a new one. - ENTITY FIELDS section header groups the localizable fields already living on nodes, scenes, characters, and other entities.
- Stale badge flags a row whose source text has changed since it was translated.
- Needs review badge flags a row a translator or import marked for a second pass.
Custom strings vs entity fields
Custom strings are writer-defined text_* keys not tied to any entity. Resolve at runtime via Localize(text_key). Reach for these when a piece of copy needs to live outside any node or scene, or when the same string gets used from more than one place.
Entity fields are localizable fields already on an entity, a node caption, a scene name, a character display name. The table inlines them automatically; you don’t create them explicitly, they show up because the entity has translatable text.
The inspector
The right pane is the inspector. Source text, Translator note, Max length, and one Target field per configured locale. Edits save when you click away from the field.
Coverage, Stale, Needs review
Coverage is the percentage of target-locale translations that exist for a row’s translatable fields. 0% means no target locale has been translated; 100% means every target locale has a translation for every field.
Stale flags a translation whose source text has changed since the translation was written. Clear it by opening the row and either updating the translation (the badge lifts on save) or explicitly accepting it as-is through the Stale popover.
Needs review flags a translation the translator or a re-import marked for a second pass. Clear it by editing the field, or by opening the Needs review popover and dismissing it.
ICU format
StoryBonsai uses the ICU format for plurals, selects, and variable interpolation. The full grammar lives on ICU format; this section is a quick taste.
- Translator note trigger is the notebook icon next to the Source label; click it to open the note panel.
- Source text with ICU plural markup,
{count, plural, one {# encounter} other {# encounters}}. - Localization note body, expanded to show the translator guidance you leave for whoever localizes this string.
- es-419 translation matching the plural shape.
The runtime picks the singular or plural form based on the count. The translator writes the target-locale plural forms using the same syntax.
Switching locale
The Locale switcher lives in the menu bar and sets the locale every view renders.
- Trigger label shows the current locale.
- Open dropdown lists the source locale, every target locale you’ve added, and two entries at the bottom, Add locale for a new target locale and Manage locales to open Project Settings on the localization tab.
- Coverage badge next to the trigger shows how much of the current locale is translated.
There is no per-view locale setting.
Testing translations
In the Simulator
Set the Locale switcher to a target locale, then open the Simulator. When you hit content that has no translation, the line renders with an outline.
- Translated bubble has a Spanish overlay, so the line renders normally.
- Outlined untranslated bubble has no overlay, so it falls back to the English source with a red outline.
Changing the Locale switcher swaps the locale the Simulator runs in, so the outline follows whichever target locale still has gaps. There is nothing to toggle in the Simulator itself. See simulator for the rest of the tool.
Across many runs
The Path Tester has a Locale picker on its top row. Point it at a target locale and it runs its randomized walks against that overlay, surfacing untranslated-string warnings in the issues list. See path tester for setup and reading the results.
Sending translations out
When you’re ready to hand a target locale to a translator, use File then Export Localization.
- Status picks which rows to include based on their current state: All, Stale only, or Untranslated only.
- Scope picks how much of the project the file covers: the whole project, or a single scene.
- Format picks the file layout: CSV, JSON, or XLIFF.
- Packaging picks a single file or a chunked zip.
- Save writes the file.
Between Scope and Format, the Target locales group picks which locales to export for; check one or more. Pick target locales, pick what rows to include, save the file, hand it to a translator.
Receiving translations back
When a translator sends the file back, use File then Import Localization.
- Target locale picker at the top of the dialog.
- Tab bar shows Updates, Staleness, and Orphan translations with counts.
- Staleness row with a per-item picker for the incoming translation.
- Apply button commits the merge.
Updates
Straight-through translations that didn’t clash with anything on your side. These merge on Apply.
Staleness
Rows where the source text has changed since the file was exported. Each stale row gets a per-item picker with three choices:
- Apply, mark needs review keeps the translation and flags it Needs review so a second pass revisits it.
- Apply anyway (stale) keeps the translation as-is, no flag.
- Discard throws the incoming translation away.
Orphan translations
Incoming translations for text_* keys that no longer exist in the project (the key was renamed or deleted after export). Per-item picker:
- Discard drops it.
- Keep anyway retains it in the overlay under the incoming key. Useful if you’re planning to restore the key.
See also
- icu format: the ICU format grammar the localization system understands.
- project settings: where source locale and supported target locales are configured.
- simulator: how the locale switcher affects live playback.
- path tester: running the Path Tester against a target locale to surface untranslated-string warnings across many runs.
- glossary: every locked term.
- Common pitfalls: Switching locales doesn’t change my text: the source-text fallback when a locale override is missing.
- Error messages: Template text is longer than the runtime cap: panel message when an ICU template’s worst-case substitution pushes it over the per-line cap.
- Error messages: Structural changes are locked to the source locale: panel toast when structural edits are attempted from a translation locale.