feat: add default language configuration

This commit is contained in:
shiyu
2026-04-19 16:42:19 +08:00
parent 398dbcf8ae
commit 1101273077
17 changed files with 165 additions and 59 deletions

View File

@@ -66,7 +66,7 @@ export default function SystemSettingsPage({ tabKey, onTabNavigate }: SystemSett
});
}, [t]);
const handleSave = async (values: Record<string, unknown>) => {
const handleSave = async (values: Record<string, unknown>): Promise<boolean> => {
setLoading(true);
try {
for (const [key, value] of Object.entries(values)) {
@@ -81,10 +81,13 @@ export default function SystemSettingsPage({ tabKey, onTabNavigate }: SystemSett
if (Object.keys(values).some(k => Object.values(THEME_KEYS).includes(k))) {
await refreshTheme();
}
return true;
} catch (e: any) {
message.error(e.message || t('Save failed'));
return false;
} finally {
setLoading(false);
}
setLoading(false);
};
// 离开“外观设置”时,恢复后端持久化配置(取消未保存的预览)

View File

@@ -2,6 +2,7 @@ import { Alert, Button, Divider, Form, Input, Select, Switch, message } from 'an
import { useEffect, useMemo, useState } from 'react';
import { rolesApi, type RoleInfo } from '../../../api/roles';
import { useI18n } from '../../../i18n';
import { normalizeLang, readStoredLang } from '../../../i18n/lang';
interface AppConfigKey {
key: string;
@@ -12,7 +13,7 @@ interface AppConfigKey {
interface AppSettingsTabProps {
config: Record<string, string>;
loading: boolean;
onSave: (values: Record<string, unknown>) => Promise<void>;
onSave: (values: Record<string, unknown>) => Promise<boolean>;
configKeys: AppConfigKey[];
}
@@ -22,7 +23,7 @@ export default function AppSettingsTab({
onSave,
configKeys,
}: AppSettingsTabProps) {
const { t } = useI18n();
const { t, setLang } = useI18n();
const [rolesLoading, setRolesLoading] = useState(false);
const [roles, setRoles] = useState<RoleInfo[]>([]);
@@ -52,6 +53,7 @@ export default function AppSettingsTab({
const roleId = roleIdRaw ? Number(roleIdRaw) : undefined;
return {
...Object.fromEntries(configKeys.map(({ key, default: def }) => [key, config[key] ?? def ?? ''])),
APP_DEFAULT_LANGUAGE: normalizeLang(config.APP_DEFAULT_LANGUAGE, 'zh'),
AUTH_ALLOW_REGISTER: allowRegister,
AUTH_DEFAULT_REGISTER_ROLE_ID: Number.isFinite(roleId) ? roleId : undefined,
};
@@ -66,12 +68,17 @@ export default function AppSettingsTab({
for (const { key } of configKeys) {
payload[key] = vals[key];
}
const defaultLanguage = normalizeLang(vals.APP_DEFAULT_LANGUAGE, 'zh');
payload.APP_DEFAULT_LANGUAGE = defaultLanguage;
const allow = !!vals.AUTH_ALLOW_REGISTER;
payload.AUTH_ALLOW_REGISTER = allow ? 'true' : 'false';
if (allow) {
payload.AUTH_DEFAULT_REGISTER_ROLE_ID = String(vals.AUTH_DEFAULT_REGISTER_ROLE_ID);
}
await onSave(payload);
const saved = await onSave(payload);
if (saved && !readStoredLang()) {
setLang(defaultLanguage, { persist: false });
}
}}
style={{ marginTop: 24 }}
key={JSON.stringify(config)}
@@ -82,6 +89,20 @@ export default function AppSettingsTab({
</Form.Item>
))}
<Form.Item
name="APP_DEFAULT_LANGUAGE"
label={t('Default Language')}
extra={t('Used when the user has not selected a language')}
>
<Select
size="large"
options={[
{ value: 'zh', label: t('Chinese') },
{ value: 'en', label: t('English') },
]}
/>
</Form.Item>
<Divider titlePlacement="left">{t('Registration Settings')}</Divider>
<Alert

View File

@@ -13,7 +13,7 @@ interface ThemeKeyMap {
interface AppearanceSettingsTabProps {
config: Record<string, string>;
loading: boolean;
onSave: (values: Record<string, unknown>) => Promise<void>;
onSave: (values: Record<string, unknown>) => Promise<boolean>;
themeKeys: ThemeKeyMap;
}

View File

@@ -28,7 +28,7 @@ import {
interface EmailSettingsTabProps {
config: Record<string, string>;
loading: boolean;
onSave: (values: Record<string, unknown>) => Promise<void>;
onSave: (values: Record<string, unknown>) => Promise<boolean>;
}
interface EmailFormValues {

View File

@@ -5,7 +5,7 @@ import { useI18n } from '../../../i18n';
interface ProtocolMappingsTabProps {
config: Record<string, string>;
loading: boolean;
onSave: (values: Record<string, unknown>) => Promise<void>;
onSave: (values: Record<string, unknown>) => Promise<boolean>;
}
const WEBDAV_KEY = 'WEBDAV_MAPPING_ENABLED';