godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.16k stars 97 forks source link

Localize key labels based on keyboard language #10350

Open AdriaandeJongh opened 3 months ago

AdriaandeJongh commented 3 months ago

Describe the project you are working on

Rift Riff, a tower defense game localized to 12 languages.

Describe the problem or limitation you are having in your project

In order to fully localize my game and support full input remapping on keyboards, I need localized key labels.

OS.get_keycode_string(DisplayServer.keyboard_get_label_from_physical(physical_key)) returns only the English name for a key, even if the keyboard's language is not English. This means getting the keycode string for the physical Key.KEY_UP will, for instance, always return "Up" and not "Oben" when using a German keyboard, while the keycode string for the physical Key.KEY_BRACKETLEFT will correctly return Ü for a German Keyboard. This is in my opinion inconsistent.

As a sidenote, it is very confusing that DisplayServer.keyboard_get_label_from_physical(physical_key) returns a Key as opposed to a String. I don't understand how it returns an enum (Key) and yet the method's description says it can return any unicode character? I must be misunderstanding something here because somehow it works in combination with OS.get_keycode_string() for characters like the Ü on German keyboards even though there is no Key enum value for that character specifically.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

A way to return the localized key label would enable me to localize my game and support full input remapping on keyboards.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

I don't know enough about the engine's inner workings to get specific here, but considering DisplayServer.keyboard_get_layout_language() exists, this means that the keyboard's language is available to Godot. Either OS.get_keycode_string() should return the key label translated to the keyboard's language, or a method (something along the lines of get_localized_key_label()) could be added to OS or DisplayServer or TranslationServer to get the localized label for the key based on the language of the keyboard.

If this enhancement will not be used often, can it be worked around with a few lines of script?

Right now, a workaround is to add the majority of English names for keys (from this list) to my game's localization and add checks to see what keys to translate manually using tr() before I display the label to players.

Is there a reason why this should be core and not an add-on in the asset library?

Both localization and input remapping are necessary features in a fully fledged game, and both features increasingly expected by players. I believe this is an issue for any localized Godot game supporting input remapping and relevant to every game developer serious about marketing.

AdriaandeJongh commented 3 months ago

One fairly silly 'workaround' I just thought of applying to my project is to use the HTML characters for the common key labels with no letters, eg: ↑ ← ↓ → ↵ ␣ and more. Unfortunately this doesn't work for all characters (like Escape), but it's kinda' an ok solution for now?

bruvzg commented 3 months ago

As a sidenote, it is very confusing that DisplayServer.keyboard_get_label_from_physical(physical_key) returns a Key as opposed to a String. I don't understand how it returns an enum (Key) and yet the method's description says it can return any unicode character?

It's retuning 32-bit integer, Unicode use only lower 20 bits (valid codepoint range ends at 0x10FFFF). And all special Key enum values have bit 22 set, so the returned value can be either enum value or Unicode codepoint.

bruvzg commented 3 months ago

I don't know enough about the engine's inner workings to get specific here, but considering DisplayServer.keyboard_get_layout_language() exists, this means that the keyboard's language is available to Godot.

Keyboard language code is available, I do not think any OS API give localized key names.

Right now, a workaround is to add the majority of English names for keys (from this list) to my game's localization and add checks to see what keys to translate manually using tr() before I display the label to players.

SThe only way to implement it is likely something like this, embedding the full set of translation for every language in existence (which will require maintaining all of the translations and will bloat export size).

Also, some of the names returned by get_keycode_string aren't exactly plain English, like AsciiCircum or AsciiTilde (and a lot of other names in CamelCase without spaces). So I would consider returned values as String identifier (e.g., something to store in a editable config file), not a readable text presented to end users.

Calinou commented 3 months ago

Keyboard language code is available, I do not think any OS API give localized key names.

I'm fairly sure there's clearly an API for it on Windows, although the key label is relative to the keyboard layout's language (and not the system or in-game language). I've seen a lot of AAA games display kley names in French because I use an AZERTY keyboard layout, even though my Windows and the game are both configured to run in English.

You can see an example in the video in https://github.com/godotengine/godot/pull/94496#issuecomment-2237851614, where "Echap" is displayed instead of "Escape".

I don't know about macOS and Linux though.

stephanbogner commented 1 month ago

I am working on the same problem currently, two points to add

(1) Mixing sprites and labels My plan to use a mix of sprites and labels. E.g. sprites for distinctly looking keys like enter, tab or caps-lock, but a plain key with a label in Godot on top for most others in order to show what player's will see on their keyboards (e.g. the "ctrl" key spells "strg" in German)

(2) Different ways to express I am developing on Mac which might differ from Windows, but for example OS.get_keycode_string and event.key_label returns "Minus" instead of "-" which I'd prefer as it actually is what is commonly printed on the key. (I will likely just use sprites for this case as well)