Skip to content

Support enum localization with EnumSourceGenerator & Support internal static PublicAPI instance with PublicApiSourceGenerator& Improve TabString performance #33

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Apr 5, 2025

Conversation

Jack251970
Copy link
Collaborator

@Jack251970 Jack251970 commented Apr 3, 2025

Important

I have thoroughly tested the EnumSourceGenerator and PublicApiSourceGenerator and I believe them are ready to move to production.

Support enum localization with EnumSourceGenerator

Enum localization solution is from https://github.com/Flow-Launcher/Flow.Launcher/blob/dev/Flow.Launcher/SettingPages/ViewModels/DropdownDataGeneric.cs.

If we have files with this enum declarition:

[EnumLocalize] // Enable localization support
public enum DemoEnum
{
    [EnumLocalizeKey("localize_key_1")] // Specific localization key
    Value1,

    [EnumLocalizeValue("localize_value_2")] // Specific localization value
    Value2,

    [EnumLocalizeKey("localize_key_3")] // If key and value both exist, will prefer localization key
    [EnumLocalizeValue("localize_value_3")]
    Value3,

    [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_localization_demo_plugin_description))] // Use Localize class
    Value4,
}

Generator will generate outputs as follows.

If we set FLLUseDependencyInjection to false,

/// <auto-generated>
/// From: Flow.Launcher.Plugin.Localization.DemoEnum
/// </auto-generated>

using System.Collections.Generic;

namespace Flow.Launcher.Plugin.Localization;

/// <summary>
/// Data class for <see cref="Flow.Launcher.Plugin.Localization.DemoEnum"/>
/// </summary>
[System.CodeDom.Compiler.GeneratedCode("EnumSourceGenerator", "0.2.17.0")]
public class DemoEnumData
{
    /// <summary>
    /// The value of the enum
    /// </summary>
    public DemoEnum Value { get; private init; }

    /// <summary>
    /// The display text of the enum value
    /// </summary>
    public string Display { get; set; }

    /// <summary>
    /// The localization key of the enum value
    /// </summary>
    public string LocalizationKey { get; set; }

    /// <summary>
    /// The localization value of the enum value
    /// </summary>
    public string LocalizationValue { get; set; }

    /// <summary>
    /// Get all values of <see cref="Flow.Launcher.Plugin.Localization.DemoEnum"/>
    /// </summary>
    public static List<DemoEnumData> GetValues()
    {
        return new List<DemoEnumData>
        {
            new()
            {
                Value = DemoEnum.Value1,
                Display = Flow.Launcher.Plugin.Localization.Main.Context.API.GetTranslation("localize_key_1"),
                LocalizationKey = "localize_key_1",
            },
            new()
            {
                Value = DemoEnum.Value2,
                Display = "localize_value_2",
                LocalizationValue = "localize_value_2",
            },
            new()
            {
                Value = DemoEnum.Value3,
                Display = Flow.Launcher.Plugin.Localization.Main.Context.API.GetTranslation("localize_key_3"),
                LocalizationKey = "localize_key_3",
                LocalizationValue = "localize_value_3",
            },
        };
    }

    /// <summary>
    /// Update the labels of the enum values when culture info changes.
    /// See <see cref="Flow.Launcher.Plugin.PluginInitContext.CultureInfoChanged"/> for more details
    /// </summary>
    public static void UpdateLabels(List<DemoEnumData> options)
    {
        foreach (var item in options)
        {
            if (!string.IsNullOrWhiteSpace(item.LocalizationKey))
            {
                item.Display = Flow.Launcher.Plugin.Localization.Main.Context.API.GetTranslation(item.LocalizationKey);
            }
        }
    }
}

Else If we set FLLUseDependencyInjection to true,

/// <auto-generated>
/// From: Flow.Launcher.Plugin.Localization.DemoEnum
/// </auto-generated>

using System.Collections.Generic;

namespace Flow.Launcher.Plugin.Localization;

/// <summary>
/// Data class for <see cref="Flow.Launcher.Plugin.Localization.DemoEnum"/>
/// </summary>
[System.CodeDom.Compiler.GeneratedCode("EnumSourceGenerator", "0.2.18.0")]
public class DemoEnumData
{
    /// <summary>
    /// The value of the enum
    /// </summary>
    public DemoEnum Value { get; private init; }

    /// <summary>
    /// The display text of the enum value
    /// </summary>
    public string Display { get; set; }

    /// <summary>
    /// The localization key of the enum value
    /// </summary>
    public string LocalizationKey { get; set; }

    /// <summary>
    /// The localization value of the enum value
    /// </summary>
    public string LocalizationValue { get; set; }

    /// <summary>
    /// Get all values of <see cref="Flow.Launcher.Plugin.Localization.DemoEnum"/>
    /// </summary>
    public static List<DemoEnumData> GetValues()
    {
        return new List<DemoEnumData>
        {
            new()
            {
                Value = DemoEnum.Value1,
                Display = Flow.Launcher.Plugin.Localization.PublicApi.Instance.GetTranslation("localize_key_1"),
                LocalizationKey = "localize_key_1",
            },
            new()
            {
                Value = DemoEnum.Value2,
                Display = "localize_value_2",
                LocalizationValue = "localize_value_2",
            },
            new()
            {
                Value = DemoEnum.Value3,
                Display = Flow.Launcher.Plugin.Localization.PublicApi.Instance.GetTranslation("localize_key_3"),
                LocalizationKey = "localize_key_3",
                LocalizationValue = "localize_value_3",
            },
        };
    }

    /// <summary>
    /// Update the labels of the enum values when culture info changes.
    /// See <see cref="Flow.Launcher.Plugin.PluginInitContext.CultureInfoChanged"/> for more details
    /// </summary>
    public static void UpdateLabels(List<DemoEnumData> options)
    {
        foreach (var item in options)
        {
            if (!string.IsNullOrWhiteSpace(item.LocalizationKey))
            {
                item.Display = Flow.Launcher.Plugin.Localization.PublicApi.Instance.GetTranslation(item.LocalizationKey);
            }
        }
    }
}

Then, in view model, you can get ItemSource and SelectedValue like this:

/// <summary>
/// This is ItemSource of ComboBox.
/// </summary>
public List<DemoEnumData> DemoEnums { get; } = DemoEnumData.GetValues();

/// <summary>
/// This is SelectedValue of ComboBox.
/// </summary>
public DemoEnum DemoEnum { get; set; }

/// <summary>
/// Update localization of Enum dropdown when culture info changes.
/// See <see cref="PluginInitContext.CultureInfoChanged"/> for more details.
/// </summary>
private void UpdateEnumDropdownLocalizations()
{
    DemoEnumData.UpdateLabels(DemoEnums);
}

In page, you can bind them like this:

<ComboBox
    DisplayMemberPath="Display"
    ItemsSource="{Binding DemoEnums}"
    SelectedValue="{Binding DemoEnum}"
    SelectedValuePath="Value" />

Test

  • Source files are generated as above.
  • Diagnosis work correctly.
image

Support Internal static PublicAPI instance with PublicApiSourceGenerator

When enabling FLLUseDependencyInjection, we will get IPublicAPI instance from Ioc.Default. We can put it in internal field for Localize class and enum data classes to use.

Test

Will generate file like this:

/// <auto-generated/>

#nullable enable

namespace Flow.Launcher.Plugin.Localization;

[System.CodeDom.Compiler.GeneratedCode("PublicApiSourceGenerator", "0.2.18.0")]
internal static class PublicApi
{
    private static Flow.Launcher.Plugin.IPublicAPI? instance = null;

    /// <summary>
    /// Get <see cref="Flow.Launcher.Plugin.IPublicAPI"> instance
    /// </summary>
    internal static Flow.Launcher.Plugin.IPublicAPI Instance => instance ??= CommunityToolkit.Mvvm.DependencyInjection.Ioc.Default.GetRequiredService<Flow.Launcher.Plugin.IPublicAPI>();
}

And Localize class is like this:

/// <auto-generated>
/// From: D:\Source\Repos\Flow.Launcher.Plugin.LocalizationDemo\Languages\en.xaml
/// </auto-generated>

#nullable enable

namespace Flow.Launcher.Plugin.Localization;

[System.CodeDom.Compiler.GeneratedCode("LocalizeSourceGenerator", "0.2.18.0")]
public static class Localize
{
    /// <remarks>
    /// e.g.: <code>
    /// Localization
    /// </code>
    /// </remarks>
    public static string flowlauncher_plugin_localization_demo_plugin_name() => Flow.Launcher.Plugin.Localization.PublicApi.Instance.GetTranslation("flowlauncher_plugin_localization_demo_plugin_name");

    /// <remarks>
    /// e.g.: <code>
    /// Demo for Flow.Launcher.Localization
    /// </code>
    /// </remarks>
    public static string flowlauncher_plugin_localization_demo_plugin_description() => Flow.Launcher.Plugin.Localization.PublicApi.Instance.GetTranslation("flowlauncher_plugin_localization_demo_plugin_description");

    /// <summary>
    /// Used format string without culture info
    /// </summary>
    /// <remarks>
    /// e.g.: <code>
    /// This is an unused string with parameters {2,-35} and {0:D}!!
    /// </code>
    /// </remarks>
    public static string flowlauncher_plugin_localization_demo_plugin_used(object value0, string value1, object? arg2) => string.Format(System.Globalization.CultureInfo.CurrentCulture, Flow.Launcher.Plugin.Localization.PublicApi.Instance.GetTranslation("flowlauncher_plugin_localization_demo_plugin_used"), value0, value1, arg2);

    /// <summary>
    /// Unused format string with culture info
    /// </summary>
    /// <remarks>
    /// e.g.: <code>
    /// This is an unused string with parameters {2:00}, {1,-35:D} and {0}!!
    /// </code>
    /// </remarks>
    public static string flowlauncher_plugin_localization_demo_plugin_unused(object value0, string value1, object? arg2) => string.Format(System.Globalization.CultureInfo.CurrentCulture, Flow.Launcher.Plugin.Localization.PublicApi.Instance.GetTranslation("flowlauncher_plugin_localization_demo_plugin_unused"), value0, value1, arg2);
}

And enum data classes are shown as above.

@Jack251970 Jack251970 changed the title Support enum localization Support enum localization with EnumSourceGenerator Apr 3, 2025
@Jack251970 Jack251970 changed the title Support enum localization with EnumSourceGenerator Support enum localization with EnumSourceGenerator & Internal static PublicAPI instance Apr 3, 2025
@Jack251970 Jack251970 changed the title Support enum localization with EnumSourceGenerator & Internal static PublicAPI instance Support enum localization with EnumSourceGenerator & Internal static PublicAPI instance with PublicApiSourceGenerator Apr 3, 2025
@Jack251970 Jack251970 changed the title Support enum localization with EnumSourceGenerator & Internal static PublicAPI instance with PublicApiSourceGenerator Support enum localization with EnumSourceGenerator & Support internal static PublicAPI instance with PublicApiSourceGenerator Apr 3, 2025
@Jack251970 Jack251970 requested a review from Copilot April 3, 2025 12:20
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces support for enum localization using a new EnumSourceGenerator and adds support for an internal static PublicAPI instance via PublicApiSourceGenerator. It includes new source generators that automatically generate code for enum data classes and plugin API access when dependency injection is enabled, along with corresponding diagnostics and helper modifications.

Reviewed Changes

Copilot reviewed 11 out of 15 changed files in this pull request and generated no comments.

Show a summary per file
File Description
Flow.Launcher.Localization.SourceGenerators/SourceGeneratorDiagnostics.cs Added diagnostic FLSG0008 for invalid enum localization key/value.
Flow.Launcher.Localization.SourceGenerators/PluginInfoHelper.cs Refactored plugin information handling and reporting diagnostics.
Flow.Launcher.Localization.SourceGenerators/Localize/PublicApiSourceGenerator.cs Implements a source generator for creating an internal static PublicApi instance.
Flow.Launcher.Localization.SourceGenerators/Localize/LocalizeSourceGenerator.cs Updated to use dependency injection and renamed assembly variable for consistency.
Flow.Launcher.Localization.SourceGenerators/Localize/EnumSourceGenerator.cs Introduced enum localization code generation, including enum data classes and update methods.
Flow.Launcher.Localization.Shared/Helper.cs Added a Spacing helper method for consistent code formatting.
Flow.Launcher.Localization.Shared/Constants.cs Added new constant definitions for enum localization and PublicApi source generation.
Flow.Launcher.Localization.Attributes/* Added attributes for marking enum localization keys/values and enums for localization.
Flow.Launcher.Localization.SourceGenerators/AnalyzerReleases.Unshipped.md Documented new diagnostic FLSG0008.
Files not reviewed (4)
  • Flow.Launcher.Localization.Attributes/Flow.Launcher.Localization.Attributes.csproj: Language not supported
  • Flow.Launcher.Localization.SourceGenerators/Flow.Launcher.Localization.SourceGenerators.csproj: Language not supported
  • Flow.Launcher.Localization.slnx: Language not supported
  • Flow.Launcher.Localization/Flow.Launcher.Localization.csproj: Language not supported
Comments suppressed due to low confidence (1)

Flow.Launcher.Localization.SourceGenerators/Localize/EnumSourceGenerator.cs:337

  • [nitpick] Consider updating the condition for UseLocalizationKey to use !string.IsNullOrWhiteSpace(LocalizationKey) instead of a null check, to ensure that an empty string does not mistakenly indicate a valid localization key.
public bool UseLocalizationKey => LocalizationKey != null;

@Jack251970 Jack251970 requested a review from Yusyuriv April 3, 2025 12:29
@Jack251970 Jack251970 marked this pull request as ready for review April 3, 2025 12:32
Copy link
Contributor

coderabbitai bot commented Apr 3, 2025

📝 Walkthrough

Walkthrough

The pull request introduces a suite of new localization components. Several attribute classes for enums and enum fields (for keys and values) have been added along with a dedicated project file for these attributes. Additionally, new constants and helper methods support localization functionality. Multiple source generators have been implemented or modified to generate enum data classes, validate plugin information, and produce a public API, with updates to diagnostic rules and project references included.

Changes

File(s) Change Summary
Flow.Launcher.Localization.Attributes/EnumLocalizeAttribute.cs, EnumLocalizeKeyAttribute.cs, EnumLocalizeValueAttribute.cs New attribute classes for marking enums and enum fields for localization (including key and value attributes).
Flow.Launcher.Localization.Attributes/…/Flow.Launcher.Localization.Attributes.csproj New project file for the localization attributes targeting netstandard2.0.
Flow.Launcher.Localization.Shared/Constants.cs Added constants for localization attribute names, class suffixes, and public API naming.
Flow.Launcher.Localization.Shared/Helper.cs Added Spacing(int n) method and updated using directives.
Flow.Launcher.Localization.SourceGenerators/Localize/EnumSourceGenerator.cs, …/Localize/LocalizeSourceGenerator.cs, …/Localize/PublicApiSourceGenerator.cs, …/PluginInfoHelper.cs, …/SourceGeneratorDiagnostics.cs Introduced/modified source generators for enum localization and public API generation; updated assembly version; added diagnostics for invalid enum localization keys/values and plugin validation logic.
Flow.Launcher.Localization.SourceGenerators/AnalyzerReleases.Unshipped.md Added a new localization analyzer warning rule (FLSG0008) for invalid enum field localization keys/values.
Flow.Launcher.Localization.slnx Added a new project entry for the localization attributes project.
Flow.Launcher.Localization/Flow.Launcher.Localization.csproj Updated project dependency settings, added a reference to the localization attributes project, and included the attributes DLL for runtime.

Sequence Diagram(s)

sequenceDiagram
    participant Compiler
    participant ESG as EnumSourceGenerator
    participant Attr as Attribute Checker
    participant CodeGen as Source Generator
    Compiler->>ESG: Provide enum declarations
    ESG->>Attr: Filter enums with localization attributes
    Attr-->>ESG: Return valid enum fields
    ESG->>CodeGen: Generate enum data classes & methods
    CodeGen-->>Compiler: Submit generated source code
Loading
sequenceDiagram
    participant Compiler
    participant PASG as PublicApiSourceGenerator
    participant PluginHelper as PluginInfoHelper
    Compiler->>PASG: Supply compilation context
    alt Dependency Injection Enabled
        PASG->>PluginHelper: Bypass plugin validation
    else
        PASG->>PluginHelper: Validate plugin info
        PluginHelper-->>PASG: Return valid info or diagnostics
    end
    PASG->>Compiler: Generate public API source code
Loading

Possibly related PRs

  • Replace strings with constants & Improve code quality #22: The changes in the main PR, which introduce new localization attributes, are related to the retrieved PR as both involve modifications to the Constants class in the Flow.Launcher.Localization.Shared namespace, specifically adding new constants relevant to localization.

Suggested labels

enhancement

Suggested reviewers

  • Yusyuriv

Poem

Hopping through the lines of code so neat,
I found new attributes along my beat.
Enum keys and values now form a merry row,
Source generators make the magic flow.
My bunny heart skips with every clever byte,
Coding carrots lead me through the night! 🥕


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d7a8a2b and 169a4b5.

📒 Files selected for processing (1)
  • Flow.Launcher.Localization.Shared/Constants.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • Flow.Launcher.Localization.Shared/Constants.cs
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: gitStream.cm
  • GitHub Check: build

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🔭 Outside diff range comments (1)
Flow.Launcher.Localization.SourceGenerators/Flow.Launcher.Localization.SourceGenerators.csproj (1)

19-21: ⚠️ Potential issue

Missing reference to the new Attributes project.

According to the PR summary, this project should reference the newly created Flow.Launcher.Localization.Attributes project, but the reference is missing.

<ItemGroup>
  <ProjectReference Include="..\Flow.Launcher.Localization.Shared\Flow.Launcher.Localization.Shared.csproj" />
+  <ProjectReference Include="..\Flow.Launcher.Localization.Attributes\Flow.Launcher.Localization.Attributes.csproj" />
</ItemGroup>

The source generators need access to the attribute classes to properly identify and process decorated enums.

🧹 Nitpick comments (5)
Flow.Launcher.Localization.Shared/Helper.cs (1)

89-101: Consider simplifying the Spacing method implementation.

While the current implementation works, it's unnecessarily complex. The method allocates a fixed-size character span, fills it with spaces, then copies the characters to a StringBuilder.

public static string Spacing(int n)
{
-    Span<char> spaces = stackalloc char[n * 4];
-    spaces.Fill(' ');
-
-    var sb = new StringBuilder(n * 4);
-    foreach (var c in spaces)
-    {
-        _ = sb.Append(c);
-    }
-
-    return sb.ToString();
+    return new string(' ', n * 4);
}

The simplified version is more readable, performs better, and achieves the same result with less code.

Flow.Launcher.Localization.SourceGenerators/Localize/PublicApiSourceGenerator.cs (2)

10-17: Consider making the PackageVersion access more resilient.

While the current implementation works, direct access to Assembly.GetName().Version can occasionally fail in certain build configurations.

-private static readonly Version PackageVersion = typeof(PublicApiSourceGenerator).Assembly.GetName().Version;
+private static readonly Version PackageVersion = typeof(PublicApiSourceGenerator).Assembly.GetName().Version ?? new Version(1, 0, 0, 0);

99-102: Consider adding more comprehensive header information.

The current header only includes the auto-generated marker. For consistency with other generators, consider adding more context similar to how GeneratedHeaderFromPath is implemented in LocalizeSourceGenerator.

-private static void GeneratedHeaderFromPath(StringBuilder sb)
-{
-    sb.AppendLine("/// <auto-generated/>");
-}
+private static void GeneratedHeaderFromPath(StringBuilder sb)
+{
+    sb.AppendLine("/// <auto-generated>")
+       .AppendLine($"/// Generated by {nameof(PublicApiSourceGenerator)}")
+       .AppendLine("/// </auto-generated>");
+}
Flow.Launcher.Localization.Shared/Constants.cs (2)

23-26: Introduce a small grouping or comment for EnumLocalize* constants.

These newly added constants for enum localization (EnumLocalizeClassSuffix, EnumLocalizeAttributeName, EnumLocalizeKeyAttributeName, EnumLocalizeValueAttributeName) are straightforward and aligned with the existing naming conventions. Consider grouping them under a short region or adding a summarizing comment to make their collective purpose clearer.


27-30: Fix the spelling in the inline comment for PublicApi constants.

Line 27 contains the word "combiguity," which seems to be a misspelling of "ambiguity." A quick fix will improve readability.

Apply this diff to ensure clarity:

-        // Use PublicApi instead of PublicAPI for possible combiguity with Flow.Launcher.Plugin.IPublicAPI
+        // Use PublicApi instead of PublicAPI to avoid ambiguity with Flow.Launcher.Plugin.IPublicAPI
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 24712e5 and c55d88d.

📒 Files selected for processing (15)
  • Flow.Launcher.Localization.Attributes/EnumLocalizeAttribute.cs (1 hunks)
  • Flow.Launcher.Localization.Attributes/EnumLocalizeKeyAttribute.cs (1 hunks)
  • Flow.Launcher.Localization.Attributes/EnumLocalizeValueAttribute.cs (1 hunks)
  • Flow.Launcher.Localization.Attributes/Flow.Launcher.Localization.Attributes.csproj (1 hunks)
  • Flow.Launcher.Localization.Shared/Constants.cs (1 hunks)
  • Flow.Launcher.Localization.Shared/Helper.cs (2 hunks)
  • Flow.Launcher.Localization.SourceGenerators/AnalyzerReleases.Unshipped.md (1 hunks)
  • Flow.Launcher.Localization.SourceGenerators/Flow.Launcher.Localization.SourceGenerators.csproj (1 hunks)
  • Flow.Launcher.Localization.SourceGenerators/Localize/EnumSourceGenerator.cs (1 hunks)
  • Flow.Launcher.Localization.SourceGenerators/Localize/LocalizeSourceGenerator.cs (5 hunks)
  • Flow.Launcher.Localization.SourceGenerators/Localize/PublicApiSourceGenerator.cs (1 hunks)
  • Flow.Launcher.Localization.SourceGenerators/PluginInfoHelper.cs (1 hunks)
  • Flow.Launcher.Localization.SourceGenerators/SourceGeneratorDiagnostics.cs (1 hunks)
  • Flow.Launcher.Localization.slnx (1 hunks)
  • Flow.Launcher.Localization/Flow.Launcher.Localization.csproj (3 hunks)
🧰 Additional context used
🧬 Code Definitions (5)
Flow.Launcher.Localization.SourceGenerators/PluginInfoHelper.cs (2)
Flow.Launcher.Localization.SourceGenerators/Localize/LocalizeSourceGenerator.cs (1)
  • ImmutableArray (133-204)
Flow.Launcher.Localization.SourceGenerators/Localize/EnumSourceGenerator.cs (1)
  • ImmutableArray (109-161)
Flow.Launcher.Localization.Attributes/EnumLocalizeValueAttribute.cs (2)
Flow.Launcher.Localization.Attributes/EnumLocalizeAttribute.cs (1)
  • AttributeUsage (8-11)
Flow.Launcher.Localization.Attributes/EnumLocalizeKeyAttribute.cs (4)
  • AttributeUsage (8-32)
  • Equals (26-27)
  • GetHashCode (29-29)
  • IsDefaultAttribute (31-31)
Flow.Launcher.Localization.SourceGenerators/Localize/PublicApiSourceGenerator.cs (3)
Flow.Launcher.Localization.SourceGenerators/Localize/EnumSourceGenerator.cs (3)
  • Generator (14-355)
  • Initialize (31-54)
  • Execute (61-103)
Flow.Launcher.Localization.SourceGenerators/Localize/LocalizeSourceGenerator.cs (3)
  • Generator (19-641)
  • Initialize (37-69)
  • Execute (76-127)
Flow.Launcher.Localization.Shared/Constants.cs (1)
  • Constants (5-34)
Flow.Launcher.Localization.SourceGenerators/Localize/LocalizeSourceGenerator.cs (4)
Flow.Launcher.Localization.Shared/Constants.cs (1)
  • Constants (5-34)
Flow.Launcher.Localization.Shared/Helper.cs (3)
  • GetFLLUseDependencyInjection (16-24)
  • PluginClassInfo (34-61)
  • Helper (12-104)
Flow.Launcher.Localization.SourceGenerators/PluginInfoHelper.cs (2)
  • PluginClassInfo (10-78)
  • PluginInfoHelper (8-79)
Flow.Launcher.Localization.Shared/Classes.cs (2)
  • PluginClassInfo (5-28)
  • PluginClassInfo (18-27)
Flow.Launcher.Localization.SourceGenerators/Localize/EnumSourceGenerator.cs (4)
Flow.Launcher.Localization.Shared/Helper.cs (5)
  • Helper (12-104)
  • PluginClassInfo (34-61)
  • GetFLLUseDependencyInjection (16-24)
  • Location (75-78)
  • Location (80-83)
Flow.Launcher.Localization.SourceGenerators/PluginInfoHelper.cs (2)
  • PluginClassInfo (10-78)
  • PluginInfoHelper (8-79)
Flow.Launcher.Localization.Shared/Constants.cs (1)
  • Constants (5-34)
Flow.Launcher.Localization.SourceGenerators/SourceGeneratorDiagnostics.cs (1)
  • SourceGeneratorDiagnostics (6-79)
🔇 Additional comments (28)
Flow.Launcher.Localization.Attributes/Flow.Launcher.Localization.Attributes.csproj (1)

1-8: LGTM! The new project file is well-structured.

The project file is correctly configured with appropriate target framework and namespace settings for attribute classes.

Flow.Launcher.Localization.slnx (1)

3-3: LGTM! Appropriate integration of the new project.

The new Attributes project is correctly included in the solution file, maintaining consistency with the existing project structure.

Flow.Launcher.Localization.Shared/Helper.cs (1)

1-4: LGTM! Adding necessary namespace imports.

The added namespace imports support the new functionality in the Helper class.

Flow.Launcher.Localization.SourceGenerators/Flow.Launcher.Localization.SourceGenerators.csproj (1)

7-8: LGTM! Proper version management.

Adding the AssemblyVersion property is a good practice for package versioning.

Flow.Launcher.Localization.Attributes/EnumLocalizeAttribute.cs (1)

5-11: Well-designed attribute implementation.

This attribute is correctly implemented as a marker attribute for enum localization. The AttributeUsage constraint properly restricts it to enum targets only, and the XML documentation clearly explains its purpose.

Flow.Launcher.Localization.SourceGenerators/AnalyzerReleases.Unshipped.md (1)

14-14: Appropriate addition to unshipped analyzer rules.

The new rule FLSG0008 follows the existing pattern and naming convention. It's properly categorized as a localization warning for invalid enum field localization key/value pairs.

Flow.Launcher.Localization.SourceGenerators/SourceGeneratorDiagnostics.cs (1)

71-78: Diagnostic descriptor correctly implemented.

The new diagnostic descriptor follows the same pattern as existing ones. The message format, severity level, and category are appropriate for reporting issues with enum field localization.

Flow.Launcher.Localization/Flow.Launcher.Localization.csproj (3)

9-9: Verify the implications of changing DevelopmentDependency to false.

Changing DevelopmentDependency from true to false means this package will be included as a regular dependency rather than a development-only dependency. Ensure this is intentional, as it affects how this package is treated by downstream projects.


36-38: Reference to new Attributes project correctly added.

Adding a reference to the Attributes project with IncludeAssets set to "runtime" ensures that the attributes will be available at runtime, which is necessary for reflection-based operations on these attributes.


53-57: Appropriate packaging configuration for the Attributes library.

Including the Attributes DLL in the lib folder is appropriate since these attributes need to be referenced by consuming projects at compile time and runtime. The Visible property is correctly set to true to make the assembly visible to projects that consume this package.

Flow.Launcher.Localization.SourceGenerators/PluginInfoHelper.cs (1)

8-79: Well-structured validation logic with good separation of concerns.

This helper class nicely encapsulates the plugin validation logic that was likely previously contained in the LocalizeSourceGenerator. The implementation follows a clear flow of validation steps with appropriate diagnostics reported at each stage.

Flow.Launcher.Localization.Attributes/EnumLocalizeKeyAttribute.cs (1)

5-32: Clean attribute implementation with proper equality and default handling.

The attribute design follows best practices by:

  1. Specifying the correct AttributeUsage target
  2. Providing a default instance
  3. Implementing proper value-based equality
  4. Overriding GetHashCode consistently
  5. Implementing IsDefaultAttribute

The protected property pattern allows for potential extension while maintaining encapsulation.

Flow.Launcher.Localization.SourceGenerators/Localize/PublicApiSourceGenerator.cs (3)

25-34: LGTM! Clean initialization with proper incremental generator setup.

The initialization method correctly sets up the dependencies required for the source generator.


41-54: Appropriate early exit pattern when dependency injection is disabled.

The logic cleanly handles the dependency injection check and exits early when not needed, preventing unnecessary code generation.


60-97: Ensure null safety when retrieving the IPublicAPI service.

While the source generator's produced code uses the null-coalescing assignment operator (??=), it doesn't handle the case where GetRequiredService throws an exception if the service isn't registered.

Consider verifying that your DI container documentation confirms that GetRequiredService throws an appropriate exception with a helpful message when the requested service isn't registered.

Flow.Launcher.Localization.SourceGenerators/Localize/LocalizeSourceGenerator.cs (4)

100-100: Improved naming for better clarity.

Renaming from assemblyName to assemblyNamespace provides better semantics, reflecting that the value represents a namespace rather than just an assembly name.


103-117: Clean conditional handling of plugin validation based on DI status.

This change properly delegates plugin validation to the new PluginInfoHelper class and conditionally bypasses validation when using dependency injection, improving separation of concerns.


507-507: Good refactor to use the shared Helper.Spacing method.

Moving the spacing functionality to a shared helper improves code reuse across the codebase.


513-514: Proper integration with the PublicApiSourceGenerator.

This code correctly uses the PublicApi class generated by the PublicApiSourceGenerator when dependency injection is enabled, creating a well-designed coupling between the two generators.

Flow.Launcher.Localization.Attributes/EnumLocalizeValueAttribute.cs (1)

1-33: Attribute implementation looks solid.

This new attribute class mirrors the structure and logic of EnumLocalizeKeyAttribute with default instances, constructors, and equality overrides. It provides a clear and concise approach for marking localization values on enum fields. No correctness or security concerns stand out, and the usage of IsDefaultAttribute() is consistent with best practices.

Flow.Launcher.Localization.SourceGenerators/Localize/EnumSourceGenerator.cs (8)

31-54: Efficient incremental generation approach in Initialize.

The creation of syntax providers for enums and plugin classes is well-structured. The combination of these providers, along with config options and the compilation, is a clean approach to collecting relevant data for source generation. Good job leveraging incremental APIs here.


61-103: Cohesive logic in Execute method for orchestrating generation.

You:

  • Validate whether dependency injection is enabled.
  • Retrieve valid plugin info if DI is disabled.
  • Filter out any enums not tagged with EnumLocalizeAttribute.
  • Tidy approach for conditionally generating sources.

Everything appears well-organized with proper diagnostic reporting for missing plugin info. No issues found.


109-161: Robust field extraction in GetEnumFields.

The method cleanly identifies enum fields and gathers both key and value attributes. The fallback logic (reporting a diagnostic when neither key nor value is provided) is a nice fail-safe. Returning _emptyEnumFields on errors to prevent partial class generation is logical.


167-264: Comprehensive source generation in GenerateSource.

The method:

  1. Builds a data class for each localizable enum using StringBuilder.
  2. Properly includes properties for the enum’s value, display text, localization key, and localization value.
  3. Generates a GetValues method reflecting all enum fields and calls GetEnumFields to ensure only valid fields are included.
  4. Seamlessly injects references to either PublicApi.Instance.GetTranslation or PluginInitContext based on DI usage.

The approach is well-encapsulated and maintains separation of concerns. Good use of the StringBuilder to form the final output.


266-279: Header generation method GeneratedHeaderFromPath.

Produces a coherent autogeneration header, referencing the enum’s fully qualified name. Straightforward and helpful for debugging. Looks good as-is.


280-304: Concise GenerateEnumField method with minimal duplication.

The generation logic for each enum field is concise, properly distinguishing between key-based translations and direct localization values. Nicely handles the scenario when only a value is provided.


306-327: Effective label refresh logic in GenerateUpdateLabelsMethod.

The loop checks for non-whitespace keys and reissues translations accordingly. This allows dynamic updates when locale or culture changes, which is crucial for a good user experience.


333-352: EnumField class usage is well-structured.

Holds essential metadata for an enum member, with clear property definitions. The UseLocalizationKey logic is intuitive, and the constructors handle both key-based and value-only fields neatly. No concerns here.

@Jack251970 Jack251970 changed the title Support enum localization with EnumSourceGenerator & Support internal static PublicAPI instance with PublicApiSourceGenerator Support enum localization with EnumSourceGenerator & Support internal static PublicAPI instance with PublicApiSourceGenerator& Improve TabString performance Apr 4, 2025
@Jack251970 Jack251970 requested a review from Copilot April 4, 2025 01:32
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 11 out of 15 changed files in this pull request and generated no comments.

Files not reviewed (4)
  • Flow.Launcher.Localization.Attributes/Flow.Launcher.Localization.Attributes.csproj: Language not supported
  • Flow.Launcher.Localization.SourceGenerators/Flow.Launcher.Localization.SourceGenerators.csproj: Language not supported
  • Flow.Launcher.Localization.slnx: Language not supported
  • Flow.Launcher.Localization/Flow.Launcher.Localization.csproj: Language not supported

@Jack251970 Jack251970 requested a review from Copilot April 4, 2025 01:45
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 11 out of 15 changed files in this pull request and generated 2 comments.

Files not reviewed (4)
  • Flow.Launcher.Localization.Attributes/Flow.Launcher.Localization.Attributes.csproj: Language not supported
  • Flow.Launcher.Localization.SourceGenerators/Flow.Launcher.Localization.SourceGenerators.csproj: Language not supported
  • Flow.Launcher.Localization.slnx: Language not supported
  • Flow.Launcher.Localization/Flow.Launcher.Localization.csproj: Language not supported

Co-authored-by: Copilot <[email protected]>
@Yusyuriv
Copy link
Member

Yusyuriv commented Apr 4, 2025

Can it be used with nameof()? So instead of [EnumLocalizeKey("localize_key_1")] you could do something like [EnumLocalizeKey(nameof(Localize.localize_key_1))]?

@Jack251970
Copy link
Collaborator Author

Can it be used with nameof()? So instead of [EnumLocalizeKey("localize_key_1")] you could do something like [EnumLocalizeKey(nameof(Localize.localize_key_1))]?

Yes, we can do that. Tested as follows:

image image

@Jack251970 Jack251970 merged commit ffb4829 into main Apr 5, 2025
2 checks passed
@Jack251970 Jack251970 deleted the enum_localization branch April 5, 2025 05:19
@Jack251970 Jack251970 added the enhancement New feature or request label Apr 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants