diff --git a/hooks.go b/hooks.go index 168c134..a19a47c 100644 --- a/hooks.go +++ b/hooks.go @@ -11,6 +11,7 @@ import ( ) var missingKeyHandler atomic.Value +var missingKeyHandlerMu sync.Mutex type missingKeyHandlersState struct { handlers []MissingKeyHandler @@ -131,6 +132,8 @@ func loadLocaleProvider(svc *Service, provider localeProviderRegistration) { // OnMissingKey registers a handler for missing translation keys. func OnMissingKey(h MissingKeyHandler) { + missingKeyHandlerMu.Lock() + defer missingKeyHandlerMu.Unlock() if h == nil { missingKeyHandler.Store(missingKeyHandlersState{}) return @@ -140,6 +143,8 @@ func OnMissingKey(h MissingKeyHandler) { // ClearMissingKeyHandlers removes all registered missing-key handlers. func ClearMissingKeyHandlers() { + missingKeyHandlerMu.Lock() + defer missingKeyHandlerMu.Unlock() missingKeyHandler.Store(missingKeyHandlersState{}) } @@ -149,6 +154,8 @@ func AddMissingKeyHandler(h MissingKeyHandler) { if h == nil { return } + missingKeyHandlerMu.Lock() + defer missingKeyHandlerMu.Unlock() current := missingKeyHandlers() current.handlers = append(current.handlers, h) missingKeyHandler.Store(current) diff --git a/hooks_test.go b/hooks_test.go index e9114f4..fa829d3 100644 --- a/hooks_test.go +++ b/hooks_test.go @@ -2,6 +2,7 @@ package i18n import ( "path/filepath" + "sync" "testing" "testing/fstest" @@ -456,6 +457,38 @@ func TestAddMissingKeyHandler_Good(t *testing.T) { assert.Equal(t, 1, second) } +func TestAddMissingKeyHandler_Good_Concurrent(t *testing.T) { + svc, err := New() + require.NoError(t, err) + prev := Default() + SetDefault(svc) + prevHandlers := missingKeyHandlers() + t.Cleanup(func() { + missingKeyHandler.Store(prevHandlers) + SetDefault(prev) + }) + svc.SetMode(ModeCollect) + + ClearMissingKeyHandlers() + t.Cleanup(func() { + ClearMissingKeyHandlers() + }) + + const handlers = 32 + var wg sync.WaitGroup + wg.Add(handlers) + for i := 0; i < handlers; i++ { + go func() { + defer wg.Done() + AddMissingKeyHandler(func(MissingKey) {}) + }() + } + wg.Wait() + + state := missingKeyHandlers() + assert.Len(t, state.handlers, handlers) +} + func TestClearMissingKeyHandlers_Good(t *testing.T) { svc, err := New() require.NoError(t, err)