上下文: 我想使用 CakePhp 创建一个应该可翻译的 Web 应用程序。我想在一个表单中保存同一字段的多个翻译。
问题: 我已经尝试了十几种方法来让它工作,我做到了。但我最终使用了两个自定义 SQL 查询,这真的不像 cakePhp 解决方案。
问题: 有人知道实现相同结果的更好方法吗?
我尝试了什么:
为表单字段指定一个名称,如“Model.fieldName.locale”,这会在输入元素的名称属性中为其提供正确的格式,但我的验证无法识别该字段名称。但保存有效。
为表单字段提供一个名称,如“modelLocale”,并传入一个名称属性“data[Model][field][locale]”,在这种情况下,验证有效,但 isUnique 除外,但保存到数据库不会'工作。
更多变体但不值得一提。
我将在下面添加我的 View 和模型:(如果您想查看更多代码或需要更多信息,请询问)
/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'
),
),
);
}
?>
注意:关于这个主题的信息不多......我对翻译行为有很多问题,比如在正确的语言环境中也获得递归结果,.. . 任何人都知道一个好的 tut 或信息来源(食谱非常有限)
感谢阅读!!
最佳答案
看来您可能正在构建某种 CRM,允许用户根据他们设置的语言创建可读入网站的内容。我会使用内置的 i18n and l10n .它使它变得非常简单,但这可能不是动态内容的解决方案。
话虽如此,我能想到的唯一其他方法非常乏味。我会构建一个带有语言标识符下拉菜单的屏幕。因此,我不会尝试在同一屏幕中为每种语言塞满所有语言,而是创建一个表单,然后使用该语言的下拉菜单。
您的模型使用列来定义行所属的语言。您创建的表格在一行中表达所有语言。因此,如果您要查看显示记录的索引页面,您当然会看到:
title 1 eng
title 1 dut
title 1 fre
title 2 eng
title 2 dut
title 2 fre
...
此外,如果您要添加一种新语言,您将不得不修改模型和表单中的验证。
但是,如果您打算这样做,请更改 | to _ and off you go。但是随后您需要将所有数据存储在一条记录中。因此,当您查看记录的索引时,您会看到:
title 1 end dut fre
title 2 end dut fre
...
我的建议:
1) 通过 .po/.pot 文件使用内置的 i18n/l10n。
2) 如果内容会经常更改并且需要存储在数据库中以便可以轻松地频繁更改/更新,则使用下拉列表。
Language: dropdown
Title: text_field
关于mysql - CakePhp TranslateBehavior,验证并保存多个语言环境,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8985582/