Monday, April 1, 2024

Godot Game Localization

In this entry, we will learn about how to make a multilanguage text in Godot.
The Godot's documentation can be seen here: https://docs.godotengine.org/en/3.6/tutorials/assets_pipeline/importing_translations.html and https://docs.godotengine.org/en/3.6/tutorials/i18n/internationalizing_games.html


First, we're going to make one simple example to see how it works.
According to the documentation, we need to have a CSV file formatted as follows:
CSV files must be formatted as follows: keys    <lang1>        <lang2>        <langN>

* The "Lang" tags must represent a language, which must be one of the valid locales supported by the engine.
* The "KEY" tags must be unique and represent a string universally. These keys will be replaced at runtime by the matching translated string.
* Note that the case is important, "KEY1" and "Key1" will be different keys.
* In addition, you have to take into account that the first raw will be ignored by the engine, and that, can have empty rows (which we can use to keep our sections separated)

With all that info, we are going to create a CSV file using LibreOffice in this entry. Open your calc file and fill it. Example below:

Once you have your cells filled, the next step is saving the file properly. Go to "Save as" and select CSV file:

Click on OK, and when for the next prompt, remember what the documentation says:
`The CSV files must be saved with UTF-8 encoding without a byte order mark`

* Be sure to click Reimport after any change to these options.

After saving your CSV file, go to your Godot's project's folder and copy-paste it or drag and drop it inside.

* Once you do this, Godot will automatically parse it and create the translation files for the project, as you can see below:

With this done, go to "Project > Project Settings"

And here, go to the "Localization" tab, it will be empty. We are going to add our recently created translation files:

One by one, select and open all your translation files

When you finish, you can close this window:

Now, if you write a key in one text string (no extra spaces or symbols, or it won't work), Godot will try to find the key in your system set language (This can only be seen during execution, so don't be afraid if you only see the key in your developer screen).

    godot07.png

* Font used: https://www.dafont.com/essays1743.font

You have made it!! However, we want the user to be able to change it so...

Let's write the text so we don't have to restart the system to change the language:
Attach this code to your label:
```
func _unhandled_input(event):
  if event.is_action_pressed("translate"):
    TranslationServer.set_locale("ja")
    text = tr("GREETINGS00")
```


This will take user input through the "translated" key (defined in your Input Map), you can use whatever key and name here.

If you run your game now, you will see the window empty (or in some cases just lack characters):

Don't worry, this only means that the default font doesn't have characters for the string, and you have to add one that has. To do this, go to your "Inspector" on the right side of the window, and in "Theme Overrides > Fonts" add your font and fallbacks fonts for those cases that the characters don't exist. VoilĂ !!

* Japanese font used: https://www.freekanjifonts.com/japanesefont-rii-handwriting-download/

If we use this code with a lot of ifs, we can make the text display in any language now. But that wouldn't be clean at all, in fact it would be long and dirty. So, for the second part of this entry, we will write and share the bullet points and the code to create a simpler and short modular scene (tscn) with a menu, that we can copy and reuse for any other project. [We can do it editing the previous tscn or creating a new one. We will make a new scene, so the steps are clearer]

Open your new and clean scene and add the following root and children nodes:

- CenterContainer: We will use this as root, so we can hide it from display when we use it as a child for other nodes.
- VBoxContainer: We will sort our screen text pattern with this one
- Label: This will contain the "language" string in the different languages, to give a nice visual touch
- Button: This will be in charge to show the language in use and the signals for it to change, among the other possible options.

Now attach this script to your `CenterContainer` node ("Locale" in the image above), so it knows what to do to manage the scene.
```
extends Node

var langKey = 00

func _ready():
    # use and display english as default locale
    # to save resources finding the language in the first run
    TranslationServer.set_locale("en")
    _set_Locale()

func _on_Button_pressed():
    langKey += 1
    if langKey > 2 : # Keep the key value in language bounds
        langKey = 0
    _set_Locale()

func _set_Locale():
    match langKey:
        00:
            TranslationServer.set_locale("en")
        01:
            TranslationServer.set_locale("es")
        02:
            TranslationServer.set_locale("ja")

    var langCode = "LANGUAGE0" + str(langKey)
    get_node("VBoxContainer/Label").text = tr("LANGUAGEID")
    get_node("VBoxContainer/Button").text = tr(langCode)
```


Don't forget to go into your Button node, and connect the "pressed" signal (to your CenterContainer node), or it won't work.

If you followed the guide carefully, you should be able to run your project and get a result like this one.
The first image shows your default window (English), if you click on the language button (the gray one), you should be able to step from one to the next and loop among them.


With that, we have accomplished our goal for today!!


Warning: at the release of this entry, the display in the PS Vita does not work, https://github.com/SonicMastr/godot-vita/issues/47 . However, since it will probably work in the future, the same way it does in the PC, I will leave it here as is. [Edit: The error was related to the font, solved here,  https://homebrew-psvita.blogspot.com/2024/04/godot-dynamicfont.html]

Extra: I added that sample project to godot's asset library if you want to tinker with it, https://godotengine.org/asset-library/asset/2855

No comments:

Post a Comment