Контекст: Я хочу создать веб-приложение с использованием CakePhp, которое должно быть переводимым. Я хочу сохранить несколько переводов для одного и того же поля в одной форме.CakePhp TranslateBehavior, подтвердите и сохраните несколько локалей
Проблема: Я пробовал дюжину способов заставить это работать, и я это сделал. Но в итоге я использовал два пользовательских SQL-запроса, которые действительно не похожи на решение cakePhp.
Вопрос: Кто-нибудь знает лучший способ добиться того же результата?
Что я пробовал:
Придание формы поля имя, как «Model.fieldName.locale», что дает ему правильный формат имени атр входного элемента, а затем мой проверки не распознает имя поля. Но спасательные работы.
Придавая форме поля имя типа 'modelLocale' и передавайте имя attr 'data [Model] [field] [locale]', в этом случае проверка выполняется за исключением isUnique, но сохранение в базе данных не делает ' т работы.
Другие варианты этого, но не стоит упоминать.
Я добавлю вид и модель ниже: (если и хотят, чтобы увидеть больше кода или нужно больше информации просто спросите)
/App/View/Category/add.ctp
<?php echo $this->Form->create(); ?>
<?php echo $this->Form->input('title|dut'); ?>
<?php echo $this->Form->input('title|eng'); ?>
<?php echo $this->Form->input('title|fre'); ?>
<?php echo $this->Form->input('description|dut', array('type'=>'textarea')); ?>
<?php echo $this->Form->input('description|eng', array('type'=>'textarea')); ?>
<?php echo $this->Form->input('description|fre', array('type'=>'textarea')); ?>
<?php echo $this->Form->end('add'); ?>
/App/Model/AppModel.php
<?php
App::uses('Model', 'Model');
class AppModel extends Model {
/**
* Check Unique
*
* Searches the i18n table to determine wetter a field is unique or not.
* Expects field name to be as following: "fieldname|locale".
*
* @param array $data The data of the field, automatically passed trough by cakePhp.
* @param string $field The name of the field, which should match the one in the view.
* @returns boolean
*/
public function checkUnique($data, $field) {
// Seperate the field key and locale which are seperated by "|".
$a = preg_split('/[|]/', $field, 2);
// If field key and locale are found...
if (is_array($a) || count($a) === 2) {
$q = sprintf("SELECT * FROM i18n WHERE i18n.locale = '%s' AND i18n.model = '%s' AND i18n.field = '%s' AND i18n.content = '%s' LIMIT 1",
Sanitize::escape($a[1]),
Sanitize::escape(strtolower($this->name)),
Sanitize::escape($a[0]),
Sanitize::escape($data[$field])
);
if ($this->query($q)) {
return false;
}
return true;
}
}
/**
* Setup Translation
*
* Loops trough the fields. If a field is translatable
* (which it will know by it's structure [fieldname]|[locale])
* and has the default locale. Then it's value will be stored
* in the array where cake expects it
* (data[Model][fieldname] instead of data[Model][fieldname|defaultLocale])
* so that cake will save it to the database.
*
* In the afterSave method the translations will be saved, for then we know
* the lastInsertId which is also the foreign_key of the i18n table.
*/
public function _setupTranslations() {
foreach($this->data[$this->name] as $key => $value) {
$a = preg_split('/[|]/', $key, 2);
if (is_array($a) && count($a) === 2) {
$languages = Configure::read('Config.languages');
if ($a[1] === $languages[Configure::read('Config.defaultLanguage')]['locale']) {
$this->data[$this->name][$a[0]] = $value;
}
}
}
}
/**
* Save Translations
*
* Saves the translations to the i18n database.
* Expects form fields with translations to have
* following structure: [fieldname]|[locale] (ex. title|eng, title|fre, ...).
*/
public function _saveTranslations() {
foreach($this->data[$this->name] as $key => $value) {
$a = preg_split('/[|]/', $key, 2);
if (is_array($a) && count($a) === 2) {
$q = sprintf("INSERT INTO i18n (locale, model, foreign_key, field, content) VALUES ('%s', '%s', '%s', '%s', '%s')",
Sanitize::escape($a[1]),
Sanitize::escape(strtolower($this->name)),
Sanitize::escape($this->id),
Sanitize::escape($a[0]),
Sanitize::escape($value)
);
$this->query($q);
}
}
}
/**
* Before Save
*/
public function beforeSave() {
$this->_setupTranslations();
return true;
}
/**
* After Save
*/
public function afterSave() {
$this->_saveTranslations();
return true;
}
}
/App/Model/Category.php
<?php
class Category extends AppModel {
public $name = 'Category';
public $hasMany = array(
'Item'=>array(
'className'=>'Item',
'foreignKey'=>'category_id',
'order'=>'Item.title ASC'
)
);
var $actsAs = array(
'Translate'=>array(
'title',
'description'
)
);
public $validate = array(
'title|dut'=>array(
'required'=>array(
'rule'=>'notEmpty',
'message'=>'Veld verplicht'
),
'unique'=>array(
'rule'=>array('checkUnique', 'title|dut'),
'message'=>'Titel reeds in gebruik'
),
),
'title|eng'=>array(
'required'=>array(
'rule'=>'notEmpty',
'message'=>'Veld verplicht'
),
'unique'=>array(
'rule'=>array('checkUnique', 'title|eng'),
'message'=>'Titel reeds in gebruik'
),
),
'title|fre'=>array(
'required'=>array(
'rule'=>'notEmpty',
'message'=>'Veld verplicht'
),
'unique'=>array(
'rule'=>array('checkUnique', 'title|fre'),
'message'=>'Titel reeds in gebruik'
),
),
);
}
?>
ПРИМЕЧАНИЕ: Существует не так много информации, там на эту тему ... У меня есть намного больше вопросов о поведении перевода, как получение рекурсивные результаты также в правильной локали, ... Кто-нибудь знает хорошую информацию или источник информации (поваренная книга весьма ограничена)
Спасибо за чтение !!
Спасибо, я уже использую файлы .po для нединамического контента. И да, используя выбранный вход для языка, это обычный способ сделать это, но так как есть только два поля, которые нуждаются в переводе, и они всегда нуждаются в переводе, я настроен на выполнение одной формы. Я предполагаю, что использование двух пользовательских запросов - это не большая жертва ... Было просто интересно, есть ли лучшее решение. Я как бы ожидал большего от поведения Translate. –