feat: add translated PDF export with layout preservation

Adds the ability to download translated documents as PDF files while
preserving the original document layout. Key changes:

- Add apply_translations() function to merge translation JSON with UnifiedDocument
- Add generate_translated_pdf() method to PDFGeneratorService
- Add POST /api/v2/translate/{task_id}/pdf endpoint
- Add downloadTranslatedPdf() method and PDF button in frontend
- Add comprehensive unit tests (52 tests: merge, PDF generation, API endpoints)
- Archive add-translated-pdf-export proposal

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
egg
2025-12-02 12:33:31 +08:00
parent 8d9b69ba93
commit a07aad96b3
15 changed files with 2663 additions and 2 deletions

View File

@@ -25,7 +25,8 @@ import {
Languages,
Globe,
CheckCircle,
Trash2
Trash2,
FileOutput
} from 'lucide-react'
import type { ProcessingTrack, TranslationStatus, TranslationListItem } from '@/types/apiV2'
import { Badge } from '@/components/ui/badge'
@@ -327,6 +328,24 @@ export default function TaskDetailPage() {
}
}
const handleDownloadTranslatedPdf = async (lang: string) => {
if (!taskId) return
try {
await apiClientV2.downloadTranslatedPdf(taskId, lang)
toast({
title: '下載成功',
description: `翻譯 PDF (${lang}) 已下載`,
variant: 'success',
})
} catch (error: any) {
toast({
title: '下載失敗',
description: error.response?.data?.detail || t('errors.networkError'),
variant: 'destructive',
})
}
}
const getStatusBadge = (status: string) => {
switch (status) {
case 'completed':
@@ -603,7 +622,16 @@ export default function TaskDetailPage() {
className="gap-1"
>
<Download className="w-3 h-3" />
JSON
</Button>
<Button
variant="default"
size="sm"
onClick={() => handleDownloadTranslatedPdf(item.target_lang)}
className="gap-1"
>
<FileOutput className="w-3 h-3" />
PDF
</Button>
<Button
variant="ghost"