Skip to content

Commit 87e39df

Browse files
jjw24TBM13
authored andcommitted
Merge pull request Flow-Launcher#3850 from Flow-Launcher/fast_load_language
Initialize language before portable clean up and plugin initialization
1 parent 3d8b732 commit 87e39df

File tree

3 files changed

+143
-74
lines changed

3 files changed

+143
-74
lines changed

Flow.Launcher.Core/Plugin/PluginManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public static class PluginManager
3939
/// <summary>
4040
/// Directories that will hold Flow Launcher plugin directory
4141
/// </summary>
42-
private static readonly string[] Directories =
42+
public static readonly string[] Directories =
4343
{
4444
Constant.PreinstalledDirectory, DataLocation.PluginsDirectory
4545
};

Flow.Launcher.Core/Resource/Internationalization.cs

Lines changed: 137 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using System.Globalization;
44
using System.IO;
55
using System.Linq;
6-
using System.Reflection;
76
using System.Threading;
87
using System.Threading.Tasks;
98
using System.Windows;
@@ -28,54 +27,46 @@ public class Internationalization
2827
private const string DefaultFile = "en.xaml";
2928
private const string Extension = ".xaml";
3029
private readonly Settings _settings;
31-
private readonly List<string> _languageDirectories = new();
32-
private readonly List<ResourceDictionary> _oldResources = new();
30+
private readonly List<string> _languageDirectories = [];
31+
private readonly List<ResourceDictionary> _oldResources = [];
3332
private static string SystemLanguageCode;
3433

3534
public Internationalization(Settings settings)
3635
{
3736
_settings = settings;
38-
AddFlowLauncherLanguageDirectory();
3937
}
4038

41-
private void AddFlowLauncherLanguageDirectory()
42-
{
43-
var directory = Path.Combine(Constant.ProgramDirectory, Folder);
44-
_languageDirectories.Add(directory);
45-
}
39+
#region Initialization
4640

41+
/// <summary>
42+
/// Initialize the system language code based on the current culture.
43+
/// </summary>
4744
public static void InitSystemLanguageCode()
4845
{
49-
SystemLanguageCode = DefaultLanguageCode;
50-
}
46+
var availableLanguages = AvailableLanguages.GetAvailableLanguages();
5147

52-
private void AddPluginLanguageDirectories()
53-
{
54-
foreach (var plugin in PluginManager.GetTranslationPlugins())
48+
// Retrieve the language identifiers for the current culture.
49+
// ChangeLanguage method overrides the CultureInfo.CurrentCulture, so this needs to
50+
// be called at startup in order to get the correct lang code of system.
51+
var currentCulture = CultureInfo.CurrentCulture;
52+
var twoLetterCode = currentCulture.TwoLetterISOLanguageName;
53+
var threeLetterCode = currentCulture.ThreeLetterISOLanguageName;
54+
var fullName = currentCulture.Name;
55+
56+
// Try to find a match in the available languages list
57+
foreach (var language in availableLanguages)
5558
{
56-
var location = Assembly.GetAssembly(plugin.Plugin.GetType()).Location;
57-
var dir = Path.GetDirectoryName(location);
58-
if (dir != null)
59-
{
60-
var pluginThemeDirectory = Path.Combine(dir, Folder);
61-
_languageDirectories.Add(pluginThemeDirectory);
62-
}
63-
else
59+
var languageCode = language.LanguageCode;
60+
61+
if (string.Equals(languageCode, twoLetterCode, StringComparison.OrdinalIgnoreCase) ||
62+
string.Equals(languageCode, threeLetterCode, StringComparison.OrdinalIgnoreCase) ||
63+
string.Equals(languageCode, fullName, StringComparison.OrdinalIgnoreCase))
6464
{
65-
API.LogError(ClassName, $"Can't find plugin path <{location}> for <{plugin.Metadata.Name}>");
65+
SystemLanguageCode = languageCode;
6666
}
6767
}
6868

69-
LoadDefaultLanguage();
70-
}
71-
72-
private void LoadDefaultLanguage()
73-
{
74-
// Removes language files loaded before any plugins were loaded.
75-
// Prevents the language Flow started in from overwriting English if the user switches back to English
76-
RemoveOldLanguageFiles();
77-
LoadLanguage(AvailableLanguages.English);
78-
_oldResources.Clear();
69+
SystemLanguageCode = DefaultLanguageCode;
7970
}
8071

8172
/// <summary>
@@ -93,13 +84,64 @@ public async Task InitializeLanguageAsync()
9384
// Get language by language code and change language
9485
var language = GetLanguageByLanguageCode(languageCode);
9586

87+
// Add Flow Launcher language directory
88+
AddFlowLauncherLanguageDirectory();
89+
9690
// Add plugin language directories first so that we can load language files from plugins
9791
AddPluginLanguageDirectories();
9892

93+
// Load default language resources
94+
LoadDefaultLanguage();
95+
9996
// Change language
100-
await ChangeLanguageAsync(language);
97+
await ChangeLanguageAsync(language, false);
10198
}
10299

100+
private void AddFlowLauncherLanguageDirectory()
101+
{
102+
// Check if Flow Launcher language directory exists
103+
var directory = Path.Combine(Constant.ProgramDirectory, Folder);
104+
if (!Directory.Exists(directory))
105+
{
106+
API.LogError(ClassName, $"Flow Launcher language directory can't be found <{directory}>");
107+
return;
108+
}
109+
110+
_languageDirectories.Add(directory);
111+
}
112+
113+
private void AddPluginLanguageDirectories()
114+
{
115+
foreach (var pluginsDir in PluginManager.Directories)
116+
{
117+
if (!Directory.Exists(pluginsDir)) continue;
118+
119+
// Enumerate all top directories in the plugin directory
120+
foreach (var dir in Directory.GetDirectories(pluginsDir))
121+
{
122+
// Check if the directory contains a language folder
123+
var pluginLanguageDir = Path.Combine(dir, Folder);
124+
if (!Directory.Exists(pluginLanguageDir)) continue;
125+
126+
// Check if the language directory contains default language file since it will be checked later
127+
_languageDirectories.Add(pluginLanguageDir);
128+
}
129+
}
130+
}
131+
132+
private void LoadDefaultLanguage()
133+
{
134+
// Removes language files loaded before any plugins were loaded.
135+
// Prevents the language Flow started in from overwriting English if the user switches back to English
136+
RemoveOldLanguageFiles();
137+
LoadLanguage(AvailableLanguages.English);
138+
_oldResources.Clear();
139+
}
140+
141+
#endregion
142+
143+
#region Change Language
144+
103145
/// <summary>
104146
/// Change language during runtime. Will change app language and plugin language & save settings.
105147
/// </summary>
@@ -128,8 +170,8 @@ public void ChangeLanguage(string languageCode)
128170

129171
private static Language GetLanguageByLanguageCode(string languageCode)
130172
{
131-
var lowercase = languageCode.ToLower();
132-
var language = AvailableLanguages.GetAvailableLanguages().FirstOrDefault(o => o.LanguageCode.ToLower() == lowercase);
173+
var language = AvailableLanguages.GetAvailableLanguages().
174+
FirstOrDefault(o => o.LanguageCode.Equals(languageCode, StringComparison.OrdinalIgnoreCase));
133175
if (language == null)
134176
{
135177
API.LogError(ClassName, $"Language code can't be found <{languageCode}>");
@@ -141,7 +183,7 @@ private static Language GetLanguageByLanguageCode(string languageCode)
141183
}
142184
}
143185

144-
private async Task ChangeLanguageAsync(Language language)
186+
private async Task ChangeLanguageAsync(Language language, bool updateMetadata = true)
145187
{
146188
// Remove old language files and load language
147189
RemoveOldLanguageFiles();
@@ -153,8 +195,11 @@ private async Task ChangeLanguageAsync(Language language)
153195
// Change culture info
154196
ChangeCultureInfo(language.LanguageCode);
155197

156-
// Raise event for plugins after culture is set
157-
await Task.Run(UpdatePluginMetadataTranslations);
198+
if (updateMetadata)
199+
{
200+
// Raise event for plugins after culture is set
201+
await Task.Run(UpdatePluginMetadataTranslations);
202+
}
158203
}
159204

160205
public static void ChangeCultureInfo(string languageCode)
@@ -177,6 +222,10 @@ public static void ChangeCultureInfo(string languageCode)
177222
thread.CurrentUICulture = currentCulture;
178223
}
179224

225+
#endregion
226+
227+
#region Language Resources Management
228+
180229
private void RemoveOldLanguageFiles()
181230
{
182231
var dicts = Application.Current.Resources.MergedDictionaries;
@@ -212,6 +261,49 @@ private void LoadLanguage(Language language)
212261
}
213262
}
214263

264+
private static string LanguageFile(string folder, string language)
265+
{
266+
if (Directory.Exists(folder))
267+
{
268+
var path = Path.Combine(folder, language);
269+
if (File.Exists(path))
270+
{
271+
return path;
272+
}
273+
else
274+
{
275+
API.LogError(ClassName, $"Language path can't be found <{path}>");
276+
var english = Path.Combine(folder, DefaultFile);
277+
if (File.Exists(english))
278+
{
279+
return english;
280+
}
281+
else
282+
{
283+
API.LogError(ClassName, $"Default English Language path can't be found <{path}>");
284+
return string.Empty;
285+
}
286+
}
287+
}
288+
else
289+
{
290+
return string.Empty;
291+
}
292+
}
293+
294+
#endregion
295+
296+
#region Available Languages
297+
298+
public List<Language> LoadAvailableLanguages()
299+
{
300+
return AvailableLanguages.GetAvailableLanguages();
301+
}
302+
303+
#endregion
304+
305+
#region Get Translations
306+
215307
public static string GetTranslation(string key)
216308
{
217309
var translation = Application.Current.TryFindResource(key);
@@ -226,7 +318,11 @@ public static string GetTranslation(string key)
226318
}
227319
}
228320

229-
private void UpdatePluginMetadataTranslations()
321+
#endregion
322+
323+
#region Update Metadata
324+
325+
public static void UpdatePluginMetadataTranslations()
230326
{
231327
// Update plugin metadata name & description
232328
foreach (var p in PluginManager.GetTranslationPlugins())
@@ -245,34 +341,6 @@ private void UpdatePluginMetadataTranslations()
245341
}
246342
}
247343

248-
private static string LanguageFile(string folder, string language)
249-
{
250-
if (Directory.Exists(folder))
251-
{
252-
var path = Path.Combine(folder, language);
253-
if (File.Exists(path))
254-
{
255-
return path;
256-
}
257-
else
258-
{
259-
API.LogError(ClassName, $"Language path can't be found <{path}>");
260-
var english = Path.Combine(folder, DefaultFile);
261-
if (File.Exists(english))
262-
{
263-
return english;
264-
}
265-
else
266-
{
267-
API.LogError(ClassName, $"Default English Language path can't be found <{path}>");
268-
return string.Empty;
269-
}
270-
}
271-
}
272-
else
273-
{
274-
return string.Empty;
275-
}
276-
}
344+
#endregion
277345
}
278346
}

Flow.Launcher/App.xaml.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,12 @@
33
using System.Text;
44
using System.Threading.Tasks;
55
using System.Windows;
6-
using System.Windows.Media;
76
using CommunityToolkit.Mvvm.DependencyInjection;
87
using Flow.Launcher.Core.Plugin;
98
using Flow.Launcher.Core.Resource;
109
using Flow.Launcher.Helper;
1110
using Flow.Launcher.Infrastructure;
1211
using Flow.Launcher.Infrastructure.Image;
13-
using Flow.Launcher.Infrastructure.Logger;
1412
using Flow.Launcher.Infrastructure.Storage;
1513
using Flow.Launcher.Infrastructure.UserSettings;
1614
using Flow.Launcher.Plugin;
@@ -168,6 +166,9 @@ await API.StopwatchLogInfoAsync(ClassName, "Startup cost", async () =>
168166
// Enable Win32 dark mode if the system is in dark mode before creating all windows
169167
Win32Helper.EnableWin32DarkMode(_settings.ColorScheme);
170168

169+
// Initialize language before portable clean up since it needs translations
170+
await Ioc.Default.GetRequiredService<Internationalization>().InitializeLanguageAsync();
171+
171172
API.LogInfo(ClassName, "Begin Flow Launcher startup ----------------------------------------------------");
172173
API.LogInfo(ClassName, $"Runtime info:{ErrorReporting.RuntimeInfo()}");
173174

@@ -184,8 +185,8 @@ await API.StopwatchLogInfoAsync(ClassName, "Startup cost", async () =>
184185

185186
await PluginManager.InitializePluginsAsync();
186187

187-
// Change language after all plugins are initialized because we need to update plugin title based on their api
188-
await Ioc.Default.GetRequiredService<Internationalization>().InitializeLanguageAsync();
188+
// Update plugin titles after plugins are initialized with their api instances
189+
Internationalization.UpdatePluginMetadataTranslations();
189190

190191
await imageLoadertask;
191192

0 commit comments

Comments
 (0)