@diglot/comark
v0.2.2
Published
comark adapter for diglot
Readme
@diglot/comark
comark adapter for diglot: extracts segments from comark documents and applies translations to them.
pnpm add @diglot/comark @diglot/coreUsage
import { apply, extract, parse, render } from '@diglot/comark'
const doc = await parse(markdown)
const { segments } = await extract(doc, { file: 'docs/intro.md' })
const translations = new Map([[segments[0].hash, 'Introduction']])
const { doc: translated, report } = await apply(doc, translations)
// report: { applied, missing, rejected }
const output = await render(translated)parse(source)parses with the options the adapter expects and keeps the source and top-level line ranges, so protected spans (inline code, links, components, inline HTML) are taken verbatim from the source. Documents parsed elsewhere work too; their protected spans are re-rendered.extract(doc, { file, policy })returns segments for headings, paragraphs, list items, table cells, blockquotes, component slots, image alts, allowlisted props, prose frontmatter, code labels and code comments.extract(doc, { spanSources: false })skips slicing and re-rendering protected spans. Links, inline code, images, components and inline HTML get empty markdown in their placeholders, which changes each segment'stextandsourceHash;hash,skeleton, placeholder types andwordsare the same. Use it when only identities are needed, as for a manifest.apply(doc, translations, { policy })returns a translated copy. Each translation is validated against the current source segment; placeholders are filled with the current source nodes, so links, code and components always come from the source. Rejected and missing segments keep their source text. Heading ids are kept. Code comments are substituted in the code text, including code already split into highlighted spans.apply(doc, translations, { onSegment })callsonSegmentwith anApplySegmentEventfor each segment.target.setAttribute(name, value)sets a prop on the text block holding the segment (h1toh6,p,li,blockquote,th,td). Text directly inside a component is wrapped in aspanthat carries the attributes; it is left unwrapped when no attribute is set. Frontmatter, props, image alts, code labels and code comments have anulltarget. Span sources are resolved foronSegmentonly; passspanSources: falsewhen the callback does not read them (hash,wordsandskeletonare unaffected).const events: ApplySegmentEvent[] = [] const { doc: translated } = await apply(doc, segment => records.get(segment.hash), { onSegment(event) { events.push(event) if (event.outcome === 'missing' || event.outcome === 'rejected') event.target?.setAttribute('lang', 'en') }, }) const coverage = wordsByStatus(events)apply(doc, translations, { copy: false })translatesdocin place instead of a copy. Use it when nothing else holds on todoc, such as a document parsed for this request.render(doc)writes comark markdown, with hard breaks as:brand bound HTML attributes such as:zoom="false"intact.extractNavigation(source)andapplyNavigation(source, translations)handle.navigation.ymlfiles.labelSegment(value, { kind, file, detail, policy })builds the segment of one label, hashed asextractNavigationhashes a.navigation.ymlvalue (%sis a placeholder) or, withkind: 'frontmatter', asextracthashes a frontmatter value.translateLabel(value, translations, options)returns its translation, orvaluewithout a valid one. Use them to translate navigation trees andtitleTemplates at runtime; pass the samefile,detailandpolicyas extraction when the policy has asalt.
