translatebot-django
AI translation for Django, covering both your .po files and the content in your database. Run one command after each change and only the new text gets translated.
Documentation: https://translatebot.dev/docs/
The problem
Static strings are the easy part of translating a Django app. makemessages collects them into .po files, and plenty of tools can fill those in.
Database content is harder. Editors write product names, blog posts and category pages after you deploy, so that text never passes through gettext. With django-modeltranslation every language gets its own column, and someone has to work out which rows are missing which language. A translated slug still has to be a valid slug. Some of your existing translations may be machine output themselves, which makes them a poor source for the next language.
The usual options don't fit:
- Copying text into Google Translate works for 20 strings. At 200 it falls apart, and you fix every broken placeholder by hand.
- ChatGPT or Claude Code will translate a
.pofile well enough once. Next sprint you're prompting from scratch again, re-translating the whole file and hoping the terminology still matches. - Localization platforms charge per word. You also get portals and review workflows that a solo developer or small team doesn't need.
What TranslateBot does
TranslateBot adds a translate management command to your project. It translates whatever is missing and leaves existing translations alone.
Database content
With django-modeltranslation installed, python manage.py translate --models fills the empty language columns of every registered model. Pass model names to limit it to those models.
- It translates from your default language whenever that column has text, since the other languages may already be machine translations. If it's empty, the first language with content is used.
- Rows created before you installed modeltranslation only have text in the original column. TranslateBot reads it from there.
- Slug fields are slugified again and cut to their
max_lengthat a word boundary. File and image fields are skipped. - Columns that already have a translation stay as they are unless you pass
--overwrite.
New content keeps arriving after you deploy, so the same function is available from Python. Call it from a Celery task or a signal handler when editors publish (see the Python API docs).
PO files
- Only new and changed strings are translated. Add 10 strings in a sprint and you pay for 10, not the whole file.
- A
TRANSLATING.mdfile in your repo holds your glossary, tone and brand rules. Every run uses it, so a term you translated last month comes out the same today. - Placeholders such as
%(name)s,{0}and%sand HTML tags are kept intact. LLM providers are told to preserve them, and DeepL gets them as protected tokens. - Every translation is checked before it's written, using the rules
compilemessagesapplies topython-formatandpython-brace-formatstrings. A translation that drops or changes a placeholder is retried once. If it fails again, an untranslated entry gets it as a#, fuzzydraft.compilemessagesskips fuzzy entries, so a bad translation never breaks your build, and the run ends with a list of drafts to review. - With LLM providers, each plural form of the target language gets its own translation (Polish, Russian, Arabic, …).
pgettextcontexts keep "May" the month apart from "May" the verb.
Everything else
- It works with OpenAI, Anthropic, Google Gemini, Azure and any provider LiteLLM supports, or with DeepL.
- One run covers every language in
LANGUAGES. Adding a locale takes one line in your settings. - Strings are batched into as few API requests as possible.
python manage.py check_translationsfails your CI build when strings are untranslated or fuzzy (CI docs).- You configure it in Django settings, and
--llm-modeloverrides the model for a single run. The API key can also come from theTRANSLATEBOT_API_KEYenvironment variable. - The test suite covers 100% of the code.
Installation
To translate PO files only, install TranslateBot as a dev dependency:
uv add --dev translatebot-django
To translate model fields from your running app, install it as a regular dependency instead (see the Python API docs):
uv add translatebot-django
Optional extras: translatebot-django[deepl] for the DeepL provider, and translatebot-django[modeltranslation] for model field translation.
Supported versions
Each Django series is tested against the Python versions Django itself supports:
| Django | Python |
|---|---|
| 4.2 | 3.10, 3.11, 3.12 |
| 5.0 | 3.10, 3.11, 3.12 |
| 5.1 | 3.10, 3.11, 3.12, 3.13 |
| 5.2 | 3.10, 3.11, 3.12, 3.13, 3.14 |
| 6.0 | 3.12, 3.13, 3.14 |
| 6.1 | 3.12, 3.13, 3.14 |
Quick start
# settings.py
import os
INSTALLED_APPS = [
# ...
"translatebot_django",
]
LANGUAGES = [("en", "English"), ("nl", "Dutch"), ("de", "German")]
TRANSLATEBOT_API_KEY = os.getenv("TRANSLATEBOT_API_KEY")
# The default; any LiteLLM model works, e.g. "claude-sonnet-5-5"
TRANSLATEBOT_MODEL = "gpt-6-luna"
On Python 3.10, set TRANSLATEBOT_MODEL to a model other than the default, such as gpt-4o-mini. The litellm versions that run there don't support gpt-6-luna properly.
The API key must belong to the provider of TRANSLATEBOT_MODEL. To use DeepL instead, set TRANSLATEBOT_PROVIDER = "deepl", put your DeepL key in TRANSLATEBOT_API_KEY and leave out TRANSLATEBOT_MODEL.
# Extract strings into .po files
python manage.py makemessages -l nl -l de
# Preview what would be translated (no API calls, but the key must be set)
python manage.py translate --dry-run
# Translate to all configured languages
python manage.py translate
# Compile for use
python manage.py compilemessages
Model fields
Model translation needs django-modeltranslation. Install the extra:
uv add "translatebot-django[modeltranslation]"
Add modeltranslation to INSTALLED_APPS, before django.contrib.admin if you use the admin:
INSTALLED_APPS = [
"modeltranslation",
# ...
"translatebot_django",
]
Once your fields are registered for translation and migrated, fill their empty language columns:
python manage.py translate --models
When to use TranslateBot
For a one-off translation of 20 strings, ChatGPT works fine. TranslateBot is for ongoing projects where translations have to keep up with your code and your content.
It's a good fit when:
- Your strings change every sprint and you're tired of re-translating whole files.
- Editors add content to your database in one language and your users read it in others.
- You support three or more languages and want them all updated in one run.
- You want the same terminology every time, without pasting a glossary into a prompt.
Documentation
For full documentation, visit translatebot.dev/docs/
- Installation
- Configuration
- PO File Translation
- Translation Context (
TRANSLATING.md) - Model Translation
- Command Reference
- Python API
- CI Integration
- Supported AI Models
- DeepL
- FAQ
Contributing
Contributions are welcome. CONTRIBUTING.md covers the fork workflow, how to report a bug and the lint steps to run before you open a pull request. To get a local setup running:
git clone https://github.com/gettranslatebot/translatebot-django.git
cd translatebot-django
uv sync --extra dev
uv run pytest
License
This project is licensed under the Mozilla Public License 2.0. See the LICENSE file for details.
Credits
Made with ❤️ for the Django community
Metadata
Release files for translatebot-django 1.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| translatebot_django-1.6.0.tar.gz | 102.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| translatebot_django-1.6.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 154.6 kB
Release files / translatebot_django-1.6.0.tar.gz
| Download URL | translatebot_django-1.6.0.tar.gz |
|---|---|
| Size | 102.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
86748b46cb4080313b8aa663b3cd453bf779cfa9c080d3cb47f88b30f544ea2b
|
|
BLAKE2b-256 checksum How to use checksums |
3b5df1e8cfadbeebf506487af3eddb7911f63590c653d43c08b12af87fd09f45
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.
Transparency logRelease files / translatebot_django-1.6.0-py3-none-any.whl
| Download URL | translatebot_django-1.6.0-py3-none-any.whl |
|---|---|
| Size | 51.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
eec591398c7dfd3ecaebf2611233c42534794abca68b893ae6f238deb47969c2
|
|
BLAKE2b-256 checksum How to use checksums |
51c6d1b36ad25751044a5f8a02eecb0c870ff2f1cfd6247981038dcf5048eb9a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.
Transparency log