CLI Reference
This document provides a comprehensive reference for all Lingo Tracker CLI commands. For initial setup instructions, see the Getting Started Guide.
Overview
The Lingo Tracker CLI provides commands to manage translation collections and resources from the command line. All commands support both interactive mode (with prompts) and non-interactive mode (for CI/CD environments).
General Usage
lingo-tracker <command> [options]
Interactive vs Non-Interactive Mode
- Interactive Mode: When running in a TTY environment without all required options, the CLI will prompt you for missing values.
- Non-Interactive Mode: In CI/CD environments or when all required options are provided, no prompts will appear.
Common Options
- Most commands accept configuration options that can override defaults from
.lingo-tracker.json - Options use
--kebab-casenaming convention - Multi-value options (like
--locales) accept space-separated values
Collection Commands
init
Initialize a new Lingo Tracker project by creating a .lingo-tracker.json configuration file.
Usage:
lingo-tracker init [options]
Options:
--collection-name <name>- Name of the initial collection key, e.g., "Main" (required in non-interactive mode)--translations-folder <path>- Path to the translations directory for this collection (required in non-interactive mode)--export-folder <path>- Output folder for exports (default:dist/lingo-export)--import-folder <path>- Input folder for imports (default:dist/lingo-import)--base-locale <locale>- Base/authoring locale (default:en)--locales <locales...>- Space-separated list of supported locales (e.g.,en fr-ca es de)
Bundle options:
--setup-bundle <true|false>- Customize bundle configuration (default: prompted interactively). When omitted and any bundle flag is provided, automatically inferred astrue--bundle-dist <path>- Bundle output directory (default:./src/assets/i18n)--bundle-name <pattern>- Bundle name pattern (default:{locale})--token-casing <casing>- Token property key casing:upperCaseorcamelCase--type-dist-file <path>- Path for generated TypeScript type definitions file (default:./src/generated/tokens.ts)--token-constant-name <name>- Custom name for the generated TypeScript constant (auto-derived from bundle key when omitted)
Auto-translation options:
--enable-auto-translation- Enable automatic translation via an external provider--translation-provider <provider>- Translation provider to use (default:google-translate). Required when--enable-auto-translationis set--translation-api-key-env <envVar>- Name of the environment variable holding the provider API key (default:GOOGLE_TRANSLATE_API_KEY). Required when--enable-auto-translationis set
Examples:
Interactive mode (prompts for values):
lingo-tracker init
Non-interactive mode (CI-safe, all required options provided):
lingo-tracker init \
--collection-name Main \
--translations-folder apps/web/src/assets/i18n \
--export-folder dist/lingo-export \
--import-folder dist/lingo-import \
--base-locale en \
--locales en fr-ca es de
Non-interactive mode with bundle configuration:
lingo-tracker init \
--collection-name Main \
--translations-folder apps/web/src/assets/i18n \
--base-locale en \
--locales en fr-ca es de \
--setup-bundle true \
--bundle-dist ./src/assets/i18n \
--bundle-name "{locale}" \
--token-casing camelCase \
--type-dist-file ./src/generated/tokens.ts
Non-interactive mode with auto-translation enabled:
lingo-tracker init \
--collection-name Main \
--translations-folder apps/web/src/assets/i18n \
--base-locale en \
--locales en fr-ca es de \
--enable-auto-translation \
--translation-provider google-translate \
--translation-api-key-env GOOGLE_TRANSLATE_API_KEY
Notes:
- Run this command once in your project root to create
.lingo-tracker.json - Creates the initial configuration with one collection and a default bundle
- In interactive mode, you will be prompted to customize the bundle configuration (dist path, name pattern, token casing, type generation)
- If you decline bundle customization, a default bundle is still created with
dist: ./src/assets/i18n,bundleName: {locale}, andcollections: All - Commit
.lingo-tracker.jsonto version control - When
--enable-auto-translationis set, thetranslationblock is written to.lingo-tracker.jsonand new/edited resources are automatically translated via the configured provider
add-collection
Add a new translation collection to an existing Lingo Tracker project. Collections allow you to manage multiple translation sources within the same repository (e.g., main app, admin panel, mobile app).
Usage:
lingo-tracker add-collection [options]
Options:
--collection-name <name>- Name of the new collection (required in non-interactive mode)--translations-folder <path>- Path to the translations directory for this collection (required in non-interactive mode)--export-folder <path>- Override global export folder for this collection--import-folder <path>- Override global import folder for this collection--base-locale <locale>- Override global base locale--locales <locales...>- Override global locales list--read-only- Mark the collection as read-only (its resources cannot be modified)--no-read-only- Force the collection writable, overridingnode_modulesauto-detection
Examples:
Interactive mode (prompts for collection details, including a read-only confirmation):
lingo-tracker add-collection
Simple, using global defaults:
lingo-tracker add-collection \
--collection-name Admin \
--translations-folder apps/admin/src/assets/i18n
With collection-specific overrides (only differences are saved):
lingo-tracker add-collection \
--collection-name Mobile \
--translations-folder apps/mobile/src/i18n \
--base-locale en-GB
Register a component library's collection as read-only:
lingo-tracker add-collection \
--collection-name DesignSystem \
--translations-folder node_modules/@acme/design-system/i18n \
--read-only
Notes:
- Requires an existing
.lingo-tracker.jsonconfiguration file (runinitfirst) - Reuses global defaults; only saves overrides when they differ
- Will refuse to add a collection if the name already exists
- Only persists per-collection settings that differ from global configuration
Read-only collections:
- A collection can be marked read-only via the
readOnlyflag on its config entry. Whentrue, the CLI, API, and web UI refuse to modify its resources —add-resource,edit-resource,delete-resource,move,normalize,import,add-locale,remove-locale, andtranslate-localeare all blocked (the CLI exits with a non-zero status so CI fails). Read-only commands (bundle,export,validate,find-similar,glossary) are unaffected. normalize --allis the one exception: it skips read-only collections with an informational message and does not fail the run (so bulk normalization stays green even when a vendored read-only collection is present). Targeting a read-only collection explicitly (normalize --collection <name>) still fails.- The lock protects a collection's resources, not its registration: you can still
delete-collection(unregister it) and edit its config entry — including turningreadOnlyoff. - When the
--translations-folderis undernode_modules, read-only defaults totrue(in interactive mode the prompt is pre-checked; in non-interactive mode pass--no-read-onlyto override). This is convenient for component-library collections vendored into a consumer repo, which should not be edited locally. - The stored
readOnlyflag is the single source of truth. Anode_modulespath only sets the default at add time — it never forces read-only at runtime, and existing collections are never auto-migrated.
edit-collection
Edit an existing collection's configuration. Currently supports managing collection-level tags that are inherited by all resources in the collection.
Usage:
lingo-tracker edit-collection <name> [options]
Options:
--add-tag <tag>- Add a tag to the collection's tag list (repeatable, normalized automatically)--remove-tag <tag>- Remove a tag from the collection's tag list (repeatable)--set-tags <a,b,c>- Replace the entire tag list with a comma-separated set; pass""to clear all tags (mutually exclusive with--add-tag/--remove-tag)
Examples:
Add a tag:
lingo-tracker edit-collection myApp --add-tag team-x
Remove a tag:
lingo-tracker edit-collection myApp --remove-tag team-x
Add multiple tags at once:
lingo-tracker edit-collection myApp --add-tag team-x --add-tag mobile
Replace all tags:
lingo-tracker edit-collection myApp --set-tags "team-x,mobile,legal"
Clear all tags:
lingo-tracker edit-collection myApp --set-tags ""
Notes:
--set-tagsand--add-tag/--remove-tagare mutually exclusive- Tags are normalized automatically (lowercase, hyphens, max 50 chars)
- Collection-level tags are inherited by every resource in the collection at read time; they are not written into
resource_entries.jsonfiles - These tags are respected by
export --tags, bundle filtering, and the Tracker UI
delete-collection
Delete a translation collection from the project.
Usage:
lingo-tracker delete-collection [options]
Options:
--collection-name <name>- Name of the collection to delete (required in non-interactive mode)
Examples:
Interactive mode (prompts for collection):
lingo-tracker delete-collection
Non-interactive mode:
lingo-tracker delete-collection --collection-name Mobile
Notes:
- Removes the collection entry from
.lingo-tracker.json - Does NOT delete translation files from disk (data is preserved)
- Will prompt for confirmation before deletion (in interactive mode)
add-locale
Add a locale to a collection and backfill all existing resources with the new locale.
Usage:
lingo-tracker add-locale [options]
Options:
--collection <name>- Name of the collection (required in non-interactive mode)--locale <locale>- Locale to add, e.g.fr-ca,de,es(required in non-interactive mode)
Examples:
Interactive mode (prompts for collection and locale):
lingo-tracker add-locale
Non-interactive mode:
lingo-tracker add-locale --collection Main --locale de
Notes:
- Validates locale format (e.g.
en,fr-ca,zh-Hans) - Errors if the locale already exists in the collection
- Cannot add the base locale
- If the collection inherits global locales (no explicit
localesin its config), global locales are copied into the collection first, then the new locale is appended - All existing
resource_entries.jsonfiles are updated with the new locale value set to the base (source) value, andtracker_meta.jsonis updated withstatus: "new"
remove-locale
Remove a locale from a collection and purge all of its translation data from resource files.
Usage:
lingo-tracker remove-locale [options]
Options:
--collection <name>- Name of the collection (required in non-interactive mode)--locale <locale>- Locale to remove (required in non-interactive mode)
Examples:
Interactive mode (prompts for collection, then shows a list of removable locales):
lingo-tracker remove-locale
Non-interactive mode:
lingo-tracker remove-locale --collection Main --locale de
Notes:
- Errors if the locale does not exist in the collection
- Cannot remove the base locale
- Removes the locale key from all
resource_entries.jsonandtracker_meta.jsonfiles in the collection - Translation data for the locale is permanently deleted from files (recoverable via git)
- Removing the last non-base locale is allowed (results in a monolingual collection)
- If the collection inherits global locales, global locales are copied into the collection first, then the target locale is removed
Resource Commands
add-resource
Add a translation resource to a collection.
Usage:
lingo-tracker add-resource [options]
Options:
--collection <name>- Collection to add the resource to (required in non-interactive mode)--key <key>- Dot-delimited resource key, e.g.,apps.common.buttons.ok(required in non-interactive mode)--value <text>- Base (source) text in the base locale (required in non-interactive mode)--comment <text>- Optional context for translators--tags <tags>- Optional comma-separated tags for filtering/exporting. Values are normalized on write: lowercased, whitespace replaced with hyphens, non-[a-z0-9-]characters stripped, max 50 chars.--target-folder <folder>- Optional dot-delimited path override for folder placement--translations <json>- Optional JSON array with translation objects
Translation Object Format:
The --translations option accepts a JSON array of objects with the following structure:
[
{
"locale": "es",
"value": "Aplicar",
"status": "translated"
},
{
"locale": "fr-ca",
"value": "Appliquer",
"status": "verified"
}
]
Valid status values: new, translated, verified, stale
Examples:
Interactive mode (prompt for all values):
lingo-tracker add-resource
Non-interactive, minimal (key placed directly in translation folder):
lingo-tracker add-resource \
--collection Main \
--key buttons.ok \
--value OK
Non-interactive, full options (key nested under apps.common, tagged, with translations):
lingo-tracker add-resource \
--collection Main \
--key buttons.ok \
--value OK \
--comment "OK button in dialogs" \
--tags "ui,buttons,dialogs" \
--target-folder apps.common \
--translations '[{"locale":"es","value":"Aceptar","status":"translated"},{"locale":"fr-ca","value":"OK","status":"new"}]'
Notes:
- In interactive mode, you'll be prompted if you want to provide translations for each configured locale
- Resources are placed in the appropriate folder based on the key and optional
--target-folder - If a translation's checksum matches the base value's checksum, the status will automatically be set to
newregardless of the provided status
delete-resource
Delete one or more translation resources from a collection.
Usage:
lingo-tracker delete-resource [options]
Options:
--collection <name>- Collection to delete resources from (required in non-interactive mode)--key <keys>- Resource key(s) - single key or comma-separated (required in non-interactive mode)--yes- Skip confirmation prompt (useful for scripts)
Examples:
Interactive mode (prompts for collection and key):
lingo-tracker delete-resource
Delete a single resource:
lingo-tracker delete-resource \
--collection Main \
--key apps.common.buttons.ok
Delete multiple resources (comma-separated):
lingo-tracker delete-resource \
--collection Main \
--key "apps.common.buttons.ok,apps.common.buttons.cancel,apps.common.buttons.save"
Skip confirmation prompt (useful for scripts):
lingo-tracker delete-resource \
--collection Main \
--key apps.common.buttons.ok \
--yes
Behavior:
- Bulk Operations: The command uses a best-effort approach. If some keys fail validation or are not found, the operation continues processing remaining keys and reports the count of successful deletions.
- File Cleanup: When the last resource entry is deleted from a folder, both
resource_entries.jsonandtracker_meta.jsonare removed. Empty parent folders are preserved (keeps Git structure stable). - Confirmation: In interactive mode (TTY), you'll be asked to confirm the deletion unless the
--yesflag is provided. The confirmation shows all keys that will be deleted. - Partial Success: If some keys succeed and others fail, the command completes successfully and reports both the deletion count and any errors encountered.
Output:
# Successful deletion
✅ Deleted 3 resource(s)
# Partial success with errors
✅ Deleted 2 resource(s)
⚠️ Some operations failed:
- invalid..key: Invalid key format
- nonexistent.key: Resource not found
Notes:
- This command removes translations for ALL locales for the specified keys
- In non-interactive mode, you must provide all required options
- Errors for individual keys don't halt the operation; other keys continue to be processed
edit-resource
Edit an existing translation resource.
Usage:
lingo-tracker edit-resource [options]
Options:
--collection <name>- Collection containing the resource (required in non-interactive mode)--key <key>- Resource key (required in non-interactive mode)--base-value <text>- New base value (updates source text)--comment <text>- New comment--tags <tags>- New tags (comma-separated, replaces existing). Values are normalized on write: lowercased, whitespace replaced with hyphens, non-[a-z0-9-]characters stripped, max 50 chars.--target-folder <folder>- New target folder--locale <locale>- Locale to update (requires--locale-value)--locale-value <text>- New translation value for the specified locale
Examples:
Interactive mode:
lingo-tracker edit-resource
Update base value (marks other locales as stale):
lingo-tracker edit-resource \
--collection Main \
--key buttons.save \
--base-value "Save Item"
Update a specific translation:
lingo-tracker edit-resource \
--collection Main \
--key buttons.save \
--locale fr-ca \
--locale-value "Enregistrer l'article"
Update metadata:
lingo-tracker edit-resource \
--collection Main \
--key buttons.save \
--comment "Main save button" \
--tags "ui,primary"
Notes:
- Updating
--base-valuetriggers a checksum update and marks all other existing translations asstale. - Updating a locale value sets its status to
translatedand updates its checksum. - If no changes are detected (values match existing), the command reports "No changes detected".
translate-locale
Auto-translate all new and stale resources in a collection for a single target locale. Requires auto-translation to be enabled in .lingo-tracker.json.
Usage:
lingo-tracker translate-locale [options]
Options:
--collection <name>- Collection name (prompted if not provided)--locale <locale>- Target locale to translate (prompted if not provided)--verbose- Show per-batch progress (default: summary only)
Interactive mode:
When running in a TTY environment without --collection or --locale, the command prompts for the missing values.
Non-interactive mode:
Both --collection and --locale are required. The command exits with a non-zero code if either is missing.
Examples:
Interactive mode (prompts for collection and locale):
lingo-tracker translate-locale
Non-interactive mode:
lingo-tracker translate-locale \
--collection Main \
--locale fr
With verbose progress:
lingo-tracker translate-locale \
--collection Main \
--locale fr \
--verbose
Output (summary mode):
Translating locale 'fr' in collection 'playground'...
Done.
Translated: 45 resources
Skipped (ICU): 3 resources
Failed: 0 resources
Output (verbose mode):
[batch 1/9] translated: 5, skipped: 0, failed: 0
[batch 2/9] translated: 10, skipped: 0, failed: 0
...
Notes:
- Only resources with status
neworstaleare translated;translatedandverifiedresources are left unchanged - Resources whose base value uses complex ICU syntax are skipped and reported in the "Skipped (ICU)" count
- Throttling is controlled by
batchSizeanddelayMsin thetranslationconfig block; see Auto-Translation for recommended settings - Requires
translation.enabled: truein.lingo-tracker.json
move
Move or rename translation resources. Supports moving single resources as well as bulk moves using wildcard patterns.
Usage:
lingo-tracker move [options]
Options:
--collection <name>- Collection to move resources in (required in non-interactive mode)--source <key>- Source key or pattern (e.g.,common.buttons.okorcommon.buttons.*) (required in non-interactive mode)--dest <key>- Destination key (e.g.,common.actions.okorcommon.actions) (required in non-interactive mode)--override- Overwrite destination if it already exists--verbose- Print detailed output for each moved resource
Examples:
Interactive mode:
lingo-tracker move
Move a single resource:
lingo-tracker move \
--collection Main \
--source common.buttons.ok \
--dest common.actions.ok
Move multiple resources using a wildcard pattern:
lingo-tracker move \
--collection Main \
--source "common.buttons.*" \
--dest "common.actions"
Result: common.buttons.ok -> common.actions.ok, common.buttons.cancel -> common.actions.cancel
Force move (overwrite destination):
lingo-tracker move \
--collection Main \
--source old.key \
--dest new.key \
--override
Notes:
- When using wildcard patterns, the suffix matched by
*is appended to the destination key. - Moving a resource preserves its comments, tags, and translations.
- The source resource is deleted after a successful move.
normalize
Normalize translation resources by recomputing checksums, adding missing locale entries, updating statuses, and cleaning up empty folders. This is a maintenance operation that ensures translation files are consistent and correct after manual edits, configuration changes, or imports.
Usage:
lingo-tracker normalize [options]
Options:
--collection <name>- Collection name to normalize (required unless--allis used)--all- Normalize all collections in the project--dry-run- Preview changes without applying them (reports what would be changed)--json- Output results as JSON (useful for scripts and automation)
What Normalization Does:
- Recomputes checksums: Updates MD5 checksums for base locale and all translations
- Adds missing locales: Creates entries for any missing locales using the base value with status
new - Updates statuses: Sets correct translation status based on checksums
new- Locale entry was just added or matches base valuestale- Base value changed since last translation (checksum mismatch)translated/verified- Preserved when base value unchanged
- Normalizes tags: Coerces all tag values to lowercase, hyphenated form (
[a-z0-9-], max 50 chars). For example"Common UI"→"common-ui". Deduplicates tags within each resource. This is the recommended way to clean up legacy tag data that pre-dates strict validation. - Creates missing files: Ensures
resource_entries.jsonandtracker_meta.jsonexist at every folder level - Cleans up empty folders: Removes folders with no entries (bottom-up recursive cleanup)
Folder Cleanup Behavior:
Normalization automatically removes empty folders to keep the translations directory clean:
- Folders are considered empty if they contain:
- No
resource_entries.jsonfile, OR - An empty
resource_entries.json(no entries or{}), AND - No subfolders
- No
- Folders containing only
tracker_meta.jsonor hidden files (.gitkeep,.DS_Store) are removed - Cleanup uses bottom-up traversal (deepest folders first) to handle recursive removal
- The root translations folder is never removed, even if empty
When to Use Normalize:
- After manually editing JSON translation files
- After adding new locales to configuration
- After importing translations from external sources
- Periodically to maintain consistency and clean up the folder structure
- When translation statuses seem incorrect
Examples:
Interactive mode (prompts for collection):
lingo-tracker normalize
Normalize a specific collection:
lingo-tracker normalize --collection Main
Normalize all collections:
lingo-tracker normalize --all
Preview changes without applying (dry-run):
lingo-tracker normalize --collection Main --dry-run
Output results as JSON (useful for scripts):
lingo-tracker normalize --collection Main --json
Normalize all collections with JSON output:
lingo-tracker normalize --all --json
Output:
Human-readable format (default):
🔄 Normalizing collection: Main
✅ Entries processed: 42
✅ Locales added: 7
✅ Values converted to ICU: 0
✅ Tags normalized: 5
✅ Files created: 2
✅ Files updated: 15
✅ Folders removed: 3
Note: "Tags normalized" only appears when at least one tag was coerced.
JSON format (--json flag):
{
"collections": [
{
"collectionName": "Main",
"entriesProcessed": 42,
"localesAdded": 7,
"valuesConverted": 0,
"tagsNormalized": 5,
"filesCreated": 2,
"filesUpdated": 15,
"foldersRemoved": 3
}
],
"totals": {
"collectionsProcessed": 1,
"entriesProcessed": 42,
"localesAdded": 7,
"valuesConverted": 0,
"tagsNormalized": 5,
"filesCreated": 2,
"filesUpdated": 15,
"foldersRemoved": 3
}
}
Notes:
- Normalization is non-destructive: it preserves existing translation values and comments
- Tag values are coerced to normalized form (lowercase, hyphens, max 50 chars) — this is the intended cleanup path for legacy tags
- Only fills in missing data and corrects metadata
- Dry-run mode counts folders that would be removed but doesn't delete them
- In interactive mode, you'll be prompted to confirm when using
--all - Best practice: run with
--dry-runfirst to preview changes before applying
bundle
Generate translation bundles for deployment.
Usage:
lingo-tracker bundle [options]
Options:
--name <names>- Bundle name(s) to generate (comma-separated). If not specified, generates all configured bundles--locale <locales>- Specific locale(s) to generate (comma-separated). If not specified, generates all locales--token-casing <casing>- Casing style for generated type token keys:upperCaseorcamelCase. Overrides anytokenCasingset in the config file. Default:upperCase--token-constant-name <name>- Custom name for the generated TypeScript constant. Must be a valid JavaScript identifier. Only works when targeting a single bundle (via--name). OverridestokenConstantNamein the bundle config--no-transform-icu-to-transloco- Disable ICU to Transloco format conversion in bundle output--debug-keys [locale]- Also emit a debug bundle where every value equals its own dot-delimited key. Useful for visually locating untranslated strings at runtime by switching your app to this locale. If no locale code is provided, defaults to99(e.g.main.99.json). ICU transformation is skipped for the debug bundle.--verbose- Show detailed output including all warnings
What Bundle Generation Does:
- Reads bundle configuration from
.lingo-tracker.jsonbundlessection - Collects translations from specified collections based on selection rules
- Applies filters using pattern matching and tag-based selection
- Resolves conflicts using merge strategies (merge or override)
- Transforms to hierarchical JSON (flat keys → nested objects)
- Writes bundle files to configured output directories with
{locale}placeholder replacement
When to Use Bundle:
- Before deploying your application to production
- As part of your build pipeline
- After translator completes translations
- When you need to generate bundles for specific locales only
- To preview bundle contents with
--verboseflag
Examples:
Interactive mode (prompts for bundle selection):
lingo-tracker bundle
Generate all configured bundles:
lingo-tracker bundle
Generate specific bundle(s):
lingo-tracker bundle --name core
lingo-tracker bundle --name core,admin
Generate bundles for specific locale(s):
lingo-tracker bundle --locale en,fr
Verbose output (shows all warnings):
lingo-tracker bundle --verbose
Combined options:
lingo-tracker bundle --name core --locale en,fr --verbose
Override token casing for generated types:
lingo-tracker bundle --token-casing camelCase
Custom constant name for a single bundle:
lingo-tracker bundle --name core --token-constant-name MY_KEYS
Generate debug bundle with default locale 99:
lingo-tracker bundle --debug-keys
Generate debug bundle with a custom locale code:
lingo-tracker bundle --debug-keys debug
Output:
Normal output (default):
🔄 Generating bundle: core
✅ Files generated: 3
✅ Locales: en, fr-ca, es
⚠️ Warnings: 2
Verbose output (--verbose flag):