Skip to content

Backends

django-traduire ships with four backends. You can also write your own in one method.

Backend Key needed Extra dependency Reads markup
Google (free) no none via placeholders
DeepL yes deepl natively
Google Cloud yes google-cloud-translate natively
OpenAI yes openai natively

Google (free)

The default. It talks to the public endpoint the Google Translate web page itself uses: no API key, no billing account, no extra package.

TRADUIRE = {
    "BACKEND": "django_traduire.backends.google_free.GoogleFreeBackend",
    "BACKEND_OPTIONS": {
        "timeout": 10.0,  # seconds per request
        "retries": 3,  # attempts per request
        "rate_limit": 0.0,  # seconds between two requests
        "max_chars": 3000,  # characters per request
    },
}

What you should know before shipping it:

  • It is not a contractual API. Google may throttle it, change its answer format, or refuse it. The backend retries 429 and 5xx with a growing delay, then raises BackendError.
  • Volume gets rate-limited by IP. Translating a whole table? Set rate_limit to 0.5 or more, and run it in a background task rather than in a request.
  • It does not read markup. Rich text still works — the tags are set aside and restored — but a provider that understands HTML will phrase long formatted sentences slightly better.

For traffic you have to guarantee, use one of the three below.

DeepL

Best quality for European languages. Ideal for Switzerland (fr/de/it/en).

TRADUIRE = {
    "BACKEND": "django_traduire.backends.deepl.DeepLBackend",
    "BACKEND_OPTIONS": {
        "auth_key": "your-deepl-api-key",
    },
}

Get your API key at deepl.com/pro-api.

Rich text is sent with tag_handling="html", so DeepL keeps a sentence whole across an inline tag and never splits one on <p> or <li>.

DeepL supports: BG, CS, DA, DE, EL, EN, ES, ET, FI, FR, HU, ID, IT, JA, KO, LT, LV, NB, NL, PL, PT, RO, RU, SK, SL, SV, TR, UK, ZH.

Google Cloud Translation

Broadest language coverage, including African languages, under a contract.

TRADUIRE = {
    "BACKEND": "django_traduire.backends.google.GoogleBackend",
    "BACKEND_OPTIONS": {
        "project_id": "your-gcp-project-id",
    },
}

Requires a Google Cloud project with the Translation API enabled and authentication configured (e.g. GOOGLE_APPLICATION_CREDENTIALS). Rich text is sent with mime_type="text/html".

OpenAI

For creative or contextual translations using an LLM.

TRADUIRE = {
    "BACKEND": "django_traduire.backends.openai.OpenAIBackend",
    "BACKEND_OPTIONS": {
        "api_key": "your-openai-api-key",
        "model": "gpt-4o-mini",  # default
        "temperature": 0.1,
        "json_mode": True,  # turn off for servers without response_format
        "max_chars": 5000,
    },
}

Works with any OpenAI-compatible API — pass base_url in BACKEND_OPTIONS for Azure, vLLM, Ollama or a local model. If the model answers with something other than the expected JSON array, the request is retried one text at a time before giving up.

Custom backend

Implement translate_raw() — one request to your provider — and declare what that request accepts. Chunking, request grouping, whitespace handling and markup protection are inherited.

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 intact

    def __init__(self, api_key, **kwargs):
        if not api_key:
            raise ValueError("MyBackend requires an api_key")
        self.client = MyClient(api_key, **kwargs)

    def translate_raw(self, texts, source, target, is_html=False):
        # texts already fit max_chars and max_texts
        # return exactly len(texts) strings, in order
        return [self.client.translate(text, source, target) for text in texts]
TRADUIRE = {
    "BACKEND": "myapp.backends.MyBackend",
    "BACKEND_OPTIONS": {"api_key": "..."},
}

Upgrading from 0.1

In 0.1 a backend implemented translate_batch(texts, source, target). That method is now the public entry point, implemented by BaseBackend. Rename your method to translate_raw(self, texts, source, target, is_html=False) and you inherit chunking and markup handling.