Internationalization Django
Working example:
Useful Links:
Django is one of the less knows framework but it was created in mind with the press and have many build-in tools like internationalization which with a little adjustment can help create a multi-language site without writing a lot of code.
This article we will divide on two project flat Django projects without database using only build in Django classes and the second one with database and two packages django-parler and django-rosetta to translate and create the database schema.
Let’s start from creating the first Django project using pipenv which help keep all in one place without impacting another project:
https://docs.python-guide.org/dev/virtualenvs/#installing-pipenv
pip install pipenv
When we have installed tools for work let’s create a folder where we will work:
mkdir django_translate
cd django_translate
pipenv shell
pipenv install django
django-admin startproject translate_project .
python manage.py startapp translate_app
And we have a starter to create our app with one application.
Let’s prepare our app for internationalization:
translate_project/settings.py...INSTALLED_APPS = [
...
'translate_app.apps.TranslateAppConfig,
...
]LANGUAGES = (
('en','English'),
('pl', 'Polish'),
)MIDDLEWARE = [
...
#The order of middleware is very important
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
...
]LOCALE_PATHS = (
os.path.join(BASE_DIR, 'locale/'),
)
...
Now we can start creating a view for our project:
translate_app/views.pyfrom django.views.generic import TemplateViewclass HomeView(TemplateView):
template_name = 'translate_app/home.html'
In translate_app dir we will create template file:
templates/
translate_app/
home.html
Example home.html with bootstrap 4 structure:
In root directory we create locale dir:
locale/
en/
pl/
This is preparation for our translation.
Next step is to create a route for our project:
translation_project/urls.py...
from django.conf.urls.i18n import i18n_patterns
from translation_app import viewsurlpatterns = i18n_patterns(
...
path('', views.HomeView.as_view(), name='home'),
)
This allowed us to change the language in our template.
Now we can use commands for creating translation which we did in a template with template tags:
django-admin makemessages --all
django-admin compilemessages
With command makemessages we create a file with an end .po where we can write a translation. When we did with command compilemessages we generate output for Django.
Example django.po:
...#: .\flat_app\templates\flat_app\home.html:58
msgid "Album"
msgstr "Album"#: .\flat_app\templates\flat_app\home.html:88
msgid "Album example"
msgstr "Przykładowy album"#: .\flat_app\templates\flat_app\home.html:89
msgid ""
"Something short and leading about the collection below—its contents, the "
"creator, etc. Make it short and sweet, but not too short so folks don’t "
"simply skip over it entirely."msgstr ""
"Trochę krótkiego tekstu na wstępniaku w jaki sposób zebrać treść znajdującą się poniżej, "
"twórcę, etc. Stwórz go krótki i przyjazny dla oka, ale nie za krótki aby czytelnik nie "
"przeoczył go w trakcie przeglądania strony. "...
At this point, we are done with our basic project next we will use Django parler and django-rosetta to create more advanced projects.
The next step will be creating an application with the database and the translated model.
To create our application more advance and translate content from the database we need to use django-parle which allowed us to create an alter table in a database and display language version in the admin panel. Let’ s start from creating a stander Django project:
mkdir dj_translate
cd dj_translate
pipenv shell
pipenv install django
pipenv install django-parler
django-admin startproject translate_project .
python manage.py startapp translate_app
Next, we prepare our app to internationalization:
translate_project/settings.py...INSTALLED_APPS = [
...
'translate_app.apps.TranslateAppConfig,
'parler',
...
]LANGUAGES = (
('en','English'),
('pl', 'Polish'),
)PARLER_LANGUAGES = {
None: (
{'code': 'en'},
{'code': 'pl'},
),
'default': {
'fallback': 'en',
'hide_untranslated': False,
}
}MIDDLEWARE = [
...
#The order of middleware is very important
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
...
]LOCALE_PATHS = (
os.path.join(BASE_DIR, 'locale/'),
)
...
With these settings, we can continue to create the model with translated fields. One good advice for a beginner is to create TranslatebleModel first because converting the existing database to Translated one need to manually rewritten fields and can be problematic.
translate_app/model.pyfrom django.db import models
from django.utils import timezone
from django.contrib.auth.models import Userfrom django.utils.translation import gettext_lazy as _
from parler.models import TranslatableModel, TranslatedFieldsclass Post(TranslatableModel):
translations = TranslatedFields(
title = models.CharField(_('title'), max_length=250, db_index=True),
body = models.TextField(_('body'), db_index=True),
)
author = models.ForeignKey(User,
on_delete=models.CASCADE,
related_name='blog_posts',
verbose_name=_('author'),)
publish = models.DateTimeField(_('publish'),default=timezone.now)
created = models.DateTimeField(_('created'),auto_now_add=True)
updated = models.DateTimeField(_('updated'),auto_now=True)def __str__(self):
return self.title
This model doesn’t translate all fields because we don’t need all of them to translate. We translate title and body using TranslatableModel. Next, we need to adjust our admin.py to display it in a proper way.
translate_app/admin.pyfrom django.contrib import admin
from .models import Post
from parler.admin import TranslatableAdmin@admin.register(Post)
class PostAdmin(TranslatableAdmin):
list_display = ('title','author','publish')
list_filter = ('created','publish','author')
search_fields = ('title','body')
Now we can create template for our app:
Proper folder structure for our translate_app:
templates/
blog/
base.html
post/
detail.html
list.html
Next, let’s create content to translate:
django-admin makemessages --all
#This is for our template translation ni locale folder
django-admin compilemessages
Let’s create a view:
from django.views.generic import ListView, DetailView
from .models import Postclass PostListView(ListView):
model = Post
template_name = 'blog/post/list.html'
context_object_name = 'posts'class PostDetail(DetailView):
model = Post
template_name = 'blog/post/detail.html'
context_object_name = 'post'
The last thing is to set up proper routes in translate_project/urls.py:
from django.contrib import admin
from django.urls import path
from django.conf.urls.i18n import i18n_patternsfrom inter_app import viewsurlpatterns = i18n_patterns(
path('admin/', admin.site.urls),
path('', views.PostListView.as_view(),name='home'),
path('post/<int:pk>/', views.PostDetail.as_view(), name='post-detail'),
)
Now we can create migrations and create superuser to add posts in admin panel:
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser
This is a basic starter for the side with database content.
Next stage will be created Django REST-API with translation.