CI/CD

GitHub Actions

Gate a Pull Request

No action needed: run the CLI and let its exit code decide the job.

@v8 follows the CLI's major: template changes reach you with the release they were written for. @main can run ahead of the CLI a pinned project installs.

.github/workflows/i18n.yml
name: i18n

on: pull_request

jobs:
  gate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22

      - name: Fail on keys that would render raw
        run: npx -y @the-i18n-kit/cli@latest check

      - name: Fail when coverage drops below 90%
        run: npx -y @the-i18n-kit/cli@latest status --fail-under 90

Both steps fail the job with exit 2 on findings. check alone is the gate worth having on day one: it needs no config file and no API key. Every gate flag is on the agent contract.

Translate Missing Keys

The composite action installs @the-i18n-kit/cli on the runner and runs translate in your checkout. Committing the result is a step of your own. Every input and output is generated from the manifest in the action reference.

.github/workflows/i18n-translate.yml
name: i18n translate

on:
  pull_request:
    paths:
      - 'i18n/locales/en.json'

permissions:
  contents: write
  pull-requests: write

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

      - uses: fabkho/the-i18n-kit@v8
        with:
          provider: google
          model: gemini-2.5-flash
          api_key: ${{ secrets.GEMINI_API_KEY }}
          layer: common

      - uses: peter-evans/create-pull-request@v7
        if: ${{ !cancelled() }}
        with:
          add-paths: |
            i18n/locales
            .i18n-kit.lock.json
          branch: i18n/translate-missing
          commit-message: 'chore(i18n): translate missing keys'

Five things there are load-bearing:

  • actions/checkout@v4 first. The action runs against the working directory.
  • layer. Required, and always passed to the CLI. Run the-i18n-cli status to see the names your project resolves — projects with one locale directory usually have one layer named root.
  • if: ${{ !cancelled() }} on the commit step. A tripped gate fails the action, and an unguarded follow-up step would be skipped along with it, discarding translations the run had already written.
  • .i18n-kit.lock.json in add-paths. The translation memory the run wrote, which is what a later run reads to tell a translation still made from the current source from one whose source has changed since. Left out of the commit, it goes with the runner and every run starts with no memory. Drop the line if you set translationMemory: false.
  • contents: write and pull-requests: write. The commit step pushes a branch and opens the pull request. Repositories can also disable pull request creation by Actions entirely, under Settings → Actions → General.

api_key reaches the CLI as the environment variable of the provider you chose, never as a command-line argument. cli_version: skip skips the install step when an earlier step already put the CLI on the PATH. Pin the action to a tag once you have a version you trust.

When the Job Fails

SituationExitWhat happens
Everything translated0Green, the commit step runs
Some keys failed, fail_on_failed off (default)0Green; the failed keys stay missing and the next run retries them
Some keys failed, fail_on_failed: true2Red, and the guarded commit step still keeps what succeeded
Nothing translated at all — unusable API key, unknown provider, unreadable project1Red, with nothing to commit

The full mapping is on the agent contract. The translated_count and failed_count outputs are for logs and downstream steps; they never decide the job outcome.

Copyright © 2026