un petit javascript.jsx pour convertir tous les fichiers Adobe Indesign .indd en fichier .idml.
Le script traite les dossiers et sous-dossiers, sauvegarde dans un dossier Export_idml en respectant les dossiers et sous-dossiers.
Merci ChatGPT
Fonctionnement
Il demande de sélectionner un dossier source.
Il parcourt récursivement tous ses dossiers et sous-dossiers.
Il détecte les fichiers .indd.
Il peut également traiter les modèles .indt.
Il crée automatiquement :
Dossier sélectionné/
└── export_idml/
Il reproduit toute l’arborescence d’origine dans export_idml.
Il exporte chaque document en .idml.
Il ferme chaque document sans modifier ni enregistrer le fichier source.
Il produit un rapport détaillé
Protections professionnelles intégrées
exclusion automatique du dossier export_idml pendant l’analyse ;
traitement indépendant de chaque fichier ;
poursuite du traitement lorsqu’un document est défectueux ;
option d’arrêt à la première erreur ;
détection des documents déjà ouverts dans InDesign ;
avertissement en présence de documents ouverts et non enregistrés ;
option de remplacement ou de conservation des IDML existants ;
exclusion facultative des fichiers et dossiers masqués ;
restauration du niveau d’interaction d’InDesign après exécution ;
journal UTF-8 avec date, heure, source, destination et erreur ;
statistiques finales : fichiers trouvés, exportés, ignorés et en échec ;
compatibilité des chemins macOS et Windows
Installation
Dans InDesign 2026 :
Ouvrez Fenêtre > Utilitaires > Scripts.
Dans le panneau Scripts, faites un clic droit sur Utilisateur.
Sélectionnez Révéler dans le Finder sur macOS ou Révéler dans l’Explorateur sous Windows.
Copiez le fichier Export_IDML_recursif_InDesign_2026.jsx dans le dossier ouvert.
Revenez dans InDesign.
Double-cliquez sur le script.
Evolution possible :
Un pourcentage de traitement
Export_IDML_recursif_InDesign_2026.jsx
Code :
#target "InDesign"
#targetengine "batchExportIDML"
/*
Export IDML récursif — Adobe InDesign 2026
Version : 1.0.0
Fonction :
- sélection d'un dossier source ;
- recherche récursive des fichiers .indd et, en option, .indt ;
- création de <dossier_source>/export_idml ;
- conservation de l'arborescence ;
- export IDML sans modifier les fichiers sources ;
- journal UTF-8 détaillé ;
- gestion des erreurs fichier par fichier.
Installation :
Fenêtre > Utilitaires > Scripts
Clic droit sur "Utilisateur" > Révéler dans l’Explorateur/Finder
Copier ce fichier .jsx dans le dossier Scripts Panel.
*/
(function () {
"use strict";
var SCRIPT_NAME = "Export IDML récursif";
var SCRIPT_VERSION = "1.0.0";
var EXPORT_FOLDER_NAME = "export_idml";
var stats = {
found: 0,
exported: 0,
skipped: 0,
failed: 0,
startedAt: new Date()
};
var logLines = [];
var originalInteractionLevel = app.scriptPreferences.userInteractionLevel;
var sourceRoot = null;
var exportRoot = null;
var settings = null;
function main() {
if (app.documents.length > 0 && hasUnsavedDocuments()) {
var proceed = confirm(
"Des documents InDesign ouverts comportent des modifications non enregistrées.\r\r" +
"Le script ne les fermera pas, mais il est recommandé de les enregistrer avant un traitement par lot.\r\r" +
"Continuer ?",
false,
SCRIPT_NAME
);
if (!proceed) {
return;
}
}
sourceRoot = Folder.selectDialog(
"Sélectionnez le dossier contenant les fichiers InDesign à convertir en IDML"
);
if (!sourceRoot) {
return;
}
settings = showOptionsDialog();
if (!settings) {
return;
}
exportRoot = new Folder(sourceRoot.fsName + "/" + EXPORT_FOLDER_NAME);
if (!ensureFolder(exportRoot)) {
alert(
"Impossible de créer le dossier d’export :\r" + exportRoot.fsName,
SCRIPT_NAME,
true
);
return;
}
logHeader();
app.scriptPreferences.userInteractionLevel = UserInteractionLevels.NEVER_INTERACT;
try {
scanFolder(sourceRoot, exportRoot);
} catch (fatalError) {
log("ERREUR FATALE", sourceRoot.fsName, formatError(fatalError));
} finally {
app.scriptPreferences.userInteractionLevel = originalInteractionLevel;
}
stats.finishedAt = new Date();
writeLog();
showSummary();
}
function showOptionsDialog() {
var dlg = new Window("dialog", SCRIPT_NAME + " — v" + SCRIPT_VERSION);
dlg.orientation = "column";
dlg.alignChildren = ["fill", "top"];
var info = dlg.add(
"statictext",
undefined,
"Les fichiers IDML seront placés dans un dossier « " +
EXPORT_FOLDER_NAME +
" » créé à la racine du dossier sélectionné.",
{ multiline: true }
);
info.preferredSize.width = 520;
var formatsPanel = dlg.add("panel", undefined, "Fichiers à traiter");
formatsPanel.orientation = "column";
formatsPanel.alignChildren = "left";
formatsPanel.margins = 14;
var includeINDD = formatsPanel.add("checkbox", undefined, "Documents InDesign (.indd)");
includeINDD.value = true;
includeINDD.enabled = false;
var includeINDT = formatsPanel.add("checkbox", undefined, "Modèles InDesign (.indt)");
includeINDT.value = false;
var behaviorPanel = dlg.add("panel", undefined, "Comportement");
behaviorPanel.orientation = "column";
behaviorPanel.alignChildren = "left";
behaviorPanel.margins = 14;
var overwrite = behaviorPanel.add(
"checkbox",
undefined,
"Remplacer les fichiers IDML existants"
);
overwrite.value = false;
var skipHidden = behaviorPanel.add(
"checkbox",
undefined,
"Ignorer les fichiers et dossiers masqués"
);
skipHidden.value = true;
var stopOnError = behaviorPanel.add(
"checkbox",
undefined,
"Arrêter le traitement à la première erreur"
);
stopOnError.value = false;
var buttons = dlg.add("group");
buttons.alignment = "right";
buttons.add("button", undefined, "Annuler", { name: "cancel" });
buttons.add("button", undefined, "Convertir", { name: "ok" });
if (dlg.show() !== 1) {
return null;
}
return {
includeINDT: includeINDT.value,
overwrite: overwrite.value,
skipHidden: skipHidden.value,
stopOnError: stopOnError.value
};
}
function scanFolder(currentSourceFolder, currentExportFolder) {
var entries;
var i;
var entry;
var childExportFolder;
try {
entries = currentSourceFolder.getFiles();
} catch (e) {
stats.failed++;
log("DOSSIER ILLISIBLE", currentSourceFolder.fsName, formatError(e));
if (settings.stopOnError) {
throw e;
}
return;
}
entries.sort(sortByName);
for (i = 0; i < entries.length; i++) {
entry = entries[i];
if (settings.skipHidden && isHidden(entry)) {
continue;
}
if (entry instanceof Folder) {
if (samePath(entry, exportRoot)) {
continue;
}
childExportFolder = new Folder(currentExportFolder.fsName + "/" + entry.name);
if (!ensureFolder(childExportFolder)) {
stats.failed++;
log(
"DOSSIER NON CRÉÉ",
childExportFolder.fsName,
"Impossible de créer le dossier de destination."
);
if (settings.stopOnError) {
throw new Error("Impossible de créer : " + childExportFolder.fsName);
}
continue;
}
scanFolder(entry, childExportFolder);
continue;
}
if (entry instanceof File && isSupportedFile(entry)) {
stats.found++;
convertFile(entry, currentExportFolder);
}
}
}
function convertFile(sourceFile, destinationFolder) {
var document = null;
var openedByScript = false;
var destinationFile = buildDestinationFile(sourceFile, destinationFolder);
try {
if (isDocumentAlreadyOpen(sourceFile)) {
stats.skipped++;
log(
"IGNORÉ",
sourceFile.fsName,
"Le document est déjà ouvert dans InDesign."
);
return;
}
if (destinationFile.exists) {
if (!settings.overwrite) {
stats.skipped++;
log(
"IGNORÉ",
sourceFile.fsName,
"Le fichier IDML existe déjà : " + destinationFile.fsName
);
return;
}
if (!destinationFile.remove()) {
throw new Error(
"Impossible de remplacer le fichier IDML existant : " +
destinationFile.fsName
);
}
}
document = app.open(sourceFile, false);
openedByScript = true;
/*
IDML est exposé par le DOM InDesign via
ExportFormat.INDESIGN_MARKUP.
*/
document.exportFile(
ExportFormat.INDESIGN_MARKUP,
destinationFile,
false
);
if (!destinationFile.exists) {
throw new Error(
"InDesign n’a pas créé le fichier IDML attendu."
);
}
stats.exported++;
log("EXPORTÉ", sourceFile.fsName, destinationFile.fsName);
} catch (e) {
stats.failed++;
log("ÉCHEC", sourceFile.fsName, formatError(e));
if (settings.stopOnError) {
throw e;
}
} finally {
if (openedByScript && document && document.isValid) {
try {
document.close(SaveOptions.NO);
} catch (closeError) {
log(
"AVERTISSEMENT",
sourceFile.fsName,
"Fermeture impossible : " + formatError(closeError)
);
}
}
}
}
function buildDestinationFile(sourceFile, destinationFolder) {
var baseName = sourceFile.name.replace(/\.[^\.]+$/, "");
var extension = getExtension(sourceFile.name);
var candidate = new File(destinationFolder.fsName + "/" + baseName + ".idml");
/*
Évite une collision rare lorsque deux fichiers du même dossier
portent le même nom avec les extensions .indd et .indt.
*/
if (
extension === "indt" &&
candidate.exists &&
!settings.overwrite
) {
candidate = new File(
destinationFolder.fsName + "/" + baseName + "__modele.idml"
);
}
return candidate;
}
function isSupportedFile(file) {
var extension = getExtension(file.name);
if (extension === "indd") {
return true;
}
return settings.includeINDT && extension === "indt";
}
function getExtension(name) {
var match = name.toLowerCase().match(/\.([^.]+)$/);
return match ? match[1] : "";
}
function ensureFolder(folder) {
if (folder.exists) {
return true;
}
/*
Folder.create() ne crée pas toujours toute une chaîne absente.
La récursion garantit que le parent existe déjà.
*/
try {
return folder.create();
} catch (e) {
return false;
}
}
function isDocumentAlreadyOpen(file) {
var i;
var doc;
var filePath = normalizePath(file.fsName);
for (i = 0; i < app.documents.length; i++) {
doc = app.documents[i];
try {
if (
doc.saved &&
normalizePath(doc.fullName.fsName) === filePath
) {
return true;
}
} catch (e) {
// Document sans chemin exploitable : sans incidence.
}
}
return false;
}
function hasUnsavedDocuments() {
var i;
for (i = 0; i < app.documents.length; i++) {
try {
if (app.documents[i].modified) {
return true;
}
} catch (e) {}
}
return false;
}
function samePath(a, b) {
return normalizePath(a.fsName) === normalizePath(b.fsName);
}
function normalizePath(path) {
var normalized = String(path).replace(/\\/g, "/");
if ($.os.toLowerCase().indexOf("windows") >= 0) {
normalized = normalized.toLowerCase();
}
return normalized.replace(/\/+$/, "");
}
function isHidden(entry) {
/*
Le point initial couvre les éléments Unix/macOS.
La propriété hidden, lorsqu’elle est disponible, couvre aussi
certains éléments masqués sous Windows.
*/
if (/^\./.test(entry.name)) {
return true;
}
try {
return entry.hidden === true;
} catch (e) {
return false;
}
}
function sortByName(a, b) {
var nameA = a.name.toLowerCase();
var nameB = b.name.toLowerCase();
if (nameA < nameB) {
return -1;
}
if (nameA > nameB) {
return 1;
}
return 0;
}
function log(status, source, detail) {
logLines.push(
[
formatDate(new Date()),
status,
source || "",
detail || ""
].join("\t")
);
}
function logHeader() {
logLines.push(SCRIPT_NAME + "\tVersion " + SCRIPT_VERSION);
logLines.push("Début\t" + formatDate(stats.startedAt));
logLines.push("Dossier source\t" + sourceRoot.fsName);
logLines.push("Dossier export\t" + exportRoot.fsName);
logLines.push(
"Options\tINDT=" + settings.includeINDT +
"; remplacement=" + settings.overwrite +
"; masqués ignorés=" + settings.skipHidden +
"; arrêt sur erreur=" + settings.stopOnError
);
logLines.push("");
logLines.push("Date et heure\tÉtat\tSource\tDétail");
}
function writeLog() {
var logFile = new File(exportRoot.fsName + "/rapport_export_idml.txt");
var summary = [
"",
"RÉSUMÉ",
"Fichiers détectés\t" + stats.found,
"Exports réussis\t" + stats.exported,
"Fichiers ignorés\t" + stats.skipped,
"Échecs\t" + stats.failed,
"Fin\t" + formatDate(stats.finishedAt),
"Durée\t" + formatDuration(stats.finishedAt - stats.startedAt)
];
logFile.encoding = "UTF-8";
logFile.lineFeed = "Unix";
try {
if (logFile.open("w")) {
logFile.write(logLines.concat(summary).join("\n"));
logFile.close();
}
} catch (e) {
try {
if (logFile.opened) {
logFile.close();
}
} catch (ignore) {}
alert(
"Le traitement est terminé, mais le journal n’a pas pu être écrit :\r" +
formatError(e),
SCRIPT_NAME,
true
);
}
}
function showSummary() {
var message =
"Traitement terminé.\r\r" +
"Fichiers détectés : " + stats.found + "\r" +
"Exports réussis : " + stats.exported + "\r" +
"Fichiers ignorés : " + stats.skipped + "\r" +
"Échecs : " + stats.failed + "\r" +
"Durée : " + formatDuration(stats.finishedAt - stats.startedAt) + "\r\r" +
"Dossier de sortie :\r" + exportRoot.fsName + "\r\r" +
"Journal : rapport_export_idml.txt";
alert(message, SCRIPT_NAME, stats.failed > 0);
}
function formatError(error) {
var parts = [];
try {
if (error.name) {
parts.push(error.name);
}
} catch (e1) {}
try {
if (error.message) {
parts.push(error.message);
} else {
parts.push(String(error));
}
} catch (e2) {
parts.push("Erreur inconnue");
}
try {
if (error.line) {
parts.push("ligne " + error.line);
}
} catch (e3) {}
return parts.join(" — ");
}
function formatDate(date) {
function pad(value) {
return value < 10 ? "0" + value : String(value);
}
return (
date.getFullYear() + "-" +
pad(date.getMonth() + 1) + "-" +
pad(date.getDate()) + " " +
pad(date.getHours()) + ":" +
pad(date.getMinutes()) + ":" +
pad(date.getSeconds())
);
}
function formatDuration(milliseconds) {
var totalSeconds = Math.max(0, Math.round(milliseconds / 1000));
var hours = Math.floor(totalSeconds / 3600);
var minutes = Math.floor((totalSeconds % 3600) / 60);
var seconds = totalSeconds % 60;
var parts = [];
if (hours > 0) {
parts.push(hours + " h");
}
if (minutes > 0 || hours > 0) {
parts.push(minutes + " min");
}
parts.push(seconds + " s");
return parts.join(" ");
}
main();
}());