fix(i18n): make default handlers idempotent
All checks were successful
Security Scan / security (push) Successful in 10s
Test / test (push) Successful in 1m30s

Avoid duplicating the built-in handler chain when WithDefaultHandlers is applied to a service that already has the defaults.

\nCo-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-04-02 00:32:16 +00:00
parent be1cf9bba8
commit 8fec2bc49f
2 changed files with 30 additions and 1 deletions

View file

@ -5,6 +5,7 @@ import (
"io/fs"
"maps"
"path"
"reflect"
"slices"
"sync"
"sync/atomic"
@ -55,7 +56,14 @@ func WithHandlers(handlers ...KeyHandler) Option {
// WithDefaultHandlers adds the default i18n.* namespace handlers.
func WithDefaultHandlers() Option {
return func(s *Service) { s.handlers = append(s.handlers, DefaultHandlers()...) }
return func(s *Service) {
for _, handler := range DefaultHandlers() {
if hasHandlerType(s.handlers, handler) {
continue
}
s.handlers = append(s.handlers, handler)
}
}
}
// WithMode sets the translation mode.
@ -713,3 +721,13 @@ func (s *Service) autoDetectLanguage() {
s.currentLang = detected
}
}
func hasHandlerType(handlers []KeyHandler, candidate KeyHandler) bool {
want := reflect.TypeOf(candidate)
for _, handler := range handlers {
if reflect.TypeOf(handler) == want {
return true
}
}
return false
}

View file

@ -412,6 +412,17 @@ func TestServiceHandlers(t *testing.T) {
}
}
func TestWithDefaultHandlers_Idempotent(t *testing.T) {
svc, err := New(WithDefaultHandlers())
if err != nil {
t.Fatalf("New() with WithDefaultHandlers() failed: %v", err)
}
if got := len(svc.Handlers()); got != 6 {
t.Fatalf("len(Handlers()) = %d, want 6", got)
}
}
func TestServiceWithOptions(t *testing.T) {
svc, err := New(
WithFallback("en"),