GitHub App

Updated

The Translatize GitHub App gives every pull request that changes your source strings its own translation branch and a Translatize check with translation status and quality results. Translations can be committed back to the pull request, and the branch is merged into your base branch when the pull request merges. There is no workflow file to write and no token secret to store.

What you need

  • A project on the Professional or Agency plan (see Plans).
  • The admin or owner role in the Translatize project.
  • Write or admin access to the repository on GitHub, for your own GitHub account. The repository is on github.com.
  • JSON locale files, one per language, such as locales/en.json and locales/de.json – nested or flat.

Install and link a repository

  1. In the app, open the project, then Project Settings → GitHub (in the Developers group). Only admins and owners see this tab.
  2. Under 1. Install the GitHub App, click Install the GitHub App (Install on another account when an installation is already listed). GitHub opens in a new tab.
  3. On GitHub, choose your account or organization and the repositories the app may access, and confirm. You can change that list later on GitHub. On an organization, GitHub may send your request to an organization owner instead – once they approve it, click Install the GitHub App again and choose the organization.
  4. GitHub sends you back to the project's GitHub tab, which confirms: "The GitHub App is installed on your-account. Pick a repository below to finish."
  5. Under 2. Pick a repository, choose the repository and the Base branch – the Translatize branch that pull request branches start from and are merged back into, usually main. Set the options described under Settings and click Link repository.
  6. Commit a translatize.config.json to the root of the repository. The tab shows one with your project id filled in, under Add translatize.config.json to the repository, with a Copy button. Pull requests whose branch contains the file are processed from then on.

Linking is tied to your own GitHub account: the repository list shows only repositories it can write to, as GitHub confirmed during the install. Another admin of the project who wants to link a repository goes through Install the GitHub App once with their own GitHub account. If the organization uses single sign-on, sign in to it on GitHub first.

A project links one repository, and a repository can be linked to one project at a time. Once linked, the tab shows the repository with its status – Active, Paused – plan or Paused – needs attention – and, when it is paused, what to do about it.

The app's access to Translatize
Linking creates an API token for the app. It is listed under Project Settings → Integrations with a GitHub App badge and can only be renewed or revoked in the GitHub tab. Linking, changing and unlinking the repository are recorded in the audit log.

translatize.config.json

The app reads translatize.config.json from the root of the repository, at the pull request's latest commit – so a change to the file applies to the pull request that makes it. It is the same file the CLI and the GitHub Action read, plus an optional github block that the CLI ignores.

translatize.config.json
{
  "projectId": "your-project-id",
  "format": "json-nested",
  "files": "locales/{lang}.json",
  "github": {
    "autoTranslate": true,
    "commitTranslations": "on-request",
    "requireComplete": false,
    "syncDefaultBranch": true
  }
}

Every field the file can hold:

FieldGitHub AppDescription
projectIdrequiredThe id of the project this repository is linked to. The CLI may leave it empty; the GitHub App needs it and stops with a message on the check when it is missing or names another project.
formatrequiredjson-nested (dotted keys become nested objects) or json-flat (dotted keys stay flat). The GitHub App works with these two formats.
filesrequiredPath of each language file with a {lang} placeholder, such as locales/{lang}.json. It must be a relative path inside the repository: no .., no leading /, nothing in .git.
namespaceoptionalOnly keys beginning with <namespace>. are synced; the rest of the file is ignored.
githuboptionalSettings for this repository. Each key overrides the matching setting in the GitHub tab – see below.
apiUrlignoredUsed by the CLI only.
branchignoredUsed by the CLI only. The GitHub App works from the base branch chosen in the GitHub tab.

The github block. A key you leave out falls back to the setting in the GitHub tab; the defaults below are the tab's own.

KeyValuesDefaultDescription
sourceLanguagelanguage codethe project source languageThe language of the source file. Without it, the app uses the project's source language (Project Settings → Languages), else en when the project has it, else the project's first language. It must be a project language.
autoTranslatetrue / falsetrueAI-translate the strings a pull request adds or changes.
commitTranslationson-request, auto, neveron-requestWhen translations are committed to the pull request – see Committing translations back.
requireCompletetrue / falsefalseFail the check until every target language has a value for each changed key.
syncDefaultBranchtrue / falsetrueWrite source strings that reach the repository default branch to the Translatize base branch.

A file with every field looks like this – apiUrl and branch are there for the CLI:

translatize.config.json
{
  "apiUrl": "https://api.translatize.com/v1",
  "projectId": "your-project-id",
  "format": "json-flat",
  "files": "src/i18n/{lang}.json",
  "namespace": "web",
  "branch": "main",
  "github": {
    "sourceLanguage": "en",
    "autoTranslate": true,
    "commitTranslations": "auto",
    "requireComplete": true,
    "syncDefaultBranch": false
  }
}

The source file and each language file are read and written as JSON and nothing else. A file larger than 5 MB is skipped with a note on the check, and the config file itself may be up to 64 KB.

What happens on a pull request

Take pull request #42, which rewords one button and adds another in the source file:

locales/en.json
// locales/en.json in pull request #42
{
  "checkout": {
-   "cta": "Buy now",
+   "cta": "Complete purchase",
+   "express": "Pay with one click"
  }
}

When the pull request is opened, gets new commits, is reopened or is marked ready for review – drafts included – the app does this:

  1. Compares the source file. It reads the config and the source-language file at the pull request's latest commit and compares the file with the commit the pull request branched off. Strings that changed on the base branch since then don't count as the pull request's. Here: checkout.express is added and checkout.cta is changed.
  2. Creates the branch. The first time, it creates the Translatize branch pr-42 from your base branch; later pushes reuse it. If a branch called pr-42 already exists and the app did not create it, the app uses pr-42-2, then pr-42-3, and so on, and leaves the existing branch alone.
  3. Adds the strings. The new and changed source strings are written to pr-42 in the source language. Keys removed from the source file are listed on the check but stay in Translatize.
  4. Translates them. With AI translation on, the strings that changed since the last push the app processed are translated into every other project language. A changed string gets fresh translations on pr-42; the base branch keeps its old ones until the merge. A push that doesn't touch the source file translates nothing, so it uses no AI characters.
  5. Checks quality. The quality checks run on the changed keys, and the project's merge gate says whether it would let pr-42 merge.
  6. Reports. The app posts the Translatize check on the pull request's latest commit, and updates it on every later push.

A pull request that adds or changes no source string gets a passing check, "No translation changes", and no branch. Changes to the other language files don't count: the app reads only the source-language file of a pull request.

When someone works on pr-42 in Translatize – a translator fills in a language, a reviewer fixes a string – the check updates on its own. Everyone in the project sees a PR #42 badge next to the branch in the branch lists, which links to the pull request.

When AI translation runs

It is the same AI translation you start in the app, so the project's AI translation settings apply, and it uses the project's monthly AI translation characters. If AI review after AI translation is on under Quality checks, the pull request's translations are reviewed too. It does not run:

  • when Translate new strings automatically is off (or autoTranslate is false);
  • for pull requests from forks;
  • when the project has no language besides the source language.

If another translation job is running in the project, the app waits for it and starts afterwards. If the characters left this month are not enough for the strings, nothing is translated and the check says so in its notes.

Pull requests from forks

A pull request from a fork gets its branch and its check like any other. It is never AI-translated – anyone can open one, and it would spend your project's AI translation characters – and nothing is ever committed to a fork. The check says so. Translate its strings in Translatize; they are merged with the rest when the pull request merges.

The Translatize check

The check is called Translatize. Its Details link opens the pull request's branch in Translatize. The title tells you where things stand:

Title (examples)ResultWhen
Translating 2 changed keysneutralAI translation is running. The check updates when it finishes.
2 changed keys – all translatedsuccessEvery target language has a value for every changed key.
2 changed keys – 4 translations missingsuccessSome values are missing, and the check is not set to fail on that.
4 translations missingfailure"Fail the check while translations are missing" is on.
2 QA errors block the mergefailureThe project merge gate is set to Block, and these errors would stop the merge.
No translation changessuccessThe pull request adds or changes no source string.

The summary underneath shows:

  • how many keys were added and changed, and the source language;
  • a table with Translated and Missing per target language, for the changed keys (any value counts as translated, whatever its review status);
  • the QA errors and warnings, with the merge gate mode – or that the gate blocks this merge;
  • how many keys the pull request removed;
  • a link such as Open pr-42 in Translatize, and below the summary the changed and removed keys and any notes.

The merge gate is set in Project Settings → Quality checks. Its default, Warn, shows QA errors without failing the check; Block makes them fail it. If the gate covers main only and your base branch is another branch, the check says the gate does not apply.

Make it a required check
To keep the merge button disabled while the check fails, add Translatize as a required status check in your repository's branch protection rules on GitHub.

Committing translations back

Translations live on the pull request's Translatize branch. Whether they are also committed to the pull request is your choice:

In the GitHub tabIn the configWhat happens
On request – a "Sync translations" button on the checkon-requestThe default. The check offers a Sync translations button; click it to commit.
Automatically – after each translation runautoThe app commits whenever an AI translation run for the pull request completes. A failed run commits nothing.
Never – translations stay in TranslatizeneverNothing is committed. Bring translations into the repository with translatize pull or the GitHub Action.

Sync translations appears on the check when the mode is On request, the pull request comes from a branch of the same repository, it changes source strings, and no translation is running.

The commit is one commit on the pull request's branch, made by the app, with the message chore(i18n): sync translations from Translatize. It holds one file per target language at the files path – locales/de.json, locales/fr.json – written exactly as translatize pull writes them: keys sorted, two spaces of indentation, a trailing newline, empty values left out. Files that would not change are left alone; when none would, the check notes "Translations in this pull request are already up to date." The app's own commit does not start another round – the check just moves to the new commit.

Target-language files come from Translatize
Each target file is written from the pull request's Translatize branch, so a change made by hand in, say, locales/de.json is replaced by the next commit. Edit translations in Translatize.

Settings

The GitHub tab holds the settings for the linked repository. A change is saved at once, and open pull requests are checked again with the new settings. A key in the config's github block wins over the tab for that repository.

SettingConfig keyDefaultWhat it does
Base branch–mainThe Translatize branch that pull request branches start from and are merged back into. When you change it, open pull requests keep their branches and the next ones start from the new base branch.
Translate new strings automaticallyautoTranslateonAI translates the source strings a pull request adds or changes.
Commit translations to the pull requestcommitTranslationsOn requestOn request, Automatically or Never – see above. Never for pull requests from forks.
Fail the check while translations are missingrequireCompleteoffThe Translatize check fails until every target language has a value for each changed key.
Sync pushes to the default branchsyncDefaultBranchonSource strings that reach the repository default branch, including commits pushed without a pull request, are written to the base branch. Only the source language is written; nothing is translated automatically.

When the pull request merges or closes

When pull request #42 is merged on GitHub, the app merges pr-42 into the base branch from the GitHub tab, whatever branch the pull request targeted on GitHub:

  • If its AI translation is still running, the app waits for it, so the merge includes the result.
  • Only what the pull request's branch added or changed is merged, language by language. Everything else on the base branch stays as it is, including changes made there while the pull request was open.
  • Keys removed from the source file are not deleted from the base branch.
  • A string the pull request changed and later changed back is not merged, so the abandoned text never reaches the base branch.
  • Where a key was also edited on the base branch while the pull request was open, the pull request's value wins. The check then reads "Translations merged – recheck 3 keys" and lists them, so someone can look again.
  • Then pr-42 is deleted.

If the merge gate is set to Block and finds QA errors, nothing is merged. The check fails with "Translations not merged – QA errors", the branch is kept, and the project's admins and owners get an in-app notification: "Translations for PR #42 were not merged – QA errors". Fix the errors and merge the branch in Translatize; an admin or owner can also override the gate there, with a written reason. If the merge fails for another reason, the check fails with "Translations not merged" and the branch is kept for you to merge in Translatize.

When a pull request is closed without merging, its branch is deleted and nothing is merged. Reopening the pull request starts again with a new branch. The thinking behind a branch per change is in Translation branching explained.

Plans

The GitHub App is part of the Professional ($49 per month) and Agency ($199 per month) plans. What counts is the plan of the account that pays for the project – the project owner, or the workspace owner for a project in a workspace. On Free and Starter, the GitHub tab explains the app and links to the plans.

AI translation of pull request strings uses the plan's monthly AI translation characters: 2,000,000 on Professional and 10,000,000 on Agency. Both plans have unlimited branches, so a branch per pull request never runs into a limit.

If that plan drops below Professional, the connection pauses: the tab shows Paused – plan, and the checks on open pull requests turn neutral with "GitHub sync requires the Professional plan". After an upgrade it resumes by itself – open pull requests are synced again, and pull requests merged or closed in the meantime are merged or cleaned up.

What the app never does

  • It never runs, builds or installs anything from your repository. It reads translatize.config.json and the locale files the files pattern names, as JSON, and nothing else.
  • It commits only to the branch of an open pull request, only in On request or Automatically mode, and never to a fork.
  • It never AI-translates a pull request from a fork.
  • It never deletes a Translatize branch it did not create.
  • It never deletes keys from your base branch.

On GitHub the app asks for these repository permissions: Contents (read and write – to read the config and locale files and to commit translations), Checks (read and write – for the Translatize check), Pull requests (read) and Metadata (read).

Disconnecting

Disconnect repository at the bottom of the GitHub tab stops GitHub sync and revokes the app's access token. Branches and translations made so far stay in Translatize. The app stays installed on GitHub until you remove it there.

Troubleshooting

On the pull request

You seeWhat to do
No Translatize check at allOpen the GitHub tab: the repository must be linked to this project and Active, and the app must still have access to the repository on GitHub.
"Translatize is not set up for this repository"translatize.config.json is missing from the root of the pull request's branch. The check shows an example with your project id.
"translatize.config.json needs attention"The file is not valid JSON, is larger than 64 KB, or has a wrong field. The check names it, for example: "files" must contain the {lang} placeholder.
"translatize.config.json points to another project"projectId is empty or names another project. Set it to the id the check shows.
"Source language not found"github.sourceLanguage names a language the project does not have. Remove the key or add the language.
"Source file not readable"The source file does not exist on the branch, is not valid JSON, or is larger than 5 MB. The check names the path.
"No translation changes" and no branchThe pull request adds or changes nothing in the source-language file. Edits to other language files do not count.
"Translating … changed keys" for a long timeTranslation is still running – open the branch in Translatize to see it. If it has finished there, click Re-run on the check in GitHub.
AI translation did not runRead the notes on the check: "Auto-translate is off for this repository.", "Auto-translate waits for another translation job in this project to finish.", "Auto-translate did not start (ai_quota_exceeded)." (the AI translation characters left this month are not enough), or the note that the pull request comes from a fork.
No "Sync translations" buttonIt shows only in On request mode, for pull requests from the same repository that change source strings, once no translation is running.
"… was skipped: … Set "format": "json-flat" in translatize.config.json."A key is both a string and the parent of other keys (checkout and checkout.title), which nested JSON cannot hold. Switch to json-flat or rename one of the keys.
"No free branch name"Every name from pr-42 to pr-42-50 is taken by branches the app did not create. Rename or delete one of them in Translatize.
"Translatize could not process this pull request" or "Translations could not be committed"The last update failed; the check names the reason. Push again or click Re-run on the check.
"GitHub sync requires the Professional plan"The plan of the account that pays for the project no longer includes the GitHub App. It resumes by itself after an upgrade.
"GitHub sync is paused"The connection needs attention. The GitHub tab says what to do (see below).
"Translations not merged – QA errors"Fix the QA errors on the kept branch and merge it in Translatize, or have an admin or owner override the gate with a reason.
"Translations merged – recheck … keys"Not an error. These keys were also edited on the base branch while the pull request was open, and the pull request's values won. Check them in Translatize.

In the GitHub tab

You seeWhat to do
"GitHub sync is part of the Professional and Agency plans"The account that pays for the project – the project owner, or the workspace owner – upgrades to Professional or Agency.
"Your GitHub account can't link any of these repositories yet …"Linking needs write access, confirmed with your own GitHub account. Click Install the GitHub App, choose the same account on GitHub and come back. The same applies to repositories added to the installation later.
"Your GitHub account needs write access to that repository to link it."Get write or admin access on GitHub, or ask an admin of the project who has it to link the repository.
"That repository is already linked to another project."A repository links to one project at a time. Disconnect it in the other project first.
"This project is already linked to a repository."Disconnect the current repository first.
"Waiting for an organization owner"GitHub sent your request to an owner of the organization. Once they approve it, click Install the GitHub App again and choose the organization.
"More than 10 minutes passed before you came back from GitHub."Start again with Install the GitHub App.
"Another Translatize account started this installation."Log in with that account, or start again with Install the GitHub App.
Paused – needs attention: "The GitHub App was uninstalled from …"Click Install the GitHub App again with access to the repository. The connection resumes by itself.
Paused – needs attention: "The GitHub App no longer has access to …" or "… is suspended …"Add the repository to the installation, or unsuspend it, with Manage on GitHub. The connection resumes by itself.
Paused – needs attention: "The admin who connected the repository left the project …"Click Renew access. The app continues under your account.
Paused – needs attention: "The base branch … was deleted."Pick another base branch in the tab.