منبع اصلی نوشتار زیر در این لینک قرار دارد

Zend_Translate و GnuGetText

یکی از اصولی که سعی میکنم هنگام طراحی رعایت کنم، استفاده نکردن هرچه بیشتر!!! از زبان فارسیست. یعنی سعی میکنم تحت هیچ شرایطی توی کد حتی یک کلمه به زبانی غیر از انگلیسی، خصوصا فارسی ننویسم.

علت سادست، فارسی میتونه باعث مشکلات زیادی در زمان کد نویسی بشه خصوصا مشکلاتی که معمولا ویرایشگرهایی که من استفاده میکنم با این زبان دارن.
راه حل سادست، استفاده از سیستمهای مترجم، که من این وسط GnuGetText رو ترجیح میدم. اونم تازه اینکه مربوطه به گنو و منم تا گنو هست هیچ مشابهی رو استفاده نمیکنم، مهم نیست که چه امکاناتی ارایه میکنه!
توی این پست و پست بعدی قصد دارم در مورد این سیستم ترجمه و چگونگی اتصال اون با Zend Framework بنویسم. اول درمورد اینکه چطور این سیستم رو فعال کنیم و دوم اینکه چطور میشه قابلیتهاشو بیشتر کرد و یه سیستم ترجمه پویا هم ایجاد کرد خواهم نوشت.
اول از همه (معمولا تو bootstrap) باید یه شی ایجاد کنیم :

  define('LANGUAGE','fa_IR');
  $trans=new Zend_Translate("Zend_Translate_Adapter_Gettext",
                            "/path/to/language/".LANGUAGE.".mo",
                            LANGUAGE);

البته بستگی داره چه زبانی مد نظرتون باشه. به ازای هر زبان باید یه فایل با پسوند mo وجود داشته باشه (که مسیرش کاملش رو به عنوان آرگومان دوم به این سازنده فرستادیم.). حالا دو مساله پیش میاد. یکی اینکه چطور این فایل mo رو بسازیم. اینو میذارم برای یه کم پایینتر، مساله فعلا اینه که چطور از این شی که ساخته شده برای ترجمه استفاده کرد.
این شی trans (این یه عادت شخصیه من اسمشو میذارم trans تو همه پروژه هام اینه که اینجا هم همینکارو انجام میدم) رو بهتره توی Zend_Registry ثبتش کنیم.
مثلا اینطوری :

  Zend_Registry::set('trans',$trans);

البته مزایایی هست که این متغیر به اسم Zend_Translate ثبت بشه. در صورت ثبت به این اسم، بعضی از کلاسها مثل Zend_Form به صورت اتوماتیک استفاده میکنن ازش برای ترجمه فیلدها. ولی من ترجیح میدم به جای اینکه به Zend_Form اجازه بدم خودش به صورت اتوماتیک فیلدها رو ترجمه کنه خودم اونها رو ترجمه کنم و به Zend_Form بفرستم. (علتشو پایینتر میگم)
حالا هرجا بخوایم چیزی رو بفرستیم به خروجی (یا اصولا هر بار خواستیم جمله ای ترجمه داشته باشه) اینطوری عمل میکنیم :

  $trans=Zend_Registry('trans');
  
  echo $trans->_("This is untranslated text.");

یعنی به راحتی به جای اینکه متن رو بفرستیم به خروجی، اون رو از این فیلتر رد کنیم.
تابع translate هم وجود داره که تابع زیرخط در حقیقت اسم دیگه ای برای این تابع اصلی هست ولی استفاده از تابع زیرخط چون پارسر GetText اون رو به صورت Out of the box میشناسه، به نظر من بهتره.

سعی کنید تا ممکنه اینجوری اینکار رو انجام ندید :

  $trans=Zend_Registry('trans');
  $msg=  "This is untranslated text.";
  echo $trans->_($msg);

البته هیچ مشکلی وجود نداره از لحاظ برنامه نویسی، مشکل بیشتر مربوط میشه به پارسر GetText .
پارسر GetText معمولا میگرده دنبال تابع _ (زیرخط) و متنهای داخل اون رو برای ترجمه بیرون میکشه. به این ترتیب لزومی نداره که خودتون دستی متون رو به فایل ترجمه اضافه کنید.
دقیقا به همین دلیله که من دوست ندارم Zend_Form (یا هر کلاس دیگری) به صورت اتوماتیک از این شی استفاده کنه. چون در اون صورت مزایای پارسر GetText رو از دست میدم. حالا این پارسر GetText چی هست؟

برای این کار، برنامه PoEdit رو لازم دارید که نصب کنید. تقریبا در تمام دیستروهای لینوکس، این برنامه توی مخازن اصلی هست و به راحتی قابل نصبه. برای ویندوز هم به راحتی از سایت اصلیش قابل دانلود هست.
متاسفانه به خاطر اینکه Zend_Framework از پسوندهای مختلفی استفاده میکنه، باید یه کم تغییر توی تنظیمات PoEdit داده بشه. تنظیمات PoEdit رو از طریق منوی Edit->Prefrence انتخب کنید. توی تب Parsers از لیست زبانهای برنامه نویسی، PHP رو انتخاب کنید و دکمه Edit رو فشار بدید و تنظیمات رو مثل شکل زیر تغییر بدید:

تنظیمات PoEdit برای شناختن پسوندهای مختلف Zend

تنظیمات PoEdit برای شناختن پسوندهای مختلف Zend


یک کاتالوگ جدید ایجاد کنید.(تنظیماتش مشخصه، اسم و ایمیل و زبان و کشور رو انتخاب کنید کافیه. برای هر زبان یک کاتالوگ باید ایجاد بشه) بعد از ایجاد کاتالوگ اونو توی یک پوشه مناسب، همون جایی که باید فایل mo قرار بگیره و بالاتر توی ایجاد Zend_Translate به عنوان آرگومان دوم نوشتید ذخیره کنید. این فایل پسوندش po هست.

گام بعدی انتخاب فایلهای پروژه برای پارسر هست. وقتی کاتالوگ باز هست، از منوی کاتالوگ گزینه Settings رو انتخاب کنید و توی دیالوگی که مثل این هست، هم میتونید اسم مترجم و چیزهای دیگه رو بنویسید و هم اینکه توی تب Paths میتونید مسیرهایی که فایلهای پروژه شما توش قرار داره انتخاب کنید.میتونید از مسیرهای مطلق استفاده کنید یا اینکه به صورت نسبی مسیر بدید که اون انتخاب شماست مثلا :

تنظیمات کاتالوگ

تنظیمات کاتالوگ


همین. (اگه پروژه ای دارید که قبلا نوشتید و یا اینکه به هر دلیلی نمیخواید از تابع زیرخط استفاده کنید، از تب Keywords میتونید تابعی رو که به عنوان مترجم استفاده کردید رو اضافه کنید تا GetText اونها رو هم به رسمیت بشناسه.)
اگه قبلا پروژه رو ساختید و کارهایی که بالاتر گفتم انجام داده باشید، با انتخاب گزینه Update from sources توی منوی Catalogs یا با دکمه معادلش توی Toolbar خود برنامه اون مسیرهایی رو که انتخاب کردید رو میگرده و تمام جملات رو استخراج میکنه. جملات رو توی PoEdit ترجمه کنید، با فشردن دکمه Save فایل mo هم ساخته میشه. هر از چندگاهی با تغییر توی پروژه میتونید دوباره دکمه Update رو بزنید. خودش جملاتی که حذف شدن رو حذف میکنه، جملاتی رو که اضافه شدن اضافه میکنه.
البته حذف شده ها همچنان توی کاتالوگ po هستن، ولی داخل فایل mo نمیان. برای آپلود فایل، دیگه فایل po لازم نیست و فایل mo کفایت میکنه.
این روش مزایایی داره نسبت به روشهای دیگه که مهمترینشون همین پارسر اتوماتیکه که دیگه لازم نیست خودتون برای اضافه کردن هر جمله کاری رو انجام بدید. جمله اصلی که به زبان انگلیسی هست در صورتی که جمله ترجمه وجود ندارشته باشه نمایش داده میشه. کد کاملا دست نخورده میمونه و سرعتشم خوبه.
البته چند تا نکته کوچیک رو بد نیست رعایت کنید یکی اینکه ترجمه ها رو Cache کنید که اینکار هم به راحتی توسط Zend_Translate پشتیبانی میشه. برای اینکار :

  $cache = Zend_Cache::factory('Core',
	                             'File',
		                           $frontendOptions,
		                           $backendOptions);
  Zend_Translate::setCache($cache);

البته ایجاد Cache یکی از اون مواردیه که گاهی فکر میکنم دربارش بنویسم بد نیست :) خط اول کد بالا همین جوری کار نمیکنه :) باید خودتون $cache رو ایجاد کنید.(شک نکنید! Cache توی Zend یکی از واجباته!)
دفعه بعد درباره ایجاد یک آداپتور ساده صحبت میکنم که یه کم قابلیتهای این آداپتور اصلی رو بهتر میکنه.



برچسب ها : , , , , , , , ,