|
1 |
| -Localization toolkit is for Flow C# plugin developers to improve their localization experience. |
| 1 | +The Localization Toolkit helps Flow Launcher C# plugin developers make the localization process easier. |
2 | 2 |
|
3 |
| -## Initialization |
| 3 | +## Getting Started |
4 | 4 |
|
5 |
| -For C# Plugins, we need to install and reference [Flow.Launcher.Localization](www.nuget.org/packages/Flow.Launcher.Localization) by Nuget. |
| 5 | +For C# plugins, install and reference [Flow.Launcher.Localization](www.nuget.org/packages/Flow.Launcher.Localization) via NuGet. |
6 | 6 |
|
7 |
| -## Build properties |
| 7 | +## Build Properties |
| 8 | + |
| 9 | +These are properties you can configure in your `.csproj` file to customize the localization process. You can set them in the `<PropertyGroup>` section. For example, to set the `FLLUseDependencyInjection` property to `true`, add the following lines: |
| 10 | + |
| 11 | +```xml |
| 12 | +<PropertyGroup> |
| 13 | + <FLLUseDependencyInjection>true</FLLUseDependencyInjection> |
| 14 | +</PropertyGroup> |
| 15 | +``` |
8 | 16 |
|
9 | 17 | ### `FLLUseDependencyInjection`
|
10 | 18 |
|
11 |
| -Whether to use dependency injection to get `IPublicAPI` instance. Default by false. |
12 |
| -If set to `false`, the `Main` class that implements **[IPlugin](/API-Reference/Flow.Launcher.Plugin/IPlugin.md)** or **[IAsyncPlugin](/API-Reference/Flow.Launcher.Plugin/IAsyncPlugin.md)** must have a [PluginInitContext](/API-Reference/Flow.Launcher.Plugin/PluginInitContext.md) property which must be at least `internal static`. |
| 19 | +This flag specifies whether to use dependency injection to obtain an IPublicAPI instance. The default is `false`. |
| 20 | +- If set to `false`, the Main class (which must implement **[IPlugin](/API-Reference/Flow.Launcher.Plugin/IPlugin.md)** or **[IAsyncPlugin](/API-Reference/Flow.Launcher.Plugin/IAsyncPlugin.md)**) |
| 21 | + must have a [PluginInitContext](/API-Reference/Flow.Launcher.Plugin/PluginInitContext.md) property that is at least `internal static`. |
| 22 | +- If set to `true`, you can access the `IPublicAPI` instance via `PublicApi.Instance` using dependency injection, and the Main class does not need to include a [PluginInitContext](/API-Reference/Flow.Launcher.Plugin/PluginInitContext.md) property. |
| 23 | + (Note: This approach is not recommended for plugin projects at the moment since it limits compatibility to Flow Launcher 1.20.0 or later.) |
13 | 24 |
|
14 |
| -If set to `true`, we can access `IPublicAPI` instance from `PublicApi.Instance` in the project by dependency injection. |
15 |
| -And the `Main` class does not need to have a [PluginInitContext](/API-Reference/Flow.Launcher.Plugin/PluginInitContext.md) property. |
16 |
| -(Not recommended for plugin projects because this will make plugins only compatible with Flow 1.20.0 or higher) |
17 | 25 | ## Usage
|
18 | 26 |
|
19 |
| -### Main class |
| 27 | +### Main Class |
20 | 28 |
|
21 |
| -`Main` class must implement [IPluginI18n](/API-Reference/Flow.Launcher.Plugin/IPluginI18n.md). |
| 29 | +The Main class must implement [IPluginI18n](/API-Reference/Flow.Launcher.Plugin/IPluginI18n.md). |
22 | 30 |
|
23 |
| -If `FLLUseDependencyInjection` is set to `false`, `Main` class must have a [PluginInitContext](/API-Reference/Flow.Launcher.Plugin/PluginInitContext.md) property like: |
| 31 | +If `FLLUseDependencyInjection` is `false`, include a [PluginInitContext](/API-Reference/Flow.Launcher.Plugin/PluginInitContext.md) property, for example: |
24 | 32 |
|
25 |
| -``` |
26 |
| -public class Main : IPlugin, IPluginI18n // Must implement IPluginI18n |
| 33 | +```csharp |
| 34 | + // Must implement IPluginI18n |
| 35 | +public class Main : IPlugin, IPluginI18n |
27 | 36 | {
|
28 |
| - internal static PluginInitContext Context { get; private set; } = null!; // At least internal static property |
29 |
| - private static IPublicAPI API => Context.API; |
30 |
| -
|
31 |
| - ... |
| 37 | + // Must be at least internal static |
| 38 | + internal static PluginInitContext Context { get; private set; } = null!; |
32 | 39 | }
|
33 | 40 | ```
|
34 | 41 |
|
35 |
| -### Localized strings |
| 42 | +### Localized Strings |
| 43 | + |
| 44 | +You can simplify your code by replacing calls like: |
| 45 | +```csharp |
| 46 | +Context.API.GetTranslation("flowlauncher_plugin_localization_demo_plugin_name") |
| 47 | +``` |
| 48 | +with: |
| 49 | +```csharp |
| 50 | +Localize.flowlauncher_plugin_localization_demo_plugin_name() |
| 51 | +``` |
36 | 52 |
|
37 |
| -With this toolkit, we can replace `Context.API.GetTranslation("flowlauncher_plugin_localization_demo_plugin_name")` with `Localize.flowlauncher_plugin_localization_demo_plugin_name()`. |
| 53 | +If your localization string uses variables, it becomes even simpler! From this: |
| 54 | +```csharp |
| 55 | +string.Format(Context.API.GetTranslation("flowlauncher_plugin_localization_demo_value_with_keys"), firstName, lastName); |
| 56 | +``` |
| 57 | +To this: |
| 58 | +```csharp |
| 59 | +Localize.flowlauncher_plugin_localization_demo_value_with_keys(firstName, lastName); |
| 60 | +``` |
38 | 61 |
|
39 |
| -And we can also replace `string.Format(Context.API.GetTranslation("flowlauncher_plugin_localization_demo_plugin_used"), string.Empty, null, string.Empty)` with `Localize.flowlauncher_plugin_localization_demo_plugin_used(string.Empty, null, string.Empty)`. |
| 62 | +### Localized Enums |
40 | 63 |
|
41 |
| -### Localized enums |
| 64 | +For enum types (e.g., DemoEnum) that need localization in UI controls such as combo boxes, use the `EnumLocalize` attribute to enable localization. For each enum field: |
| 65 | +- Use `EnumLocalizeKey` to provide a custom localization key. |
| 66 | +- Use `EnumLocalizeValue` to provide a constant localization string. |
42 | 67 |
|
43 |
| -If you have enum types like `DemoEnum` that needs localization in displaying them on a combo box control. You can add `EnumLocalize` attribute to enable localization support. |
44 |
| -For all fields in this `EnumType`, if you want to specific one localization key for this field, you can use `EnumLocalizeKey` attribute; or if you want to specific one constant value for this field, you can use `EnumLocalizeValue` attribute. |
| 68 | +Example: |
45 | 69 |
|
46 |
| -``` |
| 70 | +```csharp |
47 | 71 | [EnumLocalize] // Enable localization support
|
48 | 72 | public enum DemoEnum
|
49 | 73 | {
|
50 |
| - [EnumLocalizeKey("localize_key_1")] // Specific localization key |
| 74 | + // Specific localization key |
| 75 | + [EnumLocalizeKey("localize_key_1")] |
51 | 76 | Value1,
|
52 | 77 |
|
53 |
| - [EnumLocalizeValue("localize_value_2")] // Specific localization value |
| 78 | + // Specific localization value |
| 79 | + [EnumLocalizeValue("This is my enum value localization")] |
54 | 80 | Value2,
|
55 | 81 |
|
56 |
| - [EnumLocalizeKey("localize_key_3")] // If key and value both exist, will prefer localization key |
57 |
| - [EnumLocalizeValue("localize_value_3")] |
| 82 | + // Key takes precedence if both are present |
| 83 | + [EnumLocalizeKey("localize_key_3")] |
| 84 | + [EnumLocalizeValue("Localization Value")] |
58 | 85 | Value3,
|
59 | 86 |
|
60 |
| - [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_localization_demo_plugin_description))] // Use Localize class |
| 87 | + // Using the Localize class. This way, you can't misspell localization keys, and if you rename |
| 88 | + // them in your .xaml file, you won't forget to rename them here as well because the build will fail. |
| 89 | + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_localization_demo_plugin_description))] |
61 | 90 | Value4,
|
62 | 91 | }
|
63 | 92 | ```
|
64 | 93 |
|
65 |
| -Then you can get `DemoEnumData` class. |
| 94 | +Then, use the generated DemoEnumData class within your view model to bind to a combo box: |
66 | 95 |
|
67 |
| -In view model class which needs to display it on a combo box control, you can add two fields for binding `ItemSource` and `SelectedValue` like: |
| 96 | +```csharp |
| 97 | +// ComboBox ItemSource |
| 98 | +public List<DemoEnumData> AllDemoEnums { get; } = DemoEnumData.GetValues(); |
68 | 99 |
|
| 100 | +// ComboBox SelectedValue |
| 101 | +public DemoEnum SelectedDemoEnum { get; set; } |
69 | 102 | ```
|
70 |
| -public List<DemoEnumData> AllDemoEnums { get; } = DemoEnumData.GetValues(); // ItemSource of ComboBox |
71 | 103 |
|
72 |
| -public DemoEnum SelectedDemoEnum { get; set; } // SelectedValue of ComboBox |
73 |
| -``` |
| 104 | +In your XAML, bind as follows: |
74 | 105 |
|
75 |
| -``` |
| 106 | +```xml |
76 | 107 | <ComboBox
|
77 | 108 | DisplayMemberPath="Display"
|
78 | 109 | ItemsSource="{Binding AllDemoEnums}"
|
79 | 110 | SelectedValue="{Binding SelectedDemoEnum}"
|
80 | 111 | SelectedValuePath="Value" />
|
81 | 112 | ```
|
82 | 113 |
|
83 |
| -If you want to update localization strings when culture info changes, you can call this function to update. |
| 114 | +To update localization strings when the language changes, you can call: |
84 | 115 |
|
85 |
| -``` |
86 |
| -private void UpdateEnumDropdownLocalizations() |
87 |
| -{ |
88 |
| - DemoEnumData.UpdateLabels(AllDemoEnums); |
89 |
| -} |
| 116 | +```csharp |
| 117 | +DemoEnumData.UpdateLabels(AllDemoEnums); |
90 | 118 | ```
|
0 commit comments