Copy link to clipboard
Copied
Hi--I found a free Javascript online that ALMOST does what I want it to. But it appears to be missing (for me) the most important feature. I'm hoping that someone here can modify it for me or point me towards something that will accomplish the task. (The original author seems to have been offline since 2019.)
What I want to create is a document made up of several placed external files. Each placed file is multi-lingual, with translations contained on separate layers. For example, each placed file has English text on layer EN, French text on layer FR, Spanish text on layer ES, etc. My goal is to run the script while in the "parent" document--allowing me to choose the desired translated layer and have all of the placed files "flip" to the correct translation. The script I found (text file version attached) ALMOST works...however, it does not seem to "batch" convert all the placed files at once. For example, I placed 3 files on the parent document as a test, ran the script, and selected FR. It only "flipped" one of them. The others stayed as I originally saved them, with all four layers showing. I only got the other two to "flip" by selecting each one individually and running the script on each file.
What's missing from the attached script that won't allow me to run this and "flip" everything at once? Can it be fixed easily? Or is there a better solution? I appreciate any help that I can get with this. Thank you!
Copy link to clipboard
Copied
Hi @suep89793525, the script you linked by CrazyPanda is great, and I probably could have adjusted it to run the way you want, but it wasn't structured ideally for that, and anyway I always like to learn, so I have written my own version. Please give it a try. Hasn't been tested much, so please let me know here if you find a bug and I will fix. It should work with placed .ai, .pdf, and .indd files.
- Mark
/**
* Sets layer visibility of all placed items in active document.
* All layers are set to invisible, unless the layer name exists
* in `settings.visibleLayerNames`
* NOTES:
* - Adjust the settings object if you want to pre-populate
* the layerNames and visibleLayer.
* - Do not specify `layerNames` in settings if you want
* to choose from *every* layer in every placed item.
* @author m1b
* @discussion https://community.adobe.com/t5/indesign-discussions/batch-converting-layers-on-insets-so-close-but-need-help/m-p/13885184
*/
var settings = {
// layerNames: ['EN', 'ES', 'FR'], // uncomment this to limit the choices
visibleLayerNames: ['FR'],
showUI: true,
};
function main() {
var doc = app.activeDocument,
items = getLinkedPdfs(doc),
identifiers = [];
if (items.length == 0) {
alert("No suitable linked files in document.");
return;
}
// keep a stringified identifier
// to bypass a bug with indesign
// that assigns a new id every
// time layer visibility is updated
for (var i = 0; i < items.length; i++)
identifiers.push(stringify(items[i]));
// if no layer names specified
// in settings, collect them all
settings.layerNames = settings.layerNames || getLayerNames(items);
settings.visibleLayerNames = settings.visibleLayerNames || [];
// show UI
if (
settings.showUI
&& chooseLayers(settings) == false
)
// user cancelled UI
return;
// set each layer's visibility
for (var i = items.length - 1; i >= 0; i--) {
if (!items[i].isValid)
continue;
var len = items[i].graphicLayerOptions.graphicLayers.length;
items[i].graphicLayerOptions.updateLinkOption = UpdateLinkOptions.KEEP_OVERRIDES;
for (var j = 0; j < len; j++) {
// get the item each time (because of bug mentioned earlier)
var item = itemByStringifier(getLinkedPdfs(doc), identifiers[i], stringify);
if (item.isValid)
item.graphicLayerOptions.graphicLayers[j].currentVisibility = indexOf(item.graphicLayerOptions.graphicLayers[j].name, settings.visibleLayerNames) !== -1;
}
}
};
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Set Layer Visibility');
/**
* Returns array of linked pdf files.
* @author m1b
* @version 2023-06-24
* @param {Document} doc - an Indesign Document.
* @returns {Array<PageItem>}
*/
function getLinkedPdfs(doc) {
var items = doc.links.everyItem().parent,
linkedPdfs = [];
for (var i = 0; i < items.length; i++)
if (
items[i].hasOwnProperty('pdfAttributes')
&& items[i].hasOwnProperty('graphicLayerOptions')
&& items[i].itemLink.status === LinkStatus.NORMAL
)
linkedPdfs.push(items[i]);
return linkedPdfs;
};
/**
* Gets a single item from array `items` based
* on the result of a stringifier function.
* @author m1b
* @version 2023-06-23
* @param {Array<PageItem>} items - an array of items from which to choose.
* @param {String} identifier - the string to search for.
* @param {Function} stringifier - a stringifying function.
* @returns {PageItem}
*/
function itemByStringifier(items, identifier, stringifier) {
for (var i = 0; i < items.length; i++)
if (stringifier(items[i]) === identifier)
return items[i];
};
/**
* Generate a string just for the purpose
* of identifying a particular linked item.
* @author m1b
* @version 2023-06-23
* @param {PageItem} item - an Indesign placed item.
* @returns {String}
*/
function stringify(item) {
var str = '',
delim = '|'
if (
item.itemLink
&& item.itemLink.filePath
)
str += item.itemLink.filePath + delim;
if (item.graphicLayerOptions.graphicLayers.length > 0)
str += item.graphicLayerOptions.graphicLayers.everyItem().name.join(delim) + delim;
if (item.parentPage)
str += item.parentPage.name + delim;
return str;
};
/**
* Returns index of obj in arr.
* Returns -1 if not found.
* @param {any} obj
* @param {Array} arr
* @returns {Number}
*/
function indexOf(obj, arr) {
for (var i = 0; i < arr.length; i++)
if (arr[i] === obj)
return i;
return -1;
};
/**
* Collects array of layer names from linked pdf items.
* @param {Array<PageItem>} items - the linked pdfs.
* @returns {Array<String>}
*/
function getLayerNames(items) {
var layerNames = [],
already = {};
for (var i = 0; i < items.length; i++)
for (var j = 0; j < items[i].graphicLayerOptions.graphicLayers.length; j++)
if (!already[items[i].graphicLayerOptions.graphicLayers[j].name]) {
layerNames.push(items[i].graphicLayerOptions.graphicLayers[j].name);
already[items[i].graphicLayerOptions.graphicLayers[j].name] = true;
}
return layerNames;
};
/**
* Shows UI for selecting layers of document.
* @author m1b
* @version 2023-06-09
* @param {Object} settings
* @param {Document} settings.doc - an Indesign Document.
*/
function chooseLayers(settings) {
var layerNames = settings.layerNames,
selectedLayerNames = [],
w = new Window("dialog { text:'Set Layer Visibility' }"),
layersListBox = w.add("ListBox {alignment:['fill','fill'], properties:{multiselect:true, showHeaders:true, numberOfColumns:1, columnTitles:['Layer'] } }"),
buttons = w.add("Group { orientation: 'row', alignment: ['right','bottom'], margins:[0,12,0,22] }"),
cancelButton = buttons.add("Button { text:'Cancel', properties: { name:'cancel' } }"),
okButton = buttons.add("Button { text:'Set Visibility', properties: { name:'ok' } }");
// populate layers menu
for (var i = 0; i < layerNames.length; i++)
layersListBox.add('item', layerNames[i]);
/**
* Updates `selectedLayerNames`
* when listbox selection changes.
*/
layersListBox.onChange = function () {
var sel = this.selection;
selectedLayerNames = [];
settings.layers = [];
if (sel == null)
return;
for (var i = 0; i < sel.length; i++)
selectedLayerNames.push(sel[i].text);
};
// set the initial selection
var sel = [];
for (var i = 0; i < settings.visibleLayerNames.length; i++) {
var index = indexOf(settings.visibleLayerNames[i], settings.layerNames);
if (index != -1)
sel.push(index);
}
layersListBox.selection = sel;
layersListBox.maximumSize.height = w.maximumSize.height - 200;;
layersListBox.active = true;
if (w.show() == 2)
// user cancelled
return false;
// add the selected layers to settings object
settings.visibleLayerNames = selectedLayerNames;
};
Edit 2023-06-24: added some error checking.
Copy link to clipboard
Copied
Mark--Thank you so much! I tested your script on my three-inset sample page and so far it works perfectly! I'm going to try some other tests with AI and PDF files since our parent documents (spec sheets) also include these elements. My confidence level is high...but I'll defintely let you know if I run into any bugs along the way. Assuming all goes well, you have just saved me and my co-workers a tremendous amount of time and effort. Wow.
Copy link to clipboard
Copied
Hi again--I just tried to drop a multi-lingual AI file into my container document and got this error. Any thoughts?
Copy link to clipboard
Copied
Can you make a demo file for me to test with?
Copy link to clipboard
Copied
Here you go. The "container" file is Language Flip test; the others are insets. For some reason I couldn't attach the dimensional image as an AI file (its original format) so I changed it to a SVG which you should be able to open in Illustrator. Please let me know if you can work with these and what you find out. Thank you!
Copy link to clipboard
Copied
That's great thanks. Can you post the .ai file as a .pdf rather than a svg? You can either save as pdf or just change the file extension from .ai to .pdf.
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Thanks @suep89793525, that's perfect. But I tried them out and couldn't find an error. I was able to do any combination of layer visibility that I tried. I have updated the script slightly with some extra error checking, such as if the linked file is missing or modified. Can you try it again (using the same demo file you posted here) and tell me which combination of layers gives the error?
- Mark
Copy link to clipboard
Copied
Good morning, Mark--Do you have an updated version of the script that I can load onto my system? If so, please send it and I will continue my tests. Thanks! -- Sue
Copy link to clipboard
Copied
Hi Sue, the script above is the new version—I edited it. I it still doesn't work, please post a demo file that I can test with.
- Mark
Copy link to clipboard
Copied
I think you're on to something. Initial tests look good. Wherever and whatever the bug was, that seems to have squashed it! I'll play with this and continue my tests. And, for future communication on this, perhaps we can take it offline to spare the Adobe masses. 🙂 You can find me here, so please shoot me an email if you agree: suep@alto-shaam.com,
Thank you SO much for your help with this. It's greatly appreciated.
Find more inspiration, events, and resources on the new Adobe Community
Explore Now