3
3
using System . Globalization ;
4
4
using System . IO ;
5
5
using System . Linq ;
6
- using System . Reflection ;
7
6
using System . Threading ;
8
7
using System . Threading . Tasks ;
9
8
using System . Windows ;
@@ -28,54 +27,46 @@ public class Internationalization
28
27
private const string DefaultFile = "en.xaml" ;
29
28
private const string Extension = ".xaml" ;
30
29
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 = [ ] ;
33
32
private static string SystemLanguageCode ;
34
33
35
34
public Internationalization ( Settings settings )
36
35
{
37
36
_settings = settings ;
38
- AddFlowLauncherLanguageDirectory ( ) ;
39
37
}
40
38
41
- private void AddFlowLauncherLanguageDirectory ( )
42
- {
43
- var directory = Path . Combine ( Constant . ProgramDirectory , Folder ) ;
44
- _languageDirectories . Add ( directory ) ;
45
- }
39
+ #region Initialization
46
40
41
+ /// <summary>
42
+ /// Initialize the system language code based on the current culture.
43
+ /// </summary>
47
44
public static void InitSystemLanguageCode ( )
48
45
{
49
- SystemLanguageCode = DefaultLanguageCode ;
50
- }
46
+ var availableLanguages = AvailableLanguages . GetAvailableLanguages ( ) ;
51
47
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 )
55
58
{
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 ) )
64
64
{
65
- API . LogError ( ClassName , $ "Can't find plugin path < { location } > for < { plugin . Metadata . Name } >" ) ;
65
+ SystemLanguageCode = languageCode ;
66
66
}
67
67
}
68
68
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 ;
79
70
}
80
71
81
72
/// <summary>
@@ -93,13 +84,64 @@ public async Task InitializeLanguageAsync()
93
84
// Get language by language code and change language
94
85
var language = GetLanguageByLanguageCode ( languageCode ) ;
95
86
87
+ // Add Flow Launcher language directory
88
+ AddFlowLauncherLanguageDirectory ( ) ;
89
+
96
90
// Add plugin language directories first so that we can load language files from plugins
97
91
AddPluginLanguageDirectories ( ) ;
98
92
93
+ // Load default language resources
94
+ LoadDefaultLanguage ( ) ;
95
+
99
96
// Change language
100
- await ChangeLanguageAsync ( language ) ;
97
+ await ChangeLanguageAsync ( language , false ) ;
101
98
}
102
99
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
+
103
145
/// <summary>
104
146
/// Change language during runtime. Will change app language and plugin language & save settings.
105
147
/// </summary>
@@ -128,8 +170,8 @@ public void ChangeLanguage(string languageCode)
128
170
129
171
private static Language GetLanguageByLanguageCode ( string languageCode )
130
172
{
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 ) ) ;
133
175
if ( language == null )
134
176
{
135
177
API . LogError ( ClassName , $ "Language code can't be found <{ languageCode } >") ;
@@ -141,7 +183,7 @@ private static Language GetLanguageByLanguageCode(string languageCode)
141
183
}
142
184
}
143
185
144
- private async Task ChangeLanguageAsync ( Language language )
186
+ private async Task ChangeLanguageAsync ( Language language , bool updateMetadata = true )
145
187
{
146
188
// Remove old language files and load language
147
189
RemoveOldLanguageFiles ( ) ;
@@ -153,8 +195,11 @@ private async Task ChangeLanguageAsync(Language language)
153
195
// Change culture info
154
196
ChangeCultureInfo ( language . LanguageCode ) ;
155
197
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
+ }
158
203
}
159
204
160
205
public static void ChangeCultureInfo ( string languageCode )
@@ -177,6 +222,10 @@ public static void ChangeCultureInfo(string languageCode)
177
222
thread . CurrentUICulture = currentCulture ;
178
223
}
179
224
225
+ #endregion
226
+
227
+ #region Language Resources Management
228
+
180
229
private void RemoveOldLanguageFiles ( )
181
230
{
182
231
var dicts = Application . Current . Resources . MergedDictionaries ;
@@ -212,6 +261,49 @@ private void LoadLanguage(Language language)
212
261
}
213
262
}
214
263
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
+
215
307
public static string GetTranslation ( string key )
216
308
{
217
309
var translation = Application . Current . TryFindResource ( key ) ;
@@ -226,7 +318,11 @@ public static string GetTranslation(string key)
226
318
}
227
319
}
228
320
229
- private void UpdatePluginMetadataTranslations ( )
321
+ #endregion
322
+
323
+ #region Update Metadata
324
+
325
+ public static void UpdatePluginMetadataTranslations ( )
230
326
{
231
327
// Update plugin metadata name & description
232
328
foreach ( var p in PluginManager . GetTranslationPlugins ( ) )
@@ -245,34 +341,6 @@ private void UpdatePluginMetadataTranslations()
245
341
}
246
342
}
247
343
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
277
345
}
278
346
}
0 commit comments