Import CSV multiboutique PrestaShop : résoudre les conflits multilingues
Guide complet pour importer des catégories CSV en multiboutique multilingue PrestaShop sans écraser les traductions. Solutions testées PS 1.6 à 8.x.
En bref : L'import CSV multiboutique multilingue de PrestaShop duplique les données sur toutes les langues actives au lieu de cibler uniquement la langue sélectionnée. La solution : importer la langue par défaut sans forcer les IDs, récupérer les identifiants générés, puis importer les langues secondaires avec les IDs forcés — ou mieux, utiliser l'API Webservice sur PrestaShop 8.x.
Le défi : concilier multiboutique et multilingue lors des imports CSV
Lorsqu'on configure un PrestaShop multiboutique avec une boutique par langue (chaque langue associée à un sous-domaine), l'import CSV de catégories révèle un comportement problématique : le fichier est dupliqué pour chaque langue rattachée à la boutique, et non uniquement pour la langue ciblée.
Concrètement, si vous avez 8 langues et 269 catégories avec des champs personnalisés, PrestaShop insère 8 copies identiques en base — une par langue — même si votre CSV ne cible qu'une seule langue. Pire encore, un import ultérieur dans une autre langue écrase les traductions précédentes au lieu de les compléter.
Ce problème existe depuis PrestaShop 1.6 et persiste partiellement sur les versions 1.7 et 8.x, bien que des améliorations aient été apportées au moteur d'import.
Comprendre le mécanisme en base de données
Pour saisir l'origine du problème, il faut examiner la structure MySQL de PrestaShop. Les catégories sont stockées dans trois tables principales :
-- Table principale (données non traduisibles)
SELECT * FROM ps_category;
-- Table des traductions (une ligne par langue)
SELECT * FROM ps_category_lang;
-- Table d'association multiboutique
SELECT * FROM ps_category_shop;
La table ps_category_lang contient une clé composite (id_category, id_shop, id_lang). Lors d'un import CSV, PrestaShop itère sur toutes les langues actives de la boutique ciblée et insère ou met à jour une ligne pour chacune, en utilisant la valeur du CSV — quelle que soit la langue sélectionnée dans l'interface d'import.
-- Ce qu'on observe après un import "français" sur une boutique à 8 langues :
SELECT id_category, id_shop, id_lang, name
FROM ps_category_lang
WHERE id_category = 42;
-- Résultat : 8 lignes identiques avec le texte français
-- id_lang 1 → "Chaussures de sport" (correct)
-- id_lang 2 → "Chaussures de sport" (devrait être "Sports shoes")
-- id_lang 3 → "Chaussures de sport" (devrait être "Sportschuhe")
-- ... etc.
L'option « Forcer les identifiants » : un levier méconnu
Un paramètre crucial dans l'écran d'import CSV est la case « Forcer les identifiants numériques » (Force IDs). Son comportement influence directement la gestion multilingue :
- **Cochée** : PrestaShop utilise l'ID du CSV pour créer ou mettre à jour l'entité. Si l'entité existe déjà, il écrase **toutes les langues** avec les données du CSV.
- **Décochée** : PrestaShop laisse MySQL gérer l'auto-incrémentation et traite l'import comme une création. Les traductions existantes ne sont pas écrasées.
La solution dans la majorité des cas : décocher « Forcer les identifiants » lors des imports multilingues successifs. Cela préserve les traductions déjà importées.
Attention aux IDs de catégories
Chaque langue doit référencer les bons identifiants de catégories parentes. Si votre CSV français référence id_parent = 3 pour la catégorie « Vêtements », vos CSV anglais et allemand doivent utiliser le même identifiant. Vérifiez la correspondance en base :
SELECT c.id_category, c.id_parent, cl.id_lang, cl.name
FROM ps_category c
JOIN ps_category_lang cl ON c.id_category = cl.id_category
WHERE c.id_parent = 2
ORDER BY c.id_category, cl.id_lang;
Méthode recommandée pour un import multilingue propre
Voici le workflow que je recommande après plus de dix ans de projets PrestaShop internationaux :
Étape 1 : Préparer un CSV par langue
Créez un fichier CSV distinct par langue avec les colonnes essentielles :
id;name;description;link_rewrite;meta_title;meta_description;active
;Chaussures de sport;Notre gamme complète...;chaussures-de-sport;Chaussures de sport;Découvrez notre sélection;1
Point important : ne renseignez PAS la colonne id si vous décochez « Forcer les identifiants ». Laissez-la vide pour le premier import.
Étape 2 : Importer la langue par défaut en premier
- Allez dans **Paramètres avancés > Import**
- Sélectionnez la boutique cible (contexte multiboutique)
- Choisissez la langue par défaut de la boutique
- **Décochez** « Forcer les identifiants numériques »
- Importez le CSV de la langue principale
- Ajoutez la colonne `id` dans le CSV avec les identifiants récupérés
- **Cochez** « Forcer les identifiants » cette fois
- Sélectionnez la langue cible
- Importez
- **Meilleure gestion du contexte boutique** : l'import respecte davantage la sélection de langue.
- **API Webservice** : pour les projets à fort volume, privilégiez l'API REST qui permet un contrôle granulaire par langue :
- Maîtriser le workflow d'import décrit ci-dessus
- Utiliser l'API pour les opérations en masse plutôt que l'import CSV
- Vérifier systématiquement l'intégrité des traductions en base après chaque opération
- Mettre en place un script de contrôle automatisé qui détecte les traductions manquantes ou dupliquées
Étape 3 : Exporter pour récupérer les IDs générés
Après le premier import, exportez les catégories pour récupérer les identifiants attribués par MySQL :
SELECT id_category, name, link_rewrite
FROM ps_category_lang
WHERE id_lang = 1 AND id_shop = 1
ORDER BY id_category;
Étape 4 : Importer les langues secondaires avec les IDs
Pour chaque langue supplémentaire :
Étape 5 : Vérifier l'intégrité en base
-- Vérifier que chaque catégorie a bien toutes ses traductions
SELECT c.id_category,
COUNT(DISTINCT cl.id_lang) AS nb_langues,
GROUP_CONCAT(DISTINCT l.iso_code ORDER BY l.id_lang) AS langues
FROM ps_category c
JOIN ps_category_lang cl ON c.id_category = cl.id_category
JOIN ps_lang l ON cl.id_lang = l.id_lang
WHERE c.active = 1
GROUP BY c.id_category
HAVING nb_langues < (SELECT COUNT(*) FROM ps_lang WHERE active = 1);
Cette requête liste les catégories auxquelles il manque des traductions.
Alternative PrestaShop 8.x : l'API et les imports améliorés
Sur PrestaShop 8.x, le moteur d'import a été partiellement réécrit. Deux améliorations notables :
// Exemple d'appel API pour mettre à jour une catégorie dans une langue spécifique
$xml = $webService->get([
'resource' => 'categories',
'id' => 42
]);
$category = $xml->categories->category;
$languages = $category->name->language;
foreach ($languages as $lang) {
if ((int)$lang['id'] === 2) { // id_lang = 2 (anglais)
$lang[0] = 'Sports shoes';
}
}
$webService->edit([
'resource' => 'categories',
'id' => 42,
'putXml' => $xml->asXML()
]);
Faut-il utiliser le multiboutique pour le multilingue ?
La tentation est grande d'abandonner le multiboutique au profit de boutiques séparées avec des bases de données distinctes. C'est une approche qui fonctionne, mais qui multiplie la charge de maintenance.
Mon conseil : le multiboutique reste la bonne architecture pour un site multilingue, à condition de :
La création de 8 bases de données séparées implique 8 fois plus de mises à jour de modules, 8 configurations à maintenir, et aucune mutualisation du catalogue. Le jeu n'en vaut la chandelle que dans des cas très spécifiques où les catalogues diffèrent radicalement d'un marché à l'autre.
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.