Login Account

GitHub Actions

Use the official doloc GitHub Action to keep translation files current in CI.

This action can automatically translate files, check for stale translations, and can easily be integrated to commit or propose changes. It supports all formats that doloc supports, including React Intl / FormatJS JSON, Android XML resources, ARB (Flutter), and XLIFF 1.2/2.0.

Alternatively, you can run doloc locally, possibly integrated into your text extraction or build scripts. For a detailed discussion see When to run doloc.

Setup

Create an API token on your doloc account page, then add it to your GitHub repository secrets as DOLOC_API_TOKEN.

Pick the workflow that matches how your team treats generated translation files:

WorkflowBest fit
Commit to feature branchesSame-repository branches where translation diffs should appear in the original PR.
Check translations in PRsLocal-first workflows where CI should catch stale translation files.
Commit after mergeRepositories that update generated translations only on the default branch.
Open a translation PRProtected branches or teams that want generated translations reviewed separately.

Commit to feature branches

For small teams and same-repository feature branches, this is often the cleanest workflow: a developer changes source text, CI commits updated translation files back to the same branch, and the existing PR shows the complete diff.

name: Update translationson:  push:    branches-ignore:      - main    paths:      - src/lang/en.json      - .github/workflows/update-translations.ymlpermissions:  contents: writejobs:  update-translations:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v6      - id: doloc        uses: doloc-io/doloc-action@v1        with:          token: ${{ secrets.DOLOC_API_TOKEN }}          source: src/lang/en.json          targets: |            src/lang/de.json            src/lang/fr.json      - name: Commit translation updates        if: steps.doloc.outputs.changed == 'true'        uses: stefanzweifel/git-auto-commit-action@v7        with:          commit_message: Update translations          file_pattern: src/lang/de.json src/lang/fr.json

The paths filter intentionally watches the source file, not the generated target files. This runs the translation only when source text changed. Note, that in any case there there will only a commit when translations actually changed, so no redundant commits are created.

Use this only for trusted same-repository branches. For fork PRs, secrets are not available by default and you usually should not send untrusted contributor text to external APIs automatically.

Check translations in PRs

Use check mode when developers update translations locally and CI should only verify freshness:

name: Check translationson:  pull_request:permissions:  contents: readjobs:  check-translations:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v6      - uses: doloc-io/doloc-action@v1        with:          token: ${{ secrets.DOLOC_API_TOKEN }}          mode: check          source: src/lang/en.json          targets: |            src/lang/de.json            src/lang/fr.json

Check mode translates in memory, compares the result with committed files, and fails when updates are needed. It does not modify the working tree.

Commit after merge

If you do not want CI to mutate feature branches, update translations on the default branch after source text changes are merged:

on:  push:    branches:      - main    paths:      - src/lang/en.json      - .github/workflows/update-translations.yml

Use the same doloc and git-auto-commit-action steps from Commit to feature branches. This keeps feature PRs simpler, but translation updates appear in a follow-up commit on main.

Open a translation PR

If direct bot commits are blocked by branch protection or review policy, create a reusable translation PR instead:

name: Update translationson:  push:    branches:      - main    paths:      - src/lang/en.json      - .github/workflows/update-translations.ymlpermissions:  contents: write  pull-requests: writejobs:  update-translations:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v6      - id: doloc        uses: doloc-io/doloc-action@v1        with:          token: ${{ secrets.DOLOC_API_TOKEN }}          source: src/lang/en.json          targets: |            src/lang/de.json            src/lang/fr.json      - name: Create pull request        if: steps.doloc.outputs.changed == 'true'        uses: peter-evans/create-pull-request@v8        with:          commit-message: "Update translations"          title: "Update translations"          body: "Updated localization files using doloc."          branch: doloc/update-translations          delete-branch: true          add-paths: |            src/lang/de.json            src/lang/fr.json

The fixed branch value is intentional: peter-evans/create-pull-request updates the same open translation PR on later runs. If you explicitly want a separate PR per workflow run, add branch-suffix: timestamp, but use that sparingly.

File mappings

For most cases, the source and target language can be inferred from file contents or file name. If this is not possible, you can explicitly specify the source language with source-lang and target languages with :lang suffixes in the targets list. See Android XML example below.

For React Intl / FormatJS JSON or generic JSON, pass one source file plus one or more targets:

source: src/lang/en.jsontargets: |  src/lang/de.json  src/lang/fr.json

For Android XML resources, include source and target languages when the files do not carry enough language information:

source: app/src/main/res/values/strings.xmlsource-lang: entargets: |  app/src/main/res/values-de/strings.xml:de  app/src/main/res/values-fr/strings.xml:fr

For XLIFF, the target file itself contains the translatable units, so source should not be used:

targets: |  src/locale/messages.de.xlf  src/locale/messages.fr.xlf

Make sure the target language is configured inside each XLIFF file.

Options

The options input maps to doloc API query parameters, one option per line:

options: |  untranslated=no-state_target-equals-source,needs-translation  newState=translated

See the Options reference for the general syntax and links to each format’s supported options.

Permissions and secrets

Use the smallest permission set that matches your workflow:

WorkflowPermissions
Translate only or check modecontents: read
Commit changed filescontents: write
Create pull requestscontents: write, pull-requests: write

The doloc action itself only needs access to the checked-out files. Write permissions are needed only by later composed steps that commit files or create pull requests.

Versioning

Use the moving major tag for normal workflows:

uses: doloc-io/doloc-action@v1

This action follows semantic versioning, so v1 will always point to the latest v1 release and does not introduce breaking changes. Pinning to a specific patch version is also possible, but usually not needed.

More details

See the doloc-action README for all inputs, outputs, target mapping syntax, and troubleshooting notes.