לא, סתם. WPML מצוין ואני לא חושב שצריך להחליף אותו. לבנות חלופה ל-WPML לוקח זמן ומבזבז משאבים, בטח שכשבשווי שעתיים עבודה משיגים את הדבר הכי טוב. אבל לפעמים WPML הוא מרצדס כשבסך הכל צריך אופניים. רוצים לעשות אתר דו או תלת שפתי ובמקום להשתמש במינימום כלים ומינימום משאבים, הולכים על טנק שאוכל גם הרבה דלק (זכרון + כח שרת) וגם הרבה לוגיקה מסובכת שרק מקשה.

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

  1. הראשון הוא ה-DB, כאן מדובר בבלוקים מותאמים לשפה שעל פי לוגיקה מסויימת נטענים פר שפה (WPML ספציפים מקדיש לכל שפה פוסט נפרד, qTranslate מקדיש לכל שפה אלמנט במערך של שדה מותאם אישית).
  2. השני הוא מערך key-value שמאוחסן בדרך כלל בטבלה ב-DB או בקובץ (וורדפרס משתמשים במנגנון gettext של GNU שמאחסן את הצמדים בקבצי mo מקומפלים על פי קבצי po שניתנים לעריכה בתוכנה בשם poedit).

במקרה השני פניה למפתח מסוים (בעזרת הפונקציות __ ו- _e) תתן לנו את התרגום שלו בערך המתאים, כאשר הפניה למערך המתאים תתבצע על פי ה-locale המוגדר באותו רגע. כלומר, אם מדובר בצרפתית הקונוונציה היא לגשת לקובץ שנמצא בתיקיה מיוחדת לקבצי שפה, ולקובץ שנקרא בשם דומיין מסוים ובשם locale מסוים (של עברית: he_IL, אנגלית: en_US, צרפתית fr_FR וכו').

הן בשל הנוחות והן בגלל שזהו best practice וכבר מוטמע בליבה של וורדפרס, אדגים שימוש ב-gettext. יכול להיות שבהזדמנות אחרת אתן דוגמא של התאמת משאבים בין אנדרואיד לדוגמה לוורדפרס – באנדרואיד משתמשים בקבצי xml, ואדגים איך מייבאים קבצי xml לתוך טבלה בדאטהבייס של מפתחות-ערכים כשכל עמודה היא שפה (או יותר נכון שתי טבלאות, אחת של מפתח פר ID והשניה של ערכים פר ID).

השלב הראשון הוא להגדיר תיקיה מיוחדת לשפות. המוסכמה היא לשים אותה בתיקיה בשם languages. אני נוהג לשים אותה בתיקיה מיוחדת שאני קורא לה resources שנמצאת או בתיקיית השורש של התבנית או בתוך ה-views. ניתן לשים אותה איפה שרוצים, ואפילו בתיקיית ה-languages תחת wp-content על מנת שכל קבצי השפה כולל אלה של הליבה יאוחסנו באותו המקום. כאמור, אני מעדיף לרכז את הכל ולדעתי כך נכון, בתוך ה-sandbox של התבנית, הווה אומר רק במקום שהפונקציה locate_template יכולה לגשת אליו (תיקיית השורש של התבנית ובנותיה).

בתוך תיקיה זו אציב כאמור את כל קבצי השפה שלי, אני נוהג גם לשים את קובץ ה-pot שם על מנת שיתאפשר לי לשכפל את המערכים של צמדי המפתח-ערך, וכן את קבצי ה-po על מנת שאוכל להשתמש בתוסף בשם codestyling-localization ולערוך מתוך ממשק האדמין את המחרוזות הקיימות.

השלב השני הוא להגדיר פילטר מיוחד שיסנן לי על פי פרמטר מסוים את ה-locale המתאים. בעקרון, ניתן לחסוך את השימוש ב-setter של ה-locale בעזרת הפילטר locale המוגדר מראש, ולכן אחיל פונקציה מיוחדת שממירה את הפרמטר GET לערך locale חדש. כך אוכל לגשת בעזרת פרמטר לכל שפה. במקרה שלי בחרתי את הפרמטר l, ולכן אגש באמצעות www.example.com/?l=en לשער האנגלי שלי, אם המערכת המותקנת היא בעברית (דוגמא חיהכאןלמרות שהאתר באנגלית לא מתוחזק בכלל). הקוד להלן:

add_action('after_setup_theme', 'setLanguagesFolder');
add_filter( 'locale', 'addLocaleFilter' );

function setLanguagesFolder(){
    load_theme_textdomain( 'domain', get_template_directory().'/resources/languages' );
}


function addLocaleFilter( $locale )
{
	if ( isset( $_GET['l'] ) )
	{                
		return esc_attr( $_GET['l'] );
	}

	return $locale;
}

בשלב זה אני מסוגל לעשות שני דברים:
א. לסלק מהקוד כל טקסט מפורש. כל הטקסטים מרוכזים לי בחלק המיוחד למחרוזות.
ב. לאפשר להגדיר locale חלופי לזה הדפולטיבי שמוגדר לי ב-wp-config.php (כלומר הקבוע WPֹ_LANG)

ההערה החשובה ביותר היא:
מאחר שאני מעוניין להגדיר פונקציה שמחזירה ערך על פי מפתח, בסגנון getString, והפונקציה המיוחדת שדולה מהקבצים ( __ ) לא יכולה לקבל משתנים, אני חייב לכתוב מראש בקובץ מיוחד את כל המחרוזות שארצה ואיזה מפתח אשייך אליהם. הסיבה: כשהמחולל יסרוק את הקוד הוא צריך להסתמך על קוד מסוים בו המחרוזות כתובות באופן מפורש. בשל העובדה שאני לא רוצה לשים את המחרוזות בתוך ה-html אלא לקרוא לפונקציה המיוחדת, הדבר הכרחי לי. אגדיר קובץ בשם strings.php ובו אגדיר מערך strings, כאשר בכל שורה מוגדר $strings['key']==__('domain','value')

function getString($key)
{
return $strings[$key];
}

האפשרות הזו מכסה רק את הפתרון הראשון שמציע WPML, של הצגת מחרוזות מותאמות שפה. אם רוצים אלמנטים שונים, הבעיה גם פתירה מפני שאפשר להתנות הצגת אלמנטים בפרמטר ה-GET שמופיע בעמוד. אך מה עושים אם רוצים להציע עמודים שונים לשפות שונות? במקרה הזה אני נוהג בשיטה שונה במקצת. ב-WPML כאמור מתאימים פרמטר מסוים, אני מניח שבאמצעות טבלה מיוחדת שמאחסנת התאמות של עמודים ובה כל שורה מכילה כמה עמודות שבכל עמודה יש את ה-ID המתאים של הפוסט בטבלה wp_posts, או לחלופין כל פוסט מכיל שדה מותאם אישית שבו כתוב לאיזו שפה משתייך אותו העמוד. כשרוצים להעלות אוטומטית עמודים משפה מסויימת שולפים על פי שאילתא שמתחשבת בעמודה (במקרה של טבלה) או בשדה מותאם אישית (במקרה של הפתרון השני). ב-qTranslate כאמור פותחים שדה תוכן נוסף עבור כל שפה, ואז בהתאם לשפה שולפים את תוכן השדה המתאים – גם בשיטה זו אני מעדיף לא להשתמש.

השיטה המועדפת עלי היא פונקציה שבודקת בעזרת שאילתא פשוטה של query אם קיים עמוד עם slug זהה לעמוד שלי, רק עם תוספת ה-locale. כלומר, אם קראתי למזהה של העמוד שאני רוצה לטעון page1, ואני רוצה לטעון תוכן באנגלית מפוסט אחר, אגדיר את הפוסט החלופי עם מזהה בשם page1-en, ואבדוק בשאילתא, אם קיבלתי תוצאות. משהו בסגנון:

function getTranslatedPost($posttype,$slug,$locale)
{
     $argsUnTranslated = array (
	  'pagename'               => $slug,
          'post_type'              => $posttype,
      );

      $argsTranslated = array (
	   'pagename'               => $slug.'-'.$locale,
	   'post_type'              => $posttype,
       );

       $myposts = get_posts( $argsTranslated );
       if(count($myposts))
           return $myposts[0];
        else
           return get_posts($argsUnTranslated )[0];

         wp_reset_postdata();
}

אגב, פונקציות דומות ניתן לעשות גם לתמונות שרוצים להציג פר-שפה. מחפשים אם קיים קובץ בשם זהה עם סיומת זהה, רק שבסוף שם הקובץ יש את ה-locale. במידה וכן, לוקחים את התמונה שנמצאה, במידה ולא לוקחים את התמונה המקורית. זאת כמובן כשאת התמונות לא מעלים דרך מנהל המדיה, או לפחות לא בצורה כזאת שאי אפשר לדאוג שבאותה הספריה יהיו כמה תמונות בעלות שמות זהים עם הבדל locale.

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *