diff --git a/hooks.go b/hooks.go index 8b3eeb5..113e592 100644 --- a/hooks.go +++ b/hooks.go @@ -4,6 +4,7 @@ import ( "io/fs" "log" "runtime" + "strings" "sync" "sync/atomic" ) @@ -68,10 +69,24 @@ func dispatchMissingKey(key string, args map[string]any) { if !ok || h == nil { return } - _, file, line, ok := runtime.Caller(2) - if !ok { - file = "unknown" - line = 0 - } + 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 +} diff --git a/hooks_test.go b/hooks_test.go index 52f0e6b..0fa6355 100644 --- a/hooks_test.go +++ b/hooks_test.go @@ -1,6 +1,7 @@ package i18n import ( + "path/filepath" "sync" "testing" "testing/fstest" @@ -188,6 +189,11 @@ func TestLoadRegisteredLocales_Good(t *testing.T) { func TestOnMissingKey_Good(t *testing.T) { svc, err := New() require.NoError(t, err) + prev := Default() + SetDefault(svc) + t.Cleanup(func() { + SetDefault(prev) + }) svc.SetMode(ModeCollect) var captured MissingKey @@ -195,11 +201,11 @@ func TestOnMissingKey_Good(t *testing.T) { captured = m }) - _ = svc.T("missing.test.key", map[string]any{"foo": "bar"}) + _ = T("missing.test.key", map[string]any{"foo": "bar"}) assert.Equal(t, "missing.test.key", captured.Key) assert.Equal(t, "bar", captured.Args["foo"]) - assert.NotEmpty(t, captured.CallerFile) + assert.Equal(t, "hooks_test.go", filepath.Base(captured.CallerFile)) } func TestDispatchMissingKey_Good_NoHandler(t *testing.T) {