-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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
Change most ruleset-accessible string types to Localisable strings #19695
Conversation
Came across an issue where `LeaderboardScoreTooltip` attempts to capitalize all letters for the `displayName`. Unsure if I should completely ignore it and localise it anyway.
The argumentation for this revert is weak. Support for text case transformations on localisable strings is already in place. Please use these methods. This has zero testing. The new ctor that accepts (As an aside I'm a bit skeptical that the API there is going to fly. As I understand it, the design is such that both the label and the description must come from the same class with localisables, which I see becoming a problem down the line. But I guess this can be addressed in due time.) |
@@ -14,7 +15,7 @@ public class CatchModFloatingFruits : Mod, IApplicableToDrawableRuleset<CatchHit | |||
{ | |||
public override string Name => "Floating Fruits"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume the reason why mod names aren't also being localised here is their widespread usage, correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is correct. I can change it into a localisable string if preferred.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely not in this diff. There are many concerns to figure out with regard to that, including but not limited to how to share translations with web, or how to adapt several dependent projects like osu-tools.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the issue there? I think we can still reference osu.Resources from the rulesets.
I think if we're going to break Description
, we should also break Name
, otherwise we'll end up breaking rulesets twice over: https://github.com/taulazer/tau/blob/master/osu.Game.Rulesets.Tau/Mods/TauModDual.cs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure we should be localising mod names. They historically haven't been, as they are treated as proper nouns.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But you can transliterate proper nouns, as is done in Korean: https://osu.ppy.sh/wiki/ko/Gameplay/Game_modifier/Double_Time (lit. deobeul taim). I'm also seeing whisperings on the Japanese net about ハードロック and ダブルタイム.
Are you sure you want to keep these as latin characters?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a valid direction, but we need to decide and make sure everyone is on board with it. That shouldn't be in the PR, as I think there will be diverging opinions on it.
Currently they aren't translated in stable (or osu-web to my knowledge).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough.
@@ -48,7 +49,7 @@ public StatisticItem([NotNull] string name, [NotNull] Drawable content, [CanBeNu | |||
/// <param name="createContent">A function returning the <see cref="Drawable"/> content to be displayed.</param> | |||
/// <param name="requiresHitEvents">Whether this item requires hit events. If true, <see cref="CreateContent"/> will not be called if no hit events are available.</param> | |||
/// <param name="dimension">The <see cref="Dimension"/> of this item. This can be thought of as the column dimension of an encompassing <see cref="GridContainer"/>.</param> | |||
public StatisticItem([NotNull] string name, [NotNull] Func<Drawable> createContent, bool requiresHitEvents = false, [CanBeNull] Dimension dimension = null) | |||
public StatisticItem(LocalisableString name, [NotNull] Func<Drawable> createContent, bool requiresHitEvents = false, [CanBeNull] Dimension dimension = null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why isn't this
public StatisticItem(LocalisableString name, [NotNull] Func<Drawable> createContent, bool requiresHitEvents = false, [CanBeNull] Dimension dimension = null) | |
public StatisticItem(LocalisableString? name, [NotNull] Func<Drawable> createContent, bool requiresHitEvents = false, [CanBeNull] Dimension dimension = null) |
And no, this isn't a NRT issue or anything, because LocalisableString
is a struct. It's really weird to have a nullable name field, then one obsoleted ctor, and then another that receives the name, but the name isn't actually optional. It looks like a bug/misannotation.
Also, you will want to chase down all StatisticItem
s that pass string.Empty
as the name and update them to pass null
instead, because otherwise, this breakage happens:
master | this PR |
---|---|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fix looks ok, but this needs to be listed in the OP as a breaking change so that consumers know they also need to change empty strings to null
.
I've applied the changes requested, however, I don't understand what you mean here:
Do you mean that mod settings label and descriptions should be separated? Why can't it be unified in something like a |
As I said though, not a big deal. If a case ever arises where we want to pull the title from one localisation class and the description from another, the current setup can be trivially extended to support it. |
Pushed one menial xmldoc cleanup (d06959e). Diff looks fine to me now, but given it contains breaking changes, I'm not merging without a second approval. I will say that the number of files touched is a bit ridiculous (nearing on a hundred), but given they're 95% menial type changes and the diffstat altogether still has an acceptable size, I'm personally willing to look away this time. |
public SettingSourceAttribute(Type declaringType, string label, string? description = null) | ||
{ | ||
Label = getLocalisableStringFromMember(label) ?? string.Empty; | ||
Description = getLocalisableStringFromMember(description) ?? string.Empty; | ||
|
||
LocalisableString? getLocalisableStringFromMember(string? member) | ||
{ | ||
if (member == null) | ||
return null; | ||
|
||
var property = declaringType.GetMember(member, BindingFlags.Static | BindingFlags.Public).FirstOrDefault(); | ||
|
||
if (property == null) | ||
return null; | ||
|
||
switch (property) | ||
{ | ||
case FieldInfo f: | ||
return (LocalisableString)f.GetValue(null).AsNonNull(); | ||
|
||
case PropertyInfo p: | ||
return (LocalisableString)p.GetValue(null).AsNonNull(); | ||
|
||
default: | ||
throw new InvalidOperationException($"Member \"{member}\" was not found in type {declaringType} (must be a static field or property)"); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I fancy this custom implementation, but it's probably okay for now...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I was personally thinking it would be better to share this logic with osu!framework somehow.
@@ -59,7 +59,7 @@ public StatisticContainer([NotNull] StatisticItem item) | |||
|
|||
private static Drawable createHeader(StatisticItem item) | |||
{ | |||
if (string.IsNullOrEmpty(item.Name)) | |||
if (item.Name == null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this going to handle string.Empty
incorrectly now?
@@ -18,7 +19,7 @@ public class StatisticItem | |||
/// <summary> | |||
/// The name of this item. | |||
/// </summary> | |||
public readonly string Name; | |||
public readonly LocalisableString? Name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need to be nullable? Shouldn't a user just be providing string.Empty
as before rather than null?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I was going to suggest this as well. I think there's a difference between default(LocalisableString)
and (LocalisableString)string.Empty
, though, and we don't provide a LocalisableString.IsNullOrEmpty()
or similar method.
I would agree with this being non-null, but I think we need that method to do so.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For sure. I think a method like this should be added here or framework before this change is made.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be fine if I were to add the LocalisableString.IsNullOrEmpty()
within osu! then later on move it to the framework side of things?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm already in the process of adding it. I think this change can wait on it.
I think these changes look okay, but how does this work in practice? ie. how does a ruleset source localisation resources? Would it have to add its localisations to the global localisation stores? Also noticed that osu/osu.Game/Rulesets/Ruleset.cs Line 291 in edc4ace
|
I believe it doesn't need to, since |
Crazy. Thoughts on the variant name method? Should we just change while we're here? |
I'd agree with changing |
Commits of interest:
Revert localisation for GetDisplayNameForHitResult (1e356f6
) -- Read description7cbe2fa
)Breaking changes
Mod.Description
type has been changedResumeOverlay.Message
type has been changedRuleset.GetDisplayNameForHitResult(HitResult)
type has been changedRuleset.GetVariantName(int variant)
type has been changed