מעבר מקיים¶
אם הפרויקט שלכם כבר משתמש ב-gettext, השאלות שמכריעות אם הספרייה הזו ניתנת לאימוץ הן שאלות צרות: האם היא פוסלת את הקטלוגים שכבר יש לכם, האם היא יכולה לחיות לצד הקוד שאינכם מוכנים לשנות, וכמה מהמהלך חייב לקרות בבת אחת. התשובות, מהקצרה ואילך:
| שאלה | תשובה |
|---|---|
האם קובצי .po ו-.mo קיימים ממשיכים לעבוד? |
כן. אותם קבצים, אותם כלים. |
| האם קריאות ישנות וחדשות יכולות לחיות בקובץ אחד? | כן, ומיפוי מחלץ אחד מכסה את שתיהן. |
| האם ה-msgid משתנה? | לא מ-.format(). כן מ-%-format. |
| האם כל הפרויקט חייב לעבור בבת אחת? | לא. אתר קריאה אחד הוא שינוי תקף. |
| ומה עם Jinja, תבניות Django, JavaScript? | ללא נגיעה, אותם קטלוגים. |
שאר העמוד הזה הוא הפירוט מאחורי כל אחת מהתשובות האלה.
מ-.format(): ה-msgid אינו משתנה¶
זהו המקרה שבו המעבר כמעט אינו עולה דבר. הודעת str.format והודעת
מחרוזת-t גוזרות את אותו מפתח קטלוג, מפני שהמפתח הוא הטקסט שבתוכו
{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, ומספר שורה במקור:
בלי דגל 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 האמיתי באותו commit
שבו נמצא שינוי הקוד, וכללו איתו את הקטלוגים — אותו הרגל ששער
ה-CI כבר מבקש.
מ-%-format: ה-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המהודר, ולכן היישום מרנדר את הודעת המקור עד שאדם יאשר את הצמד — אותה הידרדרות שכל הודעה שנוסחה מחדש עוברת. - ה-CI נשאר ירוק כל עוד הן fuzzy. בודק מצייני המקום מדלג על רשומות
fuzzy, בדיוק כפי ש-
msgfmt --check-formatעושה, מפני שרשומה שאינה יכולה להגיע לזמן הריצה אינה צריכה להכשיל בנייה. ברגע שמתרגם מסיר את הדגל, הרשומה נבדקת ככל רשומה אחרת — ולכן%(name)sשנשאר בתרגום מאושר נתפס אז, בדיוק בנקודה שבה אחרת הוא היה מתחיל להיות מרונדר. - דגל ה-
python-formatהישן נוסע איתה וכדאי למחוק אותו יחד עם דגל ה-fuzzy, אחרתmsgfmt --check-formatימשיך להחיל כללי printf על הודעת brace-format.
עבור מצייני מקום של printf בעלי שם העריכה מכנית — %(name)s הופך
ל-{name} ושום דבר אחר אינו זז — ולכן קטלוג גדול הוא מעבר סקריפטי
ואחריו סקירה של מתרגם, ולא תרגום מחדש. %s פוזיציוני אינו מכני: אין
לו שם להעביר, ובחירת שם היא כל תכלית השינוי.
לפיכך המעבר יכול להתקדם בכל קצב שהסקירה מאפשרת: רשומת fuzzy שלא הומרה היא פיסת עבודה גלויה בקטלוג, לא בנייה שבורה.
קריאות ישנות וחדשות חיות זו לצד זו¶
המחלץ שקורא מחרוזות-t קורא גם קריאות gettext רגילות, ולכן מיפוי אחד מכסה קובץ שנמצא באמצע המעבר:
from gettext_tstrings import tr
from myapp.i18n import _
name = "Ada"
print(_("Save changes"))
print(tr(t"Hello {name}"))
שתי ההודעות נוחתות באותה תבנית, ורק זו של מחרוזת-t נושאת את הערת הסימון שמפעילה את הבדיקה הנוספת של הספרייה הזו:
#: 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 הן תחביר של Python; הן חלות על קוד Python. - קובצי הקטלוג שלכם. בלי שינוי פורמט, בלי קובץ חדש, בלי שלב המרה.
- פלטפורמת התרגום שלכם. מבנה החליפין של
.poזהה, ודגל ה-python-brace-formatשהודעת מחרוזת-t נושאת הוא אותו דגל שהודעת.format()נושאת — ולכן בקרת האיכות של מצייני המקום ממשיכה לעבוד. - קוד שאינו Python. קטלוג JavaScript או C באותו פרויקט אינו מושפע.
רשימת תיוג למעבר¶
- הוסיפו את התוספת
babelבכל מקום שבוpybabelרץ, ושנו את מיפוי ה-pythonב-babel.cfgלשיטתgettext_tstrings— מיפוי אחד מכסה אז את שני הסגנונות, ו--kממשיך לעבוד עבור הקריאות הרגילות. - המירו תחילה את אתרי הקריאה של
.format(). חלצו מחדש, הריצוpybabel update, וכללו את הקטלוגים יחד עם הקוד; אל תצפו לרשומות fuzzy. - המירו את אתרי הקריאה של
%-format במנות שאפשר להעביר בסקירה, תוך שכתוב מצייני המקום שהועברו והסרת הדגליםfuzzyו-python-format. - תקנו את מה שההגבלה דוחה: אינטרפולציה חייבת להיות שם פשוט, ולכן
t"Hello {user.name}"הופך תחילה למשתנה לוקלי. זו עריכה באתר הקריאה, לא בקטלוג. - הפעילו
strict = trueבמיפוי המחלץ ברגע שהסריקה הסתיימה, כדי שהודעה שאי אפשר לחלץ תכשיל את הבנייה במקום להיעלם מהתבנית. - הוסיפו את בדיקת זמן הריצה מתוך
בסביבת ייצור: רנדרו הודעה אחת לכל שפה
נשלחת דרך
Translatorקפדני.
שלבים 2 ו-3 הם commits רגילים. שום דבר ברשימה הזו אינו דורש יום מעבר אחד גדול.