92 lines
2.1 KiB
Go
92 lines
2.1 KiB
Go
package i18n
|
|
|
|
import (
|
|
"io/fs"
|
|
"log"
|
|
"runtime"
|
|
"strings"
|
|
"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 := missingKeyCaller()
|
|
h(MissingKey{Key: key, Args: args, CallerFile: file, CallerLine: line})
|
|
}
|
|
|
|
func missingKeyCaller() (string, int) {
|
|
const packagePrefix = "dappco.re/go/core/i18n."
|
|
|
|
pcs := make([]uintptr, 16)
|
|
n := runtime.Callers(2, pcs)
|
|
frames := runtime.CallersFrames(pcs[:n])
|
|
for {
|
|
frame, more := frames.Next()
|
|
if !strings.HasPrefix(frame.Function, packagePrefix) || strings.HasSuffix(frame.File, "_test.go") {
|
|
return frame.File, frame.Line
|
|
}
|
|
if !more {
|
|
break
|
|
}
|
|
}
|
|
return "unknown", 0
|
|
}
|