---
title: "comark"
description: "Extract segments from comark documents, apply translations to them and render the result."
canonical_url: "https://diglot.sh/adapters/comark"
---
# comark

> Extract segments from comark documents, apply translations to them and render the result.

`@diglot/comark` is the [comark](https://comark.dev) adapter. It extracts segments from comark documents and applies translations to them, and it handles `.navigation.yml` files.

<package-info directory="packages/comark" install="pnpm add @diglot/comark @diglot/core" name="@diglot/comark">



</package-info>

## Usage

```ts
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

`parse(source)` parses with the options the adapter expects and keeps the source and the line ranges of top-level blocks. Protected spans such as inline code, links, components and inline HTML are then taken verbatim from the source. A document parsed elsewhere works too, but its protected spans are re-rendered.

## extract

`extract(doc, { file, policy })` returns `{ segments, spans }`. The segments cover headings, paragraphs, list items, table cells, blockquotes, component slots, image alts, allowlisted props, prose frontmatter, code labels and code comments.

Pass `spanSources: false` when you only need identities, as for a manifest. Extraction then skips slicing and re-rendering, and placeholders get empty markdown, so each segment's `text` equals its `skeleton` and its `sourceHash` equals its `hash`. The `hash`, `skeleton`, placeholder types and `words` are the same either way.

## apply

`apply(doc, translations, { policy })` returns a translated copy and a report. Each translation is validated against the current source segment, and the 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 that is already split into highlighted spans.

`apply` works on a copy, so the document you pass in stays untouched. When nothing else holds on to the document, for example one you parsed for this request, pass `copy: false` to translate it in place and skip the copy.

With `onSegment`, you receive an [`ApplySegmentEvent`](https://diglot.sh/core/apply) for each segment. `target.setAttribute(name, value)` sets a prop on the text block that holds the segment (`h1` to `h6`, `p`, `li`, `blockquote`, `th`, `td`). Text directly inside a component is wrapped in a `span` that carries the attributes, and it is left unwrapped when no attribute is set. Frontmatter, props, image alts, code labels and code comments have a `null` target. Span sources are resolved only for `onSegment`, so pass `spanSources: false` when the callback doesn't read them.

```ts
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)
```

## render

`render(doc)` writes comark markdown, with hard breaks as `:br` and bound HTML attributes such as `:zoom="false"` intact.

## Navigation files

`extractNavigation(source, { file, policy })` returns the segments of the prose keys of a `.navigation.yml` file, and `applyNavigation(source, translations)` returns `{ source, report }` with only the translated values replaced. The keys come from `policy.navigation`, and `%s` in a title template becomes a placeholder.

## Labels

Navigation trees and title templates are often built at runtime, from values that came out of `.navigation.yml` files or frontmatter, so there is no document left to apply translations to. `translateLabel(value, translations, options)` translates one such value directly and returns `value` itself when there is no valid translation:

```ts
import { translateLabel } from '@diglot/comark'

const title = translateLabel(item.title, records, { file: 'docs/1.guide/.navigation.yml', detail: 'title' })
```

`labelSegment(value, options)` returns the segment behind it. By default a value is hashed as `extractNavigation` hashes a `.navigation.yml` value, with `%s` as a placeholder. With `kind: 'frontmatter'`, it is hashed as `extract` hashes a frontmatter value. When your policy has a `salt`, pass the same `file`, `detail` and `policy` as extraction, because the salt can depend on them and the hashes would otherwise differ.


## Sitemap

See the full [sitemap](https://diglot.sh/sitemap.md) for all pages.
