|
Documentation
Book a DemoPlatform
PlatformMCPCLI
APIWorkflows
GuidesChangelog

Overview

  • @lingo.dev/cli

Getting started

  • Quickstart
  • Configuration

Reference

  • lingo push
  • lingo pull
  • Other commands
  • lingo purge

Configuration

  • Key controls
  • Formats
  • Locales

Guides

  • Adding a locale
  • Existing translations
  • Retranslation
  • Translator notes
  • Runs, state, and recovery
  • CI/CD
  • Monorepos
  • Large projects

Looking for the older CLI (v0)? See the legacy CLI docs

Key controls

Most of the time you want every string in a file translated. For the exceptions — brand names, feature flags, legal copy, internal junk — the CLI gives you three per-file controls, set inside a files[] entry in .lingo/config.json.

ControlConfig fieldWhat the engine does
LocklockedKeysCopies the source value into every target, untranslated.
PreservepreservedKeysKeeps whatever is already in the target, never overwrites it.
IgnoreignoredKeysOmits the key from the target file entirely.

All three take key paths in dot/bracket notation that mirrors the structure of the file:

json
{
  "files": [
    {
      "pattern": "content/en/app.json",
      "lockedKeys": ["meta.version"],
      "preservedKeys": ["legal.terms"],
      "ignoredKeys": ["internal.debug"]
    }
  ]
}

Lock — keep the value identical everywhere#

lockedKeys copies the source value into every target file without translating it. Use it for values that must stay byte-for-byte identical across locales:

json
{
  "pattern": "content/en/app.json",
  "lockedKeys": ["meta.version", "config.apiUrl"]
}

de.json and fr.json get meta.version with the exact source string. Change the source and the next lingo push propagates the new value to every locale, still untranslated.

Preserve — protect a hand-written target#

preservedKeys tells the engine never to overwrite a target value that already exists. Use it when a key needs human translation — legal text, compliance copy, anything you've reviewed and don't want the model touching:

json
{
  "pattern": "content/en/settings.jsonc",
  "preservedKeys": ["featureFlags"]
}

The engine seeds the key from the source on first translation, then leaves your edits alone on every run after that. Compare with overrides below.

Ignore — drop the key from the output#

ignoredKeys removes the key from target files altogether — it isn't translated, copied, or written. Use it for debug strings, internal flags, and test data that should never reach a translated build:

json
{
  "pattern": "content/en/app.json",
  "ignoredKeys": ["internal.debug", "dev.testData"]
}

JSON and JSONC

Key controls operate on structured key/value formats — json and jsonc. For markdown-family formats, scope translation with translateFrontmatterFields and translateComponentProps instead (see Formats).

Overrides vs. preserve#

There are two ways an existing target value survives a run:

  • Preserve (preservedKeys) — declarative. The key is protected by config, on every locale, forever.
  • Local edits — lingo push compares each target's hash against the lockfile. If you hand-edited a target file, the push reports it as skipped (local edits) and leaves it untouched. Pass --force (with a scope) to overwrite. See lingo push.

Reach for preservedKeys when the protection is permanent and locale-wide; rely on local-edit detection for one-off manual tweaks.

Migrating from the legacy CLI#

The legacy CLI also had key renaming (carry a translation forward when a key id changed). That isn't part of the current CLI — translation state is tracked per file hash, so renaming a key re-translates it on the next push. Lock, preserve, and ignore all carry over, with one change: paths use dot/bracket notation (meta.version) instead of the old slash notation (meta/version).

Was this page helpful?

Max PrilutskiyMax Prilutskiy·Updated about 8 hours ago·2 min read