Backends
django-live-translations uses a backend system to abstract translation storage. Two backends are included out of the box, and you can implement your own by subclassing the abstract base class.
PO file backend (default)
LIVE_TRANSLATIONS = {
"BACKEND": "live_translations.backends.po.POFileBackend",
}
The POFileBackend reads and writes .po/.mo files directly on disk. This is the default backend and requires no additional setup beyond having a locale directory with .po files.
File structure
locale/
en/
LC_MESSAGES/
django.po # read/written by POFileBackend
django.mo # recompiled on every save
cs/
LC_MESSAGES/
django.po
django.mo
Best suited for local development
The PO backend writes directly to .po/.mo files on disk. If used on a deployed server, any translation edits will be lost on the next deployment when the codebase (including .po files) is replaced. Use the Database backend for production environments.
Trade-offs
Pros:
- No database or cache infrastructure required
- Zero setup - works out of the box
- Changes are written to
.pofiles, which you can commit to version control
Cons:
- Edits are lost on redeployment - the next deploy overwrites
.pofiles with what's in the repo - Writes to the filesystem (won't work on read-only deployments like containers)
- No built-in cross-process synchronization
- Requires
.pofiles to exist for each language
Database backend
LIVE_TRANSLATIONS = {
"BACKEND": "live_translations.backends.db.DatabaseBackend",
"CACHE": "default",
}
The DatabaseBackend stores translation overrides in the database and falls back to .po files for defaults. It uses Django's cache framework for cross-process synchronization.
Setup
-
Set the backend in your settings:
LIVE_TRANSLATIONS = { "BACKEND": "live_translations.backends.db.DatabaseBackend", "CACHE": "translations", # must match a CACHES entry } -
Ensure you have a proper cache backend configured:
CACHES = { "translations": { "BACKEND": "django.core.cache.backends.redis.RedisCache", "LOCATION": "redis://127.0.0.1:6379/1", } } -
Run migrations:
python manage.py migrate
Trade-offs
Pros:
- Works on read-only filesystems (containers, serverless)
- Built-in cross-process synchronization via cache
- Overrides are independent of
.pofiles - Full edit history with the
TranslationHistorymodel
Cons:
- Requires database and cache infrastructure
- Overrides are not version-controlled (unless you export them)
Comparison
| Feature | PO Backend | Database Backend |
|---|---|---|
| Storage | .po/.mo files |
Database table |
| Cross-process sync | Via filesystem | Via cache (Redis, Memcached) |
| Works on read-only filesystem | No | Yes |
| Version control | Yes (files in repo) | No |
| Requires database (migrations) | No | Yes |
| Edit history | Yes (requires DB) | Yes |
.po file fallback |
N/A | Yes |
| Inactive translations | Comment-based (ltpending:) |
is_active field |
Custom backends
To implement a custom backend, subclass TranslationBackend and implement the two required abstract methods:
from live_translations.backends.base import TranslationBackend, TranslationEntry
from live_translations.types import LanguageCode, MsgKey
class MyCustomBackend(TranslationBackend):
def get_translations(
self,
key: MsgKey,
languages: list[LanguageCode],
) -> dict[LanguageCode, TranslationEntry]:
"""Fetch translations for a msgid across multiple languages."""
...
def save_translations(
self,
key: MsgKey,
translations: dict[LanguageCode, str],
active_flags: dict[LanguageCode, bool] | None = None,
) -> None:
"""Save translations for a msgid."""
...
Optional methods to override
| Method | Purpose |
|---|---|
ensure_current() |
Check if local overrides are stale and refresh if needed |
inject_overrides() |
Inject overrides into Django's translation catalogs |
bump_catalog_version() |
Signal other processes that overrides changed |
bulk_activate(language, msgids) |
Activate multiple pending translations |
get_inactive_overrides(language) |
Return inactive translations for preview mode |
get_defaults(key, languages) |
Get baseline .po file values for display |
get_hint(key) |
Get translator comments from .po files |
check() |
Return Django system check messages |
Register your backend in settings:
LIVE_TRANSLATIONS = {
"BACKEND": "myapp.backends.MyCustomBackend",
}