feat: Support i18n

This commit is contained in:
2026-02-05 13:59:13 +08:00
parent ff0a7dc1a8
commit 2f53e14a26
87 changed files with 4290 additions and 358 deletions

View File

@@ -1,4 +1,5 @@
import { memo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import type { Job } from '@/types/job'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
@@ -28,17 +29,19 @@ const jobTypeBadgeVariant = {
voice_clone: 'outline' as const,
}
const jobTypeLabel = {
custom_voice: '自定义音色',
voice_design: '音色设计',
voice_clone: '声音克隆',
}
const HistoryItem = memo(({ job, onDelete }: HistoryItemProps) => {
const { t } = useTranslation('job')
const { t: tCommon } = useTranslation('common')
const [detailDialogOpen, setDetailDialogOpen] = useState(false)
const jobTypeLabel = {
custom_voice: t('typeCustomVoice'),
voice_design: t('typeVoiceDesign'),
voice_clone: t('typeVoiceClone'),
}
const getLanguageDisplay = (lang: string | undefined) => {
if (!lang || lang === 'Auto') return '自动检测'
if (!lang || lang === 'Auto') return t('autoDetect')
return lang
}
@@ -68,31 +71,31 @@ const HistoryItem = memo(({ job, onDelete }: HistoryItemProps) => {
<div className="space-y-2 text-sm">
{job.parameters?.text && (
<div>
<span className="text-muted-foreground">: </span>
<span className="text-muted-foreground">{t('synthesisText')}: </span>
<span className="line-clamp-2">{job.parameters.text}</span>
</div>
)}
<div className="text-muted-foreground">
: {getLanguageDisplay(job.parameters?.language)}
{t('language')}{getLanguageDisplay(job.parameters?.language)}
</div>
{job.type === 'custom_voice' && job.parameters?.speaker && (
<div className="text-muted-foreground">
: {job.parameters.speaker}
{t('speaker')}{job.parameters.speaker}
</div>
)}
{job.type === 'voice_design' && job.parameters?.instruct && (
<div>
<span className="text-muted-foreground">: </span>
<span className="text-muted-foreground">{t('voiceDescription')}: </span>
<span className="text-xs line-clamp-2">{job.parameters.instruct}</span>
</div>
)}
{job.type === 'voice_clone' && job.parameters?.ref_text && (
<div>
<span className="text-muted-foreground">: </span>
<span className="text-muted-foreground">{t('referenceText')}: </span>
<span className="text-xs line-clamp-1">{job.parameters.ref_text}</span>
</div>
)}
@@ -101,14 +104,14 @@ const HistoryItem = memo(({ job, onDelete }: HistoryItemProps) => {
{job.status === 'processing' && (
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<Loader2 className="w-4 h-4 animate-spin" />
<span>...</span>
<span>{t('statusProcessing')}</span>
</div>
)}
{job.status === 'pending' && (
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<Clock className="w-4 h-4" />
<span>...</span>
<span>{t('statusPending')}</span>
</div>
)}
@@ -132,18 +135,18 @@ const HistoryItem = memo(({ job, onDelete }: HistoryItemProps) => {
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle></AlertDialogTitle>
<AlertDialogTitle>{t('deleteJob')}</AlertDialogTitle>
<AlertDialogDescription>
{t('deleteJobConfirm')}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel></AlertDialogCancel>
<AlertDialogCancel>{tCommon('cancel')}</AlertDialogCancel>
<AlertDialogAction
onClick={() => onDelete(job.id)}
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
>
{tCommon('delete')}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>