Translate select options in Symfony2 class forms - forms

I'm using a class form in Symfony2 Beta3 as follows:
namespace Partners\FrontendBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class ConfigForm extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('no_containers', 'choice', array('choices' => array(1 => 'yes', 0 => 'no')));
...
I want to translate the 'yes' and 'no' options, but I don't know how to use the translator here.

You can use the translation resources as usual. This worked for me:
$builder->add('sex', 'choice', array(
'choices' => array(
1 => 'profile.show.sex.male',
2 => 'profile.show.sex.female',
),
'required' => false,
'label' => 'profile.show.sex.label',
'translation_domain' => 'AcmeUserBundle'
));
And then add your translations to the Resources->translations directory of your Bundle.
Update from #CptSadface:
In symfony 2.7, using the choice_label argument, you can specify the translation domain like this:
'choice_label' => 'typeName',
'choice_translation_domain' => 'messages',
Without specifying the domain, options are not translated.

I searched a while to find an answer, but finally I found out how Symfony translates form content. The easiest way in your case seems to be to just add a translation for "yes" and "no" by adding a YAML or XLIFF translation file to your application (e.g. app/Resources/translations/messages.de.yml) or your bundle. This is described here:
http://symfony.com/doc/current/book/translation.html
The problem - in my opinion - is that you don't seem to be able to use custom translation keys. The guys from FOSUserBundle solve this (or a similar) problem with "Form Themes" (http://symfony.com/doc/2.0/cookbook/form/form_customization.html). Here are two significant lines of code to achieve the usage of the form element id as translation key:
https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Resources/views/Registration/register_content.html.twig#L1 / https://github.com/FriendsOfSymfony/FOSUserBundle/blob/50ab4d8fdfd324c1e722cb982e685abdc111be0b/Resources/views/form.html.twig#L4
By adding a Form Theme you're able to modify pretty much everything of the forms in the templates - this seems to be the right way of doing this.
(Sorry, I had to split two of the links b/c I don't have enough reputation to post more than two links. Sad.)

In symfony 2.7, using the choice_label argument, you can specify the translation domain like this:
'choice_label' => 'typeName',
'choice_translation_domain' => 'messages',
Without specifying the domain, options are not translated.

CptSadface's answer was what helped me with translating my entity choices.
$builder
->add(
'authorizationRoles',
null,
[
'label' => 'app.user.fields.authorization_roles',
'multiple' => true,
'choice_label' => 'name', // entity field storing your translation key
'choice_translation_domain' => 'messages',
]
);

Related

How to have the placeholder translated in an EntityType?

I'm building a form which has an EntityType element, the problem I have is that I'm unable to have the placeholder translated.
Here is my code:
$builder
->add('Products', EntityType::class, [
'mapped' => false,
'expanded' => true,
'multiple' => false,
'required' => false,
'class' => Product::class,
'choices' => $options['step']->getProducts(),
'placeholder' => 'form.mat.alreadyOwned',
'label' => 'form.mat.alreadyOwned',
'translation_domain' => 'messages'
])
When I use the form.mat.alreadyOwnedtranslation as the label it works fine, but I would like to use it in the placeholder instead. What am I missing?
Looking forward to any tips or tricks that you have to offer!
[UPDATE]
As pointed out by #gp_sflover I'm not trying to replace the general placeholder, but the one for the empty value. This one only appears if you set required to false.
After some research and thought, the places where the placeholder is actually used are quite limited in number (as it should be). However, specific placeholder translation is not a special case (sadly).
For every choice in a ChoiceType a ChoiceView is added. Also for the placeholder a ChoiceView is added, that inherits the options of the form (which is a somewhat sensible choice for the ChoiceType), including the translation_domain parameter, which indicates that the choices shall be translated (all of them). There's also a reference in some twig template that specifically manages the translation in the twig bridge for non-expanded choice types. However, those don't open up a specific best practices answer on how to specifically handle translations for the placeholder in the ChoiceType.
For the EntityType, this doesn't change.
So there are a few approaches, some of which might be absolutely utility-free ...
translate the placeholder right there when building the form
Although this is conceptually not the most beautiful option, IMHO it's still the most practical one. Essentially, in Symfony 4 forms can receive dependencies in their constructor via auto-wiring, so injecting a TranslatorInterface will open up the ability to translate the placeholder with the requests locale (which is automatically set for the translator via event listener):
public function __construct(TranslatorInterface $translator) {
$this->translator = $translator;
}
and in your buildForm you can then use it to translate the placeholder
$builder
->add('Products', EntityType::class, [
'mapped' => false,
'expanded' => true,
'multiple' => false,
'required' => false,
'class' => Product::class,
'choices' => $options['step']->getProducts(),
'placeholder' => $this->translator->trans('form.mat.alreadyOwned'), // <-- change
'label' => 'form.mat.alreadyOwned',
'translation_domain' => 'messages'
])
not to withhold the other options, which in my opinion are almost all overkill...
set a choice_translation_domain for all entries, including placeholder
obviously, this can and probably will lead to problems, if there ever is an entity that whose choice label matches the key in the translator ... and it is not intended for translation. but it will translate the placeholder with the very same translation_domain ...
adapt the form rendering and check for the placeholder
this is problematic, since you have to assign the form theme/form rendering to all relevant forms. the placeholder does have a unique name ('placeholder', who would have thought) so it could very well be used to achieve that goal. However, setting a different translation domain could very much be challenging. (if you attempt this, it's a bit of a nuisance)
write your own entity type (optionally adding own form rendering)
theoretically, you could create your own EntityType and handle the placeholder properly there. like ... adding a translation domain to the choice view and sub form and what not. For inspiration/reference consult the ChoiceType, EntityType and DoctrineType (parent type).

Symfony - Combine two properties in a single entity form field

I have an entity for publications with many different fields as booktitle, conference etc. I want to build a search form and one of the feature requests is to combine two search parameters in a single choice field. So far I have something like this in the form builder:
$builder->add('booktitle', 'entity', array(
'required' => false,
'label' => 'Conference/Booktitle',
'property' => 'booktitle',
'class' => 'indPubBundle:Publication',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('p')
->groupBy('p.booktitle')
->orderBy('p.booktitle', 'ASC');
}
));
Basically I am displaying all booktitles as a choice field. What I want now is to have the conferences as well in the same choice field. Is there a way to achieve that?
The Entity field type is a child of the Choice field type. So you can provide Data via the "choices" parameter. Combine that with a (e.g. repository) method that returns an array with the data you need might be a solution that works for you.
$builder->add('booktitle', 'entity', array(
'required' => false,
'label' => 'Conference/Booktitle',
'class' => 'indPubBundle:Publication',
'choices' => $this->getDoctrine()->getRepository('indPubBundle:Publication')->getData(),
));

Disable some checkboxes in form

I was wondering if there is an easy way of how to disable one checkbox from modifying it by user (Symfony 2.1). I was trying something like this:
$builder->add('adminRoles', 'entity', array(
'property' => 'roleName',
'class' => 'MyBundle:Role',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('r')
->orderBy('r.roleName', 'ASC');
},
'disabled' => $this->disabledRoles,
'expanded' => true,
'multiple' => true
));
By $this->disabledRoles I meant an array of IDs of Role entities or entities themselves, but it seems that it just accepts boolean value which is applied for all entities (checkboxes). Thanks for your advice :-)
You will need to add a form listener in order to customize individual elements.
http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html
It might seem like a lot of work but it's easy enough once you work through the examples. You will end up passing disabledRoles to the listener and then setting the disabled flag accordingly.

How to use the ChoiceListInterface in Symfony 2?

I'd like to display a dynamic list of checkboxes in a form.
So far, I built a form embedding a static list of checkboxes, and I created a Tag entity for different values in different languages and populated the database. I'd like to replace the static checkboxes by a dynamic list based on the Tag entity.
The documentation says I should use the ChoiceListInterface. But it is really poorly documented. Would you have an example or a global logic explanation to help me ?
You can extend LazyChoiceList abstract class and implement loadChoiceList() method, create a service of it, inject it to the form and set it as choice_list option.
Finally, I used an entity field type :
->add('tags', 'entity', array(
'class' => 'bndMyBundle:Tag',
'query_builder' => function(EntityRepository $er){
return $er->createQueryBuilder('t')
->orderBy('t.en', 'ASC');
},
'expanded' => true,
'multiple' => true,
'property' => 'en',
))
Then, I just need to replace the 'en' value by the user's current locale to choose the right language.

How to make own frontend-Forms with Magento 1.6.2

I have make a little Extension for Magento 1.6.2. I managed to write code in the backend-system to create a EAV Model to the database and I can write/read items from it like this tutorial: http://www.pierrefay.com/magento-admin-gridview-85
How can I use the following Forms in the frontendsystem, .. I have see there are dont classes like Mage_Adminhtml_Block_Widget_Form. I dont want to use own HTML constructions, want to get I want Magento look and feel. Have anyone a idea how to make own forms in magento frontend with magento classes?
class Extension_Name_Adminhtml_Printcatalog_Edit_General_Form extends Mage_Adminhtml_Block_Widget_Form
{
protected function _prepareForm()
{
$form = new Varien_Data_Form();
$this->setForm($form);
$fieldset = $form->addFieldset('printcatalog_form',
array( 'legend' => __('Allgemeine Informationen')));
$fieldset->addField('catalog_name', 'text',
array(
'label' => __('Katalogname'),
'class' => 'required-entry',
'required' => true,
'name' => 'catalog_name',
));
$fieldset->addField('release_date', 'text',
array(
'label' => __('Erscheinungsdatum'),
'class' => 'required-entry',
'required' => true,
'name' => 'release_date',
// 'image' => Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_SKIN).'/adminhtml/default/default/images/grid-cal.gif',
// 'format' =>
Mage::app()->getLocale()->getDateFormat(Mage_Core_Model_Locale::FORMAT_TYPE_SHORT),
));
if (Mage::registry('printcatalog_data'))
{
$form->setValues(Mage::registry('printcatalog_data')->getData());
}
return parent::_prepareForm();
}
}
?>
Not possible out of the box, all magento front-end forms are hard coded. As you can see in the class you provided it is part of the Adminhtml module (Mage_Adminhtml_Block_Widget_Form), which is for the administration dashboard within magento.
The amount of development to integrate a form class like in your code is not worth the time or flexibility of a hardcoded front-end form ... in most cases. If the majority of your continued development revolved around forms, then I'd reconsider building out abstract form classes to help in the creation of your forms via the controller.
On a higher note, Magento does provide a fairly decent javascript validation system for your front-end.
You should look into Zend_Form, which came around after Magento/Varien's original form implementation.