Localization of games in Unreal Engine 4

Preparing a game for localization is an important part of game development.



We are working on the game " Cat Movies! " In the Unreal Engine 4. This is an economic strategy in which there is a lot of text, and we plan to translate it into various languages. Like many others (but this is not accurate, and I hope that this is not so), we decided to postpone the stage of setting up localization for later development iterations and, as it turned out, in vain.



Localization in UE4 is implemented smartly, and if you remember that all the text that will be translated is enough to store in Ftext (Text in Blueprint'ah) fields, then in general, there is no problem grabbing text from the game. It is enough to open the Localization Dashboard, poke a couple of buttons - and voila.



And, despite the simplicity of this action, we still encountered a number of problems, because of which we had to dig a part of the code.



How to store text



The guys from Epic Games simplified the assembly of the text to the maximum, reducing everything to a single click and further translation.



It all works very simply - for localization, the FText data type (Text in Blueprint) is used, into which the text is saved, and this text is further collected by the localization system and provided for translation.



How it works?



FText is not a standard data type that stores data in itself. Of course, it stores data in itself, but not the data that we expect.



FText is a pointer. It indicates in which table the text is stored. That is, when we assign any text to a variable of this type, the text is stored in a virtual table, and the variable itself now stores the table name and the key by which to find the text in this table.



Thus, it turns out that the text itself is stored somewhere else (we will not consider the subtleties of the implementation of this, since we are not particularly interested in it), and when switching the localization to the desired address, the text is replaced (well, or I want to think so).



image



When text collection starts, the localization system collects all Text - variables from all blueprints, widgets and tables, and rolls out one huge list of text that can be exported to * .po and translated.



Our game has a large set of widgets through which the player will control almost the entire gameplay. We have many names (for example, departments or stages of creating films or some skills, bonuses, etc.) that are used in various widgets that are completely unrelated to each other. There are descriptions of some objects (for example, a description of bonuses), and this is also used more than once in various unrelated widgets.



And here the difficulty begins. If we re-write the names of departments in each widget, then at some point in one of the widgets the name of the departments will be spelled wrong. This matter is complicated by the fact that the “descriptions” themselves (for example, the description of the department) in a large number of characters are difficult to track so that they are the same everywhere (naturally, we did not do this). Even more fun is that we have most of the widgets used as a template into which data from various sources fly, and based on what source it was, the names and texts inside the code change.



We made our task easier by creating a Data Table, in which we began to store data of specific types. For example, a department table that contains a name, description, maximum level, number of employees per level, etc. etc.

It would seem that it was possible to stop at this, but there was a difficulty in the fact that the data in the table constantly changed, something was rewritten, which was deleted as the code grew, and there were cases when the whole table crashed, and we had to roll back, pull out data, return to the current state and insert the lost data back.



Everything became much sadder when I decided to get into localization and finally try it in and out to understand whether we are all doing the right thing.



I pulled all the text from the game and realized that in the code, despite the fact that we tried to avoid repetition, there were a huge number of repeated elements of the text.



Translation is a human thing. If there is an opportunity to make a mistake, people will necessarily make a mistake. And to avoid this or at least minimize it, you need to reduce all the texts to a single template. That is, output somewhere in one place, from where the text will be taken in all parts of the code. And which will be translated only once in order to minimize the risks of errors. It would seem that you can use DataTable, but there are a number of problems there - to save just the names of something, we need to create entire tables that will store these names.



Digging into the Epic Games documentation, I turned my attention to String Tables (hereinafter referred to as “string tables”). It turned out to be an ideal option - to store the text in a separate table special for texts, which was created just to be connected to FText - variables. That is, we can create a table that will store the text in itself. And we can connect this text to any variable - whether it be a variable in the data table, a variable in the widget, a variable in the code - it all comes down to one place where the text is stored.



String Tables allow you to avoid repeating text in a project several times a little more than completely, thus avoiding errors.



String tables are created in the engine, as are the data tables in the miscellaneous section:



image



They are filled very easily - each new line must have a unique key, which you have to invent yourself. And the text itself can already be any. Also, in the table you can specify a different name for the text space from the name of the table, but, in our experience, this is not necessary.



After the string table is created, the text can now be connected to the FText variable:



image



image



Thus, we reduced the text to a single row table, from which it is very easy to pull out. To get this text settings menu, just click on the down arrow next to the text variable.



Localization



Now we just have to collect all the text and start working with it. To do this, we need to start the Localization Dashboard and start the localization settings. You can run the table through the menu Window-> Localization Dashboard.



And before you open something like this window:



image



In this window, you must specify the target (module) from which the text will be pulled out. In our case, this is a game - Game.



Next, you need to specify where exactly the text will be pulled out in the module. In our case, these are only blunts, since we do not store text in the courses. Therefore, we need to specify only “Gather from Packages” and indicate in which folders and which files we need to consider in order to search for texts.



We also need to indicate which languages ​​will be used for translation and which language will be native (primary). I highly recommend if you write and speak Russian - indicate Russian (or any other your main language). This is due to the fact that if you do not know English well, then indicating it as the main one, you complicate your translation into English from "English". Therefore, it is better to indicate in advance your language as the main one, and write all the texts in your own language, so that later you can facilitate translations for yourself and others.



Also in UE4 there is a great opportunity to create translations directly in the engine, without exporting texts for third-party programs. To do this, you need to collect all the relevant text in the game by clicking on the button number 1. And then run the editor (button number 2):



image



A window for editing the translation into the language you need will open.



Assembly



When assembling a project, you must specify the languages ​​that should be included in this assembly, as well as which set of languages ​​your project should support.



image



In our case, Internationalization Support is set to All. That is, our project will support all types of languages ​​from complex hieroglyphs to simple English letters. In general, there are 5 packages:





However, in cases where each byte in the project is important (the All package weighs 15 MB, and EFIGS 2 MB), you should pay more attention to which package you need to choose.



Localization Switching



Text switching occurs in Runtime, that is, you do not need to restart the game, you do not need to worry about the optimization of switching - everything is done easily and simply through the " SetCurrentCulture " method, where you need to indicate with the text which language you want to switch to.



image



And here there is some such snag. The fact is that different countries have their own language branches, for example, there is the main Russian language (ru), but there is Belarusian (ru-BY), Kazakh (ru-KZ), Moldavian (ru-MD), Ukrainian (ru -UA) languages ​​that fall under the branch of the Russian language. Therefore, when choosing a language that is not the main one, you need to consider and indicate the correct language. If you select just the main one, then when switching it is enough to specify "ru".



image



Conclusion



After I gathered all this information together, I realized that from the very beginning we did not correctly approach the creation of text in the game and did a lot of unnecessary work. Of course, we did not rework the code for months, but spent a maximum of 1.5 hours on this, but it would be nice to know the principles of localization in UE4 in advance and take them into account when building the architecture of the project.



The same goes for Saving and Loading in games. This turned out to be not such an easy task in the context of the strategy, where every little thing should be fixed where it stands / lies / has a certain state. But I’ll write about this some other time. And now you can continue to watch our game in our group =)



All Articles