diff --git a/service.go b/service.go index 471a671..503215f 100644 --- a/service.go +++ b/service.go @@ -771,16 +771,17 @@ func missingKeySubjectArgs(subj *Subject) map[string]any { // Raw translates without i18n.* namespace magic. func (s *Service) Raw(messageID string, args ...any) string { s.mu.RLock() - defer s.mu.RUnlock() var data any if len(args) > 0 { data = args[0] } text := s.resolveDirectLocked(messageID, data) + debug := s.debug + s.mu.RUnlock() if text == "" { - return s.handleMissingKey(messageID, args) + text = s.handleMissingKey(messageID, args) } - if s.debug { + if debug { return debugFormat(messageID, text) } return text diff --git a/service_test.go b/service_test.go index 370f719..9d34e01 100644 --- a/service_test.go +++ b/service_test.go @@ -275,6 +275,45 @@ func TestServiceRaw_DoesNotUseCommonFallbacks(t *testing.T) { } } +func TestServiceRaw_MissingKeyHandlersCanMutateService(t *testing.T) { + svc, err := New() + if err != nil { + t.Fatalf("New() failed: %v", err) + } + + prev := missingKeyHandlers() + t.Cleanup(func() { + missingKeyHandler.Store(prev) + }) + + OnMissingKey(func(m MissingKey) { + _ = svc.SetLanguage("fr") + }) + svc.SetMode(ModeCollect) + svc.SetDebug(true) + t.Cleanup(func() { + svc.SetDebug(false) + }) + + done := make(chan string, 1) + go func() { + done <- svc.Raw("missing.raw.key") + }() + + select { + case got := <-done: + if got != "[missing.raw.key] [missing.raw.key]" { + t.Fatalf("Raw(missing.raw.key) = %q, want %q", got, "[missing.raw.key] [missing.raw.key]") + } + case <-time.After(2 * time.Second): + t.Fatal("Raw(missing.raw.key) timed out while missing-key handler mutated service state") + } + + if got := svc.Language(); got != "fr" { + t.Fatalf("Language() = %q, want %q", got, "fr") + } +} + func TestServiceModes(t *testing.T) { svc, err := New() if err != nil {