From fa8fab8aa3a71b8ad09815a06fa908c9fccf27b6 Mon Sep 17 00:00:00 2001 From: bingmokaka <103943264+bingmokaka@users.noreply.github.com> Date: Sun, 28 Jun 2026 02:32:31 +0800 Subject: [PATCH 1/2] fix(settings): validate language against supported locales --- src/lib/settings/store.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/lib/settings/store.ts b/src/lib/settings/store.ts index 0a931e50..ca82ca80 100644 --- a/src/lib/settings/store.ts +++ b/src/lib/settings/store.ts @@ -41,6 +41,7 @@ */ import { create } from 'zustand'; import { persist, createJSONStorage } from 'zustand/middleware'; +import { DEFAULT_LANGUAGE, SUPPORTED_LANGUAGES } from '../../locales/config'; import { SETTINGS_SCHEMA_VERSION, SETTINGS_STORAGE_KEY } from './constants'; import { type AppSettings, appSettingsSchema, createDefaultSettings } from './types'; @@ -88,6 +89,13 @@ const noopStorage = { removeItem: (): void => undefined, }; +function normalizeLanguage(language: string): AppSettings['language'] { + const trimmed = language.trim(); + return Object.prototype.hasOwnProperty.call(SUPPORTED_LANGUAGES, trimmed) + ? trimmed + : DEFAULT_LANGUAGE; +} + function localStorageOrNoop() { if (typeof window === 'undefined') return noopStorage; try { @@ -112,7 +120,7 @@ export const useSettingsStore = create()( version: SETTINGS_SCHEMA_VERSION, ...(partial.language !== undefined ? { - language: partial.language.trim().slice(0, 24) || 'en', + language: normalizeLanguage(partial.language), } : {}), }; From e7dc9e1220da6cea27ce879f808294ec64d670a7 Mon Sep 17 00:00:00 2001 From: bingmokaka <103943264+bingmokaka@users.noreply.github.com> Date: Sun, 28 Jun 2026 02:32:33 +0800 Subject: [PATCH 2/2] test(settings): cover unsupported language fallback --- src/lib/settings/__tests__/store.test.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/lib/settings/__tests__/store.test.ts diff --git a/src/lib/settings/__tests__/store.test.ts b/src/lib/settings/__tests__/store.test.ts new file mode 100644 index 00000000..efdacbb2 --- /dev/null +++ b/src/lib/settings/__tests__/store.test.ts @@ -0,0 +1,20 @@ +import { beforeEach, describe, expect, it } from 'vitest'; +import { useSettingsStore } from '../store'; + +beforeEach(() => { + useSettingsStore.getState().resetSettings(); +}); + +describe('useSettingsStore', () => { + it('falls back to the default language for unsupported locales', () => { + useSettingsStore.getState().patchSettings({ language: 'zz-ZZ' }); + + expect(useSettingsStore.getState().settings.language).toBe('en'); + }); + + it('keeps supported languages when patching settings', () => { + useSettingsStore.getState().patchSettings({ language: 'fr' }); + + expect(useSettingsStore.getState().settings.language).toBe('fr'); + }); +}); \ No newline at end of file