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.

  1. Coverage % column shows how much of a row is translated across all target locales.
  2. CUSTOM STRINGS section header groups the writer-defined text_* keys. The Add Custom string button in the top-right creates a new one.
  3. ENTITY FIELDS section header groups the localizable fields already living on nodes, scenes, characters, and other entities.
  4. Stale badge flags a row whose source text has changed since it was translated.
  5. 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.

  1. Translator note trigger is the notebook icon next to the Source label; click it to open the note panel.
  2. Source text with ICU plural markup, {count, plural, one {# encounter} other {# encounters}}.
  3. Localization note body, expanded to show the translator guidance you leave for whoever localizes this string.
  4. 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.

  1. Trigger label shows the current locale.
  2. 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.
  3. 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.

  1. Translated bubble has a Spanish overlay, so the line renders normally.
  2. 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.

  1. Status picks which rows to include based on their current state: All, Stale only, or Untranslated only.
  2. Scope picks how much of the project the file covers: the whole project, or a single scene.
  3. Format picks the file layout: CSV, JSON, or XLIFF.
  4. Packaging picks a single file or a chunked zip.
  5. 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.

  1. Target locale picker at the top of the dialog.
  2. Tab bar shows Updates, Staleness, and Orphan translations with counts.
  3. Staleness row with a per-item picker for the incoming translation.
  4. 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

Docs last synced: 2026-07-08
Screenshot viewer