'use client' import { useState, useRef } from 'react' const API_BASE = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:8000' const LANGUAGES = [ { code: 'auto', name: '自动检测' }, { code: 'zh', name: '中文' }, { code: 'en', name: '英语' }, { code: 'ja', name: '日语' }, { code: 'ko', name: '韩语' }, { code: 'fr', name: '法语' }, { code: 'de', name: '德语' }, { code: 'es', name: '西班牙语' }, ] const STYLES = [ { value: 'literal', name: '直译' }, { value: 'fluent', name: '意译' }, { value: 'casual', name: '口语化' }, ] export default function TranslatorForm() { const [sourceText, setSourceText] = useState('') const [translation, setTranslation] = useState('') const [sourceLang, setSourceLang] = useState('auto') const [targetLang, setTargetLang] = useState('zh') const [style, setStyle] = useState('literal') const [isLoading, setIsLoading] = useState(false) const [error, setError] = useState('') const abortRef = useRef(null) const handleTranslate = async () => { if (!sourceText.trim()) return if (abortRef.current) { abortRef.current.abort() } abortRef.current = new AbortController() setIsLoading(true) setError('') setTranslation('') try { const res = await fetch(`${API_BASE}/api/v1/translate/stream`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ source_text: sourceText, source_lang: sourceLang, target_lang: targetLang, style, }), signal: abortRef.current.signal, }) if (!res.ok) { throw new Error('翻译请求失败') } const reader = res.body?.getReader() const decoder = new TextDecoder() let buffer = '' while (reader) { const { value, done } = await reader.read() if (done) break buffer += decoder.decode(value, { stream: true }) const parts = buffer.split('\n\n') buffer = parts.pop() ?? '' for (const p of parts) { const lines = p.split('\n') const dataLine = lines.find(l => l.startsWith('data:')) if (dataLine) { const data = JSON.parse(dataLine.slice(5).trim()) if (data.delta) { setTranslation(prev => prev + data.delta) } } } } } catch (err: unknown) { if (err instanceof Error && err.name !== 'AbortError') { setError(err.message || '翻译失败') } } finally { setIsLoading(false) } } const handleStop = () => { if (abortRef.current) { abortRef.current.abort() setIsLoading(false) } } const handleCopy = () => { navigator.clipboard.writeText(translation) } return (
{/* 源语言选择 */}
{/* 目标语言选择 */}
{/* 风格选择 */}
{STYLES.map((s) => ( ))}
{/* 输入输出区域 */}