2026-01-30 17:04:21 +00:00
|
|
|
// Package i18n provides internationalization for the CLI.
|
|
|
|
|
package i18n
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"runtime"
|
2026-01-30 19:02:30 +00:00
|
|
|
"sync/atomic"
|
2026-01-30 17:04:21 +00:00
|
|
|
)
|
|
|
|
|
|
2026-01-30 19:02:30 +00:00
|
|
|
var missingKeyHandler atomic.Value // stores MissingKeyHandler
|
2026-01-30 17:04:21 +00:00
|
|
|
|
|
|
|
|
// OnMissingKey registers a handler for missing translation keys.
|
|
|
|
|
// Called when T() can't find a key in ModeCollect.
|
2026-01-30 19:02:30 +00:00
|
|
|
// Thread-safe: can be called concurrently with translations.
|
2026-01-30 17:04:21 +00:00
|
|
|
//
|
|
|
|
|
// i18n.SetMode(i18n.ModeCollect)
|
|
|
|
|
// i18n.OnMissingKey(func(m i18n.MissingKey) {
|
|
|
|
|
// log.Printf("MISSING: %s at %s:%d", m.Key, m.CallerFile, m.CallerLine)
|
|
|
|
|
// })
|
|
|
|
|
func OnMissingKey(h MissingKeyHandler) {
|
2026-01-30 19:02:30 +00:00
|
|
|
missingKeyHandler.Store(h)
|
2026-01-30 17:04:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// dispatchMissingKey creates and dispatches a MissingKey event.
|
|
|
|
|
// Called internally when a key is missing in ModeCollect.
|
|
|
|
|
func dispatchMissingKey(key string, args map[string]any) {
|
2026-01-30 19:02:30 +00:00
|
|
|
v := missingKeyHandler.Load()
|
|
|
|
|
if v == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
h, ok := v.(MissingKeyHandler)
|
|
|
|
|
if !ok || h == nil {
|
2026-01-30 17:04:21 +00:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_, file, line, ok := runtime.Caller(2) // Skip dispatchMissingKey and handleMissingKey
|
|
|
|
|
if !ok {
|
|
|
|
|
file = "unknown"
|
|
|
|
|
line = 0
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-30 19:02:30 +00:00
|
|
|
h(MissingKey{
|
2026-01-30 17:04:21 +00:00
|
|
|
Key: key,
|
|
|
|
|
Args: args,
|
|
|
|
|
CallerFile: file,
|
|
|
|
|
CallerLine: line,
|
|
|
|
|
})
|
|
|
|
|
}
|