Bloga dön

Django Çevirileri Neden Bozulur (ve En Yaygın 10 Nedenin Çözümü)

2026-02-04 9 dakikalık okuma
Django Çevirileri Neden Bozulur (ve En Yaygın 10 Nedenin Çözümü)

Çeviri için dizeleri işaretlediniz, .po dosyaları oluşturdunuz, compilemessages komutunu çalıştırdınız ve uygulamanız hâlâ İngilizce gösteriyor. Yalnız değilsiniz. Django'nun i18n çerçevesi güçlüdür, ancak deneyimli geliştiricileri bile yakalayan keskin köşeleri vardır.

Bu kılavuz, Django çevirilerinin sessizce başarısız olmasının en yaygın 10 nedenini, her biri için kesin belirtileri ve çözümleri ile birlikte ele alır.

1. .po Dosyalarını Düzenledikten Sonra compilemessages Çalıştırmayı Unutmak

Bir .po dosyasını düzenlediniz (elle veya bir araçla), ancak çevrilmiş metin hiçbir zaman görünmüyor. Uygulama orijinal İngilizce dizeleri göstermeye devam ediyor.

Django çalışma zamanında .po dosyalarını okumaz. Bunun yerine derlenmiş .mo (machine object) ikili dosyalarını okur. Bir .po dosyasını yeniden derlemeden düzenlerseniz, Django hiçbir şeyin değiştiğinden habersizdir.

Her .po dosya değişikliğinden sonra compilemessages çalıştırın:

python manage.py compilemessages

Çevirilerinizi TranslateBot ile otomatikleştiriyorsanız, iş akışınızın son adımı olarak compilemessages ekleyin:

python manage.py makemessages -a --no-obsolete
python manage.py translate
python manage.py compilemessages

2. Şablonlarda {% load i18n %} Eksik

Bir şablonda {% trans "Hello" %} kullanıyorsunuz, ancak Django bir TemplateSyntaxError hatası veriyor. Ya da daha kötüsü, yanlış yapılandırılmış bir şablon motorunuz varsa etiket sessizce hiçbir şey yapmıyor.

{% trans %} ve {% blocktrans %} etiketleri Django'nun i18n şablon etiket kütüphanesinde bulunur. Yüklemeden şablon motoru bunları tanımaz.

Çeviri etiketleri kullanan her şablonun başına {% load i18n %} ekleyin:

{% load i18n %}

<h1>{% trans "Welcome to our site" %}</h1>
<p>{% blocktrans with name=user.name %}Hello, {{ name }}!{% endblocktrans %}</p>

Bu, şablon başına bir gerekliliktir. Üst şablon i18n yüklese bile, çeviri etiketleri kullanan alt şablonların kendi {% load i18n %} bildirimine ihtiyacı vardır.

3. LocaleMiddleware MIDDLEWARE'de Yok veya Yanlış Konumda

Django, tarayıcının Accept-Language başlığından, URL önekinden veya oturum ayarlarından bağımsız olarak her zaman varsayılan dilde içerik sunar.

LocaleMiddleware, her istek için etkin dili belirler. Onsuz, Django varsayılan olarak LANGUAGE_CODE kullanır ve tüm dil seçim mekanizmalarını yok sayar. Ara yazılım yığınındaki konumu da önemlidir, çünkü oturum verilerine ve URL çözümlemesine erişmesi gerekir.

LocaleMiddleware'i MIDDLEWARE ayarınıza, SessionMiddleware ve CommonMiddleware'den sonra ekleyin:

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.locale.LocaleMiddleware",  # Must be after SessionMiddleware
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
]

URL tabanlı dil değiştirme kullanıyorsanız, URL yapılandırmanıza django.conf.urls.i18n dahil edildiğinden de emin olun:

from django.conf.urls.i18n import i18n_patterns

urlpatterns = i18n_patterns(
    path("", include("myapp.urls")),
)

4. Dil Kodu Uyuşmazlıkları (ör. pt-br vs pt_BR)

Çeviriler .po dosyalarınızda mevcut, compilemessages başarılı oluyor, ancak Django belirli yerel ayarlar için çeviriyi yok sayıyor.

Django, yerel ayar dizinlerinin <language>_<COUNTRY> formatını alt çizgi ayırıcı ve büyük harf ülke koduyla takip etmesini bekler. Örneğin, Brezilya Portekizcesi için pt_BR. Dizininiz pt-br, pt-BR veya ptBR olarak adlandırılmışsa, Django onu bulamaz. Aynı durum LANGUAGES ayarı için de geçerlidir: oradaki kodlar tire kullanır (pt-br), ancak dosya sistemi alt çizgi kullanır (pt_BR).

Dizin yapınızın Django'nun beklentileriyle eşleştiğinden emin olun:

locale/
    pt_BR/
        LC_MESSAGES/
            django.po
            django.mo

Ve ayarlarınızda tireli formu kullanın:

LANGUAGES = [
    ("en", "English"),
    ("pt-br", "Brazilian Portuguese"),
    ("zh-hans", "Simplified Chinese"),
]

makemessages çalıştırırken, yerel ayar bayrağı için alt çizgili formu kullanın:

python manage.py makemessages -l pt_BR

5. Derleme Sırasında Sessizce Atlanan Belirsiz (Fuzzy) Girişler

.po dosyasında bir çeviri var, ancak Django belirli bir giriş için çalışma zamanında orijinal İngilizce dizeyi gösteriyor. Bu durum özellikle sinir bozucudur çünkü çeviri tam orada dosyanın içindedir.

Django'nun makemessages komutu kaynak dizesinin biraz değiştiğini algıladığında, mevcut çeviriyi "fuzzy" (yani insan incelemesi gerektiren bir tahmin) olarak işaretler. compilemessages komutu tüm fuzzy girişleri atlar ve onları çevrilmemiş olarak değerlendirir. Yani giriş .po dosyasında çevrilmiş görünür, ancak .mo dosyası onu tamamen dışlar.

Bir fuzzy giriş şöyle görünür:

#, fuzzy
msgid "Welcome to our website!"
msgstr "Welkom op onze website!"

Çeviriyi gözden geçirin, gerekirse msgstr'yi güncelleyin, ardından #, fuzzy bayrağını kaldırın:

msgid "Welcome to our website!"
msgstr "Welkom op onze website!"

Ardından yeniden derleyin:

python manage.py compilemessages

Daha büyük bir projede fuzzy girişler birikir ve gözden kaçırılması kolaydır. TranslateBot'un check_translations komutu bunları otomatik olarak yakalar:

python manage.py check_translations
locale/nl/LC_MESSAGES/django.po: 0 untranslated, 3 fuzzy
CommandError: Translation check failed

CI hattınıza check_translations --makemessages ekleyin ve bir daha asla fuzzy giriş göndermezsiniz.

6. LOCALE_PATHS Yapılandırılmamış veya Yanlış Dizine İşaret Ediyor

makemessages .po dosyalarını bir konumda oluşturur, ancak Django onları başka bir yerde arar. Çeviriler diskte mevcuttur ancak hiçbir zaman yüklenmez.

Django, çeviri dosyalarını belirli bir sırayla arar: önce LOCALE_PATHS dizinleri, sonra her uygulamanın locale/ dizini ve son olarak projenin locale/ dizini. LOCALE_PATHS ayarlanmamışsa veya yanlış yola işaret ediyorsa, Django .po dosyalarınızı hiçbir zaman bulamayabilir.

Ayarlarınızda LOCALE_PATHS'i mutlak bir yol olarak belirleyin:

from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

LOCALE_PATHS = [
    BASE_DIR / "locale",
]

Dizinin var olduğunu ve beklenen yapıyı içerdiğini doğrulayın:

locale/
    de/
        LC_MESSAGES/
            django.po
            django.mo
    nl/
        LC_MESSAGES/
            django.po
            django.mo

Yaygın bir hata, LOCALE_PATHS'i mutlak bir yol yerine locale/ (göreli) olarak ayarlamaktır. Django, göreli yolları proje kök dizininizden çözmez. İşlemin çalışma dizinine bağlıdır ve bu genellikle beklediğiniz gibi değildir.

7. Önbellek Eski Çevirileri Sunuyor

Çevirileri güncellediniz ve derlediniz, ancak eski metin görünmeye devam ediyor. Sunucuyu yeniden başlatmak sorunu çözüyor.

Django'nun çeviri kataloğu işlem başına bir kez yüklenir. Üretimde, Gunicorn veya Uvicorn gibi WSGI/ASGI sunucuları çalışan süreçleri uzun süreler boyunca canlı tutar. .mo dosyası diskte değişmiş olabilir, ancak çalışan süreç hâlâ bellekte eski çevirilere sahiptir. Bunun üstüne, Django'nun önbellek çerçevesini veya Nginx ya da Cloudflare gibi bir ters proxy kullanıyorsanız, önbelleğe alınmış yanıtlar süreleri dolana kadar eski içerik sunacaktır.

Yeni çevirileri dağıttıktan sonra uygulama sunucunuzu yeniden başlatın:

# Gunicorn
kill -HUP $(cat /tmp/gunicorn.pid)

# Systemd
sudo systemctl restart myapp

# Docker
docker compose restart web

Django'nun önbellek çerçevesi için, çevirileri güncelledikten sonra önbelleği temizleyin:

from django.core.cache import cache
cache.clear()

Geliştirme ortamında, runserver Python dosyaları değiştiğinde otomatik olarak yeniden yüklenir ancak .mo dosyalarını izlemez. compilemessages çalıştırdıktan sonra elle yeniden başlatmanız gerekir.

8. gettext (_() veya {% trans %}) ile Sarılmamış Dizeler

makemessages belirli dizeleri çıkarmaz, bu yüzden bunlar .po dosyalarınızda hiçbir zaman görünmez ve hiçbir zaman çevrilmez. Bu en temel sorundur ve aynı zamanda büyük bir kod tabanında gözden kaçırılması en kolay olandır.

Django'nun makemessages komutu, kaynak kodunuzu çeviri işaretleyicileri için taramak üzere xgettext kullanır. Bir dize gettext() (genellikle _() olarak takma adlandırılır), gettext_lazy(), {% trans %} veya {% blocktrans %} ile sarılmamışsa, çıkarma işlemi için görünmezdir.

Kullanıcıya yönelik her dizeyi sarın:

# Python code
from django.utils.translation import gettext_lazy as _

class Article(models.Model):
    class Meta:
        verbose_name = _("article")
        verbose_name_plural = _("articles")

# Views
from django.utils.translation import gettext as _

def my_view(request):
    message = _("Your changes have been saved.")
    return HttpResponse(message)
<!-- Templates -->
{% load i18n %}
<h1>{% trans "Welcome" %}</h1>
<p>{% blocktrans with count=items|length %}You have {{ count }} items.{% endblocktrans %}</p>

Çıkarma sırasında kaçırılan dizeleri yakalamak için şu anda çevrilmemiş olan dizeleri önizlemek üzere TranslateBot'un --dry-run bayrağını kullanın:

python manage.py translate --target-lang de --dry-run

Bu, herhangi bir API çağrısı veya değişiklik yapmadan .po dosyalarınızdaki tüm çevrilmemiş girişleri gösterir.

9. f-string'ler Çevrilemez (Django Sınırlaması)

Bir f-string'i _() ile sarıyorsunuz ve ya bir sözdizimi hatası alıyorsunuz ya da makemessages çevrilemeyen bozuk/kısmi bir dize çıkarıyor.

Python f-string'leri çalışma zamanında değerlendirilir. xgettext çıkarma aracı kaynak kodu statik olarak ayrıştırır, bu yüzden {} parantezlerinin içindeki Python ifadelerini değerlendiremez. Bu, _(f"Hello, {name}") ifadesinin literal bir {name} ifadesi içeren bir dize olarak çıkarılması (veya tamamen çıkarılamaması) anlamına gelir ve sonuçta oluşan .po girişi çalışma zamanı dizesiyle hiçbir zaman eşleşmez.

Bunun yerine Django'nun % biçimlendirmesini veya adlandırılmış yer tutucularla .format() kullanın:

# Wrong -- f-string cannot be extracted
message = _(f"Hello, {user.name}! You have {count} new messages.")

# Correct -- named placeholders
message = _("Hello, %(name)s! You have %(count)d new messages.") % {
    "name": user.name,
    "count": count,
}

# Also correct -- .format() with positional args
message = _("Hello, {0}! You have {1} new messages.").format(user.name, count)

Bu bir TranslateBot veya araç sınırlaması değildir. gettext'in çalışma şekline özgü temel bir durumdur. Kaynak dize, çıkarılabilmesi ve çalışma zamanında aranabilmesi için statik bir literal olmalıdır.

TranslateBot, tüm bu yer tutucu biçimlerini (%(name)s, {0}, %s, HTML etiketleri) çeviri sırasında korur, böylece çevrilmiş dizeler tamamen işlevsel kalır.

10. Yer Tutucu Biçim Dizesi Hataları .po Derlemesini Bozuyor

compilemessages bir hatayla başarısız oluyor veya .po dosyasında bir #, python-format bayrak uyuşmazlığı var ve giriş sessizce düşürülüyor.

Bir kaynak dize %(name)s gibi Python biçim yer tutucuları içerdiğinde, Django .po girişini #, python-format ile işaretler. Çeviride farklı yer tutucular varsa (%(nome)s gibi bir yazım hatası, eksik bir yer tutucu veya fazladan bir yer tutucu) gettext araçları girişi reddedebilir veya compilemessages başarısız olabilir. Bu genellikle elle yapılan çevirilerde veya yer tutucu semantiğini anlamayan yapay zeka çeviri araçlarında olur.

Bozuk bir giriş şöyle görünür:

#, python-format
msgid "Hello, %(name)s! You have %(count)d new messages."
msgstr "Hallo, %(naam)s! Je hebt %(count)d nieuwe berichten."

Burada %(naam)s aslında %(name)s olmalıdır. Yer tutucular kaynakla tam olarak eşleşmelidir.

Çevrilmiş dizelerin kaynakla tam olarak aynı yer tutucuları içerdiğinden emin olun. Yazım hatalarını, eksik yer tutucuları ve fazladan yer tutucuları kontrol edin.

Bu, TranslateBot'un gerçek bir avantaj sağladığı alanlardan biridir. Yer tutucu koruma mantığı, çevrilmiş çıktıdaki tüm biçim dizelerinin (%(name)s, {0}, %s) kaynakla tam olarak eşleşmesini sağlar. Yer tutucu işleme %100 test kapsamıyla kapsanmaktadır, bu nedenle çeviriden kaynaklanan biçim dizesi hataları derleme zamanında yakalanmak yerine araç düzeyinde ortadan kaldırılır.

Elle çeviri yapıyorsanız veya yer tutucuları işlemeyen bir araç kullanıyorsanız, .po dosyalarınızı şununla doğrulayın:

msgfmt --check-format locale/de/LC_MESSAGES/django.po

Bu, gettext'in biçim dizesi doğrulamasını çalıştırır ve uyuşmazlıkları bildirir.

Hepsini Bir Araya Getirmek: Savunmacı Bir İş Akışı

Bu sorunların çoğu ortak bir temel nedeni paylaşır: unutulması kolay elle yapılan adımlar. İşte 10 sorunu da önleyen bir iş akışı:

# 1. Extract strings (catches #8 -- any new gettext-wrapped strings)
python manage.py makemessages -a --no-obsolete

# 2. Translate (catches #1, #5, #8, #9, #10 -- handles untranslated,
#    fuzzy, and placeholder issues automatically)
python manage.py translate

# 3. Compile (catches #1 -- generates .mo files)
python manage.py compilemessages

# 4. Verify in CI (catches everything that slipped through)
python manage.py check_translations --makemessages
  1. adımı CI hattınıza ekleyin ve çevrilmemiş dizeler, fuzzy girişler ve biçim hataları üretime ulaşmadan önce derlemeyi başarısız kılacaktır.

Hızlı Başvuru Tablosu

Neden Belirti Tek Satırlık Çözüm
compilemessages yok Çeviriler var ama görünmüyor python manage.py compilemessages
{% load i18n %} eksik {% trans %} üzerinde TemplateSyntaxError Şablona {% load i18n %} ekleyin
LocaleMiddleware eksik Dil her zaman İngilizce olarak varsayılan MIDDLEWARE'e django.middleware.locale.LocaleMiddleware ekleyin
Dil kodu uyuşmazlığı Yerel ayar dizini bulunamadı Dizinler için pt_BR (alt çizgi), ayarlar için pt-br (tire) kullanın
Fuzzy girişler atlandı Çeviri .po'da var ama uygulamada yok İnceledikten sonra #, fuzzy bayrağını kaldırın
Yanlış LOCALE_PATHS .po dosyaları var ama Django onları yok sayıyor LOCALE_PATHS'i mutlak bir yol olarak ayarlayın
Önbelleğe alınmış çeviriler Güncellemeden sonra eski metin görünüyor Uygulama sunucusunu yeniden başlatın
Dize gettext'te değil Dize .po dosyalarında eksik _() veya {% trans %} ile sarın
gettext'te f-string Bozuk çıkarma veya çalışma zamanı uyuşmazlığı % veya .format() yer tutucularıyla değiştirin
Yer tutucu uyuşmazlığı compilemessages başarısız veya giriş düşürüldü Kaynak ve çeviri arasında yer tutucuları tam olarak eşleştirin

Bu sorunların çoğu, çeviri adımını otomatikleştirdiğinizde ve CI'da kontroller uyguladığınızda ortadan kalkar. TranslateBot'un translate komutu yer tutucu koruma ve artımlı çeviriyi yönetirken, check_translations üretime ulaşmadan önce açıktan düşen her şeyi (çevrilmemiş girişler, fuzzy bayraklar ve biçim dizesi sorunları) yakalar.

.po dosyalarını manuel düzenlemeyi bırakın

TranslateBot, Django çevirilerini yapay zeka ile otomatikleştirir. Tek komut, tüm dilleriniz, çeviri başına kuruşlar.