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 – 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 names your Translatize project, the file format and where the language files live.
| Command | Purpose |
|---|---|
pull | Download translations from Translatize into your repo locale files. |
push | Upload local source strings to Translatize. |
status | Compare local vs. remote and report drift. |
qa | Run the quality checks on the branch and read its merge gate; fail on errors (or warnings). |
Useful flags: --config <path>, --api-url <url>, --json, --dry-run (pull and push); for status, --fail-on-missing / --fail-on-diff (turn findings into a non-zero exit so a pipeline gate fails); and for qa, --fail-on error|warning. 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
| Code | Meaning | Job result |
|---|---|---|
0 | Success, including differences that status reports without a --fail-* flag. | pass |
1 | A gate condition tripped (missing translations / drift under --fail-on-missing / --fail-on-diff, QA issues at the --fail-on severity, a blocked merge gate), or an API/network/auth error (bad or expired token, unreachable API). | fail |
2 | Usage 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
include:
- component: gitlab.com/translatize/gitlab/translatize@0.2.0
inputs:
command: status
cli_version: "0.2.0"
config: translatize.config.json
extra_args: "--fail-on-missing"That adds one job, translatize-sync, to your pipeline. Its inputs:
| Input | Default | Description |
|---|---|---|
stage | test | Stage the job runs in. |
command | status | One of pull, push, status, qa. |
fail_on | error | Only for qa: the lowest severity that fails the job, error or warning. A blocked merge gate always fails it. |
cli_version | latest | npm dist-tag or exact version of @translatize/cli. qa needs 0.2.0 or newer. |
config | translatize.config.json | Path to the CLI config file, relative to the repo root. With the default path, qa also runs when the file is missing. |
api_url | "" | Override the API base URL (empty = CLI default). |
extra_args | "" | Extra flags appended verbatim, e.g. --fail-on-missing --json. |
node_image | node:24-alpine | Image that provides Node.js and npx. |
0.2.0 of the component added the qa command and the fail_on input. Include it as gitlab.com/translatize/gitlab/translatize@0.2.0, and pin the CLI with cli_version: "0.2.0" for reproducible pipelines. The component is published in the GitLab.com CI/CD Catalog at gitlab.com/translatize/gitlab; on GitLab.com, $CI_SERVER_FQDN/translatize/gitlab/translatize@0.2.0 resolves to the same component.translatize-sync, so including it twice (say, for status and qa) leaves you with one job. Use the component for one command and copy-paste jobs, with their own names, for the rest.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:
translatize-status:
stage: test
image: node:24-alpine
script:
- npx --yes @translatize/cli@latest status --config translatize.config.jsonSwap status for pull, push or qa, pin @latest to an exact version such as @0.2.0 for reproducible builds, and append flags such as --fail-on-missing or --json as needed.
CI/CD variable setup
- In Translatize, open your project and go to Project Settings → Integrations. Create an API token – it looks like
mcni_... and is shown only once. - 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; acreate-own-scope token may also target branches it created (select one with--branchinextra_args). If you sync more than one branch with standard tokens, mint one token per branch and store them under distinct variable names. - Any token role can run
pull,push,statusandqa;screenshots uploadandreleaseneed the developer role or higher. - In GitLab, go to Settings → CI/CD → Variables and add the token as a masked variable:
| Key | Value | Flags |
|---|---|---|
TRANSLATIZE_API_TOKEN | mcni_... | Masked |
The CLI reads this automatically – never echo it or pass it as a --flag.
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:
translatize-mr-gate:
stage: test
image: node:24-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.
Merge-request QA gate
Fail the pipeline on translation QA errors – broken placeholders, invalid ICU messages, text over its character limit, glossary violations. With the component:
include:
- component: gitlab.com/translatize/gitlab/translatize@0.2.0
inputs:
command: qa
fail_on: errorThe component job has no rules, so it runs in branch pipelines. To run the check in merge-request pipelines, use the job below instead:
translatize-qa:
stage: test
image: node:24-alpine
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
script:
- npx --yes @translatize/cli@latest qa --fail-on errorqa exits 1 on issues at the --fail-on severity or above (warning includes errors; info never fails). It checks the Translatize branch the token works on, not the git branch of the merge request. With a create-own token working on its own branch, add --branch <name> and it also reads that branch's merge gate into the token's base branch – a gate that would block the merge fails the job too. The checks are described under Quality checks.
Publish a delivery release
The component covers pull, push, status and qa. Other CLI commands run as plain jobs. This one publishes your delivery distribution when you start it from a pipeline on the default branch. It needs no config file and a token with the developer role, and allow_failure: true keeps the pipeline from waiting on the manual job:
translatize-release:
stage: deploy
image: node:24-alpine
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
when: manual
allow_failure: true
script:
- npx --yes @translatize/cli@0.2.0 releaseUploading Playwright screenshot captures works the same way: run npx --yes @translatize/cli@0.2.0 screenshots upload in the job that runs your tests, after they have written the captures (see the CLI docs).
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 and a role that may push to that branch, 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.
translatize-nightly-pull:
stage: test
image: node:24-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 --porcelaindetects 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.
