Translatize CLI

The command-line client for Translatize. It downloads a branch into per-language JSON files with pull, sends local source keys back with push, and reports drift with status – so a pull request can be gated on translation completeness.

Install

Add the CLI as a dev dependency. The binary is named translatize – run it with npx translatize <command> or from an npm script. It is built on @translatize/core and requires Node.js 18.17 or newer.

terminal
npm install -D @translatize/cli
On npm
@translatize/cli is published on npm under the @translatize scope, so the install above and npx @translatize/cli@latest resolve from the public registry.

Quickstart

terminal
# 1. Scaffold translatize.config.json (records your project + file layout)
npx translatize init

# 2. Provide a branch-bound API token
export TRANSLATIZE_API_TOKEN=mcni_xxx

# 3. Download translations into locales/<lang>.json
npx translatize pull

init writes a translatize.config.json you commit to your repo. The token is never written to that file – it is read from the environment or the --token flag at run time.

Authentication

The CLI authenticates with an API token – a string beginning with mcni_, not your login. Create one under Project Settings → Integrations in the app. A token is bound to a single project and a base branch, and by default translatize acts on that bound branch.

A token whose scope is create-own – an agent token – may also target branches it created: pass --branch <name> (or set branch in the config) to operate on one of them. Naming a branch the token cannot touch fails with a branch_not_allowed error that lists the branches the token may target.

The token is resolved in this order:

  1. the --token <mcni_...> flag, then
  2. the TRANSLATIZE_API_TOKEN environment variable.
Keep tokens out of version control
Never commit the token to translatize.config.json or any file. In CI, store it as a secret and expose it as the TRANSLATIZE_API_TOKEN environment variable.

Configuration

translatize.config.json lives at the root of your project, or wherever you point --config. File patterns are resolved relative to the directory that holds the config file.

translatize.config.json
{
  "apiUrl": "https://api.translatize.com/v1",
  "projectId": "your-project-id",
  "format": "json-nested",
  "files": "locales/{lang}.json",
  "namespace": "app",
  "branch": "feature-x"
}
FieldRequiredDescription
apiUrlnoAPI base URL including the /v1 segment. Defaults to https://api.translatize.com/v1.
projectIdnoThe project id. May be left empty – the CLI derives it from the token at run time. Set it to pin the project, and a mismatch with the token is reported.
formatyesOn-disk shape: json-nested (dotted keys become nested objects) or json-flat (dotted keys stay flat).
filesyesPath pattern for each language file. Must contain the {lang} placeholder, e.g. locales/{lang}.json.
namespacenoRestrict every operation to keys beginning with that namespace prefix.
branchnoDefault branch for pull/push/status. Must be in the token allowed set and is overridden by --branch. When omitted, commands use the bound branch.

The flat, dotted keys stored by the API can be written to disk two ways: json-nested turns app.nav.home into nested objects, while json-flat keeps the dotted key as-is. Both round-trip losslessly, and files are written with keys sorted and a trailing newline so re-running pull stays diff-friendly.

Commands

Every command accepts these global flags:

FlagDescription
-c, --config <path>Path to the config file. Default translatize.config.json.
--token <token>API token, overriding TRANSLATIZE_API_TOKEN.
--api-url <url>API base URL, overriding the config value.

translatize --version and translatize <command> --help are available at any level.

translatize init

Create translatize.config.json. Refuses to overwrite an existing file unless --force is passed. If a token is available it validates it via the API and prints the project name, bound branch, role, and configured languages.

FlagDescription
--project-id <id>Project id to record in the config.
--files <pattern>File pattern with a {lang} placeholder. Default locales/{lang}.json.
--format <format>json-nested (default) or json-flat.
--forceOverwrite an existing config file.

translatize pull

Download the branch and write one file per project language at the files pattern, creating parent directories as needed. A key whose value is empty or missing for a language is omitted from that file. When namespace is set, only keys under it are pulled.

FlagDescription
--branch <name>Branch to operate on. Overrides the config branch field and the token bound branch. Must be in the token allowed set.
--dry-runReport the per-file changes (new file / keys added / changed / removed locally) without writing anything.
--jsonEmit machine-readable JSON.

translatize push

Read each language file, compare it with the branch, and upload only new and changed keys. Values are assembled per key across all language files, and requests are chunked automatically to stay within the server batch limit. Translatize never deletes keys via push: keys that exist on the branch but not locally are reported and left untouched. It exits 1 if the server rejects any key.

FlagDescription
--branch <name>Branch to operate on. Overrides the config branch field and the token bound branch. Must be in the token allowed set.
--dry-runPrint the pending create/update list without sending anything.
--jsonEmit machine-readable JSON.

translatize status

Compare local files against the branch without changing either side – this is the CI gate. It prints per-language completeness (non-empty translations over total branch keys) and the counts of keys that are only local, only remote, or whose values differ, with up to 10 example keys each. Without a --fail-* flag it reports differences but still exits 0.

FlagDescription
--branch <name>Branch to operate on. Overrides the config branch field and the token bound branch. Must be in the token allowed set.
--fail-on-missingExit 1 if any language has missing translations.
--fail-on-diffExit 1 if local differs from the branch in any way.
--jsonEmit machine-readable JSON.

Selecting a branch

pull, push, and status all accept --branch <name>. The branch is resolved in this order:

  1. the --branch <name> flag, then
  2. the branch field in translatize.config.json, then
  3. the token bound (base) branch.

A standard token can only ever act on its bound branch, so --branch must name that same branch. A create-own agent token may additionally target any branch it created. Targeting a branch outside the token allowed set fails with a branch_not_allowed error listing the branches the token may use.

Agent tokens
The create-own scope lets an AI agent open and manage its own translation branches – it can act on the branches it creates but can never reach one it did not. See the MCP Server and Integration API docs for the full agent workflow.

Exit codes

CodeMeaning
0Success (including status differences when no --fail-* gate is set).
1A gate tripped, a push had server-side failures, or an API request failed.
2Usage or configuration error (bad flags, missing/invalid config, no token).

Use in CI

status is designed to fail a build when translations fall behind. This GitHub Actions job blocks merges when any language is missing translations:

.github/workflows/translations.yml
name: translations
on: [pull_request]

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - run: npx translatize status --fail-on-missing
        env:
          TRANSLATIZE_API_TOKEN: ${{ secrets.TRANSLATIZE_API_TOKEN }}

To push newly added source keys after a merge to main, run npx translatize push in a job with a token bound to that branch. Rather than script npx by hand, prefer the ready-made GitHub Action or GitLab CI component.