Localization implementation with centralized workflow

I’m having trouble implementing a centralized localization workflow for my project, so I was hoping someone here could provide a solution.

Here is the workflow I am trying to implement:

  1. All in-game text is centralized in a single excel sheet, with each row containing a key as well as the text of all supported languages (if the number of entries gets too large, it can be split up into multiple excel sheets by category as appropriate).
  2. I plan to run a script that exports the excel into multiple csv files, one for each language, with each row containing the Key/SourceString pairs for that specific language, taken from the main excel.
  3. Each csv file would be imported as a StringTable asset for that language. UI text would be linked to the StringTable’s keys, and the text should dynamically update in the editor when changing the preview language.

I determined that this workflow should be the simplest, fastest, and least error-prone method of managing the text for my project, especially based on my experience using (not implementing) similar workflows on previous projects. I do not intend to use the Localization Dashboard to handle localization.

However, when testing this workflow, I hit a roadblock:

  1. As an experiment, I created a simple file titled GameText.csv containing a couple Key/SourceString pairs in English (default language). I made another GameText.csv file with the same Key/SourceString pairs, but this time with the SourceString entries in Japanese.

  2. I created a StringTable uasset file named GameText in the Content/Localization folder and imported the English GameText.csv file.

  3. Right-clicking on the GameText.uasset StringTable file, I noticed that there was no “Asset Localization->Create Localized Asset” option. With this option unavailable, I tried creating localized versions of the GameText StringTable uasset by creating the folders Content/L10N/en/Localization and Content/L10N/ja/Localization and creating the corresponding GameText.uasset StringTable files inside these folders.

  4. However, when opening a UMG widget to set one of the keys I prepared to a TextBox, three different GameText StringTables show up in the dropdown menu instead of one. Clearly, the Engine is recognizing Content/Localization/GameText.uasset , Content/L10N/en/Localization/GameText.uasset , and Content/L10N/ja/Localization/GameText.uasset as three completely separate StringTables instead of as multiple localized versions of the same asset.

Does anyone know if there is a way around this issue? It seems as though my workflow should be feasible if I can find a way for the different StringTables to be recognized as different-language versions of the same file instead of as completely different files. Thank you.

Edit: Alternatively, it might be easier to just use a single DataTable containing all text for all languages and implement a custom TextBlock widget that uses the custom table…? I might try this and see if I can get the binding to work properly so I can preview it in the UMG editor.

Edit 2: Adding a custom widget inherited from UTextBlock that updates the Text variable with data from my all-language DataTable according to UKismetInternationalizationLibrary::GetCurrentCulture() seems as though it might have solved my problem. Currently I’m performing the Text update on RebuildWidget() and PostEditChangeProperty(), and it works in the UMG editor as well. Additionally, you can change the culture in-game and update the text language without having to restart the game. On the other hand, might there be any unforeseen issues I’ll have to face later from using this custom approach instead of the built-in system…?

This is an old question but I found this when I was looking for the intended way of using localization with string tables. Eventually I found the answer on UDN which I’ll share here for people who doesn’t have access to it.

How to localize your game using String Tables

Step 1. Create a .CSV as your localization source

This is where you add all keys and their base translation. The first and second column must be named ‘Key’ and ‘Sourcestring’ respectively. Any column following that can be named whatever you want and it’ll be treated as custom data fields that are visible in the .PO file format unreal exports translations to. In our case we’ve added ‘comment’ and ‘category’.

  • Note that you can divide your keys
    into several string tables if you’d
    prefer. However, do not add any
    translations to the .CSV files as they’re simply used for keys and their source strings.

Step 2. Convert the .CSV to a string table

There are two ways of doing this. Either create it manually in the unreal editor and import your .CSV or define it in C++. I’d recommend the latter as once its set up there’s one less manual step each time you want to update your localization source as it rebuilds directly from the .CSV each time you compile.It allows you to access the string table from code as well as blueprints.

[Here’s the official documentation on how to create string tables in c++][3]
Pay attention to the warning regarding .CSV files not being packed automatically and thus needs to be set up in the project packaging settings

CSV string tables aren’t staged automatically. It is recommended that you place your CSV string tables in a known folder and then add them to the Additional Non-Asset Directories to Package in your project’s Packaging settings.

Step 3. Set up the localization dashboard to use your string table

In order for Unreal to be able to gather the texts from your string table (assuming it’s defined in C++) you need to add the .cpp file in which you defined it under the ‘Gather from Text Files’ setting. For manually created string tables you’d add it’s folder under ‘Gather from Packages’ and add ‘.uasset’ as a file extension.

When you press the gather text button your native culture should now be populated with the keys from your string table.

Note that any changes you your source strings will render any translations for the affected key to be considered stale and thus they will be cleared. To avoid having to redo translations for all languages if you simply just want to fix a spelling error in your native language you can add a ‘dummy’ culture. Epic suggests using en-US-POISX as that won’t ever reasonably be used by anyone. Using a dummy culture as your native culture allows you to fix typos and correct text without it affecting any of your other localized languages. I.e. if your source strings are written in English you will use en-US-POISX as your native development culture and add ‘en’ as your actual ingame translations for English.

Be aware that you HAVE to package your native culture, even if it’s only used for development as otherwise you will experience unintended behavior, such as not being able to switch back to a language after already switching to another one in your game.

Step 4. Add other languages to localize

You now have your native culture set up with all the keys and source strings from you string table. In order to add additional languages you simply add a new culture. Then you can either translate the keys with the Localization Dashboard tool or export a .PO file. The pros for using the .PO files is that you can send them to someone else to do the translation and that it exposes any additional data you’ve added in your .CSV file (see step 1).

Once the translations have been added to the .PO file you’ll simply import it using the Localization Dashboard and compile the text.

That’s it! That’s the (as far as i know) intended way to to work with string tables and have a centralized(ish) localization workflow in Unreal.

One last note if you ever experience unintended behavior, press the big ‘Compile Text’ button in the localization dashboard, as forgetting to do that will possibly make you bash your head in the table wondering why your localization isn’t working.

Also, if you have trouble with the localization in builds of the game but not in the editor, make sure that all you’re languages and .CSV filed are included in the packaging settings.

1 Like