問題描述
我的問題很簡單,但我不知道如何解決.
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">
由于這些規則,required"屬性會自動添加到兩者中:
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.
食譜 > 數據庫訪問&ORM > 行為 > 翻譯 > 用另一種語言保存
將區域設置更改為默認設置是一種解決方法,但它可能有點過于具有侵入性,因為它會干擾使用該值檢查當前區域設置的任何代碼.最好直接在表上設置想要的locale
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
字段為name<選擇這些規則/code> 字段,我不知道這是否是它的工作方式.
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 AppModelTable;
use CakeDatasourceEntityInterface;
use CakeORMRulesChecker;
use CakeORMTable;
use CakeValidationValidator;
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;
}
}
配料表
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');
// ...
現在這些字段將選擇正確的驗證器,因此不會被標記為必需的.在創建/修補實體時也將應用驗證,最后也將應用應用程序規則.但是我不能保證這沒有任何副作用,因為內部的翻譯行為似乎沒有考慮到 _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)的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!