Son güncelleme: Nisan 2026 · AnomixLabs Teknik Ekibi
Çok dilli bir Django projesi inşa etmek, doğru araçlarla göründüğünden çok daha sistematik bir süreçtir. UI metinleri için gettext, veritabanı içerikleri için django-parler — ikisi birlikte mükemmel bir çözüm oluşturur.
1. Temel Kavramlar: i18n, L10n ve G11n
Internationalization (i18n) — yazılımın farklı dil ve bölgelere uyarlanabilmesi için altyapı hazırlanmasıdır. Localization (L10n) ise bu hazır altyapının belirli bir dil/bölge için doldurulmasıdır. Globalization (G11n) her ikisini kapsayan üst kavramdır. Django her ikisini de yerleşik olarak destekler; ekstra altyapı gerekmez.
Pratikte iki ayrı katmana ihtiyaç duyarsınız: statik metin çevirisi (buton etiketleri, hata mesajları — gettext ile) ve veritabanı içerik çevirisi (makale başlıkları, ürün açıklamaları — django-parler ile).
2. Django 5.x settings.py i18n Yapılandırması
LocaleMiddleware'in SessionMiddleware'den sonra, CommonMiddleware'den önce gelmesi kritiktir. Sıra yanlışsa dil tespiti çalışmaz:
LANGUAGE_CODE = 'tr'
TIME_ZONE = 'Europe/Istanbul'
USE_I18N = True
USE_L10N = True
USE_TZ = True
LANGUAGES = [
('tr', 'Türkçe'),
('en', 'English'),
]
LOCALE_PATHS = [BASE_DIR / 'locale']
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware', # ← bu sıra kritik
'django.middleware.common.CommonMiddleware',
'...',
]
INSTALLED_APPS = [
'...',
'parler',
'rosetta',
]
3. gettext Kurulumu
Ubuntu/Debian:
$ sudo apt install gettext
# Doğrulama
$ msginit --version
Windows: mlocati.github.io adresinden 64-bit installer indirin ve PATH'e ekleyin. Ardından msginit --version ile doğrulayın.
4. makemessages ve compilemessages
# Tüm Python ve template dosyalarını tara, .po oluştur
$ python manage.py makemessages -l en
$ python manage.py makemessages -l tr
# .po dosyalarını düzenledikten sonra .mo'ya derle
$ python manage.py compilemessages
# Yalnızca belirli dizini tara
$ python manage.py makemessages -l en --ignore=venv/*
# CI/CD pipeline'da otomatikleştirmek için:
$ python manage.py compilemessages --ignore=.venv
5. Model ve Form Çevirileri (gettext_lazy)
Model field verbose_name ve form label gibi kodda sabit yazılan metinlerde gettext_lazy kullanın. _('...') kısa formu standarttır:
from django.utils.translation import gettext_lazy as _
class Product(models.Model):
name = models.CharField(
verbose_name=_('Ürün Adı'),
max_length=200,
)
price = models.DecimalField(
verbose_name=_('Fiyat'),
max_digits=10, decimal_places=2,
)
class Meta:
verbose_name = _('Ürün')
verbose_name_plural = _('Ürünler')
6. Template Çevirileri
{% load i18n %}
{# Basit çeviri #}
{% translate "Hoş Geldiniz" %}
{# Değişkenli çeviri #}
{% blocktranslate with name=user.name %}
Merhaba, {{ name }}!
{% endblocktranslate %}
{# Çoğul #}
{% blocktranslate count counter=items|length %}
{{ counter }} ürün
{% plural %}
{{ counter }} ürün
{% endblocktranslate %}
7. URL Yapısı: i18n_patterns
from django.conf.urls.i18n import i18n_patterns
from django.urls import path, include
urlpatterns = [
path('i18n/', include('django.conf.urls.i18n')), # set_language view
] + i18n_patterns(
path('', views.HomeView.as_view(), name='home'),
path('hakkimda/', views.AboutView.as_view(), name='about'),
path('blog/', include('blog.urls')),
prefix_default_language=False, # /tr/ önekini gizle
)
8. django-parler: Veritabanı İçerik Çevirisi
UI metinleri için gettext yeterlidir; ancak dinamik veritabanı içeriklerini çevirmek için django-parler gereklidir. Parler, her çevrilebilir model için ayrı bir çeviri tablosu oluşturur:

$ pip install django-parler
PARLER_LANGUAGES = {
1: (
{'code': 'tr'},
{'code': 'en'},
),
'default': {
'fallback': 'tr',
'hide_untranslated': False,
},
}
from parler.models import TranslatableModel, TranslatedFields
class Article(TranslatableModel):
translations = TranslatedFields(
title=models.CharField(max_length=200),
slug=models.SlugField(unique=True),
content=models.TextField(),
summary=models.TextField(blank=True),
)
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.safe_translation_getter('title', any_language=True)
9. TranslatableAdmin
from parler.admin import TranslatableAdmin
@admin.register(Article)
class ArticleAdmin(TranslatableAdmin):
list_display = ['title', 'author', 'created_at']
# Admin panelinde dil sekmeleri otomatik görünür
10. TranslatableSlugMixin ile DetailView
from parler.views import TranslatableSlugMixin
from django.views.generic import DetailView
class ArticleDetailView(TranslatableSlugMixin, DetailView):
model = Article
template_name = 'article_detail.html'
# slug alanı aktif dile göre otomatik çözülür
11. Template: Dil Değiştirme Widget
{% load i18n %}
{% csrf_token %}
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% for lang_code, lang_name in LANGUAGES %}
{{ lang_name }}
{% endfor %}
12. django-rosetta ile Çeviri Arayüzü
$ pip install django-rosetta
if settings.DEBUG:
urlpatterns += [path('rosetta/', include('rosetta.urls'))]
Rosetta, /rosetta/ adresinde görsel bir .po editörü açar. Çevirmenlerle çalışmak için idealdir — terminal komutlarına gerek kalmaz.

13. hreflang ile SEO: Dil Sinyali
Çok dilli sitelerde Google'a hangi sayfanın hangi dil/bölge için olduğunu bildirmek için hreflang etiketi kullanılır. Yokluğunda Google farklı dildeki sayfaları birbirinin kopyası zannedebilir:
{% load i18n %}
{% get_available_languages as LANGUAGES %}
{% for lang_code, lang_name in LANGUAGES %}
{% endfor %}
14. Türkçe Slug Problemi ve Çözümü
Django'nun varsayılan slugify() fonksiyonu Türkçe karakterleri düzgün işlemez. ş, ı, ç, ğ, ö, ü harfleri tamamen atılır:
from django.utils.text import slugify
# SORUN: Türkçe karakterler atılıyor
slugify('Şeker Fabrikası') # → 'eker-fabrikas' (yanlış!)
# ÇÖZÜM: Önce karakter dönüşümü yap
TR_MAP = str.maketrans('şŞıİçÇğĞöÖüÜ', 'sSiIcCgGoOuU')
def tr_slugify(text: str) -> str:
return slugify(text.translate(TR_MAP))
tr_slugify('Şeker Fabrikası') # → 'seker-fabrikasi' (doğru!)
15. Yaygın Parler Hatası: save() Sonrası Dil Kaybı
AnomixLabs projelerinde sık karşılaştığımız bir tuzak: save() çağrısından sonra aktif dil sıfırlanır ve bir sonraki set_current_language() çağrısına kadar varsayılan dil (genellikle tr) aktif olur. İlişkili nesneleri (InsightFAQ gibi) kaydederken dili tekrar set etmek gerekir:
# YANLIŞ — save() sonrası dil sıfırlanır
article.set_current_language('en')
article.title = 'Hello'
article.save()
# Burada dil 'tr'ye döndü!
faq.set_current_language('en') # ← tekrar set etmek gerekiyor
# DOĞRU — her ilişkili nesne için dili tekrar set et
for lang_code in ['tr', 'en']:
article.set_current_language(lang_code)
article.title = translations[lang_code]['title']
article.save()
faq = InsightFAQ(article=article)
faq.set_current_language(lang_code)
faq.question = translations[lang_code]['question']
faq.save()
16. CI/CD'de compilemessages Otomasyonu
Production deploy pipeline'ınıza compilemessages adımını mutlaka ekleyin. Aksi takdirde .po dosyasındaki değişiklikler yayına girmez:
# GitHub Actions veya benzeri CI'da
- name: Compile translations
run: |
sudo apt-get install -y gettext
python manage.py compilemessages
# Makefile hedefi olarak
translate:
python manage.py makemessages -l en -l tr
python manage.py compilemessages
Özet
Django 5.x çok dilli proje mimarisi üç katmandan oluşur: gettext + rosetta (UI metinleri), django-parler (veritabanı içerikleri) ve i18n_patterns (URL yapısı). hreflang etiketleri SEO için zorunludur. Türkçe slugları için tr_slugify yardımcı fonksiyonu kullanın. Bu dört bileşen birlikte tam ölçeklenebilir, sürdürülebilir bir çok dilli platform oluşturur.
Sıkça Sorulan Sorular
django-parler ile gettext arasındaki temel fark nedir? expand_more
Yeni bir dil eklemek için ne yapılmalı? expand_more
prefix_default_language=False ne işe yarar? expand_more
hreflang etiketi neden gerekli? expand_more
RTL (sağdan sola) dil desteği nasıl eklenir? expand_more
Parler slug çakışması sorunu nasıl çözülür? expand_more
Migration sırasında mevcut modeli TranslatableModel'a dönüştürebilir miyim? expand_more
PARLER_LANGUAGES'da fallback ayarı ne işe yarar? expand_more
Ali Kasımoğlu
Full-stack Geliştirici & AnomixLabs Kurucusu
Python ve Django ekosisteminde uzmanlaşmış bir yazılım geliştirici. Modern web mimarileri, yapay zeka entegrasyonları ve minimalist kullanıcı deneyimleri üzerine odaklanıyor. AnomixLabs çatısı altında, karmaşık problemleri yalın ve etkili dijital çözümlere dönüştürmeyi hedefliyor.