Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simple localisation for framework-side strings #6075

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

Susko3
Copy link
Member

@Susko3 Susko3 commented Dec 4, 2023

RFC

This shows an idea for how to allow games to provide translation and customisation of framework-side strings. The idea is to provide static *Strings.cs classes that have static LocalisableString/TranslatableString properties (like how osu! does it). Framework would use these strings where applicable. Only English fallback strings are provided, translations in framework are not currently considered.

Consumers then have a stable way of getting the lookup key of framework strings and can do whatever with them in ILocalisationStore.Get().

Some examples of what consumers could do:

  • change framework strings to their liking, eg. "Joystick {0}" → "🎮 {0}"
    • for osu! crowdin: we need to consider how is the source strings displayed to translators, we'd want it to be the changed text, not the framework fallback
  • remap strings/keys to existing strings that are translated in the game
  • consume the framework *Strings.cs files in their own translation tooling to provide translations

Example implementation of remapping framework strings to existing osu! strings:

diff --git a/osu.Game/Localisation/ResourceManagerLocalisationStore.cs b/osu.Game/Localisation/ResourceManagerLocalisationStore.cs
index 3fa86c188c..0e4ba369ee 100644
--- a/osu.Game/Localisation/ResourceManagerLocalisationStore.cs
+++ b/osu.Game/Localisation/ResourceManagerLocalisationStore.cs
@@ -11,6 +11,7 @@
 using System.Resources;
 using System.Threading;
 using System.Threading.Tasks;
+using osu.Framework.Extensions.LocalisationExtensions;
 using osu.Framework.Localisation;
 
 namespace osu.Game.Localisation
@@ -19,6 +20,12 @@ public class ResourceManagerLocalisationStore : ILocalisationStore
     {
         private readonly Dictionary<string, ResourceManager> resourceManagers = new Dictionary<string, ResourceManager>();
 
+        private static readonly Dictionary<string, string> framework_remapping = new Dictionary<LocalisableString, LocalisableString>
+        {
+            [Framework.Localisation.Strings.CommonStrings.Paste] = CommonStrings.Paste,
+            [Framework.Localisation.Strings.CommonStrings.Copy] = CommonStrings.Copy,
+        }.ToDictionary(p => p.Key.GetTranslationKey(), p => p.Value.GetTranslationKey());
+
         public ResourceManagerLocalisationStore(string cultureCode)
         {
             EffectiveCulture = new CultureInfo(cultureCode);
@@ -30,6 +37,9 @@ public void Dispose()
 
         public string Get(string lookup)
         {
+            if (lookup.StartsWith(@"osu.Framework", StringComparison.Ordinal) && framework_remapping.TryGetValue(lookup, out string newLookup))
+                lookup = newLookup;
+
             string[] split = lookup.Split(':');
 
             if (split.Length < 2)

Future work

framework

  • use ppy/osu-localisation-analyser to make it easier to add new localisations
  • add simple localisations for more strings
  • localise inputkey/keycombination

osu!

…`LocalisableString`

Since `Data` is `internal`, a helper method is needed.
The shape of `WindowModeStrings.cs` modelled after osu! localisations.
Since the extension method is intended for a very specific use case, the name `GetKey()` felt too generic.
@smoogipoo
Copy link
Contributor

I think that this is fine. Tooling will need some additional work to behave well. Did you have anything else planned for this, or is it ready to go? Since it's a proposal/RFC atm.

@Susko3
Copy link
Member Author

Susko3 commented Mar 5, 2024

It's ready to go, I think this is all that's required to start experimenting with osu!-side support.

@frenzibyte
Copy link
Member

With the string remapping logic proposed here, how do you envision translation strings being generated for Crowdin? Are all framework localisation strings going to be translatable via Crowdin? Or do they all have to be remapped osu!-side with corresponding strings that's translatable in Crowdin?

I'm asking this question because it looks like currently such framework strings will appear as translatable in Crowdin but not taking effect because they're remapped to another string.

I think the remapping logic does not need to exist, and any osu!-side translation strings should be migrated to the corresponding framework-side string.

Even for overriding the english version of the string like in the Joystick keys case, why not just change the form in osu!framework and call it a day? We have icon support in framework, no?

@Susko3
Copy link
Member Author

Susko3 commented Mar 6, 2024

If we can get framework strings into crowding and not have to do any remapping, that would be great.

The idea of remapping framework strings to osu strings is given as a fallback option that should work without changes to the crowdin workflow. In case there's trouble with adding the strings to crowdin and exporting framework translations to game files.

I think the remapping logic does not need to exist, and any osu!-side translation strings should be migrated to the corresponding framework-side string.

I'm not too fussed about duplicate strings (eg. for "Paste"). Crowdin has translation memory that will suggest a 100% match. Applying a translation will be one-click.

Even for overriding the english version of the string like in the Joystick keys case, why not just change the form in osu!framework and call it a day? We have icon support in framework, no?

If we get framework strings in crowdin, changing them to suit osu! makes sense.

@frenzibyte
Copy link
Member

frenzibyte commented Mar 10, 2024

I'm not too fussed about duplicate strings (eg. for "Paste"). Crowdin has translation memory that will suggest a 100% match. Applying a translation will be one-click.

That's just adding unnecessary work to the translator, I don't agree with this.

If we can get framework strings into crowding and not have to do any remapping, that would be great.

The idea of remapping framework strings to osu strings is given as a fallback option that should work without changes to the crowdin workflow. In case there's trouble with adding the strings to crowdin and exporting framework translations to game files.

I would rather avoid adding complexity to the way localisations are processed if we can. I propose the following:

  1. Not involve input keys with localisation and unlink KeyButton overlapping key binding label osu#6526 from this thread (to avoid having this "remapping" logic for the sake of osu! changing the form of a framework entlish string)
  2. CommonStrings.Copy/CommonStrings.Paste should be migrated from osu! to framework, and no extra code for "remapping" should exist (osu! should use strings from framework).
  3. Framework-side localisation strings should be processed similar to osu! strings and published to crowdin.

@peppy thoughts on this direction? since you're the one handling the process of updating localisations across the repos.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants