Skip to content

Commit 2d00ab1

Browse files
authored
Merge pull request #4011 from Flow-Launcher/flow_launcher_localization1
Use Flow.Launcher.Localization to improve code quality
2 parents e068104 + ac62eba commit 2d00ab1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+417
-456
lines changed

Flow.Launcher.Core/Configuration/Portable.cs

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@
33
using System.Linq;
44
using System.Reflection;
55
using System.Windows;
6-
using CommunityToolkit.Mvvm.DependencyInjection;
76
using Flow.Launcher.Infrastructure;
87
using Flow.Launcher.Infrastructure.UserSettings;
9-
using Flow.Launcher.Plugin;
108
using Flow.Launcher.Plugin.SharedCommands;
119
using Microsoft.Win32;
1210
using Squirrel;
@@ -17,8 +15,6 @@ public class Portable : IPortable
1715
{
1816
private static readonly string ClassName = nameof(Portable);
1917

20-
private readonly IPublicAPI API = Ioc.Default.GetRequiredService<IPublicAPI>();
21-
2218
/// <summary>
2319
/// As at Squirrel.Windows version 1.5.2, UpdateManager needs to be disposed after finish
2420
/// </summary>
@@ -45,13 +41,13 @@ public void DisablePortableMode()
4541
#endif
4642
IndicateDeletion(DataLocation.PortableDataPath);
4743

48-
API.ShowMsgBox(API.GetTranslation("restartToDisablePortableMode"));
44+
PublicApi.Instance.ShowMsgBox(Localize.restartToDisablePortableMode());
4945

5046
UpdateManager.RestartApp(Constant.ApplicationFileName);
5147
}
5248
catch (Exception e)
5349
{
54-
API.LogException(ClassName, "Error occurred while disabling portable mode", e);
50+
PublicApi.Instance.LogException(ClassName, "Error occurred while disabling portable mode", e);
5551
}
5652
}
5753

@@ -68,13 +64,13 @@ public void EnablePortableMode()
6864
#endif
6965
IndicateDeletion(DataLocation.RoamingDataPath);
7066

71-
API.ShowMsgBox(API.GetTranslation("restartToEnablePortableMode"));
67+
PublicApi.Instance.ShowMsgBox(Localize.restartToEnablePortableMode());
7268

7369
UpdateManager.RestartApp(Constant.ApplicationFileName);
7470
}
7571
catch (Exception e)
7672
{
77-
API.LogException(ClassName, "Error occurred while enabling portable mode", e);
73+
PublicApi.Instance.LogException(ClassName, "Error occurred while enabling portable mode", e);
7874
}
7975
}
8076

@@ -94,13 +90,13 @@ public void RemoveUninstallerEntry()
9490

9591
public void MoveUserDataFolder(string fromLocation, string toLocation)
9692
{
97-
FilesFolders.CopyAll(fromLocation, toLocation, (s) => API.ShowMsgBox(s));
93+
FilesFolders.CopyAll(fromLocation, toLocation, (s) => PublicApi.Instance.ShowMsgBox(s));
9894
VerifyUserDataAfterMove(fromLocation, toLocation);
9995
}
10096

10197
public void VerifyUserDataAfterMove(string fromLocation, string toLocation)
10298
{
103-
FilesFolders.VerifyBothFolderFilesEqual(fromLocation, toLocation, (s) => API.ShowMsgBox(s));
99+
FilesFolders.VerifyBothFolderFilesEqual(fromLocation, toLocation, (s) => PublicApi.Instance.ShowMsgBox(s));
104100
}
105101

106102
public void CreateShortcuts()
@@ -150,12 +146,12 @@ public void PreStartCleanUpAfterPortabilityUpdate()
150146
// delete it and prompt the user to pick the portable data location
151147
if (File.Exists(roamingDataDeleteFilePath))
152148
{
153-
FilesFolders.RemoveFolderIfExists(roamingDataDir, (s) => API.ShowMsgBox(s));
149+
FilesFolders.RemoveFolderIfExists(roamingDataDir, (s) => PublicApi.Instance.ShowMsgBox(s));
154150

155-
if (API.ShowMsgBox(API.GetTranslation("moveToDifferentLocation"),
151+
if (PublicApi.Instance.ShowMsgBox(Localize.moveToDifferentLocation(),
156152
string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.Yes)
157153
{
158-
FilesFolders.OpenPath(Constant.RootDirectory, (s) => API.ShowMsgBox(s));
154+
FilesFolders.OpenPath(Constant.RootDirectory, (s) => PublicApi.Instance.ShowMsgBox(s));
159155

160156
Environment.Exit(0);
161157
}
@@ -164,9 +160,9 @@ public void PreStartCleanUpAfterPortabilityUpdate()
164160
// delete it and notify the user about it.
165161
else if (File.Exists(portableDataDeleteFilePath))
166162
{
167-
FilesFolders.RemoveFolderIfExists(portableDataDir, (s) => API.ShowMsgBox(s));
163+
FilesFolders.RemoveFolderIfExists(portableDataDir, (s) => PublicApi.Instance.ShowMsgBox(s));
168164

169-
API.ShowMsgBox(API.GetTranslation("shortcutsUninstallerCreated"));
165+
PublicApi.Instance.ShowMsgBox(Localize.shortcutsUninstallerCreated());
170166
}
171167
}
172168

@@ -177,8 +173,7 @@ public bool CanUpdatePortability()
177173

178174
if (roamingLocationExists && portableLocationExists)
179175
{
180-
API.ShowMsgBox(string.Format(API.GetTranslation("userDataDuplicated"),
181-
DataLocation.PortableDataPath, DataLocation.RoamingDataPath, Environment.NewLine));
176+
PublicApi.Instance.ShowMsgBox(Localize.userDataDuplicated(DataLocation.PortableDataPath, DataLocation.RoamingDataPath, Environment.NewLine));
182177

183178
return false;
184179
}

Flow.Launcher.Core/ExternalPlugins/CommunityPluginSource.cs

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
using System.Text.Json.Serialization;
99
using System.Threading;
1010
using System.Threading.Tasks;
11-
using CommunityToolkit.Mvvm.DependencyInjection;
1211
using Flow.Launcher.Infrastructure.Http;
1312
using Flow.Launcher.Plugin;
1413

@@ -18,13 +17,9 @@ public record CommunityPluginSource(string ManifestFileUrl)
1817
{
1918
private static readonly string ClassName = nameof(CommunityPluginSource);
2019

21-
// We should not initialize API in static constructor because it will create another API instance
22-
private static IPublicAPI api = null;
23-
private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService<IPublicAPI>();
24-
2520
private string latestEtag = "";
2621

27-
private List<UserPlugin> plugins = new();
22+
private List<UserPlugin> plugins = [];
2823

2924
private static readonly JsonSerializerOptions PluginStoreItemSerializationOption = new()
3025
{
@@ -41,7 +36,7 @@ public record CommunityPluginSource(string ManifestFileUrl)
4136
/// </remarks>
4237
public async Task<List<UserPlugin>> FetchAsync(CancellationToken token)
4338
{
44-
API.LogInfo(ClassName, $"Loading plugins from {ManifestFileUrl}");
39+
PublicApi.Instance.LogInfo(ClassName, $"Loading plugins from {ManifestFileUrl}");
4540

4641
var request = new HttpRequestMessage(HttpMethod.Get, ManifestFileUrl);
4742

@@ -59,40 +54,40 @@ public async Task<List<UserPlugin>> FetchAsync(CancellationToken token)
5954
.ConfigureAwait(false);
6055
latestEtag = response.Headers.ETag?.Tag;
6156

62-
API.LogInfo(ClassName, $"Loaded {plugins.Count} plugins from {ManifestFileUrl}");
57+
PublicApi.Instance.LogInfo(ClassName, $"Loaded {plugins.Count} plugins from {ManifestFileUrl}");
6358
return plugins;
6459
}
6560
else if (response.StatusCode == HttpStatusCode.NotModified)
6661
{
67-
API.LogInfo(ClassName, $"Resource {ManifestFileUrl} has not been modified.");
62+
PublicApi.Instance.LogInfo(ClassName, $"Resource {ManifestFileUrl} has not been modified.");
6863
return plugins;
6964
}
7065
else
7166
{
72-
API.LogWarn(ClassName, $"Failed to load resource {ManifestFileUrl} with response {response.StatusCode}");
67+
PublicApi.Instance.LogWarn(ClassName, $"Failed to load resource {ManifestFileUrl} with response {response.StatusCode}");
7368
return null;
7469
}
7570
}
7671
catch (OperationCanceledException) when (token.IsCancellationRequested)
7772
{
78-
API.LogDebug(ClassName, $"Fetching from {ManifestFileUrl} was cancelled by caller.");
73+
PublicApi.Instance.LogDebug(ClassName, $"Fetching from {ManifestFileUrl} was cancelled by caller.");
7974
return null;
8075
}
8176
catch (TaskCanceledException)
8277
{
8378
// Likely an HttpClient timeout or external cancellation not requested by our token
84-
API.LogWarn(ClassName, $"Fetching from {ManifestFileUrl} timed out.");
79+
PublicApi.Instance.LogWarn(ClassName, $"Fetching from {ManifestFileUrl} timed out.");
8580
return null;
8681
}
8782
catch (Exception e)
8883
{
8984
if (e is HttpRequestException or WebException or SocketException || e.InnerException is TimeoutException)
9085
{
91-
API.LogException(ClassName, $"Check your connection and proxy settings to {ManifestFileUrl}.", e);
86+
PublicApi.Instance.LogException(ClassName, $"Check your connection and proxy settings to {ManifestFileUrl}.", e);
9287
}
9388
else
9489
{
95-
API.LogException(ClassName, "Error Occurred", e);
90+
PublicApi.Instance.LogException(ClassName, "Error Occurred", e);
9691
}
9792
return null;
9893
}

Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using System.Linq;
55
using System.Windows;
66
using System.Windows.Forms;
7-
using CommunityToolkit.Mvvm.DependencyInjection;
87
using Flow.Launcher.Infrastructure.UserSettings;
98
using Flow.Launcher.Plugin;
109
using Flow.Launcher.Plugin.SharedCommands;
@@ -15,7 +14,7 @@ public abstract class AbstractPluginEnvironment
1514
{
1615
private static readonly string ClassName = nameof(AbstractPluginEnvironment);
1716

18-
protected readonly IPublicAPI API = Ioc.Default.GetRequiredService<IPublicAPI>();
17+
protected readonly IPublicAPI API = PublicApi.Instance;
1918

2019
internal abstract string Language { get; }
2120

@@ -58,15 +57,10 @@ internal IEnumerable<PluginPair> Setup()
5857
return SetPathForPluginPairs(PluginsSettingsFilePath, Language);
5958
}
6059

61-
var noRuntimeMessage = string.Format(
62-
API.GetTranslation("runtimePluginInstalledChooseRuntimePrompt"),
63-
Language,
64-
EnvName,
65-
Environment.NewLine
66-
);
60+
var noRuntimeMessage = Localize.runtimePluginInstalledChooseRuntimePrompt(Language, EnvName, Environment.NewLine);
6761
if (API.ShowMsgBox(noRuntimeMessage, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.No)
6862
{
69-
var msg = string.Format(API.GetTranslation("runtimePluginChooseRuntimeExecutable"), EnvName);
63+
var msg = Localize.runtimePluginChooseRuntimeExecutable(EnvName);
7064

7165
var selectedFile = GetFileFromDialog(msg, FileDialogFilter);
7266

@@ -77,12 +71,7 @@ internal IEnumerable<PluginPair> Setup()
7771
// Nothing selected because user pressed cancel from the file dialog window
7872
else
7973
{
80-
var forceDownloadMessage = string.Format(
81-
API.GetTranslation("runtimeExecutableInvalidChooseDownload"),
82-
Language,
83-
EnvName,
84-
Environment.NewLine
85-
);
74+
var forceDownloadMessage = Localize.runtimeExecutableInvalidChooseDownload(Language, EnvName, Environment.NewLine);
8675

8776
// Let users select valid path or choose to download
8877
while (string.IsNullOrEmpty(selectedFile))
@@ -120,7 +109,7 @@ internal IEnumerable<PluginPair> Setup()
120109
}
121110
else
122111
{
123-
API.ShowMsgBox(string.Format(API.GetTranslation("runtimePluginUnableToSetExecutablePath"), Language));
112+
API.ShowMsgBox(Localize.runtimePluginUnableToSetExecutablePath(Language));
124113
API.LogError(ClassName,
125114
$"Not able to successfully set {EnvName} path, setting's plugin executable path variable is still an empty string.",
126115
$"{Language}Environment");
@@ -248,7 +237,7 @@ private static bool IsUsingRoamingPath(string filePath)
248237
private static string GetUpdatedEnvironmentPath(string filePath)
249238
{
250239
var index = filePath.IndexOf(DataLocation.PluginEnvironments);
251-
240+
252241
// get the substring after "Environments" because we can not determine it dynamically
253242
var executablePathSubstring = filePath[(index + DataLocation.PluginEnvironments.Length)..];
254243
return $"{DataLocation.PluginEnvironmentsPath}{executablePathSubstring}";

Flow.Launcher.Core/ExternalPlugins/Environments/PythonEnvironment.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ internal override void InstallEnvironment()
5151
}
5252
catch (System.Exception e)
5353
{
54-
API.ShowMsgError(API.GetTranslation("failToInstallPythonEnv"));
54+
API.ShowMsgError(Localize.failToInstallPythonEnv());
5555
API.LogException(ClassName, "Failed to install Python environment", e);
5656
}
5757
});

Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptEnvironment.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ internal override void InstallEnvironment()
4646
}
4747
catch (System.Exception e)
4848
{
49-
API.ShowMsgError(API.GetTranslation("failToInstallTypeScriptEnv"));
49+
API.ShowMsgError(Localize.failToInstallTypeScriptEnv());
5050
API.LogException(ClassName, "Failed to install TypeScript environment", e);
5151
}
5252
});

Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptV2Environment.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ internal override void InstallEnvironment()
4646
}
4747
catch (System.Exception e)
4848
{
49-
API.ShowMsgError(API.GetTranslation("failToInstallTypeScriptEnv"));
49+
API.ShowMsgError(Localize.failToInstallTypeScriptEnv());
5050
API.LogException(ClassName, "Failed to install TypeScript environment", e);
5151
}
5252
});

Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using System.Collections.Generic;
33
using System.Threading;
44
using System.Threading.Tasks;
5-
using CommunityToolkit.Mvvm.DependencyInjection;
65
using Flow.Launcher.Plugin;
76
using Flow.Launcher.Infrastructure;
87

@@ -23,10 +22,6 @@ public static class PluginsManifest
2322
private static DateTime lastFetchedAt = DateTime.MinValue;
2423
private static readonly TimeSpan fetchTimeout = TimeSpan.FromMinutes(2);
2524

26-
// We should not initialize API in static constructor because it will create another API instance
27-
private static IPublicAPI api = null;
28-
private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService<IPublicAPI>();
29-
3025
public static List<UserPlugin> UserPlugins { get; private set; }
3126

3227
public static async Task<bool> UpdateManifestAsync(bool usePrimaryUrlOnly = false, CancellationToken token = default)
@@ -61,7 +56,7 @@ public static async Task<bool> UpdateManifestAsync(bool usePrimaryUrlOnly = fals
6156
}
6257
catch (Exception e)
6358
{
64-
API.LogException(ClassName, "Http request failed", e);
59+
PublicApi.Instance.LogException(ClassName, "Http request failed", e);
6560
}
6661
finally
6762
{
@@ -83,12 +78,12 @@ private static bool IsMinimumAppVersionSatisfied(UserPlugin plugin, SemanticVers
8378
}
8479
catch (Exception e)
8580
{
86-
API.LogException(ClassName, $"Failed to parse the minimum app version {plugin.MinimumAppVersion} for plugin {plugin.Name}. "
81+
PublicApi.Instance.LogException(ClassName, $"Failed to parse the minimum app version {plugin.MinimumAppVersion} for plugin {plugin.Name}. "
8782
+ "Plugin excluded from manifest", e);
8883
return false;
8984
}
9085

91-
API.LogInfo(ClassName, $"Plugin {plugin.Name} requires minimum Flow Launcher version {plugin.MinimumAppVersion}, "
86+
PublicApi.Instance.LogInfo(ClassName, $"Plugin {plugin.Name} requires minimum Flow Launcher version {plugin.MinimumAppVersion}, "
9287
+ $"but current version is {Constant.Version}. Plugin excluded from manifest.");
9388

9489
return false;

Flow.Launcher.Core/Flow.Launcher.Core.csproj

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<TargetFramework>net9.0-windows</TargetFramework>
@@ -34,6 +34,7 @@
3434
<ErrorReport>prompt</ErrorReport>
3535
<WarningLevel>4</WarningLevel>
3636
<Prefer32Bit>false</Prefer32Bit>
37+
<NoWarn>$(NoWarn);FLSG0007</NoWarn>
3738
</PropertyGroup>
3839

3940
<ItemGroup>
@@ -55,13 +56,25 @@
5556

5657
<ItemGroup>
5758
<PackageReference Include="Droplex" Version="1.7.0" />
59+
<PackageReference Include="Flow.Launcher.Localization" Version="0.0.6" />
5860
<PackageReference Include="FSharp.Core" Version="9.0.303" />
5961
<PackageReference Include="Meziantou.Framework.Win32.Jobs" Version="3.4.4" />
6062
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
6163
<PackageReference Include="SemanticVersioning" Version="3.0.0" />
6264
<PackageReference Include="squirrel.windows" Version="1.5.2" NoWarn="NU1701" />
6365
<PackageReference Include="StreamJsonRpc" Version="2.22.11" />
6466
</ItemGroup>
67+
68+
<PropertyGroup>
69+
<FLLUseDependencyInjection>true</FLLUseDependencyInjection>
70+
</PropertyGroup>
71+
72+
<ItemGroup>
73+
<AdditionalFiles Remove="Languages\en.xaml" />
74+
<AdditionalFiles Include="..\Flow.Launcher\Languages\en.xaml">
75+
<Link>Languages\en.xaml</Link>
76+
</AdditionalFiles>
77+
</ItemGroup>
6578

6679
<ItemGroup>
6780
<ProjectReference Include="..\Flow.Launcher.Infrastructure\Flow.Launcher.Infrastructure.csproj" />

Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ public Control CreateSettingPanel()
285285
HorizontalAlignment = HorizontalAlignment.Left,
286286
VerticalAlignment = VerticalAlignment.Center,
287287
Margin = SettingPanelItemLeftMargin,
288-
Content = API.GetTranslation("select")
288+
Content = Localize.select()
289289
};
290290

291291
Btn.Click += (_, _) =>

0 commit comments

Comments
 (0)