CI/CD pipelines

GitHub is the platform we support today, through the ready-made Action. On GitLab CI, Bitbucket Pipelines, Jenkins or anything else that runs a shell, you can still run the CLI yourself with translate --changed-only. It needs Node 18 or later, the LOCALHERO_API_KEY environment variable, and a clone with the base branch in it.

Running on something other than GitHub? We would like to hear about it: hi@localhero.ai. Knowing which platforms people actually use is what decides where first-class support goes next.

What the CLI does in a pipeline

  1. Your branch adds or changes keys in your source locale files.
  2. The pipeline runs npx @localheroai/cli translate --changed-only, which translates the keys that changed against your base branch and writes them to your locale files.
  3. Your pipeline commits the result, and you review and edit translations in the dashboard.

There is also a ci command, which is what the GitHub Action runs. It reads GitHub's own environment variables to tell a pull request from the default branch, so outside GitHub Actions it cannot detect the branch and falls back to translating every missing key. On other platforms use translate --changed-only instead.

Setup

1. Initialize the project locally

Run this once in your project root, on your own machine rather than in CI. It writes a localhero.json that you commit:

npx @localheroai/cli init

2. Put your API key in the runner's environment

Add your API key as a masked CI variable or secret, named LOCALHERO_API_KEY. The CLI reads that environment variable first, and it takes precedence over the local .localhero_key file, so a CI job never needs the key file on disk.

3. Fetch the base branch, not a shallow clone

--changed-only works out what to translate by diffing your branch against the base branch, so that branch has to exist in the clone the job is working with. Most CI systems clone shallow by default, which is exactly the case where the diff has nothing to compare against. Turn that off, or fetch the base branch explicitly, in whatever way your runner exposes. On GitHub Actions this is the fetch-depth: 0 setting on the checkout step, and other runners have their own equivalent.

4. Run the CLI

Plain shell, nothing platform-specific in it:

export LOCALHERO_API_KEY="<your API key, from a CI secret>"

npx @localheroai/cli translate --changed-only

Wrapped in a minimal GitLab-flavored job, where every script: line is that same shell:

.gitlab-ci.yml (excerpt)
translate:
  image: node:20
  variables:
    GIT_DEPTH: 0
  script:
    - npx @localheroai/cli translate --changed-only

Set LOCALHERO_API_KEY as a masked project variable so the job inherits it, and make sure the job's clone includes the base branch as described above.

Things worth knowing

Committing the result

translate writes the translated files and leaves them in your working tree, so the commit and push are your pipeline's. Worth checking before you wire it up: default CI tokens are often read-only or blocked from protected branches, so give the job push rights on the branches it needs.

Why not the ci command

ci is what the GitHub Action runs. It reads GITHUB_HEAD_REF and GITHUB_REF_NAME to tell a pull request from the default branch, and commits the result itself. Neither variable exists on other runners, so it cannot detect the branch and translates every missing key instead of only the changed ones. It still works, but it might translate more than you expect on each run.

npx @localheroai/cli translate --changed-only

Which branch it compares against

--changed-only diffs against main by default. If your default branch has another name, or you want a different comparison point, set translationFiles.baseBranch in localhero.json.

Every command and flag: CLI reference. Longer walkthrough of the idea: automating SaaS localization in your CI pipeline.

Last updated

Klar til å prøve?

Kom i gang på noen minutter. Du trenger ikke kredittkort.