25. Localization
In short: RPG Saga Engine ships in English only. Every text goes through Unreal's localization system, so any language can be added. The Translate with AI tool exports the texts for an AI assistant, checks what comes back, merges the good translations and compiles the language. You add as many languages as you want, and the player picks one in the options.
25.1 Basics
25.1.1 What is covered
All text that goes through the plugin is localizable:
- The plugin's own texts: screens, menus, messages, the editor tools. They live in the plugin's localization target,
RPGSagaEngine(declared inRPGSagaEngine.uplugin). - The texts of your content: dialogs, quests, items, abilities, characters, documents, tutorials, bestiary entries, shops, zones and so on. They live in your project's localization target (usually called
Game).
Texts of your own systems outside the plugin use the same engine localization. The engine's Localization Dashboard still works for them.
The vocabulary of your game ("Party", "Magic", "Lv") comes from Game Terms (Project Settings → RPG Saga Engine → Game Terms), which the foundation writes. Translate the terms like any other text. A screen text of your own that should follow the terms uses the argument {Term.<Id>} (for example {Term.Party}) instead of a fixed word.
25.1.2 The workflow in one picture
Choose target + culture -> 1. Export for AI -> (paste into an AI chat) -> 2. Import -> 3. Compile
| Step | What happens | Where the files go |
|---|---|---|
| Gather | The engine's text gatherer collects every text of source and assets into the target's manifest and .po files. Once, and again after content changes. | Config/Localization/<Target>_Gather.ini |
| Export | The texts (by default only those without a translation) are written in chunks of AI size, with a ready prompt and a glossary of your content names. | Saved/Translate/<Target>/<culture>/ |
| Translate | You paste the prompt and then one chunk at a time into any AI chat and save each answer. | .../<culture>/Translated/ |
| Import | Every entry is validated. The good ones are merged into <culture>/<Target>.po. A readable report lists the rest. | .../<culture>/Report.md |
| Compile | The engine's import and compile steps turn the .po into .archive and .locres files the game loads. | Content/Localization/<Target>/<culture>/ |
25.1.3 Your first language, step by step
Open RPG Saga Studio (or the Configurator) and go to Tools → Content Import. Scroll to Languages (Translate with AI).
- Choose the target. The list holds your project's targets and the plugin's (
RPGSagaEngine). Your own target is the default. If your project has none, press Create target. It writes the four gather configs (Config/Localization/Game_Gather.iniand its Export, Import and Compile partners). The name, the source culture and the folders it gathers assets from are in Project Settings → RPG Saga Engine → Translate with AI. - Gather texts. The button collects the target's texts. It runs in a separate editor process because it loads your assets. Skip it for the plugin's own target: its English texts are already gathered.
- Type the culture code:
ro,de,fr,es,pt-BR,ja. - 1. Export for AI, then Open pack folder. The folder holds:
PROMPT.md: the instructions for the AI;Chunk_001.json,Chunk_002.json, and so on: the texts, a few thousand characters per file. Each entry has its id, the source text, where it is used, a length limit, the placeholders and the plural categories the language needs;Glossary.csv: the names of your content, so the AI uses them consistently;Pack.json: what the import checks the answers against;Translated/: where the answers go.
- Translate. In an AI chat that handles long text:
- paste
PROMPT.mdas the first message; - paste
Chunk_001.jsonas the second message. The answer is the same JSON with thetranslationfields filled in; - save the answer as
Translated/Chunk_001.json(code fences from the chat are ignored); - repeat for each chunk. Open a new chat, or paste the prompt again, if the assistant starts to drift or shorten.
- paste
- 2. Import. Leave Answers empty to read the
Translatedfolder, or pick files. The report shows every problem with its id and text. Validate only checks without writing anything. - Fix. With problems, open
Report.md. The entries that need another pass are inRetry.json. Paste it into the same chat with the prompt and import the new answer. Importing again is safe: good entries stay. - 3. Compile. The
.locresis written, and the culture is added to Project Settings → Packaging → Localizations to Package and to the options menu. Test it in the editor with the console commandRSE.Language ro.
Do the same once for the plugin's own target (RPGSagaEngine) to translate the built-in screens and messages. It is a separate target with its own culture folder, which the tool creates.
25.1.4 How the player picks a language
The game starts in the project's default language, English unless you change Options → Default Language. The player chooses a language in Options → Game → Language, or you pass -culture=xx on the command line. The list shows every culture compiled for any target (the plugin's, your project's, yours), each by its native name ("Français"). Project Settings → RPG Saga Engine → Options → Languages is an optional allow-list: empty means all compiled cultures. Switching language changes the plugin's texts and your content's texts together. The choice is saved with the other options.
25.2 How it works
25.2.1 The prompt
PROMPT.md is generated for your project and culture. In short it tells the AI:
- translate the texts of the target from the source culture into the culture, one chunk per request, with the same glossary and tone throughout;
- answer with only the same JSON,
translationfilled in for every entry, never dropping or adding entries; - keep every placeholder exactly:
{Name},{0}, markup such as<em>..</em>,<color=Name>and</>, and the dialog directives ({p=0.5},{speed=..}..{/speed},{cue=N}). The entry'splaceholderslist is the set that must appear; - rewrite plural blocks
{N}|plural(one=card,other=cards)with the target language's plural categories, always keepingotherand keeping{N}before|plural; - respect each entry's
maxLen, use the glossary names, never translate asset ids, and keep each dialog speaker's voice (the entry'scontextsays where the text is used); - leave the do-not-translate terms alone (
HP,MP,ATBby default) and use no terms from other games.
For a language that needs more plural forms (some need one, few, other, others one, few, many, other, Arabic needs six), the prompt and each entry say which categories are required, and the import rejects a text that lacks one.
25.2.2 What the import checks
| Check | Result |
|---|---|
| Placeholders and markup: the same set as the source (order may change) | error |
| Plural blocks: same count, same argument, every category the language needs | error if missing, warning if extra |
| Ids: an id the target does not have; two different answers for one id | warning (extra), error (duplicate) |
| Ids a chunk had to return and did not | error |
| Encoding: replacement characters, byte order marks, control characters, UTF-8 read as another encoding | error |
| Length: longer than the entry's limit | warning (a setting) |
| Looks untranslated: identical to a source with real words | warning (a setting) |
| Leading or trailing spaces that differ from the source | warning (a setting) |
| A do-not-translate term that disappeared | warning |
| Empty translation | warning, and the text stays untranslated |
What happens to entries with errors is the Invalid Policy setting:
- Skip Invalid Entries (default): good entries are merged, bad ones stay untranslated and are listed in the report and in
Retry.json; - Reject Import: one error stops the whole import and nothing is written (good for a CI gate);
- Keep Invalid Entries: everything is merged and the errors are only reported.
The compile step also rejects malformed {Argument} patterns, so a broken placeholder never reaches the game. The checks guard the structure, not the quality of the prose. Review the first chunks yourself or with a native speaker.
25.2.3 Formats
- JSON (default): one object per text with context. Best for AI chats.
- CSV: columns
id, source, context, maxLen, placeholders, plural, glossary, translation. Opens in a spreadsheet, for human translators. Fill thetranslationcolumn. - PO: the engine's
.polayout for each chunk, with the limit and placeholders as comments. The import readsmsgstr.
The import reads all three whatever the export format was.
25.3 Key classes and assets
| Class / asset | Module | Role |
|---|---|---|
URSETranslateSettings | RSEEditor | Project Settings → RPG Saga Engine → Translate with AI. All the options below. |
URSETranslateLibrary | RSEEditor | Blueprint and Python functions for every step. |
URSETranslateCommandlet | RSEEditor | The -run=RSETranslate command line for CI. |
RPGSagaEngine target | plugin | The plugin's own localization target (Config/Localization/RPGSagaEngine_*.ini). |
Game target | your project | Your content's target, made by Create target. |
| Game Terms | RSECore | The vocabulary used on every screen. |
There are no data assets to create. Translations are the engine's .po, .archive and .locres files.
25.4 Settings
Project Settings → RPG Saga Engine → Translate with AI (saved in Config/DefaultEditor.ini):
- Target: Target Name (empty means your project's first), New Target Name and New Target Native Culture for a created target, and the folders it gathers assets from.
- Export: output folder, Format (JSON, CSV or PO), only untranslated texts, Max Entries Per Chunk (120) and Max Chars Per Chunk (12000), the glossary and Max Glossary Terms In Prompt, Do Not Translate (
HP,MP,ATB), and whether dialog speakers are looked up in the assets. - Length: the limit is the source length times Max Length Factor (1.5), a smaller Short Text Factor (1.3) for short labels, and a few characters always allowed.
- Validation: the severity of each warning above, Invalid Policy, and the minimum number of letters before an identical text counts as untranslated.
- Compile: Register Culture adds the compiled culture to packaging and to the options menu.
At run time, Project Settings → RPG Saga Engine → Options has Default Language (en) and the Languages allow-list. See Appendix B for every property.
25.5 Blueprint usage
The translation steps are editor-only functions in RPG Saga Engine|Translate, meant for Editor Utility Blueprints and Python: Get Targets, Get Default Target, Create Target, Gather, Export For AI, Import From AI, Compile and Get Translated Fraction. Each returns a result with success, a summary and the error and warning counts.
An Editor Utility Widget that translates a language end to end:
- Add a text box for the culture and a button.
- On the button: Get Default Target → Export For AI (Target, Culture).
- After the answers are saved (a second button): Import From AI (Target, Culture, an empty file list, Validate Only false) → check Success → Compile.
- Show Get Translated Fraction as a progress bar.
In a running game, switch language with the engine's own nodes (for example Set Current Culture), or let the player use the options menu.
25.6 C++ usage
Use LOCTEXT or NSLOCTEXT for every player-facing string, and FText::Format with named arguments, so the gatherer finds them and translators can reorder words:
#define LOCTEXT_NAMESPACE "MyGame.Reputation"
FText Msg = FText::Format(LOCTEXT("Praised", "{Town} thinks highly of you. Standing: {Points}"),
FText::FromName(TownName), FText::AsNumber(Points));
#undef LOCTEXT_NAMESPACE
Never build sentences by joining strings. Use a plural block for counts, {N}|plural(one=card,other=cards). For the game's own vocabulary, format a pattern with RSEGameTerms::Format so {Term.<Id>} arguments are filled.
The same steps from the command line, for build machines:
UnrealEditor-Cmd Project.uproject -run=RSETranslate -List
UnrealEditor-Cmd Project.uproject -run=RSETranslate -Target=Game -Gather
UnrealEditor-Cmd Project.uproject -run=RSETranslate -Target=Game -Culture=ro -Export [-Format=json|csv|po] [-All] [-Out=<dir>]
UnrealEditor-Cmd Project.uproject -run=RSETranslate -Target=Game -Culture=ro -Import [-File=<file|dir>[+...]] [-ValidateOnly] [-Policy=reject|skip|keep]
UnrealEditor-Cmd Project.uproject -run=RSETranslate -Target=Game -Culture=ro -Compile
UnrealEditor-Cmd Project.uproject -run=RSETranslate -CreateTarget=Game -Native=en
Steps run in the order Gather, Export, Import, Compile. The exit code is 0 when no step reported an error (a validation error of an import counts), so a pipeline can run -Import -Policy=reject on a pull request that brings translations.
From Python:
import unreal
lib = unreal.RSETranslateLibrary
print(lib.get_targets())
lib.gather("Game")
r = lib.export_for_ai("Game", "ro") # r.folder, r.num_entries
r = lib.import_from_ai("Game", "ro", [], False) # [] = the Translated folder; True = validate only
print(r.summary, r.report_path)
r = lib.compile("Game", "ro")
25.7 Advanced
- Translate the plugin's target once per language. It holds the built-in screens and messages. If the plugin is installed in the engine (a Fab install), copy it into your project's
Pluginsfolder first, so the translation files are written inside your project and travel with it. - Re-export after content changes. Only new and changed texts are exported. A text whose source changed counts as untranslated again.
- Keep names consistent in a long game. Fill the Translation column of
Glossary.csvonce and paste the table at the top of each chat. - Long languages. A language with many plural forms or long words (German, Russian) may need a higher length factor.
- Human translators. Export CSV, give them the sheet, and import the same file back. The checks still run.
- A different AI pack. Content Import → Export AI pack also writes a plain Translate prompt for a
.pofile. For a real translation use the Languages page, which adds the chunking, the context, the length limits and the validation. - Voice and dialog labels. Dialog nodes keep stable labels, so translations and voice recordings stay attached when the script is edited later.
- CI gate. Run
-Import -Policy=rejectin your build so a broken translation never merges.
25.8 Troubleshooting
| Symptom | Cause and fix |
|---|---|
| The game shows English although I chose another language | The game starts in English until the player picks a language (or you pass -culture=xx). The list offers only cultures with a compiled translation. Packaged games need the culture in Packaging → Localizations to Package. In the editor, RSE.Language <culture> switches while you play. |
| Editor or menu texts are English only | The plugin ships in English. Translate its own target, RPGSagaEngine, with Translate with AI. |
| A screen shows the wrong word for "Party", "Magic" or "Lv" | The vocabulary comes from Game Terms. A screen text typed as a fixed word does not follow the terms. Use {Term.<Id>}. |
| The import refused my file | Read Report.md: each problem has its id and text. A missing placeholder or plural category is an error. Paste Retry.json into the chat and import the new answer. |
| The compile failed | A broken {Placeholder} pattern. Run the import with Validate only and fix the listed entries. |
| Gather finds nothing for my project | Run Create target first, and check the asset folders in Translate with AI → Target. Gather loads assets in a separate editor process. |
| The translation looks cut off | The text is longer than the entry's limit. Raise Max Length Factor, or shorten the text. The warning shows the limit. |
| Special characters look broken | The answer was saved with the wrong encoding. Save it as UTF-8. The import reports replacement characters and mis-read UTF-8 as errors. |
25.9 See also
- Editor tools: the AI workflow for content, and where Content Import lives.
- Story, dialog and quests: dialog text, speakers and labels.
- Game foundation and archetypes: Game Terms.
- User interface: the options menu.
- Product page:
docs/product/localization.md.