biotech Django & Python

Django'da Çoklu Dil Desteği: i18n, Rosetta ve django-parler Tam Rehberi

AK
Ali Kasımoğlu
24 Kas 2023 schedule 5 dk okuma
Django'da {p}Çoklu Dil Desteği{/p}: i18n, Rosetta ve django-parler Tam Rehberi
analytics

Insight Density

groups Hedef Kitle: Deneyimli
65 Score

Teknik karmaşıklık ve içerik yoğunluğuna göre hesaplandı.

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:

django-parler ile çok dilli model yapısı diyagramı

$ 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.

Django Rosetta çeviri arayüzü — istatistik ekranı Django Rosetta çeviri düzenleme ve msgstr girişi

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
gettext (.po/.mo dosyaları) statik UI metinleri için kullanılır: buton etiketleri, form placeholder'ları, hata mesajları gibi kod içinde sabit yazılan metinler. django-parler ise veritabanında saklanan dinamik içerikler (blog başlığı, ürün açıklaması, slug) için ayrı çeviri tabloları oluşturur. Gerçek projelerde her ikisi birlikte kullanılır.
Yeni bir dil eklemek için ne yapılmalı? expand_more
1) settings.py LANGUAGES listesine yeni dil ekle, 2) PARLER_LANGUAGES'a ekle, 3) python manage.py makemessages -l [kod] çalıştır, 4) .po dosyasını çevir, 5) compilemessages ile derle. Admin panelinde TranslatableModel'lar için yeni dil sekmesi otomatik görünür.
prefix_default_language=False ne işe yarar? expand_more
Bu ayar, varsayılan dilin URL'de /tr/ öneki olmadan erişilebilmesini sağlar. Yani / adresi Türkçeye, /en/ adresi İngilizceye yönlendirir. SEO açısından ana domain Türkçe olduğunda tercih edilir; hreflang etiketleriyle birlikte kullanılmalıdır.
hreflang etiketi neden gerekli? expand_more
Google, hreflang olmadan çok dilli sayfaları birbirinin kopyası (duplicate content) olarak algılayabilir ve sıralamayı düşürebilir. hreflang ile Google'a 'bu sayfa /tr/ için, şu sayfa /en/ için' diyorsunuz. Ayrıca arama sonuçlarında kullanıcının diline uygun sayfa gösterilir — bu CTR'yi artırır.
RTL (sağdan sola) dil desteği nasıl eklenir? expand_more
Arapça, Farsça gibi RTL diller için HTML etiketine dir='rtl' ve lang='ar' eklenir. Django'da aktif dilin RTL olup olmadığını kontrol etmek için: {% load i18n %}{% get_current_language_bidi as LANGUAGE_BIDI %} — True ise RTL. CSS'de dir özelliğini kullanarak layout otomatik yansıtılabilir.
Parler slug çakışması sorunu nasıl çözülür? expand_more
Her dilde slug unique olmalıdır. Aynı içeriğin farklı dillerde farklı slugları olabilir. TranslatedFields içinde slug=models.SlugField(unique=True) ile her dil için benzersizlik sağlanır. İki farklı makalenin aynı İngilizce slugu almasını önlemek için save() metodunda slug kontrolü yapın veya clean() metoduna ValidationError ekleyin.
Migration sırasında mevcut modeli TranslatableModel'a dönüştürebilir miyim? expand_more
Evet, ama dikkatli bir migration süreci gerektirir. 1) Model'e TranslatableModel ekleyin, 2) Mevcut alanları TranslatedFields'a taşıyın, 3) Veri migration yazarak mevcut verileri yeni çeviri tablolarına kopyalayın. Üretim veritabanında önce test ortamında deneyin ve mutlaka yedek alın.
PARLER_LANGUAGES'da fallback ayarı ne işe yarar? expand_more
'fallback': 'tr' ayarı, bir içerik belirli bir dile çevrilmemişse hangi dile düşüleceğini belirler. hide_untranslated: False ise çevrilmemiş içerik fallback dilde gösterilir; True ise liste sayfalarından gizlenir. Blog gibi içeriklerde False daha kullanışlıdır — çevrilmemiş makale de görünsün ama 'çeviri eksik' uyarısı eklenebilir.
Etiketler: #Django #i18n #django-parler #Rosetta #Lokalizasyon #Çok Dilli #hreflang #SEO
share

Bu Makaleyi Paylaş

Bilgiyi ağınızla paylaşarak bize destek olun.

AK

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.

psychology
psychology

Makale Hakkında Soru Sorun

AnomixAI · Makale içeriğine dayalı yanıtlar

5 soru hakkı
Yalnızca makale içeriği hakkında 0/500
forward_to_inbox

Geleceği Çözümleyin.

Enterprise yapay zeka, yazılım mimarisi ve dijital dönüşüm üzerine aylık brifingi alan 5.000+ mühendis ve kurucuya katılın. Spam yok.