feat(frontend): 控制台 next-intl 中英双语

接入无 URL 前缀的 zh-CN/en,顶栏与外观设置可切换语言;选择写入 cookie 后刷新生效。
This commit is contained in:
ryan
2026-08-16 16:49:16 +08:00
parent 64fbaa7ef1
commit 5a8722ff07
219 changed files with 21437 additions and 5212 deletions
@@ -25,37 +25,17 @@ import {
} from '@/components/ui/select';
import type { ProxyRouteItem } from '@/lib/services/openflare';
import { useTranslations } from 'next-intl';
import { proxyRouteFormIds } from '../helpers';
import { useRouteSectionSave } from '../hooks/use-route-section-save';
import { SectionShell } from './section-shell';
const authSchema = z
.object({
auth_mode: z.enum(['none', 'basic']),
basic_auth_username: z.string(),
basic_auth_password: z.string(),
})
.superRefine((value, context) => {
if (value.auth_mode !== 'basic') {
return;
}
if (!value.basic_auth_username.trim()) {
context.addIssue({
code: z.ZodIssueCode.custom,
path: ['basic_auth_username'],
message: '请输入账号',
});
}
if (!value.basic_auth_password.trim()) {
context.addIssue({
code: z.ZodIssueCode.custom,
path: ['basic_auth_password'],
message: '请输入密码',
});
}
});
type AuthValues = z.infer<typeof authSchema>;
type AuthValues = {
auth_mode: 'none' | 'basic';
basic_auth_username: string;
basic_auth_password: string;
};
function resolveAuthMode(route: ProxyRouteItem): AuthValues['auth_mode'] {
return route.basic_auth_enabled ? 'basic' : 'none';
@@ -72,6 +52,32 @@ export function AuthSection({
onRouteUpdate,
onSavingChange,
}: AuthSectionProps) {
const t = useTranslations('proxyRoutes');
const authSchema = z
.object({
auth_mode: z.enum(['none', 'basic']),
basic_auth_username: z.string(),
basic_auth_password: z.string(),
})
.superRefine((value, context) => {
if (value.auth_mode !== 'basic') {
return;
}
if (!value.basic_auth_username.trim()) {
context.addIssue({
code: z.ZodIssueCode.custom,
path: ['basic_auth_username'],
message: t('validation.enterUsername'),
});
}
if (!value.basic_auth_password.trim()) {
context.addIssue({
code: z.ZodIssueCode.custom,
path: ['basic_auth_password'],
message: t('validation.enterPassword'),
});
}
});
const { saving, save } = useRouteSectionSave(
route,
onRouteUpdate,
@@ -99,8 +105,8 @@ export function AuthSection({
return (
<SectionShell
title='认证配置'
description='配置 Basic Auth 限制未授权访问。PoW 防护请在 WAF 规则组中配置。'
title={t('auth')}
description={t('authDesc')}
formId={proxyRouteFormIds.auth}
saving={saving}
>
@@ -122,11 +128,11 @@ export function AuthSection({
? values.basic_auth_password.trim()
: '',
},
'认证配置已保存',
t('authSaved'),
);
},
() => {
toast.error('请检查认证配置表单');
toast.error(t('authFormInvalid'));
},
)}
>
@@ -135,7 +141,7 @@ export function AuthSection({
name='auth_mode'
render={({ field }) => (
<FormItem>
<FormLabel>认证模式</FormLabel>
<FormLabel>{t('authMode')}</FormLabel>
<Select
value={field.value}
onValueChange={(mode) => {
@@ -152,12 +158,12 @@ export function AuthSection({
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value='none'>无认证</SelectItem>
<SelectItem value='none'>{t('authNone')}</SelectItem>
<SelectItem value='basic'>Basic Auth</SelectItem>
</SelectContent>
</Select>
<FormDescription>
PoW 防护仅支持在 WAF 规则组中启用并绑定站点。
{t('powHint')}
</FormDescription>
<FormMessage />
</FormItem>
@@ -171,7 +177,7 @@ export function AuthSection({
name='basic_auth_username'
render={({ field }) => (
<FormItem>
<FormLabel>账号</FormLabel>
<FormLabel>{t('username')}</FormLabel>
<FormControl>
<Input placeholder='admin' {...field} />
</FormControl>
@@ -185,7 +191,7 @@ export function AuthSection({
name='basic_auth_password'
render={({ field }) => (
<FormItem>
<FormLabel>密码</FormLabel>
<FormLabel>{t('password')}</FormLabel>
<FormControl>
<Input type='text' placeholder='secret123' {...field} />
</FormControl>