Skip to content

Commit 0b6bd07

Browse files
committed
fix: improve translation type guards to prevent misidentification
1 parent 5f9ff6d commit 0b6bd07

1 file changed

Lines changed: 55 additions & 18 deletions

File tree

frontend/src/stores/global-store.ts

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,53 @@ import type { MessageLanguages } from 'src/boot/i18n';
2121
import type { Composer } from 'vue-i18n';
2222
import type { QVueGlobals } from 'quasar';
2323

24+
const isTranslationMenu = (obj: unknown): obj is TranslationMenu => {
25+
if (!obj || typeof obj !== 'object') return false;
26+
const candidate = obj as Record<string, unknown>;
27+
return (
28+
'name' in candidate &&
29+
typeof candidate.name === 'string' &&
30+
'tasks' in candidate &&
31+
typeof candidate.tasks === 'object'
32+
);
33+
};
34+
35+
const isTranslationTask = (obj: unknown): obj is TranslationTask => {
36+
if (!obj || typeof obj !== 'object') return false;
37+
const candidate = obj as Record<string, unknown>;
38+
return (
39+
'name' in candidate &&
40+
typeof candidate.name === 'string' &&
41+
'groups' in candidate &&
42+
typeof candidate.groups === 'object'
43+
);
44+
};
45+
46+
const isTranslationGroup = (obj: unknown): obj is TranslationGroup => {
47+
if (!obj || typeof obj !== 'object') return false;
48+
const candidate = obj as Record<string, unknown>;
49+
return (
50+
'name' in candidate &&
51+
typeof candidate.name === 'string' &&
52+
'items' in candidate &&
53+
typeof candidate.items === 'object' &&
54+
(!('help' in candidate) || typeof candidate.help === 'string')
55+
);
56+
};
57+
58+
const isTranslationItem = (obj: unknown): obj is TranslationItem => {
59+
if (!obj || typeof obj !== 'object') return false;
60+
const candidate = obj as Record<string, unknown>;
61+
const keys = Object.keys(candidate);
62+
return (
63+
keys.length >= 1 &&
64+
keys.length <= 3 &&
65+
'name' in candidate &&
66+
typeof candidate.name === 'string' &&
67+
keys.every((key) => ['name', 'help', 'options'].includes(key))
68+
);
69+
};
70+
2471
export const useIstStore = defineStore('instance', {
2572
state: () => ({
2673
layout: {} as Layout,
@@ -54,18 +101,6 @@ export const useIstStore = defineStore('instance', {
54101
return null;
55102
}
56103

57-
// Type guard functions for translation interfaces
58-
const isTranslationMenu = (obj: unknown): obj is TranslationMenu =>
59-
obj !== null && typeof obj === 'object' && 'tasks' in obj;
60-
const isTranslationTask = (obj: unknown): obj is TranslationTask =>
61-
obj !== null && typeof obj === 'object' && 'groups' in obj;
62-
const isTranslationGroup = (obj: unknown): obj is TranslationGroup =>
63-
obj !== null && typeof obj === 'object' && 'items' in obj;
64-
const isTranslationItem = (obj: unknown): obj is TranslationItem =>
65-
obj !== null &&
66-
typeof obj === 'object' &&
67-
('name' in obj || 'options' in obj);
68-
69104
if (isTranslationMenu(current)) {
70105
if (key === 'name') {
71106
current = current.name;
@@ -368,19 +403,21 @@ export const useSettingsStore = defineStore('settings', {
368403
async loadSettings(i18n: Composer, quasar: QVueGlobals) {
369404
try {
370405
const settings = await fetchSettings();
371-
406+
372407
// If language is empty/null, auto-detect language based on system
373408
if (!settings.language) {
374409
const locale = quasar.lang.getLocale() || 'en-US';
375-
const lang = locale.toLowerCase().startsWith('zh') ? 'zh-CN' : 'en-US';
410+
const lang = locale.toLowerCase().startsWith('zh')
411+
? 'zh-CN'
412+
: 'en-US';
376413
this.language = lang as MessageLanguages;
377414
// Save the auto-detected language
378415
await this.setLanguage(this.language, i18n);
379416
} else {
380417
// Use saved language setting with type validation
381418
const validLanguages = ['zh-CN', 'en-US'];
382-
const savedLang = validLanguages.includes(settings.language)
383-
? settings.language as MessageLanguages
419+
const savedLang = validLanguages.includes(settings.language)
420+
? (settings.language as MessageLanguages)
384421
: 'en-US';
385422
this.language = savedLang;
386423
i18n.locale.value = savedLang;
@@ -396,11 +433,11 @@ export const useSettingsStore = defineStore('settings', {
396433
// Validate settings
397434
const validTriggers = ['scheduler_end', 'scheduled'];
398435
const validTypes = ['none', 'close_app', 'hibernate', 'shutdown'];
399-
436+
400437
if (!validTriggers.includes(this.autoActionTrigger)) {
401438
await this.setAutoActionTrigger('scheduler_end');
402439
}
403-
440+
404441
if (!validTypes.includes(this.autoActionType)) {
405442
await this.setAutoActionType('none');
406443
}

0 commit comments

Comments
 (0)