If you're building a Django app that needs to support more than one language, Django's built-in internationalisation (i18n) is a decent start. But if you want to go further — like translating model fields, managing multilingual content, and switching language context dynamically — Django-parler is the tool you want.
This guide is aimed at beginners and covers everything from installation to usage, with best practices and practical examples.
  
  
  🌍 Why Use Django-parler?
Django itself provides tools for translating strings in templates and Python code. Still, it doesn't offer a clean way to make database models translatable — to have fields that store multiple language versions.
Django-parler solves this with a well-designed API and seamless integration into Django admin and queries.
🔧 Installation and Basic Configuration
First, install the package:
pip install django-parler
Then, add it to your INSTALLED_APPS in settings.py:
INSTALLED_APPS = [
    ...
    'parler',
]
Set your supported languages:
LANGUAGE_CODE = 'en'
LANGUAGES = [
    ('en', 'English'),
    ('pl', 'Polski'),
]
PARLER_LANGUAGES = {
    None: (
        {'code': 'en'},
        {'code': 'pl'},
    ),
    'default': {
        'fallbacks': ['en'],
        'hide_untranslated': False,
    },
}
🧱 Making a Model Translatable
Let's say you want to create a Category model in which each language's name and slug should differ.
Here's how to do it with parler:
from django.db import models
from parler.models import TranslatableModel, TranslatedFields
class Category(TranslatableModel):
    translations = TranslatedFields(
        name=models.CharField(max_length=200),
        slug=models.SlugField(max_length=200, unique=True),
    )
    def __str__(self):
        return self.safe_translation_getter('name', any_language=True)
Key points:
- Use TranslatableModelas your base class.
- Define translatable fields inside TranslatedFields().
- Use safe_translation_getter()to safely get the translated value.
🛠 Using Translations in the Admin
Django-parler provides an admin mixin to show translation tabs automatically:
from django.contrib import admin
from parler.admin import TranslatableAdmin
from .models import Category
@admin.register(Category)
class CategoryAdmin(TranslatableAdmin):
    list_display = ('__str__',)
You'll now see tabs for each language when editing an object in the admin.
🔍 Querying Translatable Models
To avoid duplicate entries or incorrect results, always use .translated() when querying:
from .models import Category
# Only get categories that are translated into the current language
Category.objects.translated('pl').filter(translations__is_published=True)
Or to get only those that exist in the current request's language:
from django.utils.translation import get_language
Category.objects.translated(get_language()).all()
⚠️ Avoid using .filter(translations__...) without .translated(...) or .distinct() — this can lead to duplicate rows in querysets.
🎯 Rendering Translations in Templates
Use safe_translation_getter() to access values in templates:
{{ category.safe_translation_getter:"name" }}
Or use the standard property (like category.name) if you're sure the model is correctly translated in the context.
🧪 Testing Translations
Use Django's override context to test translations:
from django.utils.translation import override
with override('pl'):
    category = Category.objects.first()
    print(category.name)  # Should be in Polish
🧹 Best Practices
- Use safe_translation_getterto preventNoneTypeerrors.
- Always use .translated()when filtering by translatable fields.
- Never mix translated and untranslated queries unless you use .distinct().
- Use admin mixins to have a smooth experience when editing translations.
- Don't duplicate logic — define fallbacks and supported languages in one place (settings.py).
✅ Summary
Django-parler is a powerful tool for multilingual content in Django. With minimal configuration, you can:
- Translate model fields.
- Filter and fetch content in the current language.
- Provide a seamless admin experience.
Stay tuned, and happy translating! 🌍
 
 
              
 
    
Top comments (0)