Créer un champ multilingue dans un AdminController PrestaShop
Guide complet pour ajouter des champs multilingues dans un AdminController PrestaShop : table _lang, ObjectModel et formulaire avec gestion des langues.
En bref : Pour créer un champ multilingue dans un AdminController PrestaShop, trois éléments sont indispensables : une table `_lang` en base de données avec clé composite, un ObjectModel déclaré avec `'multilang' => true` et `'lang' => true` sur chaque champ traduisible, et le paramètre `'lang' => true` dans la définition du formulaire du contrôleur.
Introduction
Lorsque vous développez un module PrestaShop avec une interface d'administration personnalisée, vous aurez souvent besoin de gérer des contenus traduits dans plusieurs langues : descriptions, titres, labels… PrestaShop intègre nativement un mécanisme de champs multilingues dans ses AdminController, mais sa mise en place exige une architecture précise côté base de données et côté ObjectModel.
Ce guide détaille les trois étapes indispensables : la création de la table _lang, la configuration du modèle objet, et le paramétrage du formulaire dans le contrôleur d'administration.
Étape 1 : Créer la table `_lang` en base de données
Le système multilingue de PrestaShop repose sur une convention stricte : pour chaque entité stockée dans une table principale (par exemple ps_mon_entite), les champs traduisibles sont isolés dans une table suffixée _lang (soit ps_mon_entite_lang).
Cette table de langue doit obligatoirement contenir :
- La clé primaire de l'entité parente (`id_mon_entite`)
- L'identifiant de la langue (`id_lang`)
- Les colonnes traduisibles (titre, description, etc.)
Schéma SQL complet
Voici un exemple de script d'installation à placer dans la méthode install() de votre module :
CREATE TABLE IF NOT EXISTS `_DB_PREFIX_mon_entite` (
`id_mon_entite` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`active` TINYINT(1) NOT NULL DEFAULT 1,
`date_add` DATETIME NOT NULL,
`date_upd` DATETIME NOT NULL,
PRIMARY KEY (`id_mon_entite`)
) ENGINE=_MYSQL_ENGINE_ DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `_DB_PREFIX_mon_entite_lang` (
`id_mon_entite` INT(11) UNSIGNED NOT NULL,
`id_lang` INT(11) UNSIGNED NOT NULL,
`title` VARCHAR(255) NOT NULL,
`description` TEXT,
PRIMARY KEY (`id_mon_entite`, `id_lang`)
) ENGINE=_MYSQL_ENGINE_ DEFAULT CHARSET=utf8mb4;
Bonne pratique PrestaShop 8.x : Utilisez systématiquement
utf8mb4comme charset pour supporter les émojis et caractères spéciaux. Les anciennes versions utilisaient souventutf8(alias deutf8mb3), ce qui provoquait des troncatures silencieuses.
Prenez modèle sur les tables natives comme ps_category_lang ou ps_product_lang pour vous assurer de respecter la convention.
Étape 2 : Configurer l'ObjectModel avec les définitions multilingues
L'ObjectModel est le cœur du mécanisme. C'est lui qui indique à PrestaShop quels champs sont traduisibles et comment les persister dans la table _lang.
La clé est le paramètre 'lang' => true dans la définition des champs :
class MonEntite extends ObjectModel
{
public $id_mon_entite;
public $active;
public $title;
public $description;
public $date_add;
public $date_upd;
public static $definition = [
'table' => 'mon_entite',
'primary' => 'id_mon_entite',
'multilang' => true,
'fields' => [
'active' => [
'type' => self::TYPE_BOOL,
'validate' => 'isBool',
'required' => true,
],
'date_add' => [
'type' => self::TYPE_DATE,
'validate' => 'isDate',
],
'date_upd' => [
'type' => self::TYPE_DATE,
'validate' => 'isDate',
],
// Champs multilingues
'title' => [
'type' => self::TYPE_STRING,
'lang' => true,
'validate' => 'isGenericName',
'size' => 255,
'required' => true,
],
'description' => [
'type' => self::TYPE_HTML,
'lang' => true,
'validate' => 'isCleanHtml',
],
],
];
}
Points critiques à ne pas oublier
- **`'multilang' => true`** au niveau de la définition globale : sans cette directive, PrestaShop ne cherchera jamais la table `_lang`.
- **`'lang' => true`** sur chaque champ traduisible : c'est ce flag qui détermine dans quelle table le champ est stocké.
- **Les propriétés publiques** doivent exister pour chaque champ, y compris les champs multilingues. Lorsqu'ils sont chargés, ces champs deviennent des tableaux indexés par `id_lang` (ex : `$obj->title[1]` pour le français).
Gestion du multiboutique
Si votre module doit aussi supporter le multiboutique, ajoutez 'multishop' => true et créez une table _shop supplémentaire :
public static $definition = [
'table' => 'mon_entite',
'primary' => 'id_mon_entite',
'multilang' => true,
'multishop' => true,
// ...
];
PrestaShop cherchera alors automatiquement ps_mon_entite_shop et ps_mon_entite_lang (voire ps_mon_entite_lang_shop si les traductions varient par boutique).
Étape 3 : Déclarer le champ multilingue dans le formulaire AdminController
Dans votre AdminController, la méthode renderForm() utilise un tableau $this->fields_form pour générer l'interface. Pour activer le sélecteur de langue sur un champ, il suffit d'ajouter 'lang' => true :
class AdminMonEntiteController extends AdminController
{
public function __construct()
{
$this->table = 'mon_entite';
$this->className = 'MonEntite';
$this->identifier = 'id_mon_entite';
$this->bootstrap = true;
$this->lang = true;
parent::__construct();
}
public function renderForm()
{
$this->fields_form = [
'legend' => [
'title' => $this->l('Mon Entité'),
'icon' => 'icon-pencil',
],
'input' => [
[
'type' => 'text',
'lang' => true,
'label' => $this->l('Titre'),
'name' => 'title',
'required' => true,
'col' => 6,
],
[
'type' => 'textarea',
'lang' => true,
'label' => $this->l('Description'),
'name' => 'description',
'autoload_rte' => true,
'required' => false,
'cols' => 40,
'rows' => 10,
],
[
'type' => 'switch',
'label' => $this->l('Actif'),
'name' => 'active',
'values' => [
['id' => 'active_on', 'value' => 1, 'label' => $this->l('Oui')],
['id' => 'active_off', 'value' => 0, 'label' => $this->l('Non')],
],
],
],
'submit' => [
'title' => $this->l('Enregistrer'),
],
];
return parent::renderForm();
}
}
Détail des paramètres du champ textarea multilingue
Important : N'oubliez pas
$this->lang = true;dans le constructeur du contrôleur. Sans cette propriété, PrestaShop ne générera pas le sélecteur de langue même si vos champs sont déclarés avec'lang' => true.
Checklist récapitulative
Avant de tester votre formulaire multilingue, vérifiez ces points dans l'ordre :
- **Table `_lang` créée** avec la clé primaire composite (`id_entite`, `id_lang`)
- **`'multilang' => true`** dans la définition statique de l'ObjectModel
- **`'lang' => true`** sur chaque champ traduisible dans `$definition['fields']`
- **Propriétés publiques** déclarées dans la classe pour chaque champ
- **`$this->lang = true`** dans le constructeur de l'AdminController
- **`'lang' => true`** sur chaque input du formulaire `fields_form`
- **Charset `utf8mb4`** sur la table `_lang` pour éviter les problèmes d'encodage
- Les `FormType` Symfony avec `TranslateType` ou `TranslatableType`
- Les `CommandHandler` pour la persistance
Si le sélecteur de langue n'apparaît pas ou que les traductions ne se sauvegardent pas, reprenez cette checklist point par point : dans 90 % des cas, c'est l'un de ces éléments qui manque.
Différences entre PrestaShop 1.7 et 8.x
Le mécanisme des AdminController legacy reste fonctionnel en PrestaShop 8.x et la syntaxe décrite ci-dessus est toujours valide. Cependant, PrestaShop 8 introduit progressivement les formulaires Symfony via le pattern CQRS. Pour les nouveaux développements sur PrestaShop 8.x, vous pouvez également utiliser :
Le choix entre l'approche legacy (AdminController) et l'approche Symfony dépend du contexte : si votre module doit rester compatible PrestaShop 1.7, l'approche legacy reste le choix le plus pragmatique.
Questions fréquentes
Tout ce que vous devez savoir sur ce sujet.
Un projet PrestaShop ?
Discutons-en directement.
193 projets livrés
Lire sur le blog

Alexandre Carette
Expert PrestaShop & Architecture E-commerce
Développeur PrestaShop depuis 2014, 193 projets livrés. Je conçois des architectures headless Nuxt + PrestaShop et des outils d'automatisation IA pour les e-commerçants.