GitLab CI

Keep your repository translation files in sync with Translatize straight from your GitLab pipelines. Wire it up with a CI/CD Catalog component you include:, or drop a copy-paste job into any .gitlab-ci.yml today – both run the Translatize CLI through npx, so there is nothing to vendor into your repo.

What the CLI does

The translatize CLI reads a config file (default translatize.config.json, committed to your repo) that points at your Translatize project and maps its label namespaces to files on disk.

CommandPurpose
pullDownload translations from Translatize into your repo locale files.
pushUpload local source strings to Translatize.
statusCompare local vs. remote and report drift.

Useful flags: --config <path>, --api-url <url>, --json, --dry-run, and – for status --fail-on-missing / --fail-on-diff (turn findings into a non-zero exit so a pipeline gate fails). The token is never passed on the command line: the CLI reads TRANSLATIZE_API_TOKEN from the environment, which you provide as a masked CI/CD variable.

Exit codes

CodeMeaningJob result
0Success – nothing to report.pass
1A gate condition tripped (missing translations / drift) under --fail-on-missing / --fail-on-diff, or an API/network/auth error (bad or expired token, unreachable API).fail
2Usage or configuration error (unreadable/invalid config, missing token, bad flags).fail

Any non-zero code fails the job. Add allow_failure: true to a job to make it advisory instead of blocking.

Component usage

.gitlab-ci.yml
include:
  - component: $CI_SERVER_FQDN/translatize/gitlab/translatize@0.1.0
    inputs:
      command: status
      cli_version: latest
      config: translatize.config.json
      extra_args: "--fail-on-missing"

That adds one job, translatize-sync, to your pipeline. Its inputs:

InputDefaultDescription
stagetestStage the job runs in.
commandstatusOne of pull, push, status.
cli_versionlatestnpm dist-tag or exact version of @translatize/cli.
configtranslatize.config.jsonPath to the CLI config file.
api_url""Override the API base URL (empty = CLI default).
extra_args""Extra flags appended verbatim, e.g. --fail-on-missing --json.
node_imagenode:20-alpineImage that provides Node.js and npx.
Published to the CI/CD Catalog
This component is published to the GitLab CI/CD Catalog at gitlab.com/translatize/gitlab, so the include: component: line above resolves as printed. Prefer not to use the catalog? The copy-paste job below runs the identical npx invocation.

Copy-paste job (no component needed)

Drop this into your project .gitlab-ci.yml. It runs the exact same npx invocation as the component defaults:

.gitlab-ci.yml
translatize-status:
  stage: test
  image: node:20-alpine
  script:
    - npx --yes @translatize/cli@latest status --config translatize.config.json

Swap status for pull or push, pin @latest to an exact version for reproducible builds, and append flags such as --fail-on-missing or --json as needed.

CI/CD variable setup

  1. In Translatize, open your project and go to Project Settings → Integrations. Create an API token – it looks like mcni_...
  2. Tokens are branch-bound: each token is tied to one project and a base branch (default main). A standard token acts only on that branch; a create-own-scope token may also target branches it created (select one with --branch in extra_args). If you sync more than one branch with standard tokens, mint one token per branch and store them under distinct variable names.
  3. In GitLab, go to Settings → CI/CD → Variables and add the token as a masked variable:
KeyValueFlags
TRANSLATIZE_API_TOKENmcni_...Masked

The CLI reads this automatically – never echo it or pass it as a --flag.

Masked vs. protected
Protected variables are not exposed to merge-request pipelines (those run on unprotected refs). If you want the MR gate below to work, keep TRANSLATIZE_API_TOKEN masked but not protected. A push token used only by branch or scheduled pipelines can be both masked and protected.

Merge-request status gate

Fail the MR pipeline when translations are missing, so drift cannot merge to your default branch:

.gitlab-ci.yml
translatize-mr-gate:
  stage: test
  image: node:20-alpine
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
  script:
    - npx --yes @translatize/cli@latest status --config translatize.config.json --fail-on-missing

--fail-on-missing makes the CLI exit 1 when any target language is missing translations, which fails the job and blocks the merge. Add allow_failure: true to make it advisory instead.

Scheduled nightly pull that commits back

Pull the latest translations every night and commit them to the branch. Because a bot needs to write to the repo, this uses a GitLab project access token with the write_repository scope (Developer role or higher), stored as a masked and protected CI/CD variable TRANSLATIZE_GIT_TOKEN. This is a different token from TRANSLATIZE_API_TOKEN – the GitLab token authorizes the git push, the Translatize token authorizes the pull. Create the schedule under Settings → CI/CD → Pipeline schedules, targeting the branch your Translatize token is bound to.

.gitlab-ci.yml
translatize-nightly-pull:
  stage: test
  image: node:20-alpine
  rules:
    - if: '$CI_PIPELINE_SOURCE == "schedule"'
  variables:
    GIT_STRATEGY: clone
    GIT_DEPTH: "0"
  script:
    - apk add --no-cache git
    - npx --yes @translatize/cli@latest pull --config translatize.config.json
    - |
      if [ -z "$(git status --porcelain)" ]; then
        echo "Translations already up to date."
        exit 0
      fi
      git config user.email "bot@translatize.com"
      git config user.name "Translatize Bot"
      git add -A
      git commit -m "chore(i18n): sync translations from Translatize [skip ci]"
      git push "https://oauth2:${TRANSLATIZE_GIT_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git" "HEAD:${CI_COMMIT_BRANCH}"
  • [skip ci] in the commit message stops the push from triggering another pipeline.
  • git status --porcelain detects both edited and newly-created locale files, so a no-op night makes no empty commit.
  • HEAD:${CI_COMMIT_BRANCH} pushes the detached CI checkout back onto the scheduled branch.