Skip to content

feat(plugin-i18n): registerGlobalOptionResources extension - #343

Merged
kazupon merged 4 commits into
mainfrom
fix/global-options-i18n
Oct 18, 2025
Merged

feat(plugin-i18n): registerGlobalOptionResources extension#343
kazupon merged 4 commits into
mainfrom
fix/global-options-i18n

Conversation

@kazupon

@kazupon kazupon commented Oct 18, 2025

Copy link
Copy Markdown
Owner

Description

Linked Issues

Additional context

Summary by CodeRabbit

  • New Features

    • i18n plugin: register localization resources for global options (registerGlobalOptionResources).
  • Documentation

    • README and plugin guidelines updated to document global option resources and expanded package naming examples.
  • Tests

    • Coverage extended to validate registering and resolving global option translations.
  • Chores

    • JSDoc and type-signature clarifications; workspace/config and development dependency listings updated.

@coderabbitai

coderabbitai Bot commented Oct 18, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds a global-option localization mechanism to the i18n plugin (registering per-option locale resources), exposes registerGlobalOptionResources in the plugin API, updates resource mapping/loading to include global options, tightens a shared utility type, updates docs/tests/devDependencies/config, and makes a minor JSDoc wording edit.

Changes

Cohort / File(s) Summary
I18n plugin core
packages/plugin-i18n/src/index.ts
Added COMMON_ARGS import; introduced globalOptionResources storage; implemented registerGlobalOptionResources and getGlobalOptions; updated mapResourceWithBuiltinKey and loadResource to merge global-option resources and built-ins; exposed registerGlobalOptionResources from the extension.
I18n typings
packages/plugin-i18n/src/types.ts
Added registerGlobalOptionResources(option: string, resources: Record<string,string>): void to I18nExtension.
I18n tests
packages/plugin-i18n/src/index.test.ts
Added imports/exposure for plugin id/types; added tests for registerGlobalOptionResources; removed some previous assertions for built-in keys; extended test scaffolding for a debug global option.
I18n README
packages/plugin-i18n/README.md
Documented new registerGlobalOptionResources extension method in Available extensions list.
Shared utilities
packages/shared/src/utils.ts
Narrowed resolveBuiltInKey generic default from `CommandBuiltinArgsKeys
Dev deps / config
packages/plugin-i18n/package.json, knip.config.ts
Added devDependencies: @gunshi/bone, @gunshi/plugin-global, @gunshi/plugin-renderer; added packages/plugin-i18n workspace entry and ignore rule for @gunshi/plugin-global.
Docs guidance
packages/docs/src/guide/plugin/guidelines.md
Expanded scoped package naming guidance to allow an additional form and added examples.
JSDoc wording
packages/gunshi/src/types.ts
Minor JSDoc wording edits for log parameters (no functional change).

Sequence Diagram(s)

sequenceDiagram
    participant App as Application
    participant I18n as i18n Plugin
    participant Adapter as Adapter/Resource Store

    App->>I18n: initialize extension(ctx)
    I18n->>I18n: derive builtinGlobalOptions ← COMMON_ARGS
    I18n->>I18n: register built-in global option resources
    I18n-->>App: extension exposed (includes registerGlobalOptionResources)

    Note right of App: At runtime
    App->>I18n: loadResource(locale)
    I18n->>Adapter: request base resources
    Adapter-->>I18n: base resources

    alt global option resources exist
        I18n->>I18n: collect per-option resources for locale
        I18n->>Adapter: merge option-specific locale strings into resources
    end

    I18n-->>App: merged resources returned
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I hopped through keys and stitched each tongue,

I learned the locales so flags can be sung.
Options now whisper in each chosen land,
I left little carrots where translators stand.
🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "feat(plugin-i18n): registerGlobalOptionResources extension" directly corresponds to the primary changes in the changeset. The core of this PR implements a new registerGlobalOptionResources extension method across multiple files: it's added to the I18nExtension interface (types.ts), implemented in the plugin (index.ts), documented in the README, and tested with a new test suite (index.test.ts). The title is concise, specific, and clearly identifies the main feature being introduced. Secondary changes like JSDoc updates, type narrowing, and configuration adjustments are supporting changes for this primary feature.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/global-options-i18n

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new

pkg-pr-new Bot commented Oct 18, 2025

Copy link
Copy Markdown

Open in StackBlitz

@gunshi/bone

npm i https://pkg.pr.new/@gunshi/bone@343

@gunshi/definition

npm i https://pkg.pr.new/@gunshi/definition@343

gunshi

npm i https://pkg.pr.new/gunshi@343

@gunshi/plugin

npm i https://pkg.pr.new/@gunshi/plugin@343

@gunshi/plugin-completion

npm i https://pkg.pr.new/@gunshi/plugin-completion@343

@gunshi/plugin-dryrun

npm i https://pkg.pr.new/@gunshi/plugin-dryrun@343

@gunshi/plugin-global

npm i https://pkg.pr.new/@gunshi/plugin-global@343

@gunshi/plugin-i18n

npm i https://pkg.pr.new/@gunshi/plugin-i18n@343

@gunshi/plugin-renderer

npm i https://pkg.pr.new/@gunshi/plugin-renderer@343

@gunshi/resources

npm i https://pkg.pr.new/@gunshi/resources@343

@gunshi/shared

npm i https://pkg.pr.new/@gunshi/shared@343

commit: d287334

@kazupon kazupon added the feature Includes new features label Oct 18, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/plugin-i18n/src/index.ts (1)

294-303: Consider renaming function for clarity.

The function now conditionally maps keys based on whether they are global options (using resolveArgKey) or built-in resources (using resolveBuiltInKey). The current name mapResourceWithBuiltinKey is misleading since it doesn't exclusively map built-in keys anymore.

Consider renaming to better reflect its dual purpose:

-function mapResourceWithBuiltinKey(
+function mapResourceKeys(
   resource: Record<string, string>,
   ctx: CommandContext,
   globalOptions: string[]
 ): Record<string, string> {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 158f049 and 623f164.

⛔ Files ignored due to path filters (6)
  • e2e/fixture/advanced/internationalization/loading/english-help.snap is excluded by !**/*.snap
  • e2e/fixture/advanced/internationalization/loading/japanese-help.snap is excluded by !**/*.snap
  • e2e/fixture/advanced/internationalization/sub-command/english-create-help.snap is excluded by !**/*.snap
  • e2e/fixture/advanced/internationalization/sub-command/english-help.snap is excluded by !**/*.snap
  • e2e/fixture/advanced/internationalization/sub-command/japanese-create-help.snap is excluded by !**/*.snap
  • e2e/fixture/advanced/internationalization/sub-command/japanese-help.snap is excluded by !**/*.snap
📒 Files selected for processing (6)
  • packages/gunshi/src/types.ts (1 hunks)
  • packages/plugin-i18n/README.md (1 hunks)
  • packages/plugin-i18n/src/index.test.ts (0 hunks)
  • packages/plugin-i18n/src/index.ts (6 hunks)
  • packages/plugin-i18n/src/types.ts (1 hunks)
  • packages/shared/src/utils.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • packages/plugin-i18n/src/index.test.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Use ES modules throughout the codebase
Follow existing code style (enforced by ESLint and Prettier)

Files:

  • packages/plugin-i18n/src/types.ts
  • packages/plugin-i18n/src/index.ts
  • packages/gunshi/src/types.ts
  • packages/shared/src/utils.ts
packages/gunshi/src/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

packages/gunshi/src/**/*.ts: All source code is in TypeScript with strict mode enabled
Type safety is a core feature - maintain strict TypeScript types throughout

Files:

  • packages/gunshi/src/types.ts
🧬 Code graph analysis (2)
packages/plugin-i18n/src/index.ts (5)
packages/gunshi/src/plugin/core.ts (1)
  • plugin (390-436)
packages/shared/src/utils.ts (2)
  • resolveArgKey (52-57)
  • resolveBuiltInKey (34-38)
packages/shared/src/constants.ts (1)
  • COMMON_ARGS (33-44)
packages/gunshi/src/types.ts (1)
  • CommandContext (361-451)
packages/gunshi/src/plugin/context.ts (1)
  • globalOptions (168-170)
packages/shared/src/utils.ts (2)
packages/plugin-i18n/src/index.ts (1)
  • resolveBuiltInKey (62-62)
packages/shared/src/types.ts (2)
  • CommandBuiltinResourceKeys (68-68)
  • GenerateNamespacedKey (55-58)
🪛 LanguageTool
packages/plugin-i18n/README.md

[grammar] ~343-~343: Ensure spelling is correct
Context: ...tion, you can install resource of it at exntesion or onExtension hook ## 📝 Resource K...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test on Node.js 20
🔇 Additional comments (9)
packages/plugin-i18n/src/types.ts (1)

83-89: LGTM! Clear public API extension for global option resources.

The new registerGlobalOptionResources method extends the I18nExtension interface to support registering locale-specific resources for global options. The signature is well-defined, and the documentation clearly explains its purpose.

packages/plugin-i18n/src/index.ts (7)

40-40: LGTM! Import required for global option resources.

The COMMON_ARGS import is necessary for setting up built-in global option resources (help and version options).


104-104: LGTM! Appropriate data structure for global option resources.

The globalOptionResources map stores locale-specific resources for each global option, which is accessed and managed by the helper functions below.


163-167: LGTM! Updated resource mapping to handle global options.

The setResource function now passes the list of global options to mapResourceWithBuiltinKey, enabling conditional key resolution based on whether a key represents a global option (using resolveArgKey) or a built-in resource (using resolveBuiltInKey).


212-219: LGTM! Global option resources are correctly augmented during resource loading.

The logic iterates through registered global options and injects locale-specific resources, falling back to built-in resources if a locale-specific value is not available. This ensures that global options are properly localized for each command.


230-231: LGTM! Correctly exposes the new API method.

The extension now returns registerGlobalOptionResources, making it available to consumers via ctx.extensions['g:i18n'].registerGlobalOptionResources.


111-124: Verification confirmed: async extension factories are supported.

The plugin system explicitly awaits extension factories (line 231 in core.test.ts: await extension.factory(...)), and the type system confirms they return Promises (using Awaited<ReturnType<...>> patterns at lines 350, 419-420, 496). The changes in packages/plugin-i18n/src/index.ts are compatible with the plugin architecture.


169-187: DefaultResource contains all COMMON_ARGS keys—no issues found.

Verification confirms that DefaultResource (from packages/resources/locales/en-US.json) contains both help and version keys that correspond to COMMON_ARGS. Both built-in locale resources (en-US and ja-JP) include these keys, so accessing them at line 176 is safe.

The cast (DefaultResource as Record<string, string>)[globalOption] will not produce undefined values for the built-in resources.

packages/shared/src/utils.ts (1)

34-36: Type constraint narrowing is correct and verified across all call sites.

The default generic parameter has been narrowed from CommandBuiltinArgsKeys | CommandBuiltinResourceKeys to CommandBuiltinResourceKeys. This change is correct:

  • All direct call sites use resource key literals (test files, plugin-renderer)
  • The critical usage in plugin-i18n conditionally routes args keys through resolveArgKey() instead, ensuring only resource keys reach resolveBuiltInKey()
  • CommandBuiltinArgsKeys is not imported in utils.ts and only exists in the union type definition
  • The constraint accurately reflects the function's actual semantic purpose

No breaking changes detected in the codebase.

Comment thread packages/gunshi/src/types.ts
Comment thread packages/plugin-i18n/README.md Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 623f164 and 0cdaa1d.

⛔ Files ignored due to path filters (2)
  • packages/gunshi/src/__snapshots__/cli.test.ts.snap is excluded by !**/*.snap
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (6)
  • knip.config.ts (1 hunks)
  • packages/docs/src/guide/plugin/guidelines.md (1 hunks)
  • packages/plugin-i18n/README.md (1 hunks)
  • packages/plugin-i18n/package.json (1 hunks)
  • packages/plugin-i18n/src/index.test.ts (3 hunks)
  • packages/plugin-i18n/src/index.ts (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/plugin-i18n/README.md
  • packages/plugin-i18n/src/index.test.ts
🧰 Additional context used
📓 Path-based instructions (1)
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Use ES modules throughout the codebase
Follow existing code style (enforced by ESLint and Prettier)

Files:

  • knip.config.ts
  • packages/plugin-i18n/src/index.ts
🧬 Code graph analysis (1)
packages/plugin-i18n/src/index.ts (4)
packages/shared/src/constants.ts (1)
  • COMMON_ARGS (33-44)
packages/shared/src/utils.ts (2)
  • resolveArgKey (52-57)
  • resolveBuiltInKey (34-38)
packages/gunshi/src/types.ts (1)
  • CommandContext (361-451)
packages/gunshi/src/plugin/context.ts (1)
  • globalOptions (168-170)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test on Node.js 20
🔇 Additional comments (10)
packages/docs/src/guide/plugin/guidelines.md (1)

59-60: Inconsistent example in scoped package naming patterns.

The example @feature/gunshi/plugin on line 60 does not match the documented scoped package formats. According to the patterns defined on line 59:

  • @{org}/gunshi-plugin-{feature} → would match @feature/gunshi-plugin
  • @{org}/gunshi-plugin → would match @feature/gunshi-plugin

The provided example uses a different pattern (/gunshi/plugin with a slash instead of hyphen), which deviates from the naming conventions being described.

Please clarify whether:

  1. @feature/gunshi/plugin is an intentional undocumented format and should be added to the patterns list, or
  2. The example should be corrected to match one of the documented patterns (e.g., @feature/gunshi-plugin)
knip.config.ts (1)

15-17: LGTM! Appropriate handling of optional peer dependency.

The ignoreDependencies rule correctly prevents Knip from flagging @gunshi/plugin-global as unused. This is appropriate since it's an optional peer dependency used in development/testing.

packages/plugin-i18n/package.json (1)

74-76: LGTM! DevDependencies correctly added for testing.

The three devDependencies are appropriately added to support testing the new global option resources functionality:

  • @gunshi/bone and @gunshi/plugin-renderer provide test infrastructure
  • @gunshi/plugin-global follows the standard pattern of adding an optional peer dependency as a devDependency to ensure it's available during testing

All use the correct workspace:* protocol and maintain alphabetical ordering.

packages/plugin-i18n/src/index.ts (7)

40-40: LGTM!

The import of COMMON_ARGS is appropriate for initializing built-in global options.


104-105: LGTM!

The Map structure for storing global option resources is appropriately typed and initialized.


117-119: Verify if preventing updates to registered options is intentional.

The early return prevents updates to already-registered global option resources. If a plugin or user code calls registerGlobalOptionResources with the same option name but different resources, the new resources will be silently ignored.

Is this the intended behavior, or should updates be allowed?


142-144: LGTM!

The helper function correctly returns all registered global option keys as an array.


174-178: LGTM!

The updated call to mapResourceWithBuiltinKey correctly passes getGlobalOptions() to enable proper key mapping for global options.


180-197: LGTM with noted typo.

The logic for setting up and registering built-in global option resources is correct. The variable name typo at line 181 (buildinGlobalOptionResources) should be corrected as noted in the previous comment.


305-314: LGTM!

The updated signature and logic correctly differentiate global options (mapped using resolveArgKey) from other built-in keys (mapped using resolveBuiltInKey).

Comment thread packages/plugin-i18n/src/index.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0cdaa1d and acd99ee.

📒 Files selected for processing (1)
  • packages/plugin-i18n/src/index.ts (5 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Use ES modules throughout the codebase
Follow existing code style (enforced by ESLint and Prettier)

Files:

  • packages/plugin-i18n/src/index.ts
🧬 Code graph analysis (1)
packages/plugin-i18n/src/index.ts (5)
packages/shared/src/constants.ts (1)
  • COMMON_ARGS (33-44)
packages/gunshi/src/plugin/core.ts (1)
  • plugin (390-436)
packages/shared/src/utils.ts (2)
  • resolveArgKey (52-57)
  • resolveBuiltInKey (34-38)
packages/gunshi/src/types.ts (1)
  • CommandContext (361-451)
packages/gunshi/src/plugin/context.ts (1)
  • globalOptions (168-170)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Test on Node.js 20
  • GitHub Check: release
  • GitHub Check: release
🔇 Additional comments (9)
packages/plugin-i18n/src/index.ts (9)

40-40: LGTM!

The import of COMMON_ARGS is correctly added and used to derive built-in global options.


101-102: LGTM!

The variable naming is correct and consistent with the codebase conventions (e.g., builtinResources). The previous typo concern has been addressed.


105-105: LGTM!

The type signature correctly models per-option, per-locale resource storage.


142-144: LGTM!

The helper correctly returns a snapshot of registered global option keys.


174-178: LGTM!

The integration of global options into resource mapping is correct and aligns with the feature's objective to treat global options as arguments.


180-197: LGTM!

The setup logic correctly builds locale-specific resources for each built-in global option, ensuring at minimum a DEFAULT_LOCALE fallback exists.


243-243: LGTM!

The public API correctly exposes registerGlobalOptionResources, enabling external plugins to register global option localization.


306-315: LGTM, but verify ctx.name is defined at call sites.

The updated logic correctly differentiates global options (mapped to arg keys) from other built-in keys. However, note that ctx.name at line 312 can be undefined per the CommandContext type. Ensure all call sites (line 176) occur in contexts where ctx.name is guaranteed to be defined.


113-140: Original review comment is incorrect.

The resolveArgKey function explicitly declares name as an optional parameter (name?: string) and handles undefined values in its implementation: ${name ? ${name}${BUILT_IN_KEY_SEPARATOR} : ''}... When ctx.name is undefined, the function correctly omits the name prefix and returns a valid key format. No guard or defensive check is needed at line 129.

Likely an incorrect or invalid review comment.

Comment thread packages/plugin-i18n/src/index.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/plugin-i18n/src/index.ts (1)

113-140: Consider logging when duplicate registration is silently ignored.

At lines 117-119, the function silently returns early if the option is already registered. This prevents resource updates and might hide mistakes where a developer attempts to modify or re-register global option resources. Consider logging a warning or throwing an error to make this behavior explicit.

Apply this diff to add a warning:

       if (globalOptionResources.has(option)) {
+        console.warn(`Global option "${option}" is already registered. Skipping duplicate registration.`)
         return
       }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between acd99ee and d287334.

📒 Files selected for processing (1)
  • packages/plugin-i18n/src/index.ts (5 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Use ES modules throughout the codebase
Follow existing code style (enforced by ESLint and Prettier)

Files:

  • packages/plugin-i18n/src/index.ts
🧬 Code graph analysis (1)
packages/plugin-i18n/src/index.ts (3)
packages/shared/src/constants.ts (1)
  • COMMON_ARGS (33-44)
packages/shared/src/utils.ts (3)
  • namespacedId (105-109)
  • resolveArgKey (52-57)
  • resolveBuiltInKey (34-38)
packages/gunshi/src/types.ts (1)
  • CommandContext (361-451)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test on Node.js 20
🔇 Additional comments (6)
packages/plugin-i18n/src/index.ts (6)

40-40: LGTM!

The import of COMMON_ARGS is correctly added to support the global option resources feature.


101-105: LGTM!

The variable declarations correctly establish storage for built-in global options and global option resources. The typo from the previous review has been addressed.


174-197: LGTM!

The setup of built-in global option resources is well-structured. The logic correctly:

  1. Initializes each built-in option with the default locale (en-US) from DefaultResource
  2. Enriches with additional locales from builtinResources
  3. Registers all options via registerGlobalOptionResources

This ensures that built-in global options always have a DEFAULT_LOCALE fallback.


224-234: LGTM! Defensive fallback properly implemented.

The fallback chain at lines 228-232 now includes:

  1. Requested locale (localeStr)
  2. Default locale (DEFAULT_LOCALE)
  3. First available locale (Object.values(optionResource)[0])
  4. Empty string fallback

This addresses the previous review concern about potentially undefined values when externally registered options lack the default locale.


310-319: LGTM!

The signature update correctly adds globalOptions parameter to conditionally route keys to the appropriate resolver:

  • Global options use resolveArgKey (command-namespaced)
  • Built-in keys use resolveBuiltInKey (built-in prefix)

This properly differentiates between global option resources and other built-in resources.


243-248: LGTM!

The extension correctly exposes registerGlobalOptionResources as part of the public API, enabling external code to register custom global option resources.

@kazupon
kazupon merged commit 4030d2d into main Oct 18, 2025
10 checks passed
@kazupon
kazupon deleted the fix/global-options-i18n branch October 18, 2025 15:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Includes new features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant