go-i18n/hooks.go
Snider 9eb25f567b
All checks were successful
Security Scan / security (push) Successful in 10s
Test / test (push) Successful in 42s
fix: remove panic patterns and surface swallowed errors
- SetDefault(nil) no longer panics — allows clearing the default service
- Default() logs Init() errors instead of discarding them
- NewWithLoader checks LanguagesErr() via interface assertion for richer error context
- hooks.go logs LoadFS errors instead of silently ignoring them

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 08:22:42 +00:00

77 lines
1.7 KiB
Go

package i18n
import (
"io/fs"
"log"
"runtime"
"sync"
"sync/atomic"
)
var missingKeyHandler atomic.Value
type localeRegistration struct {
fsys fs.FS
dir string
}
var (
registeredLocales []localeRegistration
registeredLocalesMu sync.Mutex
localesLoaded bool
)
// RegisterLocales registers a filesystem containing locale files.
// Call this in your package's init() to register translations.
//
// //go:embed locales/*.json
// var localeFS embed.FS
//
// func init() {
// i18n.RegisterLocales(localeFS, "locales")
// }
func RegisterLocales(fsys fs.FS, dir string) {
registeredLocalesMu.Lock()
defer registeredLocalesMu.Unlock()
registeredLocales = append(registeredLocales, localeRegistration{fsys: fsys, dir: dir})
if localesLoaded {
if svc := Default(); svc != nil {
if err := svc.LoadFS(fsys, dir); err != nil {
log.Printf("i18n: RegisterLocales failed to load %q: %v", dir, err)
}
}
}
}
func loadRegisteredLocales(svc *Service) {
registeredLocalesMu.Lock()
defer registeredLocalesMu.Unlock()
for _, reg := range registeredLocales {
if err := svc.LoadFS(reg.fsys, reg.dir); err != nil {
log.Printf("i18n: loadRegisteredLocales failed to load %q: %v", reg.dir, err)
}
}
localesLoaded = true
}
// OnMissingKey registers a handler for missing translation keys.
func OnMissingKey(h MissingKeyHandler) {
missingKeyHandler.Store(h)
}
func dispatchMissingKey(key string, args map[string]any) {
v := missingKeyHandler.Load()
if v == nil {
return
}
h, ok := v.(MissingKeyHandler)
if !ok || h == nil {
return
}
_, file, line, ok := runtime.Caller(2)
if !ok {
file = "unknown"
line = 0
}
h(MissingKey{Key: key, Args: args, CallerFile: file, CallerLine: line})
}