Archives For Localization

Hello again folks!

This week, I pick up where I left off last week with Localizing FATED in Unreal Engine 4 – Part 1. I already covered the basis of text localization, i’ll follow up with Voice-Over localization using Wwise as well as other things to consider when localizing in Unreal Engine 4.

Localizing Voice-Over Using Wwise

Wwise is a really great tool, and I can’t imagine doing audio work without it ever again. The Unreal Engine integration is great, even if some stuff is missing, namely localization support. Fortunately, all the ground work is pretty much done, meaning there are only a couple of things you need to modify to make it all work.

Adding localized audio files in your Wwise project

The first thing you want to do is actually setup your localized audio files in your Wwise project using the Wwise authoring tool. This is very easy to do, and requires no additional step in the UE4 editor, since what you import in Unreal (Events and Banks) is language-agnostic. Basically, the event stays the same, but the audio files played will differ. The only thing you have to do is import the new localized audio file over the already existing audio files in Wwise. Right-click on an audio file (or folder) and select “Import Audio Files…”.
This screen will show up:

Audio File Importer
Be sure to select “Localize languages” in Import Mode, and the desired language in “Destination language”.


Select the preview language in theWwise authoring tool


Now, you do this for every VO of your game. It is important that every VO file name match your original VO file name. You can import by folder to go faster. You can also set your project in the desired language; that way Wwise recognizes which audio files have a counterpart file for the selected language. This makes it easy to know which audio does not have a valid localization yet. Once this is done, everything you had to do on the Wwise side is done! Let’s return to Unreal!

Generating banks for all supported languages

In AkAudioBankGenerationHelpers.cpp you will find the GenerateSoundBanks() function. In there, the following line specifies which bank language will be generated:

CommandLineParams += TEXT(" -Language English(US)");

For some reason, by default it only generates English banks; basically you have to add each language you want to generate. Even simpler, just comment out the line. This will make it so that it generates all languages specified in your Wwise project.

Specifying Culture in the Game

Now that the text and voice-overs have been generated in every supported language, you actually need to specify which language you want the game to show. In general, you’ll want to do this operation at the very start of the game. Unreal offers a simple way to launch the game in the desired culture using a launch argument: -culture=“fr”.

This will effectively call for the change in culture on the text side; unfortunately, it does not do anything regarding the Wwise banks. Instead of using the -culture argument, let’s dive in and see the actual calls we need to make the switch of culture happen.

For the text, the FInternationalization class is used to set different cultures. Here is an example of how to set the game in French:


This will only change the text, however. For the Wwise content, you need to do yet another small change. For that purpose, I added a function to the UAkGameplayStatics class that I called void SetLanguageToCurrentCulture().

In this function, the first step is to get the current culture:

 FString currentCulture = FInternationalization::Get().GetCurrentCulture()->GetName();

After that, you can assign the Wwise current language this way:


The name of the language is a string equivalent of how the language is called inside the Wwise authoring tool.

Optionally, you can also get the current Wwise language and unload the VO bank if the new language is not the same as what was loaded.


Now you should have everything you need to have your game’s text and voice-overs localized.

IMPORTANT NOTE: For some reason, Unreal does not allow the culture to be changed directly in the editor. This can be frustrating if you want to see the content in another culture directly in the editor. Fortunately, there is a way to remedy the situation quite easily.

In TextLocalizationManager.cpp, you can find the OnCultureChanged() function. What you want to do is remove the FApp::IsGame() from the ShouldLoadGame initialization.

//const bool ShouldLoadGame = bIsInitialized && FApp::IsGame(); //Before
 const bool ShouldLoadGame = bIsInitialized; //After

IMPORTANT NOTE 2: Yet another “annoying” default behavior is that a packaged game will not fallback to “root” culture when the culture specified is more specific. For example, if your game is in “fr-CA”, it will not default back to “fr” but rather to the default culture, which is “en”. Yet again, a small change will fix that.

In ICUInternalization.cpp, you can find the SetCurrentCulture(const FString&) function. You simply want to allow fallback, which is something already done in Unreal, just not set by default.

// Allow Fallback, this make it so that we can use “root” language like “en” and “fr” and not need to specify “en-US”,”fr-CA”, “fr-CD”, “fr-CF”…

FCulturePtr NewCurrentCulture = FindOrMakeCulture(Name, true /*Allow Fallback*/);

Getting the Steam App Language

I won’t go over how to setup your game for Steam (there are already a few good tutorials out there for that), but I’ll talk about the snippet of code needed to use the language currently selected in Steam.

First, I added FString GetSteamAppLanguage(); in OnlineSubsystemSteam. You can add it to your custom version of OnlineSubsystemSteam, but I felt it was enough of a “core” feature to be added directly to OnlineSubsystemSteam.
Here is the function in its entirety:

FString FOnlineSubsystemSteam::GetSteamAppLanguage()
 FString langFString = TEXT("english");//Default
ISteamApps* steamApps = SteamApps();
 if (steamApps)
 langFString = FString(ANSI_TO_TCHAR(steamApps->GetCurrentGameLanguage()));
 return langFString;

SteamApps() won’t always be valid, depending on some factors (like if the game was launched from Steam or not), so be sure to have a default value to fallback to.

Unreal is certainly going to add a lot to its Localization toolset; in fact, it’s already happening in 4.10.1 with the OneSky localization service plugin. This will certainly come in handy if you’re thinking about using that service for your game. There is also the experimental “Localization Dashboard” that can be activated in the “Experimental” section of Editor Preferences.


I did not use the Dashboard extensively, but it promises to one day remove all that “.ini” manipulation (which is not that user-friendly…) and make it all transparent through a nice visual tool. It seems to work well enough, but all it will do is manipulate all the files we talked about earlier, so it is still relevant to know how these files work.

This is it for localization in UE4. Obviously, there is more to it than what I addressed in this post, but you should be well on your way to making it work in your own game. Hope this was helpful, and don’t hesitate to ask questions in the comments section. Stay tuned for more on FATED, as we quickly approach the release date!

Mick / Lead Programmer / @Mickd777

Hello again!

Last month I had the mandate to localize FATED in French. As some of you may be aware, Frima Studio is a Québec City-based studio that predominantly speaks French, so it was fun to finally have the script integrated in our native language. One of our characters is even voiced by Nicolas Cage’s official French voice actor. How cool is that?!

Unreal is equipped with a lot of game localization tools, even if they’re not quite as polished as the rest of the engine. In this post, I’ll explain how localization works, from text to voice-over. I’ll also give a few tips on how to modify the engine to allow different culture directly in the editor, which changes are needed to support localization for Steam builds, and, finally, which modifications are required to have the Wwise UE4 integration fully localization-ready. In short, how we managed to have a fully working localized build for FATED!

Before reading on, take note that I worked on the localization using Unreal 4.8.2. We recently upgraded to 4.10.1, so while I can confirm that this is all still valid, some new features may have been added that I’m not aware of.

Localizing Text

If you’re familiar with UE3, you’ll notice how different the localization system is now. Epic pretty much ditched their old system. While UE3’s localization system was lacking in some ways, I personally find that UE4’s localization system sometimes neglects simplicity for an all-around, more robust and polyvalent system that is unfortunately not quite ready yet, which sometimes leads to confusion. In UE3, you just had to use a LOCALIZE macro with some parameters that would point to the correct “.ini” file containing the localized text. In UE4, the process is a bit more convoluted, but once you’ve familiarized yourself with its intricacies, it’s quite easy to use. Now let’s dive in!

FString and FText
If you’re familiar with Unreal development, you already know about FString, which is the custom implementation of strings that is used throughout the engine. For localization, Epic introduced a new class, FText, which needs to be used whenever we wish to localize text content. The usage of FText will then mark said text to be gathered in a later phase of the localization process, the “gathering” phase using a specific commandlet (namely the GatherText commandlet).

When changing text directly in the code, you need to use the NSLOCTEXT macro. This macro uses three parameters: the namespace of the text, a key to represent this text, and the string literal in the default language, which in our case is English. It looks something like this:

FText chapterSelectTxt = NSLOCTEXT("MainMenuUI", "ChapterSelect", "Chapter Selection");

This will later determine how your language archive is generated. We will look at the .archive file generated in a moment.

GatherText Commandlet
The next step is to actually gather all the FText from your project. This also means that we will be able to get text from every blueprint instance for every map of your game, for example. For this to work, you need to start the UE4 editor with a specific command line. I find that the best way to do this is to create a batch file. So I created the LocalizeJotunn.bat file (Jotunn is the internal codename for FATED), which is located in the same folder as the .uproject file.

..\..\Engine_4.10.1\Engine\Binaries\Win64\UE4Editor.exe %PROJECT_PATH%/Jotunn.uproject
-Run=GatherText -config="%PROJECT_PATH%/Config/Localization/Game.ini" -log > localization.log

From that file, you can notice a reference to a file named Game.ini in Config/Localization/. You need to create that file: this is where the entire configuration for the GatherText commandlet is going to reside. You can find our config file here: configFile
I strongly recommend you start from that file and adjust for your needs. This file has different sections; let’s take a look at them.

This is where you set where the localization files will reside. It is important that you put the same path that is set under the [Internationalization] section of BaseGame.ini (or your custom %YourGameName%Game.ini). By default, this is the path you should see:


CommonSettings is also where you get to set the native culture of your game (default language).  After that, using the CulturesToGenerate property, you can list all the languages for which you need to create localization files.

There will be a number of GatherTextStep, each with its own Commandlet class. The two most important ones you will want to check are GatherTextFromSource and GatherTextFromAssets. GatherTextFromSource will scan source code for those NSLOCTEXT I mentioned earlier, while GatherTextFromAsset will scan for the FText in your .uasset and .umap.

The documentation on this on the Web is not up to date; at least it wasn’t when I worked on the localization, so follow our file for that. You will mainly want to verify the paths for the objects to gather text from. BEWARE! Some of the required parameters are paths (SearchDirectoryPaths) and some are filters (IncludePathFilters). Both kinda look the same, but for filters you don’t want to miss out on the required asterisk (*)!

I personally found that GatherTextFromAssets was getting too much FText I did not want to localize in the first place. We use a lot of TextRenderComponent in the game that are used in the editor only, and this was polluting the localization archive. Since FATED doesn’t have that much text anyway, I decided to only use GatherTextFromSource and force our texts to be localized in source using the NSLOCTEXT macro. It simplified the process for us, but it may not be what you need for your game.

The other steps (GenerateGatherManifest, GenerateGatherArchive,etc) I did not change, but they are required to actually generate the files that will be in you localization content folder (Content/Localization/Game).

Generated files: .archive and .manifest files
The main generated file that you will want to modify afterward is the .archive file. This is where your actual localization text will be stored. For each language generated, a folder will be created in a Content/Localization/Game that represents it; in our case an “en” and “fr” folder. You can open the .archive file using any text editor. For example:

        "Text": "2.1 - A New Beginning"
        "Text": "2.1 - Un nouveau départ"

The .manifest file is not meant to be modified, but you can get information on the gathering process there. It could be useful to track down where the text was gathered and the actual key used. Example:

        "Text": "2.1 - A New Beginning"
"Keys": [
                "Key": "Chapter4Name",
                "Path": "Source/Jotunn/Private/UI/UIChapterSelect.cpp - line 196"


That’s it for Text Localization. I’ll go over the Voice-Over localization using Wwise as well as other things to consider when localizing in my next blog entry next week. I hope this guide has been helpful to you folks out there. See you next week.


Mick / Lead Programmer / @Mickd777