feat: '🔄 Neu übersetzen' im Review-Modal (überschreibt Zielsprachen)

Ruft /pairs/:id/translate mit overwrite:true, um falsche bestehende
Übersetzungen (z.B. SV) neu zu generieren, und lädt den Modal-Inhalt neu.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-05 21:29:20 +02:00
parent 4fd9c3c4e4
commit 350614d6e0
2 changed files with 26 additions and 3 deletions

View File

@@ -59,13 +59,22 @@ function buildRows(content) {
return rows; return rows;
} }
export default function PairReviewModal({ pair, content, onClose, onDone }) { export default function PairReviewModal({ pair, content, onClose, onDone, onRetranslate }) {
const [busy, setBusy] = useState(null); // 'review' | 'block' const [busy, setBusy] = useState(null); // 'review' | 'block' | 'retranslate'
const [missing, setMissing] = useState(null); const [missing, setMissing] = useState(null);
const [error, setError] = useState(null); const [error, setError] = useState(null);
const rows = buildRows(content); const rows = buildRows(content);
async function handleRetranslate() {
setBusy('retranslate'); setMissing(null); setError(null);
try {
await onRetranslate();
} catch (e) {
setError(e.message);
} finally { setBusy(null); }
}
async function handleReview() { async function handleReview() {
setBusy('review'); setMissing(null); setError(null); setBusy('review'); setMissing(null); setError(null);
try { try {
@@ -129,7 +138,15 @@ export default function PairReviewModal({ pair, content, onClose, onDone }) {
)} )}
{/* Footer — Aktionen */} {/* Footer — Aktionen */}
<div className="flex items-center justify-end gap-2 px-6 py-4 border-t border-slate-200"> <div className="flex items-center gap-2 px-6 py-4 border-t border-slate-200">
{onRetranslate && (
<button onClick={handleRetranslate} disabled={!!busy}
className="px-4 py-2 text-sm font-medium rounded-lg bg-indigo-50 text-indigo-700 hover:bg-indigo-100 disabled:opacity-40"
title="Alle Zielsprachen neu übersetzen (überschreibt vorhandene)">
{busy === 'retranslate' ? 'Läuft …' : '🔄 Neu übersetzen'}
</button>
)}
<div className="flex-1" />
<button onClick={onClose} disabled={!!busy} <button onClick={onClose} disabled={!!busy}
className="px-4 py-2 text-sm rounded-lg text-slate-500 hover:bg-slate-100 disabled:opacity-40">Abbrechen</button> className="px-4 py-2 text-sm rounded-lg text-slate-500 hover:bg-slate-100 disabled:opacity-40">Abbrechen</button>
<button onClick={handleBlock} disabled={!!busy} <button onClick={handleBlock} disabled={!!busy}

View File

@@ -1189,6 +1189,11 @@ function PairsPanel({ selectedObject, allObjects, objectPairs, loadingPairs, onP
} finally { setTranslatingId(null); } } finally { setTranslatingId(null); }
} }
async function handleRetranslate(pair) {
const res = await apiPost(`/pairs/${pair.id}/translate`, { overwrite: true });
setReviewData({ pair, content: res.content });
}
if (!selectedObject) { if (!selectedObject) {
return ( return (
<aside className="w-2/5 border-l border-slate-200 bg-white flex items-center justify-center"> <aside className="w-2/5 border-l border-slate-200 bg-white flex items-center justify-center">
@@ -1274,6 +1279,7 @@ function PairsPanel({ selectedObject, allObjects, objectPairs, loadingPairs, onP
content={reviewData.content} content={reviewData.content}
onClose={() => setReviewData(null)} onClose={() => setReviewData(null)}
onDone={() => { setReviewData(null); (onReloadAll || onPairsReload)(); }} onDone={() => { setReviewData(null); (onReloadAll || onPairsReload)(); }}
onRetranslate={() => handleRetranslate(reviewData.pair)}
/> />
)} )}
</aside> </aside>