A game framework written with osu! in mind.
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.Collections.Generic;
5using System.Globalization;
6using osu.Framework.Bindables;
7using osu.Framework.Configuration;
8
9#nullable enable
10
11namespace osu.Framework.Localisation
12{
13 public partial class LocalisationManager
14 {
15 private readonly List<LocaleMapping> locales = new List<LocaleMapping>();
16
17 private readonly Bindable<string> configLocale = new Bindable<string>();
18 private readonly Bindable<bool> configPreferUnicode = new BindableBool();
19
20 private readonly Bindable<LocalisationParameters> currentParameters = new Bindable<LocalisationParameters>(new LocalisationParameters(null, false));
21
22 public LocalisationManager(FrameworkConfigManager config)
23 {
24 config.BindWith(FrameworkSetting.Locale, configLocale);
25 configLocale.BindValueChanged(updateLocale);
26
27 config.BindWith(FrameworkSetting.ShowUnicode, configPreferUnicode);
28 configPreferUnicode.BindValueChanged(updateUnicodePreference, true);
29 }
30
31 public void AddLanguage(string language, ILocalisationStore storage)
32 {
33 locales.Add(new LocaleMapping(language, storage));
34 configLocale.TriggerChange();
35 }
36
37 /// <summary>
38 /// Creates an <see cref="ILocalisedBindableString"/> which automatically updates its text according to information provided in <see cref="ILocalisedBindableString.Text"/>.
39 /// </summary>
40 /// <returns>The <see cref="ILocalisedBindableString"/>.</returns>
41 public ILocalisedBindableString GetLocalisedString(LocalisableString original) => new LocalisedBindableString(original, this);
42
43 private void updateLocale(ValueChangedEvent<string> locale)
44 {
45 if (locales.Count == 0)
46 return;
47
48 var validLocale = locales.Find(l => l.Name == locale.NewValue);
49
50 if (validLocale == null)
51 {
52 var culture = string.IsNullOrEmpty(locale.NewValue) ? CultureInfo.CurrentCulture : new CultureInfo(locale.NewValue);
53
54 for (var c = culture; !EqualityComparer<CultureInfo>.Default.Equals(c, CultureInfo.InvariantCulture); c = c.Parent)
55 {
56 validLocale = locales.Find(l => l.Name == c.Name);
57 if (validLocale != null)
58 break;
59 }
60
61 validLocale ??= locales[0];
62 }
63
64 ChangeSettings(CreateNewLocalisationParameters(validLocale.Storage, currentParameters.Value.PreferOriginalScript));
65 }
66
67 private void updateUnicodePreference(ValueChangedEvent<bool> preferUnicode)
68 => ChangeSettings(CreateNewLocalisationParameters(currentParameters.Value.Store, preferUnicode.NewValue));
69
70 /// <summary>
71 /// Changes the localisation parameters.
72 /// </summary>
73 /// <param name="parameters">The new localisation parameters.</param>
74 protected void ChangeSettings(LocalisationParameters parameters) => currentParameters.Value = parameters;
75
76 /// <summary>
77 /// Creates new <see cref="LocalisationParameters"/>.
78 /// </summary>
79 /// <remarks>
80 /// Can be overridden to provide custom parameters for <see cref="ILocalisableStringData"/> implementations.
81 /// </remarks>
82 /// <param name="store">The <see cref="ILocalisationStore"/> to be used for string lookups and culture-specific formatting.</param>
83 /// <param name="preferOriginalScript">Whether to prefer the "original" script of <see cref="RomanisableString"/>s.</param>
84 /// <returns>The resultant <see cref="LocalisationParameters"/>.</returns>
85 protected virtual LocalisationParameters CreateNewLocalisationParameters(ILocalisationStore? store, bool preferOriginalScript)
86 => new LocalisationParameters(store, preferOriginalScript);
87
88 private class LocaleMapping
89 {
90 public readonly string Name;
91 public readonly ILocalisationStore Storage;
92
93 public LocaleMapping(string name, ILocalisationStore storage)
94 {
95 Name = name;
96 Storage = storage;
97 }
98 }
99 }
100}