Skip to content

Commit 5e026c0

Browse files
authored
Merge pull request #3566 from Flow-Launcher/winform_language_issue
Fix plugin culture info issue for those that use WinForm
2 parents 93bc231 + 9e24d2c commit 5e026c0

File tree

4 files changed

+94
-40
lines changed

4 files changed

+94
-40
lines changed

Flow.Launcher.Core/Resource/Internationalization.cs

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Globalization;
34
using System.IO;
45
using System.Linq;
56
using System.Reflection;
7+
using System.Threading;
8+
using System.Threading.Tasks;
69
using System.Windows;
10+
using CommunityToolkit.Mvvm.DependencyInjection;
711
using Flow.Launcher.Core.Plugin;
812
using Flow.Launcher.Infrastructure;
913
using Flow.Launcher.Infrastructure.UserSettings;
1014
using Flow.Launcher.Plugin;
11-
using System.Globalization;
12-
using System.Threading.Tasks;
13-
using CommunityToolkit.Mvvm.DependencyInjection;
1415

1516
namespace Flow.Launcher.Core.Resource
1617
{
@@ -29,13 +30,12 @@ public class Internationalization
2930
private readonly Settings _settings;
3031
private readonly List<string> _languageDirectories = new();
3132
private readonly List<ResourceDictionary> _oldResources = new();
32-
private readonly string SystemLanguageCode;
33+
private static string SystemLanguageCode;
3334

3435
public Internationalization(Settings settings)
3536
{
3637
_settings = settings;
3738
AddFlowLauncherLanguageDirectory();
38-
SystemLanguageCode = GetSystemLanguageCodeAtStartup();
3939
}
4040

4141
private void AddFlowLauncherLanguageDirectory()
@@ -44,7 +44,7 @@ private void AddFlowLauncherLanguageDirectory()
4444
_languageDirectories.Add(directory);
4545
}
4646

47-
private static string GetSystemLanguageCodeAtStartup()
47+
public static void InitSystemLanguageCode()
4848
{
4949
var availableLanguages = AvailableLanguages.GetAvailableLanguages();
5050

@@ -65,11 +65,11 @@ private static string GetSystemLanguageCodeAtStartup()
6565
string.Equals(languageCode, threeLetterCode, StringComparison.OrdinalIgnoreCase) ||
6666
string.Equals(languageCode, fullName, StringComparison.OrdinalIgnoreCase))
6767
{
68-
return languageCode;
68+
SystemLanguageCode = languageCode;
6969
}
7070
}
7171

72-
return DefaultLanguageCode;
72+
SystemLanguageCode = DefaultLanguageCode;
7373
}
7474

7575
private void AddPluginLanguageDirectories()
@@ -173,15 +173,33 @@ private async Task ChangeLanguageAsync(Language language)
173173
LoadLanguage(language);
174174
}
175175

176-
// Culture of main thread
177-
// Use CreateSpecificCulture to preserve possible user-override settings in Windows, if Flow's language culture is the same as Windows's
178-
CultureInfo.CurrentCulture = CultureInfo.CreateSpecificCulture(language.LanguageCode);
179-
CultureInfo.CurrentUICulture = CultureInfo.CurrentCulture;
176+
// Change culture info
177+
ChangeCultureInfo(language.LanguageCode);
180178

181179
// Raise event for plugins after culture is set
182180
await Task.Run(UpdatePluginMetadataTranslations);
183181
}
184182

183+
public static void ChangeCultureInfo(string languageCode)
184+
{
185+
// Culture of main thread
186+
// Use CreateSpecificCulture to preserve possible user-override settings in Windows, if Flow's language culture is the same as Windows's
187+
CultureInfo currentCulture;
188+
try
189+
{
190+
currentCulture = CultureInfo.CreateSpecificCulture(languageCode);
191+
}
192+
catch (CultureNotFoundException)
193+
{
194+
currentCulture = CultureInfo.CreateSpecificCulture(SystemLanguageCode);
195+
}
196+
CultureInfo.CurrentCulture = currentCulture;
197+
CultureInfo.CurrentUICulture = currentCulture;
198+
var thread = Thread.CurrentThread;
199+
thread.CurrentCulture = currentCulture;
200+
thread.CurrentUICulture = currentCulture;
201+
}
202+
185203
public bool PromptShouldUsePinyin(string languageCodeToSet)
186204
{
187205
var languageToSet = GetLanguageByLanguageCode(languageCodeToSet);

Flow.Launcher.Infrastructure/UserSettings/Settings.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,13 @@ public void SetStorage(FlowLauncherJsonStorage<Settings> storage)
2525

2626
public void Initialize()
2727
{
28+
// Initialize dependency injection instances after Ioc.Default is created
2829
_stringMatcher = Ioc.Default.GetRequiredService<StringMatcher>();
30+
31+
// Initialize application resources after application is created
32+
var settingWindowFont = new FontFamily(SettingWindowFont);
33+
Application.Current.Resources["SettingWindowFont"] = settingWindowFont;
34+
Application.Current.Resources["ContentControlThemeFontFamily"] = settingWindowFont;
2935
}
3036

3137
public void Save()
@@ -119,8 +125,11 @@ public string SettingWindowFont
119125
{
120126
_settingWindowFont = value;
121127
OnPropertyChanged();
122-
Application.Current.Resources["SettingWindowFont"] = new FontFamily(value);
123-
Application.Current.Resources["ContentControlThemeFontFamily"] = new FontFamily(value);
128+
if (Application.Current != null)
129+
{
130+
Application.Current.Resources["SettingWindowFont"] = new FontFamily(value);
131+
Application.Current.Resources["ContentControlThemeFontFamily"] = new FontFamily(value);
132+
}
124133
}
125134
}
126135
}

Flow.Launcher/App.xaml.cs

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ public partial class App : IDisposable, ISingleInstanceApp
4141
private static readonly string ClassName = nameof(App);
4242

4343
private static bool _disposed;
44+
private static Settings _settings;
4445
private static MainWindow _mainWindow;
4546
private readonly MainViewModel _mainVM;
46-
private readonly Settings _settings;
4747

4848
// To prevent two disposals running at the same time.
4949
private static readonly object _disposingLock = new();
@@ -55,18 +55,7 @@ public partial class App : IDisposable, ISingleInstanceApp
5555
public App()
5656
{
5757
// Initialize settings
58-
try
59-
{
60-
var storage = new FlowLauncherJsonStorage<Settings>();
61-
_settings = storage.Load();
62-
_settings.SetStorage(storage);
63-
_settings.WMPInstalled = WindowsMediaPlayerHelper.IsWindowsMediaPlayerInstalled();
64-
}
65-
catch (Exception e)
66-
{
67-
ShowErrorMsgBoxAndFailFast("Cannot load setting storage, please check local data directory", e);
68-
return;
69-
}
58+
_settings.WMPInstalled = WindowsMediaPlayerHelper.IsWindowsMediaPlayerInstalled();
7059

7160
// Configure the dependency injection container
7261
try
@@ -123,16 +112,6 @@ public App()
123112
ShowErrorMsgBoxAndFailFast("Cannot initialize api and settings, please open new issue in Flow.Launcher", e);
124113
return;
125114
}
126-
127-
// Local function
128-
static void ShowErrorMsgBoxAndFailFast(string message, Exception e)
129-
{
130-
// Firstly show users the message
131-
MessageBox.Show(e.ToString(), message, MessageBoxButton.OK, MessageBoxImage.Error);
132-
133-
// Flow cannot construct its App instance, so ensure Flow crashes w/ the exception info.
134-
Environment.FailFast(message, e);
135-
}
136115
}
137116

138117
#endregion
@@ -142,6 +121,29 @@ static void ShowErrorMsgBoxAndFailFast(string message, Exception e)
142121
[STAThread]
143122
public static void Main()
144123
{
124+
// Initialize settings so that we can get language code
125+
try
126+
{
127+
var storage = new FlowLauncherJsonStorage<Settings>();
128+
_settings = storage.Load();
129+
_settings.SetStorage(storage);
130+
}
131+
catch (Exception e)
132+
{
133+
ShowErrorMsgBoxAndFailFast("Cannot load setting storage, please check local data directory", e);
134+
return;
135+
}
136+
137+
// Initialize system language before changing culture info
138+
Internationalization.InitSystemLanguageCode();
139+
140+
// Change culture info before application creation to localize WinForm windows
141+
if (_settings.Language != Constant.SystemLanguageCode)
142+
{
143+
Internationalization.ChangeCultureInfo(_settings.Language);
144+
}
145+
146+
// Start the application as a single instance
145147
if (SingleInstance<App>.InitializeAsFirstInstance())
146148
{
147149
using var application = new App();
@@ -152,6 +154,19 @@ public static void Main()
152154

153155
#endregion
154156

157+
#region Fail Fast
158+
159+
private static void ShowErrorMsgBoxAndFailFast(string message, Exception e)
160+
{
161+
// Firstly show users the message
162+
MessageBox.Show(e.ToString(), message, MessageBoxButton.OK, MessageBoxImage.Error);
163+
164+
// Flow cannot construct its App instance, so ensure Flow crashes w/ the exception info.
165+
Environment.FailFast(message, e);
166+
}
167+
168+
#endregion
169+
155170
#region App Events
156171

157172
#pragma warning disable VSTHRD100 // Avoid async void methods
Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,23 @@
1-
using Microsoft.Win32;
1+
using System;
2+
using Microsoft.Win32;
23

34
namespace Flow.Launcher.Helper;
5+
46
internal static class WindowsMediaPlayerHelper
57
{
8+
private static readonly string ClassName = nameof(WindowsMediaPlayerHelper);
9+
610
internal static bool IsWindowsMediaPlayerInstalled()
711
{
8-
using var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\MediaPlayer");
9-
return key?.GetValue("Installation Directory") != null;
12+
try
13+
{
14+
using var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\MediaPlayer");
15+
return key?.GetValue("Installation Directory") != null;
16+
}
17+
catch (Exception e)
18+
{
19+
App.API.LogException(ClassName, "Failed to check if Windows Media Player is installed", e);
20+
return false;
21+
}
1022
}
1123
}

0 commit comments

Comments
 (0)