add first run lang detection

This commit is contained in:
Eduard Gert
2026-05-29 14:24:20 +02:00
parent 1985caf993
commit 9dc9e7184e
4 changed files with 53 additions and 15 deletions
+6 -4
View File
@@ -111,11 +111,16 @@ func NewStore(validator LanguageValidator, emitter Emitter) (*Store, error) {
return nil, fmt.Errorf("resolve preferences path: %w", err)
}
// Language starts empty — the absence of a value is the signal the
// frontend uses on first launch to detect the browser locale and call
// SetLanguage. Consumers that need an effective language (tray
// Localizer, i18n.Bundle.Translate) already fall back to
// i18n.DefaultLanguage when the code is empty.
s := &Store{
path: path,
validator: validator,
emitter: emitter,
current: UIPreferences{Language: i18n.DefaultLanguage, ViewMode: DefaultViewMode},
current: UIPreferences{ViewMode: DefaultViewMode},
}
if err := s.load(); err != nil {
@@ -222,9 +227,6 @@ func (s *Store) load() error {
return err
}
if loaded.Language == "" {
loaded.Language = i18n.DefaultLanguage
}
if !loaded.ViewMode.IsValid() {
loaded.ViewMode = DefaultViewMode
}
+12 -7
View File
@@ -79,7 +79,8 @@ func TestStore_DefaultsWhenFileMissing(t *testing.T) {
require.NoError(t, err)
got := s.Get()
assert.Equal(t, i18n.DefaultLanguage, got.Language, "default language should be served when no file is on disk")
assert.Equal(t, i18n.LanguageCode(""), got.Language, "language must be empty when no file is on disk so the frontend can detect the browser locale")
assert.Equal(t, DefaultViewMode, got.ViewMode, "view-mode default should still apply")
}
func TestStore_SetLanguagePersistsAndBroadcasts(t *testing.T) {
@@ -153,13 +154,17 @@ func TestStore_SetLanguageIdempotent(t *testing.T) {
s, err := NewStore(fakeValidator{ok: map[i18n.LanguageCode]bool{"en": true}}, emitter)
require.NoError(t, err)
// First call goes from "" (unset) to "en" — real change, one broadcast.
require.NoError(t, s.SetLanguage("en"))
require.Len(t, emitter.calledWith(EventPreferencesChanged), 1,
"first SetLanguage from unset should broadcast")
// SetLanguage to the current value is a no-op — no disk write, no
// broadcast. Without this guard the tray would re-render the menu on
// every cosmetic re-save of the preferences file.
assert.Empty(t, emitter.calledWith(EventPreferencesChanged),
"setting the current language should not broadcast")
// Second call is a no-op — no disk write, no broadcast. Without this
// guard the tray would re-render the menu on every cosmetic re-save of
// the preferences file.
require.NoError(t, s.SetLanguage("en"))
assert.Len(t, emitter.calledWith(EventPreferencesChanged), 1,
"re-setting the current language should not broadcast again")
}
func TestStore_CorruptFileFallsBackToDefault(t *testing.T) {
@@ -173,7 +178,7 @@ func TestStore_CorruptFileFallsBackToDefault(t *testing.T) {
require.NoError(t, err, "corrupt file should not fail construction")
got := s.Get()
assert.Equal(t, i18n.DefaultLanguage, got.Language, "corrupt JSON should leave the default in place")
assert.Equal(t, i18n.LanguageCode(""), got.Language, "corrupt JSON should leave the empty (unset) default in place so the frontend can re-detect")
}
func TestStore_UnsubscribeStopsUpdates(t *testing.T) {