آموزش¶
این صفحه از یک پوشهٔ خالی آغاز میکند و به برنامهای میرسد که به ژاپنی خوشآمد میگوید. پنج گام، بدون پیشفرضِ هیچ تجربهای با gettext، و هر فرمان همراه با خروجیای که واقعاً تولید میکند نشان داده میشود — تا در هر گام بدانید در مسیر درست هستید یا نه.
به پایتون 3.14 یا جدیدتر نیاز دارید، چون t-string نحو تازهای در 3.14
است. زبان مقصدِ نمونهٔ این صفحه ژاپنی است، اما هیچچیز به این انتخاب
وابسته نیست. برای استفاده از زبانی دیگر، ja را در گام ۴ عوض کنید —
همان کد محلی تنها جایی است که این زبان را نام میبرد.
۱. نصب¶
افزونهٔ [babel] ابزار Babel را میآورد؛ همان ابزاری که در گام ۳
پیامهای شما را در فایلهای کاتالوگ گرد میآورد. این یک ابزار زمانِ
توسعه است: کد عملیاتی تنها با کتابخانهٔ استاندارد رندر میکند.
۲. علامتگذاری یک پیام در کد¶
فایل app.py را بسازید:
t"Hello {name}" شبیه یک f-string است، اما پیشوند t متن و مقدار را
بهجای ادغام درجا، جدا از هم نگه میدارد. همین جدایی است که به tr()
اجازه میدهد ترجمهٔ کل جملهٔ Hello {name} را جستوجو کند و مقدار را
پس از آن جایگذاری کند.
همین حالا اجرایش کنید:
هنوز هیچ ترجمهای نصب نشده، پس متن مبدأ همانطور که هست رندر میشود. برنامهای که از این کتابخانه استفاده میکند هرگز برای اجرا نیازمند کاتالوگ نیست — انگلیسی (یا هر زبان مبدأ شما) پشتیبانِ درونی است.
۳. استخراج پیامها¶
مترجمها معمولاً بهجای کد مبدأ از کاتالوگها کار میکنند، پس فایل کوچکی به نام کاتالوگ میان شما و آنها رفتوآمد میکند. نخستین گام برای ساختن آن، گرد آوردن همهٔ پیامهای علامتگذاریشده از دل کد است.
با ساختن babel.cfg به Babel بگویید پیامهایتان را چگونه بیابد:
سپس آنها را در یک فایل الگو (.pot) استخراج کنید:
$ mkdir -p locales
$ pybabel extract -F babel.cfg -c "Translators:" -o locales/messages.pot .
extracting messages from app.py (encoding="utf-8")
writing PO template file to locales/messages.pot
اکنون locales/messages.pot برای هر پیام یک مدخل دارد:
msgid کلیدی است که کد شما جستوجو خواهد کرد. msgstrِ خالی جای ترجمه
است — اما نه در این فایل: .pot یک الگو است و گام بعدی برای هر زبان
یک نسخه از آن میگیرد.
۴. ترجمه و کامپایل¶
کاتالوگ ژاپنی را از روی الگو بسازید:
$ pybabel init -i locales/messages.pot -d locales -l ja
creating catalog locales/ja/LC_MESSAGES/messages.po based on locales/messages.pot
فایل locales/ja/LC_MESSAGES/messages.po را باز کنید و msgstr را پر
کنید:
{name} را دقیقاً همانطور که هست نگه دارید — جاینگهدار همان راهی است
که مقدار از آن جای خود را در جملهٔ ترجمهشده پیدا میکند، و ترجمه آزاد
است آن را هر جا که زبان مقصد لازم دارد جابهجا کند. در یک پروژهٔ واقعی
همین فایل .po است که به مترجم میسپارید یا به پلتفرم ترجمه بارگذاری
میکنید؛ قالب در هر دو حالت یکی است.
کاتالوگها به شکل متن ویرایش میشوند اما به شکل دودویی (.mo) بار
میشوند؛ پس کامپایل کنید:
$ pybabel compile -d locales
compiling catalog locales/ja/LC_MESSAGES/messages.po to locales/ja/LC_MESSAGES/messages.mo
این فرمان یک تور ایمنی هم هست. اگر ترجمه جاینگهدار را خراب کرده بود —
مثلاً {nome} بهجای {name} — از پذیرفتن آن سر باز میزد:
$ pybabel compile -d locales
error: locales/ja/LC_MESSAGES/messages.po:24: translation does not match the
source placeholders: {name} is missing; {nome} is not in the source message
1 errors encountered.
یک نکتهٔ درخور دانستن از همین حالا: خطا را گزارش میکند و با کد ناصفر
بیرون میآید، اما .mo را به هر حال مینویسد. در یک پروژهٔ واقعی این CI
است که باید بر آن کد خروج بایستد — در محیط
عملیاتی همین را برپا میکند.
۵. اجرا¶
گامهای ۲ تا ۴ از tr() استفاده میکردند که دنبال کاتالوگ میگردد و
هیچ نمییابد. حالا که کاتالوگی هست، آن را بار کنید و یکبار مقید کنید:
Translator کاتالوگ را نگه میدارد تا محلهای فراخوانی مجبور نباشند
نامش را ببرند، و _ نام مرسوم gettext برای نتیجه است.
app.py را به کاتالوگ کامپایلشده وصل کنید. روی نشانگرها کلیک کنید تا
ببینید هر خط چه میکند:
import gettext
from gettext_tstrings import Translator
_ = Translator(gettext.translation("messages", localedir="locales", languages=["ja"])) # (1)!
name = "Ada"
print(_(t"Hello {name}")) # (2)!
- کتابخانهٔ استاندارد
.moِ کامپایلشده را بار میکند وTranslatorآن را به یک فراخوانیپذیر میبندد._نام مرسوم gettext برای «این را ترجمه کن» است — کوتاه، چون روی هر رشتهٔ رو به کاربر ظاهر میشود. این همان ترجمهای را انجام میدهد کهtrمیکرد، بستهشده به یک کاتالوگ. - در لحظهٔ فراخوانی: متن t-string به کلید جستوجوی
Hello {name}تبدیل میشود، کاتالوگ پاسخこんにちは {name}را میدهد، پاسخ در برابر جاینگهدارهای مبدأ بررسی میشود، و تنها پس از آن مقدار جایگذاری میشود.
این کل چرخه است، و ارزشش را دارد که یکجا در یک تصویر دیده شود:
flowchart LR
mark["۱–۲ علامتگذاری<br>t-string در کد"] --> extract["۳ استخراج<br>messages.pot"]
extract --> translate["۴ ترجمه<br>ja/…/messages.po"]
translate --> compile["۴ کامپایل<br>ja/…/messages.mo"]
compile --> run["۵ اجرا<br>こんにちは Ada"]
علامتگذاری ← استخراج ← ترجمه ← کامپایل ← اجرا. هر چیز دیگری در این وبگاه، پرداختی بر یکی از همین پنج گام است.
گامهای بعدی¶
- چرا t-string؟ — این طراحی از چه چیزی محافظت میکند، در
مقایسه با
%(name)sو.format()و رشتههای$. - راهنما — صورتهای جمع، زبانِ هر درخواست، رشتههای معوق، و آنچه در زمان اجرا رخ میدهد وقتی کاتالوگ به هر حال خراب باشد.
- در محیط عملیاتی — همین چرخه آنگونه که یک تیم هفته به هفته میگرداند: بهروزرسانی کاتالوگها، دروازههای CI، و پلتفرمهای ترجمه.
- استخراج — مرجع کامل
pybabel: نامهای تابع سفارشی، حالت سختگیرانه در CI، و بررسیهایی که از کاتالوگهایتان پاسداری میکنند. - مهاجرت — اگر پروژهای که واقعاً میخواهید این کار را در آن بکنید، از پیش کاتالوگهای gettext دارد.
- برای مترجمان — تنها صفحهای که باید به دست کسی
بدهید که آن خطهای
msgstrرا پر میکند.