From 277445cc5d9f25816d5a10fa22919faab91e98e8 Mon Sep 17 00:00:00 2001 From: Virgil Date: Wed, 1 Apr 2026 23:06:02 +0000 Subject: [PATCH] fix(service): re-detect registered locales after init Co-Authored-By: Virgil --- hooks_test.go | 37 +++++++++++++++++++++++++++++++++++ localise.go | 5 ++++- service.go | 54 ++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 82 insertions(+), 14 deletions(-) diff --git a/hooks_test.go b/hooks_test.go index 7727fb6..52f0e6b 100644 --- a/hooks_test.go +++ b/hooks_test.go @@ -110,6 +110,43 @@ func TestInit_LoadsRegisteredLocales(t *testing.T) { assert.Equal(t, "loaded on init", got) } +func TestInit_ReDetectsRegisteredLocales(t *testing.T) { + t.Setenv("LANG", "de_DE.UTF-8") + + registeredLocalesMu.Lock() + savedLocales := registeredLocales + savedLoaded := localesLoaded + registeredLocales = nil + localesLoaded = false + registeredLocalesMu.Unlock() + + defaultOnce = sync.Once{} + defaultService.Store(nil) + + defer func() { + registeredLocalesMu.Lock() + registeredLocales = savedLocales + localesLoaded = savedLoaded + registeredLocalesMu.Unlock() + defaultService.Store(nil) + defaultOnce = sync.Once{} + }() + + fs := fstest.MapFS{ + "locales/de.json": &fstest.MapFile{ + Data: []byte(`{"hello": "hallo"}`), + }, + } + RegisterLocales(fs, "locales") + + require.NoError(t, Init()) + + svc := Default() + require.NotNil(t, svc) + assert.Contains(t, svc.Language(), "de") + assert.Equal(t, "hallo", svc.T("hello")) +} + func TestLoadRegisteredLocales_Good(t *testing.T) { svc, err := New() require.NoError(t, err) diff --git a/localise.go b/localise.go index 794368c..b4a833b 100644 --- a/localise.go +++ b/localise.go @@ -105,8 +105,11 @@ func detectLanguage(supported []language.Tag) string { return "" } matcher := language.NewMatcher(supported) - bestMatch, _, confidence := matcher.Match(parsedLang) + bestMatch, bestIndex, confidence := matcher.Match(parsedLang) if confidence >= language.Low { + if bestIndex >= 0 && bestIndex < len(supported) { + return supported[bestIndex].String() + } return bestMatch.String() } return "" diff --git a/service.go b/service.go index 20a33bd..fb4b8df 100644 --- a/service.go +++ b/service.go @@ -16,16 +16,17 @@ import ( // Service provides grammar-aware internationalisation. type Service struct { - loader Loader - messages map[string]map[string]Message // lang -> key -> message - currentLang string - fallbackLang string - availableLangs []language.Tag - mode Mode - debug bool - formality Formality - handlers []KeyHandler - mu sync.RWMutex + loader Loader + messages map[string]map[string]Message // lang -> key -> message + currentLang string + fallbackLang string + languageExplicit bool + availableLangs []language.Tag + mode Mode + debug bool + formality Formality + handlers []KeyHandler + mu sync.RWMutex } // Option configures a Service during construction. @@ -222,11 +223,16 @@ func (s *Service) SetLanguage(lang string) error { return log.E("Service.SetLanguage", "no languages available", nil) } matcher := language.NewMatcher(s.availableLangs) - bestMatch, _, confidence := matcher.Match(requestedLang) + bestMatch, bestIndex, confidence := matcher.Match(requestedLang) if confidence == language.No { return log.E("Service.SetLanguage", "unsupported language: "+lang, nil) } - s.currentLang = bestMatch.String() + if bestIndex >= 0 && bestIndex < len(s.availableLangs) { + s.currentLang = s.availableLangs[bestIndex].String() + } else { + s.currentLang = bestMatch.String() + } + s.languageExplicit = true return nil } @@ -571,6 +577,7 @@ func (s *Service) AddLoader(loader Loader) error { } s.mu.Unlock() } + s.autoDetectLanguage() return nil } @@ -578,7 +585,17 @@ func (s *Service) AddLoader(loader Loader) error { // Deprecated: Use AddLoader(NewFSLoader(fsys, dir)) instead for proper grammar handling. func (s *Service) LoadFS(fsys fs.FS, dir string) error { s.mu.Lock() - defer s.mu.Unlock() + defer func() { + s.mu.Unlock() + if s.languageExplicit { + return + } + if detected := detectLanguage(s.availableLangs); detected != "" { + s.mu.Lock() + s.currentLang = detected + s.mu.Unlock() + } + }() entries, err := fs.ReadDir(fsys, dir) if err != nil { return log.E("Service.LoadFS", "read locales directory", err) @@ -605,3 +622,14 @@ func (s *Service) LoadFS(fsys fs.FS, dir string) error { } return nil } + +func (s *Service) autoDetectLanguage() { + s.mu.Lock() + defer s.mu.Unlock() + if s.languageExplicit { + return + } + if detected := detectLanguage(s.availableLangs); detected != "" { + s.currentLang = detected + } +} -- 2.45.3