Godot Game Localization


I wanted to give myself a challenge, so I decided to teach myself how to localize games in Godot. Godot is a free, open-source game engine, and currently (3.0+), it uses three different languages: GDScript (its own language that is dynamically scripted, similar to Python), C#, and JSON. A single game can have all three.

On the surface, Godot localization is simple. It is integrated into the editor, and translation files are automatically generated from CSV or .mo/.po files. You can easily assign fonts, images, or sounds to certain languages by remapping them in your Project Settings. It has a built-in translation method (tr()). It even has a TranslationServer class to manage translations. But there are many different ways text can end up on the screen, and each of these requires a slightly different approach.

In the game I chose to localize into Russian, I encountered two of the three languages (GDScript and JSON), and four different localization strategies were required. The game I ended up experimenting with is Hijinx, which was developed by John Gabriel. Gabriel had posted his games on a Reddit post asking for people to offer up their games for people to use to help them learn the engine, and I chose it because it had a lot of text compared to other Godot games, which I figured would mean that there would be a wide variety of localization problems — and I was right.

Different Localization Scenarios

Static UI Text

The way Godot primarily works is that there are “labels” in the game, and you create a CSV in Excel with “keys” for the labels and the translations in all your languages (or .mo/.po files, if you want to take that route). Some of these labels are simply in the UI, and you can change the label directly in the .tscn (scene) file using the scene editor, in the 2D or 3D space. Then the corresponding key for the language the game is running in will be found during run time. There is no need to wrap strings or change anything in code. An example of this would be the copyright line on the main menu screen.

Copyright editor view
Changing copyright text in the UI and the label editor.
Copyright text in the game
The copyright text in the game.

Static UI Text Requiring Player Interaction

Another variation on this theme is text in the UI that while it can be changed directly in the 2D/3D scene editor, it also has to be changed in the code itself in the .gd file that corresponds to the .tscn file (you can access the script by clicking on the scroll icon next to the name of the scene file in the scene menu, although sometimes you just have to search around for the necessary code), because the player will interact with it in some way (clicking on it, pressing the “return” key, etc.). An example of this would be any of the menus in the game. The label text in the game, which would just be a hard-coded string in a game that has not been internationalized, is simply changed to the key you have designated for the label.

Menu item in editor
Changing a menu item in the UI.
The corresponding script
The corresponding script.
In the game
In the game.

Dynamically Changing Text in the UI

Sometimes, you will come across text that you can see in the Scene Editor, but you cannot change the label there – the text is determined by what is happening on the screen. I encountered this while localizing the map UI. The name of the level, for instance, displays at the bottom, depending on what location on the map your character is standing on. For this, I had to locate where the text is in the script files and change the hard-coded strings to the keys there.

Level name in editor
The level name goes here… but it cannot be changed from here.
Level names in code
The level names have to be changed in the code.
Localized level name
“Proving Grounds” successfully localized to “Полигон.”

Dynamically Changing Text in a .tscn File

There can also be text that does not appear in the scene editor (the designated location will be visible, but no text). In this game, there are tips that show to the user before they play a level. The hard-coded strings had to be changed to keys in the .tscn file itself. Interestingly, the concatenated string required wrapping using tr(), while the others did not.

Tips in .tscn
Hard-coded strings are changed to labels corresponding to keys.
TIP_TEXT (L) and TIPONE_TEXT (R) in Russian in the game.

Dynamically Changing Text in a JSON File

The last method I had to use to localize text successfully was one that required me to draw upon my past knowledge of Python, JavaScript, etc., and apply it to GDScript. There is an interactive conversation you have with a turtle in the tutorial level, where he explains the plot of the game to you, and this conversation is pulled in and read from a JSON file. Wrapping strings and using keys did not work here. Instead, I translated the file itself in Visual Studio Code, and used Godot’s TranslationServer feature to bring it in. In the .tscn where the file is pulled in, I used get_locale(), a TranslationServer method, and stored that in a global variable, in case I had to use it later, although I know this is not a best practice. Once I had my current locale stored in a variable, I added an if/else statement to the load_conversation function, telling it to pull in the translated file if the locale was “ru,” and otherwise to pull in the English file (if I were localizing into more languages, I would add elif statements). This worked, and now my turtle speaks (Google-translated) Russian. This is the code:

var loc = TranslationServer.get_locale()

func load_conversation():
	var file = File.new()
	if loc == "ru" :
		file.open("res://json/conversations_ru.tscn", file.READ)
		file.open("res://json/conversations.tscn", file.READ)
	var contents = parse_json(file.get_as_text())
	conversation = contents["conversations"][conversation_slug]
Visual Studio Code
Translated text in Visual Studio Code.
The turtle
The turtle in action.


Hijinx is a complex game, and one of the challenges of Godot localization that I found is that while there is so much built into Godot for localization, there is not a lot of information available on it. I ended up having to download Godot’s demo games and trying localize those, but once it clicked, then it did become as easy as the documentation promised. And I hope that this blog post will help fill in some of the gaps for the next person who decides to localize a Godot game!

Additional Resources