ब्लॉगवर परत जा

Django भाषांतरे का तुटतात (आणि 10 सर्वात सामान्य कारणे कशी दुरुस्त करावीत)

2026-02-04 9 मिनिट वाचन
Django भाषांतरे का तुटतात (आणि 10 सर्वात सामान्य कारणे कशी दुरुस्त करावीत)

तुम्ही भाषांतरासाठी स्ट्रिंग्स चिन्हांकित केल्या, .po फाइल्स तयार केल्या, compilemessages चालवला, आणि तुमची अॅप अजूनही इंग्रजी दाखवत आहे. तुम्ही एकटे नाही. Django चे i18n फ्रेमवर्क शक्तिशाली आहे, पण त्यात अशा तीक्ष्ण कडा आहेत ज्या अनुभवी डेव्हलपर्सनाही अडकवतात.

हे मार्गदर्शक Django भाषांतरे शांतपणे अयशस्वी होण्याच्या 10 सर्वात सामान्य कारणांचे वर्णन करते, प्रत्येकासाठी अचूक लक्षणे आणि उपाय.

1. .po फाइल्स संपादित केल्यानंतर compilemessages चालवायला विसरणे

तुम्ही एक .po फाइल संपादित केली (हाताने किंवा साधनाने), पण भाषांतरित मजकूर कधीच दिसत नाही. अॅप मूळ इंग्रजी स्ट्रिंग्स दाखवत राहते.

Django रनटाइमला .po फाइल्स वाचत नाही. ते संकलित .mo (मशीन ऑब्जेक्ट) बायनरी फाइल्स वाचते. जर तुम्ही .po फाइल पुन्हा संकलित न करता संपादित केली, तर Django ला काहीही बदलल्याची कल्पना नाही.

प्रत्येक .po फाइल बदलानंतर compilemessages चालवा:

python manage.py compilemessages

जर तुम्ही TranslateBot ने तुमची भाषांतरे स्वयंचलित करता, तर तुमच्या कार्यप्रवाहाच्या शेवटच्या टप्प्यात compilemessages जोडा:

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

2. टेम्पलेट्समध्ये {% load i18n %} गहाळ

तुम्ही टेम्पलेटमध्ये {% trans "Hello" %} वापरता, पण Django TemplateSyntaxError फेकते. किंवा अजून वाईट, तुमचे टेम्पलेट इंजिन चुकीच्या पद्धतीने कॉन्फिगर केले असल्यास टॅग शांतपणे काहीही करत नाही.

{% trans %} आणि {% blocktrans %} टॅग्स Django च्या i18n टेम्पलेट टॅग लायब्ररीमध्ये आहेत. ती लोड केल्याशिवाय, टेम्पलेट इंजिन त्यांना ओळखत नाही.

भाषांतर टॅग्स वापरणाऱ्या प्रत्येक टेम्पलेटच्या शीर्षस्थानी {% load i18n %} जोडा:

{% load i18n %}

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

ही प्रति-टेम्पलेट आवश्यकता आहे. पॅरेंट टेम्पलेट i18n लोड करत असले तरी, भाषांतर टॅग्स वापरणाऱ्या चाइल्ड टेम्पलेट्सना स्वतःची {% load i18n %} घोषणा आवश्यक आहे.

3. LocaleMiddleware MIDDLEWARE मध्ये नाही किंवा चुकीच्या स्थानावर आहे

ब्राउझरच्या Accept-Language हेडर, URL उपसर्ग, किंवा सत्र सेटिंग्जकडे दुर्लक्ष करून Django नेहमी डीफॉल्ट भाषेत सामग्री देते.

LocaleMiddleware प्रत्येक विनंतीसाठी सक्रिय भाषा निर्धारित करते. त्याशिवाय, Django LANGUAGE_CODE वर डीफॉल्ट होते आणि सर्व भाषा-निवड यंत्रणा दुर्लक्षित करते. मिडलवेअर स्टॅकमधील त्याचे स्थान देखील महत्त्वाचे आहे, कारण त्याला सत्र डेटा आणि URL रिझोल्यूशनमध्ये प्रवेश आवश्यक आहे.

SessionMiddleware आणि CommonMiddleware नंतर तुमच्या MIDDLEWARE सेटिंगमध्ये LocaleMiddleware जोडा:

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-आधारित भाषा स्विचिंग वापरत असल्यास तुमच्या URL कॉन्फिगरेशनमध्ये django.conf.urls.i18n समाविष्ट आहे याची खात्री करा:

from django.conf.urls.i18n import i18n_patterns

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

4. भाषा कोड जुळत नाहीत (उदा. pt-br विरुद्ध pt_BR)

भाषांतरे तुमच्या .po फाइल्समध्ये आहेत, compilemessages यशस्वी होतो, पण Django काही लोकेल्ससाठी भाषांतर दुर्लक्षित करतो.

Django अपेक्षा करतो की लोकेल डिरेक्टरीज <language>_<COUNTRY> स्वरूपाचे अनुसरण करतील, अंडरस्कोर विभाजक आणि अपरकेस देश कोडसह. उदाहरणार्थ, ब्राझिलियन पोर्तुगीजसाठी pt_BR. तुमच्या डिरेक्टरीचे नाव pt-br, pt-BR, किंवा ptBR असल्यास, Django ती शोधणार नाही. LANGUAGES सेटिंगलाही हेच लागू होते: तिथले कोड हायफन (pt-br) वापरतात, पण फाइलसिस्टम अंडरस्कोर (pt_BR) वापरतो.

तुमची डिरेक्टरी रचना Django च्या अपेक्षांशी जुळत असल्याची खात्री करा:

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

आणि तुमच्या सेटिंग्जमध्ये, हायफनयुक्त स्वरूप वापरा:

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

makemessages चालवताना, लोकेल फ्लॅगसाठी अंडरस्कोर स्वरूप वापरा:

python manage.py makemessages -l pt_BR

5. संकलनादरम्यान Fuzzy एन्ट्रीज शांतपणे वगळल्या जातात

.po फाइलमध्ये भाषांतर आहे, पण Django त्या विशिष्ट एन्ट्रीसाठी रनटाइमला मूळ इंग्रजी स्ट्रिंग दाखवतो. हे विशेषतः निराशाजनक आहे कारण भाषांतर फाइलमध्येच आहे.

जेव्हा Django च्या makemessages ला आढळते की स्रोत स्ट्रिंग थोडी बदलली आहे, तेव्हा ते विद्यमान भाषांतरला "fuzzy" (म्हणजे हा एक अंदाज आहे ज्याला मानवी पुनरावलोकन आवश्यक आहे) म्हणून चिन्हांकित करते. compilemessages कमांड सर्व fuzzy एन्ट्रीज वगळतो, त्यांना अभाषांतरित मानतो. त्यामुळे एन्ट्री .po फाइलमध्ये भाषांतरित दिसते, पण .mo फाइल ती पूर्णपणे वगळते.

fuzzy एन्ट्री अशी दिसते:

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

भाषांतराचे पुनरावलोकन करा, आवश्यक असल्यास msgstr अद्यतनित करा, नंतर #, fuzzy फ्लॅग काढा:

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

नंतर पुन्हा संकलित करा:

python manage.py compilemessages

मोठ्या प्रकल्पात, fuzzy एन्ट्रीज जमा होतात आणि चुकवणे सोपे असते. TranslateBot चा check_translations कमांड आपोआप त्या पकडतो:

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

check_translations --makemessages सह तुमच्या CI पाइपलाइनमध्ये जोडा आणि तुम्ही पुन्हा कधीही fuzzy एन्ट्री शिप करणार नाही.

6. LOCALE_PATHS कॉन्फिगर केलेले नाही किंवा चुकीच्या डिरेक्टरीकडे निर्देश करते

makemessages एका ठिकाणी .po फाइल्स तयार करतो, पण Django त्यांना दुसऱ्या ठिकाणी शोधतो. भाषांतरे डिस्कवर आहेत पण कधी लोड होत नाहीत.

Django विशिष्ट क्रमाने भाषांतर फाइल्स शोधतो: प्रथम LOCALE_PATHS डिरेक्टरीज, नंतर प्रत्येक अॅपची locale/ डिरेक्टरी, आणि शेवटी प्रकल्पाची locale/ डिरेक्टरी. LOCALE_PATHS सेट नसल्यास किंवा चुकीच्या मार्गाकडे निर्देश करत असल्यास, Django तुमच्या .po फाइल्स कधीही शोधू शकणार नाही.

तुमच्या सेटिंग्जमध्ये LOCALE_PATHS परिपूर्ण मार्गावर सेट करा:

from pathlib import Path

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

LOCALE_PATHS = [
    BASE_DIR / "locale",
]

डिरेक्टरी अस्तित्वात आहे आणि अपेक्षित रचना आहे हे सत्यापित करा:

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

एक सामान्य चूक म्हणजे LOCALE_PATHS ला परिपूर्ण मार्गाऐवजी locale/ (सापेक्ष) सेट करणे. Django तुमच्या प्रकल्प रूटवरून सापेक्ष मार्ग सोडवत नाही. ते प्रक्रियेच्या कार्यरत डिरेक्टरीवर अवलंबून असते, जी बऱ्याचदा तुमच्या अपेक्षेप्रमाणे नसते.

7. कॅशे जुनी भाषांतरे देत आहे

तुम्ही भाषांतरे अद्यतनित आणि संकलित केली, पण जुना मजकूर दिसत राहतो. सर्व्हर पुन्हा सुरू केल्यावर ते ठीक होते.

Django चा भाषांतर कॅटलॉग प्रति प्रक्रिया एकदा लोड होतो. उत्पादनात, Gunicorn किंवा Uvicorn सारखे WSGI/ASGI सर्व्हर कामगार प्रक्रिया दीर्घ काळासाठी जिवंत ठेवतात. .mo फाइल डिस्कवर बदलली असू शकते, पण चालू प्रक्रियेत अजूनही स्मृतीत जुनी भाषांतरे आहेत. शिवाय, तुम्ही Django चे कॅशे फ्रेमवर्क किंवा Nginx किंवा Cloudflare सारखा रिव्हर्स प्रॉक्सी वापरत असल्यास, कॅशे केलेले प्रतिसाद कालबाह्य होईपर्यंत जुनी सामग्री देतील.

नवीन भाषांतरे तैनात केल्यानंतर तुमचा अनुप्रयोग सर्व्हर पुन्हा सुरू करा:

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

# Systemd
sudo systemctl restart myapp

# Docker
docker compose restart web

Django च्या कॅशे फ्रेमवर्कसाठी, भाषांतरे अद्यतनित केल्यानंतर कॅशे साफ करा:

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

विकासात, runserver Python फाइल्स बदलल्यावर स्वयंचलित पुन्हा लोड होतो पण .mo फाइल्स पहात नाही. compilemessages चालवल्यानंतर तुम्हाला ते हाताने पुन्हा सुरू करावे लागेल.

8. स्ट्रिंग्स gettext (_() किंवा {% trans %}) मध्ये गुंडाळलेले नाहीत

makemessages काही स्ट्रिंग्स काढत नाही, म्हणून ते कधीच तुमच्या .po फाइल्समध्ये दिसत नाहीत आणि कधीच भाषांतरित होत नाहीत. ही सर्वात मूलभूत समस्या आहे आणि मोठ्या कोडबेसमध्ये सर्वात सहजपणे दुर्लक्षित होणारी देखील.

Django चा makemessages कमांड भाषांतर चिन्हकांसाठी तुमचा स्रोत कोड स्कॅन करण्यासाठी xgettext वापरतो. स्ट्रिंग gettext() (सामान्यतः _() म्हणून उपनामित), gettext_lazy(), {% trans %}, किंवा {% blocktrans %} मध्ये गुंडाळले नसल्यास, ते निष्कर्षण प्रक्रियेला अदृश्य असते.

प्रत्येक वापरकर्त्याला दिसणारी स्ट्रिंग गुंडाळा:

# 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>

सध्या अभाषांतरित स्ट्रिंग्सचे पूर्वावलोकन करण्यासाठी TranslateBot चा --dry-run फ्लॅग वापरा, जेणेकरून निष्कर्षणादरम्यान चुकलेल्या स्ट्रिंग्स पकडता येतील:

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

हे कोणतेही API कॉल्स किंवा बदल न करता तुमच्या .po फाइल्समधील सर्व अभाषांतरित एन्ट्रीज दाखवते.

9. f-string भाषांतरित करता येत नाही (Django मर्यादा)

तुम्ही _() मध्ये f-string गुंडाळता आणि एकतर सिंटॅक्स एरर मिळतो, किंवा makemessages तुटलेली/अपूर्ण स्ट्रिंग काढतो जी भाषांतरित करता येत नाही.

Python f-string रनटाइमला मूल्यांकित होतात. xgettext निष्कर्षण साधन स्रोत कोड स्थिरपणे पार्स करतो, त्यामुळे {} कंसातील Python अभिव्यक्ती मूल्यांकित करू शकत नाही. याचा अर्थ _(f"Hello, {name}") शब्दशः {name} अभिव्यक्ती असलेली स्ट्रिंग म्हणून काढली जाते (किंवा पूर्णपणे काढण्यात अयशस्वी), आणि परिणामी .po एन्ट्री कधीही रनटाइम स्ट्रिंगशी जुळणार नाही.

त्याऐवजी Django चे % स्वरूपन किंवा नामांकित प्लेसहोल्डर्ससह .format() वापरा:

# 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)

ही TranslateBot किंवा साधनाची मर्यादा नाही. gettext कसे कार्य करते याचा हा मूलभूत भाग आहे. स्रोत स्ट्रिंग स्थिर शाब्दिक असणे आवश्यक आहे जेणेकरून ती रनटाइमला काढता आणि शोधता येईल.

TranslateBot भाषांतरादरम्यान हे सर्व प्लेसहोल्डर स्वरूप (%(name)s, {0}, %s, HTML टॅग्स) जतन करतो, त्यामुळे भाषांतरित स्ट्रिंग्स पूर्णपणे कार्यक्षम राहतात.

10. प्लेसहोल्डर स्वरूप स्ट्रिंग एरर .po संकलन तोडत आहेत

compilemessages एरर सह अयशस्वी होतो, किंवा .po फाइलमध्ये #, python-format फ्लॅग जुळत नाही, आणि एन्ट्री शांतपणे वगळली जाते.

स्रोत स्ट्रिंगमध्ये %(name)s सारखे Python स्वरूप प्लेसहोल्डर्स असतात तेव्हा, Django .po एन्ट्रीला #, python-format ने चिन्हांकित करतो. भाषांतरात वेगळे प्लेसहोल्डर्स असल्यास (%(nome)s सारखी टायपो, गहाळ प्लेसहोल्डर, किंवा अतिरिक्त) gettext साधने एन्ट्री नाकारू शकतात किंवा compilemessages अयशस्वी होऊ शकतो. हे सामान्यतः मॅन्युअल भाषांतरांसह किंवा प्लेसहोल्डर अर्थशास्त्र न समजणाऱ्या AI भाषांतर साधनांसह होते.

तुटलेली एन्ट्री अशी दिसते:

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

येथे %(naam)s हे %(name)s असावे. प्लेसहोल्डर्स स्रोताशी अचूक जुळले पाहिजेत.

भाषांतरित स्ट्रिंग्समध्ये स्रोतासारखे अचूक प्लेसहोल्डर्स आहेत याची खात्री करा. टायपो, गहाळ प्लेसहोल्डर्स, आणि अतिरिक्त प्लेसहोल्डर्स तपासा.

हे असे क्षेत्र आहे जिथे TranslateBot खरा फायदा देतो. त्याचे प्लेसहोल्डर संरक्षण तर्क सुनिश्चित करतो की भाषांतरित आउटपुटमधील सर्व स्वरूप स्ट्रिंग्स (%(name)s, {0}, %s) स्रोताशी अचूक जुळतात. प्लेसहोल्डर हाताळणी 100% चाचणी कव्हरेजने संरक्षित आहे, त्यामुळे भाषांतरातून स्वरूप स्ट्रिंग एरर संकलन वेळी पकडले जाण्याऐवजी साधन स्तरावरच दूर केले जातात.

तुम्ही हाताने भाषांतर करत असल्यास किंवा प्लेसहोल्डर्स हाताळत नसलेल्या साधनाने, तुमच्या .po फाइल्स याने प्रमाणित करा:

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

हे gettext चे स्वरूप स्ट्रिंग प्रमाणीकरण चालवतो आणि कोणत्याही विसंगतीची नोंद करतो.

सर्व एकत्र आणणे: एक संरक्षणात्मक कार्यप्रवाह

यातील बहुतेक समस्या एक सामान्य मूळ कारण सामायिक करतात: विसरणे सोपे असलेले मॅन्युअल टप्पे. हा एक कार्यप्रवाह आहे जो सर्व 10 समस्या प्रतिबंधित करतो:

# 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

टप्पा 4 तुमच्या CI पाइपलाइनमध्ये जोडा आणि अभाषांतरित स्ट्रिंग्स, fuzzy एन्ट्रीज, आणि स्वरूप एरर उत्पादनात पोहोचण्यापूर्वी बिल्ड अयशस्वी करतील.

द्रुत संदर्भ सारणी

कारण लक्षण एक-ओळ उपाय
compilemessages नाही भाषांतरे आहेत पण दिसत नाहीत python manage.py compilemessages
{% load i18n %} गहाळ {% trans %} वर TemplateSyntaxError टेम्पलेटमध्ये {% load i18n %} जोडा
LocaleMiddleware गहाळ भाषा नेहमी इंग्रजी डीफॉल्ट MIDDLEWARE मध्ये django.middleware.locale.LocaleMiddleware जोडा
भाषा कोड जुळत नाही लोकेल डिरेक्टरी सापडली नाही डिरेक्टरींसाठी pt_BR (अंडरस्कोर), सेटिंग्जसाठी pt-br (हायफन) वापरा
Fuzzy एन्ट्रीज वगळल्या .po मध्ये भाषांतर पण अॅपमध्ये नाही पुनरावलोकनानंतर #, fuzzy फ्लॅग काढा
चुकीचे LOCALE_PATHS .po फाइल्स आहेत पण Django दुर्लक्षित करतो LOCALE_PATHS परिपूर्ण मार्गावर सेट करा
कॅशे केलेली भाषांतरे अद्यतनानंतर जुना मजकूर दिसतो अनुप्रयोग सर्व्हर पुन्हा सुरू करा
स्ट्रिंग gettext मध्ये नाही .po फाइल्समध्ये स्ट्रिंग गहाळ _() किंवा {% trans %} मध्ये गुंडाळा
gettext मध्ये f-string तुटलेले निष्कर्षण किंवा रनटाइम विसंगती % किंवा .format() प्लेसहोल्डर्सने बदला
प्लेसहोल्डर जुळत नाहीत compilemessages अयशस्वी किंवा एन्ट्री वगळली स्रोत आणि भाषांतर दरम्यान प्लेसहोल्डर्स अचूक जुळवा

तुम्ही भाषांतर टप्पा स्वयंचलित केल्यावर आणि CI मध्ये तपासणी लागू केल्यावर यातील बहुतेक समस्या नाहीशा होतात. TranslateBot चा translate कमांड प्लेसहोल्डर संरक्षण आणि वाढीव भाषांतर हाताळतो, तर check_translations उत्पादनात पोहोचण्यापूर्वी सुटलेले सर्व काही (अभाषांतरित एन्ट्रीज, fuzzy फ्लॅग्स, आणि स्वरूप स्ट्रिंग समस्या) पकडतो.

.po फाइल्स मॅन्युअली संपादित करणे थांबवा

TranslateBot AI च्या सहाय्याने Django भाषांतर स्वयंचलित करते. एक कमांड, सर्व भाषा, प्रति भाषांतर नाममात्र खर्च.