【问题标题】:CakePHP 3.1: Validation for translate behaviour fields (i18n)CakePHP 3.1:翻译行为字段的验证 (i18n)
【发布时间】:2015-10-02 20:20:27
【问题描述】:

我正在尝试使用 CakePHP translate behaviour 添加一个包含多个翻译的项目以一种形式

如何验证翻译字段?是否需要特定语言?

假设您有一个简单的items 表和一个separate translations table items_i18n,按照书中的描述进行设置。作为一个简单的例子,items 表只有一个字段title 要翻译,我想用五种语言保存title。所以我做了一个这样的表格(在add视图模板中):

echo $this->Form->create($item, ['controller' => 'Items', 'action' => 'add']);
echo $this->Form->input('title', ['label' => __('English')]);
echo $this->Form->input('_translations.es.title', ['label' => __('Spanish')]);
echo $this->Form->input('_translations.fr.title', ['label' => __('French')]);
echo $this->Form->input('_translations.de.title', ['label' => __('German')]);
echo $this->Form->input('_translations.it.title', ['label' => __('Italian')]);
echo $this->Form->button(__('Save'), ['type' => 'submit']);
echo $this->Form->end();

并像这样保存在控制器(add action/function)中:

$item = $this->Items->newEntity();
if ($this->request->is('post')) {
  $translations = [
    'es' => ['title' => $this->request->data['_translations']['es']['title']],
    'fr' => ['title' => $this->request->data['_translations']['fr']['title']],
    'de' => ['title' => $this->request->data['_translations']['de']['title']],
    'it' => ['title' => $this->request->data['_translations']['it']['title']],
  ];
  foreach ($translations as $lang => $data) {
    $item->translation($lang)->set($data, ['guard' => false]);
  }
  $item = $this->Items->patchEntity($item, $this->request->data, ['validate' => 'default'] );
  if ( $this->Items->save($item) ) { $this->Flash->success(__('Saved.')); }
  else { $this->Flash->error(__('Not saved.')); }
}
$this->set('item', $item);

这是在没有验证的情况下工作,或者如果我只有“本机”title 字段的验证规则(应该,我简化了 stackoverflow 的代码并为示例重命名了一些部分,所以可能有一些拼写错误,但你应该明白...)。

现在让我们进一步假设语言英语(默认)和西班牙语必需的,其他语言字段是可选的。我怎样才能做到这一点?

ItemsTable 中,我尝试了类似的方法进行验证:

class ItemsTable extends Table {
  public function validationDefault(Validator $validator) {
    $validator
      // Title English (default field)
      ->requirePresence('title')
      ->notEmpty('title', __('Required field'))
      // Title Spanish (translate behaviour field)
      ->requirePresence('_translations.es.title')
      ->notEmpty('_translations.es.title', __('Required field'))
      ;
    return $validator;
  }
}

但这总是会带来验证错误“此字段是必需的”,因为patchEntity($item, $this->request->data); 会导致翻译被丢弃。我通过一个公开的issue on GitHub 知道这一点,关于保存工作流程(顺便说一句,此请求 +1 :)。

所以目前我不确定在使用 CakePHP 翻译行为时是否有办法为翻译字段定义验证规则... 必填 语言字段只是一个例子,同样的问题也会发生如果你想验证例如外语输入字段的最小/最大长度...

【问题讨论】:

标签: validation cakephp internationalization multilingual cakephp-3.1


【解决方案1】:

好的,我想我找到了解决方案。至少是暂时的,因为我还发现了一个带有 NestedValidatorFormHelperissue

目前验证仍适用于所有其他语言。所以这不是我想要的,也不是最终的答案。如果您知道如何将验证应用于单一语言,请发表评论或回答。

所以这是我目前使用CakePHP 3.1.1的中间解决方案:

在表类中为 i18n 翻译字段添加 nested validator

这些嵌套验证规则将适用于所有其他语言字段,因为它们在$this->request->data['_translations'] 中分组在一起:

class ItemsTable extends Table {
  public function validationDefault(Validator $validator) {
    $validator
      // Title English (default language)
      ->requirePresence('title')
      ->notEmpty('title')
      ->add('title', [
          'minLength'=>['rule'=>['minLength', 2], 'message' => __('MinLength 2')],
          'maxLength'=>['rule'=>['maxLength', 255], 'message' => __('MaxLength 255')],
          ])
      ;
      // Nested Validation for i18n fields (Translate Behaviour)
      // These rules will apply to all 'title' fields in all additional languages
      $translationValidator = new Validator();
      $translationValidator
        ->requirePresence('title', 'false') // I want translation to be optional
        ->allowEmpty('title') // I want translation to be optional
        ->add('title', [
          'minLength'=>['rule'=>['minLength', 5], 'message' => __('MinLength 5')],
          'maxLength'=>['rule'=>['maxLength', 255], 'message' => __('MaxLength 255')],
          ])
      ;
      // Now apply the nested validator to the "main" validation
      // ('_translations' is containing the translated input data)
      $validator
        ->addNestedMany('_translations', $translationValidator)
        // To prevent "field is required" for the "_translations" data
        ->requirePresence('_translations', 'false')
        ->allowEmpty('_translations')
        ;
    return $validator;
  }
}

在我的测试设置中,我希望翻译字段是可选的,并将其他 minLength 作为默认语言。正如您在上面的代码中看到的,我添加了allowEmpty 并将requirePresence 设置为false 用于翻译字段。目前TranslateBehaviour 仍然强制要求翻译title 字段。所以我在添加/编辑表单的翻译输入字段中额外添加了'required' => false

echo $this->Form->input('_translations.es.title', ['required' => false]);

现在将单独的验证规则应用于翻译字段,如调试结果所示(在测试时临时添加到控制器中):

$item = $this->Items->patchEntity($item, $this->request->data);
debug($item);

当您在输入字段中仅输入一个字符时,minLength 错误消息在调试错误数组中可用。

但目前FormHelper不支持嵌套错误消息。我报告了这个issue on GitHub。在表单中显示错误的临时解决方案是手动检查error 数组。为此,请添加控制器:

$item = $this->Items->patchEntity($item, $this->request->data);
if ( !$item->errors() ) {
  foreach ($this->request->data['_translations'] as $lang => $data) {
    $item->translation($lang)->set($data, ['guard' => false]);  
  }
}
// Temp workaround for issue#7532:
else {
  $this->set('formerrors', $language->errors()); 
}

在添加/编辑视图中,您可以检查和使用额外的$formerrors 数组:

if ( isset($formerrors['_translations']['es']['title']) ) { ... }

answer to this question 中显示了另一种有趣的方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-31
    • 1970-01-01
    • 2013-12-01
    • 2012-11-11
    • 2018-03-05
    • 1970-01-01
    • 2013-07-09
    • 2015-10-27
    相关资源
    最近更新 更多