Skip to main content

django-traduire

Documentation | PyPI | GitHub

Auto-translate django-modeltranslation fields.

Fill in content in one language, and django-traduire populates all the other language columns automatically — including long articles and rich text — whose headings, lists, tables and emphasis come back exactly where they were.

Install

pip install django-traduire            # free Google backend, no API key needed
pip install django-traduire[deepl]     # DeepL
pip install django-traduire[google]    # Google Cloud Translation
pip install django-traduire[openai]    # OpenAI / any compatible server
pip install django-traduire[all]       # all backends

Quick start

# settings.py
INSTALLED_APPS = [
    ...
    "modeltranslation",
    "django_traduire",
]

LANGUAGES = [
    ("fr", "Francais"),
    ("de", "Deutsch"),
    ("en", "English"),
    ("it", "Italiano"),
]

TRADUIRE = {
    "SOURCE_LANGUAGE": "fr",
}

That is the whole configuration: the default backend is the free Google endpoint, which needs no key and no billing account.

Translate in Python

from django_traduire import translate_instance

article = Article.objects.get(pk=1)
# article.title_fr = "Bonjour le monde"

translate_instance(article)
# article.title_de = "Hallo Welt"
# article.title_en = "Hello world"
# article.title_it = "Ciao mondo"

Long texts

Every provider caps the size of one request. A 20 000-character article sent as one string comes back truncated — or not at all.

django-traduire cuts it on the most natural boundary that fits (paragraph, then sentence, then word), translates the pieces, and glues them back exactly. Nothing to configure: the budget comes from the backend, and MAX_CHARS overrides it.

TRADUIRE = {
    "MAX_CHARS": 2000,  # smaller requests, for a provider that throttles
}

Rich text

A rich-text field is not plain text. Sent as-is, a provider strips the tags or translates them as words.

<!-- before -->
<h2>Le cacao</h2>
<p>Un secteur <strong>strategique</strong>, mais <em>fragile</em>.</p>

<!-- after, translated to English -->
<h2>Cocoa</h2>
<p>A <strong>strategic</strong> sector, but <em>fragile</em>.</p>

Headings (h1–h6), sections, lists, quotes, links and inline emphasis are preserved. <script>, <style>, <code> and <pre> are never sent to a provider. A sentence stays whole across a <strong>, so the translation reads as a sentence.

Tables of any size work. The document is never cut into slices — it is planned, and only the prose inside each block is sent. A table cell is its own request, so a 400-row table, a table nested in a table, or an entire article wrapped in one <div> all go through as many small requests as they need, instead of one the provider refuses.

<!-- a 400-row table: every cell translated, not one tag moved -->
<figure class="table"><table><tbody>
  <tr><td>Cacao</td><td>450&nbsp;kg/ha</td></tr>
  <tr><td>Cashew</td><td>Production remains <em>stable</em> this year.</td></tr>
</tbody></table></figure>

The attributes a reader sees — alt, title, placeholder, aria-label — are translated too; href, src, class and id never are. Django and Jinja template syntax ({{ … }}, {% … %}) inside prose is left alone.

Nothing a provider returns is stored before it is checked: markup that does not nest, a tag the segment never carried, a damaged placeholder or an empty answer are all refused, and that segment falls back to translating its text nodes one by one — every tag preserved.

Rich text is detected automatically: from HTML_FIELDS, from the field class (CKEditor, TinyMCE, Quill…), then from the content itself. HTML_MODE forces the decision either way.

TRADUIRE = {
    "HTML_MODE": "auto",  # auto | always | never
    "HTML_FIELDS": {"blog.Article": ["body"]},  # explicit is better than sniffed
    "TRANSLATE_ATTRIBUTES": True,  # alt, title, placeholder, aria-label
}

Management command

# Translate all registered models
python manage.py traduire

# One model, one field, overwriting what is there
python manage.py traduire blog.Article --fields body --overwrite

# Bound a run
python manage.py traduire blog.Article --limit 100

# Dry run
python manage.py traduire --dry-run

Admin integration

from django.contrib import admin
from modeltranslation.admin import TranslationAdmin
from django_traduire.admin import TraduireMixin


@admin.register(Article)
class ArticleAdmin(TraduireMixin, TranslationAdmin):
    pass

This adds "Translate empty fields" and "Translate all fields (overwrite)" actions to the admin.

Auto-translate on save

TRADUIRE = {
    ...
    "AUTO_TRANSLATE": True,
}

Every time a model is saved, empty translation columns are filled. Convenient for a small site; for long articles or many languages, call translate_instance() from a background task instead — a request that waits on a translation API is a request the user watches spin.

Backends

Backend Install Key Reads markup Best for
Google (free) pip install django-traduire none via placeholders getting started, side projects, wide coverage
DeepL django-traduire[deepl] required natively European languages, highest quality
Google Cloud django-traduire[google] required natively broadest coverage, contractual traffic
OpenAI django-traduire[openai] required natively creative / contextual translations

The free backend uses the public endpoint the Google Translate web page uses. It is not a contractual API: it can throttle by IP, so it ships with retries and rate_limit. For production traffic under an SLA, use one of the other three.

Writing a backend

from django_traduire.backends.base import BaseBackend


class MyBackend(BaseBackend):
    max_chars = 5000  # characters one request accepts
    max_texts = 20  # texts one request accepts
    supports_html = False  # True if the provider keeps markup

    def translate_raw(self, texts, source, target, is_html=False):
        return [my_api(text, source, target) for text in texts]

Chunking, request grouping and markup handling are inherited — one request in, one list out.

License

MIT - Paul Guindo / Altius Academy SNC.

Release files for django-traduire 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-traduire 0.3.0
File Size Uploaded
django_traduire-0.3.0.tar.gz 62.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for django-traduire 0.3.0
File Interpreter ABI Platform
django_traduire-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 104.3 kB

Release files / django_traduire-0.3.0.tar.gz

Download URL django_traduire-0.3.0.tar.gz
Size 62.1 kB
Tags Source
SHA-256 checksum
How to use checksums
bf20d75927912d8c1b85e8a8910e02262c08bf5ab8a3c5bbcb46374a84ac5b35
BLAKE2b-256 checksum
How to use checksums
768cf90a9b43640962ed4b5bfeb11da5ac3f4890d822b1da70ce92999f190f62
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 Sep 8, 2026.

Transparency log

Release files / django_traduire-0.3.0-py3-none-any.whl

Download URL django_traduire-0.3.0-py3-none-any.whl
Size 42.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
99518393e8387e6520072af08f762b18354cfeeddad0c8d8c405254fe9dacf93
BLAKE2b-256 checksum
How to use checksums
eaa9d3f4b4dd5a2dca68978d283641968b07752617621a5c014cdc1b83f526c6
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 Sep 8, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page