feat: auto-derive i18n keys from command names (Conclave pattern)
commandService.applyI18n() walks registered commands and sets
Short/Long from cmd.{name}.short/long keys automatically. Downstream
packages no longer need to call i18n.T() for command descriptions —
the CLI Conclave handles it via service name derivation.
This is the Conclave pattern: services inside a sealed core.New()
auto-discover each other's capabilities via the lifecycle hooks.
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
91de96994a
commit
0c1b74c637
1 changed files with 25 additions and 1 deletions
|
|
@ -25,7 +25,7 @@ import (
|
||||||
// cli.WithCommands("dev", dev.AddDevCommands, locales.FS)
|
// cli.WithCommands("dev", dev.AddDevCommands, locales.FS)
|
||||||
func WithCommands(name string, register func(root *Command), localeFS ...fs.FS) core.Option {
|
func WithCommands(name string, register func(root *Command), localeFS ...fs.FS) core.Option {
|
||||||
return core.WithName("cmd."+name, func(c *core.Core) (any, error) {
|
return core.WithName("cmd."+name, func(c *core.Core) (any, error) {
|
||||||
svc := &commandService{core: c, register: register}
|
svc := &commandService{core: c, name: name, register: register}
|
||||||
if len(localeFS) > 0 {
|
if len(localeFS) > 0 {
|
||||||
svc.localeFS = localeFS[0]
|
svc.localeFS = localeFS[0]
|
||||||
}
|
}
|
||||||
|
|
@ -35,6 +35,7 @@ func WithCommands(name string, register func(root *Command), localeFS ...fs.FS)
|
||||||
|
|
||||||
type commandService struct {
|
type commandService struct {
|
||||||
core *core.Core
|
core *core.Core
|
||||||
|
name string
|
||||||
register func(root *Command)
|
register func(root *Command)
|
||||||
localeFS fs.FS
|
localeFS fs.FS
|
||||||
}
|
}
|
||||||
|
|
@ -42,10 +43,33 @@ type commandService struct {
|
||||||
func (s *commandService) OnStartup(_ context.Context) error {
|
func (s *commandService) OnStartup(_ context.Context) error {
|
||||||
if root, ok := s.core.App.(*cobra.Command); ok {
|
if root, ok := s.core.App.(*cobra.Command); ok {
|
||||||
s.register(root)
|
s.register(root)
|
||||||
|
// Auto-set Short/Long from i18n keys derived from command name.
|
||||||
|
// The Conclave's i18n service has already loaded all translations
|
||||||
|
// from sibling services' LocaleProvider before commands attach.
|
||||||
|
s.applyI18n(root)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// applyI18n walks commands added by this service and sets Short/Long
|
||||||
|
// from derived i18n keys if they're empty or still raw keys.
|
||||||
|
func (s *commandService) applyI18n(root *cobra.Command) {
|
||||||
|
for _, cmd := range root.Commands() {
|
||||||
|
key := "cmd." + cmd.Name()
|
||||||
|
// Only set if Short is empty or looks like a raw key (contains dots)
|
||||||
|
if cmd.Short == "" || cmd.Short == key+".short" {
|
||||||
|
if translated := T(key + ".short"); translated != key+".short" {
|
||||||
|
cmd.Short = translated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cmd.Long == "" || cmd.Long == key+".long" {
|
||||||
|
if translated := T(key + ".long"); translated != key+".long" {
|
||||||
|
cmd.Long = translated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Locales implements core.LocaleProvider.
|
// Locales implements core.LocaleProvider.
|
||||||
func (s *commandService) Locales() fs.FS {
|
func (s *commandService) Locales() fs.FS {
|
||||||
return s.localeFS
|
return s.localeFS
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue