CakePHP 3.0.8翻译行为和数据验证(requirePresence,notEmpty) [英] CakePHP 3.0.8 translate behavior and data validation (requirePresence, notEmpty)

查看:433
本文介绍了CakePHP 3.0.8翻译行为和数据验证(requirePresence,notEmpty)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题很简单,但我不知道如何解决。

My problem is simple, yet I can't figure out how to solve it.

我的网站是多语言的。我想让用户能够添加多种语言的文章,如果他想要,同时要求他的语言(取决于他的语言环境)的输入。

My website is multilanguage. I want the user to be able to add an article in multiple language if he wants, while requiring the inputs of his language (depending on his locale).

问题是,有了CakePHP关于翻译的约定,所有的输入必须以字段的名称结束,不管使用什么语言。因此,所有字段对于相同字段具有相同的规则。

Problem is, with CakePHP's conventions about translation, all the inputs must end with the field's name, no matter what language. So all the fields has the same rule for the same field. I can't make one "name" required while another in another language not required.

例如,默认语言的输入将是:

For example, the default language's input would be:

<input type="text" name="name" required="required" maxlength="45" id="name">

下面是同一字段的另一种语言输入:

And below that, another language's input for the same field:

<input type="text" name="locales[fr_CA][name]" required="required" maxlength="45" id="locales-fr-ca-name">

由于以下规则,必需属性会自动添加到这两个属性中:

The "required" attribute is automatically added to both because of these rules:

$validator
    ->requirePresence('name', 'create')
    ->notEmpty('name')
    ->add('name', [
        'length' => [
            'rule' => ['minLength', 10],
            'message' => 'The title needs to be at least 10 characters long.',
        ]
    ]);

注意:当我保存时,我必须将区域设置更改为默认(en_US)保存多种语言+默认语言(否则默认输入保存在默认表和i18n表中)。

Note: I have to change the locale to the default (en_US) when I save to be able to save in multiple languages + the default language (otherwise the default inputs are saved in the default table AND in the i18n table).

if ($this->request->is('post')) {
    I18n::locale('en_US');
    // ......

编辑:所以这里是完整的代码当我保存(IngredientsController.php)

So here's the complete piece of code when I save (IngredientsController.php)

public function add() {
    $ingredient = $this->Ingredients->newEntity();
    if ($this->request->is('post')) {
        $ingredient = $this->Ingredients->patchEntity($ingredient, $this->request->data);

        if(isset($this->request->data['locales'])) {
            foreach ($this->request->data['locales'] as $lang => $data) {
                $ingredient->translation($lang)->set($data, ['guard' => false]);
            }
        }

        $locale = I18n::locale(); // At this point the locale is fr_CA (not de default)
        I18n::locale('en_US'); // Change the locale to the default

        if ($this->Ingredients->save($ingredient)) {
            $this->Flash->success(__('The ingredient has been saved.'));
            I18n::locale($locale); // Put the locale back to the user's locale
            return $this->redirect(['action' => 'index']);
        } else {
            I18n::locale($locale);
            $this->Flash->error(__('The ingredient could not be saved. Please, try again.'));
        }
    }

    $this->set(compact('ingredient'));
    $this->set('_serialize', ['ingredient']);
}



我设置默认语言环境是bootstrap.php

I set the default locale is the bootstrap.php

/**
 * Set the default locale. This controls how dates, number and currency is
 * formatted and sets the default language to use for translations.
 */
ini_set('intl.default_locale', 'en_US');
Configure::write('Config.locales', ['fr_CA']);

我在AppController.php中确定用户的区域设置

I determine the user's locale in the AppController.php

public function beforeFilter(Event $event)
{
    $locales = Configure::read('Config.locales');
    $boom = explode(',', str_replace('-', '_', $_SERVER['HTTP_ACCEPT_LANGUAGE']));
    $user_lang = substr($boom[0], 0, 2);

    // This piece of code is only to change the locale to fr_CA even if the user's language is just fr or fr_FR
    if(in_array($user_lang, Configure::read('Config.langs'))) {
        if(in_array($boom[0], $locales)) {
            I18n::locale($boom[0]);
        } else {
            foreach ($locales as $locale) {
                if(substr($locale, 0, 2) == $user_lang) {
                    I18n::locale($locale);
                }
            }
        }
    }

    $this->set('locales', $locales);
    $this->set('locale', I18n::locale());
}

所以如果我在不同的语言环境中保存,默认输入将保存在成分表和fr_CA中的i18n表中

So if I save while being in a different locale than the default, the same default inputs will be saved in the ingredients table AND in the i18n table in fr_CA

推荐答案

保存在翻译表中的默认值



默认语言的输入被存储在翻译表中,以防默认语言环境被改变,这似乎是预期的行为,就像读取数据时

Defaults saved in translation table

The fact that the input for the default language is being stored in the translation table in case the default locale has been changed, seems to be the expected behavior, just like when reading data where it will retrieve the data with respect to the current locale, the same applies when saving data.

Cookbook>数据库访问& ORM>行为>翻译>保存在其他语言

Cookbook > Database Access & ORM > Behaviours > Translate > Saving in Another Language

将区域设置更改为默认值是一种解决方法,但它可能有点太因为它会干扰使用该值检查当前语言环境的任何代码。最好是直接在表格上设置所需的区域设置

Changing the locale to the default is a workaround, but it might be a little too invasive, as it will interfer with any code that uses that value to check the current locale. It's better to directly set the desired locale on the table

$Ingredients->locale(I18n::defaultLocale());

或者是侵入性最小的选项。

or, which is the least invasive option, on the main entity instead

$ingredient->_locale = I18n::defaultLocale();

同样,前者是链接文档的描述,但实际上没有显示,固定。

Also the former is what the linked docs sesction is describing, but not actually showing, that needs to be fixed.

虽然我可以看到为什么表单助手实体上下文,拾取错误字段的验证规则,即 xyz.name 字段选择名称

While I can see why the form helper, respectively the entity context, picks up validation rules for the "wrong" fields, ie xyz.name fields pick up those for the name field, I can't tell whether this is how it is ment to work.

  • https://github.com/cakephp/cakephp/blob/3.0.10/src/View/Form/EntityContext.php#L394
  • https://github.com/cakephp/cakephp/blob/3.0.10/src/View/Form/EntityContext.php#L439

因为它不会拾取嵌套错误是预期的行为,但我不确定,所以我建议 建立问题在GitHub 。在任何情况下,有各种方法来解决这个问题,例如通过重命名字段,或通过将 required 选项设置为 false

Since it wouldn't pick up nested errors, I guess this is the expected behavior, but I'm not sure, so I'd suggest to create an issue over at GitHub for clarification. In any case, there are various ways to work around this, for example by renaming the fields, or by setting the required option to false.

echo $this->Form->input('locales.fr_CA.name', [
    // ...
    'required' => false
]);

在你的例子中,这几乎只是一个前端问题,因为字段不会实际

In your example this is pretty much just a frontend issue, as the fields are not going to be actually validated on the server side.

另一种选择是使用自定义翻译表类,具有特定于翻译的验证,实际上应用于使用的字段,但是这是

Another option would be to use a custom translation table class, with validation specific to translations, that actually apply to the used fields, however this is probably not that advisable unless you actually want to apply any validation at all.

为了完成,我们还要覆盖验证/应用程序规则。

For the sake of completion, let's cover validation/application rules too.

为了真正应用验证和/或应用程序规则,并且在表单中识别它们,您将使用一个保存规则的自定义翻译表类,并且您必须使用翻译行为用于 hasMany 关联的翻译表,其为 _i18n

In order to actually apply validation and/or application rules, and have them recognized in forms, you'll have use a custom translation table class that holds the rules, and you must use the actual property name that the translate behavior uses for the hasMany associated translation table, which is _i18n.

这是一个示例。

src / Model / Table / IngredientsI18nTable.php

namespace App\Model\Table;

use Cake\Datasource\EntityInterface;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;

class IngredientsI18nTable extends Table
{
    public function initialize(array $config) {
        $this->entityClass('Ingredient');
        $this->table('i18n');
        $this->displayField('id');
        $this->primaryKey('id');
    }

    public function validationDefault(Validator $validator) {

        $validator
            ->allowEmpty('name')
            ->add('name', 'valid', [
                'rule' => function ($value, $context) {
                    return false;
                }
            ]);
        return $validator;
    }

    public function buildRules(RulesChecker $rules)
    {
        $rules->add(
            function (EntityInterface $entity, $options) {
                return false;
            },
            'i18nName',
            [
                'errorField' => 'name'
            ]
        );

        return $rules;
    }
}

IngredientsTable >

IngredientsTable

public function initialize(array $config) {
    // ...

    $this->addBehavior('Translate', [
        // ...
        'translationTable' => 'IngredientsI18n'
    ]);
}

查看模板 b

echo $this->Form->hidden('_i18n.0.locale', ['value' => 'fr_FR']);
echo $this->Form->input('_i18n.0.name');

echo $this->Form->hidden('_i18n.1.locale', ['value' => 'da_DK']);
echo $this->Form->input('_i18n.1.name');

// ...

现在,字段将拾取正确的验证器,因此不会被标记为必需。还将在创建/修补实体时应用验证,并且最终应用规则也被应用。但是,我不能保证这没有任何副作用,因为Translate行为在内部似乎没有考虑到 _i18n 属性已设置的情况

Now the fields will pick up the correct validator, and thus are not being marked as required. Also validation will be applied when creating/patching entities, and finally application rules are being applied too. However I can't guarantee that this doesn't have any side effects, as the Translate behavior internally doesn't seem to account for the situation that the _i18n property has been set externally!

此外,您还必须使用 translations()在实体上设置翻译正确保存翻译!

Also you'll still have to set the translations on the entity using translations() in order for the translations to be saved correctly!

foreach ($this->request->data['_i18n'] as $translation) {
    $ingredient->translation($translation['locale'])->set('name', $translation['name']);
}

这篇关于CakePHP 3.0.8翻译行为和数据验证(requirePresence,notEmpty)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆