GitHub Action

Translatize Sync wraps the Translatize CLI so you can keep your repository and your Translatize project in sync from CI – push new source keys, pull completed translations, and gate pull requests on missing or changed strings and on translation QA errors.

What it does

The action runs a single Translatize CLI command inside your workflow:

CommandWhat it does
pushUploads source keys from your repo to the token branch.
pullDownloads translations from the token branch into your local files.
statusReports the diff between repo and branch; can fail the job on missing or changed strings.
qaRuns the quality checks on the branch and reads its merge gate; fails the job on errors (or warnings) and whenever the gate would block the merge.

It authenticates with a branch-bound API token (mcni_...), which the action passes to the CLI as the TRANSLATIZE_API_TOKEN environment variable. A token carries a base branch, so most workflows never set a branch at all. A token whose scope is create-own may additionally target branches it created – pass --branch <name> through args (or set branch in the config) to sync one.

The action first sets up Node.js, then the step runs (--fail-on is added only for qa):

npx --yes @translatize/cli@<version> <command> --config <config> [--api-url <api-url>] [--fail-on <fail-on>] <args>

Every command follows the CLI exit-code contract, so a failed check fails the job: 0 on success; 1 when a gate trips (a --fail-on-* flag of status, QA issues at the fail-on severity, or a blocked merge gate) or an API error occurs (for example an expired token); 2 on a usage or configuration error. An unknown command, or an unknown fail-on value with qa, fails the step before the CLI runs.

Quickstart

  1. Create a token. In Translatize, open Project Settings → Integrations and create an API token. Pick the branch it should be bound to (for example main). Copy the mcni_... value – it is shown only once.
  2. Store it as a secret. In your GitHub repo, go to Settings → Secrets and variables → Actions → New repository secret, name it TRANSLATIZE_TOKEN, and paste the token.
  3. Commit your config. Add a translatize.config.json at the repo root – the same file the CLI reads locally. See the CLI documentation for its fields.
  4. Add a workflow. Start with the status gate below, then add push and pull.
.github/workflows/translatize.yml
name: Translatize
on: [workflow_dispatch]
jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: translatize/sync-action@v1
        with:
          command: status
          token: ${{ secrets.TRANSLATIZE_TOKEN }}

Workflow recipes

Push new source keys on every push to main

Whenever your source strings change on main, upload the new keys to Translatize so translators can start working.

.github/workflows/push-keys.yml
name: Push source keys to Translatize

on:
  push:
    branches: [main]
    paths:
      - 'locales/en.json'
      - 'src/**/*.json'

jobs:
  push:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Push source keys
        uses: translatize/sync-action@v1
        with:
          command: push
          token: ${{ secrets.TRANSLATIZE_TOKEN }}

Nightly translation pull that opens a pull request

Pull finished translations every night and let a second action open a pull request with the changes, so a person reviews and merges them.

.github/workflows/nightly-pull.yml
name: Nightly translation pull

on:
  schedule:
    - cron: '0 3 * * *'
  workflow_dispatch:

permissions:
  contents: write
  pull-requests: write

jobs:
  pull:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Pull latest translations
        uses: translatize/sync-action@v1
        with:
          command: pull
          token: ${{ secrets.TRANSLATIZE_TOKEN }}

      - name: Open a pull request
        uses: peter-evans/create-pull-request@v7
        with:
          commit-message: 'chore(i18n): sync translations from Translatize'
          title: 'Update translations from Translatize'
          body: 'Automated nightly translation sync from the Translatize branch bound to TRANSLATIZE_TOKEN.'
          branch: chore/translatize-sync
          labels: i18n, automated
Permissions
create-pull-request needs the contents: write and pull-requests: write permissions shown above. If the PR step fails to open a PR, also enable Settings → Actions → General → Allow GitHub Actions to create and approve pull requests.

Block a PR when translations are missing

Run status --fail-on-missing on pull requests so a PR that adds untranslated source keys turns the check red until translations land.

.github/workflows/status-gate.yml
name: Translation status gate

on:
  pull_request:
    branches: [main]

jobs:
  status:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Fail if translations are missing
        uses: translatize/sync-action@v1
        with:
          command: status
          token: ${{ secrets.TRANSLATIZE_TOKEN }}
          args: --fail-on-missing
Swap --fail-on-missing for --fail-on-diff to instead fail when a source string changed but its translations were not updated. Pass both to enforce either condition.

Block a PR on translation QA errors

Run qa on pull requests so broken placeholders, invalid ICU messages, text over its character limit or glossary violations turn the check red. It checks the Translatize branch the token works on, not the git branch of the pull request. With a create-own token that works on its own branch, pass --branch <name> through args and the step also reads that branch's merge gate into the token's base branch.

.github/workflows/translation-qa.yml
name: Translation QA

on:
  pull_request:
    branches: [main]

jobs:
  qa:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Fail on QA errors
        uses: translatize/sync-action@v1
        with:
          command: qa
          token: ${{ secrets.TRANSLATIZE_TOKEN }}
          fail-on: error
Set fail-on: warning to fail on warnings too. Info-level findings never fail the step. Add --json to args to get the full report in the log. The checks themselves are described under Quality checks.

Screenshots and releases

The action runs pull, push, status and qa. For screenshots upload and release, call the CLI in a run step. Both need a token with the developer role. This workflow publishes your delivery distribution when you start it by hand. If the token can see more than one distribution, add --distribution <name>.

.github/workflows/publish-translations.yml
name: Publish translations
on: workflow_dispatch

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/setup-node@v4
        with:
          node-version: 24
      - name: Publish the delivery distribution
        run: npx --yes @translatize/cli@0.2.0 release
        env:
          TRANSLATIZE_API_TOKEN: ${{ secrets.TRANSLATIZE_TOKEN }}

Inputs

InputRequiredDefaultDescription
commandyes–CLI command to run: pull, push, status, or qa. Any other value fails the step.
tokenyes–Branch-bound Translatize API token (mcni_...). Passed to the CLI as TRANSLATIZE_API_TOKEN. Use a secret.
versionnolatest@translatize/cli version to run (for example 0.2.0). qa needs 0.2.0 or newer.
confignotranslatize.config.jsonPath to the CLI config file, relative to the workspace. With the default path, qa also runs when the file is missing.
api-urlno""Override the Translatize API base URL. Empty uses the CLI default.
fail-onnoerrorOnly for qa: the lowest severity that fails the step, error or warning. A blocked merge gate always fails it. Ignored by the other commands.
argsno""Extra CLI flags appended verbatim, split on whitespace, e.g. --dry-run, --json, --fail-on-missing, --fail-on-diff, --branch <name>.
node-versionno24Node.js version used to run the CLI.

This action has no outputs – surface results through the step exit status (a red check) and the CLI --json output in the logs.

Setting up the token secret

Tokens are created in Project Settings → Integrations at app.translatize.com and are prefixed mcni_. Store the value as a repository (or environment/organization) secret named TRANSLATIZE_TOKEN and reference it as token: ${{ secrets.TRANSLATIZE_TOKEN }}. Never paste the raw token into a workflow file.

A token carries its own role – translator, developer or admin. Any of them can run pull, push, status and qa, including creating new keys with push; screenshot uploads and releases need developer or higher. A token may also be limited to IP addresses or given an expiry date – set these to match what the workflow needs.

One token per branch

Each API token has a base branch, chosen when you mint it. A standard (fixed-scope) token may act only on that branch, so naming a different one is rejected by the API – the branch is decided by the token, not the workflow. A create-own-scope token is the exception: it may also target branches it created, selected with --branch via args or the config branch field. Teams that sync several branches with fixed-scope tokens typically create one token per branch – a main-bound token for the workflows on main, and a separate token bound to staging stored as a second secret. Rotate a token by creating a new one and updating the secret; revoking the old token in Translatize invalidates it immediately.

Versions and publishing

Published on the GitHub Marketplace
The action is live on the GitHub Marketplace, with its source at github.com/Translatize/sync-action. Reference it as uses: translatize/sync-action@v1, exactly as the examples above do.

@v1 follows the latest 1.x release. The current one is v1.1.0, which added the qa command and the fail-on input. To pin an exact release, use translatize/sync-action@v1.1.0 or a full commit SHA, and set version to pin the CLI as well.

You can also consume the action without the Marketplace: copy action.yml from the source repository into your own (for example to .github/actions/translatize/action.yml) and reference it by path with uses: ./.github/actions/translatize, or fork the repository and pin to a tag or commit SHA. Both take the same inputs as the Marketplace version.