1using Microsoft.Extensions.Localization;
3using System.ComponentModel;
4using System.Globalization;
5using System.Reflection;
6using System.Runtime.CompilerServices;
15 [ContentProperty(nameof(Path))]
16 public class LocalizeExtension : IMarkupExtension<BindingBase>, INotifyPropertyChanged, IDisposable
18 private static readonly Dictionary<Type, SortedDictionary<string, bool>> missingStrings = [];
19 private static Timer? timer =
null;
21 private IStringLocalizer? localizer;
22 private bool isDisposed;
26 Log.Terminating += Log_Terminating;
29 private static void Log_Terminating(
object? sender, EventArgs e)
43 return this.localizer;
47 public string Path {
get;
set; } =
".";
48 public BindingMode Mode {
get;
set; } = BindingMode.OneWay;
49 public IValueConverter? Converter {
get;
set; } =
null;
50 public string? ConverterParameter {
get;
set; } =
null;
51 public string? StringFormat {
get;
set; } =
null;
52 public Type? StringResource {
get;
set; } =
null;
54 public object ProvideValue(IServiceProvider ServiceProvider)
56 return (
this as IMarkupExtension<BindingBase>).ProvideValue(ServiceProvider);
59 BindingBase IMarkupExtension<BindingBase>.ProvideValue(IServiceProvider ServiceProvider)
61 Type ResourcesType = this.StringResource ?? typeof(AppResources);
63 if (ResourcesType.GetRuntimeProperties().FirstOrDefault(pi => pi.Name ==
this.Path) is
null)
66 return new Binding(
"Localizer[STRINGNOTDEFINED]", this.Mode, this.Converter, this.ConverterParameter, this.StringFormat,
this);
69 return new Binding($
"Localizer[{this.Path}]", this.Mode, this.Converter, this.ConverterParameter, this.StringFormat,
this);
84 if (!missingStrings.TryGetValue(Type, out SortedDictionary<string, bool>? PerId))
87 missingStrings[Type] = PerId;
90 PerId[StringId] =
true;
92 timer =
new Timer(LogAlert,
null, 1000, Timeout.Infinite);
96 private static void LogAlert(
object? _)
98 StringBuilder sb =
new();
100 sb.AppendLine(
"Missing localized strings:");
103 lock (missingStrings)
105 foreach (KeyValuePair<Type, SortedDictionary<string, bool>> P
in missingStrings)
108 sb.AppendLine(P.Key.FullName);
109 sb.AppendLine(
new string(
'-', (P.Key.FullName?.Length ?? 0) + 3));
112 foreach (
string Key
in P.Value.Keys)
119 missingStrings.Clear();
122 ServiceRef.LogService.LogAlert(sb.ToString());
125 public LocalizeExtension()
127 LocalizationManager.CurrentCultureChanged += this.OnCurrentCultureChanged;
135 private void OnCurrentCultureChanged(
object? sender, CultureInfo culture)
137 PropertyChanged?.Invoke(
this,
new PropertyChangedEventArgs(nameof(this.
Localizer)));
146 GC.SuppressFinalize(
this);
152 protected virtual void Dispose(
bool disposing)
157 LocalizationManager.CurrentCultureChanged -= this.OnCurrentCultureChanged;
159 this.isDisposed =
true;
162 public event PropertyChangedEventHandler? PropertyChanged;
Access to localized strings.
static void ReportMissingString(string StringId, Type Type)
Reports a missing string
virtual void Dispose(bool disposing)
IDisposable.Dispose
void Dispose()
IDisposable.Dispose
IStringLocalizer Localizer
Localizer instance reference.