Gary Pegeot
Gary Pegeot

Reputation: 23

Translate custom form type in symfony2

I'm trying to create a custom form type in Symfony (2.7), in order to add an help_block (Boostrap 3 style) to some of my forms fields.

I followed this page instructions : http://symfony.com/doc/current/cookbook/form/create_form_type_extension.html

Displaying is OK, help_block works fine, but it is not translatable, (dev bar not showing any missing translation). So there is my question : How can I make a custom form type translatable, like the label option, and if possible, in the same translation_domain than the form?

Here is the extension code:

<?php

namespace WIC\MasterBundle\Form\Extension;

use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\OptionsResolver\OptionsResolver;

/**
 * Add a BootStrap Help block to any form field
 */
class HelpTextExtension extends AbstractTypeExtension
{

    /**
     * Returns the name of the type being extended.
     *
     * @return string The name of the type being extended
     */
    public function getExtendedType() {
        return 'form';
    }

    /**
     * Add the help_text option
     *
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver) {
        $resolver->setDefined(array('help_text'));
        $resolver->setDefault('help', null);
    }

    /**
     * Pass the Help Text to the view
     *
     * @param FormView $view
     * @param FormInterface $form
     * @param array $options
     */
    public function buildView(FormView $view, FormInterface $form, array $options) {
        $view->vars['help_text'] = $form->getConfig()->getAttribute('help_text');
    }

    public function buildForm(FormBuilderInterface $builder, array $options) {
        if (array_key_exists('help_text', $options)) {
            $builder->setAttribute('help_text', $options['help_text']);
        }
    }

}

And my template override:

{% extends 'bootstrap_3_horizontal_layout.html.twig' %}

{% block form_row -%}
    {% spaceless %}
        <div class="form-group{% if (not compound or force_error|default(false)) and not valid %} has-error{% endif %}">
            {{ form_label(form) }}
            <div class="{{ block('form_group_class') }}">
                {{ form_widget(form) }}
                {{ form_errors(form) }}
                {% if help_text is not null %}
                    <span class="help-block">{{ help_text }}</span>
                {% endif %}
            </div>
        </div>
    {% endspaceless %}
{%- endblock form_row %}

Thanks in advance for any help,

Best regards

Upvotes: 1

Views: 10016

Answers (2)

Frank B
Frank B

Reputation: 3697

a) set locale parameter and enable translation in config.yml

parameters:
    locale: en

framework:
    #esi:             ~
    translator:      { fallbacks: ["%locale%"] }

b) create custom form type. I created the GenderType from the docs.

c) extend the custom form type with a constructor to get access to the translator and use the translater where you want to:

namespace AppBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Translation\Translator;

class GenderType extends AbstractType
{
    private $translator;

    public function __construct(Translator $translator)
    {
        $this->translator = $translator;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'choices' => array(
                'm' => $this->translator->trans('user.male'),
                'f' => $this->translator->trans('user.female'),
            )
        ));
    }

    public function getParent()
    {
        return 'choice';
    }

    public function getName()
    {
        return 'gender';
    }
}

d) Create your Field Type as a Service

// app/config/services.yml
services:
    app.form.type.gender:
        class: AppBundle\Form\Type\GenderType
        arguments:
            - @translator.default
        tags:
            - { name: form.type, alias: gender }

e) Create a translationfile:

// src/AppBundle/Resources/translations/user.en.yml
user:
    creation: Create User
    gender: Gender
    male: Male
    female: Female

f) Extend your formType (e.g. UserType). Make sure that you pass the fieldtype by the 'gender' service-alias that you created at step d. Also set the label and the translation_domain options for each field.

// src/AppBundle/Form/UserType.php
namespace AppBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use AppBundle\Form\Type\GenderType;

class UserType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('gender', 'gender', array('label' => 'user.gender', 'translation_domain' => 'user'))
            // and more fields
        ;
    }

    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle\Entity\User'
        ));
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'appbundle_user';
    }
}

g) add trans_default_domain to your twig templates and translate whatever you want to translate. Example:

{% extends '::base.html.twig' %}

{% trans_default_domain 'user' %}

{% block body -%}
    <h1>{{ 'user.creation'|trans }}</h1>

    {{ form(form) }}

{% endblock %}

Upvotes: 1

nakashu
nakashu

Reputation: 1068

You can add translations like in other places, just fill the label.

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('title', 'text', [
            'label' => 'rpr.page.title', // <- any string can be there
        ]);
}

The default translation domain is 'messages', to change add 'translation_domain' to you configureOptions

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults([
       'data_class'         => 'Acme\Entity\DemoEntity',
       'translation_domain' => 'forms'
    ]);
}

Of course you then need to create the translation files in the right place: AcmeBundle\Resources\translations

Important things to note: - when you create new translation files in your AcmeBundle\Resources\translations like forms.de.yml you need to clear the cache even in development.

docs here: http://symfony.com/doc/current/reference/forms/types/form.html#translation-domain

Upvotes: 6

Related Questions