0
votes

Quoting from the cakephp Book (ver 1.3):

Note that only fields of the model you are directly doing find on will be translated. Models attached via associations won't be translated because triggering callbacks on associated models is currently not supported.

Has anyone come up with a solution for this?

If not could you give me some pointers concerning the following simple scenario.

I have 2 models:

Project, Category.
Project HABTM Category

I have properly set up i18n table and I have a few entries in the db, all translated. When I retrieve a project it does retrieve the translation but not the translated category because as it says in the cakephp book models attached via associations won't be translated.

4

4 Answers

3
votes

I have another workaround; I don't know if it is any better or worse performance- or style-wise, only that it suits the "fat models, skinny controllers" goal:

AppModel.php

public function getTranslatedModelField($id = 0, $field) {

        $res = false;

        $db = $this->getDataSource();
        $tmp = $db->fetchAll('SELECT content from s2h_i18n WHERE model = ? AND locale = ? AND foreign_key = ? AND field = ? LIMIT 1',
            array($this->alias, Configure::read('Config.language'), $id, $field)
        );      
        if (!empty($tmp)) {
            $res = $tmp[0]['s2h_i18n']['content'];
        }
        return $res;
}

SomeModel.php

   public function afterFind($results, $primary = false) {

        foreach ($results as $key => $val) {
            if (isset($val['SomeOtherModel']) && isset($val['SomeOtherModel']['id'])) {
                $results[$key]['SomeOtherModel']['name'] = 
    $this->SomeOtherModel->getTranslatedModelField($val['SomeOtherModel']['id'], 'name');
            }
            // other possible queries for other models and/or fields
         }

        return $results;
    }
0
votes

OK I found a solution. Which is mostly a workaround. I should have thought of that earlier.

What I'm doing is the following. I'm finding all projects and recursively all categories associated with projects. Now since cakephp does not translate categories I am using the results from the initial query and I am performing a second one only for categories but using the category id values that I found on the first query. Now cakephp translates categories since I'm only searching for them and I can have their data translated.

At the moment I'm OK with this solution but it would be nice if first cakephp makes the translate behavior out of the box ready or secondly if someone had a behavior that could support retrieval of translation on associated models.

0
votes

I generalized the afterFind part a bit, so that it automatically grabs the fields to translate from the associated models' actsAs["Translate"] array, and uses an array of associated models to (potentially) translate:

public function afterFind($results, $primary = false){

    $modelsToTranslate = array("SomeModel", "AnotherModel");

    foreach ($results as $key => $val){
        foreach($modelsToTranslate as $mtt){
            if (isset($val[$mtt])){
                foreach($val[$mtt] as $fieldname => $fieldval){
                    foreach ($this->$mtt->actsAs["Translate"] as $fieldToTranslate){
                        $results[$key][$mtt][$fieldname][$fieldToTranslate] = $this->$mtt->getTranslatedModelField($val[$mtt][$fieldname]['id'], $fieldToTranslate);
                    }
                }            
            }               
        }
    }
    return $results;
}
0
votes

I took above solution and generalized both functions a bit, now it needs to be used together with the translate behaviour and both functions need to go into the model.php - everything else should work by itself:

public function getTranslatedModelField($id = 0, $field) {
    $res = false;
    $translateTable = (isset($this->translateTable))?$this->translateTable:"i18n";

    $db = $this->getDataSource();
    $tmp = $db->fetchAll(
        "SELECT content from {$translateTable} WHERE model = ? AND locale = ? AND foreign_key = ? AND field = ? LIMIT 1",
        array($this->alias, Configure::read('Config.language'), $id, $field)
    );
    if (!empty($tmp)) {
        $res = $tmp[0][$translateTable]['content'];
    }
    return $res;
}   

public function afterFind($results, $primary = false) {

    if($primary == false && array_key_exists('Translate', $this->actsAs)) {
        foreach ($results as $key => $val) {
            if (isset($val[$this->name]) && isset($val[$this->name]['id'])) {
                foreach($this->actsAs['Translate'] as $translationfield) {  
                    $results[$key][$this->name][$translationfield] = 
                    $this->getTranslatedModelField($val[$this->name]['id'], $translationfield);
                }
            } else if($key == 'id' && is_numeric($val)) {
                foreach($this->actsAs['Translate'] as $translationfield) {  
                    $results[$translationfield] = 
                    $this->getTranslatedModelField($val, $translationfield);
                }                   
            }
         }
    }

    return $results;
}