mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
feat(i18n): 21-language pipeline, landing/docs/API wiring, landing+API translations
Shared Claude Code translation pipeline (scripts/i18n, no API key) plus Astro/VitePress/Scalar i18n wiring. Landing and API reference translated into all 20 languages; docs i18n wiring + English source anchors. The translated docs markdown (apps/docs/<locale>/**, 3,620 files) follows in a companion PR because it exceeds GitHub's per-PR CI file limit.
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
<!-- scripts/i18n/adapter-contract.md -->
|
||||
# i18n adapter contract
|
||||
|
||||
Each surface (landing UI, landing SEO, docs, API spec) implements one adapter object:
|
||||
|
||||
```js
|
||||
export const adapter = {
|
||||
name: "docs", // unique surface key used on the CLI
|
||||
async extract() { /* return Unit[] */ },
|
||||
async load(locale) { /* return Map<id, StoredEntry> */ },
|
||||
async write(locale, entries) { /* persist Map<id, StoredEntry> */ },
|
||||
};
|
||||
```
|
||||
|
||||
Unit: `{ id: string, sourceText: string, kind: "markdown"|"text"|"html", context?: string }`
|
||||
- `id` must be stable across runs (a file path, a data key). It keys the stored translation.
|
||||
|
||||
StoredEntry (written and read back by the adapter, hashes stored inline per the spec):
|
||||
`{ text: string, sourceHash: string, provenance: "machine"|"human", outputHash: string, stale?: boolean }`
|
||||
|
||||
Rules the adapter owns:
|
||||
- `load` reads whatever inline representation the surface uses (frontmatter for `.md`,
|
||||
`_sourceHash`/`_meta` for JSON) and reconstructs `StoredEntry`.
|
||||
- `write` persists it back in that same representation. `stale: true` entries keep their
|
||||
existing `text` and should surface a review marker in the file (e.g. a frontmatter flag).
|
||||
- Adapters never call the model. They only extract and persist. `core.mjs` owns gating.
|
||||
Reference in New Issue
Block a user