GitHub Actions Guide

Set up automatic translations in your pull requests. Every PR gets complete translations, automatically committed and ready to merge.

How it works

The init command automatically creates a GitHub Actions workflow file. Here's what happens when you open a pull request:

When it runs

The workflow triggers automatically when someone opens or updates a pull request that changes your translation files. It only watches the specific paths you configured in localhero.json.

Concurrency: If you push new changes while the workflow is running, it automatically cancels the old run and starts fresh with your latest changes.

What it does

1. Checks out your PR branch

2. Sets up Node.js

3. Runs npx @localheroai/cli ci using your API key from repository secrets

4. Compares your branch with the base branch to find changed keys

5. Translates the keys that were added or modified in your branch

6. Commits the translated files directly to your PR

Skipped automatically: Draft PRs, PRs with skip-translation label, and commits by the Localhero bot.

Permissions needed

contents: write - Allows the workflow to commit translated files back to your PR

pull-requests: write - Lets the workflow add information to the PR

These are standard GitHub permissions. All changes are made as separate commits in the PR for you to review.

Setting it up

Quick setup

1. Run npx @localheroai/cli init — if your project is already set up, running init again will only prompt you to create the workflow file

2. Add your API key to GitHub repository secrets as LOCALHERO_API_KEY

On GitHub: Repository → Settings → Secrets and variables → Actions → New repository secret.
Get your key from your account.

3. Commit the workflow file at .github/workflows/localhero-translate.yml

4. That's it! The next PR that changes translation files will trigger automatic translations.

View the generated workflow file

The auto-generated .github/workflows/localhero-translate.yml:

name: Localhero.ai - Automatic I18n translation

on:
  pull_request:
    paths:
      - "config/locales/**"
  workflow_dispatch:

concurrency:
  group: translate-${{ github.head_ref || github.run_id }}
  cancel-in-progress: true

jobs:
  translate:
    if: |
      !contains(github.event.pull_request.labels.*.name, 'skip-translation') &&
      github.event.pull_request.draft == false &&
      !(github.actor == 'localhero-ai[bot]' && github.event.action == 'synchronize')
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write

    steps:
    - name: Checkout code
      uses: actions/checkout@v5
      with:
        ref: ${{ github.head_ref }}
        fetch-depth: 0

    - name: Fetch base branch for comparison
      if: github.event_name == 'pull_request'
      run: |
        git fetch --no-tags origin ${{ github.base_ref }}

    - name: Set up Node.js
      uses: actions/setup-node@v5
      with:
        node-version: 22

    - name: Translate strings
      env:
        LOCALHERO_API_KEY: ${{ secrets.LOCALHERO_API_KEY }}
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        GITHUB_BASE_REF: ${{ github.base_ref }}
      run: npx -y @localheroai/cli ci

Customization

Skip translation for a PR

Add the skip-translation label to any PR to prevent the workflow from running. Draft PRs are also skipped automatically — translations run when you mark the PR as ready for review.

Run manually

The workflow includes workflow_dispatch trigger, so you can run it manually from the GitHub Actions tab.

Go to Actions → Localhero.ai - Automatic I18n translation → Run workflow

Change trigger paths

Edit the paths: section in the workflow file to watch different directories.

on:
  pull_request:
    paths:
      - "src/locales/**"    # Your custom path
      - "public/i18n/**"    # Additional path

Gettext / PO file projects

If your project uses gettext (PO files), you should run your message extraction command before the LocalHero CLI. This ensures new translation keys are properly extracted from your source code with correct source references.

    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: '3.11'

    - name: Install dependencies
      run: |
        sudo apt-get update && sudo apt-get install -y gettext
        pip install -r requirements.txt

    - name: Translate strings
      env:
        LOCALHERO_API_KEY: ${{ secrets.LOCALHERO_API_KEY }}
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        GITHUB_BASE_REF: ${{ github.base_ref }}
      run: |
        python manage.py makemessages -a
        npx -y @localheroai/cli ci

Adjust the extraction command for your framework (e.g., xgettext for C/C++, pybabel extract for Flask).

Need help? Drop us a line at hi@localhero.ai