Localising Your Game

Localising your dialogue with the Yarn Project’s localisations takes five steps:

flowchart TB
  yarn["Yarn Scripts"]
  tags["Yarn Scripts with line tags"]
  csv["Strings CSV"]
  translated["Translated CSV,<br>from your translators"]
  project[("Yarn Project,<br>with a localisation for each language")]
  game["Your game, in another language"]
  yarn -->|"1. add line tags"| tags
  tags -->|"2. export"| csv
  csv -->|"3. translate"| translated
  translated -->|"4. add to the Yarn Project"| project
  project -->|"5. choose the language"| game
The five steps, from your Yarn Scripts to translated lines in the game.

The plugin doesn’t add localisation buttons to the editor. Steps 1 and 2 use the Yarn Spinner Console, ysc, which you installed with the plugin. Step 4 is an edit to your .yarnproject file. See Installing Yarn Spinner for Unreal Engine.

If your game uses Unreal’s String Tables, you can keep your lines in a String Table instead. Steps 1 and 2 are the same. See Using Unreal’s String Tables.

1. Add line tags

A line tag is an ID at the end of a line, like #line:a1b2c3d. Translations are matched to lines by their IDs. A line without a tag gets an ID made from where it is in the file. That ID changes when you edit the Yarn Script, and the line’s translations stop matching it.

To tag every line that doesn’t have one, run ysc tag with your Yarn Scripts:

ysc tag Start.yarn Tower.yarn
Adding line tags to two Yarn Scripts, from the folder they’re in.

It edits your Yarn Scripts and adds a tag to the end of each untagged line. Lines that already have a tag keep it. To write the tagged files to another folder instead, add -o and the folder’s path. Every line ID must be unique across all your Yarn Scripts.

The plugin watches your Yarn Scripts, so the Yarn Project is reimported with the new tags. Tag your lines before you export them, and tag new lines as you write them.

2. Export your lines

Run ysc compile with your .yarnproject file, and -o with the folder to write to:

ysc compile Dialogue.yarnproject -o Translations
Exporting the lines of Dialogue.yarnproject to a folder called Translations.

ysc writes three files, named after the .yarnproject file. The strings file, Dialogue-Lines.csv, has a row for each line, with its ID and its text in your base language:

id,text,file,node,lineNumber
line:a1b2c3d,Rosa: The lamp's been out for days.,.../Start.yarn,Start,3
line:c3d4e5f,Rosa: You've got {0} coins.,.../Start.yarn,Start,4
An exported strings file, Dialogue-Lines.csv. The file column has the full path of the Yarn Script, shortened here.
ColumnWhat it holds
idThe line’s ID. This is how the translation is matched to the line.
textThe line’s text.
file, node, lineNumberWhere the line is in your Yarn Scripts.
The columns in a strings file.

The metadata file, Dialogue-Metadata.csv, tells translators where each line comes from, and lists each line’s tags. The .yarnc file is the compiled dialogue. The plugin doesn’t read either of them back in, so you can delete them.

A spreadsheet for translators, from Blueprints

The plugin can also write a CSV file that’s easier for people to read. Call Export Strings To CSV from any Blueprint, like a button in an Editor Utility Widget, with your Yarn Project asset, a File Path on disk, and the Options to use. Get Default Export Path gives you a path next to the Yarn Project asset, in your project’s Content folder, ending in _strings.csv. From C++, call UYarnLocalizationExportLibrary::ExportStringsToCSV(), in YarnLocalizationExport.h.

id,node,character,text,Translation
line:a1b2c3d,Start,Rosa,The lamp's been out for days.,
line:c3d4e5f,Start,Rosa,You've got {0} coins.,
A file from Export Strings To CSV, with the default options.
OptionDefaultWhat it does
Include Line IDonAdd the id column.
Include Node NameonAdd the node column.
Include CharacteronAdd the character column.
Include TagsoffAdd a tags column, with each line’s tags.
Include Translation ColumnonAdd an empty column for translators.
Translation Column HeaderTranslationThe heading of that column.
Delimiter,The character between columns.
Sort LinesonSort the rows by node, then by line ID.
The options for Export Strings To CSV.

The result tells you if it worked, how many lines it wrote, and the error if it didn’t.

This file is for reading, not for adding to the Yarn Project. Its text column doesn’t have the character’s name, and the plugin doesn’t read the Translation column. To make a strings file you can add to the Yarn Project, use ysc compile.

3. Translate

Make a copy of the strings file for each language, and give each copy to its translator. Translators replace the text column with their translation:

id,text,file,node,lineNumber
line:a1b2c3d,Rosa: Die Lampe ist seit Tagen aus.,.../Start.yarn,Start,3
line:c3d4e5f,Rosa: Du hast {0} Münzen.,.../Start.yarn,Start,4
The same file translated into German, as Translations/de.csv.

Translators should leave the id column alone. If the id changes, Yarn Spinner can’t match the translation to its line. The plugin only reads the id and text columns, so the other columns are there for the translator.

Each line’s text starts with the character’s name, like Rosa:. Translators should keep the name and the colon at the start, but they can translate the name itself.

4. Add the translations to the Yarn Project

Add a localisation section to your .yarnproject file, with an entry for each language. The key is the language’s code, like de for German or pt-BR for Brazilian Portuguese, and strings is the path to its strings file, from the folder the .yarnproject file is in:

{
  "projectFileVersion": 3,
  "sourceFiles": ["**/*.yarn"],
  "baseLanguage": "en",
  "localisation": {
    "de": {
      "strings": "Translations/de.csv"
    }
  }
}
Line 4 The language your Yarn Scripts are written in.
Lines 5–9 One entry for each translation.
Dialogue.yarnproject, with a German translation.

The plugin watches the .yarnproject file, so saving it reimports the Yarn Project. The Output Log then shows how many lines it read for each language, like Loaded 2 strings for culture 'de' from Translations/de.csv. If the file isn’t there, or it doesn’t have id and text columns, the Output Log shows a warning, and that language has no translations.

The plugin doesn’t watch the strings files. When a translator sends you an updated file, reimport the Yarn Project yourself: right-click it in the Content Browser and choose Reimport.

5. Choose the language

The game’s language is set on the Dialogue Runner’s Line Provider. Unless you’ve given the Dialogue Runner a Line Provider of your own, it makes a Yarn Builtin Line Provider when play begins.

The Yarn Builtin Line Provider follows the game’s language. Its Auto Detect Culture setting is on, so for each line, it uses Unreal’s current language, if the Yarn Project has a translation for it. It tries the two-letter code first, like de, then the full code, like de-AT. If the Yarn Project has neither, it uses your base language.

So with Auto Detect Culture on, Unreal’s own Set Current Culture and Set Current Language nodes switch your dialogue’s language too.

To choose the language for your dialogue alone, call Set Locale Code on the Line Provider. It turns Auto Detect Culture off, and uses the language you give it from then on:

  1. Get your Yarn Dialogue Runner’s Line Provider.
  2. Connect it to a Cast To YarnBuiltinLineProvider node.
  3. From the cast’s result, call Set Locale Code, with the language’s code in Locale Code, like de.
  4. Call Refresh Asset Provider Context on the Yarn Dialogue Runner, so its Asset Provider knows the language has changed.
PLACEHOLDER — Screenshot needed
A Blueprint graph with a custom event Set Language that has a Locale Code string input. A Yarn Dialogue Runner reference goes into a Line Provider getter, then into Cast To YarnBuiltinLineProvider. The cast’s output pin calls Set Locale Code with the event’s Locale Code, and then the graph calls Refresh Asset Provider Context on the Yarn Dialogue Runner.

In C++:

#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "YarnDialogueRunner.h"
#include "YarnLocalization.h"
#include "LanguageLibrary.generated.h"

UCLASS()
class ULanguageLibrary : public UBlueprintFunctionLibrary
{
	GENERATED_BODY()

public:
	UFUNCTION(BlueprintCallable, Category = "Dialogue")
	static void SetDialogueLanguage(UYarnDialogueRunner* DialogueRunner, const FString& LocaleCode)
	{
		if (!DialogueRunner)
		{
			return;
		}

		if (UYarnBuiltinLineProvider* LineProvider = Cast<UYarnBuiltinLineProvider>(DialogueRunner->LineProvider))
		{
			LineProvider->SetLocaleCode(LocaleCode);
		}

		DialogueRunner->RefreshAssetProviderContext();
	}
};
Line 23 The Dialogue Runner’s Line Provider. It’s only a Yarn Builtin Line Provider if you haven’t given the Dialogue Runner one of your own.
Line 25 Use this language from now on. Call SetDialogueLanguage(DialogueRunner, TEXT("de")) to switch to German.
Line 28 Tell the Asset Provider about the new language.
LanguageLibrary.h, a Blueprint function library that switches the dialogue’s language.

Get Locale Code gives you the language the Line Provider is using, and Get Available Locales gives you the codes of the languages in the .yarnproject file’s localisation section.

If a line is on screen when the language changes, it stays in the old language. The next line is in the new one.

Your font needs the characters for every language you support. If it doesn’t have them, lines in those languages show empty boxes.

Voice clips in other languages

The Asset Provider that comes with the plugin finds a line’s voice clip from an #audio: tag on the line, like #audio:/Game/Dialogue/Voice/a1b2c3d. The tag is the same in every language, so it finds the same clip in every language.

To play a different clip in each language, give the Dialogue Runner an Asset Provider of your own, which picks the clip by language. See Writing your own Asset Provider.

When a line isn’t translated

If a line has no translation in the current language, the Yarn Builtin Line Provider shows the text from your Yarn Script. A translation that’s empty in the strings file counts as no translation.

To try another translation first, set the Line Provider’s Fallback Locale Code. For example, a game with Brazilian Portuguese and European Portuguese can show a line in pt when it isn’t in pt-BR yet.

PropertyDefaultWhat it does
Auto Detect CultureonUse Unreal’s current language. Set Locale Code turns it off.
Text Locale CodeemptyThe language to use when Auto Detect Culture is off. Leave it empty to use your base language.
Use FallbackonTry the Fallback Locale Code language when a line isn’t translated.
Fallback Locale CodeemptyThe language to try. Leave it empty to use the text from your Yarn Script.
The Yarn Builtin Line Provider’s settings.

The Line Provider isn’t in the Details panel, because the Dialogue Runner makes it when play begins. Set these from a Blueprint, from the result of the Cast To YarnBuiltinLineProvider node in step 5, or from C++, where they’re bAutoDetectCulture, TextLocaleCode, bUseFallback and FallbackLocaleCode.

If the line isn’t in the fallback language either, the Line Provider uses the text from your Yarn Script. If even that’s missing, the Output Log shows Missing localized line: and the line’s ID.

Adding translations while the game runs

Add Localized String adds a translation for one line, while the game runs. Give it the Line ID, the Locale Code and the Text. It’s used in place of the translation from the strings file, and it isn’t saved: it’s gone the next time the game starts.

Plurals and ordinals in other languages

[plural] and [ordinal] pick the right word for a number, following the rules of the line’s language. See Markup.

The Yarn Builtin Line Provider uses its current language’s rules. Yarn Spinner for Unreal Engine gets those rules from Unreal’s own language data. Yarn Spinner for Unity has rules for about 150 languages, and Unreal has them for about 130. For a language Unreal doesn’t have rules for, you might get the other form where Unity would pick another one, like few. Test your [plural] and [ordinal] lines in each language.

Unreal only puts language data for some languages into a packaged game. Choose which in Internationalization Support, in the advanced settings of EditProject SettingsPackaging. If a line’s language isn’t in the packaged game, [plural] and [ordinal] use the rules of Unreal’s current language.

Using Unreal’s String Tables

If your game already uses Unreal’s String Tables for the rest of its text, you can keep your lines in String Tables too. The plugin comes with two Line Providers that read String Tables:

Line ProviderWhere it gets text
Yarn String Table Line ProviderOne String Table.
Yarn Culture Aware Line ProviderOne String Table for each language, picked by Unreal’s current language.
The Line Providers that read String Tables.

Each entry’s key is the line’s ID without line: at the start. The text for #line:a1b2c3d is in the entry a1b2c3d.

Filling a String Table with your lines

Import Yarn Project To String Table adds an entry to a String Table for each line in a Yarn Project, with the line’s text in your base language. Give it the Yarn Project in In Yarn Project and the String Table in In String Table. It only works in the editor, so call it from an Editor Utility Blueprint or Editor Utility Widget, then save the String Table. In a packaged game, it does nothing, and the Output Log shows an error.

Call it again after you change your lines, so the String Table has the new text.

The String Table Line Provider

The Yarn String Table Line Provider reads each line from its String Table. It reads the entry’s source text, so it doesn’t use translations made in Unreal’s Localization Dashboard. To use those, write your own Line Provider. See Writing your own Line Provider.

PropertyDefaultWhat it does
String TablenoneThe String Table to read lines from. You can also set it with Set String Table.
Fallback To Base TextonWhen a line isn’t in the String Table, use the text from your Yarn Script. If it’s off, the line shows its ID.
Log Missing EntriesoffShow a warning in the Output Log for each line that isn’t in the String Table.
The Yarn String Table Line Provider’s settings.

The Culture Aware Line Provider

The Yarn Culture Aware Line Provider has a String Table for each language, in its Culture String Tables map, with the language’s code as the key. Each table has the same keys, with the text in that table’s language. For each line, it uses the table for Unreal’s current language, like de-AT. If there isn’t one, it tries the two-letter code, like de, then Default Culture.

PropertyDefaultWhat it does
Culture String TablesemptyThe String Table for each language. You can also add one with Add Culture String Table.
Default CultureenThe table to use when there isn’t one for the current language.
Fallback To Base TextonWhen a line isn’t in the table, use the text from your Yarn Script. If it’s off, the line shows its ID.
The Yarn Culture Aware Line Provider’s settings.

To switch language, use Unreal’s Set Current Culture or Set Current Language node. Get Current Culture and Get Current Base Culture give you Unreal’s current language, like de-AT, and its two-letter code, like de.

Giving the Dialogue Runner a String Table Line Provider

The Dialogue Runner only makes a Yarn Builtin Line Provider for itself, so make the String Table Line Provider yourself, before the dialogue starts:

  1. Check that the Yarn Dialogue Runner’s Auto Start is off, so the dialogue doesn’t start before the Line Provider is ready. It’s off by default.
  2. In Event BeginPlay, call Construct Object from Class, with Class set to Yarn String Table Line Provider and Outer set to Self.
  3. From the new object, call Set String Table with your String Table.
  4. Call Set Yarn Project on the new object, with the Yarn Dialogue Runner’s Yarn Project.
  5. Set the Yarn Dialogue Runner’s Line Provider to the new object.
  6. Call Start Dialogue on the Yarn Dialogue Runner.
PLACEHOLDER — Screenshot needed
A Blueprint graph on Event BeginPlay: Construct Object from Class with Class set to Yarn String Table Line Provider and Outer set to Self, then Set String Table with a String Table asset, then Set Yarn Project with the Yarn Dialogue Runner’s Yarn Project, then Set Line Provider on the Yarn Dialogue Runner, then Start Dialogue with Node Name set to Start.
UYarnStringTableLineProvider* LineProvider = NewObject<UYarnStringTableLineProvider>(this);
LineProvider->SetStringTable(DialogueStrings);
LineProvider->SetYarnProject(DialogueRunner->YarnProject);
DialogueRunner->LineProvider = LineProvider;
DialogueRunner->StartDialogue(TEXT("Start"));
Giving the Dialogue Runner a String Table Line Provider, in an Actor’s BeginPlay().

DialogueStrings is a UStringTable* property on the Actor, and DialogueRunner is its Yarn Dialogue Runner. The Line Provider classes are in YarnLocalization.h. A Culture Aware Line Provider goes in the same way: call Add Culture String Table for each language instead of Set String Table.

[plural] and [ordinal] in lines from the String Table Line Provider follow the rules of your base language, whatever the game’s language is. The Culture Aware Line Provider follows the rules of Unreal’s current language.
Next step Line and Asset Providers How the Line Provider finds each line's text, how the Asset Provider finds its assets, and how to write your own.