In-game 'Recent' profile section is not localised
Type
Localisation
Bug description
Doesn't seem to change even when reloading the profile after changing both in-game and web language: it stays in English.
Screenshots or videos
An example of my profile with the supporter message (but it's not limited to that one). Notice the Italian title:
Version
2024.312.1
Logs
n/a
Almost forgot about the Kudosu! section. That one's also always in English. (Simple guess is that there's no indication to retrieve the data in a different language in those API calls..?)
Probably needs https://github.com/ppy/osu-framework/pull/5632 (non-working right now).
But I managed to make a diff (has some copypaste issues, but is POC) that resolves this (hardcoding markdown formatting with MessageFormatter):
diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs
index aa72996fff..7347d9f702 100644
--- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs
+++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs
@@ -33,7 +33,7 @@ public LinkFlowContainer(Action<SpriteText> defaultCreationParameters = null)
[Resolved]
private GameHost host { get; set; }
- public void AddLinks(string text, List<Link> links)
+ public void AddLinks(string text, List<Link> links, Action<SpriteText> linkCreationParameters = null)
{
if (string.IsNullOrEmpty(text) || links == null)
return;
@@ -61,7 +61,7 @@ public void AddLinks(string text, List<Link> links)
object linkArgument = link.Argument;
string tooltip = displayText == link.Url ? null : link.Url;
- AddLink(displayText, link.Action, linkArgument, tooltip);
+ AddLink(displayText, link.Action, linkArgument, tooltip, linkCreationParameters);
previousLinkEnd = link.Index + link.Length;
}
diff --git a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs
index 8a0003b4ea..8a5035eca7 100644
--- a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs
+++ b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs
@@ -2,11 +2,13 @@
// See the LICENCE file in the repository root for full licence text.
using System.Linq;
+using System.Text.RegularExpressions;
using osu.Framework.Allocation;
-using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
+using osu.Framework.Localisation;
+using osu.Framework.Logging;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Online.API;
@@ -14,6 +16,7 @@
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Chat;
using osu.Game.Online.Leaderboards;
+using osu.Game.Resources.Localisation.Web;
using osu.Game.Rulesets;
namespace osu.Game.Overlays.Profile.Sections.Recent
@@ -28,6 +31,9 @@ public partial class DrawableRecentActivity : CompositeDrawable
[Resolved]
private IRulesetStore rulesets { get; set; } = null!;
+ [Resolved]
+ private LocalisationManager localisation { get; set; } = null!;
+
private readonly APIRecentActivity activity;
private LinkFlowContainer content = null!;
@@ -131,44 +137,36 @@ private Drawable createIcon()
private void createMessage()
{
+ LocalisableString text = string.Empty;
+
switch (activity.Type)
{
case RecentActivityType.Achievement:
- addUserLink();
- addText($" unlocked the \"{activity.Achievement.Name}\" medal!");
+ text = EventsStrings.Achievement(getUserLink(), activity.Achievement.Name);
break;
case RecentActivityType.BeatmapPlaycount:
- addBeatmapLink();
- addText($" has been played {activity.Count} times!");
+ text = EventsStrings.BeatmapPlaycount(getBeatmapLink(), activity.Count.ToString());
break;
case RecentActivityType.BeatmapsetApprove:
- addBeatmapsetLink();
- addText($" has been {activity.Approval.ToString().ToLowerInvariant()}!");
+ text = EventsStrings.BeatmapsetApprove(getBeatmapsetLink(), activity.User.Username, activity.Approval.ToString().ToLowerInvariant());
break;
case RecentActivityType.BeatmapsetDelete:
- addBeatmapsetLink();
- addText(" has been deleted.");
+ text = EventsStrings.BeatmapsetDelete(getBeatmapsetLink());
break;
case RecentActivityType.BeatmapsetRevive:
- addBeatmapsetLink();
- addText(" has been revived from eternal slumber by ");
- addUserLink();
+ text = EventsStrings.BeatmapsetRevive(getBeatmapsetLink(), activity.User.Username);
break;
case RecentActivityType.BeatmapsetUpdate:
- addUserLink();
- addText(" has updated the beatmap ");
- addBeatmapsetLink();
+ text = EventsStrings.BeatmapsetUpdate(activity.User.Username, getBeatmapsetLink());
break;
case RecentActivityType.BeatmapsetUpload:
- addUserLink();
- addText(" has submitted a new beatmap ");
- addBeatmapsetLink();
+ text = EventsStrings.BeatmapsetUpdate(activity.User.Username, getBeatmapsetLink());
break;
case RecentActivityType.Medal:
@@ -176,59 +174,60 @@ private void createMessage()
break;
case RecentActivityType.Rank:
- addUserLink();
- addText($" achieved rank #{activity.Rank} on ");
- addBeatmapLink();
- addText($" ({getRulesetName()})");
+ text = EventsStrings.Rank(getUserLink(), $"#{activity.Rank}", getBeatmapLink(), getRulesetName());
break;
case RecentActivityType.RankLost:
- addUserLink();
- addText(" has lost first place on ");
- addBeatmapLink();
- addText($" ({getRulesetName()})");
+ text = EventsStrings.RankLost(getUserLink(), getBeatmapLink(), getRulesetName());
break;
case RecentActivityType.UserSupportAgain:
- addUserLink();
- addText(" has once again chosen to support osu! - thanks for your generosity!");
+ text = EventsStrings.UserSupportAgain(getUserLink());
break;
case RecentActivityType.UserSupportFirst:
- addUserLink();
- addText(" has become an osu!supporter - thanks for your generosity!");
+ text = EventsStrings.UserSupportFirst(getUserLink());
break;
case RecentActivityType.UserSupportGift:
- addUserLink();
- addText(" has received the gift of osu!supporter!");
+ text = EventsStrings.UserSupportGift(getUserLink());
break;
case RecentActivityType.UsernameChange:
- addText($"{activity.User?.PreviousUsername} has changed their username to ");
- addUserLink();
+ text = EventsStrings.UsernameChange(activity.User.PreviousUsername, getUserLink());
break;
}
+
+ if (!LocalisableString.IsNullOrEmpty(text))
+ {
+ var localisedText = localisation.GetLocalisedBindableString(text);
+
+ localisation.CurrentParameters.BindValueChanged(_ =>
+ {
+ content.Clear();
+
+ // TODO: should probably use markdown container and replace html formatting with the markdown ones, will fix bottom TODO also
+ var formattedSource = MessageFormatter.FormatText(Regex.Replace(localisedText.Value, @"<(.|\n)*?>", string.Empty));
+
+ // TODO: link creation parameters should only affect user link
+ content.AddLinks(formattedSource.Text, formattedSource.Links, t => t.Font = getLinkFont(FontWeight.Bold));
+ }, true);
+ }
}
private string getRulesetName() =>
rulesets.AvailableRulesets.FirstOrDefault(r => r.ShortName == activity.Mode)?.Name ?? activity.Mode;
- private void addUserLink()
- => content.AddLink(activity.User.AsNonNull().Username, LinkAction.OpenUserProfile, getLinkArgument(activity.User.AsNonNull().Url), creationParameters: t => t.Font = getLinkFont(FontWeight.Bold));
-
- private void addBeatmapLink()
- => content.AddLink(activity.Beatmap.AsNonNull().Title, LinkAction.OpenBeatmap, getLinkArgument(activity.Beatmap.AsNonNull().Url), creationParameters: t => t.Font = getLinkFont());
+ private LocalisableString getUserLink()
+ => LocalisableString.Interpolate($"[{activity.User.Username}]({api.WebsiteRootUrl}{activity.User.Url})");
- private void addBeatmapsetLink()
- => content.AddLink(activity.Beatmapset.AsNonNull().Title, LinkAction.OpenBeatmapSet, getLinkArgument(activity.Beatmapset.AsNonNull().Url), creationParameters: t => t.Font = getLinkFont());
+ private LocalisableString getBeatmapLink()
+ => LocalisableString.Interpolate($"[{activity.Beatmap.Title}]({api.WebsiteRootUrl}{activity.Beatmap.Url})");
- private object getLinkArgument(string url) => MessageFormatter.GetLinkDetails($"{api.WebsiteRootUrl}{url}").Argument.AsNonNull();
+ private LocalisableString getBeatmapsetLink()
+ => LocalisableString.Interpolate($"[{activity.Beatmapset.Title}]({api.WebsiteRootUrl}{activity.Beatmapset.Url})");
private FontUsage getLinkFont(FontWeight fontWeight = FontWeight.Regular)
=> OsuFont.GetFont(size: font_size, weight: fontWeight, italics: true);
-
- private void addText(string text)
- => content.AddText(text, t => t.Font = OsuFont.GetFont(size: font_size, weight: FontWeight.SemiBold));
}
}
Not sure if this is any more cursed than what is done in this file right now.
I mean there's a precedent (a little different as the string itself already has markdown). Also this doesn't update after language change cuz no BindValueChanged:
https://github.com/ppy/osu/blob/8ee391530f8799399690b677c898ee0102c2d07f/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs#L116-L121