The Lingo.dev GitHub App sets up continuous localization for a repository using .lingo/config.json.
Prerequisites#
Before you install the app, make sure you have:
- A Lingo.dev organization with the GitHub integration feature enabled
- A localization engine in that organization
- Admin access to the GitHub organization or repository you want to connect
If you are not an admin of the GitHub organization, GitHub lets you request the installation instead. A GitHub organization admin must approve that request before Lingo.dev can access the selected repositories.
Connect the GitHub App#
- In Lingo.dev, open your organization.
- Go to Settings.
- Find GitHub (App) in the integrations section.
- Click Connect on the GitHub (App) row.
- On GitHub, choose the account or organization to install the app into.
- Choose either All repositories or Only select repositories.
- Click Install.
After installation, Lingo.dev shows the connected GitHub account and repositories in Settings > GitHub (App). Use Manage repositories on GitHub from the same settings card when you need to add or remove repositories later.
If your install request is waiting for approval, a GitHub admin can review it in GitHub under the organization's Settings > GitHub Apps area. GitHub also shows pending app requests to organization owners in the organization settings.
Add the repository config#
Create .lingo/config.json in the repository you installed the app on:
{
"engineId": "eng_abc123",
"sourceLocale": "en",
"targetLocales": ["es", "fr", "de"],
"files": [
{ "pattern": "docs/en/**/*.md" },
{ "pattern": "docs/en/**/*.mdx" },
{ "pattern": "locales/en.json" }
],
"github": {
"workflows": {
"onPushToDefaultBranch": { "enabled": true },
"onPullRequest": { "enabled": true }
},
"safety": {
"requireApproval": false
}
}
}| Field | Required | Description |
|---|---|---|
engineId | Yes | The Lingo.dev engine that should translate this repository. |
sourceLocale | Yes | The source locale used in your source file paths, such as en or en-US. |
targetLocales | Yes | Locale codes to translate into. Up to 50 unique locales are supported. |
files | Yes | Repo-relative source file patterns. Up to 100 patterns are supported. |
github.workflows.onPushToDefaultBranch.enabled | No | Runs when source files change on the default branch. Enabled by default. |
github.workflows.onPullRequest.enabled | No | Runs when source files change in pull requests. Disabled by default. |
github.safety.requireApproval | No | Requires approval before automatic push or PR workflows translate. Disabled by default. |
File patterns#
files patterns point to source (default locale) files. The app checks changed files against these patterns and only processes supported source files that match.
Patterns are repo-relative, case-sensitive, and may use:
*to match inside one path segment**/to match any directory depth
Patterns cannot start with / and cannot contain ...
{
"files": [
{ "pattern": "docs/en/**/*.md" },
{ "pattern": "src/content/en/**/*.mdx" },
{ "pattern": "messages/en.jsonc" }
]
}Where localized files are written#
The app derives each target path from the source path and the locale codes in your config:
| Source path | Target locale | Output path |
|---|---|---|
docs/en/guide.md | es | docs/es/guide.md |
docs/en-US/guide.md | fr-FR | docs/fr-FR/guide.md |
locales/en.json | de | locales/de.json |
README.md | es | es/README.md |
Use the full directory name or filename as the locale code. For example, if source files live in docs/en-US/, set "sourceLocale": "en-US", not "en". If source strings live in messages/en.json, set "sourceLocale": "en".
When the source path contains a locale directory, the app replaces that directory. When the source path is a locale-named file, the app replaces the filename. If neither pattern exists, the app places the translated file in a new target-locale directory next to the source file.
Workflows#
Push to default branch#
When a matching source file is added or changed on the default branch, the app translates it and commits the localized files to:
lingo/translations/<default-branch>It then opens or updates a pull request from that translations branch back into the default branch. If the translations branch already exists, new commits are appended to it.
If a target file is added or changed in the same push, the app treats that file as already handled and carries it into the translation PR instead of overwriting it.
Pull requests#
When github.workflows.onPullRequest.enabled is true, the app checks pull request changes for matching source files. It commits translated files directly to the PR branch.
The app does not write to forked PR branches, and it does not write to the default branch from a PR comment. Pull requests must be open for the app to commit translations.
On PRs, Lingo.dev updates a PR comment with the translated files and any failures.
Incremental updates and recovery#
For existing target files, the app translates only the source changes it can detect instead of regenerating the whole file. For new target files, it creates the localized file for each configured target locale.
If a previous PR localization missed a source change or failed before updating the target file, the next PR synchronization can recover by comparing the PR source against the base branch source and translating the missing change.
If a source file no longer exists at the commit being processed, the app skips it.
Approval mode#
Set github.safety.requireApproval to true when you want a human approval step before automatic translations run.
On default-branch pushes, the Lingo.dev check run shows Approve and Deny actions. On pull requests, the app posts a translation proposal comment; reply with:
/lingo approveScoped /lingo translate commands do not require this approval gate.
Manual PR command#
Use /lingo in a pull request comment to backfill or force translations for specific files.
/lingo translate docs/en/**/*.md/lingo translate docs/en/**/*.mdx --locales fr,es/lingo translate docs/en/**/*.md --forceCommand reference:
| Command | Description |
|---|---|
/lingo | Shows help. |
/lingo help | Shows help. |
/lingo translate <glob>... | Translates missing target files for matching source files. |
/lingo translate <glob>... --locales fr,es | Limits the run to configured target locales. Locale values are lowercased by the command parser. |
/lingo translate <glob>... --force | Translates every matching source and locale in scope, overwriting existing targets. |
/lingo approve | Approves a pending translation proposal on the PR. |
The command must be on its own line. Globs are matched against files that also match your configured files source patterns. Like config patterns, command globs cannot start with / and cannot contain ...
By default, /lingo translate runs in backfill mode: it only creates target files that are missing on the PR branch. Add --force when you want to regenerate existing target files.
Supported formats#
The GitHub App currently supports:
- JSON (
.json) - JSONC (
.jsonc) - Markdown (
.md) - MDX (
.mdx)
More formats are coming soon.
Large updates#
The app may split translation output across multiple commits. This happens when a run would write more than 100 files in one commit or more than 5 MB of translated file content in one commit.
When that happens, commit messages include the batch number, such as:
feat: Lingo.dev translations (1/3)
feat: Lingo.dev translations (2/3)
feat: Lingo.dev translations (3/3)What happens when nothing matches#
If .lingo/config.json is missing, the app skips the repository silently. Once the config exists, invalid config creates a failing check run and, on PRs, a comment with the validation error.
If no changed files match your source patterns, the app completes without writing translations. For /lingo translate, the bot replies with a short explanation, such as no matching files, no matching locales, or all target files already existing.
