Ship in every language.
Zero manual work.
Lokali watches your source locale file and opens a translation PR every time you push new strings. This page covers install, config, and the PR workflow.
Quickstart
Three steps from zero to automated translations. No CLI, no config files to write manually — Lokali's welcome PR creates everything for you.
Visit github.com/apps/lokali and click Install. Select the repos you want Lokali to watch. Takes 30 seconds.
Within a minute, Lokali scans your repo for a source locale file (e.g. messages/en.json, locales/en.json). If found, it opens a PR adding .lokali.yml and LOKALI.md with sensible defaults.
.lokali.yml (config) and LOKALI.md (team quickstart) to your repo.
Edit target_locales to pick your languages, then merge.
Merge the welcome PR. From now on, every push that touches your source locale file triggers a translation PR for all your target languages — automatically, within minutes.
target_locales in .lokali.yml before merging. The full config reference is below.
en.json file, and Lokali picks it up automatically.
.lokali.yml
Drop a .lokali.yml in the root of your repo (Lokali's welcome PR does this automatically). Here's the full schema.
| Key | Type | Description | |
|---|---|---|---|
| source | string | BCP-47 language code for your source strings. Usually en. |
required |
| targets | string[] | List of target language codes. Add or remove codes to control which languages get PRs. | required |
| paths | string[] | Glob patterns for locale files. Use {lng} as a placeholder for the language code. Lokali watches these paths for changes. |
required |
| exclude | string[] | Paths to skip. Useful for internal-only keys, generated files, or non-translatable locale data. | optional |
| glossary | string[] | Terms that must never be translated. Brand names, product names, technical identifiers. Passed as hard constraints to the model. | optional |
| pr_strategy | string | batch (default) — one PR per push, all languages in one branch. per_language — a separate PR per target locale. |
optional |
Supported languages: Spanish, French, German, Portuguese (BR + PT), Japanese, Korean, Chinese Simplified, Chinese Traditional, Arabic, Hindi.
Copy-paste configs per framework
messages/en.json for changes. When you push new keys, it writes messages/es.json, messages/fr.json, etc. and opens a PR.public/locales/en/translation.json. Targets: public/locales/es/translation.json, etc. Works with multiple namespaces — add more entries to paths.locales/en.json. Targets: locales/es.json, locales/fr.json, etc. If you use namespaced files, add patterns like locales/{lng}/common.json.src/locales/en.json. Targets: src/locales/es.json, etc. Works with both JSON and YAML locale files — use .yml extension in the path if your project uses YAML.config/locales/en.yml. Use the exclude list to skip gem-generated locale files like devise or activerecord that shouldn't be translated.Translation PRs
Every push that touches your source locale file triggers Lokali. Within minutes, a translation PR appears with every target language updated.
PR title format
PR body format (example)
How to review
Each locale file is a separate diff. Review the language you know first — check tone and proper nouns. The rest is usually correct without review.
If you've set a glossary in .lokali.yml, Lokali hard-codes those terms as untranslated. Verify they're preserved correctly.
Use GitHub's standard PR review. If a specific locale needs adjustment, leave a comment or edit the file directly in the PR branch.
FAQ
Edit the targets list in your .lokali.yml and push. Lokali detects the config change and opens a PR with the new language translated from your source file. No other setup needed.
Yes. Add terms to the glossary key in .lokali.yml. Anything in the glossary is passed as a hard constraint to the model — it will never be translated, transliterated, or paraphrased. Useful for product names, technical terms, and trademarks.
Edit the target locale file directly — either in the PR branch before merging, or in your main branch after. Lokali respects existing values by default: it only writes keys that are new or changed in the source. Your manual overrides stay intact.
Within minutes of the push that touches your source locale file. Most PRs appear in under 3 minutes. During high-load periods it may take up to 10 minutes. There is no manual queue — processing starts automatically when the webhook fires.
GPT-4o-mini with the full diff context plus your glossary and repo language as constraints. The model sees the entire key-value structure of your source file, not just isolated strings — this gives it enough context to translate idioms and UI-specific language correctly.
No source code is sent to OpenAI. Lokali only sends the changed key-value pairs from your locale file — the actual translation strings — plus minimal context (your repo's primary language detected from the README, and your glossary). No routes, no components, no business logic, no secrets. The privacy boundary is: if it's not in your locale JSON/YAML, it doesn't leave your repo.
Go to GitHub Settings → Applications → Lokali → Configure → Uninstall. Lokali immediately stops watching your repos. Your existing locale files stay exactly as they are — nothing is deleted. You can also remove .lokali.yml and LOKALI.md manually afterward if you want a clean slate.
Yes. Add multiple entries to paths to cover nested packages. For example:
paths: [apps/web/messages/{lng}.json, packages/ui/locales/{lng}.json]
Lokali watches each glob independently and groups changes from the same push into a single PR.
Ready to ship every language?
Install takes 30 seconds. First translation PR on your next push.