A game framework written with osu! in mind.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'master' into android-show-keyboard-on-click-of-focused-textbox

authored by

Dan Balasescu and committed by
GitHub
26e5a96e 4f895c9f

+463 -16
+2 -2
osu.Framework.Android/Input/AndroidTextInput.cs
··· 25 25 inputMethodManager = view.Context.GetSystemService(Context.InputMethodService) as InputMethodManager; 26 26 } 27 27 28 - public void Deactivate(object sender) 28 + public void Deactivate() 29 29 { 30 30 activity.RunOnUiThread(() => 31 31 { ··· 63 63 public event Action<string> OnNewImeComposition; 64 64 public event Action<string> OnNewImeResult; 65 65 66 - public void Activate(object sender) 66 + public void Activate() 67 67 { 68 68 activity.RunOnUiThread(() => 69 69 {
+1 -1
osu.Framework.Templates/templates/template-flappy/README.md
··· 12 12 13 13 * Flappy Bird artwork by [Matthias Gall](https://github.com/digitalbreed/how-to-build-a-game-like-flappy-bird-with-xcode-and-sprite-kit). 14 14 * Number sprites by ahmadmanga, available on [opengameart.org](http://opengameart.org). 15 - * Arcade font by [Jakob Fischer](www.pizzadude.dk). 15 + * Arcade font by [Jakob Fischer](https://www.pizzadude.dk). 16 16 * Remaining artwork + sounds are from [osu! resources](https://github.com/ppy/osu-resources). 17 17
+126 -1
osu.Framework.Tests/Localisation/LocalisationTest.cs
··· 9 9 using System.Threading.Tasks; 10 10 using NUnit.Framework; 11 11 using osu.Framework.Configuration; 12 + using osu.Framework.Extensions.LocalisationExtensions; 12 13 using osu.Framework.Localisation; 13 14 14 15 namespace osu.Framework.Tests.Localisation ··· 234 235 var dateTime = new DateTime(1); 235 236 const string format = "MMM yyyy"; 236 237 237 - var text = manager.GetLocalisedString(new LocalisableFormattableString(dateTime, format)); 238 + var text = manager.GetLocalisedString(dateTime.ToLocalisableString(format)); 238 239 239 240 Assert.AreEqual("Jan 0001", text.Value); 240 241 ··· 242 243 Assert.AreEqual("janv. 0001", text.Value); 243 244 } 244 245 246 + [Test] 247 + public void TestCaseTransformableString() 248 + { 249 + const string localisable_string_en_title_case = "Localised EN"; 250 + 251 + config.SetValue(FrameworkSetting.Locale, "en"); 252 + 253 + var uppercasedText = manager.GetLocalisedString(new TranslatableString(FakeStorage.LOCALISABLE_STRING_EN, FakeStorage.LOCALISABLE_STRING_EN).ToUpper()); 254 + var titleText = manager.GetLocalisedString(new TranslatableString(FakeStorage.LOCALISABLE_STRING_EN, FakeStorage.LOCALISABLE_STRING_EN).ToTitle()); 255 + 256 + Assert.AreEqual(uppercasedText.Value, "LOCALISED EN"); 257 + Assert.AreEqual(titleText.Value, localisable_string_en_title_case); 258 + } 259 + 260 + [Test] 261 + public void TestCaseTransformableStringNonEnglishCultureCasing() 262 + { 263 + manager.AddLanguage("tr", new FakeStorage("tr")); 264 + 265 + var uppercasedText = manager.GetLocalisedString(new TranslatableString(FakeStorage.LOCALISABLE_STRING_EN, FakeStorage.LOCALISABLE_STRING_EN).ToUpper()); 266 + var lowercasedText = manager.GetLocalisedString(new TranslatableString(FakeStorage.LOCALISABLE_STRING_EN, FakeStorage.LOCALISABLE_STRING_EN).ToLower()); 267 + 268 + config.SetValue(FrameworkSetting.Locale, "en"); 269 + 270 + Assert.AreEqual(uppercasedText.Value, "LOCALISED EN"); 271 + Assert.AreEqual(lowercasedText.Value, "localised en"); 272 + 273 + config.SetValue(FrameworkSetting.Locale, "tr"); 274 + 275 + Assert.AreEqual(uppercasedText.Value, "LOCALİSED TR (İ/I)"); 276 + Assert.AreEqual(lowercasedText.Value, "localised tr (i/ı)"); 277 + } 278 + 279 + [Test] 280 + public void TestTranslatableEvaluatingLocalisableFormattableString() 281 + { 282 + const string key = FakeStorage.LOCALISABLE_NUMBER_FORMAT_STRING_EN; 283 + 284 + manager.AddLanguage("fr", new FakeStorage("fr")); 285 + 286 + var text = manager.GetLocalisedString(new TranslatableString(key, key, new LocalisableFormattableString(0.1234, "0.00%"))); 287 + 288 + Assert.AreEqual("number 12.34% EN", text.Value); 289 + 290 + config.SetValue(FrameworkSetting.Locale, "fr"); 291 + 292 + Assert.AreEqual("number 12,34% FR", text.Value); 293 + } 294 + 295 + [Test] 296 + public void TestTranslatableEvaluatingRomanisableString() 297 + { 298 + const string key = FakeStorage.LOCALISABLE_FORMAT_STRING_EN; 299 + 300 + var text = manager.GetLocalisedString(new TranslatableString(key, key, new RomanisableString("unicode", "romanised"))); 301 + 302 + Assert.AreEqual("unicode localised EN", text.Value); 303 + 304 + config.SetValue(FrameworkSetting.ShowUnicode, false); 305 + 306 + Assert.AreEqual("romanised localised EN", text.Value); 307 + } 308 + 309 + [Test] 310 + public void TestTranslatableEvaluatingTranslatableString() 311 + { 312 + const string key = FakeStorage.LOCALISABLE_FORMAT_STRING_EN; 313 + const string nested_key = FakeStorage.LOCALISABLE_STRING_EN; 314 + 315 + manager.AddLanguage("ja", new FakeStorage("ja")); 316 + 317 + var text = manager.GetLocalisedString(new TranslatableString(key, key, new TranslatableString(nested_key, nested_key))); 318 + 319 + Assert.AreEqual("localised EN localised EN", text.Value); 320 + 321 + config.SetValue(FrameworkSetting.Locale, "ja"); 322 + 323 + Assert.AreEqual("localised JA localised JA", text.Value); 324 + } 325 + 326 + [Test] 327 + public void TestTranslatableEvaluatingComplexString() 328 + { 329 + const string key = FakeStorage.LOCALISABLE_COMPLEX_FORMAT_STRING_EN; 330 + const string nested_key = FakeStorage.LOCALISABLE_NUMBER_FORMAT_STRING_EN; 331 + 332 + manager.AddLanguage("fr", new FakeStorage("fr")); 333 + 334 + var text = manager.GetLocalisedString(new TranslatableString(key, key, 335 + new LocalisableFormattableString(12.34, "0.00"), 336 + new TranslatableString(nested_key, nested_key, new LocalisableFormattableString(0.9876, "0.00%")), 337 + new TranslatableString(nested_key, nested_key, new RomanisableString("unicode", "romanised")))); 338 + 339 + Assert.AreEqual("number 12.34 with number 98.76% EN and number unicode EN EN", text.Value); 340 + 341 + config.SetValue(FrameworkSetting.Locale, "fr"); 342 + 343 + Assert.AreEqual("number 12,34 with number 98,76% FR and number unicode FR FR", text.Value); 344 + 345 + config.SetValue(FrameworkSetting.ShowUnicode, false); 346 + 347 + Assert.AreEqual("number 12,34 with number 98,76% FR and number romanised FR FR", text.Value); 348 + 349 + config.SetValue(FrameworkSetting.Locale, "en"); 350 + 351 + Assert.AreEqual("number 12.34 with number 98.76% EN and number romanised EN EN", text.Value); 352 + } 353 + 245 354 private class FakeFrameworkConfigManager : FrameworkConfigManager 246 355 { 247 356 protected override string Filename => null; ··· 263 372 public const string LOCALISABLE_STRING_EN = "localised EN"; 264 373 public const string LOCALISABLE_STRING_JA = "localised JA"; 265 374 public const string LOCALISABLE_STRING_JA_JP = "localised JA-JP"; 375 + public const string LOCALISABLE_STRING_TR = "localised TR (i/I)"; 266 376 public const string LOCALISABLE_FORMAT_STRING_EN = "{0} localised EN"; 267 377 public const string LOCALISABLE_FORMAT_STRING_JA = "{0} localised JA"; 268 378 public const string LOCALISABLE_NUMBER_FORMAT_STRING_EN = "number {0} EN"; 269 379 public const string LOCALISABLE_NUMBER_FORMAT_STRING_FR = "number {0} FR"; 380 + public const string LOCALISABLE_COMPLEX_FORMAT_STRING_EN = "number {0} with {1} and {2} EN"; 381 + public const string LOCALISABLE_COMPLEX_FORMAT_STRING_FR = "number {0} with {1} and {2} FR"; 270 382 271 383 public CultureInfo EffectiveCulture { get; } 272 384 ··· 295 407 296 408 case "ja-JP": 297 409 return LOCALISABLE_STRING_JA_JP; 410 + 411 + case "tr": 412 + return LOCALISABLE_STRING_TR; 298 413 } 299 414 300 415 case LOCALISABLE_FORMAT_STRING_EN: ··· 315 430 316 431 case "fr": 317 432 return LOCALISABLE_NUMBER_FORMAT_STRING_FR; 433 + } 434 + 435 + case LOCALISABLE_COMPLEX_FORMAT_STRING_EN: 436 + switch (locale) 437 + { 438 + default: 439 + return LOCALISABLE_COMPLEX_FORMAT_STRING_EN; 440 + 441 + case "fr": 442 + return LOCALISABLE_COMPLEX_FORMAT_STRING_FR; 318 443 } 319 444 320 445 default:
+28
osu.Framework.Tests/Visual/UserInterface/TestSceneColourPicker.cs
··· 1 1 // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2 2 // See the LICENCE file in the repository root for full licence text. 3 3 4 + using System.Linq; 4 5 using NUnit.Framework; 5 6 using osu.Framework.Graphics; 6 7 using osu.Framework.Graphics.UserInterface; 8 + using osu.Framework.Testing; 7 9 8 10 namespace osu.Framework.Tests.Visual.UserInterface 9 11 { ··· 29 31 Current = { Value = Colour4.Goldenrod } 30 32 }); 31 33 AddAssert("colour is correct", () => colourPicker.Current.Value == Colour4.Goldenrod); 34 + } 35 + 36 + [Test] 37 + public void TestExternalHSVChange() 38 + { 39 + const float hue = 0.34f; 40 + const float saturation = 0.46f; 41 + const float value = 0.84f; 42 + 43 + ColourPicker colourPicker = null; 44 + 45 + AddStep("create picker", () => Child = colourPicker = new BasicColourPicker 46 + { 47 + Current = { Value = Colour4.Goldenrod } 48 + }); 49 + AddStep("hide picker", () => colourPicker.Hide()); 50 + AddStep("set HSV manually", () => 51 + { 52 + var saturationValueControl = this.ChildrenOfType<HSVColourPicker.SaturationValueSelector>().Single(); 53 + 54 + saturationValueControl.Hue.Value = hue; 55 + saturationValueControl.Saturation.Value = saturation; 56 + saturationValueControl.Value.Value = value; 57 + }); 58 + 59 + AddUntilStep("colour is correct", () => colourPicker.Current.Value == Colour4.FromHSV(hue, saturation, value)); 32 60 } 33 61 } 34 62 }
+18
osu.Framework.Tests/Visual/UserInterface/TestSceneHSVColourPicker.cs
··· 109 109 } 110 110 111 111 [Test] 112 + public void TestExternalChangeWhileNotPresent() 113 + { 114 + const float hue = 0.34f; 115 + const float saturation = 0.46f; 116 + const float value = 0.84f; 117 + 118 + AddStep("hide picker", () => colourPicker.Hide()); 119 + AddStep("set HSV manually", () => 120 + { 121 + colourPicker.SaturationValueControl.Hue.Value = hue; 122 + colourPicker.SaturationValueControl.Saturation.Value = saturation; 123 + colourPicker.SaturationValueControl.Value.Value = value; 124 + }); 125 + 126 + AddUntilStep("colour is correct", () => colourPicker.Current.Value == Colour4.FromHSV(hue, saturation, value)); 127 + } 128 + 129 + [Test] 112 130 public void TestHueUnchangedIfSaturationAlmostZero() 113 131 { 114 132 AddStep("change colour", () => colourPicker.Current.Value = Colour4.FromHSV(0.5f, 0.5f, 0.5f));
+64
osu.Framework.Tests/Visual/UserInterface/TestSceneTextBox.cs
··· 456 456 AddAssert("text replaced", () => textBox.FlowingText == "another" && textBox.FlowingText == textBox.Text); 457 457 } 458 458 459 + [Test] 460 + public void TestReadOnly() 461 + { 462 + BasicTextBox firstTextBox = null; 463 + BasicTextBox secondTextBox = null; 464 + 465 + AddStep("add textboxes", () => textBoxes.AddRange(new[] 466 + { 467 + firstTextBox = new BasicTextBox 468 + { 469 + Text = "Readonly textbox", 470 + Size = new Vector2(500, 30), 471 + ReadOnly = true, 472 + TabbableContentContainer = textBoxes 473 + }, 474 + secondTextBox = new BasicTextBox 475 + { 476 + Text = "Standard textbox", 477 + Size = new Vector2(500, 30), 478 + TabbableContentContainer = textBoxes 479 + } 480 + })); 481 + 482 + AddStep("click first (readonly) textbox", () => 483 + { 484 + InputManager.MoveMouseTo(firstTextBox); 485 + InputManager.Click(MouseButton.Left); 486 + }); 487 + AddAssert("first textbox has no focus", () => !firstTextBox.HasFocus); 488 + 489 + AddStep("click second (editable) textbox", () => 490 + { 491 + InputManager.MoveMouseTo(secondTextBox); 492 + InputManager.Click(MouseButton.Left); 493 + }); 494 + AddStep("try to tab backwards", () => 495 + { 496 + InputManager.PressKey(Key.ShiftLeft); 497 + InputManager.Key(Key.Tab); 498 + InputManager.ReleaseKey(Key.ShiftLeft); 499 + }); 500 + AddAssert("first (readonly) has no focus", () => !firstTextBox.HasFocus); 501 + 502 + AddStep("drag on first (readonly) textbox", () => 503 + { 504 + InputManager.MoveMouseTo(firstTextBox.ScreenSpaceDrawQuad.Centre); 505 + InputManager.PressButton(MouseButton.Left); 506 + InputManager.MoveMouseTo(firstTextBox.ScreenSpaceDrawQuad.TopLeft); 507 + InputManager.ReleaseButton(MouseButton.Left); 508 + }); 509 + AddAssert("first textbox has no focus", () => !firstTextBox.HasFocus); 510 + 511 + AddStep("make first textbox non-readonly", () => firstTextBox.ReadOnly = false); 512 + AddStep("click first textbox", () => 513 + { 514 + InputManager.MoveMouseTo(firstTextBox); 515 + InputManager.Click(MouseButton.Left); 516 + }); 517 + AddStep("make first textbox readonly again", () => firstTextBox.ReadOnly = true); 518 + AddAssert("first textbox yielded focus", () => !firstTextBox.HasFocus); 519 + AddStep("delete last character", () => firstTextBox.OnPressed(new PlatformAction(PlatformActionType.CharPrevious, PlatformActionMethod.Delete))); 520 + AddAssert("no text removed", () => firstTextBox.Text == "Readonly textbox"); 521 + } 522 + 459 523 public class InsertableTextBox : BasicTextBox 460 524 { 461 525 /// <summary>
+2 -2
osu.Framework.iOS/Input/IOSTextInput.cs
··· 38 38 pending += text; 39 39 } 40 40 41 - public void Deactivate(object sender) 41 + public void Deactivate() 42 42 { 43 43 view.KeyboardTextField.HandleShouldChangeCharacters -= handleShouldChangeCharacters; 44 44 view.KeyboardTextField.UpdateFirstResponder(false); 45 45 } 46 46 47 - public void Activate(object sender) 47 + public void Activate() 48 48 { 49 49 view.KeyboardTextField.HandleShouldChangeCharacters += handleShouldChangeCharacters; 50 50 view.KeyboardTextField.UpdateFirstResponder(true);
+52
osu.Framework/Extensions/LocalisationExtensions/LocalisableStringExtensions.cs
··· 1 + // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2 + // See the LICENCE file in the repository root for full licence text. 3 + 4 + using osu.Framework.Localisation; 5 + 6 + namespace osu.Framework.Extensions.LocalisationExtensions 7 + { 8 + public static class LocalisableStringExtensions 9 + { 10 + /// <summary> 11 + /// Returns a <see cref="CaseTransformableString"/> with the specified underlying localisable string uppercased. 12 + /// </summary> 13 + /// <param name="str">The localisable string.</param> 14 + /// <returns>A case transformable string with its localisable string uppercased.</returns> 15 + public static CaseTransformableString ToUpper(this LocalisableString str) => new CaseTransformableString(str, Casing.UpperCase); 16 + 17 + /// <summary> 18 + /// Returns a <see cref="CaseTransformableString"/> with the specified underlying string data uppercased. 19 + /// </summary> 20 + /// <param name="data">The string data.</param> 21 + /// <returns>A case transformable string with its string data uppercased.</returns> 22 + public static CaseTransformableString ToUpper(this ILocalisableStringData data) => new LocalisableString(data).ToUpper(); 23 + 24 + /// <summary> 25 + /// Returns a <see cref="LocalisableString"/> with the specified underlying localisable string transformed to title case. 26 + /// </summary> 27 + /// <param name="str">The localisable string.</param> 28 + /// <returns>A case transformable string with its localisable string transformed to title case.</returns> 29 + public static CaseTransformableString ToTitle(this LocalisableString str) => new CaseTransformableString(str, Casing.TitleCase); 30 + 31 + /// <summary> 32 + /// Returns a <see cref="LocalisableString"/> with the specified underlying string data transformed to title case. 33 + /// </summary> 34 + /// <param name="data">The string data.</param> 35 + /// <returns>A case transformable string with its string data transformed to title case.</returns> 36 + public static CaseTransformableString ToTitle(this ILocalisableStringData data) => new LocalisableString(data).ToTitle(); 37 + 38 + /// <summary> 39 + /// Returns a <see cref="LocalisableString"/> with the specified underlying localisable string lowercased. 40 + /// </summary> 41 + /// <param name="str">The localisable string.</param> 42 + /// <returns>A case transformable string with its localisable string lowercased.</returns> 43 + public static CaseTransformableString ToLower(this LocalisableString str) => new CaseTransformableString(str, Casing.LowerCase); 44 + 45 + /// <summary> 46 + /// Returns a <see cref="LocalisableString"/> with the specified underlying string data lowercased. 47 + /// </summary> 48 + /// <param name="data">The string data.</param> 49 + /// <returns>A case transformable string with its string data lowercased.</returns> 50 + public static CaseTransformableString ToLower(this ILocalisableStringData data) => new LocalisableString(data).ToLower(); 51 + } 52 + }
+2
osu.Framework/Graphics/UserInterface/ColourPicker.cs
··· 63 63 /// </summary> 64 64 protected abstract HexColourPicker CreateHexColourPicker(); 65 65 66 + public override bool IsPresent => base.IsPresent || hsvColourPicker.IsPresent; 67 + 66 68 protected override void LoadComplete() 67 69 { 68 70 base.LoadComplete();
+4
osu.Framework/Graphics/UserInterface/HSVColourPicker.cs
··· 69 69 /// </summary> 70 70 protected abstract SaturationValueSelector CreateSaturationValueSelector(); 71 71 72 + public override bool IsPresent => base.IsPresent 73 + || saturationValueSelector.Scheduler.HasPendingTasks 74 + || hueSelector.Scheduler.HasPendingTasks; 75 + 72 76 protected override void LoadComplete() 73 77 { 74 78 base.LoadComplete();
+20 -5
osu.Framework/Graphics/UserInterface/TextBox.cs
··· 63 63 /// <returns>Whether the character is allowed to be added.</returns> 64 64 protected virtual bool CanAddCharacter(char character) => true; 65 65 66 - public bool ReadOnly; 66 + private bool readOnly; 67 + 68 + public bool ReadOnly 69 + { 70 + get => readOnly; 71 + set 72 + { 73 + readOnly = value; 74 + 75 + if (readOnly) 76 + KillFocus(); 77 + } 78 + } 67 79 68 80 /// <summary> 69 81 /// Whether the textbox should rescind focus on commit. ··· 743 755 private void killFocus() 744 756 { 745 757 var manager = GetContainingInputManager(); 746 - if (manager.FocusedDrawable == this) 758 + if (manager?.FocusedDrawable == this) 747 759 manager.ChangeFocus(null); 748 760 } 749 761 ··· 778 790 protected override void OnDrag(DragEvent e) 779 791 { 780 792 //if (textInput?.ImeActive == true) return true; 793 + 794 + if (ReadOnly) 795 + return; 781 796 782 797 if (doubleClickWord != null) 783 798 { ··· 868 883 869 884 protected override bool OnMouseDown(MouseDownEvent e) 870 885 { 871 - if (textInput?.ImeActive == true) return true; 886 + if (textInput?.ImeActive == true || ReadOnly) return true; 872 887 873 888 selectionStart = selectionEnd = getCharacterClosestTo(e.MousePosition); 874 889 ··· 917 932 918 933 private void unbindInput() 919 934 { 920 - textInput?.Deactivate(this); 935 + textInput?.Deactivate(); 921 936 } 922 937 923 938 private void bindInput() 924 939 { 925 - textInput?.Activate(this); 940 + textInput?.Activate(); 926 941 } 927 942 928 943 private void onImeResult()
+2 -2
osu.Framework/Input/GameWindowTextInput.cs
··· 35 35 } 36 36 } 37 37 38 - public void Deactivate(object sender) 38 + public void Deactivate() 39 39 { 40 40 switch (window) 41 41 { ··· 49 49 } 50 50 } 51 51 52 - public void Activate(object sender) 52 + public void Activate() 53 53 { 54 54 switch (window) 55 55 {
+2 -2
osu.Framework/Input/ITextInputSource.cs
··· 15 15 16 16 string GetPendingText(); 17 17 18 - void Deactivate(object sender); 18 + void Deactivate(); 19 19 20 - void Activate(object sender); 20 + void Activate(); 21 21 22 22 /// <summary> 23 23 /// Ensures that the native implementation that retrieves user text input is activated
+112
osu.Framework/Localisation/CaseTransformableString.cs
··· 1 + // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2 + // See the LICENCE file in the repository root for full licence text. 3 + 4 + using System; 5 + using System.Globalization; 6 + 7 + #nullable enable 8 + 9 + namespace osu.Framework.Localisation 10 + { 11 + /// <summary> 12 + /// A string which can apply case transformations to underlying localisable string. 13 + /// </summary> 14 + public class CaseTransformableString : IEquatable<CaseTransformableString>, ILocalisableStringData 15 + { 16 + /// <summary> 17 + /// The case to apply to the underlying data. 18 + /// </summary> 19 + public readonly Casing Casing; 20 + 21 + /// <summary> 22 + /// The underlying localisable string of this transformable string. 23 + /// </summary> 24 + public readonly LocalisableString String; 25 + 26 + /// <summary> 27 + /// Constructs a new transformable string with specified underlying localisable string and casing. 28 + /// </summary> 29 + /// <param name="str">The localisable string to apply case transformations on.</param> 30 + /// <param name="casing">The casing to use on the localisable string.</param> 31 + public CaseTransformableString(LocalisableString str, Casing casing) 32 + { 33 + String = str; 34 + Casing = casing; 35 + } 36 + 37 + public string GetLocalised(LocalisationParameters parameters) 38 + { 39 + var stringData = getStringData(parameters); 40 + var cultureText = parameters.Store?.EffectiveCulture?.TextInfo ?? CultureInfo.InvariantCulture.TextInfo; 41 + 42 + switch (Casing) 43 + { 44 + case Casing.UpperCase: 45 + return cultureText.ToUpper(stringData); 46 + 47 + case Casing.TitleCase: 48 + return cultureText.ToTitleCase(stringData); 49 + 50 + case Casing.LowerCase: 51 + return cultureText.ToLower(stringData); 52 + 53 + case Casing.Default: 54 + default: 55 + return stringData; 56 + } 57 + } 58 + 59 + public override string ToString() => GetLocalised(new LocalisationParameters(null, false)); 60 + 61 + public bool Equals(ILocalisableStringData? other) => other is CaseTransformableString transformable && Equals(transformable); 62 + 63 + public bool Equals(CaseTransformableString? other) 64 + { 65 + if (ReferenceEquals(null, other)) return false; 66 + if (ReferenceEquals(this, other)) return true; 67 + 68 + return Casing == other.Casing && String.Equals(other.String); 69 + } 70 + 71 + private string getStringData(LocalisationParameters localisationParameters) 72 + { 73 + switch (String.Data) 74 + { 75 + case string plain: 76 + return plain; 77 + 78 + case ILocalisableStringData data: 79 + return data.GetLocalised(localisationParameters); 80 + 81 + default: 82 + return string.Empty; 83 + } 84 + } 85 + } 86 + 87 + /// <summary> 88 + /// Case applicable to the underlying localisable string of a <see cref="CaseTransformableString"/>. 89 + /// </summary> 90 + public enum Casing 91 + { 92 + /// <summary> 93 + /// Use the string data case. 94 + /// </summary> 95 + Default, 96 + 97 + /// <summary> 98 + /// Transform the string data to uppercase. 99 + /// </summary> 100 + UpperCase, 101 + 102 + /// <summary> 103 + /// Transform the string data to title case aka capitalized case 104 + /// </summary> 105 + TitleCase, 106 + 107 + /// <summary> 108 + /// Transform the string data to lowercase. 109 + /// </summary> 110 + LowerCase 111 + } 112 + }
+1
osu.Framework/Localisation/LocalisableString.cs
··· 44 44 public static implicit operator LocalisableString(TranslatableString translatable) => new LocalisableString(translatable); 45 45 public static implicit operator LocalisableString(RomanisableString romanisable) => new LocalisableString(romanisable); 46 46 public static implicit operator LocalisableString(LocalisableFormattableString formattable) => new LocalisableString(formattable); 47 + public static implicit operator LocalisableString(CaseTransformableString transformable) => new LocalisableString(transformable); 47 48 48 49 public static bool operator ==(LocalisableString left, LocalisableString right) => left.Equals(right); 49 50 public static bool operator !=(LocalisableString left, LocalisableString right) => !left.Equals(right);
+17
osu.Framework/Localisation/LocalisableStringExtensions.cs
··· 1 + // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2 + // See the LICENCE file in the repository root for full licence text. 3 + 4 + using System; 5 + 6 + namespace osu.Framework.Localisation 7 + { 8 + public static class LocalisableStringExtensions 9 + { 10 + /// <summary> 11 + /// Returns a <see cref="LocalisableFormattableString"/> formatting the given <paramref name="value"/> with the specified <paramref name="format"/>. 12 + /// </summary> 13 + /// <param name="value">The value to format.</param> 14 + /// <param name="format">The format string.</param> 15 + public static LocalisableFormattableString ToLocalisableString(this IFormattable value, string format) => new LocalisableFormattableString(value, format); 16 + } 17 + }
+10 -1
osu.Framework/Localisation/TranslatableString.cs
··· 59 59 60 60 try 61 61 { 62 - return string.Format(parameters.Store.EffectiveCulture, localisedFormat, Args); 62 + return string.Format(parameters.Store.EffectiveCulture, localisedFormat, Args.Select(argument => 63 + { 64 + if (argument is LocalisableString localisableString) 65 + argument = localisableString.Data; 66 + 67 + if (argument is ILocalisableStringData localisableData) 68 + return localisableData.GetLocalised(parameters); 69 + 70 + return argument; 71 + }).ToArray()); 63 72 } 64 73 catch (FormatException e) 65 74 {