如何本地化Symfony2表单?

4

我有一个Symfony2表单,用户可以输入地址,目前地址格式是固定的,由于我们想要为软件提供国际化支持,因此我正在寻找最好的方法来实现SF中的国际化。

与其制作一个通用的地址类型,我们想将表单本地化,同时保留不支持语言环境的通用格式作为备选方案。

我想要将布局和本地化(顺序、分组、标签、翻译、必填和可选字段)与表单处理(PHP/SF)和实际呈现(TWIG)分开。

我的解决方案是:从数据库模型创建一个地址表单类型,其中包含所有可能的字段。通过调用form_widget(form)自动在TWIG中呈现此表单类型,或根据需要呈现单个字段。最后;以某种配置格式(YML、数组等)定义表单的“布局”,并扩展默认的TWIG表单呈现方式,以迭代在该配置中定义的表单元素。

例如,荷兰和美国的地址配置如下:

- NL-nl
  - [firstname, infix, lastname]
  - [street1, number]
  - [postcode, city]
- EN-us
  - [fullname]
  - [street1]
  - [street2]
  - [city, state]
  - [zip]

接下来我们将在此配置中添加本地化标签、类、可选和必填字段等。

目前我们的一个大问题是:将此配置放在哪里?在 finishView 类中使用一个简单的数组?把配置放在一个YML文件中,由需要本地化表单布局的表单类型进行解析?

非常感谢遇到过此问题的人提供任何信息。

2个回答

3
稍后我们将向此配置中添加本地化标签、类、可选和必填字段等内容。 本地化标签是自动处理的,可以根据用户的语言环境进行翻译和转换。强制字段可以使用约束来解决。
这个配置应该直接放在实体和表单类型中:
您可以创建一个 LocaleAddressType 并根据当前“语言环境”值添加这些字段,但首先需要有一个包含所有与“地址”相关的可能字段的实体。 LocaleAddress 实体:
// src/AppBundle/Entity/LocaleAddress.php

use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Table()
 * @ORM\Entity()
 */
class LocaleAddress
{
    /**
     * @var string
     *
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @Assert\NotBlank(groups={"nl-NL", ...})
     * @ORM\Column(type="string", nullable=true)
     */
    private $firstName;

    // ...
}

包括所有可能的区域设置和使用nullable=true来设置所有唯一的字段。此外,使用NotBlank约束和groups选项来验证每个区域设置的必填字段。

配置文件

# AppBundle/Resources/config/locale_address_form.yml
address_form:
   nl-NL:
      - [firstname, infix, lastname]
      - [street1, number]
      - [postcode, city]
   en-US:
      - [fullname]
      - [street1]
      - [street2]
      - [city, state]
      - [zip]

复合LocaleAddressType根据locale选项添加一些字段, 默认情况下为Locale::getDefault()

// src/AppBundle/Form/Type/LocaleAddressType.php

class LocaleAddressType extends AbstractType
{ 
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $config = $this->loadLocaleFormConfig($options['locale']);

        foreach ($config as $fields) {
            foreach (fields as $field) {
                $builder->add($field);
            }
        }
    }

    public function buildView(FormView $view, FormInterface $form, array $options)
    {
        $view->vars['config'] = $this->loadLocaleFormConfig($options['locale']);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => 'AppBundle\Entity\LocaleAddress',
            'locale', \Locale::getDefault(),
        ]);

        // force that validation groups will equal to configured locale.
        $resolver->setNormalizer('validation_groups', function (Options $options) {
            return [$options['locale']];
        });

        $resolver->setAllowedTypes('locale', ['string']);

        // pending validate the custom locale value.
    }

    private function loadLocaleFormConfig($locale) 
    {
        $config = Yaml::parse(file_get_contents('path/to/locale_address_form.yml'));

        return $config['address_form'][$locale];        
    }
}

注意:在提交时,该字段将根据locale值进行验证。

注册表单类型:

# app/config/services.yml
services:
    app.form.locale_address:
        class: AppBundle\Form\Type\LocaleAddressType
        tags:
            - { name: form.type }

使用表单

现在,您可以在其他表单中使用此表单类型,并与localeAddress字段相关联。

$build->add('localeAddress', LocaleAddressType::class);

当您更改应用程序中的语言环境\Locale::setDefault,这会影响表单字段的显示。

为字段创建模板

我希望将表单布局和本地化(顺序、分组、标签、翻译、必填和可选字段)与表单处理(PHP/SF)和实际渲染(TWIG)分开。

{% block locale_address_widget %}
    {% for fields in config %}
        <div class="row">
        {% set n = 12 // fields|length %}
        {% for field in fields %}
            <div class="col-md-{{ n }}">
                {{ form_row(form[field]) }}
            </div>
        {% endfor %}
        </div>
    {% endfor %}
{% endblock %}

这段代码基于Symfony3。


如果您需要用于Symfony2 < 2.8,请告诉我,我会更改答案。 - yceruto
我们实际上使用的是2.7,但我认为你提供的解决方案不是我们正在寻找的。如果我们为世界上的每个200多个国家创建本地化表单,那么这个开关将会非常巨大并且充满了冗余代码。当然,我们可以将冗余部分移动到帮助程序或其他地方,但问题仍然存在:我们将在哪里定义表单元素的布局?我们仍然相信,在一个单一的表单类型中定义所有可能的值,并根据配置中描述的语言环境进行呈现,是最清晰的方法。重要的问题是:在哪里以及如何进行配置? - Dreamdealer
你可以创建一个像你所描述的 config yml 文件,并在表单类型中加载它,然后确保只加载当前语言环境的配置,接下来,在表单构建器中添加相应的字段。另一方面,在你的 twig 布局中,传递相同的语言环境配置,并使用 .col-md-N 类来创建内联输入和 .row 来创建新行。 - yceruto

0

有很多选择:

  • 您可以为每个国家创建不同的表单类型
  • 您可以创建一个包含所有字段的表单类型,然后使用表单事件删除与当前选择的国家无关的字段
  • 您可以为每个国家创建不同的视图和一个大型表单类型

第二个选项是我们想要构建的。但是有一点不同,因为我们还需要定义布局(顺序等),分组(名字和姓氏内联),约束(邮政编码!)以及其他自定义内容,例如触发特定JS绑定的类等。 - Dreamdealer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接