diff --git a/pkg/core/cli.go b/pkg/core/cli.go index a13b263..12e4297 100644 --- a/pkg/core/cli.go +++ b/pkg/core/cli.go @@ -121,8 +121,9 @@ func (cl *Cli) PrintHelp() { if cmd.Hidden { continue } - desc := cl.core.I18n().Translate(cmd.I18nKey()).Value.(string) - if desc == cmd.I18nKey() { + tr := cl.core.I18n().Translate(cmd.I18nKey()) + desc, _ := tr.Value.(string) + if desc == "" || desc == cmd.I18nKey() { cl.Print(" %s", path) } else { cl.Print(" %-30s %s", path, desc) diff --git a/pkg/core/command.go b/pkg/core/command.go index 4b81ba8..8619128 100644 --- a/pkg/core/command.go +++ b/pkg/core/command.go @@ -130,10 +130,6 @@ type commandRegistry struct { // c.Command("deploy", Command{Action: handler}) // r := c.Command("deploy") func (c *Core) Command(path string, command ...Command) Result { - if c.commands == nil { - c.commands = &commandRegistry{commands: make(map[string]*Command)} - } - if len(command) == 0 { c.commands.mu.RLock() cmd, ok := c.commands.commands[path] diff --git a/pkg/core/contract.go b/pkg/core/contract.go index e95a86c..a033b58 100644 --- a/pkg/core/contract.go +++ b/pkg/core/contract.go @@ -73,16 +73,18 @@ type ActionTaskCompleted struct { // }) func New(opts ...Options) *Core { c := &Core{ - app: &App{}, - data: &Data{}, - drive: &Drive{}, - fs: &Fs{root: "/"}, - config: &Config{ConfigOptions: &ConfigOptions{}}, - error: &ErrorPanic{}, - log: &ErrorLog{log: defaultLog}, - lock: &Lock{}, - ipc: &Ipc{}, - i18n: &I18n{}, + app: &App{}, + data: &Data{}, + drive: &Drive{}, + fs: &Fs{root: "/"}, + config: &Config{ConfigOptions: &ConfigOptions{}}, + error: &ErrorPanic{}, + log: &ErrorLog{log: defaultLog}, + lock: &Lock{}, + ipc: &Ipc{}, + i18n: &I18n{}, + services: &serviceRegistry{services: make(map[string]*Service)}, + commands: &commandRegistry{commands: make(map[string]*Command)}, } if len(opts) > 0 { diff --git a/pkg/core/embed.go b/pkg/core/embed.go index 5512cd4..809226e 100644 --- a/pkg/core/embed.go +++ b/pkg/core/embed.go @@ -70,11 +70,12 @@ func AddAsset(group, name, data string) { func GetAsset(group, name string) Result { assetGroupsMu.RLock() g, ok := assetGroups[group] - assetGroupsMu.RUnlock() if !ok { + assetGroupsMu.RUnlock() return Result{} } data, ok := g.assets[name] + assetGroupsMu.RUnlock() if !ok { return Result{} } diff --git a/pkg/core/i18n.go b/pkg/core/i18n.go index 0f10c09..c2a88ed 100644 --- a/pkg/core/i18n.go +++ b/pkg/core/i18n.go @@ -94,19 +94,30 @@ func (i *I18n) Translate(messageID string, args ...any) Result { return Result{messageID, true} } -// SetLanguage sets the active language. No-op if no translator is registered. +// SetLanguage sets the active language and forwards to the translator if registered. func (i *I18n) SetLanguage(lang string) Result { - - if lang != "" { - i.locale = lang + if lang == "" { + return Result{OK: true} + } + i.mu.Lock() + i.locale = lang + t := i.translator + i.mu.Unlock() + if t != nil { + if err := t.SetLanguage(lang); err != nil { + return Result{err, false} + } } return Result{OK: true} } // Language returns the current language code, or "en" if not set. func (i *I18n) Language() string { - if i.locale != "" { - return i.locale + i.mu.RLock() + locale := i.locale + i.mu.RUnlock() + if locale != "" { + return locale } return "en" } diff --git a/pkg/core/lock.go b/pkg/core/lock.go index 851c8aa..a8eaac5 100644 --- a/pkg/core/lock.go +++ b/pkg/core/lock.go @@ -40,9 +40,6 @@ func (c *Core) LockEnable(name ...string) { } c.Lock(n).Mutex.Lock() defer c.Lock(n).Mutex.Unlock() - if c.services == nil { - c.services = &serviceRegistry{services: make(map[string]*Service)} - } c.services.lockEnabled = true } diff --git a/pkg/core/options.go b/pkg/core/options.go index 83d3529..4d4c5f8 100644 --- a/pkg/core/options.go +++ b/pkg/core/options.go @@ -50,21 +50,21 @@ type Result struct { // r.Result(value) // OK = true, Value = value // r.Result() // after set — returns the value func (r Result) Result(args ...any) Result { + if len(args) == 0 { + return r + } if len(args) == 1 { return Result{args[0], true} } - if len(args) >= 2 { - if err, ok := args[len(args)-1].(error); ok { - if err != nil { - return Result{err, false} - } - return Result{args[0], true} + if err, ok := args[len(args)-1].(error); ok { + if err != nil { + return Result{err, false} } + return Result{args[0], true} } return Result{args[0], true} - } // Option is a single key-value configuration pair. diff --git a/pkg/core/service.go b/pkg/core/service.go index 8007b83..4bc9fbd 100644 --- a/pkg/core/service.go +++ b/pkg/core/service.go @@ -38,10 +38,6 @@ type serviceRegistry struct { // c.Service("auth", core.Service{OnStart: startFn}) // r := c.Service("auth") func (c *Core) Service(name string, service ...Service) Result { - if c.services == nil { - c.services = &serviceRegistry{services: make(map[string]*Service)} - } - if len(service) == 0 { c.Lock("srv").Mutex.RLock() v, ok := c.services.services[name] diff --git a/pkg/core/task.go b/pkg/core/task.go index cfc0a78..553e7ae 100644 --- a/pkg/core/task.go +++ b/pkg/core/task.go @@ -35,7 +35,12 @@ func (c *Core) PerformAsync(t Task) Result { if e, ok := r.Value.(error); ok { err = e } else { - err = E("core.PerformAsync", Join(" ", "no handler found for task type", reflect.TypeOf(t).String()), nil) + taskType := reflect.TypeOf(t) + typeName := "" + if taskType != nil { + typeName = taskType.String() + } + err = E("core.PerformAsync", Join(" ", "no handler found for task type", typeName), nil) } } c.ACTION(ActionTaskCompleted{TaskIdentifier: taskID, Task: t, Result: r.Value, Error: err}) diff --git a/tests/utils_test.go b/tests/utils_test.go index 76a4322..dcb8d4c 100644 --- a/tests/utils_test.go +++ b/tests/utils_test.go @@ -202,8 +202,16 @@ func TestResult_Result_WithError_Bad(t *testing.T) { assert.Equal(t, err, r.Value) } -func TestResult_Result_ZeroArgs_Ugly(t *testing.T) { - assert.Panics(t, func() { - Result{}.Result() - }) +func TestResult_Result_ZeroArgs_Good(t *testing.T) { + r := Result{"hello", true} + got := r.Result() + assert.Equal(t, "hello", got.Value) + assert.True(t, got.OK) +} + +func TestResult_Result_ZeroArgs_Empty_Good(t *testing.T) { + r := Result{} + got := r.Result() + assert.Nil(t, got.Value) + assert.False(t, got.OK) }