Home/Integrations/GitHub
GitHub integration

Your translations, kept in step by GitHub Actions

No plugin to install and no bot to authorise. GitHub already runs commands on merge; two of them keep your translations in step.

GitHub en.json, strings.xml, .po locoloop translate · review glossary · history EU hosted GitHub every locale, native format push pull Source strings leave your repository on every merge. Translated files come back the same way.

The whole integration

Everything below authenticates with one API key, scoped to read or write and optionally pinned to a single platform, so a build job can never reach further than the app it builds.

.github/workflows/locoloop.yml
name: locoloop
on:
  push:
    branches: [main]

env:
  LOCOLOOP: https://api.rondigi.com/api/v1

jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      # 1. Source strings out of the repo. `prune: true` deprecates keys you
      #    deleted; nothing is ever hard-deleted, so a bad merge is revertible.
      - name: Push English
        run: |
          jq '{platform: "web", prune: true,
               keys: [to_entries[] | {name: .key, value: .value}]}' \
            locales/en.json > push.json
          curl -fsS -X POST "$LOCOLOOP/push" \
            -H "X-Api-Key: ${{ secrets.LOCOLOOP_API_KEY }}" \
            -H "Content-Type: application/json" \
            --data @push.json

      # 2. Finished translations back in, in the platform's own format.
      - name: Pull every locale
        run: |
          for locale in de fr es pl; do
            curl -fsS "$LOCOLOOP/pull?platform=web&locale=$locale" \
              -H "X-Api-Key: ${{ secrets.LOCOLOOP_API_KEY }}" \
              -o "locales/$locale.json"
          done

      - uses: peter-evans/create-pull-request@v6
        with:
          branch: locoloop/translations
          title: "Translations from locoloop"
          commit-message: "chore(i18n): pull translations"

Gate the release on it

GET /status reports how far every locale has got. Fail the job when the language you promised is not finished, and an untranslated string cannot reach production by accident.

.github/workflows/locoloop.yml
gate:
    runs-on: ubuntu-latest
    steps:
      - name: German must be complete before we ship
        run: |
          pct=$(curl -fsS "$LOCOLOOP/status?platform=web" \
            -H "X-Api-Key: ${{ secrets.LOCOLOOP_API_KEY }}" | jq '.locales.de.pct')
          echo "German is at ${pct}%"
          [ "$pct" -eq 100 ]
German100%French96%Polish71%

What GitHub gets you

Idempotent pushes

A push compares values. Re-running the job on an unchanged branch writes nothing and enqueues nothing.

Never clobbers a human

A changed English string flags its translations needs review. It does not overwrite what a translator wrote.

A real build gate

status returns per-locale counts and the plural forms a language is still missing, not just a percentage.

Put it in your GitHub pipeline today

Create a workspace, mint a read/write key, paste the job in. Free while you are evaluating.

Start freeLog inBook a demo