You don't have to start from an empty project. If you already have translated files, the CLI works alongside them: it fills in what's missing and leaves your existing translations in place.
Point the config at what you have#
Set your source and target locales and the file patterns, matching wherever your translations already live:
{
"sourceLocale": "en",
"targetLocales": ["de", "fr"],
"files": [{ "pattern": "locales/en.json" }]
}If locales/de.json and locales/fr.json already exist, they stay as they are.
Fill the gaps#
lingo push --backfill-missing--backfill-missing only produces targets that are missing — a locale with no file yet, or (after the first run) keys the engine hasn't translated. Files you already have aren't overwritten.
✓ Run lfr_a8c...: localized 1 target file(s), 2 already up-to-date.Keep specific values frozen#
If some existing translations are hand-reviewed and must never change, mark them preservedKeys so no future run touches them:
{ "pattern": "locales/en.json", "preservedKeys": ["legal.terms"] }How the lockfile bootstraps#
The first push records a hash of every source file in .lingo/lock.json. From then on, plain lingo push only sends sources that changed — your existing translations are never re-sent unless you change the source or force it. Commit the lockfile alongside your translations. See Configuration.
Overwriting on purpose
--backfill-missing never overwrites. To deliberately regenerate existing translations (after a model or rule change), use a scoped --force push.
