Le behavior Translate est en fait assez simple à paramétrer et à faire fonctionner out of the box, le tout avec très peu de configuration. Dans cette section, vous apprendrez comment ajouter et configurer ce behavior, pour l’utiliser dans n’importe quel model.
Si vous utilisez le behavior Translate en parallèle de Containable, assurez-vous de définir la clé “fields” pour vos requêtes. Sinon, vous pourriez vous retrouver avec des fragments SQL générés invalides.
Vous pouvez soit utiliser la console CakePHP, soit les créer manuellement. Il est recommandé d’utiliser la console pour cela, parce qu’il pourrait arriver que le layout change dans les futures versions de CakePHP. En restant fidèle à la console, cela garantira que vous ayez le bon layout:
./cake i18n
Sélectionner``[I]``, ce qui lancera le script d’initialisation de la base de données i18n. Il vous sera demandé si vous voulez supprimer toute table existante et si vous voulez en créer une. Répondez par oui si vous êtes certain qu’il n’y a pas encore une table i18n et répondez encore par oui pour créer la table.
Ajoutez-le à votre model en utilisant la propriété $actsAs
comme dans
l’exemple suivant.
class Post extends AppModel {
public $actsAs = array(
'Translate'
);
}
Ceci ne produira encore rien, parce qu’il faut un couple d’options avant que cela ne commence à fonctionner. Vous devez définir, quels champs du model courant devront être détectés dans la table de traduction que nous avons créée précédemment.
Vous pouvez définir les champs en étendant simplement la valeur 'Translate'
avec un autre tableau, comme:
class Post extends AppModel {
public $actsAs = array(
'Translate' => array(
'fieldOne', 'fieldTwo', 'and_so_on'
)
);
}
Après avoir fait cela (par exemple, en précisant « title » comme l’un des champs), vous avez déjà terminé la configuration de base. Super ! D’après notre exemple courant, le model devrait maintenant ressembler à quelque chose comme cela:
class Post extends AppModel {
public $actsAs = array(
'Translate' => array(
'title'
)
);
}
Quand vous définissez vos champs à traduire dans le Behavior Translate, assurez-vous d’omettre les champs du schéma de model traduits. Si vous laissez les champs en place, il peut y avoir un problème de récupération de données avec les locales.
Note
Si tous les champs dans votre model sont traduits, assurez-vous d’ajouter
les colonnes created
et modified
à votre table. CakePHP a besoin
d’au moins un champ différent d’une clé primaire avant d’enregistrer un
enregistrement.
Lorsque vous définissez des champs qui sont traduits, vous pouvez aussi configurer
le chargement des traductions pour qu’il se fasse via un LEFT JOIN
à la place
d’un INNER JOIN
(qui est la méthode standard).
Cela vous permettra de charger les enregistrements qui pourraient être partiellement
traduits:
class Post extends AppModel {
public $actsAs = array(
'Translate' => array(
'title',
'body',
'joinType' => 'left'
)
);
}
Nouveau dans la version 2.10.0: L’option joinType
a été ajoutée dans 2.10.0
A partir de maintenant, chaque mise à jour/création d’un enregistrement fera que le Behavior Translate copiera la valeur de « title » dans la table de traduction (par défaut : i18n), avec la locale courante. Une « locale » est un identifiant d’une langue, pour ainsi dire.
Par défaut, le TranslateBehavior va automatiquement récupérer et ajouter les
données basées sur la locale courante. La locale courante est lue à partir de
Configure::read('Config.language')
qui est assignée par la classe
L10n
. Vous pouvez surcharger cette valeur par défaut à la volée
en utilisant $Model->locale
.
En définissant $Model->locale
, vous pouvez lire les traductions pour une
locale spécifique:
// Lire les données de la locale espagnole.
$this->Post->locale = 'es';
$results = $this->Post->find('first', array(
'conditions' => array('Post.id' => $id)
));
// $results va contenir la traduction espagnole.
Si vous voulez avoir tous les enregistrements de traduction attachés à l’enregistrement de model courant, vous étendez simplement le tableau champ dans votre paramétrage du behavior, comme montré ci-dessous. Vous êtes complètement libre de choisir le nommage.
class Post extends AppModel {
public $actsAs = array(
'Translate' => array(
'title' => 'titleTranslation'
)
);
}
Avec ce paramétrage, le résultat de votre $this->Post->find()
devrait
ressembler à quelque chose comme cela
Array
(
[Post] => Array
(
[id] => 1
[title] => Beispiel Eintrag
[body] => lorem ipsum...
[locale] => de_de
)
[titleTranslation] => Array
(
[0] => Array
(
[id] => 1
[locale] => en_us
[model] => Post
[foreign_key] => 1
[field] => title
[content] => Example entry
)
[1] => Array
(
[id] => 2
[locale] => de_de
[model] => Post
[foreign_key] => 1
[field] => title
[content] => Beispiel Eintrag
)
)
)
Note
L’enregistrement du model contient un champ virtuel appelé « locale ». Il indique quelle locale est utilisée dans ce résultat.
Notez que seuls les champs du model que vous faîtes avec un `find` seront traduits. Les Models attachés via les associations ne seront pas traduits parce que le déclenchement des callbacks sur les models associés n’est actuellement pas supporté.
Vous pouvez aussi récupérer toutes les traductions seulement quand vous en avez besoin, en utilisant la méthode bindTranslation.
$fields
st un tableau associatif composé du champ et du nom de
l’association, dans lequel la clé est le champ traduisible et la valeur
est le nom fictif de l’association.
$this->Post->bindTranslation(array('name' => 'titleTranslation'));
$this->Post->find('all', array('recursive' => 1)); // il est nécessaire d'avoir au moins un recursive à 1 pour que ceci fonctionne
Avec ce paramétrage, le résultat de votre find() devrait ressembler à quelque chose comme ceci
Array
(
[Post] => Array
(
[id] => 1
[title] => Beispiel Eintrag
[body] => lorem ipsum...
[locale] => de_de
)
[titleTranslation] => Array
(
[0] => Array
(
[id] => 1
[locale] => en_us
[model] => Post
[foreign_key] => 1
[field] => title
[content] => Example entry
)
[1] => Array
(
[id] => 2
[locale] => de_de
[model] => Post
[foreign_key] => 1
[field] => title
[content] => Beispiel Eintrag
)
)
)
Vous pouvez forcer le model qui utilise le TranslateBehavior à sauvegarder dans une autre langue que celle détectée.
Pour dire à un model dans quelle langue le contenu devra être sauvé, changez simplement la valeur de la propriété $locale du model, avant que vous ne sauvegardiez les données dans la base. Vous pouvez faire cela dans votre controller ou vous pouvez le définir directement dans le model.
Exemple A: Dans votre controller:
class PostsController extends AppController {
public function add() {
if (!empty($this->request->data)) {
$this->Post->locale = 'de_de'; // we are going to save the german version
$this->Post->create();
if ($this->Post->save($this->request->data)) {
$this->redirect(array('action' => 'index'));
}
}
}
}
Exemple B: Dans votre model:
class Post extends AppModel {
public $actsAs = array(
'Translate' => array(
'title'
)
);
// Option 1) just define the property directly
public $locale = 'en_us';
// Option 2) create a simple method
public function setLanguage($locale) {
$this->locale = $locale;
}
}
Si vous attendez beaucoup d’entrée, vous vous demandez certainement comment gérer tout cela dans une base de données qui grossit rapidement. Il y a deux propriétés introduite dans le Behavior Translate qui permettent de spécifier quel model doit être relié au model qui contient les traductions.
Ceux-ci sont $translateModel et $translateTable.
Disons que nous voulons sauver nos traductions pour tous les posts dans la table « post_i18ns » au lieu de la valeur par défaut de la table « i18n ». Pour faire cela vous avez besoin de paramétrer votre model comme cela:
class Post extends AppModel {
public $actsAs = array(
'Translate' => array(
'title'
)
);
// Utilise un model différent (et table)
public $translateModel = 'PostI18n';
}
Note
Il est important vous mettiez au pluriel la table. C’est maintenant un model habituel et il peut être traité en tant que tel avec les conventions qui en découlent. Le schéma de la table elle-même doit être identique à celui généré par la console CakePHP. Pour vous assurer qu’il s’intègre vous pourriez initialiser une table i18n vide au travers de la console et renommer la table après coup.
Pour que cela fonctionne vous devez créer le fichier du model actuel dans le dossier des models. La raison est qu’il n’y a pas de propriété pour définir le displayField directement dans le model utilisant ce behavior.
Assurez vous de changer le $displayField
en 'field'
.
class PostI18n extends AppModel {
public $displayField = 'field'; // important
}
// nom de fichier: PostI18n.php
C’est tout ce qu’il faut. Vous pouvez aussi ajouter toutes les propriétés
des models comme $useTable. Mais pour une meilleure cohérence nous
pouvons faire cela dans le model qui utilise ce model de traduction.
C’est là que l’option $translateTable
entre en jeu.
Si vous voulez changer le nom de la table, il vous suffit simplement de définir $translateTable dans votre model, comme ceci:
class Post extends AppModel {
public $actsAs = array(
'Translate' => array(
'title'
)
);
// Utilise un model différent
public $translateModel = 'PostI18n';
// Utilise une table différente pour translateModel
public $translateTable = 'post_translations';
}
A noter que vous ne pouvez pas utiliser $translateTable seule.
Si vous n’avez pas l’intention d’utiliser un Model de traduction
$translateModel
personnalisé, alors laissez cette propriété inchangée.
La raison est qu’elle casserait votre configuration et vous afficherait un
message « Missing Table » pour le model I18n par défaut, lequel est créé à
l’exécution.