Localization
Loreline has built-in support for translating your scripts into multiple languages.
How it works
Localization in Loreline follows three steps:
- Tag translatable text with
#keyhash comments in your script. - Create a translation file (
.lang.lor) for each target language. - Load the translation file at runtime and pass it to the interpreter.
The interpreter looks up each #key at runtime and replaces the original text with the translated version. If a key has no translation, the original text is used as a fallback.
Tagging text for translation
You don't have to add these keys by hand. The CLI can generate them automatically. See Using the CLI below.
To mark text for translation, add a #key hash comment after any translatable element. Three types of content can be tagged:
Text statements (narrative):
"The cafe smells wonderful." #intro
Dialogue (character speech):
barista: "Welcome! What can I get you?" #welcome
Choice options:
choice
Espresso #opt-espresso
Latte #opt-latte
Keys can be any combination of letters, digits, hyphens, and underscores, for example #intro, #opt-espresso, or #chapter2_greeting.
Literal hash characters
If you need a literal # in your text, use ## (doubled) or \# (escaped):
This has a literal ##hashtag in text.
barista: "Use \#escaped for literal hash."
Full example
Here's a complete script with localization keys:
character barista
name: Alex
beat Menu
"The cafe smells wonderful." #intro
barista: "Welcome! What can I get you?" #welcome
choice
Espresso #opt-espresso
barista: One espresso! #espresso-reply
Latte #opt-latte
barista: One latte! #latte-reply
Worried about readability? In the VS Code extension, press
Cmd+Shift+H(Mac) orCtrl+Shift+H(Windows/Linux), or use the command palette, to hide all localization keys so they never get in the way of reading or writing your script. The Playground on this website also has this option.
Translation files
Translation files use the naming convention Filename.lang.lor, for example CoffeeShop.fr.lor for French or CoffeeShop.de.lor for German.
Each entry in a translation file consists of:
- A
#keyfollowed by//and the original text as reference - The translated text on the next line
Here's the French translation for the example above (CoffeeShop.fr.lor):
#intro // "The cafe smells wonderful."
Le café sent très bon.
#welcome // "Welcome! What can I get you?"
Bienvenue ! Qu'est-ce que je te sers ?
#opt-espresso // Espresso
Expresso
#espresso-reply // One espresso!
Un expresso !
#opt-latte // Latte
Latté
#latte-reply // One latte!
Un latté
The // comment on each key line is there for reference only. The interpreter ignores it. Translators can see the original text without needing to open the source file.
Using the CLI
The loreline translate command automates the localization workflow. It can generate keys, create translation files, and clean up.
Auto-generate keys
If your script doesn't have #key tags yet, the CLI can add them automatically:
loreline translate CoffeeShop.lor --auto-ids
This scans all text, dialogue, and choice nodes in the script and inserts random keys (like #a7k2m) on any line that doesn't already have one. Your existing comments and formatting are preserved.
Generate a translation file
To create or update a translation file for a specific language:
loreline translate CoffeeShop.lor --lang fr
This creates CoffeeShop.fr.lor with all translatable entries. If the file already exists, existing translations are preserved and new entries are added.
Remove keys
To strip all #key hash comments from a source file:
loreline translate CoffeeShop.lor --clear
Typical workflow
# 1. Add keys to your script
loreline translate CoffeeShop.lor --auto-ids
# 2. Generate a French translation file
loreline translate CoffeeShop.lor --lang fr
# 3. Edit CoffeeShop.fr.lor, replace each placeholder with the French text
# 4. Add more languages as needed
loreline translate CoffeeShop.lor --lang de
loreline translate CoffeeShop.lor --lang es
When you add new text to your script, run --auto-ids again to tag the new lines, then --lang fr to update the translation file. Existing translations won't be overwritten.
Interpolation in translations
Translations work seamlessly with text interpolation. Variables like $count or ${expression} are preserved in the translation file and evaluated at runtime:
Source script:
state
count: 3
beat Start
You have $count items #item-count
barista: You ordered $count drinks #drink-reply
Translation file (Story.fr.lor):
#item-count // You have $count items
Vous avez $count articles
#drink-reply // You ordered $count drinks
Vous avez commandé $count boissons
At runtime, $count is replaced with its current value (3), producing "Vous avez 3 articles".
Loading translations at runtime
To use translations in your application, parse the translation file and pass the extracted translations to the interpreter. Here's a JavaScript example:
import { Loreline } from 'loreline';
// Parse the main script
const script = Loreline.parse(sourceContent);
// Parse the translation file
const translationScript = Loreline.parse(frenchContent);
const translations = Loreline.extractTranslations(translationScript);
// Play with French translations
Loreline.play(script, onDialogue, onChoice, onFinish, {
translations: translations
});
The same pattern applies in all supported languages. See the integration guides for details on C#, C++, Python, Lua, and Haxe.