// Placeholder-Format in Satz-/Titel-Feldern: {{label.w:uuid}} (Wort) bzw. {{label.o:uuid}} (Objekt). // Geteilt zwischen translate.js (Token-Schutz) und TTS (Auflösung in Sprechtext). const PLACEHOLDER_RE = /\{\{([^.{}]+)\.(w|o):([0-9a-f-]{36})\}\}/g; // Legacy-Form ohne Label: {{uuid}} — sollte migriert sein, defensiv trotzdem entfernen. const LEGACY_PLACEHOLDER_RE = /\{\{\s*[0-9a-f-]{36}\s*\}\}/g; // Schutz-Token während Übersetzung/Review: ⟦PHn:label⟧. Darf nie in der DB landen — // falls doch (Claude-Halluzination), wird er überall defensiv zum Label aufgelöst. const TOKEN_RE = /⟦(PH\d+):([^⟧]*)⟧/g; // Entfernt geleakte ⟦PHn:label⟧-Tokens aus einem Text → nur das Label bleibt. function stripLeakedTokens(text) { if (!text) return text; return String(text).replace(TOKEN_RE, (_, _key, label) => label.trim()); } // Macht aus "Ist das ein {{Apfel.w:1234-…}}?" → "Ist das ein Apfel?" (für TTS/Anzeige). function resolvePlaceholdersToLabels(text) { if (!text) return ''; return String(text) .replace(PLACEHOLDER_RE, (_, label) => label) .replace(LEGACY_PLACEHOLDER_RE, '') .replace(TOKEN_RE, (_, _key, label) => label.trim()) .replace(/\s{2,}/g, ' ') .trim(); } module.exports = { PLACEHOLDER_RE, TOKEN_RE, stripLeakedTokens, resolvePlaceholdersToLabels };