refactor: 优化 i18n 类型安全与渲染性能
- 导出 TranslationKey 类型,翻译 key 拼写错误编译期即报错 - zh.ts 使用 TranslationKey 约束,确保中英文 key 同步 - useMemo 包装 context value,避免不必要的全局重渲染 - ConfirmDialog confirmText 默认值改用 t() 而非硬编码英文 - SchemaProperties 递归组件改为 prop 传递 t,减少 useContext 调用 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -11,7 +11,7 @@ type ConfirmDialogProps = {
|
||||
variant?: 'danger' | 'warning';
|
||||
};
|
||||
|
||||
export default function ConfirmDialog({ open, onConfirm, onCancel, title, description, confirmText = 'Confirm', variant = 'danger' }: ConfirmDialogProps) {
|
||||
export default function ConfirmDialog({ open, onConfirm, onCancel, title, description, confirmText, variant = 'danger' }: ConfirmDialogProps) {
|
||||
const { t } = useI18n();
|
||||
const iconColor = variant === 'danger' ? 'text-danger bg-danger-muted' : 'text-warning bg-warning-muted';
|
||||
|
||||
@@ -35,7 +35,7 @@ export default function ConfirmDialog({ open, onConfirm, onCancel, title, descri
|
||||
onClick={onConfirm}
|
||||
className={variant === 'danger' ? 'btn-danger' : 'btn-primary'}
|
||||
>
|
||||
{confirmText}
|
||||
{confirmText ?? t('common.confirm')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Replaces raw JSON.stringify output with readable tables and schema trees.
|
||||
*/
|
||||
|
||||
import { useI18n } from '../lib/i18n';
|
||||
import { useI18n, type TFunction } from '../lib/i18n';
|
||||
|
||||
/* ===== Helpers ===== */
|
||||
|
||||
@@ -159,8 +159,7 @@ export function ParametersView({ parameters }: { parameters: unknown }) {
|
||||
|
||||
/* ===== Schema Properties Tree ===== */
|
||||
|
||||
function SchemaProperties({ schema, depth = 0 }: { schema: SchemaObj; depth?: number }) {
|
||||
const { t } = useI18n();
|
||||
function SchemaProperties({ schema, depth = 0, t }: { schema: SchemaObj; depth?: number; t: TFunction }) {
|
||||
const properties = schema.properties;
|
||||
const requiredSet = new Set(schema.required || []);
|
||||
|
||||
@@ -217,8 +216,8 @@ function SchemaProperties({ schema, depth = 0 }: { schema: SchemaObj; depth?: nu
|
||||
{t('dashboard.schema.default')} <code className="font-mono">{JSON.stringify(prop.default)}</code>
|
||||
</div>
|
||||
)}
|
||||
{hasChildren && <SchemaProperties schema={prop} depth={depth + 1} />}
|
||||
{isArray && prop.items && <SchemaProperties schema={prop.items} depth={depth + 1} />}
|
||||
{hasChildren && <SchemaProperties schema={prop} depth={depth + 1} t={t} />}
|
||||
{isArray && prop.items && <SchemaProperties schema={prop.items} depth={depth + 1} t={t} />}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
@@ -247,7 +246,7 @@ export function RequestBodyView({ requestBody }: { requestBody: unknown }) {
|
||||
{body.required && <span className="text-danger ml-2 normal-case tracking-normal text-[11px]">{t('dashboard.schema.required')}</span>}
|
||||
</p>
|
||||
<div className="border border-border-default rounded-lg p-3">
|
||||
<SchemaProperties schema={body.schema} />
|
||||
<SchemaProperties schema={body.schema} t={t} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -274,7 +273,7 @@ export function RequestBodyView({ requestBody }: { requestBody: unknown }) {
|
||||
<div className="p-3">
|
||||
{media.schema ? (
|
||||
media.schema.properties ? (
|
||||
<SchemaProperties schema={media.schema} />
|
||||
<SchemaProperties schema={media.schema} t={t} />
|
||||
) : (
|
||||
<div className="flex items-center gap-2 text-[13px]">
|
||||
<TypeBadge type={resolveType(media.schema)} />
|
||||
@@ -351,13 +350,13 @@ export function ResponsesView({ responses }: { responses: unknown }) {
|
||||
{schema && (schema.properties || schema.items?.properties || schema.type) && (
|
||||
<div className="p-3">
|
||||
{schema.properties ? (
|
||||
<SchemaProperties schema={schema} />
|
||||
<SchemaProperties schema={schema} t={t} />
|
||||
) : schema.type === 'array' && schema.items?.properties ? (
|
||||
<div>
|
||||
<div className="text-[11px] text-text-muted mb-1">
|
||||
<TypeBadge type="array" /> {t('dashboard.schema.ofObjects')}
|
||||
</div>
|
||||
<SchemaProperties schema={schema.items} />
|
||||
<SchemaProperties schema={schema.items} t={t} />
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center gap-2 text-[13px]">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useTheme } from '../lib/theme';
|
||||
import { useI18n } from '../lib/i18n';
|
||||
import { useI18n, type TranslationKey } from '../lib/i18n';
|
||||
|
||||
const icons = {
|
||||
light: (
|
||||
@@ -31,7 +31,7 @@ export default function ThemeToggle() {
|
||||
<button
|
||||
key={key}
|
||||
onClick={() => setTheme(key)}
|
||||
title={t(`theme.${key}`)}
|
||||
title={t(`theme.${key}` as TranslationKey)}
|
||||
className={`flex items-center justify-center w-8 h-7 rounded-md transition-all duration-150 ${
|
||||
theme === key
|
||||
? 'bg-bg-elevated text-text-primary shadow-sm'
|
||||
|
||||
Reference in New Issue
Block a user