Django Web Sitesine Çoklu Dil Desteği Ekleme - Yerelleştirme (Localization) ve Küreselleştirme (Internationalization)

Günümüz web siteleri artık çok daha geniş kitlelere hitap etmektedir. Bu sebeple bir web sitesi yaparken çoğunlukla birden fazla dil desteğinin olması öngörülür. Django, uluslararasılaştırma (internationalization) ve yerelleştirme (localization) için güçlü bir çerçeve sunar. Bu çerçeve sayesinde, uygulamanızı birden çok dile çevirebilir ve kullanıcıların kendi dillerini seçmesine izin verebilirsiniz.

Bu yazımda sizlere Django web sitesine çoklu dil desteği ekleme nasıl yapılır tüm detaylarıyla anlatacağım. Yani sadece Django'nun dahili çoklu dil desteği sistemini değil, aynı zamanda işinizi oldukça kolaylaştıracak Rosetta (django-rosettave Parler (django-parlergibi ek kütüphanelerden de bahsedeğiz.

İçindekiler:

  1. Internationalization (i18n) / Uluslararasılaştırma Nedir?
  2. Localization (L10N) Yerelleştirme Nedir?
  3. Django'da Çoklu Dil Kullanımı
  4. Django Rosetta Çeviri Arayüzü
  5. Django Parler İle Modelleri Çevirin
  6. Son Söz

Internationalization (i18n) / Uluslararasılaştırma Nedir?

Uluslararasılaştırma, uygulamanızın farklı diller için hazır duruma getirilmesidir. Bu, uygulamanızdaki metinlerin ve diğer yerelleştirilebilir verilerin, yani çevirilebilir yazıların, farklı dillere çevrilmeye hazır bir şekilde yazılımcı tarafından düzenlenmesini içerir. Kafanızda çok fazla birşey canlanmadıysa endişelenmeyin. Yazı sonunda hepsine hakim olacaksınız.

Django'da uluslararasılaştırmayı etkinleştirmek için, settings.py dosyasında aşağıdaki ayarları yapmanız gerekir:

# Internationalization
# https://docs.djangoproject.com/en/3.1/topics/i18n/

LANGUAGE_CODE = 'tr'
TIME_ZONE = 'Europe/Istanbul'
USE_I18N = True
USE_L10N = True
USE_TZ = True

Bu ayarlar, uygulamanızın birden çok dile çevrilebileceğini belirtir. Gelin yukarıdaki ayarları biraz daha açıklayalım:

LANGUAGE_CODE değişkeni ile aslen sitemizin hangi dilde olacağını, yani varsayılan dilini tanımlıyoruz. Varsayılan olarak en-us yerele özgü (locale-specific) tanımıyla gelir. Bunun genel (generic) tanımı ise en şeklinde yazılır. Türkçe için genel tanım tr olacaktır.

Not: LANGUAGE_CODE'un aktif olabilmesi için ayrıca Django'nun çeviri sistemini etkinleştiren USE_I18N değişkeninin True olarak ayarlanmış olması gerekmektedir.

TIME_ZONE varsayılan olarak America/Chicago tanımıyla gelir. Tüm tz veritabanı saat dilimlerinin listesi burada yer almaktadır. USE_TZ değişkeni False olduğunda bu, Django'nun tüm "datetimes" verilerinin depolayacağı saat dilimidir. USE_TZ değişkeni True olduğunda bu, Django'nun şablonlarda "datetimes" görüntülemek ve formlara girilen "datetimes" yorumlamak için kullanacağı varsayılan saat dilimidir. Türkiye için Europe/Istanbul saat dilimini yazıyoruz.

USE_TZ varsayılan olarak False tanımıyla gelir. Django çoklu dil kullanımında True tanımını tavsiye eder. Aktif olduğunda datetimes saat dilimine duyarlı olur.

USE_I18N varsayılan olarak True tanımıyla gelir. Yukarıda da bahsettiğim üzere çoklu dil mekanizmasının çalışması için bu değişkenin True olarak tanımlanması gerekmektedir.

USE_L10N varsayılan olarak True tanımıyla gelir. Yerelleştirme mekanizmasının çalışması için için bu değişkenin True olarak tanımlanması şarttır.

Localization (L10N) Yerelleştirme Nedir?

Yerelleştirme, uygulamanızın farklı dillere uyarlanmasıdır, yani sitenize birden fazla dilin tanımlanmasını sağlar. Bu, uygulamanızın kullanıcı arayüzü, hata mesajları ve diğer yerelleştirilebilir verilerin, farklı dillere göre uyarlanmasını içerir.

Django'da yerelleştirmeyi yapmak için, uygulamanız için dil dosyaları oluşturmanız gerekir. Bu dosyalar, uygulamanızdaki metinlerin ve diğer yerelleştirilebilir verilerin, farklı dillere çevrilmiş halini içerir.

Django yerelleştirme mekanizması .po dosyalarının derlenmesi için gettext fonksiyonunu kullanır.

Windows ve Linux'te Gettext Yükleme

Windows kullanıcıları için gettext yüklemek için buraya tıklayabilirsiniz. Ubuntu Linux'te gettext yüklemek için aşağıdaki komutu kullanabilirsiniz:

sudo apt update -y
sudo apt install -y gettext

Yerelleştirme Ayarları

Öncelikle sitemizde tanımlamak istediğimiz dilleri settings.py dosyamızda tanımlıyoruz.

from django.utils.translation import gettext_lazy as _

LANGUAGES = (
    ('tr', _('Türkçe')),
    ('en', _('İngilizce')),
)

LANGUAGE_CODE tanımımızda varsayılan dil olarak Türkçe'yi ayarladığımız için ilk sıraya da onu yazıyoruz ve dil isimlerini de varsayılan dilde yazıyoruz. Burada dikkatinizi "_" alt çizgi işareti çekmiş olmalı. Bu gettext kütüphanesinin çeviri olarak tanımlayacağımız alanları işaretlememize yarayan fonksiyon. Bu sayede çevirilerimizi derlediğimizde gettext bu alanların çeviriye dahil edileceğini bilir. Bir diğer önemli husus ise, django çeviri sisteminden bu fonksiyonu gettext_lazy ile çağırmış olmamız. Bu sayede circular import (dairesel yükleme) hatalarının önüne geçebiliyoruz.

Yerelleştirme sistemini kullanmadan önce settings.py dosyanızdaki MIDDLEWARE ayarlarında aşağıdaki gibi LocaleMiddleware tanımını SessionMiddleware den sonra ve CommonMiddleware den önce eklendiğinizden emin olun.

MIDDLEWARE = [
    ...
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.locale.LocaleMiddleware',  # çoklu dil desteği için eklenmeli
    'django.middleware.common.CommonMiddleware',
    ...
]

Django, makemessages komutunu kullanarak dil dosyaları oluşturmanıza yardımcı olur. Bu komut, uygulamanızdaki tüm yerelleştirilebilir verileri tarar ve bunları, locale/ dizini altında bulunan dil dosyalarına dönüştürür.

Ancak öncesinde settings.py dosyamızda LOCALE_PATHS yolunun tanımlamasını yapmamız gerekmektedir.

LOCALE_PATHS = [
    BASE_DIR / 'locale/',
]

Bu kod sayesinde gettext ile oluşturulan çeviri dosyalarımız projemizin anadizininin locale/ klasöründe olduğunu belirtmiş oluruz.

Dil Dosyalarını Oluşturma

Dil dosyalarını oluşturmak için, Linux'te aşağıdaki komutu çalıştırın:

python manage.py makemessages -l tr -l en

Bu komut, Türkçe ve İngilizce dilleri için dil dosyaları oluşturacaktır. Dilerseniz dilleri ayrı ayrı yazmadan tüm dillerin oluşturulmasını aşağıdaki komutla da sağlayabilirsiniz.

python manage.py makemessages --all

PyCharm gibi bir IDE içindeki terminalde kullanım için aşağıdaki komutu kullanabilirsiniz:

django-admin makemessages --all --ignore=env

Bu komutlardan sonra gettext belirlediğimiz tüm çeviri alanlarını tespit edecek ve projenizin anadizininde aşağıdaki gibi klasörler oluşacaktır:

locale
└── en
    └── LC_MESSAGES
        └── django.po

.po dosyalarımızı *.po dosya formatını düzenleyebilen bir editörde açabilir veya IDE içerisinde açıp text olarak düzenleyebilirsiniz. Örnek olarak:

msgid "Türkçe"
msgstr "Turkish"

Varsayılan dilimiz Türkçe olduğundan ve haricinde sadece İngilizce dili olduğundan en/ klasörü oluşturuldu ve dolayısıyla .po dosyasındaki msgstr alanına da İngilizce karşılıklarını yazıyoruz.

Dil Dosyalarını Derleme

Dil dosyalarını oluşturduktan sonra, bunları compilemessages komutunu kullanarak derlemeniz gerekir. Bu komut, dil dosyalarını, uygulamanız tarafından kullanılabilecek bir formata dönüştürür.

Dil dosyalarını derlemek için, Linux'te aşağıdaki komutu çalıştırın:

python manage.py compilemessages

PyCharm gibi bir IDE içindeki terminalde kullanım için aşağıdaki komutu kullanabilirsiniz:

django-admin compilemessages --ignore=env

Django'da Çoklu Dil Kullanımı

Django'da çoklu dil kullanmak için, uygulamanızdaki metinleri ve diğer yerelleştirilebilir verileri modellerde, görünümlerde, formlarda ve template şablonlarında işaretlememiz gerekmektedir. Bunu size nasıl yapacağımızı size aşağıda detaylı olarak anlatacağım.

Çeviri Alanlarını İşaretleme

Django'da çeviri alanlarını işaretlemek için gettext veya gettext_lazy fonksiyonu kullanıyoruz. Ben size gettext_lazy fonksiyonunu kullanmanızı yukarıda tavsiye etmiştim. Örneklerimizi de bu şekilde vereceğiz. gettext_lazy fonksiyonunu çağırmak için aşağıdaki kodu çağırmak gerekir:

from django.utils.translation import gettext_lazy as _

Fark ettiyseniz çağırırken gettext_lazy'yi "_" alt tire ismiyle çağır dedik. Bu sayede çevirilecek alanları işaretlerken sadece başına "_" alt tire koymamız yeterli olacak. settings.py dosyamızda ayarladığımız LANGUAGE değişkeninde dilleri nasıl tanımladığımızı hatırlayın:

LANGUAGES = (
    ('tr', _('Türkçe')),
    ('en', _('İngilizce')),
)

"_" alt tire ile başlayan ve sonrasında parantez içerisinde belirttiğimiz ifade artık çeviri için işaretlenmiş oldu. Bunu tüm string (str) verilerimizde uygulayabilmemiz mümkün. Dil dosyasını makemessages komutu ile oluşturduğumuzda otomatik olarak bu alanlar çeviri dosyamıza eklenecek.

Model İçinde Çeviri İşaretleme

Django'da model.py dosyalarımızda çevrilmesini istediğimiz alanları aşağıdaki şekilde kolayca işaretleyebiliriz.

from django.db import models
from django.utils.translation import gettext_lazy as _

class Blog(models.Model):
    title = models.CharField(_('Sayfa Başlığı'), max_length=150, unique=True)
    short_description = models.TextField(_('Kısa Açıklama'), max_length=300)
    published_date = models.DateTimeField(_('Yayınlanma Tarihi'), default=timezone.now)

    def __str__(self):
        return self.title

Görünümlerin (Views) ve Formların (Forms) İçinde Çeviri İşaretleme

Model içinde işaretlemeyle aynı mantıktadır. Çevirisini yapmak istediğiniz ifadenin önünü "_" işareti ile ifadeyi parantez içine almanız yeterlidir. Bir örnek de formlar için verelim.

from django import forms
from django.utils.translation import gettext_lazy as _

class OrnekForm(forms.Form):
    first_name = forms.CharField(label=_('İsim'))

Yukarıdaki örneklerde gördüğünüz üzere çeviri işaretleme oldukça basit. Gelin bir de bunun şablonlar (templates) içerisinde nasıl yapıldığını öğrenelim.

Şablonlar (Templates) İçinde Çeviri İşaretleme

Şablonların içinde çeviri alanı işaretleme model, görünüm veya diğer alanlardaki "_" işaretiyle işaretlemeden biraz daha farklıdır. Django şablonlar için bize {% translate %} ve {% blocktranslate %} isminde iki tamplate tag (şablon etiketi) sunar. Bu şablon etiketlerini kullanabilmek için HTML kodunuzun en üstüne {% load i18n %} kodunu eklemeniz yeterli olacaktır.

Örnek olarak aşağıdaki gibi bir kodumuz olsun:

...

<meta name="title" content="Test Blog Sayfası Başlığı">

<h1>Test Blog Yazısı</h1>

<a href="#" title="">{{ post.title }} yazını oku.</a>

<div>Yayınlanma Tarihi:<br>{{ post.published_date }}</div>

...

Bu kodu işaretlemek için şu şekilde düzenleme yapmamız gerekirdi.

{% load i18n %}

...

<meta name="title" content="{% translate "Test Blog Sayfası Başlığı" %}">

<h1>{% translate "Test Blog Yazısı" %}</h1>

<a href="#" title="">{% blocktranslate %}'{{ post.title }}' yazını oku.{% endblocktranslate %}</a>

<div>{% blocktranslate %}Yayınlanma Tarihi:<br>{{ post.published_date }}{% endblocktranslate %}</div>

...

Gördüğünüz gibi translate etiketini kullanırken içerisinde string (metin) dışında herhangi bir ifade bulunmazken, blocktranslate etiketinin içerisinde şablon değişkeni veya html kodu kullanabiliyoruz.

İşaretlemeleriniz bittikten sonra yukarıdaki Dil Dosyasını Oluşturma bölümünde de anlattığım makemessages komutuyla çeviri dosyanızı oluşturabilir ve oluşturulan .po dosyanızın içerisindeki "msgstr" alanlarına ilgili çevirileri ekledikten sonra Dil Dosyalarını Derleme bölümünde anlattığım compilemessages komutunu kullanarak çevirilerinizi derleyebilirsiniz.

Django herhangi bir ek uygulama gerektirmeden dil dosyalarımızı oluşturup derlememize olanak sağlıyor. Ancak bunu çok daha güzel ve kolay şekilde yapmanın yöntemi de var. .po dosyasının içerisinde msgstr değişkenlerini düzenlemek yerine, doğrudan Django admin panelinden bu işlemleri göster bir arayüz kullanarak da yapabilirsiniz. Bunun için projemize Rosetta kütüphanesini dahil etmemiz gerekiyor.

URL Modelleri İçin Dil Ön Eki (prefix) Ekleme ve URL Çeviri İşaretleme

Django çoklu dil kullanımında URL katmanı için de oldukça geniş imkanlar sunar. Eğer sitenize çoklu dil eklemek istiyorsanız, url adresinizin sonunda dil tanımının da gözükmesi doğru olacaktır. Örnek olarak: siteadresi.com/tr/ veya siteadresi.com/en/ şeklinde dili ifade edecek prefix eklenmesi gerek kullanıcılar açısından, gerek ise SEO açısından doğru tercih olacaktır. Bu işlevi tanımlayabilmek için projemizin ana dizinindeki urls.py dosyamızda ufak bir değişikliğe ihtiyacımız olacak. Django bunun için bize i18n_patterns fonksiyonunu sunuyor.

... # diğer eklediğiniz modüller
from django.urls import path, include
from django.conf.urls.i18n import i18n_patterns

urlpatterns = i18n_patterns(
    path('admin/', admin.site.urls),
    path('', include('mainsite.urls')),
)

i18n_patterns() fonksiyonu ile projemizin ana url dosyasında yukarıdaki gibi tanımlama yaptığımızda, web sitesinin tüm sayfalarının url adresinde aktif dil prefix'i eklenmiş olacak. Ancak bazı durumlarda url dosyamızda ekleyebileceğimiz url'lerin dil prefix'ini göstermesini istemeyebilirsiniz. Bunun için şöyle bir düzenleme yapabilirsiniz:

... # diğer eklediğiniz modüller
from django.urls import path, include
from django.conf.urls.i18n import i18n_patterns

urlpatterns = i18n_patterns(
    path('admin/', admin.site.urls),
    path('', include('mainsite.urls')),
) + [
    path('sitemap.xml', sitemap, {'sitemaps': sitemaps}, name='django.contrib.sitemaps.views.sitemap'),
    path('robots.txt', TemplateView.as_view(template_name="robots.txt", content_type='text/plain')),
    path('service-worker.js', TemplateView.as_view(template_name="service-worker.js", content_type='text/javascript')),
]

Ayrıca istersek herhangi bir sayfamızın url adresini dile göre çevirebiliriz de. Bunun için de dilediğiniz url dosyasında aşağıdaki gibi değişiklik yapmanız yeterli olur.

from django.urls import path
from django.utils.translation import gettext_lazy as _
from mainsite.views import IndexView, AboutmeView

app_name = 'mainsite'
urlpatterns = [
    path('', IndexView.as_view(), name='index'),
    path(_('hakkimda/'), AboutmeView.as_view(), name='about-me'),
]

Fark ettiğiniz gibi url'ler için de çeviri işaretleme aynı diğer katmanlarda olduğu gibi gettext_lazy ile "_" tanımını kullanarak yapılıyor. İşaretleme sonrası aynı diğer katmanlarda yaptığımız gibi makemessages komutuyla çeviri dosyanızı oluşturabilir ve oluşturulan .po dosyanızın içerisindeki "msgstr" alanlarına ilgili çevirileri ekledikten sonra compilemessages komutunu kullanarak çevirilerinizi derleyebilirsiniz. Türkçe dil seçeneği ile sitenize giren kullanıcı siteadresi.com/tr/hakkimda/ url'ini görecekken, İngilizce diliyle giren kullanıcı siteadresi.com/en/about-me/ url'ini görecektir.

Kullanıcıların Dil Değiştirmesini Sağlama

Django web sitemizde kullanıcıların mevcut dilleri görüp diller arası geçiş yapmasını sağlamak oldukça kolaydır. Bunun birkaç farklı yöntemi olmakla birlikte, aslında bunlar yöntemden çok tarz veya arayüz beklentileri ile alakalıdır. Aşağıda bunun için size iki farklı örnek vereceğim.

{% get_current_language as CURRENT_LANGUAGE %}
{% get_available_languages as AVAILABLE_LANGUAGES %}
{% get_language_info_list for AVAILABLE_LANGUAGES as languages %}
<div>
    <p>{% trans "Dil Seçenekleri" %}:</p>
    <ul>
    {% for language in languages %}
        <li>
            <a href="/{{ language.code }}/"
            {% if language.code == CURRENT_LANGUAGE %} class="active"{% endif %}>
                {{ language.name }}
            </a>
        </li>
    {% endfor %}
    </ul>
</div>

Yukarıdaki kodda Django'dan get_current_language şablon etiketi ile aktif olan dili CURRENT_LANGUAGE değişkenine tanımlayarak aldık. Ardından get_available_languages şablon etiketini AVAILABLE_LANGUAGES değişkeni ile tanımlayarak tüm dil seçeneklerini aldık. Sonra da get_language_info_list şablon etiketi ile tüm dil seçeneklerinin içinden açıklama bilgilerini languages değişkeni ile aldık.

Sonrasında html kodlarımızda Django şablon dilini kullanarak tüm mevcut dil seçeneklerini yazdırdık. if koşuluyla da eğer döngü içerisindeki dil mevcut aktif dil ise bunun bağlantı class'ı için active etiketini eklettik. Çıktımız aşağıdaki gibi olacaktır:

Dil Seçenekleri:

  • Türkçe
  • İngilizce

Bir diğer örnek ise şöyle:

{% get_current_language as CURRENT_LANGUAGE %}
    <li>
        <div>
            <img class="flag-icon" src="{% static 'img/flag-usa-16.webp' %}" alt="English" title="English"><a class="{% if CURRENT_LANGUAGE == "en" %}pe-none text-decoration-none{% endif %}" href="/{{ language.code }}/" title="English"><span>English</span></a>
            <img class="flag-icon" src="{% static 'img/flag-turkey-16.webp' %}" alt="Türkçe" title="Türkçe"><a class="lang-menu-text {% if CURRENT_LANGUAGE == "tr" %}pe-none text-decoration-none{% endif %}" href="/{{ language.code }}/" title="Türkçe"><span>Türkçe</span></a>
        </div>
    </li>

Bu örnekler ihtiyaçlarımıza göre değiştirlebilir. Burada önemli olan Django'nun bize hangi etiketleri ve daha doğrusu imkanları sunduğuna vakıf olabilmektir. Bunun için detaylı bilgiye Django'nun dökümentasyonundan buraya tıklayarak ulaşabilirsiniz. Tüm detaylı bilgileri öğrenebileceğiniz Django'nun Translation (Çeviri) Dökümentasyonu için buraya tıklayabilirsiniz.

Django Rosetta Çeviri Arayüzü

Rosetta .po uzantılı dil dosyalarının kolayca Django admin arayüzü üzerinden düzenlemesine olanak sağlayan üçüncü taraf kütüphanedir. 

Django Rosetta Kurulumu

django-rosetta kütüphanesini projemizin çevresine (environment) ekleyebilmek için öncelikle environment'in aktif edilmesi sonra kurulum için komutların çalıştırılması gerekmektedir.

python3 -m venv env    # bu komutla eğer daha önce oluşturmadıysak projemize environment oluşturuyoruz
source env/bin/activate    # bu komutla environmen'imizi aktif ediyoruz

pip install django-rosetta    # bu komutla django-rosetta kütüphanesini yüklüyoruz

Ardından settings.py dosyamızdaki INSTALLED_APPS değişkenimize rosetta uygulamasını dahil ediyoruz.

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'mainsite.apps.MainsiteConfig',

    # third party
    'rosetta',
]

Yine settings.py dosyamızın içine projeniz için eğer ana dil olarak İngilizce kullanmıyorsanız, mesela örneklerimizde biz anadil olarak Türkçe kullandık, Rosetta'ya özel iki ayar eklemek gerekir.

ROSETTA_MESSAGES_SOURCE_LANGUAGE_CODE = 'tr'
ROSETTA_MESSAGES_SOURCE_LANGUAGE_NAME = 'Turkish'

Bu ve diğer tüm ayarlara Rosetta'nın dökümentasyonundan buraya tıklayarak ulaşabilirsiniz.

Daha sonra projemizin ana urls.py dosyası içine rosstta'nın url adresini dahil ediyoruz.

from django.conf import settings
from django.conf.urls import include, path

if 'rosetta' in settings.INSTALLED_APPS:
    urlpatterns += [
        path('rosetta/', include('rosetta.urls'))
    ]

Bu işlemleri tamamladıktan sonra veritabanını güncelleyebiliriz.

(env)$ python manage.py makemigrations
(env)$ python manage.py migrate

Veri tabanını güncelledikten sonra projemizi yeniden başlatmayı unutmayın. PyCharm gibi bir IDE editör kullanıyorsanız bu işlem basit. Ancak üretim modundaysanız Ubuntu gibi bir linux dağıtımı için bunu aşağıdaki komutla gunicorn'u yeniden başlatarak da yapabilirsiniz.

sudo systemctl restart gunicorn

Not: Üretim modunda Rosetta'nın locale/ klasöründe bulunan .po dosyasına okuma ve yazma yetkisi verilmelidir.

Rosetta'ya ulaşabilmek için tarayıcınızın adres çubuğuna http://127.0.0.1:8000/rosetta/ url'ini yazmanız yeterli. 

Django Rosetta

Açılan sayfada genel istatistikleri görebilir, listedeki UYGULAMA alanından proje adına tıkladığımızda çevirileri yapabileceğiniz ekrana ulaşabilirsiniz.

Django Rosetta Çeviri

Çevirileri yaptıktan sonra "Kaydet ve Sonraki Bloğu Çevir" butonuna basarak çevirileri kaydedebilirsiniz. Bu işlemden sonra Rosetta çeviri dosyasını otomatik olarak derleyecektir, dolayısıyla django-admin compilemessages --ignore=env komutunu manuel olarak çalıştırmanıza gerek yoktur. Çeviriler sitenizde gözükmüyorsa yukarıda anlattığım şekilde gunicorn'u yeniden başlatabilirsiniz.

django-rosetta kütüphanesinin kendi dökümentasyonu için buraya tıklayarak tüm bilgilere ulaşabilirsiniz.

Django Parler İle Modelleri Çevirin

Django modeller için hazırda tam bir çeviri altyapısı sunmamaktadır. Bunun için üçüncü taraf kütüphanelere ihtiyacımız olup, bu kütüphaneler arasında da en iyisi olan django-parler kullanımı size anlatacağım. Tam olarak Parler'in ne işe yaradığını aşağıdaki resime bakarak kafanızda canlandırabilirsiniz.

Django Parler

Gördüğünüz gibi, örnekte kullanılan blog modeli için iki farklı model oluşturmak yerine, sadece django-parler kütüphanesini kullanarak aynı modeli istediğimiz dillerde doğrudan Django admin paneli üzerinden düzenleyerek çevirebiliyoruz. Bu bize olduça fazla konfor sağlayacaktır.

Django Parler Kurulumu

django-parler kütüphanesini projemize kurmak için komut satırında aşağıdaki kodu çalıştırabilirsiniz:

pip install django-parler

Ardından settings.py dosyamızdaki INSTALLED_APPS değişkenine parler uygulamasını eklemeniz gerekmektedir.

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'mainsite.apps.MainsiteConfig',

    # third party
    'rosetta',
    'parler',  # parler uygulaması
]

Zorunlu olmayan ama eklenmesini tavsite ettiğim dir diğer ayar da şöyle:

PARLER_LANGUAGES = {
    None: (
        {'code': 'tr', },  # Türkçe
        {'code': 'en', },  # İngilizce
    ),
    'default': {
        'fallbacks': ['tr'],
        'hide_untranslated': False,
    }
}

PARLER_DEFAULT_LANGUAGE_CODE = 'tr'

Burada None yazan alanda, eğer ayarlarınızda çoklu siteli proje (multi-site) veya başka bir nedenle SITE_ID kullanıyorsanız, SITE_ID için tanımladığınız rakamı yazabilirsiniz. Örneğin SITE_ID = 1 ise None yerine de 1 ve 2 şeklinde yazabilirsiniz.

Dil kodlarında ilk sırada varsayılan dilin önce yazılması gerekmektedir. default olarak tanımlanan fallbacks anahtarı PARLER_DEFAULT_LANGUAGE_CODE için tanımlanmış varsayılan dil kodununun değerini alır ama yazmaktan zarar gelmez. hide_untranslated anahtarı ise çevirisi eklenmemiş dillerin görüntülenip görüntülenmeyeceğini belirler. Genelde örnek olarak bir blog yazısı yazarken, diğer dilleri de hemen ardından eklemek en doğru seçenek olduğu için, bunu False olarak bırakmanız mantıklı olacaktır. Eğer diğer dil seçeneğinde bir ekleme yapmadıysanız, fallbacks anahtarının değerindeki dil kodunda yer alan içerik gözükecektir.

Django Parler Model İçerisinde Kullanımı

django-parler, model alanlarını çevirmek için bir TranslatableModel model sınıfı ile bir TranslatedFields sarmalayıcı sınıf (wrapper class) sağlar ve çevrilebilir her model için veritabanında başka bir model oluşturarak çevirileri yönetir. Gelin anlatmaktansa aşağıdaki örnekle bunu anlamaya çalışalım.

from django.db import models
from ckeditor_uploader.fields import RichTextUploadingField
from django.utils import timezone

from django.utils.translation import gettext_lazy as _
from parler.models import TranslatableModel, TranslatedFields


class Blog(TranslatableModel):
    status = models.BooleanField('Aktif/Pasif', default=False)

    translations = TranslatedFields(
        slug=models.SlugField("Slug", max_length=60, unique=True),
        title=models.CharField('Sayfa Başlığı', max_length=150, unique=True),
        short_description=models.TextField('Kısa Açıklama', max_length=300),
        content=RichTextUploadingField('İçerik Yazısı'),
    )

    published_date = models.DateTimeField(_('Yayınlanma Tarihi'), default=timezone.now)

    def __str__(self):
        return self.title

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.seo_title)
        super(Blog, self).save(*args, **kwargs)

    def get_absolute_url(self):
        return reverse('mainsite:blog-details', args=[self.slug])

    class Meta:
        verbose_name_plural = "Blog Yazıları"
        verbose_name = "Blog Yazısı"
        ordering = ['-published_date']

Yukarıdaki örneği tek tek inceleyelim:

Normal şartlarda Django ile model sınıfı tasarlarken models.Model sınıfını kullanırken, django-parler ile TranslatableModel sınıfını kullanıyoruz. Modelin içerisinde çevirisinin olmasını istediğimiz alanları ise translations değişkeni içerisinde TranslatedFields sarmalayıcı sınıfını kullanarak tanımlıyoruz.

Burada slug alanı ile alakalı bazı önemli bilgileri size birazdan vereceğim. Şimdilik buna kafa yormanıza gerek yok. Ayrıca farkettiyseniz yine "_" alt çizgi ile çevirisini işaretlediğimiz bazı metinlerimiz (strings) bulunuyor.

Model içerisinde yapmamız gereken ayarlamalar bu kadar. Şimdi aşağıdaki komutlarla veritabanını güncelleyebiliriz.

(env)$ python manage.py makemigrations
(env)$ python manage.py migrate

Ayrıca üretim modundaysanız gunicorn'u da yeniden başlatmanız faydalı olacaktır.

Django Parler Views (Görünümler) İçinde Kullanımı

django-parler 'i görünümler (views) içinde normal durumlarda kullanmanız gerekmez. Ancak bazı durumlarda, örneğin yukarıdaki slug kullanmak isteyeceğiniz durumlarda görünümlerde de bazı değişiklikler yapmanız gerekecektir. Bu ve bunlar gibi durumlar için parler bize ViewUrlMixin, TranslatableSlugMixin, LanguageChoiceMixin, TranslatableModelFormMixinTranslatableCreateView, TranslatableUpdateView gibi hazır sınıflar sunuyor. Aşağıda slug kullanımına yönelik görünümler üzerinden bir örnek verelim.

from django.views.generic import DetailView
from parler.views import TranslatableSlugMixin


class BlogDetailView(TranslatableSlugMixin, DetailView):
    template_name = "mainsite/blog-details.html"
    queryset = Blog.objects.filter(status=True)
    context_object_name = "blog_post"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['blog'] = self.get_object()
        return context

Görüldüğü üzere projenizdeki çevirilebilir her slug içeren modelin DetailView görünümünde ek olarak TranslatableSlugMixin sınıfını çağırmamız yeterli oluyor. Ayrıca aşağıda göreceğiniz admin.py dosyasında da bazı değişiklikler gerekecek. Bu sayede slug alanını her dil için kolayca çevirebilir ve html kodumuzda kolayca ilgili dile ait slug url sini çağırabiliriz. Bunu da mesela yukarıda örneğini verdiğimiz kullanıcı dil seçimi aracında {% get_translated_url 'en' %} etiketini kullanarak kolayca yapabilirsiniz. Bu etiket, mevcut modelin İngilizce dilinceki url adresini otomatik olarak alabilmemizi sağlıyor. Tabi bu etiketi kullanabilmek için öncelikle html kodunuzun en üstünde daha önce eklediğiniz i18n etiketinin yanına parler_tags etiketini de eklemeniz gerekiyor. Yani şu şekilde olacak: {% load i18n parler_tags %}.

Django Parler Admin Dosyası İçinde Kullanımı

Parler ile modelimizi düzenledikten sonra elbette django yönetici paneli içinde de bunun çalışabilmesi için bazı basit ayarlamalar yapmak gerekiyor. Normal durumlarda admin.py dosyasında bir modeli kayıt edebilmek için admin.ModelAdmin sınıfını çağırıyorduk. Parler ile bunu yapmak için sadece bu sınıfı değiştirmeniz yeterli. Aşağıdaki örneği inceleyelim.

@admin.register(Blog)
class BlogAdmin(TranslatableAdmin):
    list_display = ["title", "published_date", "status"]
    list_editable = ["status"]
    readonly_fields = ["published_date"]
    fieldsets = (
        ("İÇERİK", {
            "fields": ("status", "title", "short_description", "content", "published_date")
        }),
    )

    def get_prepopulated_fields(self, request, obj=None):
        return {
            'slug': ('title',)
        }

Gördüğünüz gibi yukarıda Blog modelini admin paneline kayıt ederken TranslatableAdmin sınıfını çağırıyoruz. Slug alanı için ise get_prepopulated_fields fonksiyonu ile slug adresinin Blog modelindeki title alanından otomatik olarak üretilmesini sağlıyoruz. Bunu normal şartlarda doğrudan BlogAdmin sınıfı içinde prepopulated_fields değişkeni ile tanımlıyorken, django-parler ile ayrı bir fonksiyon içersinde yapmamız gerekiyor.

Parler hakkında detaylı bilgiye sahip olmak için django-parler resmi dökümantasyonuna buraya tıklayarak ulaşabilirsiniz.

Son Söz

Django, çoklu dil desteğini kolayca eklemenize olanak tanır. Bu, uygulamanızın daha geniş bir kitleye ulaşmasına yardımcı olur.

Bu blog yazısında, Django için çoklu dil ekleme hakkında detaylı bilgi paylaştım. Bu bilgilere dayanarak, kendi uygulamanızda çoklu dil desteğini ekleyebilirsiniz.

Paylaş

Yeni Blog Yazılarımdan Haberdar Olun

Yeni yazılarımdan anında haberdar olmak için email listeme abone olun. Size spam göndermeyeceğime söz veriyorum!