Localisation for Input Keys

I’ve been using the new input system’s automatic human readable string InputControlPath.ToHumanReadableString.
Really love the idea and it works super well with rebinding, thanks a lot!

The one issue I’m having is that these are not localized. ‘Space’ is ‘Espace’ in french for instance.

Is there already a solution present to localize this? I have not found one. It seems like something that the community could be working on together if not, as all devs wanting to use this will face the same issue.

I’ve taken the liberty to start a project on GitHub if anybody wants to contribute:
https://github.com/GieziJo/UnityInputSystemLocalisation

Happy to scrap it if something better already exists, just didn’t find anything :smile:

2 Likes

I did some prototyping on how we could handle Input some time ago.
It’s still on the plan to look into this more but I cant say when we will get to it, its quite low down the list.

This is what I had, I was planning to make a global variable so users could type {input.action-name}.

#if PACKAGE_INPUT
using UnityEngine.InputSystem;

// TODO: Support localizing the input names, e.g "Right Trigger". Maybe hook into an optional StringTableCollection which would need to be preloaded.

namespace UnityEngine.Localization.SmartFormat.GlobalVariables
{
    struct InputActionVariable : IGlobalVariable
    {
        InputAction m_Action;

        public object SourceValue => this;

        public InputActionVariable(InputAction action) => m_Action = action;

        public override string ToString() => m_Action.GetBindingDisplayString();
    }

    [CreateAssetMenu(menuName = "Localization/Global Variables/Input System Mapping Group")]
    public class InputSystemMappingGroup : GlobalVariablesGroupAsset
    {
        [SerializeField]
        InputActionAsset m_ActionsAsset;

        public override IGlobalVariable this[string key]
        {
            get
            {
                var action = m_ActionsAsset.FindAction(key);
                if (action != null)
                    return new InputActionVariable(action);
                return null;
            }
        }

        public override bool TryGetValue(string key, out IGlobalVariable value)
        {
            var action = m_ActionsAsset.FindAction(key);
            if (action != null)
            {
                value = new InputActionVariable(action);
                return true;
            }

            value = default;
            return false;
        }
    }
}
#endif

This doesn’t localize the actual values, just extracts them. The next step would be to do what you are doing.

1 Like

Oh that looks cool!
So if I understand correctly this would map the defined input actions to the strings. But would this work for rebinding of input keys for multiplayer? For that one you need the PlayerInput specific Input binding as far as I understand, right?

For the problem of specifically translating keys to other languages I don’t suppose there are any plans yet?

Thanks a lot for your inputs!

Regarding your remark:

Would that be easier now with Nested Translations?

I’m not sure it would work with nested translations. You still need to extract the Bindings Display String from the action, once that’s done then you may as well just call LocalizationSettings.StringDatabase.GetLocalizedString. Im not sure how it could work as a nested translation unless you were to update the nested translation persistent variable instead.
E.G have a LocalizedString with:

English → “Press {action-name} to Jump”
action-name is a local LocalizedString
https://docs.unity3d.com/Packages/com.unity.localization@1.3/manual/Smart/Persistent-Variables-Source.html

You change the value of action-name in script:

public LocalizedString myString = new LocalizedString("My String Table", "My Game Text")
{
    // These variables will be visible in the inspector Local Variables field.
    { "action-name", new LocalizedString() },
};

void UpdateText(string action)
{
    var action = m_ActionsAsset.FindAction(action);
    var key = action.GetBindingDisplayString();

    var nested = myString["action-name"] as LocalizedString;
    nested.SetReference("My Table", key);
}

You would have entries in the table such as

Key: Right Trigger
English: Right Trigger
etc

That should work. You still need a script to do the conversion from InputSystem action though.
You could try returning a LocalizedString in TryGetValue instead. You would need to call GetSourceValue on the localizedString and return that result.

1 Like

Gotcha!

I’ve made some headway with this, but currently I’m stuck on how to hook up the IVariableValueChanged.ValueChanged event. I am detecting when the input device changes and firing the event on my IVariables, but it seems that with a custom ISource, that event is not subscribed to by default. Even though I’m adding the IVariable to the FormatCache.VariableTriggers. I guess I don’t understand the localization framework good enough to know how my code ties into LocalizedString.UpdateVariableListeners

Here’s a gist with the essential files (essentially an elaboration of the code you posted above)

https://gist.github.com/noio/5209550ebcb049da763f521027ec50f5

[EDIT: I’m realizing that this is still on the ‘Input System’ forum, and this is squarely a Localization System question, I’ll post over there: https://discussions.unity.com/t/893466 ]

1 Like