mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-13 10:26:38 +08:00
feat(frontend): 控制台 next-intl 中英双语
接入无 URL 前缀的 zh-CN/en,顶栏与外观设置可切换语言;选择写入 cookie 后刷新生效。
This commit is contained in:
@@ -13,6 +13,8 @@ import { LoadingStateWithBorder } from '@/components/layout/loading';
|
||||
import { previewOriginErrorPageHTML } from '@/lib/openflare/default-origin-error-page-html';
|
||||
import { OptionService } from '@/lib/services/openflare';
|
||||
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
import {
|
||||
mapOptionsToErrorFields,
|
||||
OPTIONS_QUERY_KEY,
|
||||
@@ -20,6 +22,7 @@ import {
|
||||
} from '../../components/shared';
|
||||
|
||||
export default function ErrorPagePreviewPage() {
|
||||
const t = useTranslations('responses');
|
||||
const { user, loading: authLoading } = useAuth();
|
||||
|
||||
const optionsQuery = useQuery({
|
||||
@@ -38,7 +41,7 @@ export default function ErrorPagePreviewPage() {
|
||||
if (authLoading) {
|
||||
return (
|
||||
<div className='w-full py-6 px-1'>
|
||||
<LoadingStateWithBorder description='加载权限信息...' />
|
||||
<LoadingStateWithBorder description={t('loadingPermission')} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -47,8 +50,8 @@ export default function ErrorPagePreviewPage() {
|
||||
return (
|
||||
<div className='w-full py-6 px-1'>
|
||||
<EmptyStateWithBorder
|
||||
title='权限不足'
|
||||
description='只有管理员可以预览错误页。'
|
||||
title={t('forbidden')}
|
||||
description={t('forbiddenPreviewError')}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -57,7 +60,7 @@ export default function ErrorPagePreviewPage() {
|
||||
if (optionsQuery.isLoading) {
|
||||
return (
|
||||
<div className='w-full py-6 px-1'>
|
||||
<LoadingStateWithBorder description='加载错误页配置...' />
|
||||
<LoadingStateWithBorder description={t('loadingErrorConfig')} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -69,7 +72,7 @@ export default function ErrorPagePreviewPage() {
|
||||
message={
|
||||
optionsQuery.error instanceof Error
|
||||
? optionsQuery.error.message
|
||||
: '加载失败'
|
||||
: t('loadFailed')
|
||||
}
|
||||
onRetry={() => void optionsQuery.refetch()}
|
||||
/>
|
||||
@@ -82,14 +85,14 @@ export default function ErrorPagePreviewPage() {
|
||||
<div className='flex items-center justify-between gap-3 border-b bg-background/95 px-4 py-2 backdrop-blur shrink-0'>
|
||||
<div className='flex items-center gap-2 min-w-0'>
|
||||
<Button variant='outline' size='icon' className='h-8 w-8' asChild>
|
||||
<Link href='/responses?tab=error' aria-label='返回错误页'>
|
||||
<Link href='/responses?tab=error' aria-label={t('backToError')}>
|
||||
<ArrowLeft className='size-4' />
|
||||
</Link>
|
||||
</Button>
|
||||
<div className='min-w-0'>
|
||||
<p className='text-sm font-semibold truncate'>错误页预览</p>
|
||||
<p className='text-sm font-semibold truncate'>{t('errorPreview')}</p>
|
||||
<p className='text-[11px] text-muted-foreground font-mono truncate'>
|
||||
{'{{status}}'}→502 · {'{{host}}'}→example.com · 全屏展示
|
||||
{'{{status}}'}→502 · {'{{host}}'}→example.com · {t('fullscreen')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -97,18 +100,18 @@ export default function ErrorPagePreviewPage() {
|
||||
<Button variant='outline' size='sm' asChild>
|
||||
<Link href='/responses/error-page/edit'>
|
||||
<Pencil className='size-3.5' />
|
||||
编辑
|
||||
{t('edit')}
|
||||
</Link>
|
||||
</Button>
|
||||
<Button variant='ghost' size='icon' className='h-8 w-8' asChild>
|
||||
<Link href='/responses?tab=error' aria-label='关闭预览'>
|
||||
<Link href='/responses?tab=error' aria-label={t('closePreview')}>
|
||||
<X className='size-4' />
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<iframe
|
||||
title='源站错误页预览'
|
||||
title={t('errorPagePreview')}
|
||||
sandbox=''
|
||||
srcDoc={previewSrcDoc}
|
||||
className='flex-1 w-full border-0 bg-background min-h-0'
|
||||
|
||||
Reference in New Issue
Block a user