[Solved] Multi Language support to video games (desktop)

HI.
I’m not a coder/programmer or a game developer (this is my first attempt). but I play vedeo games almost 30 years, so I have my expectations.
and one more thing: I prefer PC to the gaming platform. I know (but may be I’m wrong) you here are using GDevelop to create mobile games mostly. may be I’m in a wrong place? :thinking: :grin:

doesn’t matter. so. I want my game has a multiple language support. two first (my native language Hungarian and of course English for international use), but I want easy expandability.
if anybody has a well-tried solution in GDevelop please share with me.
in other case please help realize “my” conception:

I want a global variable (for example call it GV_lang), where its value represent the selected language. “1” = Hungarian, “2” = English, ect… I think I need an 2 dimensional array object for this, but sadly I cant find in GDevelop yet. :cry: in this non-existent array every text object has a row (the Y Index) and the columns contains the same text in different languages (the X Index). after this, I only need to say all my text object wich line is theirs, and they will see from the global variable’s value wich column is the actual.

I did not tried this in GD but in case your target platform is PC I guess you could use the new File system events to load text from JSON.

What you could do for example is have a JSON that include the languages and the name of their files.

languages.json
{
“English”: “En_en.json”,
“Hungarian”: “Hu_hu.json”,
“French”: “Fr_fr.json”
}

And then have a settings file where you store the current language of the game.

settings.json
{
“Language”: “English”
}

Then, of couse you would have the actual language files contain the translations

En_en.json
{
“Settings”: “Settings”,
“Save”: “Save”
}

Hu_hu.json
{
“Settings”: “Beállítások”,
“Save”: “Mentés”
}

Fr_fr.json
{
“Settings”: “Réglages”,
“Save”: “Sauver”
}
…etc

So then, what you can do is load the settings from settings.json to get what language is set (Hungarian), then use that string to get the name of the language file (Hu_hu.json) from languages.json and finally, get all the strings in the selected language from that file.

As I mentioned I did not test this in GD, but this is what I usually do in other engines.

In case you find this solution way too complicated for your taste and purposes and or you don’t need to actually store the translations externally, the most simple thing you can do is store all the translations in a structure variable internally.

Languages.English.Settings = “Settings”
Languages.English.Save = “Save”
Languages.Hungarian.Settings = “Beállítások”
Languages.Hungarian.Save = “Mentés”
Languages.French.Settings = “Réglages”
Languages.French.Save = “Sauver”
…etc

You get the idea. Then, you can use expressions to get the language:
Languages[“Hungarian”][“Settings”] to get the word “Settings” in Hungarian.

Notice in the expression “Hungarian” and “Settings” is a string, so you can replace that with a string variable. For example if you store the language in a variable called LangOption = “Hungarian”, you can replace the string with

Languages[VariableString(LangOption)][“Settings”] to get the word “Settings” in whatever language you store in LangOption variable.

2 Likes

In case anyone need one, I have uploaded an example with structure variables here:
(GDevelop5_multi-language-menu.zip)

The benefit of using structures over JSON is that it does work also on Android.

3 Likes

thank you. JaSON is my new enemy.
but unfortunatly I dont understand the GDevelop version too. why are you using those random punctuation marks?
and thank you the example file. I try to understand it. it seems too over copmlicated to me… why are you load up the text from the code to global variable and than the text object, why not directly from code to the oject?

Do you mean [“”]?
That is for the expression, you can read about expressions here:
http://wiki.compilgames.net/doku.php/gdevelop5/all-features/expressions
It is basically just a syntax you need to get used to.

If not in variables then how would you store all the text for all languages for all scenes?
In my simple example where I have only a menu and a settings scene, it would have been enough to just change the text directly in 2 scenes but what if you have 100 dialogs in 100 scenes? Do you go and use thousands of events to change text hundreds different places based on what language is selected?

Technically it is not required to store the text in variables but with using the variables I can store all my text in a central location so I can get all the text from 1 place and by using structures and expressions I can do this by changing a single text from “English” to “Hungarian” and if I need to change anything later, add, remove, edit any text, I need to do it 1 place only instead of going through all scenes and edit all texts one by one. That’s the idea with the global variables, structures and expressions.

As for being global, It is also don’t really need to be global but I did explain that in the example actually.

1 Like

thank you for the link. that was useful and I really missed it earlier. but it doesn’t mention the puncuation marks. and doesn’t show examples how to insert an expression to another expression. :slightly_frowning_face:.
never mind. I believe you. I saw it work in your example (and other things too). many thanks fot that. now I have a concept to implement my own primitive version. I got some inspiration from you. Thank You.

Those are used for structure variables only, you can read about it here:
http://wiki.compilgames.net/doku.php/gdevelop5/all-features/variables

But as I mentioned it is just a syntax.
Let say you have a variable called Var1. It is just that, a variable but in GDevelop you can add child variables to an other variable by using a dot ‘.’ like so. Var1.Child1 and Var1.Child2
Now you can assign different values to Child1 and Child2 within the same variable.

In events, you can access these child variables by simply entering the name Var1.Child1
But when you need the value of Child1 in a value field such as the text of the text object, you need to use expressions.

The expression to access a global number variable is GlobalVariable(variable_name) without “” and the expression to access a child of a variable is variable_name[“child_name”] with putting the child name in to “”
So if you put it all together the expression is GlobalVariable(variable_name[“child_name”])
In case of a text object however, the value must be a text or otherwise called “string”.
In case it is a number variable, you need to convert the number to string and there is an expression to do just that ToString(variable). So the expression to get a child of a global number variable as text looks like this:
ToString(GlobalVariable(variable_name[“child_name”]))

However, in the example I was using text variables to store the language option “English”, “Hungarian”…etc.
So I did not have to convert it but I needed the expression to get the value of a text variable and the expression for that is GlobalVariableString(variable)
So to get the text value of a child of a global text variable, looks like this:
GlobalVariableString(variable_name[“child_name”])

Now, so far we had only a variable and that variable had a child. Var1.Child1
But we don’t need to stop here, childs also can have childs.
Var1.Child1.Child1
Var1.Child1.Child2
Var1.Child2.Child1
Var1.Child2.Child2
…etc

So to access the child of a child in an expression we just need to use more of
variable_name[“child_name”][“child_name”]

So in my example, I have a structure to store the translations for all languages
Languages.English.Settings = “Settings”
Languages.Hungarian.Settings = “Beállítások”
…etc

Languages is the variable and English and Hungarian is a child of the variable and Settings is a child of the child.
So then, in my example in order to get settings in hungarian I can just use the expression
GlobalVariableString(Languages[“Hungarian”][“Settings”])
And because I store the language in a variable called AppLanguage, I can use that in place of “Hungarian” to get the settings in any language I want without using 1000 events
GlobalVariableString(Languages[GlobalVariableString(AppLanguage)][“Settings”])

So instead of doing this:
If AppLanguage = “Hungarian”
Do = “Beállítások” to text of SettingsText
If AppLanguage = “English”
Do = “Settings” to text of SettingsText
…and repeat this 100 times for all languages and mind you this is only 1 text object

I can just do
GlobalVariableString(Languages[GlobalVariableString(AppLanguage)][“Settings”])
Only 1 time even if I have 10 or 100 languages to choose from.

I hope it helps to understand how it works and why I did what I did in the example.

1 Like

Thank You the long and detailed explanation. now I understand!

LOL . where are you know what I planning :rofl:

I nned to thank you again Master Yoda this detailed explanation of how the variable structures- and their syntax works! I come back day after day and read it again.
it is super useful :+1:

today’s question is related to this, more like than the original topic. but I think tis is fine.so.
I have an obect. it has it’s own structure like this:

where the “carPart” is the name of the whole structure. the name of its children is just numbers. and every child has the same 4 children. their names is usaily a single letter. but the structure has ~70 from the numbered children!

is there a fast and easy way to check all [“m”] cild of all numbered child is equal to zero? or I need to sum all in a single condition, and then check the result is greater then zero? :eyes:

I want to do something like this:
if any [“m”] child is greater than zero :arrow_right: than do this…
otherwise :arrow_right: do that…

I can think of 2 ways to do it.

If you know the exact number of child and it is always the same, all you need to do is use the compare the value of an object variable condition like so:

Variable carPart.1.m of car = 0
Variable carPart.2.m of car = 0

If you don’t know the number of child because it is different depends on the car type or something, the first thing we need is the Repeat event to repeat certain event as many times as many child you want to test. So wee need to use the Repeat event. Then, we need to know how many child the carPart variable has and we need to use an expression to get the number of child of carPart:

car.VariableChildCount(carPart)

“car” is the object and the rest is an expression to get the child count of the object variable called “carPart”. It is going to return the number of child this variable directly has but not the sub-child like m and others. So in case there is 2 child, it is going to return 2 and the event looks like this:

Repeat car.VariableChildCount(carPart) times:
condition : action

So we repeat the events as many times as many child the carPart variable has. But we need to know exactly if it is child 1 or child 2 or which. So we need to know if it was the first time the Repeat event fired or the second or what. I don’t think there is any built-in way to do it. So we need a counter variable to count manually.
Initialize a variable called counter with the value 1 at the beginning of the scene or whenever you want to compare the childs.

At the beginning of the scene : Do = 1 to scene variable counter

Then, we are going to use this value inside an expression to pick the specific child of carPart and pick the “m” child of that child

Variable carPart[ToString(Variable(counter))][“m”]

Then we are using this expression inside the Repeat event to compare the m value of each child of carPart if the value is = 0 or not

Repeat car.VariableChildCount(carPart) times:
Variable carPart[ToString(Variable(counter))][“m”] of car = 0 : action

replace “action” with anything you want to do if value of “m” is = 0
But, you want to put this as a sub event of the Repeat event, so leave the Repeat event blank and use a sub-event to compare the value of “m”

Repeat car.VariableChildCount(carPart) times:
no condition : action
sub-event: Variable carPart[ToString(Variable(counter))][“m”] of car = 0 : action

The last thing is to add one more sub-event and increase the value of the counter by 1

Repeat car.VariableChildCount(carPart) times:
no condition : action
sub-event: Variable carPart[ToString(Variable(counter))][“m”] of car = 0 : action
sub-event: no condition : Do + 1 to scene variable counter

The reason you want to use sub-event is the counter variable because you want to increase the value of the variable in the loop even if the value of m is > or < 0.

And that’s it. You fire the loop, it is going to repeat the events as many times as many child carPart variable of the car objects has and compare the “m” value of each child.

If you are familiar with the loops, expressions, it might seem confusing at first but not that difficult really.
Let me know if something is not clear :+1:

1 Like

Thank You for the detailed explanation. it is loud and clear :+1:. You must be a teacher somewhere!

the original question was a little bit different, but you inspired me. I realized that I didn’t want to do it right from the start. when I start developing the “queue”, I wasn’t familiar with child variables. so I put the whole car with all its parts to the queue. but now, with the knowledge I have received from you, I developed a more powerful version of my queue. now I put only a single car part from any selected car to the queue! and the worker NPC can find it and its car later! (yes, the pathfinder behavior is a little bit stupid :rofl:)

although the original question is no longer relevant, I have a theoretical question about the repeat event. it may come in handy later.
if I understand it correctly, this will loop as many times that I have given. and it give output (true or false) in each loop. in my case 60 times. but I wanted only 1 output in the end. true, when it found even one of the inspected variables that is greater than zero. or false if all inspected variables are equal to zero. yes, I can create an another counter to do this, add +1 for every variable wich greater than zero. and after the repeat (60 times) event I can check this one. when it is still zero do my action, or when it is greater than zero do another action.

now the question is: can I force stop a repeat event from the inside? before it finishes his job?
in my case, if any variable from the 60 is greater than zero I’m done. so if the first inspected variable give “true” output, I dont need to check the other 59. can I do this?

No, unfortunately there is no way to break from a loop in GDevelop as far as I know.

The only thing you can do is have a variable and call it “run” or anything you like and initialize the value to 0.
Check the value of this variable first inside the repeat event and add everything else as a sub-event.
If the value = 0, then execute everything else.
Then, if m > 0 you can set the value of this variable to 1 and this way you can make it skip all the events from that point.

Repeat 60 times
scene variable run = 0 : no action
sub-event: carPart[“1”][“m”] > 0 : Do = 1 to scene variable run
sub-event: carPart[“1”][“m”] = 0 : Do something else
…etc

It would still run 60 times but this way you don’t use resources to check all the conditions, if run is not = 0 then all other event is going to be skipped and potentially it could save you some resources and you can also use this variable to check if there was any variable with the value > 0. If run = 1 (or > 0) that means there was. So you can achieve both using a single variable.

But indeed, a break function to be able to break from a loop could be useful and more efficient.

1 Like

Thank You. I’ll try it. sooner than I thought.

it works fantastic! :+1:
Thank You very much!

LoL. today you helped me out again with this! I want to thank you again, and I want like the post again! why I can’t like a super useful post multiple times?! I want to do that!
anyways. Thank You again!