You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Keep the packages/datavis i18next locales translated automatically via Loco: push new English keys, AI-translate on the server, pull translated JSONs back into the repo. The build never depends on the Loco server at runtime — locale files stay committed (File-Mode philosophy).
flowchart LR
Source[en-US.json<br/>source of truth] -->|1. push keys| Register[POST /api/textnodes<br/>+ approve]
Register -->|2. find gaps| Gaps[GET /api/textnodes/untranslated-ids]
Gaps -->|3. translate| AIJob[POST /api/ai-jobs<br/>poll until done]
AIJob -->|4. pull| Export[GET /api/export/:lang]
Export -->|5. write| Locales[src/i18n/locales/*.json<br/>committed to repo]
Loading
Milestone 1 — Connectivity & key-model spike
Confirm/create a Loco project for datavis and obtain LOCO_API_KEY
Curl smoke tests: GET /api (health), GET /api/languages, POST /api/textnodes with sample keys, GET /api/export/{lang}
Decide the key model (blocking): datavis uses ID keys (t('COLUMN_CONFIG') || 'Column configuration') while Loco is text-keyed — push English fallback text as the Loco key with context: 'datavis:<KEY>', or push the raw key?
Map repo locale names (zh-Hans-CN, es-MX, …) to Loco language codes (GET /api/languages)
Exit criteria: one key travels en-US.json → Loco → AI translation → exported JSON in the expected shape
Create packages/datavis/scripts/loco-sync.mjs (zero-dep Node, same style as check-i18n-keys.mjs); config via LOCO_API_URL / LOCO_API_KEY env vars
--pull-only mode: GET /api/export/{lang} per language in src/i18n/config.ts, remap to repo keys, write src/i18n/locales/*.json (sorted keys, 2-space indent, trailing newline; skip unchanged files)
Keys missing on Loco keep their committed value — never delete translations on pull
Add "i18n:pull": "node scripts/loco-sync.mjs --pull-only" to packages/datavis/package.json
Goal
Keep the
packages/datavisi18next locales translated automatically via Loco: push new English keys, AI-translate on the server, pull translated JSONs back into the repo. The build never depends on the Loco server at runtime — locale files stay committed (File-Mode philosophy).flowchart LR Source[en-US.json<br/>source of truth] -->|1. push keys| Register[POST /api/textnodes<br/>+ approve] Register -->|2. find gaps| Gaps[GET /api/textnodes/untranslated-ids] Gaps -->|3. translate| AIJob[POST /api/ai-jobs<br/>poll until done] AIJob -->|4. pull| Export[GET /api/export/:lang] Export -->|5. write| Locales[src/i18n/locales/*.json<br/>committed to repo]Milestone 1 — Connectivity & key-model spike
LOCO_API_KEYGET /api(health),GET /api/languages,POST /api/textnodeswith sample keys,GET /api/export/{lang}t('COLUMN_CONFIG') || 'Column configuration') while Loco is text-keyed — push English fallback text as the Loco key withcontext: 'datavis:<KEY>', or push the raw key?zh-Hans-CN,es-MX, …) to Loco language codes (GET /api/languages)Milestone 2 —
loco-sync.mjspull path (read-only half)packages/datavis/scripts/loco-sync.mjs(zero-dep Node, same style ascheck-i18n-keys.mjs); config viaLOCO_API_URL/LOCO_API_KEYenv vars--pull-onlymode:GET /api/export/{lang}per language insrc/i18n/config.ts, remap to repo keys, writesrc/i18n/locales/*.json(sorted keys, 2-space indent, trailing newline; skip unchanged files)"i18n:pull": "node scripts/loco-sync.mjs --pull-only"topackages/datavis/package.jsonpnpm i18n:pullyields a clean/correct diff;pnpm lint:i18npasses; Storybook renders fr-FR unchangedMilestone 3 — Push + AI-translate path (full sync)
en-US.jsonkeys against Loco (GET /api/translations/all), register new ones (POST /api/textnodes), bulk-approve (PATCH /api/textnodes/status)GET /api/textnodes/untranslated-ids→POST /api/ai-jobs→ pollGET /api/ai-jobs/{jobId}with timeout, then pull"i18n:sync": "node scripts/loco-sync.mjs"topackages/datavis/package.jsonen-US.json, runpnpm i18n:sync, all 9 locale files gain a translated entryMilestone 4 — Build & CI integration
buildonly whenLOCO_API_KEYis set; skip silently otherwise so offline/contributor builds work from committed localesi18n:pull+git diff --exit-codefail-on-drifti18n:syncthat opens a PR with refreshed locale files (never auto-commits to main)LOCO_API_KEYas a repo secretMilestone 5 — Hardening & docs
{{count}}etc.) survive AI translation; fail the key otherwisepackages/datavis(workflow diagram, env vars, commands); note in TESTING.md if the drift check lands in CIRisks
GET /api/languages