Translate-It now uses a shared markdown rendering architecture for user-facing previews and a separate extraction path for plain-text cleanup.
The key design rule is simple:
- Providers emit raw translation content and Markdown shape only.
- UI rendering is handled by a shared preview pipeline.
- Cleanup, copy, TTS, and export extraction stay in
SimpleMarkdown.
This keeps display concerns, text extraction concerns, and provider contracts isolated from one another.
- Providers own the translation payload and its markdown structure.
- Providers must not emit HTML.
- Providers should use markdown conventions that the UI can render consistently:
- bold-label sections for dictionary entries
- inline code for IPA / pronunciation snippets
- plain markdown paragraphs, lists, headings, and code fences where appropriate
renderMarkdownPreview()owns safe UI markdown rendering.- It is the shared display pipeline for:
TranslationDisplay- Sidepanel history previews
- Mobile history previews
- It is responsible for:
markedparsing- DOMPurify sanitization
- legacy
SimpleMarkdownfallback rendering when needed - link normalization
- dictionary label/list grouping
- whitespace cleanup
- per-block direction normalization
SafeMarkdownPreviewowns the only controlledv-htmlsink in the UI.- The component must only receive sanitized HTML produced by
renderMarkdownPreview().
SimpleMarkdownowns:- legacy fallback extraction
- plain-text cleanup for copy/TTS/export
- pronunciation-guide stripping
- dictionary primary-text extraction
SimpleMarkdownis not the UI markdown renderer.
The shared markdown preview pipeline is:
- Receive provider output or history text.
- Decide whether modern markdown rendering is appropriate.
- Render markdown with
markedwhen possible. - Sanitize the output with DOMPurify.
- Parse the sanitized markup in a detached DOM.
- Apply structural normalization:
- label/list grouping
- whitespace text-node cleanup
- direction normalization
- Re-sanitize the final HTML.
- Pass the sanitized result to
SafeMarkdownPreview.
If the content matches a legacy dictionary shape, the helper falls back to the legacy SimpleMarkdown path to preserve compatibility.
Translation history stores raw text and preserves the original markdown-rich translation payload.
sourceTextremains plain text in history views.translatedTextis rendered through the shared preview pipeline only.- History views do not own markdown parsing or sanitization.
Exports remain independent from display rendering:
json_rawpreserves the raw stored content.json_clean,csv, andankiuse cleaned plain-text extraction.
Text extraction must stay in SimpleMarkdown.
Use SimpleMarkdown for:
- copy cleanup
- TTS text extraction
- export cleaning
- dictionary primary-text extraction
- pronunciation guide stripping
- legacy plain-text fallback
Dictionary mode should use the primary-only extraction strategy so pronunciation and metadata do not leak into spoken or copied text.
Providers must follow a markdown-first, HTML-free contract:
- emit Markdown or plain text only
- never emit HTML
- use bold-label markdown for dictionary sections
- use inline code for pronunciation / IPA snippets
- avoid display-specific wrappers or UI-specific formatting
- keep pronunciation metadata in display text only when that metadata is part of the provider contract
New provider output shapes must be validated in:
- provider contract tests
- preview rendering tests
- extraction tests when the output affects copy/TTS/export behavior
When changing provider markdown or preview behavior, verify:
- provider output matches the expected markdown contract
renderMarkdownPreview()renders the intended HTMLSafeMarkdownPreviewremains the onlyv-htmlsink- history previews still render only
translatedText SimpleMarkdownstill strips/normalizes the expected plain text- TTS still speaks the intended text only
- export modes still produce the expected raw or cleaned output
- dictionary sections still render correctly in Google, Vajehyab, and AI output
- pronunciation / IPA lines still preserve inline code rendering in display mode
- Prefer MockProvider fixtures for UI rendering regressions because they provide deterministic markdown samples that can be exercised consistently across TranslationDisplay, History previews, TTS extraction, and future UI surfaces.
- Keep preview rendering and text extraction separate.
- Do not move display formatting logic back into providers.
- Add new markdown patterns to the shared preview helper first, not to the history views.
- Add new cleanup rules to
SimpleMarkdownonly when they affect copy/TTS/export extraction. - If a new provider introduces a special dictionary shape, add:
- a provider fixture
- a preview rendering test
- an extraction test if the text is meant for TTS or copy