Set default language based on Windows language.

This commit is contained in:
Burak Kaan Köse
2026-04-22 22:39:19 +02:00
parent 39cde10fab
commit 81e28129b7
6 changed files with 158 additions and 10 deletions
@@ -2,6 +2,8 @@
public interface IConfigurationService
{
bool Contains(string key);
void Set(string key, object value);
T Get<T>(string key, T defaultValue = default);
@@ -0,0 +1,23 @@
using FluentAssertions;
using Wino.Core.Domain.Enums;
using Wino.Services;
using Xunit;
namespace Wino.Core.Tests.Services;
public class TranslationServiceTests
{
[Theory]
[InlineData("pl-PL", AppLanguage.Polish)]
[InlineData("de-AT", AppLanguage.Deutsch)]
[InlineData("pt-PT", AppLanguage.PortugeseBrazil)]
[InlineData("zh-TW", AppLanguage.Chinese)]
[InlineData("tr_TR", AppLanguage.Turkish)]
[InlineData("nl-NL", AppLanguage.English)]
public void ResolveSupportedLanguage_ReturnsExpectedLanguage(string languageTag, AppLanguage expectedLanguage)
{
var result = TranslationService.ResolveSupportedLanguage([languageTag]);
result.Should().Be(expectedLanguage);
}
}
@@ -9,6 +9,9 @@ namespace Wino.Mail.WinUI.Services;
public class ConfigurationService : IConfigurationService
{
public bool Contains(string key)
=> ApplicationData.Current.LocalSettings.Values.ContainsKey(key);
public T Get<T>(string key, T defaultValue = default!)
=> GetInternal(key, ApplicationData.Current.LocalSettings.Values, defaultValue);
+61 -7
View File
@@ -147,10 +147,31 @@ public sealed partial class SettingsPage : SettingsPageAbstract,
public void Receive(SettingsRootNavigationRequested message)
{
var currentRootPage = SettingsNavigationInfoProvider.GetRootPage(PageHistory.LastOrDefault()?.Request.PageType ?? WinoPage.SettingOptionsPage);
if (message.PageType != WinoPage.SettingOptionsPage && currentRootPage == message.PageType)
var activePage = PageHistory.LastOrDefault()?.Request.PageType ?? WinoPage.SettingOptionsPage;
var currentRootPage = SettingsNavigationInfoProvider.GetRootPage(activePage);
if (message.PageType == currentRootPage)
{
if (activePage == currentRootPage)
return;
var currentRootIndex = PageHistory
.Select((item, index) => new { item.Request.PageType, Index = index })
.FirstOrDefault(item => item.PageType == currentRootPage)?.Index ?? -1;
if (TryNavigateToBreadcrumbIndex(currentRootIndex))
return;
}
if (message.PageType == WinoPage.SettingOptionsPage)
{
if (activePage == WinoPage.SettingOptionsPage)
return;
NavigateToSettingsHome();
return;
}
NavigateToRootPage(message.PageType);
}
@@ -196,11 +217,7 @@ public sealed partial class SettingsPage : SettingsPageAbstract,
private void NavigateToRootPage(WinoPage targetPage)
{
PageHistory.Clear();
SettingsFrame.BackStack.Clear();
SettingsFrame.ForwardStack.Clear();
NavigateBreadcrumb(new BreadcrumbNavigationRequested(Translator.MenuSettings, WinoPage.SettingOptionsPage));
NavigateToSettingsHome();
if (targetPage != WinoPage.SettingOptionsPage)
{
@@ -213,6 +230,43 @@ public sealed partial class SettingsPage : SettingsPageAbstract,
UpdateWindowTitle();
}
private void NavigateToSettingsHome()
{
if (PageHistory.Count == 0 || SettingsFrame.Content == null)
{
ResetToSettingsHome();
return;
}
if (PageHistory.Count == 1)
return;
if (!TryNavigateToBreadcrumbIndex(0))
{
ResetToSettingsHome();
}
}
private bool TryNavigateToBreadcrumbIndex(int targetIndex)
{
if (!BreadcrumbNavigationHelper.NavigateTo(SettingsFrame, PageHistory, targetIndex))
return false;
UpdateBackNavigationState();
_ = RefreshCurrentPageStateAsync();
UpdateWindowTitle();
return true;
}
private void ResetToSettingsHome()
{
PageHistory.Clear();
SettingsFrame.BackStack.Clear();
SettingsFrame.ForwardStack.Clear();
NavigateBreadcrumb(new BreadcrumbNavigationRequested(Translator.MenuSettings, WinoPage.SettingOptionsPage));
}
public void ResetForModeSwitch()
{
while (PageHistory.Count > 1 && SettingsFrame.CanGoBack)
+3
View File
@@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Wino.Core.Tests")]
+66 -3
View File
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.Json;
@@ -19,17 +20,19 @@ public class TranslationService : ITranslationService
private ILogger _logger = Log.ForContext<TranslationService>();
private readonly IPreferencesService _preferencesService;
private readonly IConfigurationService _configurationService;
private bool isInitialized = false;
public AppLanguageModel CurrentLanguageModel { get; private set; }
public TranslationService(IPreferencesService preferencesService)
public TranslationService(IPreferencesService preferencesService, IConfigurationService configurationService)
{
_preferencesService = preferencesService;
_configurationService = configurationService;
}
// Initialize default language with ignoring current language check.
public Task InitializeAsync() => InitializeLanguageAsync(_preferencesService.CurrentLanguage, ignoreCurrentLanguageCheck: true);
public Task InitializeAsync() => InitializeLanguageAsync(GetInitialLanguage(), ignoreCurrentLanguageCheck: true);
public async Task InitializeLanguageAsync(AppLanguage language, bool ignoreCurrentLanguageCheck = false)
{
@@ -65,6 +68,66 @@ public class TranslationService : ITranslationService
WeakReferenceMessenger.Default.Send(new LanguageChanged());
}
private AppLanguage GetInitialLanguage()
{
if (_configurationService.Contains(nameof(IPreferencesService.CurrentLanguage)))
return _preferencesService.CurrentLanguage;
var windowsDisplayLanguage = CultureInfo.CurrentUICulture?.Name;
var initialLanguage = ResolveSupportedLanguage(
[
windowsDisplayLanguage ?? string.Empty,
CultureInfo.CurrentUICulture?.TwoLetterISOLanguageName ?? string.Empty
]);
_logger.Information("No saved app language preference found. Using Windows display language {LanguageTag} -> {Language}.",
string.IsNullOrWhiteSpace(windowsDisplayLanguage) ? "<unknown>" : windowsDisplayLanguage,
initialLanguage);
return initialLanguage;
}
internal static AppLanguage ResolveSupportedLanguage(IEnumerable<string> languageTags)
{
foreach (var languageTag in languageTags)
{
if (string.IsNullOrWhiteSpace(languageTag))
continue;
var normalizedLanguageTag = languageTag.Replace('_', '-').Trim();
var languageCode = normalizedLanguageTag.Split('-')[0];
if (TryResolveSupportedLanguage(languageCode, out var supportedLanguage))
return supportedLanguage;
}
return DefaultAppLanguage;
}
private static bool TryResolveSupportedLanguage(string languageCode, out AppLanguage supportedLanguage)
{
supportedLanguage = languageCode.ToLowerInvariant() switch
{
"cs" => AppLanguage.Czech,
"de" => AppLanguage.Deutsch,
"el" => AppLanguage.Greek,
"en" => AppLanguage.English,
"es" => AppLanguage.Spanish,
"fr" => AppLanguage.French,
"id" => AppLanguage.Indonesian,
"it" => AppLanguage.Italian,
"pl" => AppLanguage.Polish,
"pt" => AppLanguage.PortugeseBrazil,
"ro" => AppLanguage.Romanian,
"ru" => AppLanguage.Russian,
"tr" => AppLanguage.Turkish,
"zh" => AppLanguage.Chinese,
_ => AppLanguage.None
};
return supportedLanguage != AppLanguage.None;
}
public List<AppLanguageModel> GetAvailableLanguages()
{
return