מאמרים בנושא ‏Unicode‏.

לשרוד פיתוח תואם "Windows" בעידן Unicode...

ב־יום ראשון, 13 ביוני 2010, מאת ארתיום; פורסם תחת: תכנה חופשית, פיתוח, תכנה ומחשבים, C++‎‏, Unicode, Boost‏; ‏8 תגובות

אם פיתחתם מעט עבור Windows אתם בוודאי מכירים את המושג שנקרא Wide-API. קרי לכל פונקציית המערכת יש שתי גרסאות: "ANSI" ו־"Wide", למשל: DeleteFileA ו־DeleteFileW, כאשר אחת מהן מקבלת char const *‎ והשניה wchar_t const *‎.

נחמד לא? יש לך שני סוגי API שנוח לך, או לעבוד עם המחרוזות הפשוטות או לעבוד עם מחרוזות מבוססות "תווים־רחבים". אבל, לא בדיוק.

למעשה, לפי מדיניות של Microsoft, כדי לגשת לכל הכוח של מערכת ההפעלה אתה חייב להשתמש ב־Wide API אחרת... אתה אפילו לא תוכל ליצור קובץ "שלום.txt". נחמד, לא?

הבעיה שלא C99 ולא, C++‎, וגם לא C++0x לא מכירים במושג העמעום של wide-path ולמעשה, לפי התקן אין, דרך לפתוח קובץ שהשם לו הוא "שלום.txt" מקודד כמחרוזת של wchar_t (רק char). כמובן חבר'ה ב־MS הם "ידידותיים" למפתחים והם הציע API חילופי: ‎_wfopen(wchar_t const *,wchar_t const *);‎ וגם הוסיפו הרחבה לסטנדרט ב־Visual Studio‏: std::fstream::open(wchar_t const *,...);‎ הכל לטובת המפתח (הם כנראה לא שמעו בכלל על UTF-8)...

כאן, מתחיל הסיוט, למעשה למפתח יש שתי אופציות:

  • להתעלם מהטמטום של Wide-API ולעבוד רק עם "ANSI-API" ו... התוכנה תפסיק לעבוד באופן אקראי על קבצים אקראיים, והמשתמשים המסכנים ישברו את הראש מה לא עובד.
  • להתחיל לשכפל את כל הקוד שלך למקרה wide ולמקרה נורמלי.

סיוט. לא פלא, שרבים בורחים באופציה הראשונה, ולכן בשנת 2010, אנחנו נתקלים יישומים כמו Thunderbird, שלא עובד כשתיקיית המשתמש שלך בחלונות מכילה תוים עבריים.

כך גם, אני כשהתחלתי תמיכה בחלונות ב־CppCMS החלטתי להתעלם מהעובדה ש־fopen או std::fstream::open לא יעבדו לי. אבל בסוף ייסורי מצפון הזיזו את כף־המאזניים: מספיק לכתוב קוד גרוע... והכנתי ספריית עזר קטנה, קראתי לה booster::nowide. כל מה שהיא עושה זה: להעביר ל־namespace שלך את הכלים סטנדרטיים שקיימים ב־stdio וב־STL בכל מערכות ההפעלה נורמליות. ובחלונות, היא פשוט עוטפת אתה API‏ ‎_w*‎ עם פונקציות משלה שממירות UTF-8 ל־UTF-16 ואז קוראות לפונקציות המתאימות.

בנוסף יצרתי מחלקות תואמות ל־std::fstream שעובדות מעל stdio (ועל הדרך סוף־סוף הבנתי כיצד לממש streambuf משלך).

התוצאה? אם אתה מתכוון לתמוך בחלונו, במקום לכתוב

std::ofstream f("שלום.txt")

שמייצרת ג'יבריש במקרה הטוב אתה כותב:

booster::nowide::ofstream f("שלום.txt")

וזה עובד בצורה שקופה, כנ"ל, std::fopen, std::freopen, std::remove, std::rename - רק החלף std::‎ ב־booster::nowide::‎.

במילים אחרות: no-more-wide-crap!

הספרייה היא חלק מ־booster של CppCMS ומופצת תחת רישיון Boost (משהו סגנון MIT). אם מישהו ירצה ספריה בלתי תלויה ב־booster, אז תגידו ואני אגזור אחת (לא מסובך בכלל).

קריאה נוספת: "Should UTF-16 be considered harmful?‎‏"

גרסת הספרית nowide התלויה בקומפיילר C++‎ לבלבד ניתנת להורדה כאן:
http://art-blog.no-ip.info/files/nowide.zip

ספריית Boost.Locale הוגשה לביקורת רשימית

ב־יום שני, 24 במאי 2010, מאת ארתיום; פורסם תחת: תכנה חופשית, פיתוח, תכנה ומחשבים, C++‎‏, Unicode, Boost‏; ‏0 תגובות

בשעה טובה, הגשתי את הספריית לוקליזציה Boost.Locale‏ לביקורת רשמית (formal review) של קהילת ה־Boost. אם היא תעבור אותה היא תתקבל כחלק רשמי של Boost.

קישורים:

אעדכן אתכם על התפתחויות בהמשך.

עדכון: זה רשמי -- Boost.Locale התווספה לרשימת הספריות הממתינות לביקורת. עכשיו צריך שמישהו מהקהילה יתנדב להיות מנהל הביקורת (review manager).

הוספת הקשר לתרגומי Gettext

ב־יום שני, 24 במאי 2010, מאת ארתיום; פורסם תחת: תכנה חופשית, פיתוח, תכנה ומחשבים, Unicode; ‏4 תגובות

אחת התכונות החסרות ביותר ב־gettext הייתה עד לא מזמן היא העדר אפשרות להעביר מידע על הקשר המילה. כך למשל, מילה "exchange" יכולה להיות מתורגמת ל"החלף" כשמדובר בחפצים ו"המר" כשמדובר בכסף. אבל אם שתי המילים מופיעות באותה תוכנה הדורשות תרגומים שונים בהקשרים שונים, ב־gettext לא הייתה שום דרך להבחין ביניהם.

החל מגרסה 0.15 התווספה התמיכה במה שנקרא הקשר. אם עד היום התרגום של מחרוזת "exchange" נעשה כ:

gettext("exchange");

אז הפונקציה pgettext מאפשרת להוסיף הקשר לתרגום:

pgettext("currency","exchange");

שיכולה להיות מתורגמת בצורה נכונה בכל הקשר. בקטלוג מחרוזות po הדוגמה הזו תופיע כ־

msgctxt "currency"
msgid "exchange"
msgstr "המר"

חשוב לזכור:

  • צריך להשתמש ב־gettext עדכני
  • צריך להשתמש בכלי תרגום עדכניים שיודעים לעבוד עם msgctxt.

    כך KBabel כלל לא תומך ב־msgctxt, ‏poedit לא מציג מידע על הקשר. עד כמה שידוע לי, גרסאות עדכניות של lokalize ו־gtranslator תומכות בהקשרים במילוני gettext.

כמובן שגם Boost.Locale תומך בהקשרים של Gettext.

שוחררה Boost.Locale

ב־יום שבת, 13 במרץ 2010, מאת ארתיום; פורסם תחת: תכנה חופשית, תכנה ומחשבים, C++‎‏, Unicode, Boost‏; ‏0 תגובות

שוחררה גרסה חדשה של הספריה שמיועדת ל־boost ‏‏Boost.Locale‏ (ראה הודעה ברשמת התפוצה של Boost‏):

הגרסה הזו מכילה את השיפורים הבאים:

  • תכנון מחדש של איטרטור גבולות (כלי המאפשר להפריד בין מילים, משפטים וכד').
  • התווספה תמיכה בעבודה עם תאריכים בלוחות שנה שונים כמו גרגוריאני (לועזי), עברי ואחרים. ראה דוגמה calendar.cpp‏ המדפיסה לוח שנה בהתאם ללוקל.
  • תיקוני באגים רבים.
  • תמיכה בפלטפורמות נוספות

ועוד.

הספרייה מספקת:

  • נורמליזציה של Unicode, טיפול נכון בשינוי case של מחרוזות.
  • מיון (collation) לפי 4 רמות unicode שונות.
  • טיפול אחיד בלוחות שנה שונים כמו, גרגוריאני (לועזי), עברי ואחרים
  • אנליזה של גבולות הטקסט (מילים, משפטים, תווים ועוד).
  • הדפסה של מספרים, תאריכים, ערכי כסף, איות מספרים ועוד.
  • פרמוט של מחרוזות המתאים ללוקליזציה ותרגום מחרוזות בעזרת מילונים של gettext.
  • תמיכה בקידודים שונים, utf-8/16/32 וקידודים אחרים כמו cp1255.

  • תיעוד: http://cppcms.sourceforge.net/boost_locale/html/index.html

  • הורדה: https://sourceforge.net/projects/cppcms/files/
  • מדריך מקיף: http://cppcms.sourceforge.net/boost_locale/html/tutorial.html

חשוב לציין

  1. Boost.Locale איננה חלק רשמי של Boost (בינתיים) ובתקווה תהפוך לכזו.
  2. היא לא מממשת את רוב כלי Uniode בעצמה אלא לרוב עוטפת API של ICU בצורה ידידותית למפתח C++‎.

תכירו Boost.Locale

ב־יום ראשון, 8 בנובמבר 2009, מאת ארתיום; פורסם תחת: תכנה חופשית, פיתוח, תכנה ומחשבים, C++‎‏, Unicode, Boost‏; תגובה אחת

אחרי תהיות עמוקות על תמיכה בלוקליזציה ב־C++‎, הבנתי שלא ניתן יהיה ללכת איתה רחוק. לקחתי ICU והתחלתי לעטוף אותו בסביבה ידידותית לתכנות C++‎ מודרני.

אחרי הרבה עבודה הבנתי... כל מה שאני עושה יהיה שימושי הרבה מעבר ל־CppCMS ולכן החלטתי להכין ספריה נפרדת שמטפלת בלוקליזציה במטרה לשלב אותה ב־Boost. כך נולד Boost.Locale שנותנת כלים פשוטים וחזקים לעבודה עם לוקליזציה.

דוגמה פשוטה שתבהיר את החשיבותה ועוצמתה. הנה קטע קוד שמציג למשל את תאריך המאמר באתר:

out << format(translate("{1}, posted  at {2,date} on {2,time} by {3}")) 
          % title % date % author;

ועכשיו המתרגם יכול לתרגם את המשפט לצורה הבאה:

"{1}, פורסם ב{2,locale=he_IL@calendar=hebrew,date} ‏(לועזי {2,date}) ב־{2,time} ע"י {3}"

מה קרה כאן? התצוגה באנגלית תהיה

‎Some article was published at 11/8/2009 on 10:30 PM by somebody

כאשר התצוגה בעברית תהיה

מאמר מסוים פורסם בכ"א בחשון התש"ע (לועזי 08/11/2009) ב־22:30 ע"י מישהו

למעשה, בלי שימוש ב־libhdate, בלי לעבוד קשה מידי, קיבלתי אפשרות להציג את התאריך העברי והלועזי לפי הלוקל העברי, רק בגלל ש־ICU תומך בלוח־השנה העברי.

למעשה, עבזרת Boost.Locale ניתן לעשות המון דברים בצורה פשוטה. למשל:

cout << as::spellout << 123 <<endl;

יידפיס בלוקל עברי

מאה עשרים ושלוש

יאפשר לחלק מילה "שָלוֹם" לארבעה תווים בהתחשב בניקוד: "שָ", "ל", "וֹ" ו־"ם" ועוד. למיין טקסט בצורה נכונה ועוד עשרות פעולות חשובות שניתנות ע"י ICU רק בצורה נוחה וטבעית ל־C++‎.

תכירו Boost.Locale:

תהנו, אשמח גם לתגובות.

העמוד הבא

העמוד הבא

דפים

נושאים