【问题标题】:CakePhp TranslateBehavior, validate and save multiple localeCakePhp TranslateBehavior,验证和保存多个语言环境
【发布时间】:2012-01-28 00:40:52
【问题描述】:

背景: 我想使用应该可翻译的 CakePhp 创建一个 Web 应用程序。我想在一个表单中保存同一字段的多个翻译。

问题: 我已经尝试了十几种方法来让它工作,我做到了。但我最终使用了两个自定义 SQL 查询,这真的不像 cakePhp 解决方案。

问题: 有没有人知道达到相同结果的更好方法?

我尝试了什么:

  • 将表单字段命名为“Model.fieldName.locale”之类的名称,这样可以在输入元素的名称 attr 中为其提供正确的格式,但随后我的验证无法识别字段名称。但保存有效。

  • 为表单字段命名为“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'
      ),
    ),
  );
}
?>

注意:关于这个主题的信息并不多......我还有很多关于翻译行为的问题,比如在正确的语言环境中获得递归结果,.. . 任何人都知道一个好的 tut 或信息来源(食谱非常有限)

感谢阅读!!

【问题讨论】:

    标签: mysql cakephp behavior cakephp-2.0 translate


    【解决方案1】:

    看来您可能正在构建某种类型的 CRM,它允许用户根据他们设置的语言建立可读入网站的内容。我会使用内置的i18n and l10n。它使它变得非常简单,但这可能不是动态内容的解决方案。

    话虽如此,但我能想到的唯一其他方法是非常乏味的。我将构建一个带有语言标识符下拉菜单的屏幕。因此,我不会尝试将所有语言都塞进同一个屏幕并为每种语言设置一个测试框,而是创建一个表单,然后使用该语言的下拉菜单。

    您的模型使用列来定义行所属的语言。您创建的表单在一行中表示所有语言。因此,如果您要查看显示记录的索引页面,您当然会看到:

    title 1 eng
    title 1 dut
    title 1 fre
    title 2 eng
    title 2 dut
    title 2 fre
    ...
    

    此外,如果您要添加新语言,则必须修改模型和表单中的验证。

    但是,如果您打算这样做,请更改 |到_然后离开。但是,您需要将所有数据存储在一条记录中。因此,当您查看记录的索引时,您会看到:

    title 1 end dut fre
    title 2 end dut fre
    ...
    

    我的建议:

    1) 使用内置的 i18n / l10n 使用 .po / .pot 文件。

    2) 如果内容将经常更改并需要存储在数据库中以便可以轻松地随时更改/更新,则使用下拉菜单。

    Language: dropdown
    Title: text_field
    

    【讨论】:

    • 谢谢,我已经将 .po 文件用于非动态内容。是的,使用语言的选择输入是执行此操作的常用方法,但由于只有两个字段需要翻译并且它们总是需要翻译,所以我准备使用一种形式。我想使用两个自定义查询并没有太大的牺牲......只是想知道是否有更好的解决方案。我对翻译行为的期望更高。
    猜你喜欢
    • 1970-01-01
    • 2017-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    • 2023-03-22
    • 2019-06-25
    • 1970-01-01
    相关资源
    最近更新 更多