אתר עם שפה

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

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

התחלתי בכך שיצרתי יחידה אחת שכל התפקיד שלה זה לטפל בשפות, כולל להחזיק את המחרוזות השונות באמצעות ResourceString.

הרבה אנשים אשר רגילים לשיטות אחרות מאשר ResourceString, לא אוהבים את השיטה, היות ושם אני מדבר עם "קבועים" במקום עם טקסטים. אבל אני דווקא מוצא את הגישה הזו טובה יותר, היות ודבר ראשון, אנחנו מספקים שמות אשר מסבירים מה כל הודעה אמורה להיות פחות או יותר, ודבר שני, כאשר משתמשים בתרגום טקסט מתוך טקסט (כמו מרבית השיטות האחרות), אז מה קורה כאשר הטקסט שלו השתנה, כמו רווח בין פסיקים או אפילו שגיאת כתיב ? התשובה היא תרגום חדש שיש לבצע, בעוד שבשיטה של ResourceString יש תמיד אחידות, ולמעשה הרבה פעמים פחות מחרוזות זהות שיש צורך לתרגם בשל כך. ועוד יותר, הגישה של ResourceString אינה מוגבלת לשיטת תרגום כזו או אחרת, ונראה איך זה מתבצע עוד מעט:

unit untResourceString;

interface
...
resourcestring
  rsIsBidi        = 'no';
  rsHeader   = 'Hello World';
  rsFooter    = 'Thank you for visiting the web site.';
  rsError500 = 'Server error #500';
...
function LoadLanguage(const Lang, Default : String) : Boolean;
...
implementation
uses sysutils, gettext ...;
...
function LoadLanguage ( const Lang, Default : String ) : Boolean;
var
  MainFile    : String;
  DefaultFile : String;
  MoFile      : TMOFile;
begin
  if not DirectoryExists(LanguageDir) then
    Exit(False);

  MainFile    := LanguageDir + Lang    + '.mo';
  DefaultFile := LanguageDir + Default + '.mo';

  if FileExists(MainFile)                   then
     begin
       MoFile         := TMOFile.Create(MainFile);
       ActiveLanguage := Lang;
     end
  else if FileExists(DefaultFile)           then
    begin
      MoFile         := TMOFile.Create(DefaultFile);
      ActiveLanguage := Default;
    end
  else
    Exit(False);

  try
    try
     TranslateResourceStrings(MoFile);
     Result := True;
    except
      Result := False;
    end;
  finally
    MoFile.Free;
  end;
end;
...

הגישה שבחרתי כאן היא שיש לי שפה שאני רוצה שתהיה פעילה, במידה ואין לה קובץ תרגום, אני אשתמש בשפה שהגדרתי כfallback ואם אין לי קובץ אליה, הוא ישתמש בתוכן של הResourceString עצמו. עוד החלטתי, לטעון ידנית את קובץ ה mo, ולהגיד לו לתרגם לבד את הResourceString. אבל זו לא הדרך היחידה לטעון קבצי mo, ביחידה שאני משתמש בה. כל מה שנשאר עכשיו, הוא לגרום לכך שיהיה לנו תרגום בזמן רציה. כלומר כאשר אנחנו מקבלים בקשה מסויימת, אנחנו צריכים למצוא מה השפה של המשתמש, לטעון את התרגום המתאים ויש לנו אתר אשר תומך במגוון שפות בצורה הבאה:

procedure TSite_Main.DataModuleRequest ( Sender : TObject;
              ARequest : TRequest; AResponse : TResponse; var Handled : Boolean ) ;
var
  LangLoaded : Boolean;
begin
  Session.TimeOutMinutes := DefaultSessionTimeout;
  LangLoaded := LoadLanguage(Session.Variables['lang'], DefaultLanguage);
  Session.Variables['lang'] := ActiveLanguage;

  if FileExists(TemplatePath + 'main_template.html') then
    begin
      ModuleTemplate.FileName            := TemplatePath + 'main_template.html';
      SetTemplate(ModuleTemplate);
      AResponse.Content                  := ModuleTemplate.GetContent;
    end
  else begin
     AResponse.Content := Format(rsErrorHTML,[rsError500, rsError500, rsErrorReason,
     rsErrorNoTemplate]);

    AResponse.Code    := 500;
  end;

  Handled := true;
end;

וזהו,  הCGI שלנו מתורגם כולל תמיכה ביותר מ fallback אחד, לפי התכנון שאני יצרתי כאן. כאמור להגיע לגישה הזו לקח לי כ10 דקות עבודה, ועכשיו שאתם רואים את זה מולכם, יקח לכם מספר דקות קטן יותר.

כאשר נהדר את ה CGI שלנו, נקבל גם קובץ בשם untresourcestring.rst. הקובץ הוא הקובץ לתרגום שלנו. אנחנו נשתמש עכשיו בתוכנה שמגיעה עם FPC אשר תמיר אותו לקובץ po:


$ rstconv -f po -i untresourcestring.rst -o en_us.po

ועכשיו יצרנו קובץ בשם en_us.po שהוא קובץ po להמדרין. כל מה שנשאר זה להדר את התרגום שלנו לקובץ mo, ויש לנו תרגום מוכן.

להשאיר תגובה

הזינו את פרטיכם בטופס, או לחצו על אחד מהאייקונים כדי להשתמש בחשבון קיים:

הלוגו של WordPress.com

אתה מגיב באמצעות חשבון WordPress.com שלך. לצאת מהמערכת / לשנות )

תמונת Twitter

אתה מגיב באמצעות חשבון Twitter שלך. לצאת מהמערכת / לשנות )

תמונת Facebook

אתה מגיב באמצעות חשבון Facebook שלך. לצאת מהמערכת / לשנות )

תמונת גוגל פלוס

אתה מגיב באמצעות חשבון Google+ שלך. לצאת מהמערכת / לשנות )

מתחבר ל-%s