A game framework written with osu! in mind.
at master 18 kB view raw
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 4using System; 5using System.Collections.Generic; 6using System.Globalization; 7using System.IO; 8using System.Linq; 9using System.Threading.Tasks; 10using NUnit.Framework; 11using osu.Framework.Configuration; 12using osu.Framework.Extensions.LocalisationExtensions; 13using osu.Framework.Localisation; 14 15namespace osu.Framework.Tests.Localisation 16{ 17 [TestFixture] 18 public class LocalisationTest 19 { 20 private FrameworkConfigManager config; 21 private LocalisationManager manager; 22 23 [SetUp] 24 public void Setup() 25 { 26 config = new FakeFrameworkConfigManager(); 27 manager = new LocalisationManager(config); 28 manager.AddLanguage("en", new FakeStorage("en")); 29 } 30 31 [Test] 32 public void TestNoLanguagesAdded() 33 { 34 // reinitialise without the default language 35 manager = new LocalisationManager(config); 36 37 var localisedText = manager.GetLocalisedString(new TranslatableString(FakeStorage.LOCALISABLE_STRING_EN, FakeStorage.LOCALISABLE_STRING_EN)); 38 Assert.AreEqual(FakeStorage.LOCALISABLE_STRING_EN, localisedText.Value); 39 } 40 41 [Test] 42 public void TestConfigSettingRetainedWhenAddingNewLanguage() 43 { 44 config.SetValue(FrameworkSetting.Locale, "ja-JP"); 45 46 // ensure that adding a new language which doesn't match the user's choice doesn't cause the configuration value to get reset. 47 manager.AddLanguage("po", new FakeStorage("po-OP")); 48 Assert.AreEqual("ja-JP", config.Get<string>(FrameworkSetting.Locale)); 49 50 var localisedText = manager.GetLocalisedString(new TranslatableString(FakeStorage.LOCALISABLE_STRING_EN, FakeStorage.LOCALISABLE_STRING_EN)); 51 Assert.AreEqual(FakeStorage.LOCALISABLE_STRING_EN, localisedText.Value); 52 53 // ensure that if the user's selection is added in a further AddLanguage call, the manager correctly translates strings. 54 manager.AddLanguage("ja-JP", new FakeStorage("ja-JP")); 55 Assert.AreEqual(FakeStorage.LOCALISABLE_STRING_JA_JP, localisedText.Value); 56 } 57 58 [Test] 59 public void TestNotLocalised() 60 { 61 manager.AddLanguage("ja-JP", new FakeStorage("ja-JP")); 62 config.SetValue(FrameworkSetting.Locale, "ja-JP"); 63 64 var localisedText = manager.GetLocalisedString(FakeStorage.LOCALISABLE_STRING_EN); 65 66 Assert.AreEqual(FakeStorage.LOCALISABLE_STRING_EN, localisedText.Value); 67 68 localisedText.Text = FakeStorage.LOCALISABLE_STRING_JA; 69 70 Assert.AreEqual(FakeStorage.LOCALISABLE_STRING_JA, localisedText.Value); 71 } 72 73 [Test] 74 public void TestLocalised() 75 { 76 manager.AddLanguage("ja-JP", new FakeStorage("ja-JP")); 77 78 var localisedText = manager.GetLocalisedString(new TranslatableString(FakeStorage.LOCALISABLE_STRING_EN, FakeStorage.LOCALISABLE_STRING_EN)); 79 80 Assert.AreEqual(FakeStorage.LOCALISABLE_STRING_EN, localisedText.Value); 81 82 config.SetValue(FrameworkSetting.Locale, "ja-JP"); 83 Assert.AreEqual(FakeStorage.LOCALISABLE_STRING_JA_JP, localisedText.Value); 84 } 85 86 [Test] 87 public void TestLocalisationFallback() 88 { 89 manager.AddLanguage("ja", new FakeStorage("ja")); 90 91 config.SetValue(FrameworkSetting.Locale, "ja-JP"); 92 93 var localisedText = manager.GetLocalisedString(new TranslatableString(FakeStorage.LOCALISABLE_STRING_EN, FakeStorage.LOCALISABLE_STRING_EN)); 94 95 Assert.AreEqual(FakeStorage.LOCALISABLE_STRING_JA, localisedText.Value); 96 } 97 98 [Test] 99 public void TestFormatted() 100 { 101 const string to_format = "this {0} {1} formatted"; 102 const string arg_0 = "has"; 103 const string arg_1 = "been"; 104 105 string expectedResult = string.Format(to_format, arg_0, arg_1); 106 107 var formattedText = manager.GetLocalisedString(string.Format(to_format, arg_0, arg_1)); 108 109 Assert.AreEqual(expectedResult, formattedText.Value); 110 } 111 112 [Test] 113 public void TestFormattedInterpolation() 114 { 115 const string arg_0 = "formatted"; 116 117 manager.AddLanguage("ja-JP", new FakeStorage("ja")); 118 config.SetValue(FrameworkSetting.Locale, "ja-JP"); 119 120 string expectedResult = string.Format(FakeStorage.LOCALISABLE_FORMAT_STRING_JA, arg_0); 121 122 var formattedText = manager.GetLocalisedString(new TranslatableString(FakeStorage.LOCALISABLE_FORMAT_STRING_EN, interpolation: $"The {arg_0} fallback should only matches argument count")); 123 124 Assert.AreEqual(expectedResult, formattedText.Value); 125 } 126 127 [Test] 128 public void TestFormattedAndLocalised() 129 { 130 const string arg_0 = "formatted"; 131 132 string expectedResult = string.Format(FakeStorage.LOCALISABLE_FORMAT_STRING_JA, arg_0); 133 134 manager.AddLanguage("ja", new FakeStorage("ja")); 135 config.SetValue(FrameworkSetting.Locale, "ja"); 136 137 var formattedText = manager.GetLocalisedString(new TranslatableString(FakeStorage.LOCALISABLE_FORMAT_STRING_EN, FakeStorage.LOCALISABLE_FORMAT_STRING_EN, arg_0)); 138 139 Assert.AreEqual(expectedResult, formattedText.Value); 140 } 141 142 [Test] 143 public void TestNumberCultureAware() 144 { 145 const double value = 1.23; 146 147 manager.AddLanguage("fr", new FakeStorage("fr")); 148 config.SetValue(FrameworkSetting.Locale, "fr"); 149 150 var expectedResult = string.Format(new CultureInfo("fr"), FakeStorage.LOCALISABLE_NUMBER_FORMAT_STRING_FR, value); 151 Assert.AreEqual("number 1,23 FR", expectedResult); // FR uses comma for decimal point. 152 153 var formattedText = manager.GetLocalisedString(new TranslatableString(FakeStorage.LOCALISABLE_NUMBER_FORMAT_STRING_EN, null, value)); 154 155 Assert.AreEqual(expectedResult, formattedText.Value); 156 } 157 158 [Test] 159 public void TestStorageNotFound() 160 { 161 manager.AddLanguage("ja", new FakeStorage("ja")); 162 config.SetValue(FrameworkSetting.Locale, "ja"); 163 164 const string expected_fallback = "fallback string"; 165 166 var formattedText = manager.GetLocalisedString(new TranslatableString("no such key", expected_fallback)); 167 168 Assert.AreEqual(expected_fallback, formattedText.Value); 169 } 170 171 [Test] 172 public void TestUnicodePreference() 173 { 174 const string non_unicode = "non unicode"; 175 const string unicode = "unicode"; 176 177 var text = manager.GetLocalisedString(new RomanisableString(unicode, non_unicode)); 178 179 config.SetValue(FrameworkSetting.ShowUnicode, true); 180 Assert.AreEqual(unicode, text.Value); 181 182 config.SetValue(FrameworkSetting.ShowUnicode, false); 183 Assert.AreEqual(non_unicode, text.Value); 184 } 185 186 [Test] 187 public void TestUnicodeStringChanging() 188 { 189 const string non_unicode_1 = "non unicode 1"; 190 const string non_unicode_2 = "non unicode 2"; 191 const string unicode_1 = "unicode 1"; 192 const string unicode_2 = "unicode 2"; 193 194 var text = manager.GetLocalisedString(new RomanisableString(unicode_1, non_unicode_1)); 195 196 config.SetValue(FrameworkSetting.ShowUnicode, false); 197 Assert.AreEqual(non_unicode_1, text.Value); 198 199 text.Text = new RomanisableString(unicode_1, non_unicode_2); 200 Assert.AreEqual(non_unicode_2, text.Value); 201 202 config.SetValue(FrameworkSetting.ShowUnicode, true); 203 Assert.AreEqual(unicode_1, text.Value); 204 205 text.Text = new RomanisableString(unicode_2, non_unicode_2); 206 Assert.AreEqual(unicode_2, text.Value); 207 } 208 209 [Test] 210 public void TestEmptyStringFallback([Values("", null)] string emptyValue) 211 { 212 const string non_unicode_fallback = "non unicode"; 213 const string unicode_fallback = "unicode"; 214 215 var text = manager.GetLocalisedString(new RomanisableString(unicode_fallback, emptyValue)); 216 217 config.SetValue(FrameworkSetting.ShowUnicode, false); 218 Assert.AreEqual(unicode_fallback, text.Value); 219 220 text = manager.GetLocalisedString(new RomanisableString(emptyValue, non_unicode_fallback)); 221 222 config.SetValue(FrameworkSetting.ShowUnicode, true); 223 Assert.AreEqual(non_unicode_fallback, text.Value); 224 } 225 226 /// <summary> 227 /// This tests the <see cref="LocalisableFormattableString"/>, which allows for formatting <see cref="IFormattable"/>s, 228 /// without necessarily being in a <see cref="TranslatableString"/> which requires keys mapping to strings from localistaion stores. 229 /// </summary> 230 [Test] 231 public void TestLocalisableFormattableString() 232 { 233 manager.AddLanguage("fr", new FakeStorage("fr")); 234 235 var dateTime = new DateTime(1); 236 const string format = "MMM yyyy"; 237 238 var text = manager.GetLocalisedString(dateTime.ToLocalisableString(format)); 239 240 Assert.AreEqual("Jan 0001", text.Value); 241 242 config.SetValue(FrameworkSetting.Locale, "fr"); 243 Assert.AreEqual("janv. 0001", text.Value); 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 354 private class FakeFrameworkConfigManager : FrameworkConfigManager 355 { 356 protected override string Filename => null; 357 358 public FakeFrameworkConfigManager() 359 : base(null) 360 { 361 } 362 363 protected override void InitialiseDefaults() 364 { 365 SetDefault(FrameworkSetting.Locale, ""); 366 SetDefault(FrameworkSetting.ShowUnicode, true); 367 } 368 } 369 370 private class FakeStorage : ILocalisationStore 371 { 372 public const string LOCALISABLE_STRING_EN = "localised EN"; 373 public const string LOCALISABLE_STRING_JA = "localised JA"; 374 public const string LOCALISABLE_STRING_JA_JP = "localised JA-JP"; 375 public const string LOCALISABLE_STRING_TR = "localised TR (i/I)"; 376 public const string LOCALISABLE_FORMAT_STRING_EN = "{0} localised EN"; 377 public const string LOCALISABLE_FORMAT_STRING_JA = "{0} localised JA"; 378 public const string LOCALISABLE_NUMBER_FORMAT_STRING_EN = "number {0} EN"; 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"; 382 383 public CultureInfo EffectiveCulture { get; } 384 385 private readonly string locale; 386 387 public FakeStorage(string locale) 388 { 389 this.locale = locale; 390 EffectiveCulture = new CultureInfo(locale); 391 } 392 393 public async Task<string> GetAsync(string name) => await Task.Run(() => Get(name)).ConfigureAwait(false); 394 395 public string Get(string name) 396 { 397 switch (name) 398 { 399 case LOCALISABLE_STRING_EN: 400 switch (locale) 401 { 402 default: 403 return LOCALISABLE_STRING_EN; 404 405 case "ja": 406 return LOCALISABLE_STRING_JA; 407 408 case "ja-JP": 409 return LOCALISABLE_STRING_JA_JP; 410 411 case "tr": 412 return LOCALISABLE_STRING_TR; 413 } 414 415 case LOCALISABLE_FORMAT_STRING_EN: 416 switch (locale) 417 { 418 default: 419 return LOCALISABLE_FORMAT_STRING_EN; 420 421 case "ja": 422 return LOCALISABLE_FORMAT_STRING_JA; 423 } 424 425 case LOCALISABLE_NUMBER_FORMAT_STRING_EN: 426 switch (locale) 427 { 428 default: 429 return LOCALISABLE_NUMBER_FORMAT_STRING_EN; 430 431 case "fr": 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; 443 } 444 445 default: 446 return null; 447 } 448 } 449 450 public Stream GetStream(string name) => throw new NotSupportedException(); 451 452 public void Dispose() 453 { 454 } 455 456 public IEnumerable<string> GetAvailableResources() => Enumerable.Empty<string>(); 457 } 458 } 459}