Buttons text remains 'Left to Right' (RTL) when the game runs in 'Right to Left'

Started by Gal Shemesh, Tue 20/06/2023 11:22:23

Previous topic - Next topic

Gal Shemesh

Hi everyone,

I've made a 'Right to Left' (RTL) Hebrew version for the template game that comes with AGS, with a translation file (Hebrew.trs), as explained in the manual, and it works quite fine. The only problem I encounter with is that although most of the text switches to be written from 'Right to Left', all the buttons text remains written from 'Left to Right'.

I've set the TextDirection to RIGHT in my translation file as all other text strings (as far as I found) appears correctly, so I'm in doubts what goes wrong...

Thanks
Gal Shemesh,
goldeng

Crimson Wizard

I noticed this recently when investigating how RTL works in AGS. This is the original behavior, and I have no explanation to this. Could be an oversight of the AGS creator, or some hidden intent which meaning was lost in time.

I would also test other things, such as ListBox and TextBox.

This could be fixed in the upcoming version 3.6.1, or a patch to 3.6.0.

Snarky

In the mean time, you can use this function to reverse a String:

Code: ags
String Reverse(this String*)
{
  String reverse = "";
  for(int i=this.Length-1; i>=0; i--)
  {
    reverse = reverse.AppendChar(this.Chars[i]);
  }
  return reverse;
}

You call it like:

Code: ags
  myButton.Text = myString.Reverse();
  // ... Or if that doesn't work:
  String transString = GetTranslation(myString);
  myButton.Text = transString.Reverse();

(Untested, so let me know if you have any problems with it. The results may be unexpected if the String contains linebreaks.)

Gal Shemesh

Thanks @Crimson Wizard and @Snarky for the prompt replies. Much appreciated.

I didn't get to testing ListBox and TextBox yet. Being working on upgrading the template so both me and other users could benefit from having a pre-made multilanguage template that has both a translation file and speech for 2 lanugages as a starting point. I'm doing the voices for both languages myself. :)

Anyway, for the meantime I just wrote the Hebrew text backward in the translation file. Not the best way but I prefer to have it this way than in code as if it will be in code I might forget that it is broken in the first place. Hope that it will be fixed in a coming update.

I just posted another issue that appears like a bug with buttons, where if you have a function that changes the button text and it is based on a particular text for the function to keep functioning, then the function gets broken when the text on the button is shown based on the translation file. It looks like buttons don't work very well with translation in general at the moment. Here's a link to the other issue if you can take a look please. Thanks
https://www.adventuregamestudio.co.uk/forums/advanced-technical-forum/template-voice-and-text-trigger-button-code-breaks-in-translation/new/#new
Gal Shemesh,
goldeng

Crimson Wizard

I opened a draft for changing this, but there's a number of questions following:
https://github.com/adventuregamestudio/ags/pull/2044

Questions are this:
1. Do we need a per-control setting that tells whether to apply RTL render? Alternatively, all GUI controls have a hidden "translated" flag, which is set by default, although only ListBox has a visible property in the editor (because list boxes may be used to store saves and other filenames, which must not be translated). We could make this flag tell whether to apply RTL as well.
2. How to deal with a situation when original text has one RTL mode, translation has another, but is missing an entry. Should the original text be drawn in original mode instead? For example: English game with Hebrew translation. Currently RTL is applied unconditionally. Should it be applied according to whether the text is original or got from translation?

Gal Shemesh

Quote from: Crimson Wizard on Thu 22/06/2023 01:38:26I opened a draft for changing this, but there's a number of questions following:
https://github.com/adventuregamestudio/ags/pull/2044

Questions are this:
1. Do we need a per-control setting that tells whether to apply RTL render? Alternatively, all GUI controls have a hidden "translated" flag, which is set by default, although only ListBox has a visible property in the editor (because list boxes may be used to store saves and other filenames, which must not be translated). We could make this flag tell whether to apply RTL as well.
2. How to deal with a situation when original text has one RTL mode, translation has another, but is missing an entry. Should the original text be drawn in original mode instead? For example: English game with Hebrew translation. Currently RTL is applied unconditionally. Should it be applied according to whether the text is original or got from translation?

1. By per control do you mean that all GUI elements (apart from List Boxes that already have it) will have the hidden 'Translated' bool flag visible in the editor? If so then that could be great, as one may want to keep a certain button for example in the original language, without it being affected by the translation file.

Regarding List Boxes that serves for game saves: I'm not sure how AGS handles it if the list box is set to accept other languages input, like Hebrew. I do remember from some the Hebrew version games that we could write our game saves description in Hebrew, while the filename created was always in English and with a general syntax of SaveXXX. But anyway, having a separated RTL bool option so the user could set whether the specific element should be switched to show text in RTL based on the translation file then that would be even better, as it gives more control on the appearance of the elements. I think that such bool should be for all GUI elements.

2. As for a missing entry - do you mean if the translation file has not been filled with a transation for a particular line yet but an empty line below the original text? If so then I think that the engine should always be based on the original; if the original is in English which is LTR then have the original text appear at the missing entry in LTR.
Gal Shemesh,
goldeng

Gal Shemesh

Hi @Crimson Wizard

I have some more feedback to share. I've just finished my short game and also fully translated it to Hebrew - I have found that GUI buttons still show from left-to-right, although the rest text of the game shows correctly based on the translation file. Was this supposed to be fixed in the recent patch?

I also found these problems so I share my feedback below if you find it required for future fixing:

- The 'game title' property from the General Settings doesn't have a line in the translation file. So if it's shown on a statusline in the game then it shows the English title backwards.

- Numbers (including Scores) and parentheses signs shows flipped. For example, the number 12 is shown as 21, and a string of "(something)" in parentheses shows as ")someting(".

- If there's a string with a mix of Hebrew and English, the English text is shown from right-to-left instead of from left-to-right.
 
All these matters can be worked-around by writing their content backwards. But the main problem is with the buttons that don't present the text from right-to-left based on the translation file //#TextDirection=RIGHT option.

Last thing which I guess is by design, but maybe probably not brought too much to the attention as most games are in English: when including speech files pointers, for exapmle character.Say("&1 some line") or having a pointer in dialogue option cells, the pointer which is part of the string gets included for the English lines in the translation file. This requires to copy and paste them as well in the translated lines below them, or else the speech file will not play. So my question, is there another way to include pointers to speech files but not to include the & sign in the actual strings? I can use the custom function that @Khris assisted me with for making the narrator to play speech files, but I'm not sure how this can be implemented for dialogue options.

Thanks
Gal Shemesh,
goldeng

Crimson Wizard

Quote from: Gal Shemesh on Tue 25/07/2023 00:56:55I have some more feedback to share. I've just finished my short game and also fully translated it to Hebrew - I have found that GUI buttons still show from left-to-right, although the rest text of the game shows correctly based on the translation file. Was this supposed to be fixed in the recent patch?

There have been a mistake made with buttons, where it uses the settings inverse. I did not notice this in time. It should be fixed in the temp build here, but there will be another beta update soon too:
https://cirrus-ci.com/task/4938154059235328



Quote from: Gal Shemesh on Tue 25/07/2023 00:56:55- The 'game title' property from the General Settings doesn't have a line in the translation file. So if it's shown on a statusline in the game then it shows the English title backwards.

This might be years old error, probably nobody paid attention. I'll double check, but I suppose this may be fixed easily.

Quote from: Gal Shemesh on Tue 25/07/2023 00:56:55- Numbers (including Scores) and parentheses signs shows flipped. For example, the number 12 is shown as 21, and a string of "(something)" in parentheses shows as ")someting(".

The current implementation of RTL in AGS is: when text is reversed - everything is reversed, it does not parse the string to know what's inside, so digits and everything else will be in reverse order as well.
This indeed can lead to parentheses look wrong: if you have a string "(abcdefg)" and reverse it, then you'll have ")gfedcba(".

The existing solution was added in the 3.6.1 beta: set label to non-translating if it's meant to display numbers. Or workaround by creating dynamic untranslated string perhaps.


Quote from: Gal Shemesh on Tue 25/07/2023 00:56:55- If there's a string with a mix of Hebrew and English, the English text is shown from right-to-left instead of from left-to-right.

As been mentioned few times in the past, the AGS does not detect the language inside the text, it only uses the global option. If the option sais "RTL", then it will reverse everything.
This may be solved only by supporting the rendering using Unicode control characters which separate LTR and RTL parts in the text.
 

Quote from: Gal Shemesh on Tue 25/07/2023 00:56:55Last thing which I guess is by design, but maybe probably not brought too much to the attention as most games are in English: when including speech files pointers, for exapmle character.Say("&1 some line") or having a pointer in dialogue option cells, the pointer which is part of the string gets included for the English lines in the translation file. This requires to copy and paste them as well in the translated lines below them, or else the speech file will not play.

Yes of course this is by design, and there have been alot of translated games in the past, as well as certain amount of games in other languages, so either this was not bothering anyone, or nobody was bothered enough to report this as a problem, at least in my memory.
Currently, when game runs with translation, it passes the already translated line into the speech system, so that system does not know the original voice number at that time. I don't think that we can enforce automatically propagating voice numbers from source lines, as user might want to have a custom behavior with the particular translation too. But i guess that in theory we could support a translation option that does that (along with text direction and other things).

Quote from: Gal Shemesh on Tue 25/07/2023 00:56:55So my question, is there another way to include pointers to speech files but not to include the & sign in the actual strings? I can use custom function that @Khris assisted me with for making the narrator to play speech files, but I'm not sure how this can be implemented for dialogue options.

I'd like to clarify what is the problem, is it that you have to copy this sign, or that you cannot or do not want to use this particular & sign in the translation?

If you like to have your own meta-information in the strings, then that's perfectly doable with certain effort, where you parse the text in your custom function, display text using one method and play voice explicitly using Game.PlayVoiceClip (as an example).

The custom functions may be used in dialog scripts if you assign their names in General Settings ("Custom Narrate function in dialog scripts" and "Custom Say function in dialog scripts".

Unfortunately the dialog option titles themselves won't work like that, there's a difference in how these are processed in the engine, and previously I was not able to make this work easily.
The workaround is to uncheck the "Say" checkbox at the option, and duplicate the option's text in the dialog script as the first line by the player.

Gal Shemesh

Thank you so much @Crimson Wizard for taking the time to realte to all my queries! Much appreciated. :)

You gave me answers to everything, so I'll just wait for the next stable build with the buttons text fix and the set label to non-translating option for the score label.

As for the clarification about the '&' sign with the speech file number:
personally I'd prefer to have the pointer to the speech file only from the editor script side, so it won't show as part of the string. The reason is that it makes the translation process more fragile, as there's more place for errors which will only occur in the translated line if they're not written properly, either by a mistype or by forgetting to put the pointer at all. And then you can find yourself have to go all over your translation file again line-by-line to fix this - happened to me just last night.

Personally (and I might be mistaken), I don't see why someone will want to have a custom behavior with the particular translation in terms of speech files, since AGS by design uses the same index speech file numbers for all languages, and knows to pick the appropriate file from the sub-directories in the Speech folder if a translation is used. So while Ego1.wav in the root of Speech is used for the default langauge, Ego1.wav in Speech\Hebrew for examlpe is used as the speech file of the same line, only in Hebrew voice-over. So why would someone want to have it point to a different number? I mean, wouldn't it make a mess troubleshooting afterwards?

Hope it makes sense. :)

*By the way, maybe it's my bad but I've found that when I accidently clicked on the Update option instead of on Compile in on the translations file entry in the editor, I got duplications of the same lines in different places in the translation file. Maybe it was after fixing something in some lines, and then reverting them back as they were before the change and it caused the original version of the strings to appear more than once in the translation file. Is this normal? When this happens, I'm not sure where should I put the translation lines: under the old line of the same string in the translation file or under the new line...?

**Also, when I began the translation process and troubleshoot the different issues, I found that if I remove the translation file from the game directory altogether, that the editor then refuses to load the game afterwards; I had to take a translation file from a backup I had in hand and to copy it to the game's folder in order for the game to load again. Deleting the translation file from within the editor doesn't cause any issues loading the game without a translation file, though.
Gal Shemesh,
goldeng

Crimson Wizard

Quote from: Gal Shemesh on Tue 25/07/2023 11:11:42You gave me answers to everything, so I'll just wait for the next stable build with the buttons text fix and the set label to non-translating option for the score label.

This Translated property is already available in the 3.6.1, I discussed this in the "RTL" issue ticket, and noted in the changes list in the 3.6.1 release thread.

Quote from: Gal Shemesh on Tue 25/07/2023 11:11:42personally I'd prefer to have the pointer to the speech file only from the editor script side, so it won't show as part of the string. The reason is that it makes the translation process more fragile, as there's more place for errors which will only occur in the translated line if they're not written properly, either by a mistype or by forgetting to put the pointer at all. And then you can find yourself have to go all over your translation file again line-by-line to fix this - happened to me just last night.

This is how the translation system works in AGS at the moment - it writes source texts as translation keys as-is, also regardless of any meta data in them. The speech sign is only one potential problem, there are others, like typos, or the fact that same text in language A may have different translations in language B depending on a context. This is an issue of its own, and fixing this properly would require a major redesign of the translation system in the engine (as well as adjusting any plugins that rely on current system).

There's also no such thing as "editor script side", the texts that are part of the script or properties are compiled into the script or game data as-is. If we wanted to separate speech tags from them, we would have to introduce a new separate part of data for each string.

Quote from: Gal Shemesh on Tue 25/07/2023 11:11:42I don't see why someone will want to have a custom behavior with the particular translation in terms of speech files, since AGS by design uses the same index speech file numbers for all languages

No it does not use same index speech file by design. It uses whatever is written in the text. Besides the voice-over was not supported for multiple languages before 3.6.0, it's a very new feature, that has not been fleshed out yet.

But, regardless, by "custom behavior" I meant that the users may want to parse and process the language texts themselves in the script, and execute text and voice-over using custom methods, by either parsing default AGS speech tags, or having completely custom meta-data. If engine would enforce playing a voice-over depending on its presence in the source text, that would conflict with such approach.


Quote from: Gal Shemesh on Tue 25/07/2023 11:11:42*By the way, maybe it's my bad but I've found that when I accidently clicked on the Update option instead of on Compile in on the translations file entry in the editor, I got duplications of the same lines in different places in the translation file. Maybe it was after fixing something in some lines, and then reverting them back as they were before the change and it caused the original version of the strings to appear more than once in the translation file. Is this normal? When this happens, I'm not sure where should I put the translation lines: under the old line of the same string in the translation file or under the new line...?

It is also a known problem that any change to a source text will cause it to create a new entry in the translation.
Solving this also needs a translation system redesign.

Quote from: Gal Shemesh on Tue 25/07/2023 11:11:42**Also, when I began the translation process and troubleshoot the different issues, I found that if I remove the translation file from the game directory altogether, that the editor then refuses to load the game afterwards

Editor is rather sensitive to the removal of project files. I might fix it to let it load at least.

Crimson Wizard

The situation with the speech numbers is actually even worse, because you can switch speech.voxes regardless of the language, that is have text in one lang and speech in another.

But if the speech numbers are different or missing in the translation, then it's possible to play mismatching voice-over in "original" language.

In other words, the speech numbers in translation of language A will be controlling voice-over in language B. And it is possible that neither of those two languages are the "original language", which means that we may not even have access to the texts in language B to check if numbers are matching, since these texts will not be loaded.

This is a very serious oversight by me in this feature, I did not realize this when adding support for multiple speech.voxes. I'm not really certain how to improve this properly now. Some very serious thought has to be put into this.

But at the moment it seems that you must keep same numbers everywhere, to avoid breaking things.

EDIT: So, apparently, the source text must enforce the voice number, contradictory to what I stated above.
the source text is always available (loaded in memory), therefore it's possible to check its contents.
But this will require numerous changes in the engine, because currently it's coded in such way that the original text is discarded and replaced by translation very early, and the translated text is then passed further into the speech functions.
Also, it's not immediately clear which potential problems this may cause.
This problem has to be documented and thought through very well before changing anything.

This is definitely not for 3.6.1 update.

Gal Shemesh

Thanks @Crimson Wizard, I much appreciate all your input.

For the time being I managed to create this custom function (end of page 2) to make character speech without having the '&' pointer in the actual strings, and so the translation file is now cleaned from speech file pointers whatsoever.
Gal Shemesh,
goldeng

Crimson Wizard

Quote from: Gal Shemesh on Tue 25/07/2023 14:47:54For the time being I managed to create this custom function (end of page 2) to make character speech without having the '&' pointer in the actual strings, and so the translation file is now cleaned from speech file pointers whatsoever.

I have to clarify, that this function type won't work with the settings "custom say/narrate function in dialog scripts", because it currently expects function to have a single string argument. This is tied to how dialog scripts are parsed, so I don't see any feasible way to support an arbitrary function prototype at the moment.

Therefore it has to be called explicitly in the dialogs (with "custom function" settings one may use classic dialog script in the form of "charname: sais").

Gal Shemesh

Quote from: Crimson Wizard on Tue 25/07/2023 15:38:23
Quote from: Gal Shemesh on Tue 25/07/2023 14:47:54For the time being I managed to create this custom function (end of page 2) to make character speech without having the '&' pointer in the actual strings, and so the translation file is now cleaned from speech file pointers whatsoever.

I have to clarify, that this function type won't work with the settings "custom say/narrate function in dialog scripts", because it currently expects function to have a single string argument. This is tied to how dialog scripts are parsed, so I don't see any feasible way to support an arbitrary function prototype at the moment.

Therefore it has to be called explicitly in the dialogs (with "custom function" settings one may use classic dialog script in the form of "charname: sais").

Yep, you're 100% correct. I've just finished modifying my entire mini-game to use this custom function, and all the dialogues to use the regular scripting with indentation; I also find it quite straightforward when copying 'saying' lines from regular scripts to dialogue scripts and vice versa, as I don't use the unique dialog scripting.

I also removed all the '&' signs from the translation file, so I now have a cleaned file with just the literal strings in it which looks and works great! :)

The only thing I'm trying to figure out now is how to set the dialogue selection options when the dialogue starts to align to the right of the screen, as currently they're aligned to the left.
Gal Shemesh,
goldeng

Crimson Wizard

Quote from: Gal Shemesh on Tue 25/07/2023 17:47:24The only thing I'm trying to figure out now is how to set the dialogue selection options when the dialogue starts to show from right-to-left on the screen

If you mean that the dialog options cannot be aligned to the right side, that's apparently another thing that is not supported in AGS. There's a number of elements that may be drawn besides the option text, such as "bullet" icons and option numbers, all this has to be accounted if alignment is implemented.

At the moment the only alternative is to use custom dialog options render:
https://adventuregamestudio.github.io/ags-manual/CustomDialogOptions.html

Gal Shemesh

Yep, I meant the alignment to the right. Thought I'm just missing an option as I took alignment for granted as a built-in option.

Anyway, thanks for the custom dialog options render suggestion and link! However, as I'm using 'Wait()' functions from within the dialogues in traditional scripting to make some 'pause' between the conversations, this may not work for me. As if I understood correctly from what is written there, blocking functions can't be used...
Gal Shemesh,
goldeng

Gal Shemesh

QuoteEditor is rather sensitive to the removal of project files. I might fix it to let it load at least.
Forgot to relate to this:

Thanks! That would be great if the project could be at least loaded if a translation file is missing.

QuoteIt is also a known problem that any change to a source text will cause it to create a new entry in the translation.
Solving this also needs a translation system redesign.
I wanted to note that I've found that even if the editor makes duplicated lines, manually editing of the trs file and removing them (while their exact version already exists above in the file) and then recompiling it, makes the editor to relate the original lines again. And then, if you re-update the translation file from the editor it doesn't make duplications in the trs file for these lines again.

I wouldn't touch the way that translation and speech are currently working in AGS; during trial and error I managed to develop some best practice and got a grip on the sensitivity of the translation file, in a way that I'm more experienced now in fixing things in it before the issues even arise. I also made a sophisticated Excel file for writing all the strings used in the game, along with formulas of direct links to the speech files of each line so you could listen to them directly from the Excel when doing either the English voice recording or voice-over; its structure is the same as the trs file, with odd lines for the original text and even lines for the translation. So if something goes wrong I can simply generate a new translation file, and then copy and paste all the lines from my Excel to it.

I will probably make an online tutorial showing this method as this may help others - by building a game that way this can save a lot of time afterwards, in both dubbing and translating process.
Gal Shemesh,
goldeng

Crimson Wizard

Quote from: Gal Shemesh on Fri 28/07/2023 00:44:31I also made a sophisticated Excel file for writing all the strings used in the game, along with formulas of direct links to the speech files of each line so you could listen to them directly from the Excel when doing either the English voice recording or voice-over

This seems similar to what the SpeechCenter plugin does:
https://www.adventuregamestudio.co.uk/forums/modules-plugins-tools/editor-plugin-speech-center-version-2-2-0/

Gal Shemesh

Quote from: Crimson Wizard on Fri 28/07/2023 04:15:33This seems similar to what the SpeechCenter plugin does:
https://www.adventuregamestudio.co.uk/forums/modules-plugins-tools/editor-plugin-speech-center-version-2-2-0/

Ahh, didn't know that it exists. Thanks for pointing this out! Just checked it and found that there is some similarity, yet there are some differences:

I really like the idea that the plugin works directly in the editor, and that there's this feature that you can changes your entire game string directly from it; this is a very powerful feature. Yet I still find having an external file from the editor better, as I fear a little from plugins that can change my scripts - I prefer to do it manually, literly knowing that I'm the one who actually changing my scripts. :)

I also found a few issues, such as that the plugin didn't include my custom .Say function lines (I read the discussion of other members relating to this). Also, I've found that it considered some Display() messages as if my Narrator is saying them; I have a custom Narrate function for showing messages, but I'm not sure why it considered as if the Narrator is saying them, as I used a regular Display() function (not the custom one) in their case, such as when I click on the 'About' button to show some text on the screen.

As for the export to CSV, that's great but it lacks styling benefits. That is why I prefer to have a pure Excel (.xlsx) file; I made table-format which highlights odd and even lines in different color, making them much easier to read when translating. Here's a screenshot of the strings file from my recent 'Going Home' mini-game:


As for listening to either the original or voice-over speech files, the formula shown above is a local folder path link, and it gives you the freedom of having them play in your default media player program. The best thing is that you don't need to load the game in the editor for being able to see and click-to-hear the speech files next to the text lines, and you can even just send the Excel file along with the relevant speech files to your voice actors so they could work on them from their home.

Another note about how I handle audio files in advanced for saving time and effort later:
I made a very basic CMD script that lets you create copies of an 'empty-template audio file' of your choice, for setting up in advanced as 'placeholders' in scripts: the script asks you to choose a name for the file, along with the amount of files that you want. Then, it does all the work for you creating them in a Speech folder - if files already exist, it skips them so you don't end up with overwriting the precious speech files that you already recorded; for my convenience I made the empty file at the exact 1000KB in size, just so I could distinguish them in a detailed-list in File Explorer.

I made this script so I could provide speech files index number for my string lines in advanced, right when creating them in my scripts. This saves me time later, as once I have voice acting speech files I don't have to come back to each and every line in my scripts and manually add pointers to them; I just copy the most updated files over the empty ones and "tada"! :) Besides, it also lifts from your head the need for saving a new speech file and to manually give it a number after each recording (which could also have mistypes); you just open the empty placeholder audio file number that you need, record what you need, save and exit from it and move forward to the next file. And if you find that you need more placeholders, you just run the script again and give it a higher number.

Here's a GIF animation of how it works - I'm thinking about including this in my video tutorials:



I guess it's a matter of what works best for you, the same as we all make different ways for achieving the same goal. :)
Gal Shemesh,
goldeng

Gal Shemesh

Quote from: Crimson Wizard on Tue 20/06/2023 16:13:08I noticed this recently when investigating how RTL works in AGS. This is the original behavior, and I have no explanation to this. Could be an oversight of the AGS creator, or some hidden intent which meaning was lost in time.

I would also test other things, such as ListBox and TextBox.

This could be fixed in the upcoming version 3.6.1, or a patch to 3.6.0.
Only came to checking this now in the current game of a friend which I finished migrating to 3.6.0. The text boxes are also showing the Hebrew text backwards. I just checked saving in Hebrew and realized that writing in the text box is backward... I guess it's the same as with the labels.
Gal Shemesh,
goldeng

SMF spam blocked by CleanTalk