oruji.github.io
oruji.github.ioPersian Tutorials
ویرایش: 1396/11/13 19:21
A A

آموزش بین المللی سازی (Internationalization) در جنگو (Django)

جنگو در ابتدا درست در ایالات متحده ی میانی توسعه یافت – در معنای واقعی کلمه، در لارنس، کنزاس، کمتر از 40 مایلی مرکز جغرافیای قاره ایالات متحده. همانند اغلب پروژه های منبع باز (open source)، جنگو در بین مردم سرتاسر زمین بزرگ شد. همانطور که جامعه جنگو به طور افزاینده ای متنوع می شدند، internationalization و localization به طور افزاینده ای دارای اهمیت شد. به دلیل آن که بسیاری از توسعه دهندگان درک مبهمی از این دوره ها دارند، به طور اختصار آنها را تعریف می کنیم.

internationalization به پردازش طراحی برنامه ها برای استفاده ی بالقوه از هر مکان رجوع می کند. این شامل علامت گذاری متن (از قبیل المان های UI و پیام های خطا) برای ترجمه ی آینده، abstract کردن نمایش تاریخ ها و زمان ها به طوری که استاندارهای مختلف محلی ممکن observed باشه، تهیه ی پشتیبانی برای منطقه های زمانی مختلف، و به طور کلی اطمینان از اینکه کد حاوی هیچ فرضی در باره ی محل آن کاربران نباشد. اغلب "internationalization" را به صورت اختصار I18N می بینید. ("18" به تعداد حروف حذف شده بین حرف اول "I" و حرف آخر "N" می باشد.)

localization به پردازش ترجمه ی واقعی یک برنامه ی internationalize شده برای استفاده در یک محل خاص رجوع می کند. گاهی اوقات "localization" به صورت اختصار L10N می بینید.

خود جنگو به طور کامل internationalize شده می باشد؛ تمام رشته ها برای ترجمه علامت گذاری شده اند، و تنظیمات نمایش مقادیر local-dependent مانند تاریخ ها و زمان ها را کنترل می کنند. جنگو همچنین دارای بیشتر از 50 فایل localization می باشد. در صورتی که زبان مادری شما انگلیسی نمی باشد، یک شانس خوب وجود دارد که جنگو قبلا به زبان اصلی شما ترجمه شده است.

فریم ورک همسان internationalization برای این localization ها برای شما جهت استفاده از کد و template های خودتان در دسترس می باشند.

جهت استفاده از این فریم ورک یا چارچوب، نیاز به اضافه کردن حداقل hook ها به کد پایتون و template های خود دارید. این hook ها رشته های ترجمه نام دارند. آن ها به جنگو می گویند، "این متن باید به زبان کاربر ترجمه شود، در صورتی که یک ترجمه برای این متن در آن زبان در دسترس باشد."

فریم ورک یا چارچوب جنگو (Django) مراقب استفاده از این hook ها برای ترجمه ی برنامه های وب می باشد، بسیار سریع، بر طبق تنظیمات زبان کاربر.

اساسا، جنگو دو کار را انجام می دهد:

سه مرحله برای internationalize کردن برنامه جنگو به قرار زیر می باشند:

  1. رشته های ترجمه را در کد پایتون خود را template قرار دهید.
  2. ترجمه هایی برای آن رشته های بدست آورید، در هر زبانی که برای پشتیبانی می خواهید.
  3. locale middleware را در تنظیمات جنگو خود فعال کنید.

هر کدام از این مراحل را به تفصیل پوشش خواهیم داد.

1. نحوه ی تعیین رشته های ترجمه

رشته های ترجمه "این متن باید ترجمه شده باشد" تعیین می کنند این رشته ها می توانند در کد پایتون و template های شما ظاهر شوند. علامت گذاری رشته های ترجمه بر عهده ی شما می باشد؛ سیستم تنها می تواند رشته هایی را که می شناسد ترجمه کند.

در کد پایتون

ترجمه استاندارد

تعیین یک رشته ی ترجمه با استفاده از تابع ugettext() می باشد. به صورت قرار است که این تابع به صورت یک نام مستعار کوتاه تر یعنی "_" import شود.

در مثال زیر، متن "Welcome to my site." به صورت رشته ی ترجمه علامت گذاری شده است:

from django.utils.translation import ugettext as _ def my_view(request): output = _("Welcome to my site.") return HttpResponse(output)

واضح است، می توانید بدون استفاده از نام مستعار کد فوق را بنویسید. مثال زیر برابر با مثال فوق می باشد:

from django.utils.translation import ugettext def my_view(request): output = ugettext("Welcome to my site.") return HttpResponse(output)

ترجمه با مقدار محاسبه شده کار می کند. مثال زیر برابر با دو مثال قبلی می باشد:

def my_view(request): words = ['Welcome', 'to', 'my', 'site.'] output = _(' '.join(words)) return HttpResponse(output)

ترجمه با متغیرها نیز کار می کند. برای بار دیگر، مثال زیر برابر با مثال های قبلی می باشد:

def my_view(request): sentence = 'Welcome to my site.' output = _(sentence) return HttpResponse(output)

(اخطار در مورد استفاده از متغیرها یا مقادیر محاسبه شده، همانطور که در دو مثال قبلی مشاهده کردید، این است که مزیت تشخیص رشته ی ترجمه یعنی django-admin.py makemessages، قادر به یافتن این رشته ها نخواهد بود. در مورد makemessage کمی بعد بیشتر توضیح خواهیم داد.)

رشته هایی که به _() یا ugettext() ارسال می کنید، می توانند placeholder هایی دریافت کنند، که درون زبان پایتون وجود دارند. مثال:

def my_view(request, m, d): output = _('Today is %(month)s %(day)s.') % {'month': m, 'day': d} return HttpResponse(output)

این تکنیک به ترجمه های زبان خاص اجازه می دهد متن placeholder را دوباره چیدمان کنند. برای مثال، یک ترجمه ی انگلیسی ممکن است "Today is November 26." باشد، هنگام ترجمه ی اسپانیایی ممکن است "Hoy es 26 de Noviembre." باشد – با placeholder ها (ماه و روز) با موقعیت های عوض شدهی آنها.

به همین دلیل، شما باید از رشته های نام گذاری شده (مانند %(day)s) به جای رشته های موضعی (مانند، %s یا %d) هر زمان که بیشتر از یک پارامتر وجود دارد استفاده کنید. در صورتی که از رشته های موضعی استفاده می کنید قادر نمی باشد placeholder متن را دوباره چیدمان کنید.

علامت گذاری رشته ها به صورت No-Op

از تابع django.utils.translation.ugettext_noop() جهت علامت گذاری یک رشته به صورت یک رشته ی ترجمه بدون ترجمه کردن آن استفاده کنید.

در صورتی که رشته های ثابتی دارید که باید در ریشه ی زبان ذخیره شده باشند چرا که آن ها در سرتاسر سیستم ها و کاربران رد و بدل می شوند – مانند رشته های درون یک پایگاه داده – ولی باید در آخرین نقطه ی ممکن ترجمه شوند، مانند زمانی که رشته به کاربر نشان داده می شود، از این استفاده کنید.

ترجمه ی Lazy

از تابع django.utils.translation.ugettext_lazy() جهت ترجمه ی رشته های به صورت lazy استفاده کنید – زمانی که مقدار در دسترس است، به جای هنگامی که تابع ugettext_lazy() فراخوانی شده است.

برای مثال، جهت ترجمه ی مدل help_text کد زیر را عمل کنید:

from django.utils.translation import ugettext_lazy class MyThing(models.Model): name = models.CharField(help_text=ugettext_lazy('This is the help text'))

در مثال فوق، ugettext_lazy() یک بازگشت lazy به رشته را ذخیره می کند – نه ترجمه ی واقعی را. خود ترجمه، هنگامی که رشته در یک رشته ی context استفاده شده باشد، مانند render کردن template در سایت مدیر جنگو، انجام خواهد شد.

نتیجه فراخوانی یک ugettext_lazy() می تواند هر جایی که شما یک رشته ی یونیکد (یک شیء از نوع unicode) در پایتون استفاده می کند استفاده شده باشد. در صورتی که سعی کنید در جایی که انتظار یک bytestring (شیء str) از آن استفاده کنید، هیچ چیز آن طوری که انتظار آن می رود کار نخواهد کرد، چون یک شیء uggettext_lazy() نحوه ی تبدیل خودش به یک bytestring را نمی داند. نمی توانید از یک رشته ی یونیکد درون یک bytestring استفاده کنید، بنابراین این رفتار عادی پایتون می باشد. برای مثال:

# This is fine: putting a unicode proxy into a unicode string. u"Hello %s" % ugettext_lazy("people") # This will not work, since you cannot insert a unicode object # into a bytestring (nor can you insert our unicode proxy there) "Hello %s" % ugettext_lazy("people")

در صورتی که همواره خروجی شبیه به "hello <django.utils.functional...>" مشاهده می کند، باید سعی به درج نتیجه ی ugettext_lazy() به درون یک bytestring کنید. آن یک اشکال در کد شما می باشد.

در صورتی که نام طولانی ugettext_lazy را نمی پسندید، می توانید از نام مستعار "_" (خط تیره)، مانند زیر استفاده کنید:

from django.utils.translation import ugettext_lazy as _ class MyThing(models.Model): name = models.CharField(help_text=_('This is the help text'))

همواره از ترجمه های lazy در مدل های جنگو استفاده کنید. نام های فیلد و نام جدول باید برای ترجمه علامت گذاری شده باشند(در غیر این صورت، آن ها درون رابط مدیر ترجمه نخواهند شد). این بدین معنی است که نوشتن صریح option های verbose_name و verbose_name_plural در کلاس Meta، به جای اعتماد به تعیین پیشفرض verbose_name و verbose_name_plural جنگو توسط نگاه به نام کلاس مدل:

from django.utils.translation import ugettext_lazy as _ class MyThing(models.Model): name = models.CharField(_('name'), help_text=_('This is the help text')) class Meta: verbose_name = _('my thing') verbose_name_plural = _('mythings')

جمع بندی

برای تعیین پیام های جمع بندی شده از تابع django.utils.translation.ungettext() استفاده کنید. مثال:

from django.utils.translation import ungettext def hello_world(request, count): page = ungettext('there is %(count)d object', 'there are %(count)d objects', count) % { 'count': count, } return HttpResponse(page)

ungettext سه آرگومان دریافت می کند: رشته ی ترجمه ی تک، رشته ی ترجمه ی جمع و تعداد شیء ها (که به زبان های ترجمه به صورت متغیر count ارسال شده است).

در کد Template

ترجمه در template های جنگو از دو تگ template و یک syntax کمی متفاوت تر از کد پایتون استفاده می کند. برای دادن دسترسی به این تگ ها به template خود، {% load i18n %} را نزدیک بالای template خود قرار دهید.

تگ template {% trans %} هر دوی رشته ی ثابت (احاطه شده درون دابل کتیشن یا تک کتیشن) یا محتوای متغیر را ترجمه می کند:

<title>{% trans "This is the title." %}</title> <title>{% trans myvar %}</title>

در صورتی که آپشن noop موجود باشد، variable lookup همچنان اتفاه می افتد ولی ترجمه انجام نمی شود. در دست ترجمه ....

<title>{% trans "myvar" noop %}</title>

امکان ترکیب یک متغیر template درون یک رشته ی داخل {% trans %} امکان پذیر نمی باشد. در صورتی که ترجمه های شما نیازمند رشته هایی با متغیرها (placeholder ها) باشد، از {% blocktrans %} استفاده کنید:

{% blocktrans %}This string will have {{ value }} inside.{% endblocktrans %}

جهت ترجمه ی یک عبارت template – تصور کنید، از فیلترهای template استفاده می کند – نیاز چسباندن عبارت به متغیر محلی برای استفاده درون بلاک ترجمه می باشد:

{% blocktrans with value|filter as myvar %} This will have {{ myvar }} inside. {% endblocktrans %}

در صورتی که نیاز به چسباندن بیشتر از یک عبارت داخل یک تگ blocktrans دارید، قسمت ها را با and جدا کنید:

{% blocktrans with book|title as book_t and author|title as author_t %} This is {{ book_t }} by {{ author_t }} {% endblocktrans %}

جهت جمع بستن، هر دو فرم های تک و جمع را با تگ {% plural %} تعیین کنید، که درون {% blocktrans %} و {% endblocktrans %} ظاهر می شوند. مثال:

{% blocktrans count list|length as counter %} There is only one {{ name }} object. {% plural %} There are {{ counter }} {{ name }} objects. {% endblocktrans %}

به طور داخلی، تمام بلاک و ترجمه های درون خطی از فراخوانی مناسب ugettext / ungettext استفاده می کنند.

هر RequestContext دارای دسترسی به سه متغیر ترجمه ی خاص می باشد:

در صورتی که از RequestContext extension استفاده نمی کنید، می توان آن مقادیر را با سه تگ زیر بدست آورد:

{% get_current_language as LANGUAGE_CODE %} {% get_available_languages as LANGUAGES %} {% get_current_language_bidi as LANGUAGE_BIDI %}

این تگ ها همچنین به یک {% load i18n %} نیاز دارند

{% some_special_tag _("Page not found") value|yesno:_("yes,no") %}

کار با شیء های ترجمه ی Lazy

استفاده از ugettext_lazy() و ungettext_lazy() برای علامت گذاری رشته ها در مدل ها و توابع یک عمل رایج می باشد. هنگامی که با این شیء ها در جای دیگر کد خود کار می کنید، باید مطمئن باشید که به طور تصادفی آن ها را رشته ها تبدیل نمی کنید، زیرا آن ها باید در آخرین زمان ممکن تبدیل شوند (در دست ترجمه ...). این موضوع ایجاب می کند که از چند تابع کمکی استفاده کنید.

متصل کردن رشته ها: string_concat()

join های رشته ی استاندارد پایتون (''.join([...])) بر روی لیست های حاوی شیء های ترجمه ی lazy کار نخواهند کرد. در عوض، می توانید از django.utils.translation.string_concat() استفاده کنید، که یک شیء lazy ایجاد می کند که محتویات آن را به هم وصل کرده و آن ها را تنها هنگامی که نتیجه در یک رشته شامل شده باشد، به هم متصل می کند. برای مثال:

from django.utils.translation import string_concat # ... name = ugettext_lazy(u'John Lennon') instrument = ugettext_lazy(u'guitar') result = string_concat([name, ': ', instrument])

در این مورد، ترجمه ی lazy در result تنها زمانی که خود result در یک رشته استفاده شده باشد به رشته ها تبدیل می شود (معمولا زمان render شدن template).

دکوریتور allow_lazy()

جنگو بسیاری توابع سودمند (به ویژه در django.utils) ارائه می کند که یک رشته را به صورت اولین آرگومان دریافت می کنند و کاری را بر روی آن رشته انجام می دهند. این توابع توسط فیلترهای template همچنین به طور مستقیم در کد دیگر استفاده می شوند.

در صورتی که توابع مشابه خود را بنویسید و با ترجمه های سر و کار داشته باشید، زمانی که اولین آرگومان یک شیء ترجمه ی lazy باشد با مشکل چه باید بکنم رو به رو می شوید. شما نمی خواهید آن را بلا فاصله به یک رشته تبدیل کنید، چرا که ممکن است تابع را بیرون از view نیز استفاده کنید (در دست ترجمه ...).

برای موارد شبیه به این، از دکوریتور django.utils.functional.allow_lazy() استفاده کنید. این دکوریتور تابع اصلاح می کند، به طوری که اگر با یک ترجمه lazy به عنوان اولین آرگومان فراخوانی شود، ارزیابی تابع تا زمانی که نیاز باشد به یک رشته تبدیل شود به تاخیر می افتد.

برای مثال:

from django.utils.functional import allow_lazy def fancy_utility_function(s, ...): # Do some conversion on string 's' # ... fancy_utility_function = allow_lazy(fancy_utility_function, unicode)

در دست ترجمه ....

استفاده از این دکوریتور بدین معناست که شما می توانید تابع خود را نوشته و فرض کنید که ورودی یک رشته ی مناسب می باشد، سپس پشتیبان برای شیء های ترجمه ی lazy در پایان اضافه کنید.

2. نحوه ی ساختن فایل های زبان

هنگامی رشته های خود را برای ترجمه ی بعدی ضمیمه کردید، نیاز به نوشتن (بدست آوردن) خود ترجمه های زبان دارید. در زیر نحوه ی این عمل وجود دارد.

فایل های پیام

اولین قدم برای یک زبان جدید ساختن یک فایل پیام می باشد. فایل پیام یک فایل متنی ساده برای نشان دادن یک زبان است، که حاوی تمام رشته های در دسترس برای ترجمه و چگونگی نمایش آن ها در زبان داده شده است. فایل های پیام دارای پسوند .po می باشند.

جنگو ابزاری به نام django‑admin.py makemessages ارائه می کند، که ساختن و نگهداری این فایل ها را خودکار می کند. جهت ساخت و به روز رسانی یک فایل پیام، دستور زیر را اجرا کنید:

django-admin.py makemessages -l de

de کد زبان برای فایل پیامی که می خواهید بسازید می باشد. کد زبان، در این مورد در قابل بندی locale می باشد. برای مثال، pt_BR برای برزیلی پرتغالی و de_AT برای اتریشی آلمانی می باشد.

اسکریپت باید از یکی از این سه مکان اجرا شود:

این اسکریپت در سرتاسر درخت منبع پروژه یا درخت منبع برنامه اجرا می شود و تمام رشته های علامت گذاری شده برای ترجمه را بیرون می کشد. این اسکریپت یک فایل پیام در دایرکتوری locale/LANG/LC_MESSAGES می سازد (یا بروز رسانی می کند). در مثال de، فایل locale/de/LC_MESSAGES/django.po خواهد بود.

به طور پیشفرض django-admin.py makemessages هر فایلی که دارای پسوند .html باشد را بررسی می کند. در مواردی که می خواهید آن پیشفرض را override کنید، از آپشن –extension یا –e برای تعیین پسوندهای فایل جهت بررسی استفاده کنید:

django-admin.py makemessages -l de -e txt

چندین پسوند را با کاما و / یا با استفاده از –e یا ––extension چندین بار جدا کنید:

django-admin.py makemessages -l de -e html,txt -e xml

زمان ساختن کاتالوگ های ترجمه ی جاوا اسکریپت (که کمی بعد در این آموزش از کتاب پوشش داده خواهد شد،) نیاز به استفاده از دامنه ی خاص 'djangojs' دارید، نه –e js.

قالب بندی فایل های .po ساده می باشد. هر فایل .po حاوی یک قسمت کوچک از metadata، از قبیل اطلاعات تماس maintainer ترجمه، توده ی فایل یک لیست از پیام ها می باشد – ارتباط های ساده بین رشته های ترجمه و متن ترجمه شده ی واقعی برای زبان خاص.

برای مثال، در صورتی که app جنگو شما حاوی یک رشته ی ترجمه برای متن "Welcom to my site." مانند زیر می باشد:

_("Welcome to my site.")

... سپس django-admin.py makemessages یک فایل .po حاوی تکه کد های زیر را خواهد ساخت – یک پیام:

#: path/to/python/module.py:23 msgid "Welcome to my site." msgstr ""

یک توضیح سریع:

پیام های طولانی یک مورد خاص می باشند. در آن جا، اولین رشته به طور مستقیم بعد از msgstr (یا msgid) یک رشته ی خالی می باشد. سپس خود محتوا خودش سرتاسر چند خط بعدی به صورت یک رشته در هر خط نوشته شده خواهند بود. آن رشته ها به صورت مستقیم متصل شده اند. space های عقبی درون رشته ها را فراموش نکنید؛ در غیر اینصورت، آن ها بدون فاصله به یکدیگر وصل می شوند!

جهت بررسی دوباره ی تمام کد منبع و template ها برای رشته های ترجمه ی جدید و به روز رسانی تمام فایل های پیام برای تمام زبان ها، دستور زیر را اجرا کنید:

django-admin.py makemessages -a

کامپایل فایل های Message

بعد از این که فایل پیام خود را ایجاد نمودید – و هر بار که تغییراتی در آن انجام دهید – نیاز به کامپایل آن درون یک فرم موثرتر خواهید داشت، جهت استفاده با gettext. این کار را با مزیت django‑admin.py compilemessages انجام دهید.

این ابزار سرتاسر تمام فایل های .po در دسترس اجرا می شود و فایل های .mo را ایجاد می کند که فایل های باینری بهینه شده برای استفاده توسط gettext می باشند. درون دایرکتوری همسانی که دستور django‑admin.py makemessages را اجرا کردید، دستور django-admin.py compilemessages را مانند زیر اجرا کنید:

django-admin.py compilemessages

همین. ترجمه های شما آماده برای استفاده می باشند.

3. طریقه ی پی بردن جنگو به ترجیح زبان

هنگامی ترجمه های خود را آماده می کنید – یا، در صورتی که تنها می خواهید از ترجمه های موجود در خود جنگو استفاده کنید – تنها نیاز خواهید داشت ترجمه را برای app خود فعال کنید.

در پشت صحنه، جنگو دارای یک مدل خیلی منعطف از تصمیم گیری در مورد زبانی که باید استفاده شود می باشد – installation‑wide برای یک کاربر خاص، یا هر دو.

برای قرار دادن preference زبان installation-wide، LANGUAGE_CODE را قرار دهید. جنگو از این زبان به صورت ترجمه ی پیشفرض استفاده می کند – تلاش نهایی در صورتی که مترجم دیگری یک ترجمه پیدا کند.

در صورتی که بخواهید جنگو را با زبان مادری خود اجرا کنید، و یک فایل زبان برای زبان شما در دسترس می باشد، نیاز به قرار دادن LANGUAGE_CODE دارید.

در صورتی که می خواهید برای هر کاربر منحصر به فرد زبان مورد ترجیح خودش را مشخص کنید، از LocaleMiddleware استفاده کنید. LocaleMiddleware انتخاب زبان بر اساس داده ی درخواست را فعال می کند. LocaleMiddleware محتوا را برای کاربر سفارشی می کند.

جهت استفاده از LocaleMiddlewareT، 'django.middleware.locale.localeMiddleware' را به تنظیم MIDDLEWARE_CLASSES اضافه کنید. به دلیل آن که ترتیب middleware مهم می باشد، باید دستور العمل های زیر را دنبال کنید:

به عنوان مثال، MIDDLEWARE_CLASSES ممکن است شبیه به زیر باشد:

MIDDLEWARE_CLASSES = ( 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.locale.LocaleMiddleware', 'django.middleware.common.CommonMiddleware', )

(برای اطلاعات بیشتر درباره ی middleware، به مبحث middleware مراجعه کنید.)

LocaleMiddleware تلاش می کند preference زبان کاربر را توسط الگوریتم زیر تعیین کند:

نکته ها:

هنگامی که LocalMiddleware، preference کاربر را تعیین می کند، این preference را به صورت request.LANGUAGE_CODE برای هر HttpRequest قابل دسترس می کند. احساس آزادی کندی برای خواند این مقدار در کد view خود. در زیر یک مثال ساده وجود دارد:

def hello_world(request): if request.LANGUAGE_CODE == 'de-at': return HttpResponse("You prefer to read Austrian German.") else: return HttpResponse("You prefer to read another language.")

توجه داشته باشید که، با ترجمه استاتیک (بدون middleware)، زبان دز settings.LANGUAGE_CODE می باشد، در حالی که با ترجمه ی پویا (middleware)، در request.LANGUAGE_CODE می باشد.

استفاده از ترجمه ها در پروژه ی خودتان

جنگو توسط الگوریتم زیر به دنبال ترجمه می گردد:

می توانید برنامه هایی که شامل ترجمه های خودشان باشند را بنویسید، و می توانید پایگاه ترجمه ها را در مسیر پروژه ی خود override کنید. یا، می توانید تنها یک پروژهی بزرگ خارج از چندین app ساخته و تمام ترجمه ها را درون یک پروژه ی بزرگ فایل پیام قرار دهید. انتخاب با خودتان می باشد.

تمامی مخازن (repositories) دارای ساخت به روش یکسان می باشند، آن ها:

جهت ساخت فایل های پیام، از ابزار همسان django-admin.py makemessages همانطور که فایل های پیام جنگو با آن بود استفاده می کنید. تنها نیاز است د رجای مناسب باشید – در دایرکتوری conf/locale ((در دست ترجمه ...)) یا locale/ ((در دست ترجمه ...)) دایرکتوری قرار دارند. همچنین از دستور همسان django-admin.py compilemessages برای تولید فایل های باینری django.mo که توسط gettext استفاده می شوند استفاده می شود.

همچنین می توانید django-admin.py compilemessages --settings=path.to.settings را برای ایجاد پردازش کامپایلر تمام دایرکتوری های موجود در تنظیم LOCALE_PATHS اجرا کرد.

فایل های پیام برنامه برای پی بردن کمی پیچیده می باشند – آن ها نیاز به LocaleMiddleware دارند. در صورتی که از middleware استفاده نمی کنید، تنها فایل های پیام جنگو و فایل های پیام پروژه پردازش خواهند شود.

(در دست ترجمه ...). در صورتی که برنامه ها نیاز به تحویل داده شدن به کاربران دیگر داشته و در پروژه های دیگر استفاده خواهد شد، ممکن است بخواهید ترجمه های app-specific را استفاده کنید. ولی استفاده از ترجمه های app‑specific و ترجمه های پروژه می تواند مشکلات مرموزی با makemessages زتولید کند: makemessages از تمام دایرکتوری های زیر مسیر فعلی عبور کرده و بنابراین ممکن است ID های پیام را درون فایل پیام پروژه قرار دهد که قبلا در فایل های پیام برنامه وجود داشته اند.

ساده ترین راه ذخیره کردن برنامه هایی است که بخشی از پروژه نیستند (و بنابراین ترجمه های خودشان را حمل می کنند) خارج از درخت پروژه. django-admin.py makemessages در سطح پروژه تنها رشته هایی که پروژه ی صریح شما متصل هستند را ترجمه می کند و نه رشته هایی که به طور مستقل توزیع شده هستند.

view تغییر مسیر set_language

برای راحتی، جنگو یک view به نام django.views.i18n.set_language ارائه می کند، که یک preference زبان کاربر را قرار می دهد و به صفحه ی قبلی تغییر مسیر می دهد.

این view را توسط اضافه کردن خط زیر به URLconf فعال کنید:

(r'^i18n/', include('django.conf.urls.i18n')),

(توجه داشته باشید که این مثال view را در /i18n/setlang/ قابل دسترس می کند.)

view انتظار دارد توسط روش POST فراخوانی شود، با یک پارامتر langage در درخواست. در صورتی که پشتیبانی session فعال شده باشد، view انتخاب زبان در session کاربر را ذخیره می کند. در غیر اینصورت، زبان انتخاب در یک کوکی که به طور پیشفرض با نام django_language می باشد را ذخیره می کند. (نام می تواند از طریق تنظیم LANGUAGE_COOKIE_NAME تغییر کند.)

بعد از تنظیم انتخاب زبان، جنگو با الگوریتم زیر کاربر را تغییر مسیر می دهد:

در زیر مثال کد HTML template وجود دارد:

<form action="/i18n/setlang/" method="post"> <input name="next" type="hidden" value="/next/page/" /> <select name="language"> {% for lang in LANGUAGES %} <option value="{{ lang.0 }}">{{ lang.1 }}</option> {% endfor %} </select> <input type="submit" value="Go" /> </form>

ترجمه ها و جاوا اسکریپت

اضافه کردن ترجمه ها به جاوا اسکریپت برخی مشکلات را موجب می شود:

جنگو یک راهکار یکپارچه سازی شده برای این مشکلات تهی می کند: ترجمه ها را به جاوا استکریپت اراسل می کند، بنابراین می توانید gettext و غیره را از درون جاوا اسکریپت فراخوانی کنید.

javascript_catalog

راهکار اصلی برای این مشکلات، view ای با نام javascript_catalog می باشد، که یک کتابخانه ی کد جاوا اسکریپت با توابعی است که رابط gettext را تقلید کرده است، به اضافه ی یک آرایه از رشته های ترجمه. آن رشته های ترجمه گرفته شده از برنامه، پروژه یا هسته ی جنگو می باشد، مطابق آن چه را که شما در info_dict یا URL تعیین کرده اید.

به شکل زیر آن را مرتبط می کنید:

js_info_dict = { 'packages': ('your.app.package',), } urlpatterns = patterns('', (r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict), )

هر رشته در packages باید در syntax پایتون dotted-package باشد (قالب بندی همسان به صورت رشته ها در INSTALLED_APPS) و باید به یک پکیجی که حاوی دایرکتوری locale می باشد رجوع کند. در صورتی که چندین پکیج تعیین می کنید، تمام آن کاتالوگ ها در یک کاتالوگ ادغام می شوند. در صورتی که جاوا اسکریپتی دارید که از رشته های برنامه های مختلف استفاده می کند این مفید می باشد.

می توانید view را توسط قرار دادن پکیج هایی داخل الگوی URL پویا کنید:

urlpatterns = patterns('', (r'^jsi18n/(?P<packages>\S )/$', 'django.views.i18n.javascript_catalog'), )

با این موضوع، شما پکیج هایی را به صورت یک لیست از نام های پکیج محدود شده توسط علامت های ' 'در URL تعیین می کنید. این بویژه در صورتی که صفحات شما کدهایی از app های مختلف استفاده می کند و این اغلب تغییر می کند و نمی خواهید در یک فایل کاتالوگ بزرگ بکشید مفید است. به عنوان یک اقدام امنیتی، این مقادیر تنها django.conf یا هر پکیجی از تنظیم INSTALLED_APPS می باشند.

استفاده از کاتالوگ ترجمه ی جاوا استکریپت

جهت استفاده از کاتالوگ، تنها کافیست (در دست ترجمه ...):

<script type="text/javascript" src="/django/path/to/jsi18n/"></script>

این نحوه ای است که مدیر ترجمه ی کاتالوگ سرور را واکشی می کند. هنگامی که کاتالوگ بارگذاری شد، کد جاوا اسکریپت شما می تواند از رابط gettext استاندارد برای دسترسی به آن استفاده کند:

document.write(gettext('this is to be translated'));

همچنین یک رابط ngettext نیز وجود دارد:

var object_cnt = 1 // or 0, or 2, or 3, ... s = ngettext('literal for the singular case', 'literal for the plural case', object_cnt);

و حتی یک تابع رشته ی interpolation:

function interpolate(fmt, obj, named);

interpolation syntax قرض گرفته شده از پایتون می باشد، بنابراین تابع interpolate هر دوی interpolation موضعی و نام گذاری شده را پشتیبانی می کند:

شما نباید بالا با رشته ی interpolation بروید: این همچنان جاوا اسکریپت می باشد، بنابراین، کد باید تعویض های تکرار شده ی regular-expression را ایجاد کند. این به همان سرعت رشته ی interpolation در جاوا نمی باشد، بنابراین آن را برای مورادی که واقعا به آن نیاز دارید نگه دارید (برای مثال، در رابطه با ngettet برای تولید جمع بندی های مناسب).

ساختن کاتالوگ های ترجمه ی جاوا اسکریپت

شما کاتالوگ های ترجمه را به همان روشی که کاتالوگ های ترجمه ی دیگر جنگو را ساخته و به روز رسانی می کردید – با ابزار django-admin.py makemessages – انجام می دهید. تنها تفاوت این است که نیاز به تهیه ی یک پارامتر –d djangojs مانند زیر خواهید داشت:

django-admin.py makemessages -d djangojs -l de

دستور فوق کاتالوگ ترجمه برای جاوا اسکریپت برای آلمانی را ساخته یا به روز رسانی می کند. بعد از به روز رسانی کاتالوگ های ترجمه، تنها کافیست دستور django-admin.py compilemessages همانند کاتالوگ های عادی جنگو اجرا کنید.

نکته هایی برای کاربران آشنا به gettext

در صورتی که gettext را می شناسید، ممکن است متوجه این تخصص های روش جنگو برای انجام ترجمه شده باشید:

gettext در ویندوز

این تنها برای افرادی که می خواهند ID های پیام را استخراج کنند یا فایل های پیام را کامپایل کنند ضروری می باشد (.op). خود کار ترجمه تنها با ویرایش فایل های موجود از این نوع درگیر است، ولی در صورتی که می خواهید فایل های پیام خود را ایجاد کنید، یا می خواهید یک فایل پیام تغییر کرده را آزمون یا کامپایل کنید، نیاز به مزیت های gettext خواهید داشت:

همچنین می توانید از باینری های gettect نیز که در جای دیگر بدست آورده شده است استفاده کنید، مادامی که دستور xtgett –version به درستی کار می کند. برخی نسخه های باینری 0.14.4 این دستور را پشتیبانی نمی کنند. در صورتی که دستور xgettext –version وارد شده در یک command prompt ویندوز موجب یک پنجره ی popup شده است "xgettext.exe has generated errors and will be closed by Windows" برای استفاده از مزیت های ترجمه ی جنگو با پکیج gettext تلاش نکنید.