using System; using System.Windows; using HC_APTBS.Infrastructure.Logging; namespace HC_APTBS.Services.Impl { /// /// Manages runtime language switching by swapping a merged /// in . /// /// /// On construction the service reads /// and loads the corresponding dictionary. Subsequent calls to /// replace it in-place and persist the preference. /// public sealed class LocalizationService : ILocalizationService { private const string LogId = "LOCALIZATION"; private const string EspUri = "pack://application:,,,/Resources/Strings.es.xaml"; private const string EngUri = "pack://application:,,,/Resources/Strings.en.xaml"; private readonly IConfigurationService _config; private readonly IAppLogger _log; // Single, persistent slot in Application.Resources.MergedDictionaries whose // Source we re-point on every language change. Mutating an existing // dictionary's Source triggers WPF's DynamicResource invalidation reliably, // whereas removing-and-adding entries can leave stale resolved values // depending on the dictionary's parent/owner state. private readonly ResourceDictionary _stringsSlot = new(); /// public string CurrentLanguage { get; private set; } = "ESP"; /// public event Action? LanguageChanged; /// /// Initialises the localization service and loads the language /// stored in . /// public LocalizationService(IConfigurationService config, IAppLogger log) { _config = config; _log = log; // Mount the persistent slot once. From here on we only update its Source. Application.Current.Resources.MergedDictionaries.Add(_stringsSlot); // Load persisted language without saving (already persisted). LoadDictionary(_config.Settings.Language); } /// public void SetLanguage(string languageCode) { var code = NormaliseCode(languageCode); _log.Info(LogId, $"SetLanguage('{languageCode}') -> normalised='{code}', current='{CurrentLanguage}'"); if (code == CurrentLanguage) { _log.Info(LogId, "SetLanguage: already current, no-op."); return; } LoadDictionary(code); // Persist the choice. _config.Settings.Language = code; _config.SaveSettings(); LanguageChanged?.Invoke(); } /// public string GetString(string key) { return Application.Current.Resources[key]?.ToString() ?? key; } // ── Helpers ────────────────────────────────────────────────────────────── private void LoadDictionary(string languageCode) { var code = NormaliseCode(languageCode); var uri = code == "ENG" ? EngUri : EspUri; try { _stringsSlot.Source = new Uri(uri, UriKind.Absolute); } catch (Exception ex) { _log.Error(LogId, $"LoadDictionary({code}) failed to load {uri}: {ex.Message}"); return; } CurrentLanguage = code; _log.Info(LogId, $"LoadDictionary({code}): {uri} loaded with {_stringsSlot.Count} keys."); } private static string NormaliseCode(string code) => string.Equals(code, "ENG", StringComparison.OrdinalIgnoreCase) ? "ENG" : "ESP"; } }