مهاجرت¶
اگر پروژهٔ شما همین حالا از gettext استفاده میکند، پرسشهایی که تعیین میکنند این کتابخانه پذیرفتنی هست یا نه، پرسشهای محدودیاند: آیا کاتالوگهایی را که دارید بیاعتبار میکند، آیا میتواند با کدی که هنوز آمادهٔ تغییرش نیستید همزیستی کند، و چه اندازه از این جابهجایی باید یکباره رخ دهد. پاسخها، از کوتاهترین:
| پرسش | پاسخ |
|---|---|
آیا فایلهای .po و .moِ موجود هنوز کار میکنند؟ |
بله. همان فایلها، همان ابزارها. |
| آیا فراخوانیهای قدیم و جدید میتوانند در یک فایل زندگی کنند؟ | بله، و یک نگاشت استخراجکننده هر دو را میپوشاند. |
| آیا msgid تغییر میکند؟ | از .format() نه. از قالب % بله. |
| آیا کل پروژه باید یکباره جابهجا شود؟ | نه. یک محل فراخوانی هم تغییری معتبر است. |
| Jinja و قالبهای Django و JavaScript چه میشوند؟ | دستنخورده، با همان کاتالوگها. |
باقی این صفحه، جزئیاتِ پشت هر یک از اینهاست.
از .format(): msgid تغییر نمیکند¶
این همان حالتی است که مهاجرت در آن تقریباً هیچ هزینهای ندارد. یک پیام
str.format و یک پیام t-string همان کلید کاتالوگ را میسازند، چون
کلید در هر دو حالت متنی است که {name} در آن باقی مانده است:
# Before
_("Hello {name}").format(name=name)
# After — the msgid is still "Hello {name}"
tr(t"Hello {name}")
پس ترجمهٔ موجود همچنان به پیام چسبیده میماند. از کاتالوگی آغاز کنید که این را دارد
فراخوانی را تغییر دهید، دوباره استخراج کنید و بهروزرسانی کنید:
$ pybabel extract -F babel.cfg -o locales/messages.pot .
extracting messages from app.py (encoding="utf-8")
writing PO template file to locales/messages.pot
$ pybabel update -i locales/messages.pot -d locales
updating catalog locales/ja/LC_MESSAGES/messages.po based on locales/messages.pot
مدخلی که بازمیگردد تنها در دو خط فراداده فرق دارد و بس — یک توضیحِ نشانه که آن را پیامی t-string معرفی میکند، و یک شمارهٔ خط مبدأ:
نه پرچم fuzzy، نه ترجمهٔ دوباره، در هیچ زبانی. پیام بیدرنگ رندر
میشود:
$ pybabel compile -d locales
compiling catalog locales/ja/LC_MESSAGES/messages.po to locales/ja/LC_MESSAGES/messages.mo
$ python app.py
こんにちは Ada
update --check کاتالوگها را عقبافتاده گزارش میکند
همان توضیحِ نشانه و شمارههای خطِ جابهجاشده برای این کافیاند که
pybabel update --check بگوید کاتالوگ نیاز به بازتولید دارد، چون
کل مدخل را مقایسه میکند نه فقط ترجمه را. pybabel updateِ واقعی
را در همان کامیتِ تغییر کد اجرا کنید و کاتالوگها را با آن کامیت
کنید — همان عادتی که دروازهٔ CI پیشتر
میخواهد.
از قالب %: msgid تغییر میکند، پس ترجمهها fuzzy میشوند¶
نحو printf درون پیام زندگی میکند؛ پس جایگزینکردنش کلید کاتالوگ را
بازنویسی میکند. راهی گرد آن نیست، و این هزینهٔ صادقانهٔ کنارگذاشتن
%(name)s است:
pybabel update پیام تازه را خویشاوندِ نزدیکِ پیام حذفشده میشناسد و
ترجمهٔ قدیمی را با نشانِ fuzzy به آن میرساند:
#. gettext-tstrings
#: app.py:4
#, fuzzy, python-brace-format, python-format
msgid "Hello {name}"
msgstr "こんにちは %(name)s"
سه چیز دربارهٔ این وضعیت باید بدانید:
- در زمان اجرا چیزی نمیشکند. مدخلهای fuzzy از
.moِ کامپایلشده کنار گذاشته میشوند؛ پس برنامه تا وقتی انسانی جفت را تأیید نکرده، پیام مبدأ را رندر میکند — همان تنزلی که هر پیامِ بازنویسیشده از سر میگذراند. - تا وقتی fuzzyاند، CI سبز میماند. بررسیکنندهٔ جاینگهدار از
مدخلهای fuzzy میگذرد، دقیقاً همانطور که
msgfmt --check-formatمیکند، چون مدخلی که نمیتواند به زمان اجرا برسد نباید بیلدی را بشکند. همان لحظه که مترجم پرچم را پاک کند، مدخل مانند هر مدخل دیگری بررسی میشود — پس%(name)sای که در ترجمهای تأییدشده جا مانده باشد همانجا گرفته میشود، یعنی همان نقطهای که وگرنه شروع به رندرشدن میکرد. - پرچم قدیمی
python-formatهم سوار میشود و باید همراه پرچمfuzzyحذف شود، وگرنهmsgfmt --check-formatقواعد printf را بر پیامی با قالب آکولادی اعمال خواهد کرد.
برای جاینگهدارهای نامدارِ printf این ویرایش مکانیکی است — %(name)s
میشود {name} و هیچ چیز دیگری تکان نمیخورد — پس یک کاتالوگ بزرگ یک
گذرِ اسکریپتی است و پس از آن بازبینی یک مترجم، نه ترجمهای از نو.
%sِ موضعی مکانیکی نیست: نامی ندارد که منتقل شود، و برگزیدن یک نام
اصلاً نکتهٔ همین تغییر است.
بنابراین مهاجرت میتواند با هر سرعتی که بازبینی اجازه میدهد پیش برود: یک مدخلِ fuzzyِ تبدیلنشده کارِ نمایانی در کاتالوگ است، نه بیلدی شکسته.
همزیستی فراخوانیهای قدیم و جدید¶
استخراجکنندهای که t-stringها را میخواند فراخوانیهای معمولی gettext را هم میخواند؛ پس یک نگاشت، فایلی را که میانهٔ مهاجرت است میپوشاند:
from gettext_tstrings import tr
from myapp.i18n import _
name = "Ada"
print(_("Save changes"))
print(tr(t"Hello {name}"))
هر دو پیام در یک الگو فرود میآیند، و تنها پیامِ t-string توضیحِ نشانهای را دارد که بررسی افزودهٔ این کتابخانه را روشن میکند:
#: app.py:5
msgid "Save changes"
msgstr ""
#. gettext-tstrings
#: app.py:6
#, python-brace-format
msgid "Hello {name}"
msgstr ""
این استخراجکننده _()، چهار نام استاندارد gettext، نامهای دیگر tr()
و ntr() و صورتهای معوق lazy_gettext() و lazy_pgettext() را
میشناسد. کمکیِ خودتان باید
در نگاشت نام برده شود.
در زمان اجرا این دو سبک به یک اندازه مستقلاند: gettext.translation()
یک شیء ترجمه برمیگرداند و هم _ و هم نقطههای ورود این کتابخانه از
همان میخوانند.
چه چیزی جابهجا نمیشود¶
- زبانهای قالب.
{% trans %}ِ Jinja2، تگهای قالب Django و استخراجکنندههای Babelِ آنها بیتغییر کار میکنند و همان کاتالوگهای PO را تغذیه میکنند. t-stringها نحو پایتوناند؛ به کد مبدأ پایتون مربوطاند. - فایلهای کاتالوگ شما. نه تغییر قالب، نه فایل تازه، نه گام تبدیل.
- پلتفرم ترجمهٔ شما. تبادلِ
.poیکسان است، و پرچمpython-brace-formatکه یک پیام t-string دارد همان پرچمی است که یک پیام.format()دارد — پس QA جاینگهدار به کار خود ادامه میدهد. - کدِ غیرپایتونی. یک کاتالوگ JavaScript یا C در همان پروژه بیاثر میماند.
چکلیستی برای مهاجرت¶
- افزونهٔ
babelرا آنجا کهpybabelاجرا میشود بیفزایید و نگاشتpythonرا درbabel.cfgبه روشgettext_tstringsتغییر دهید — از آن پس یک نگاشت هر دو سبک را میپوشاند و-kبرای فراخوانیهای معمولی همچنان کار میکند. - نخست محلهای فراخوانی
.format()را تبدیل کنید. دوباره استخراج کنید،pybabel updateرا اجرا کنید و کاتالوگها را همراه کد کامیت کنید؛ انتظار هیچ مدخل fuzzy نداشته باشید. - محلهای فراخوانی قالب
%را در دستههایی تبدیل کنید که بتوانید بازبینیشان کنید، و جاینگهدارهای منتقلشده را بازنویسی و پرچمهایfuzzyوpython-formatرا پاک کنید. - آنچه را محدودیت رد میکند اصلاح کنید: یک درونیابی باید نامی ساده
باشد؛ پس
t"Hello {user.name}"نخست به یک متغیر محلی تبدیل میشود. این ویرایشی در محل فراخوانی است، نه در کاتالوگ. - وقتی این گذر تمام شد،
strict = trueرا در نگاشت استخراجکننده روشن کنید تا پیامی که نمیشود استخراجش کرد بهجای ناپدیدشدن از الگو، بیلد را بشکند. - بررسی زمان اجرا را از در محیط عملیاتی
بیفزایید: بهازای هر زبانِ روانهشده یک پیام را از یک
Translatorِ سختگیر بگذرانید.
گامهای ۲ و ۳ کامیتهای معمولیاند. هیچ چیز در این فهرست به یک روزِ تعویضِ یکبارهٔ همهچیز نیاز ندارد.