Django Parler

2.3 · active · verified Thu Apr 16

Django Parler (current version 2.3) provides simple Django model translations without nasty hacks, featuring nice admin integration. It enables storing multiple language versions of model fields in a separate table. The library is actively maintained with updates for Django compatibility and new features regularly released.

Common errors

Warnings

Install

Imports

Quickstart

To quickly get started with django-parler, first install it and add `'parler'` to your `INSTALLED_APPS`. Configure `LANGUAGES` and `PARLER_LANGUAGES` in `settings.py`. Define your models by inheriting from `TranslatableModel` and wrapping translatable fields in `TranslatedFields`. Register your model with `TranslatableAdmin` in `admin.py` for full administrative support. Access translations using `set_current_language()` or `django.utils.translation.override()` and query with `.translated()` or `.active_translations()` methods.

# settings.py
INSTALLED_APPS = [
    # ...
    'parler',
    # Your app
    'myapp',
]

LANGUAGE_CODE = 'en'
LANGUAGES = (
    ('en', 'English'),
    ('fr', 'French'),
    ('es', 'Spanish'),
)

PARLER_LANGUAGES = {
    None: (
        {'code': 'en'},
        {'code': 'fr'},
        {'code': 'es'},
    ),
    'default': {
        'fallbacks': ['en'],
        'hide_untranslated': False, 
    }
}

# myapp/models.py
from django.db import models
from django.utils.translation import gettext_lazy as _
from parler.models import TranslatableModel, TranslatedFields

class Category(TranslatableModel):
    translations = TranslatedFields(
        name=models.CharField(_("Name"), max_length=200, unique=True)
    )
    # Add a non-translatable field for demonstration
    is_active = models.BooleanField(default=True)

    def __str__(self):
        return self.safe_translation_getter('name', any_language=True)

# myapp/admin.py
from django.contrib import admin
from parler.admin import TranslatableAdmin
from .models import Category

@admin.register(Category)
class CategoryAdmin(TranslatableAdmin):
    list_display = ('name', 'is_active',)
    # Prepopulated fields (if you had a slug for example)
    # prepopulated_fields = {'slug': ('name',)}

# Example usage in a shell or view
from django.utils import translation

# Create a category
cat = Category(is_active=True)
cat.set_current_language('en')
cat.name = "Electronics"
cat.save()

cat.set_current_language('fr')
cat.name = "Électronique"
cat.save()

# Accessing translations
with translation.override('en'):
    print(f"English Name: {cat.name}") # Output: English Name: Electronics

with translation.override('fr'):
    print(f"French Name: {cat.name}") # Output: French Name: Électronique

# Querying translated fields
# All categories with name 'Electronics' in any language
electronics_en = Category.objects.translated(name='Electronics').first()
print(f"Found in EN: {electronics_en.name}")

# Categories with active translations for current language or fallbacks
active_cats = Category.objects.active_translations().filter(is_active=True)
for c in active_cats:
    print(f"Active Category ({c.get_current_language()}): {c.name}")

view raw JSON →