From 8154f08e044983051d5330a21323fd95312255c8 Mon Sep 17 00:00:00 2001 From: admin Date: Fri, 12 Jun 2026 21:58:28 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20index.html=20nicht=20cachen=20+=20unaufg?= =?UTF-8?q?el=C3=B6ste=20=E2=9F=A6PHn:wort=E2=9F=A7-Tokens=20defensiv=20an?= =?UTF-8?q?zeigen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - nginx: Cache-Control no-cache für index.html — Browser hingen sonst auf alten JS-Bundles (gehashte Assets bleiben immutable gecacht) - Karten: Pipeline-Tokens ⟦PHn:wort⟧ aus der Übersetzung werden als blankes Wort gerendert/gesprochen statt roh angezeigt (Datenfix gehört ins Backend) Co-Authored-By: Claude Fable 5 --- nginx.conf | 3 ++- src/components/PairSentenceCard.jsx | 6 +++++- src/components/PairWordCard.jsx | 2 ++ src/components/PairYesNoCard.jsx | 2 ++ 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/nginx.conf b/nginx.conf index 956537b..f6fc60e 100644 --- a/nginx.conf +++ b/nginx.conf @@ -4,9 +4,10 @@ server { root /usr/share/nginx/html; index index.html; - # SPA fallback + # SPA fallback — index.html nie cachen, sonst hängen Browser auf alten Bundles location / { try_files $uri $uri/ /index.html; + add_header Cache-Control "no-cache"; } # Cache static assets diff --git a/src/components/PairSentenceCard.jsx b/src/components/PairSentenceCard.jsx index 95e4270..4331a72 100644 --- a/src/components/PairSentenceCard.jsx +++ b/src/components/PairSentenceCard.jsx @@ -53,6 +53,8 @@ function SelectionOverlay({ chip }) { // Sentence format: {{label.w:uuid}} or {{label.o:uuid}} function resolveSentence(sentence, placeholders, onChipClick, activeId) { if (!sentence) return null + // Unaufgelöste Pipeline-Tokens (⟦PHn:wort⟧) defensiv als blankes Wort anzeigen + sentence = sentence.replace(/[⟦〚]PH\d+:([^⟧〛]*)[⟧〛]/g, '$1') const parts = sentence.split(/(\{\{[^}]+\.[wo]:[0-9a-f-]{36}\}\})/) return parts.map((part, i) => { const m = part.match(/^\{\{([^.]+)\.(w|o):([0-9a-f-]{36})\}\}$/) @@ -88,7 +90,9 @@ function extractVocab(sentence) { // Strip placeholders to plain text for TTS function toPlainText(sentence) { if (!sentence) return '' - return sentence.replace(/\{\{([^.]+)\.[wo]:[0-9a-f-]{36}\}\}/g, '$1') + return sentence + .replace(/\{\{([^.]+)\.[wo]:[0-9a-f-]{36}\}\}/g, '$1') + .replace(/[⟦〚]PH\d+:([^⟧〛]*)[⟧〛]/g, '$1') } const LANG_LABELS = { sv: 'Svenska', en: 'English', de: 'Deutsch' } diff --git a/src/components/PairWordCard.jsx b/src/components/PairWordCard.jsx index 362daf1..aea13b4 100644 --- a/src/components/PairWordCard.jsx +++ b/src/components/PairWordCard.jsx @@ -53,6 +53,8 @@ function SelectionOverlay({ chip }) { // Sentence format: {{label.w:uuid}} or {{label.o:uuid}} function resolveSentence(sentence, placeholders, onChipClick, activeId) { if (!sentence) return null + // Unaufgelöste Pipeline-Tokens (⟦PHn:wort⟧) defensiv als blankes Wort anzeigen + sentence = sentence.replace(/[⟦〚]PH\d+:([^⟧〛]*)[⟧〛]/g, '$1') const parts = sentence.split(/(\{\{[^}]+\.[wo]:[0-9a-f-]{36}\}\})/) return parts.map((part, i) => { const m = part.match(/^\{\{([^.]+)\.(w|o):([0-9a-f-]{36})\}\}$/) diff --git a/src/components/PairYesNoCard.jsx b/src/components/PairYesNoCard.jsx index e1301ff..833b3b7 100644 --- a/src/components/PairYesNoCard.jsx +++ b/src/components/PairYesNoCard.jsx @@ -53,6 +53,8 @@ function SelectionOverlay({ chip }) { // Sentence format: {{label.w:uuid}} or {{label.o:uuid}} function resolveSentence(sentence, placeholders, onChipClick, activeId) { if (!sentence) return null + // Unaufgelöste Pipeline-Tokens (⟦PHn:wort⟧) defensiv als blankes Wort anzeigen + sentence = sentence.replace(/[⟦〚]PH\d+:([^⟧〛]*)[⟧〛]/g, '$1') const parts = sentence.split(/(\{\{[^}]+\.[wo]:[0-9a-f-]{36}\}\})/) return parts.map((part, i) => { const m = part.match(/^\{\{([^.]+)\.(w|o):([0-9a-f-]{36})\}\}$/)