Thank you very much for your guide. I've solved I18N in a little different way, but you way is inspirational.
On 11 čvn, 11:49, "Christopher Schnell" <[email protected]> wrote: > Forgot to mention one thing. The objects __toString methods need to be able > to do some sort of language fallback like > > public function __toString() > { > // get the title in the current language > $title=$this->getTitle(); > > // maybe some other preferences here > //... > > // Last possibility: get the title in the first available language > if(empty($title)) > { > $cultures=sfConfig::get('sf_application_cultures'); > > for($i=0;$i<count($cultures['code']);$i++){ > if($this->getTitle($cultures['code'][$i])!=null) > { > $title=$this->getTitle($cultures['code'][$i]); > break; > } > } > } > > return $title; > } > > -----Ursprüngliche Nachricht----- > Von: [email protected] [mailto:[email protected]] > Im Auftrag von Christopher Schnell > Gesendet: Freitag, 11. Juni 2010 11:29 > An: [email protected] > Betreff: AW: [symfony-users] Re: Managing i18n content for frontend in the > backend > > Ok, here we go: > > Maybe I should explain the project a little: It is a system for managing > online E-Learning courses. It has several customers that can be assigned to > courses. The customers can manage their courses in coursecategories. Courses > and coursecategories have titles and descriptions which are translated. > Originally, we had German and English, so I did it the "Jobeet way". Then a > customer said, they wanted to also store the data also in Simplified Chinese. > Thats when I started to rebuild the translation system. Now, I have a system, > where i can simply add a language in my configuration file and be done with > it. Here is how it works: > > 1. in the apps settings.yml, I add the available cultures, like > ... > application_cultures: > code: [en, de, zh] > name: [English, Deutsch, Simp.Chinese] > > 2. In the schema.yml I have to set the "required" option for the translated > values to false, so that I won't get an error on saving the form. > > 3. Then, I had to write an custom validator, that validates that a title (or > any other mandatory field) is set in at least one language. > > In configure() of the main Form (not the I18n): > ... > $cultures=sfConfig::get('sf_application_cultures'); > > $this->embedI18n($cultures['code']); > for($i=0;$i<count($cultures['code']);$i++) > { > $this->widgetSchema->setLabel($cultures['code'][$i], > $cultures['name'][$i]);} > > $this->validatorSchema->setPostValidator( > new sfValidatorCallback(array('callback' => array($this, > 'validateOneTitle'))) > ); > ... > > And then write a method validateOneTitle() > public function validateOneTitle($validator, $values) > { > $cultures=sfConfig::get('sf_application_cultures'); > for($i=0;$i<count($cultures['code']);$i++) > { > if(!empty($values[$cultures['code'][$i]]['title'])) > { > return $values; > } > } > > throw new sfValidatorError($validator, 'You need to enter the title in the > language, you are editing.'); > > } > > That is all in the form class. > > Now we have to add a small filter form that can be used to trigger the ajax > call. It looks like this: > > class LanguageFilterForm extends BaseForm > { > public function configure() > { > $cultures=sfConfig::get('sf_application_cultures'); > > for($i=0;$i<count($cultures['code']);$i++){ > $mycultures[$cultures['code'][$i]]=$cultures['name'][$i]; > } > > $this->widgetSchema['languages']=new > sfWidgetFormSelect(array('choices'=>$mycultures)); > } > > } > > The more tricky parts are the template and the action class. Lets start with > the template: > In the editSuccess.php the div for the form that is reloaded by the ajax-call > is located. I do all my ajax-stuff with jquery. In my example, I use the form > for a above explained "Coursecategory". > > <div id="canvas"> > <img id="loader" src="/images/loader.gif" style="vertical-align: middle; > display: none" /> > <?php include_partial('form', > array('form'=>$form,'editingLanguageCode'=>$editingLanguageCode,'editingLanguageName'=>$editingLanguageName,'coursecategory'=>$coursecategory))?> > </div> > > <?php slot('col2_content') ?> > <?php include_partial('global/ajaxLanguageForm', > array('module'=>$sf_context->getModuleName(),'action'=>'edit','object'=>$coursecategory,'languageForm'=>$languageForm))?> > <?php end_slot() ?> > > We pass all the required data to the form partial (the form object, the > coursecategory object (which of course isn't nessessary, but "grown" code), > and the languagecode and name). > > The partial in the slot is a dropdownbox, that I include in all forms for > translated Objects, therefor it resides in the layout folder and gets the > module and action passed, as well as the LanguageFilterForm. The code of the > partial is like: > > <?php echo javascript_tag() ?> > $(document).ready(function() > { > $("#languages").change(function() > { > $('#loader').show(); > > var myLang=$(this).children('option:selected').val(); > $("#canvas").load( > $(this).parents('form').attr('action'), > { lang: myLang }, > function() { $('#loader').hide(); } > ); > });}); > > <?php end_javascript_tag() ?> > > <form action="<?php echo url_for($module.'/'.$action.(!$object->isNew() ? > '?id='.$object->getId() : '')) ?>" method="post"> > <?php echo $languageForm['languages']->renderError() ?> > <?php echo $languageForm['languages'] ?> > <?php echo $languageForm['_csrf_token']?> > </form> > > Now the form partial is still missing. I leave this code out, since it is a > little long. The important thing is that the form is not rendered by <?php > echo $form?> but as single form fields. I split the form into two partials, > one is the form with non translated values and the other is the form with > translations. So in the main form, I include: > > <?php include_partial('i18nForm', > array('form'=>$form,'editingLanguageCode'=>$editingLanguageCode));?> > > The I18nForm partial now needs to change the language code in the form fields > to store the translated values like: > > <tr> > <th> > <label for="coursecategory_<?php echo > $editingLanguageCode?>_title"><?php echo __('Title') ?> *</label> > </th> > <td> > <div class="error_message"><?php echo > $form[$editingLanguageCode]['title']->renderError() ?></div> > <?php echo $form[$editingLanguageCode]['title']->render(array('class' > => 'input')) ?> > </td> > </tr> > > Thats all in the templates, only the action is missing. Since i have to > process two forms (languageform and Objectform), I placed the form creation > code in a separate method. Most of the code is pretty standard. > > public function executeNew(sfWebRequest $request) > { > $this->getForms($request->getParameter('lang')); > } > > public function executeCreate(sfWebRequest $request) > { > $this->forward404Unless($request->isMethod(sfRequest::POST)); > > $this->getForms($request->getParameter('lang')); > > $this->processForm($request, $this->form); > > $this->setTemplate('new'); > } > > /** > * Edit a Coursecategory > * > * @param sfWebRequest $request A request object > */ > public function executeEdit(sfWebRequest $request) > { > > $this->coursecategory=CoursecategoryPeer::retrieveByPk($request->getParameter('id')); > > $this->getForms($request->getParameter('lang'),$this->coursecategory); > > if($request->isXmlHttpRequest()) > { > return $this->renderPartial('coursecategory/form', array('form' => > $this->form,'coursecategory'=>$this->coursecategory,'editingLanguageCode'=>$this->editingLanguageCode,'editingLanguageName'=>$this->editingLanguageName)); > } > } > > public function executeUpdate(sfWebRequest $request) > { > $this->forward404Unless($request->isMethod(sfRequest::POST) || > $request->isMethod(sfRequest::PUT)); > $this->forward404Unless($Coursecategory = > CoursecategoryPeer::retrieveByPk($request->getParameter('id')), > sprintf('Object Coursecategory does not exist (%s).', > $request->getParameter('id'))); > > $this->getForms($request->getParameter('lang'),$Coursecategory); > > $this->processForm($request, $this->form); > > $this->setTemplate('edit'); > } > > protected function processForm(sfWebRequest $request, sfForm $form) > { > $form->bind($request->getParameter($form->getName()), > $request->getFiles($form->getName())); > if ($form->isValid()) > { > $this->getUser()->setFlash('notice', 'Coursecategory saved > successfully.'); > $Coursecategory = $form->save(); > > $this->redirect('@coursecategory'); > } > } > > protected function getForms($lang=null,$coursecategory=null) > { > $editingLanguage=$this->getUser()->getEditingLanguage($lang); > $this->editingLanguageCode=$editingLanguage['code']; > $this->editingLanguageName=$editingLanguage['name']; > > $this->form = new CoursecategoryForm($coursecategory); > > $this->languageForm=new LanguageFilterForm(); > $this->languageForm->setDefault('languages',$this->editingLanguageCode); > } > > Last thing, I forgot was that the default language should be the one, the > user selected for himself, so that is the call to > this->getUser()->getEditingLanguage($lang); > > In myUser.class.php > > public function getEditingLanguage($lang=null) > { > $cultures=sfConfig::get('sf_application_cultures'); > > $editingLanguage['code']=$this->getCulture(); > > if(!is_null($lang)) > { > $editingLanguage['code']=$lang; > } > > for($i=0;$i<count($cultures['code']);$i++){ > if($cultures['code'][$i]==$editingLanguage['code']) > { > $editingLanguage['name']=$cultures['name'][$i]; > } > } > > return $editingLanguage; > } > > That's all, I hope I didn't forget anything. If anything is unclear, feel > free to ask. Here is also some screenshot of the > form:http://www.mda.ch/lms/Bildschirmfoto.pnghttp://www.mda.ch/lms/Bildschirmfoto-1.png > > Regards, > Christopher. > > -----Ursprüngliche Nachricht----- > Von: [email protected] [mailto:[email protected]] > Im Auftrag von Tom Ptacnik > Gesendet: Donnerstag, 10. Juni 2010 10:10 > An: symfony users > Betreff: [symfony-users] Re: Managing i18n content for frontend in the backend > > I prefer codewise, but if you can show me also how it look in action, > I don't ... > > číst dál » -- If you want to report a vulnerability issue on symfony, please send it to security at symfony-project.com You received this message because you are subscribed to the Google Groups "symfony users" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/symfony-users?hl=en
