CakePHP 3.0.8翻译行为和数据验证(Requirementence,notEmpty)
我的问题很简单,但我不知道如何解决它 我的网站是多语言的。我希望用户能够添加多种语言的文章,如果他愿意的话,同时需要输入他的语言(取决于他的语言环境) 问题是,根据CakePHP关于翻译的约定,所有输入都必须以字段名称结尾,不管是哪种语言。因此,所有字段对同一字段都有相同的规则。我不能让一个“名字”是必需的,而另一个用另一种语言的则不是必需的 例如,默认语言的输入为:CakePHP 3.0.8翻译行为和数据验证(Requirementence,notEmpty),php,validation,cakephp,internationalization,cakephp-3.0,Php,Validation,Cakephp,Internationalization,Cakephp 3.0,我的问题很简单,但我不知道如何解决它 我的网站是多语言的。我希望用户能够添加多种语言的文章,如果他愿意的话,同时需要输入他的语言(取决于他的语言环境) 问题是,根据CakePHP关于翻译的约定,所有输入都必须以字段名称结尾,不管是哪种语言。因此,所有字段对同一字段都有相同的规则。我不能让一个“名字”是必需的,而另一个用另一种语言的则不是必需的 例如,默认语言的输入为: <input type="text" name="name" required="required" maxlength=
<input type="text" name="name" required="required" maxlength="45" id="name">
注意:我必须在保存时将区域设置更改为默认设置(en_US),以便能够以多种语言+默认语言进行保存(否则,默认输入将保存在默认表和i18n表中)
编辑:下面是我保存时的完整代码(IngredientsController.php)
我设置的默认区域设置是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中确定用户的区域设置
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']);
}
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表中
默认语言的输入被存储在翻译表中,以防默认语言环境发生更改,这似乎是预期的行为,就像在读取数据时,它将根据当前语言环境检索数据一样,保存数据时也是如此
将区域设置更改为默认值是一种变通方法,但可能有点太过侵入性,因为它会干扰使用该值检查当前区域设置的任何代码。最好直接在表上设置所需的区域设置
$Ingredients->locale(I18n::defaultLocale());
或者,这是侵入性最小的选项,改为在主实体上
$ingredient->_locale = I18n::defaultLocale();
另外,前者是需要修复的LinkedDocs sesection正在描述但没有实际显示的内容
拾取“错误”验证规则的字段
虽然我可以理解为什么表单助手(分别是实体上下文)会为“错误”字段(即xyz.name
字段)选择验证规则,但我无法判断这是否是有效的
required
选项设置为false
echo $this->Form->input('locales.fr_CA.name', [
// ...
'required' => false
]);
在您的示例中,这几乎只是一个前端问题,因为字段不会在服务器端进行实际验证
另一种选择是使用自定义翻译表类,该类具有特定于翻译的验证,实际应用于所使用的字段,但是这可能并不可取,除非您确实希望应用任何验证
将验证/应用规则应用于已翻译的列
为了完整起见,我们还将讨论验证/应用程序规则
为了实际应用验证和/或应用程序规则,并在表单中识别它们,必须使用保存规则的自定义翻译表类,并且必须使用翻译行为用于hasMany
关联翻译表的实际属性名称,即\u 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;
}
}
InCreditStable
public function initialize(array $config) {
// ...
$this->addBehavior('Translate', [
// ...
'translationTable' => 'IngredientsI18n'
]);
}
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');
// ...
查看模板
public function initialize(array $config) {
// ...
$this->addBehavior('Translate', [
// ...
'translationTable' => 'IngredientsI18n'
]);
}
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');
// ...
现在,字段将选择正确的验证器,因此不会按要求标记。此外,在创建/修补实体时将应用验证,最后也将应用应用程序规则。但是,我不能保证这不会有任何副作用,因为内部的翻译行为似乎无法解释外部设置了\u i18n
属性的情况
此外,为了正确保存翻译,您还必须使用translations()
在实体上设置翻译
foreach ($this->request->data['_i18n'] as $translation) {
$ingredient->translation($translation['locale'])->set('name', $translation['name']);
}
不幸的是,带有验证和形式的翻译似乎有点过于复杂;(无论如何,在不更改区域设置的情况下保存两次的默认语言听起来很可疑,你能添加完整的保存代码,以及为你的应用程序/用户设置/更改(默认)区域设置的代码吗?啊,好的,明白了。我稍后回到我的机器后会发布答案。。。
foreach ($this->request->data['_i18n'] as $translation) {
$ingredient->translation($translation['locale'])->set('name', $translation['name']);
}