Skip to content

JSON

Designed for projects that keep UI copy in nested JSON files per locale (for example src/i18n/en/translation.json) instead of t("…") in source. The CLI walks string values in those files, translates them via the active LLM provider, and writes per-locale outputs using json[].outputPathTemplate. It uses the same SQLite cache as translate-docs and translate-svg (cacheDir).

This pipeline does not run extract — there is no strings.json catalog. Enable it with features.translateJson and one or more entries in top-level json[].

Per-locale model overrides

translate-json resolves models per target locale: localeModels(locale) first when configured, then translationModels. Use this for nested JSON bundles where certain locales benefit from dedicated models — for example zh-Hans / zh-Hant theme files. See Providers and models.

Step 1: Initialise for nested JSON

bash
ai-i18n-tools init -t ui-json-bundles [-P <provider>]

That template sets features.translateJson: true, disables UI extraction and document translation, and scaffolds a single json[] block pointing at src/i18n/en/translation.json with output src/i18n/{llocale}/translation.json. It also includes a default provider / providers block (openrouter unless you pass -P <provider>) — set the matching API key (or use local Ollama) before running translate-json or sync; see Provider and API key. Edit sourceLocale, targetLocales, contentPaths, and outputPathTemplate for your repo layout.

Step 2: Configure json[]

Each json[] block describes one pipeline:

  • contentPaths — one or more .json files, directories, or globs (for example "src/i18n/en/translation.json" or "src/i18n/en/overrides/*.json"). Paths are resolved from the project root.
  • outputPathTemplate — required. Where to write each target locale file. Placeholders: {locale}, {LOCALE}, {llocale} (lowercased locale, useful for Astro route folders), {stem}, {basename}, {extension}, {relativeToSourceRoot}.
  • targetLocales (optional) — subset for this block only; otherwise root targetLocales applies.
  • keyPolicy — which JSON keys hold translatable prose vs stable identifiers (see below).
  • description (optional) — shown in CLI headers and status output.

Example (multiple source files, lowercase locale folders):

json
{
  "sourceLocale": "en",
  "targetLocales": ["de", "fr", "pt-BR"],
  "features": {
    "translateJson": true
  },
  "cacheDir": ".translation-cache",
  "json": [
    {
      "description": "App UI bundle",
      "contentPaths": [
        "src/i18n/en/translation.json",
        "src/i18n/en/overrides/*.json"
      ],
      "outputPathTemplate": "src/i18n/{llocale}/{basename}",
      "keyPolicy": {
        "mode": "denylist",
        "skipKeys": ["id", "slug", "href", "url", "key", "code"],
        "translateKeys": []
      }
    }
  ]
}

keyPolicy

modeBehaviour
allowlistOnly keys matching translateKeys (dot paths; minimatch globs) are translated.
denylistTranslate all string values except keys matching skipKeys.
bothApply translateKeys first, then remove matches from skipKeys.

Paths use dot notation (nav.home.label). A bare name like slug matches the final key segment at any depth.

Step 3: Translate JSON bundles

bash
ai-i18n-tools translate-json

Optional flags (same ideas as translate-docs): -l / --locale for a subset of targets, -p / --path to limit files, --dry-run, --force (clear file tracking and segment cache for matched files), --force-update (re-process when file hash matches; segment cache still applies), -b / --batch-concurrency, --prompt-format (xml | json-array | json-object).

JSON-only projects can run:

bash
ai-i18n-tools sync --no-ui --no-svg --no-docs

When UI or docs are also enabled, sync runs translate-json after translate-docs (unless --no-json). Skip JSON with --no-json.

Check coverage per file and locale:

bash
ai-i18n-tools status

When translateJson is on, status prints a json[] section (✓ up to date, ● stale or missing).

JSON vs other pipelines

SituationUse
UI strings in t("…") / i18n.t("…") in JS/TS/AstroUI stringsextract + translate-ui
Docusaurus write-translations catalog ({ "key": { "message": "…", "description": "…" } })Documents — docs[].docusaurusCatalogDir + translate-docs, not json[]
VitePress theme/nav/sidebar stringsDocuments — docsOutput.vitepressThemeCatalog + translate-docs; do not use json[] — see VitePress integration
Nextra _meta.ts labels and theme dictionary .tsDocuments — translate-docs (auto _meta when style: "nextra", optional nextraDictionaryPath); do not use json[] — see Nextra integration
Fumadocs meta.json labels and UI overrides catalogDocuments — translate-docs (auto meta.json when style: "fumadocs", optional fumadocsUiCatalog); do not use json[] — see Fumadocs integration
Standalone nested locale JSON (ZenBrowser-style translation.json trees)JSON — json[] + translate-json
Illustrated .svg files with <text> / <title> / <desc>features.translateSVG + svg + translate-svg (optional; not one of the three main pipelines)

Field reference: json in Configuration reference. Cache keys for cleanup use json-block:{blockIndex}:{projectRelPath} in file_tracking.

Released under the MIT License.