Localization
You can localize almost every asset in your novel. Readers can choose separate languages for text, voice, and images, and each one starts out matching their operating system’s language.
Declaring supported locales
Section titled “Declaring supported locales”First, list the locales your novel supports in your workspace’s project.json, using IETF language tags:
{ "locales": ["en-US", "fr-FR", "ja-JP"]}Localized filenames
Section titled “Localized filenames”To localize a file, put the locale in its filename:
scene-i.en-US.fountainOr put it in a locale folder:
screenplay/en-US/act-i/scene-i.fountainYou can use both approaches in the same novel. The only rule is that a file’s translations follow the same pattern as the original. If the original is in a locale folder, its translations need to be in locale folders too.
Screenplays
Section titled “Screenplays”Only translate the text the reader sees: narration, dialogue, and link text. Leave everything else as it is in the original.
Every other part of the screenplay connects to your artwork and code, and changing it breaks that connection.
Artwork
Section titled “Artwork”There are two ways to localize artwork, and you can mix them in the same novel.
- Separate files. Make a complete copy of the PSD for each locale, named or placed in a folder like any other localized file.
- Variation sets. Keep a single PSD, and add a layer for each locale inside a variation set. The reader’s current locale counts as a label, so a layer named
en-USshows and hides the same way as any other variation.
A stem with lyrics is localized like any other file. Inkweaver picks the version that matches the reader’s voice language.
JavaScript
Section titled “JavaScript”JavaScript files are the only assets that can’t be localized.
If a script needs a localized asset, load it with the SDK’s resolve function.
Interface text
Section titled “Interface text”The Web UI plugin draws some text of its own, like the buttons in the controls dialog and the names of gamepad buttons. That text comes from the getI18nValue selector. It knows English out of the box, and you can add other languages by decorating it.
Most keys are the English text itself, like Cancel. The exception is button, the fallback name for a gamepad button, which is Button {{index}}. Any key without an entry is returned as written, with its placeholders filled in. So to translate, pass your translation to the base implementation as the key:
const JAPANESE = { Cancel: "キャンセル", button: "ボタン {{index}}",};
decorateSelector("getI18nValue", (context, next) => { const { resolveLocale } = getSelectors(); const { locale } = resolveLocale({ role: "text" }); const text = locale === "ja-JP" ? JAPANESE[context.key] : undefined;
return next(text == null ? context : { ...context, key: text });});Menu fields work differently. Each field carries its own translations in its locales property.