[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"theme-db":3,"$fPmJRjuMA-6jLZ1PMO_3w7j1MDjvv00nP0Hwi24x6BSQ":22,"$fKnz2vuX4bZz1LbUTiuFsvSZ3e07l5_5fqNYp4Tzdhi8":59,"megamenu":140,"footer-db":196,"$fDZPMa0_N0xqbRQ95gHTiIP1rNFkyLILeI5-x-NKQs10":214,"header-db":228},{"theme":4},{"colors":5,"typography":13,"ui":17,"defaultColorMode":21},{"primary":6,"secondary":7,"background":8,"foreground":9,"muted":10,"headerBg":11,"footerBg":12,"topBarBg":9,"topBarText":11},"#4F46E5","#0D9488","#F9FAFB","#111827","#6B7280","#ffffff","#020617",{"fontFamily":14,"fontUrl":15,"baseFontSize":16},"Inter, system-ui, sans-serif","https:\u002F\u002Ffonts.googleapis.com\u002Fcss2?family=Inter:wght@400;500;600;700&family=Playfair+Display:ital,wght@0,400;0,700;0,800;0,900;1,400;1,700&display=swap","16px",{"borderRadius":18,"contentWidth":19,"shadow":20},"lg","7xl",true,"light",{"title":23,"slug":24,"metaDescription":25,"category":26,"tags":27,"difficulty":32,"psVersions":33,"content":37,"faq":38,"tldr":54,"readingTime":55,"generatedAt":56,"publishDate":56,"relatedArticles":57,"sourceCategory":58},"Import CSV multiboutique PrestaShop : résoudre les conflits multilingues","import-csv-multiboutique-prestashop-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.","multiboutique",[26,28,29,30,31],"import-csv","multilingue","catégories","base-de-données","avance",[34,35,36],"1.6","1.7","8.x","\u003Ch2>Le défi : concilier multiboutique et multilingue lors des imports CSV\u003C\u002Fh2>\n\u003Cp>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 : \u003Cstrong>le fichier est dupliqué pour chaque langue rattachée à la boutique\u003C\u002Fstrong>, et non uniquement pour la langue ciblée.\u003C\u002Fp>\n\u003Cp>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 \u003Cstrong>écrase les traductions précédentes\u003C\u002Fstrong> au lieu de les compléter.\u003C\u002Fp>\n\u003Cp>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.\u003C\u002Fp>\n\u003Ch2>Comprendre le mécanisme en base de données\u003C\u002Fh2>\n\u003Cp>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 :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-sql\">\n-- Table principale (données non traduisibles)\nSELECT * FROM ps_category;\n\n-- Table des traductions (une ligne par langue)\nSELECT * FROM ps_category_lang;\n\n-- Table d'association multiboutique\nSELECT * FROM ps_category_shop;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>La table \u003Ccode>ps_category_lang\u003C\u002Fcode> contient une clé composite \u003Ccode>(id_category, id_shop, id_lang)\u003C\u002Fcode>. Lors d'un import CSV, PrestaShop itère sur \u003Cstrong>toutes les langues actives de la boutique ciblée\u003C\u002Fstrong> 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.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-sql\">\n-- Ce qu'on observe après un import \"français\" sur une boutique à 8 langues :\nSELECT id_category, id_shop, id_lang, name\nFROM ps_category_lang\nWHERE id_category = 42;\n\n-- Résultat : 8 lignes identiques avec le texte français\n-- id_lang 1 → \"Chaussures de sport\"  (correct)\n-- id_lang 2 → \"Chaussures de sport\"  (devrait être \"Sports shoes\")\n-- id_lang 3 → \"Chaussures de sport\"  (devrait être \"Sportschuhe\")\n-- ... etc.\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>L'option « Forcer les identifiants » : un levier méconnu\u003C\u002Fh2>\n\u003Cp>Un paramètre crucial dans l'écran d'import CSV est la case \u003Cstrong>« Forcer les identifiants numériques »\u003C\u002Fstrong> (Force IDs). Son comportement influence directement la gestion multilingue :\u003C\u002Fp>\n\u003Cul>\n\u003Cli>**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.\u003C\u002Fli>\n\u003Cli>**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.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>\u003Cstrong>La solution dans la majorité des cas : décocher « Forcer les identifiants »\u003C\u002Fstrong> lors des imports multilingues successifs. Cela préserve les traductions déjà importées.\u003C\u002Fp>\n\u003Ch3>Attention aux IDs de catégories\u003C\u002Fh3>\n\u003Cp>Chaque langue doit référencer les bons identifiants de catégories parentes. Si votre CSV français référence \u003Ccode>id_parent = 3\u003C\u002Fcode> pour la catégorie « Vêtements », vos CSV anglais et allemand doivent utiliser le même identifiant. Vérifiez la correspondance en base :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-sql\">\nSELECT c.id_category, c.id_parent, cl.id_lang, cl.name\nFROM ps_category c\nJOIN ps_category_lang cl ON c.id_category = cl.id_category\nWHERE c.id_parent = 2\nORDER BY c.id_category, cl.id_lang;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>Méthode recommandée pour un import multilingue propre\u003C\u002Fh2>\n\u003Cp>Voici le workflow que je recommande après plus de dix ans de projets PrestaShop internationaux :\u003C\u002Fp>\n\u003Ch3>Étape 1 : Préparer un CSV par langue\u003C\u002Fh3>\n\u003Cp>Créez un fichier CSV distinct par langue avec les colonnes essentielles :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-csv\">\nid;name;description;link_rewrite;meta_title;meta_description;active\n;Chaussures de sport;Notre gamme complète...;chaussures-de-sport;Chaussures de sport;Découvrez notre sélection;1\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>Point important :\u003C\u002Fstrong> ne renseignez PAS la colonne \u003Ccode>id\u003C\u002Fcode> si vous décochez « Forcer les identifiants ». Laissez-la vide pour le premier import.\u003C\u002Fp>\n\u003Ch3>Étape 2 : Importer la langue par défaut en premier\u003C\u002Fh3>\n\u003Col>\n\u003Cli>Allez dans **Paramètres avancés > Import**\u003C\u002Fli>\n\u003Cli>Sélectionnez la boutique cible (contexte multiboutique)\u003C\u002Fli>\n\u003Cli>Choisissez la langue par défaut de la boutique\u003C\u002Fli>\n\u003Cli>**Décochez** « Forcer les identifiants numériques »\u003C\u002Fli>\n\u003Cli>Importez le CSV de la langue principale\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3>Étape 3 : Exporter pour récupérer les IDs générés\u003C\u002Fh3>\n\u003Cp>Après le premier import, exportez les catégories pour récupérer les identifiants attribués par MySQL :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-sql\">\nSELECT id_category, name, link_rewrite\nFROM ps_category_lang\nWHERE id_lang = 1 AND id_shop = 1\nORDER BY id_category;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Étape 4 : Importer les langues secondaires avec les IDs\u003C\u002Fh3>\n\u003Cp>Pour chaque langue supplémentaire :\u003C\u002Fp>\n\u003Col>\n\u003Cli>Ajoutez la colonne `id` dans le CSV avec les identifiants récupérés\u003C\u002Fli>\n\u003Cli>**Cochez** « Forcer les identifiants » cette fois\u003C\u002Fli>\n\u003Cli>Sélectionnez la langue cible\u003C\u002Fli>\n\u003Cli>Importez\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3>Étape 5 : Vérifier l'intégrité en base\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-sql\">\n-- Vérifier que chaque catégorie a bien toutes ses traductions\nSELECT c.id_category,\n       COUNT(DISTINCT cl.id_lang) AS nb_langues,\n       GROUP_CONCAT(DISTINCT l.iso_code ORDER BY l.id_lang) AS langues\nFROM ps_category c\nJOIN ps_category_lang cl ON c.id_category = cl.id_category\nJOIN ps_lang l ON cl.id_lang = l.id_lang\nWHERE c.active = 1\nGROUP BY c.id_category\nHAVING nb_langues &lt; (SELECT COUNT(*) FROM ps_lang WHERE active = 1);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Cette requête liste les catégories auxquelles il manque des traductions.\u003C\u002Fp>\n\u003Ch2>Alternative PrestaShop 8.x : l'API et les imports améliorés\u003C\u002Fh2>\n\u003Cp>Sur PrestaShop 8.x, le moteur d'import a été partiellement réécrit. Deux améliorations notables :\u003C\u002Fp>\n\u003Col>\n\u003Cli>**Meilleure gestion du contexte boutique** : l'import respecte davantage la sélection de langue.\u003C\u002Fli>\n\u003Cli>**API Webservice** : pour les projets à fort volume, privilégiez l'API REST qui permet un contrôle granulaire par langue :\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cpre>\u003Ccode class=\"language-php\">\n\u002F\u002F Exemple d'appel API pour mettre à jour une catégorie dans une langue spécifique\n$xml = $webService-&gt;get([\n    'resource' =&gt; 'categories',\n    'id' =&gt; 42\n]);\n\n$category = $xml-&gt;categories-&gt;category;\n$languages = $category-&gt;name-&gt;language;\n\nforeach ($languages as $lang) {\n    if ((int)$lang['id'] === 2) { \u002F\u002F id_lang = 2 (anglais)\n        $lang[0] = 'Sports shoes';\n    }\n}\n\n$webService-&gt;edit([\n    'resource' =&gt; 'categories',\n    'id' =&gt; 42,\n    'putXml' =&gt; $xml-&gt;asXML()\n]);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>Faut-il utiliser le multiboutique pour le multilingue ?\u003C\u002Fh2>\n\u003Cp>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.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Mon conseil\u003C\u002Fstrong> : le multiboutique reste la bonne architecture pour un site multilingue, à condition de :\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Maîtriser le workflow d'import décrit ci-dessus\u003C\u002Fli>\n\u003Cli>Utiliser l'API pour les opérations en masse plutôt que l'import CSV\u003C\u002Fli>\n\u003Cli>Vérifier systématiquement l'intégrité des traductions en base après chaque opération\u003C\u002Fli>\n\u003Cli>Mettre en place un script de contrôle automatisé qui détecte les traductions manquantes ou dupliquées\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>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.\u003C\u002Fp>",[39,42,45,48,51],{"q":40,"a":41},"Pourquoi mon import CSV écrase-t-il les traductions des autres langues en multiboutique PrestaShop ?","Le moteur d'import CSV de PrestaShop insère une ligne dans ps_category_lang pour chaque langue active de la boutique, pas uniquement pour la langue sélectionnée. Lorsque « Forcer les identifiants » est coché, l'import met à jour toutes les langues avec les données du CSV courant, écrasant les traductions existantes. La solution consiste à importer d'abord sans forcer les IDs pour la langue principale, puis avec les IDs pour les langues secondaires.",{"q":43,"a":44},"Faut-il créer une base de données par langue au lieu d'utiliser le multiboutique PrestaShop ?","Non, le multiboutique reste la meilleure architecture pour un site multilingue. Des bases séparées impliquent une maintenance multipliée (mises à jour modules, configurations, catalogue non mutualisé). Le multiboutique fonctionne bien à condition de maîtriser le workflow d'import CSV multilingue et de privilégier l'API Webservice pour les opérations en masse.",{"q":46,"a":47},"Comment vérifier en base de données que toutes les traductions sont présentes pour mes catégories PrestaShop ?","Exécutez une requête SQL joignant ps_category, ps_category_lang et ps_lang avec un GROUP BY sur id_category et un HAVING qui filtre les catégories dont le nombre de langues est inférieur au total de langues actives. Cela identifie immédiatement les catégories auxquelles il manque une ou plusieurs traductions.",{"q":49,"a":50},"Quel rôle joue l'option Forcer les identifiants lors d'un import CSV PrestaShop ?","Lorsqu'elle est cochée, PrestaShop utilise l'ID du CSV pour identifier l'entité existante et la mettre à jour, ce qui peut écraser toutes les langues. Décochée, PrestaShop crée de nouvelles entités avec auto-incrémentation MySQL, préservant les données existantes. Pour un import multilingue, décochez-la au premier import puis cochez-la pour les langues suivantes une fois les IDs connus.",{"q":52,"a":53},"Comment importer des catégories en 8 langues sans conflit sur PrestaShop 8.x ?","Sur PrestaShop 8.x, privilégiez l'API Webservice qui permet de cibler précisément une langue via l'attribut id du nœud XML language. Pour l'import CSV, suivez le workflow en 5 étapes : un CSV par langue, import de la langue par défaut sans forcer les IDs, export pour récupérer les IDs générés, puis import des langues secondaires avec les IDs forcés, et enfin vérification d'intégrité en base.","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.",6,"2026-03-21T14:19:41.000Z",[],"Utilisation de PrestaShop : configuration et difficultés",{"columns":60},[61,77,107,128],{"title":62,"links":63},"Plateforme",[64,68,71,74],{"label":65,"href":66,"external":67},"Offre Starter (2 500 €)","\u002Foffre-starter",false,{"label":69,"href":70,"external":67},"Devenir Ambassadeur","\u002Fambassadeur",{"label":72,"href":73,"external":67},"Modules PrestaShop","\u002Fmodules",{"label":75,"href":76,"external":20},"CodeMyShop.com","https:\u002F\u002Fcodemyshop.com",{"title":78,"links":79},"Le Synedre",[80,83,86,89,92,95,98,101,104],{"label":81,"href":82,"external":67},"L'histoire","\u002Fsynedre",{"label":84,"href":85,"external":67},"Constitution","\u002Fsynedre\u002Fconstitution",{"label":87,"href":88,"external":67},"L'équipe","\u002Fequipe",{"label":90,"href":91,"external":67},"Le réacteur en direct","\u002Freacteur",{"label":93,"href":94,"external":67},"Le Drill (entraînement)","\u002Fdrill",{"label":96,"href":97,"external":67},"Protocole de réunion","\u002Fsynedre\u002Freunion",{"label":99,"href":100,"external":67},"Les agents IA","\u002Fagents-ia",{"label":102,"href":103,"external":67},"La Conduite","\u002Fsynedre\u002Fconduite",{"label":105,"href":106,"external":67},"Charte plateforme","\u002Fsynedre\u002Fcharte",{"title":108,"links":109},"Ressources",[110,113,116,119,122,125],{"label":111,"href":112,"external":67},"Blog","\u002Fblog",{"label":114,"href":115,"external":67},"Academy","\u002Facademy",{"label":117,"href":118,"external":67},"Dictionnaire","\u002Fdictionnaire",{"label":120,"href":121,"external":67},"Expertise PrestaShop","\u002Fexpertise",{"label":123,"href":124,"external":67},"Flywheel","\u002Fflywheel",{"label":126,"href":127,"external":67},"Manifeste","\u002Fmanifeste",{"title":129,"links":130},"À propos",[131,134,137],{"label":132,"href":133,"external":67},"Alexandre Carette","\u002Fa-propos",{"label":135,"href":136,"external":67},"Dossier de presse","\u002Fpresse",{"label":138,"href":139,"external":67},"Contact","\u002Fcontact",{"items":141},[142,151,157,163,171,179,185,190],{"id":143,"type":144,"label":145,"href":121,"icon":147,"description":147,"badge":147,"groupTitle":147,"style":147,"gridColumns":147,"cssClass":147,"psCategoryId":147,"showPsChildren":67,"position":148,"children":149,"psChildren":150},41,"link",{"fr":146},"Expertise",null,0,[],[],{"id":152,"type":144,"label":153,"href":112,"icon":147,"description":147,"badge":147,"groupTitle":147,"style":147,"gridColumns":147,"cssClass":147,"psCategoryId":147,"showPsChildren":67,"position":154,"children":155,"psChildren":156},42,{"fr":111},1,[],[],{"id":158,"type":144,"label":159,"href":73,"icon":147,"description":147,"badge":147,"groupTitle":147,"style":147,"gridColumns":147,"cssClass":147,"psCategoryId":147,"showPsChildren":67,"position":160,"children":161,"psChildren":162},43,{"fr":72},2,[],[],{"id":164,"type":144,"label":165,"href":167,"icon":147,"description":147,"badge":147,"groupTitle":147,"style":147,"gridColumns":147,"cssClass":147,"psCategoryId":147,"showPsChildren":67,"position":168,"children":169,"psChildren":170},44,{"fr":166},"Outils IA","\u002Foutils-ia",3,[],[],{"id":172,"type":144,"label":173,"href":66,"icon":147,"description":147,"badge":147,"groupTitle":147,"style":175,"gridColumns":147,"cssClass":147,"psCategoryId":147,"showPsChildren":67,"position":176,"children":177,"psChildren":178},45,{"fr":174},"Offre Starter ✨",{"highlight":20},4,[],[],{"id":180,"type":144,"label":181,"href":115,"icon":147,"description":147,"badge":147,"groupTitle":147,"style":147,"gridColumns":147,"cssClass":147,"psCategoryId":147,"showPsChildren":67,"position":182,"children":183,"psChildren":184},46,{"fr":114},5,[],[],{"id":186,"type":144,"label":187,"href":133,"icon":147,"description":147,"badge":147,"groupTitle":147,"style":147,"gridColumns":147,"cssClass":147,"psCategoryId":147,"showPsChildren":67,"position":55,"children":188,"psChildren":189},47,{"fr":129},[],[],{"id":191,"type":144,"label":192,"href":139,"icon":147,"description":147,"badge":147,"groupTitle":147,"style":147,"gridColumns":147,"cssClass":147,"psCategoryId":147,"showPsChildren":67,"position":193,"children":194,"psChildren":195},48,{"fr":138},7,[],[],{"footer":197},{"theme":198,"description":147,"hours":147,"logo":199,"contact":202,"social":203,"bottomBar":213},"dark",{"src":200,"href":201,"alt":132},"\u002Flogo-ac.svg","\u002F",{"email":147,"phone":147,"address":147,"cta":147},[204,207,210],{"platform":205,"href":206,"label":205},"linkedin","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Falexandre-carette\u002F",{"platform":208,"href":209,"label":208},"malt","https:\u002F\u002Fwww.malt.fr\u002Fprofile\u002Falexandrecarette",{"platform":211,"href":212,"label":211},"github","https:\u002F\u002Fgithub.com\u002Fprest4cafe",{"copyright":147},{"academy":215,"blog":216,"expertise":227},[],[217,221,224],{"title":218,"url":219,"score":154,"type":220},"PrestaShop headless avec Nuxt 3 : pourquoi séparer back et front","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fprestashop-headless-nuxt-separation-front-back","blog",{"title":222,"url":223,"score":154,"type":220},"PrestaShop headless : Nuxt 3, pas Next.js — le choix souverain","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fprestashop-headless-nuxt-nextjs-souverainete",{"title":225,"url":226,"score":154,"type":220},"Sylius rachète PrestaShop : ce que ça change pour vous","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fsylius-rachat-prestashop-headless-souverainete",[],{"header":229},{"logo":230,"topBar":233,"contactEmail":236,"features":237,"navBar":147},{"src":200,"alt":231,"text":132,"href":201,"class":232},"Alexandre Carette — Architecte E-commerce Souverain","h-10 w-10",{"message":147,"showLanguages":67,"align":234,"languages":235},"left",[],"contact@alexandrecarette.fr",{"showSearch":67,"showWishlist":67,"showLogin":20,"showContact":67,"showCart":67,"stickyHeader":20,"headerLayout":238},"inline"]