Docs menu
Monorepos
In a monorepo with several apps, give each app its own Localhero.ai project and its own localhero.json in the app's directory. One GitHub Actions workflow at the repository root runs a job per app with working-directory pointing at it. Each app keeps its own target languages, and a sync from the web app lands only in the app it belongs to.
Prerequisites
- A Localhero.ai project for each app. Apps can have different target languages.
- The Localhero GitHub App installed on the repository.
- A
LOCALHERO_API_KEYrepository secret. One key covers every project in the organization. - CLI 0.0.80 or later. The Action uses the latest CLI unless you pin
cli-version.
Setup
1. Run init in each app's directory
cd apps/web
npx @localheroai/cli init
Answer no when it offers to set up GitHub Actions. init writes localhero.json next to the app; the workflow it offers would land in apps/web/.github/workflows/, which GitHub does not run. The workflow belongs at the root (step 2). Translation paths in localhero.json are relative to the app's directory.
2. Add one workflow at the repository root
.github/workflows/localhero-translate.yml:
name: Localhero.ai - Automatic I18n translation
on:
pull_request:
paths:
- "apps/*/public/locales/**"
- "apps/*/localhero.json"
repository_dispatch:
types: [localhero-sync]
workflow_dispatch:
concurrency:
group: translate-${{ github.event.client_payload.branch || github.head_ref || github.run_id }}
cancel-in-progress: false
jobs:
translate:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
strategy:
matrix:
app: [web, admin]
steps:
- name: Checkout code
uses: actions/checkout@v7
with:
ref: ${{ github.event.client_payload.branch || github.head_ref || github.ref_name }}
fetch-depth: 0
persist-credentials: false
- name: Translate
uses: localheroai/localhero-action@v1
with:
api-key: ${{ secrets.LOCALHERO_API_KEY }}
working-directory: apps/${{ matrix.app }}
Change matrix.app to your app directories and the paths entries to where their locale files live. Keep apps/*/localhero.json in paths.
3. Try it
Open a pull request that adds a string to one app. That app's job translates it and commits to the branch; the other apps' jobs find nothing to do.
How it fits your workflow
One job per app. Each job reads the localhero.json in its working-directory and only sends that app's keys.
cancel-in-progress: false matters with a matrix. Each app commits its translations to the pull request, and that commit starts a new run. With cancel-in-progress: true, the new run cancels the one still in progress, including apps that have not finished translating.
Two apps committing at the same time. Both jobs start from the same commit, so the second push is rejected. The CLI puts its commit on top of the first one and pushes again. If the other commit changed one of the same translation files, it skips its commit with a notice instead of overwriting it.
Syncs from the web app. A sync reaches every app's job. The app it belongs to applies it; the others print "Nothing to apply here" and pass.
Shared terminology. Glossary terms can belong to the organization instead of a single project, so product names and fixed terms stay consistent across apps. See glossary and settings.
One project or several
A project maps to a set of locale paths, not to a repository. One project can cover several catalogs in the same repo, with one glossary and one translation memory. Use separate projects when apps need different target languages, different terminology or different reviewers. Separate projects is the setup this page describes.
Limitations
- Export to GitHub (sending web-app edits as a new pull request) does not work yet for a project whose
localhero.jsonis in a subdirectory. Edits made while a pull request is open sync to that pull request as normal. - Connecting the repository can open a setup pull request that adds a
localhero.jsonat the root. Close it; each app has its own.
FAQ
Can the apps have different target languages?
Yes. Each project has its own languages, and each localhero.json lists its own outputLocales.
Do I need one API key per app?
No. The key belongs to the organization and works for every project in it.
Does every app run on every pull request?
Yes, the matrix starts a job per app. A job with nothing to translate finishes in seconds. To skip apps entirely, split the workflow per app with its own paths filter.
Can I run the CLI without the Action?
Yes. Run npx @localheroai/cli ci with working-directory set to the app's directory, or cd into it first.
Further reading
- GitHub Actions, the full workflow reference.
- Translations in the pull request, how commits, syncs and reviews work on a branch.
- i18next, for React and Next.js apps.
Last updated
Ready to try it?
Get setup in a couple of minutes. No credit card required.