CI Integration¶
TranslateBot includes a check_translations management command that verifies all .po files are fully translated with no fuzzy entries. It exits with code 1 on failure, making it ideal for CI pipelines.
The check_translations Command¶
This scans all .po files across your project (LOCALE_PATHS, app locale directories, and the locale/ directory in BASE_DIR when LOCALE_PATHS is empty) and reports:
- Untranslated entries - strings with an empty
msgstr - Fuzzy entries - strings flagged for review by
makemessages, or translation drafts that failed validation
If any issues are found, the command exits with code 1 and prints the details to stderr.
The --makemessages Flag¶
In CI, you typically want to ensure .po files are in sync with your source code before checking. The --makemessages flag runs makemessages -a --no-obsolete automatically before checking:
This single command replaces the two-step workflow of running makemessages then check_translations separately.
Note
The --makemessages flag requires gettext to be installed on your system. See the CI examples below for how to install it.
GitHub Actions¶
jobs:
translations:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v4
with:
enable-cache: true
- run: uv python install
- run: uv sync --frozen
- name: Install gettext
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends gettext
- name: Check translations
run: uv run python manage.py check_translations --makemessages
Or if you prefer to run makemessages as a separate step:
- name: Extract messages
run: uv run python manage.py makemessages -a --no-obsolete
- name: Check translations
run: uv run python manage.py check_translations
GitLab CI¶
check-translations:
image: python:3.13
before_script:
- apt-get update && apt-get install -y --no-install-recommends gettext
- pip install uv && uv sync --frozen
script:
- uv run python manage.py check_translations --makemessages
What It Catches¶
When a developer adds a new translatable string but forgets to translate it, the CI check will fail:
/app/locale/de/LC_MESSAGES/django.po: 2 untranslated, 0 fuzzy
/app/locale/nl/LC_MESSAGES/django.po: 0 untranslated, 1 fuzzy
CommandError: Translation check failed
Typical Workflow¶
- Developer adds new strings with
{% trans %}orgettext() - CI runs
check_translations --makemessages - CI fails because the new strings are untranslated
- Developer runs
python manage.py translateto translate them - CI passes
This ensures translations never fall out of sync with your source code.
Translating in CI¶
You can also let CI do step 4: run translate and commit the result. Store your provider's API key as a repository secret; TRANSLATEBOT_API_KEY is read from the environment when it isn't set in Django settings.
on:
workflow_dispatch:
jobs:
translate:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v4
- run: uv sync --frozen
- name: Install gettext
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends gettext
- run: uv run python manage.py makemessages -a --no-obsolete
- name: Translate
env:
TRANSLATEBOT_API_KEY: ${{ secrets.TRANSLATEBOT_API_KEY }}
run: uv run python manage.py translate
- name: Commit translations
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add -A -- '*.po'
git diff --cached --quiet || git commit -m "chore: update translations"
git push
Tip
Run translate --dry-run in pull requests to see what would be translated without spending API credits. A dry run still requires TRANSLATEBOT_API_KEY to be set, but any value works since no API call is made.