0

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

如何验证翻译字段?例如,需要特定的语言?

假设您有一个简单的items表,其中包含一个单独的翻译表 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动作/功能)中:

$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);会导致翻译被丢弃。我通过GitHub 上关于保存工作流程的一个未解决的问题知道这一点(顺便说一句,此请求 +1 :)。

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

4

1 回答 1

1

好的,我想我找到了解决方案。至少是暂时的,因为我还发现了NestedValidatorFormHelper问题

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

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

在表类中为 i18n 翻译字段添加一个嵌套验证器。

这些嵌套验证规则将适用于所有其他语言字段,因为它们组合在一起$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不支持嵌套错误消息。在 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']) ) { ... }

另一种有趣的方法显示在对这个问题的回答中

于 2015-10-11T21:09:54.070 回答