diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 58c24181d3..b51ecb4f7e 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -31,6 +31,12 @@
"commands": [
"CodeFileSanity"
]
+ },
+ "ppy.localisationanalyser.tools": {
+ "version": "2021.524.0",
+ "commands": [
+ "localisation"
+ ]
}
}
}
\ No newline at end of file
diff --git a/osu.Android.props b/osu.Android.props
index 57550cfb93..b3842a528d 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,6 +52,6 @@
-
+
diff --git a/osu.Game/Graphics/UserInterface/DialogButton.cs b/osu.Game/Graphics/UserInterface/DialogButton.cs
index 9b53ee7b2d..1047aa4255 100644
--- a/osu.Game/Graphics/UserInterface/DialogButton.cs
+++ b/osu.Game/Graphics/UserInterface/DialogButton.cs
@@ -15,6 +15,7 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics.Effects;
using osu.Game.Graphics.Containers;
using osu.Framework.Input.Events;
+using osu.Framework.Localisation;
namespace osu.Game.Graphics.UserInterface
{
@@ -180,9 +181,9 @@ namespace osu.Game.Graphics.UserInterface
}
}
- private string text;
+ private LocalisableString text;
- public string Text
+ public LocalisableString Text
{
get => text;
set
diff --git a/osu.Game/Localisation/ButtonSystem.ja.resx b/osu.Game/Localisation/ButtonSystem.ja.resx
new file mode 100644
index 0000000000..02f3e7ce2f
--- /dev/null
+++ b/osu.Game/Localisation/ButtonSystem.ja.resx
@@ -0,0 +1,38 @@
+
+
+ text/microsoft-resx
+
+
+ 1.3
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ ソロ
+
+
+ プレイリスト
+
+
+ 遊ぶ
+
+
+ マルチ
+
+
+ エディット
+
+
+ ブラウズ
+
+
+ 閉じる
+
+
+ 設定
+
+
diff --git a/osu.Game/Localisation/ButtonSystem.resx b/osu.Game/Localisation/ButtonSystem.resx
new file mode 100644
index 0000000000..d72ffff8be
--- /dev/null
+++ b/osu.Game/Localisation/ButtonSystem.resx
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ solo
+
+
+ multi
+
+
+ playlists
+
+
+ play
+
+
+ edit
+
+
+ browse
+
+
+ settings
+
+
+ back
+
+
+ exit
+
+
\ No newline at end of file
diff --git a/osu.Game/Localisation/ButtonSystemStrings.cs b/osu.Game/Localisation/ButtonSystemStrings.cs
new file mode 100644
index 0000000000..8083f80782
--- /dev/null
+++ b/osu.Game/Localisation/ButtonSystemStrings.cs
@@ -0,0 +1,59 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Localisation;
+
+namespace osu.Game.Localisation
+{
+ public static class ButtonSystemStrings
+ {
+ private const string prefix = @"osu.Game.Localisation.ButtonSystem";
+
+ ///
+ /// "solo"
+ ///
+ public static LocalisableString Solo => new TranslatableString(getKey(@"solo"), @"solo");
+
+ ///
+ /// "multi"
+ ///
+ public static LocalisableString Multi => new TranslatableString(getKey(@"multi"), @"multi");
+
+ ///
+ /// "playlists"
+ ///
+ public static LocalisableString Playlists => new TranslatableString(getKey(@"playlists"), @"playlists");
+
+ ///
+ /// "play"
+ ///
+ public static LocalisableString Play => new TranslatableString(getKey(@"play"), @"play");
+
+ ///
+ /// "edit"
+ ///
+ public static LocalisableString Edit => new TranslatableString(getKey(@"edit"), @"edit");
+
+ ///
+ /// "browse"
+ ///
+ public static LocalisableString Browse => new TranslatableString(getKey(@"browse"), @"browse");
+
+ ///
+ /// "settings"
+ ///
+ public static LocalisableString Settings => new TranslatableString(getKey(@"settings"), @"settings");
+
+ ///
+ /// "back"
+ ///
+ public static LocalisableString Back => new TranslatableString(getKey(@"back"), @"back");
+
+ ///
+ /// "exit"
+ ///
+ public static LocalisableString Exit => new TranslatableString(getKey(@"exit"), @"exit");
+
+ private static string getKey(string key) => $@"{prefix}:{key}";
+ }
+}
\ No newline at end of file
diff --git a/osu.Game/Localisation/Chat.resx b/osu.Game/Localisation/Chat.resx
new file mode 100644
index 0000000000..055e351463
--- /dev/null
+++ b/osu.Game/Localisation/Chat.resx
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ chat
+
+
+ join the real-time discussion
+
+
\ No newline at end of file
diff --git a/osu.Game/Localisation/ChatStrings.cs b/osu.Game/Localisation/ChatStrings.cs
new file mode 100644
index 0000000000..daddb602ad
--- /dev/null
+++ b/osu.Game/Localisation/ChatStrings.cs
@@ -0,0 +1,24 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Localisation;
+
+namespace osu.Game.Localisation
+{
+ public static class ChatStrings
+ {
+ private const string prefix = "osu.Game.Localisation.Chat";
+
+ ///
+ /// "chat"
+ ///
+ public static LocalisableString HeaderTitle => new TranslatableString(getKey("header_title"), "chat");
+
+ ///
+ /// "join the real-time discussion"
+ ///
+ public static LocalisableString HeaderDescription => new TranslatableString(getKey("header_description"), "join the real-time discussion");
+
+ private static string getKey(string key) => $"{prefix}:{key}";
+ }
+}
diff --git a/osu.Game/Localisation/Common.resx b/osu.Game/Localisation/Common.resx
new file mode 100644
index 0000000000..59de16a037
--- /dev/null
+++ b/osu.Game/Localisation/Common.resx
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Cancel
+
+
\ No newline at end of file
diff --git a/osu.Game/Localisation/CommonStrings.cs b/osu.Game/Localisation/CommonStrings.cs
new file mode 100644
index 0000000000..f448158191
--- /dev/null
+++ b/osu.Game/Localisation/CommonStrings.cs
@@ -0,0 +1,19 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Localisation;
+
+namespace osu.Game.Localisation
+{
+ public static class CommonStrings
+ {
+ private const string prefix = "osu.Game.Localisation.Common";
+
+ ///
+ /// "Cancel"
+ ///
+ public static LocalisableString Cancel => new TranslatableString(getKey("cancel"), "Cancel");
+
+ private static string getKey(string key) => $"{prefix}:{key}";
+ }
+}
diff --git a/osu.Game/Localisation/Language.cs b/osu.Game/Localisation/Language.cs
new file mode 100644
index 0000000000..edcf264c7f
--- /dev/null
+++ b/osu.Game/Localisation/Language.cs
@@ -0,0 +1,16 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.ComponentModel;
+
+namespace osu.Game.Localisation
+{
+ public enum Language
+ {
+ [Description("English")]
+ en,
+
+ [Description("日本語")]
+ ja
+ }
+}
diff --git a/osu.Game/Localisation/Notifications.resx b/osu.Game/Localisation/Notifications.resx
new file mode 100644
index 0000000000..08db240ba2
--- /dev/null
+++ b/osu.Game/Localisation/Notifications.resx
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ notifications
+
+
+ waiting for 'ya
+
+
\ No newline at end of file
diff --git a/osu.Game/Localisation/NotificationsStrings.cs b/osu.Game/Localisation/NotificationsStrings.cs
new file mode 100644
index 0000000000..092eec3a6b
--- /dev/null
+++ b/osu.Game/Localisation/NotificationsStrings.cs
@@ -0,0 +1,24 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Localisation;
+
+namespace osu.Game.Localisation
+{
+ public static class NotificationsStrings
+ {
+ private const string prefix = "osu.Game.Localisation.Notifications";
+
+ ///
+ /// "notifications"
+ ///
+ public static LocalisableString HeaderTitle => new TranslatableString(getKey("header_title"), "notifications");
+
+ ///
+ /// "waiting for 'ya"
+ ///
+ public static LocalisableString HeaderDescription => new TranslatableString(getKey("header_description"), "waiting for 'ya");
+
+ private static string getKey(string key) => $"{prefix}:{key}";
+ }
+}
diff --git a/osu.Game/Localisation/NowPlaying.resx b/osu.Game/Localisation/NowPlaying.resx
new file mode 100644
index 0000000000..40fda3e25b
--- /dev/null
+++ b/osu.Game/Localisation/NowPlaying.resx
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ now playing
+
+
+ manage the currently playing track
+
+
\ No newline at end of file
diff --git a/osu.Game/Localisation/NowPlayingStrings.cs b/osu.Game/Localisation/NowPlayingStrings.cs
new file mode 100644
index 0000000000..d742a56895
--- /dev/null
+++ b/osu.Game/Localisation/NowPlayingStrings.cs
@@ -0,0 +1,24 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Localisation;
+
+namespace osu.Game.Localisation
+{
+ public static class NowPlayingStrings
+ {
+ private const string prefix = "osu.Game.Localisation.NowPlaying";
+
+ ///
+ /// "now playing"
+ ///
+ public static LocalisableString HeaderTitle => new TranslatableString(getKey("header_title"), "now playing");
+
+ ///
+ /// "manage the currently playing track"
+ ///
+ public static LocalisableString HeaderDescription => new TranslatableString(getKey("header_description"), "manage the currently playing track");
+
+ private static string getKey(string key) => $"{prefix}:{key}";
+ }
+}
diff --git a/osu.Game/Localisation/ResourceManagerLocalisationStore.cs b/osu.Game/Localisation/ResourceManagerLocalisationStore.cs
new file mode 100644
index 0000000000..7b21e1af42
--- /dev/null
+++ b/osu.Game/Localisation/ResourceManagerLocalisationStore.cs
@@ -0,0 +1,69 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Resources;
+using System.Threading.Tasks;
+using osu.Framework.Localisation;
+
+namespace osu.Game.Localisation
+{
+ public class ResourceManagerLocalisationStore : ILocalisationStore
+ {
+ private readonly Dictionary resourceManagers = new Dictionary();
+
+ public ResourceManagerLocalisationStore(string cultureCode)
+ {
+ EffectiveCulture = new CultureInfo(cultureCode);
+ }
+
+ public void Dispose()
+ {
+ }
+
+ public string Get(string lookup)
+ {
+ var split = lookup.Split(':');
+
+ string ns = split[0];
+ string key = split[1];
+
+ lock (resourceManagers)
+ {
+ if (!resourceManagers.TryGetValue(ns, out var manager))
+ resourceManagers[ns] = manager = new ResourceManager(ns, GetType().Assembly);
+
+ try
+ {
+ return manager.GetString(key, EffectiveCulture);
+ }
+ catch (MissingManifestResourceException)
+ {
+ // in the case the manifest is missing, it is likely that the user is adding code-first implementations of new localisation namespaces.
+ // it's fine to ignore this as localisation will fallback to default values.
+ return null;
+ }
+ }
+ }
+
+ public Task GetAsync(string lookup)
+ {
+ return Task.FromResult(Get(lookup));
+ }
+
+ public Stream GetStream(string name)
+ {
+ throw new NotImplementedException();
+ }
+
+ public IEnumerable GetAvailableResources()
+ {
+ throw new NotImplementedException();
+ }
+
+ public CultureInfo EffectiveCulture { get; }
+ }
+}
diff --git a/osu.Game/Localisation/Settings.resx b/osu.Game/Localisation/Settings.resx
new file mode 100644
index 0000000000..85c224cedf
--- /dev/null
+++ b/osu.Game/Localisation/Settings.resx
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ settings
+
+
+ change the way osu! behaves
+
+
\ No newline at end of file
diff --git a/osu.Game/Localisation/SettingsStrings.cs b/osu.Game/Localisation/SettingsStrings.cs
new file mode 100644
index 0000000000..cfbd392691
--- /dev/null
+++ b/osu.Game/Localisation/SettingsStrings.cs
@@ -0,0 +1,24 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Localisation;
+
+namespace osu.Game.Localisation
+{
+ public static class SettingsStrings
+ {
+ private const string prefix = "osu.Game.Localisation.Settings";
+
+ ///
+ /// "settings"
+ ///
+ public static LocalisableString HeaderTitle => new TranslatableString(getKey("header_title"), "settings");
+
+ ///
+ /// "change the way osu! behaves"
+ ///
+ public static LocalisableString HeaderDescription => new TranslatableString(getKey("header_description"), "change the way osu! behaves");
+
+ private static string getKey(string key) => $"{prefix}:{key}";
+ }
+}
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index 06e0b6e9bf..b7946f1c2f 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -51,6 +51,7 @@ using osu.Game.Utils;
using LogLevel = osu.Framework.Logging.LogLevel;
using osu.Game.Database;
using osu.Game.IO;
+using osu.Game.Localisation;
using osu.Game.Skinning.Editor;
namespace osu.Game
@@ -562,6 +563,12 @@ namespace osu.Game
{
base.LoadComplete();
+ foreach (var language in Enum.GetValues(typeof(Language)).OfType())
+ {
+ var cultureCode = language.ToString();
+ Localisation.AddLanguage(cultureCode, new ResourceManagerLocalisationStore(cultureCode));
+ }
+
// The next time this is updated is in UpdateAfterChildren, which occurs too late and results
// in the cursor being shown for a few frames during the intro.
// This prevents the cursor from showing until we have a screen with CursorVisible = true
diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs
index 28f2287514..285041800a 100644
--- a/osu.Game/Overlays/ChatOverlay.cs
+++ b/osu.Game/Overlays/ChatOverlay.cs
@@ -24,6 +24,8 @@ using osu.Game.Overlays.Chat.Tabs;
using osuTK.Input;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
+using osu.Framework.Localisation;
+using osu.Game.Localisation;
using osu.Game.Online;
namespace osu.Game.Overlays
@@ -31,8 +33,8 @@ namespace osu.Game.Overlays
public class ChatOverlay : OsuFocusedOverlayContainer, INamedOverlayComponent
{
public string IconTexture => "Icons/Hexacons/messaging";
- public string Title => "chat";
- public string Description => "join the real-time discussion";
+ public LocalisableString Title => ChatStrings.HeaderTitle;
+ public LocalisableString Description => ChatStrings.HeaderDescription;
private const float textbox_height = 60;
private const float channel_selection_min_height = 0.3f;
diff --git a/osu.Game/Overlays/Dialog/ConfirmDialog.cs b/osu.Game/Overlays/Dialog/ConfirmDialog.cs
index a87c06ffdf..d1c0d746d1 100644
--- a/osu.Game/Overlays/Dialog/ConfirmDialog.cs
+++ b/osu.Game/Overlays/Dialog/ConfirmDialog.cs
@@ -33,7 +33,7 @@ namespace osu.Game.Overlays.Dialog
},
new PopupDialogCancelButton
{
- Text = @"Cancel",
+ Text = Localisation.CommonStrings.Cancel,
Action = onCancel
},
};
diff --git a/osu.Game/Overlays/FullscreenOverlay.cs b/osu.Game/Overlays/FullscreenOverlay.cs
index 735f0bcbd4..58c41c4a4b 100644
--- a/osu.Game/Overlays/FullscreenOverlay.cs
+++ b/osu.Game/Overlays/FullscreenOverlay.cs
@@ -8,6 +8,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
+using osu.Framework.Localisation;
using osu.Game.Graphics.Containers;
using osu.Game.Online.API;
using osuTK.Graphics;
@@ -18,8 +19,8 @@ namespace osu.Game.Overlays
where T : OverlayHeader
{
public virtual string IconTexture => Header.Title.IconTexture ?? string.Empty;
- public virtual string Title => Header.Title.Title ?? string.Empty;
- public virtual string Description => Header.Title.Description ?? string.Empty;
+ public virtual LocalisableString Title => Header.Title.Title;
+ public virtual LocalisableString Description => Header.Title.Description;
public T Header { get; }
diff --git a/osu.Game/Overlays/INamedOverlayComponent.cs b/osu.Game/Overlays/INamedOverlayComponent.cs
index 38fb8679a0..ca0aea041e 100644
--- a/osu.Game/Overlays/INamedOverlayComponent.cs
+++ b/osu.Game/Overlays/INamedOverlayComponent.cs
@@ -1,14 +1,16 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using osu.Framework.Localisation;
+
namespace osu.Game.Overlays
{
public interface INamedOverlayComponent
{
string IconTexture { get; }
- string Title { get; }
+ LocalisableString Title { get; }
- string Description { get; }
+ LocalisableString Description { get; }
}
}
diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs
index d51d964fc4..b26e17b34c 100644
--- a/osu.Game/Overlays/NotificationOverlay.cs
+++ b/osu.Game/Overlays/NotificationOverlay.cs
@@ -11,16 +11,18 @@ using osu.Game.Graphics.Containers;
using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
+using osu.Framework.Localisation;
using osu.Framework.Threading;
using osu.Game.Graphics;
+using osu.Game.Localisation;
namespace osu.Game.Overlays
{
public class NotificationOverlay : OsuFocusedOverlayContainer, INamedOverlayComponent
{
public string IconTexture => "Icons/Hexacons/notification";
- public string Title => "notifications";
- public string Description => "waiting for 'ya";
+ public LocalisableString Title => NotificationsStrings.HeaderTitle;
+ public LocalisableString Description => NotificationsStrings.HeaderDescription;
private const float width = 320;
diff --git a/osu.Game/Overlays/NowPlayingOverlay.cs b/osu.Game/Overlays/NowPlayingOverlay.cs
index 81bf71cdec..f88be91c01 100644
--- a/osu.Game/Overlays/NowPlayingOverlay.cs
+++ b/osu.Game/Overlays/NowPlayingOverlay.cs
@@ -19,6 +19,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
+using osu.Game.Localisation;
using osu.Game.Overlays.Music;
using osuTK;
using osuTK.Graphics;
@@ -28,8 +29,8 @@ namespace osu.Game.Overlays
public class NowPlayingOverlay : OsuFocusedOverlayContainer, INamedOverlayComponent
{
public string IconTexture => "Icons/Hexacons/music";
- public string Title => "now playing";
- public string Description => "manage the currently playing track";
+ public LocalisableString Title => NowPlayingStrings.HeaderTitle;
+ public LocalisableString Description => NowPlayingStrings.HeaderDescription;
private const float player_height = 130;
private const float transition_length = 800;
diff --git a/osu.Game/Overlays/OverlayTitle.cs b/osu.Game/Overlays/OverlayTitle.cs
index c3ea35adfc..d92979e8d4 100644
--- a/osu.Game/Overlays/OverlayTitle.cs
+++ b/osu.Game/Overlays/OverlayTitle.cs
@@ -6,6 +6,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
+using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osuTK;
@@ -19,15 +20,15 @@ namespace osu.Game.Overlays
private readonly OsuSpriteText titleText;
private readonly Container icon;
- private string title;
+ private LocalisableString title;
- public string Title
+ public LocalisableString Title
{
get => title;
protected set => titleText.Text = title = value;
}
- public string Description { get; protected set; }
+ public LocalisableString Description { get; protected set; }
private string iconTexture;
diff --git a/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs
index 44e42ecbfe..c2767f61b4 100644
--- a/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs
+++ b/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs
@@ -1,27 +1,45 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
using osu.Framework.Allocation;
+using osu.Framework.Bindables;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
+using osu.Game.Localisation;
namespace osu.Game.Overlays.Settings.Sections.General
{
public class LanguageSettings : SettingsSubsection
{
+ private SettingsDropdown languageSelection;
+ private Bindable frameworkLocale;
+
protected override string Header => "Language";
[BackgroundDependencyLoader]
private void load(FrameworkConfigManager frameworkConfig)
{
+ frameworkLocale = frameworkConfig.GetBindable(FrameworkSetting.Locale);
+
Children = new Drawable[]
{
+ languageSelection = new SettingsEnumDropdown
+ {
+ LabelText = "Language",
+ },
new SettingsCheckbox
{
LabelText = "Prefer metadata in original language",
Current = frameworkConfig.GetBindable(FrameworkSetting.ShowUnicode)
},
};
+
+ if (!Enum.TryParse(frameworkLocale.Value, out var locale))
+ locale = Language.en;
+ languageSelection.Current.Value = locale;
+
+ languageSelection.Current.BindValueChanged(val => frameworkLocale.Value = val.NewValue.ToString());
}
}
}
diff --git a/osu.Game/Overlays/Settings/SettingsHeader.cs b/osu.Game/Overlays/Settings/SettingsHeader.cs
index d8ec00bd99..a7f1cef74c 100644
--- a/osu.Game/Overlays/Settings/SettingsHeader.cs
+++ b/osu.Game/Overlays/Settings/SettingsHeader.cs
@@ -4,6 +4,7 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
@@ -11,10 +12,10 @@ namespace osu.Game.Overlays.Settings
{
public class SettingsHeader : Container
{
- private readonly string heading;
- private readonly string subheading;
+ private readonly LocalisableString heading;
+ private readonly LocalisableString subheading;
- public SettingsHeader(string heading, string subheading)
+ public SettingsHeader(LocalisableString heading, LocalisableString subheading)
{
this.heading = heading;
this.subheading = subheading;
diff --git a/osu.Game/Overlays/SettingsOverlay.cs b/osu.Game/Overlays/SettingsOverlay.cs
index 7bd84dbc6c..8c21880cc6 100644
--- a/osu.Game/Overlays/SettingsOverlay.cs
+++ b/osu.Game/Overlays/SettingsOverlay.cs
@@ -10,14 +10,16 @@ using osuTK.Graphics;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Bindables;
+using osu.Framework.Localisation;
+using osu.Game.Localisation;
namespace osu.Game.Overlays
{
public class SettingsOverlay : SettingsPanel, INamedOverlayComponent
{
public string IconTexture => "Icons/Hexacons/settings";
- public string Title => "settings";
- public string Description => "change the way osu! behaves";
+ public LocalisableString Title => SettingsStrings.HeaderTitle;
+ public LocalisableString Description => SettingsStrings.HeaderDescription;
protected override IEnumerable CreateSections() => new SettingsSection[]
{
diff --git a/osu.Game/Screens/Menu/Button.cs b/osu.Game/Screens/Menu/Button.cs
index d956394ebb..26f26d1304 100644
--- a/osu.Game/Screens/Menu/Button.cs
+++ b/osu.Game/Screens/Menu/Button.cs
@@ -19,6 +19,7 @@ using osu.Game.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
+using osu.Framework.Localisation;
using osu.Game.Beatmaps.ControlPoints;
namespace osu.Game.Screens.Menu
@@ -50,7 +51,7 @@ namespace osu.Game.Screens.Menu
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => box.ReceivePositionalInputAt(screenSpacePos);
- public Button(string text, string sampleName, IconUsage symbol, Color4 colour, Action clickAction = null, float extraWidth = 0, Key triggerKey = Key.Unknown)
+ public Button(LocalisableString text, string sampleName, IconUsage symbol, Color4 colour, Action clickAction = null, float extraWidth = 0, Key triggerKey = Key.Unknown)
{
this.sampleName = sampleName;
this.clickAction = clickAction;
diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs
index 81b1cb0bf1..a836f7bf09 100644
--- a/osu.Game/Screens/Menu/ButtonSystem.cs
+++ b/osu.Game/Screens/Menu/ButtonSystem.cs
@@ -15,6 +15,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
+using osu.Framework.Localisation;
using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Framework.Threading;
@@ -22,6 +23,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Input;
using osu.Game.Input.Bindings;
+using osu.Game.Localisation;
using osu.Game.Online.API;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
@@ -97,8 +99,8 @@ namespace osu.Game.Screens.Menu
buttonArea.AddRange(new Drawable[]
{
- new Button(@"settings", string.Empty, FontAwesome.Solid.Cog, new Color4(85, 85, 85, 255), () => OnSettings?.Invoke(), -WEDGE_WIDTH, Key.O),
- backButton = new Button(@"back", @"button-back-select", OsuIcon.LeftCircle, new Color4(51, 58, 94, 255), () => State = ButtonSystemState.TopLevel, -WEDGE_WIDTH)
+ new Button(ButtonSystemStrings.Settings, string.Empty, FontAwesome.Solid.Cog, new Color4(85, 85, 85, 255), () => OnSettings?.Invoke(), -WEDGE_WIDTH, Key.O),
+ backButton = new Button(ButtonSystemStrings.Back, @"button-back-select", OsuIcon.LeftCircle, new Color4(51, 58, 94, 255), () => State = ButtonSystemState.TopLevel, -WEDGE_WIDTH)
{
VisibleState = ButtonSystemState.Play,
},
@@ -121,19 +123,19 @@ namespace osu.Game.Screens.Menu
private LoginOverlay loginOverlay { get; set; }
[BackgroundDependencyLoader(true)]
- private void load(AudioManager audio, IdleTracker idleTracker, GameHost host)
+ private void load(AudioManager audio, IdleTracker idleTracker, GameHost host, LocalisationManager strings)
{
- buttonsPlay.Add(new Button(@"solo", @"button-solo-select", FontAwesome.Solid.User, new Color4(102, 68, 204, 255), () => OnSolo?.Invoke(), WEDGE_WIDTH, Key.P));
- buttonsPlay.Add(new Button(@"multi", @"button-generic-select", FontAwesome.Solid.Users, new Color4(94, 63, 186, 255), onMultiplayer, 0, Key.M));
- buttonsPlay.Add(new Button(@"playlists", @"button-generic-select", OsuIcon.Charts, new Color4(94, 63, 186, 255), onPlaylists, 0, Key.L));
+ buttonsPlay.Add(new Button(ButtonSystemStrings.Solo, @"button-solo-select", FontAwesome.Solid.User, new Color4(102, 68, 204, 255), () => OnSolo?.Invoke(), WEDGE_WIDTH, Key.P));
+ buttonsPlay.Add(new Button(ButtonSystemStrings.Multi, @"button-generic-select", FontAwesome.Solid.Users, new Color4(94, 63, 186, 255), onMultiplayer, 0, Key.M));
+ buttonsPlay.Add(new Button(ButtonSystemStrings.Playlists, @"button-generic-select", OsuIcon.Charts, new Color4(94, 63, 186, 255), onPlaylists, 0, Key.L));
buttonsPlay.ForEach(b => b.VisibleState = ButtonSystemState.Play);
- buttonsTopLevel.Add(new Button(@"play", @"button-play-select", OsuIcon.Logo, new Color4(102, 68, 204, 255), () => State = ButtonSystemState.Play, WEDGE_WIDTH, Key.P));
- buttonsTopLevel.Add(new Button(@"edit", @"button-edit-select", OsuIcon.EditCircle, new Color4(238, 170, 0, 255), () => OnEdit?.Invoke(), 0, Key.E));
- buttonsTopLevel.Add(new Button(@"browse", @"button-direct-select", OsuIcon.ChevronDownCircle, new Color4(165, 204, 0, 255), () => OnBeatmapListing?.Invoke(), 0, Key.D));
+ buttonsTopLevel.Add(new Button(ButtonSystemStrings.Play, @"button-play-select", OsuIcon.Logo, new Color4(102, 68, 204, 255), () => State = ButtonSystemState.Play, WEDGE_WIDTH, Key.P));
+ buttonsTopLevel.Add(new Button(ButtonSystemStrings.Edit, @"button-edit-select", OsuIcon.EditCircle, new Color4(238, 170, 0, 255), () => OnEdit?.Invoke(), 0, Key.E));
+ buttonsTopLevel.Add(new Button(ButtonSystemStrings.Browse, @"button-direct-select", OsuIcon.ChevronDownCircle, new Color4(165, 204, 0, 255), () => OnBeatmapListing?.Invoke(), 0, Key.D));
if (host.CanExit)
- buttonsTopLevel.Add(new Button(@"exit", string.Empty, OsuIcon.CrossCircle, new Color4(238, 51, 153, 255), () => OnExit?.Invoke(), 0, Key.Q));
+ buttonsTopLevel.Add(new Button(ButtonSystemStrings.Exit, string.Empty, OsuIcon.CrossCircle, new Color4(238, 51, 153, 255), () => OnExit?.Invoke(), 0, Key.Q));
buttonArea.AddRange(buttonsPlay);
buttonArea.AddRange(buttonsTopLevel);
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 1e3b77cd70..fa2945db6a 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -29,7 +29,11 @@
-
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
diff --git a/osu.iOS.props b/osu.iOS.props
index a2a9ac35fc..e35b1b5c42 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -70,7 +70,7 @@
-
+
@@ -93,7 +93,7 @@
-
+
diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings
index 4ac796ccd0..62751cebb1 100644
--- a/osu.sln.DotSettings
+++ b/osu.sln.DotSettings
@@ -120,6 +120,7 @@
WARNING
WARNING
HINT
+ HINT
WARNING
HINT
HINT