| 1 | import { Fragment, type ReactNode } from "react"; |
| 2 | import { splitTokens } from "@/lib/i18n/dictionaries"; |
| 3 | |
| 4 | /** |
| 5 | * Typeset a dictionary template whose `{token}` placeholders stand for |
| 6 | * code-owned literals (commands, env names, config keys, job states). The |
| 7 | * literals stay in the page; the sentence stays one translated unit and a |
| 8 | * locale may reorder the tokens freely. An unknown token renders as |
| 9 | * `{token}` so template/literal drift is visible in review, never silent. |
| 10 | */ |
| 11 | export function withCodeSpans(template: string, spans: Record<string, string>): ReactNode { |
| 12 | return splitTokens(template).map((part, i) => |
| 13 | "token" in part ? ( |
| 14 | <code key={`${i}-${part.token}`} className="inline"> |
| 15 | {spans[part.token] ?? `{${part.token}}`} |
| 16 | </code> |
| 17 | ) : ( |
| 18 | <Fragment key={`${i}-text`}>{part.text}</Fragment> |
| 19 | ), |
| 20 | ); |
| 21 | } |
| 22 | |
| 23 | /** A `[term, detail]` reference list, the docs pages' one table shape. */ |
| 24 | export function RefRows({ |
| 25 | rows, |
| 26 | spans = {}, |
| 27 | termSpans = false, |
| 28 | }: { |
| 29 | rows: readonly (readonly [string, string])[]; |
| 30 | spans?: Record<string, string>; |
| 31 | /** Typeset the term column as code (command tables). */ |
| 32 | termSpans?: boolean; |
| 33 | }) { |
| 34 | return ( |
| 35 | <dl className="docs-ref-rows"> |
| 36 | {rows.map(([term, detail]) => ( |
| 37 | <div key={term}> |
| 38 | <dt>{termSpans ? <code className="inline">{term}</code> : term}</dt> |
| 39 | <dd>{withCodeSpans(detail, spans)}</dd> |
| 40 | </div> |
| 41 | ))} |
| 42 | </dl> |
| 43 | ); |
| 44 | } |
| 45 |