Copy link to clipboard
Copied
Hello everyone,
I'm really sorry if this has already been asked, I have found discussions that touch on it, but haven't found any suggestions or solutions.
I am a web developer, with no inDesign experience, our graphic designer uses it to build our flyers.
We have been talking about translating the flyers to another language, and I have been working on making them interactive (with an image map)on our website.
If I'm going to suggest we revise the flyer structure for automating the translation, I'd like to also handle the image mapping (pulling image + area coordinates)
The thought was to write a js script that will pull the text frames from the file so I can work with them using other scripts to translate, get coordinates, etc.
I have more or less succeeded in doing this using the textFrame's name.
I'm currently renaming each item in the Layers window with a key-value naming structure (000-000-000|Title, 000-000-000|Description) and then splitting the name by '|' to get the product code [0] and the textFrame 'tag' [1]. Then I can run the 'tag' portion of the content through a translation script, or coordinate script as needed.
But there are dozens of pages with numerous products on each page, and multiple fields (title, description, price, quantity, product number) for each product.
I don't want to propose our designer meticulously rename thousands of elements.
I have found the Tags window to be much quicker to associate a type to each textFrame. But I haven't been able to work with the tags through script...
From what I've read, CS5 and later doesn't allow you to get a tag/label through scripting.
Is this true? Is anyone aware of any way around it?
-TLDR-
I have thousands of text (and image) elements in a InDesign file, and I would like to pull their contents out with a script and process them depending on the text field's type (product description, image, price, etc.).
Tags/Labels seem perfect, as I could just loop through all textFrame elements, and say if has tag 'description' then pass into translate(), if image getCoords().
And they are rather quick to associate with elements.
But from what I've read CS5 + doesn't allow you to work with tags through scripts in this way.
Any suggestions to accomplish this without working with the textFrame's names? (I'd like to avoid adding that much work to our graphic designer's monthly process)
If it is relevant I'm using inDesign CC 2017 V- 12.1.0.56
Thanks in advance for any input or direction you can provide. InDesign is not something I am familiar with 😕
Copy link to clipboard
Copied
Hi,
if you mean the following:
doc.pageItems.item("String")
doc.pageItems.itemByName("String")
this will work with pageItem.name only with InDesign CS5 and above.
And you get always one item in return even if more than one pageItems share the same name.
Before, in CS4, you could use the label property:
pageItem.label = "String"
and retrieve all pageItems with the same label value with:
doc.item("String");
All that said, there is one other problem you have to keep in mind:
pageItems that are nested in groups, are anchored or nested elsewhere cannot be reached with:
doc.pageItems.item("String")
doc.pageItems.itemByName("String")
If you are looking for all items, nested or not, you could use:
var nearlyAllItems = doc.allPageItems; // Returns array of pageItems
And you would loop this array to look after a distinct page item with a distinct name or label value.
Why did I named this variable nearlyAllItems and not reallyAllItems ?
Because the allPageItems array omits objects that are in states of multistate objects that are not the active state.
They cannot be reached with allPageItems!
But for this problem there is a hack! A trick I found several years ago. With every pageItems comes an id. And we could loop page items by id. That will also find page items in states that are not the active ones. Also things we never thought about as page items. What we need to do this effectively is knowing e.g. about the highest id number and possibly the lowest id number that makes sense. You could test this for yourself: Add a new document, add a simple rectangle to the page and ask about the value for id of the rectangle.
var doc = app.documents.add();
var rect = doc.rectangles.add();
alert( rect.id.toString() ); // Returns 216 in my case, your case could be different.
A good bet is that we can leave out id numbers 1 to 100, maybe 1 to 150, if we loop all page items by their ids.
And the highest number? Just add a rectangle to the document, read out its id number and remove it. Use that number to limit your loop.
Just an experiment you should do with the ESTK ( ExtendScript Toolkit ) connected to InDesign CC 2018.1 with an open document:
var doc = app.documents[0];
var tempRect = doc.rectangles.add();
var idMax = tempRect.id;
var e;
tempRect.remove();
for( var n=150; n < idMax-1 ; n++ )
{
try
{
// getElements()[0] is the key feature here that will resolve a pageItem to the object that it really is:
var currentItem = doc.pageItems.itemByID(n).getElements()[0];
$.writeln( n +"\t"+ currentItem.constructor.name +"\t"+currentItem.name +"\t"+ currentItem.label );
}catch( e )
{
$.writeln(n +"\t"+ e.message );
};
}
Below the result of a new empty document with a different document preset than the one I did before where the highest id number was 216. This time it was 221.The loop ran from 150 to 221. If you'll test this, you could run it with 1 to the max number to see if there are interesting things you might find in the lower numbers.
Note: A page item could be addressed e.g. by its id as well:
doc.pageItems.itemByID(Number);
Important:
With getElements()[0] you can resolve that page item and know exactly what kind of pageItem this is, a rectangle, a textFrame or something else.
And with doc.pageItems.itemByID(Number) you can always drill through nested structures like groups etc.pp. to access the item.
150 ObjectStyle [Einfacher Textrahmen]
151 ObjectStyle [Einfaches Raster]
152 Object is invalid
153 CrossReferenceFormat Vollständiger Absatz und Seitenzahl
154 CrossReferenceFormat Vollständiger Absatz
155 CrossReferenceFormat Absatztext und Seitenzahl
156 CrossReferenceFormat Absatztext
157 CrossReferenceFormat Absatznr. und Seitenzahl
158 CrossReferenceFormat Absatznr.
159 CrossReferenceFormat Name des Textankers und Seitenzahl
160 CrossReferenceFormat Name des Textankers
161 CrossReferenceFormat Seitenzahl
162 TOCStyle [Standard]
163 CompositeFont [No composite font]
164 CompositeFontEntry Kanji
165 Object is invalid
166 CompositeFontEntry Kana
167 CompositeFontEntry Interpunktion
168 CompositeFontEntry Symbole
169 CompositeFontEntry Latein
170 CompositeFontEntry Zahlen
171 XmlStory
172 Object is invalid
173 Object is invalid
174 Object is invalid
175 Object is invalid
176 Object is invalid
177 Object is invalid
178 Object is invalid
179 Object is invalid
180 Object is invalid
181 Object is invalid
182 Object is invalid
183 Object is invalid
184 Object is invalid
185 Object is invalid
186 Object is invalid
187 Object is invalid
188 XMLTag Root
189 Object is invalid
190 Object is invalid
191 Object is invalid
192 Object is invalid
193 Object is invalid
194 Object is invalid
195 Object is invalid
196 Object is invalid
197 Layer Internal_pages_layer_name
198 Layer Ebene 1
199 TrapPreset k[No Trap Preset]
200 TrapPreset kDefaultTrapStyleName
201 Spread
202 Object is invalid
203 Object is invalid
204 Object is invalid
205 Object is invalid
206 Page 1
207 Section
208 MasterSpread A-Musterseite
209 Object is invalid
210 Object is invalid
211 Object is invalid
212 Object is invalid
213 Page A
214 Page A
215 Assignment Nicht zugewiesener InCopy-Inhalt
216 Object is invalid
217 Object is invalid
218 Object is invalid
219 Object is invalid
220 Object is invalid
221 Object is invalid
As you can see from this list I'm running a German InDesign version. And, it might be a surprise to you, you could also address a page with doc.pageItems.itemByID(Number). In my case, yours will be different, by id number 206. That's the page named 1. It has an empty string as label by default, but a name, and that is "1".
Please note, that in DOM documentation of all the objects listed above you will find none documented under pageItems. Only by ID you can see them as pageItems. "Normal" pageItems like rectangles, textFrames etc. pp. will be listed as well, if there are any. And this time really ALL pageItems of the document are in the list. Also the ones that are deeply nested!
Happy hunting after named or labeled items!
Regards,
Uwe
Copy link to clipboard
Copied
Thank you so much for the detailed response.
Just to clarify, in these later versions of inDesign, there is no way to group items and then get an array/list of those group items via script?
As I mentioned, I did have it 'working' by using the items Name. But I really don't want to ask our graphics designer to carefully name 6 elements for each of the hundreds of products when she creates the flyers each month.
If that's really the best solution given the version we are using, I may have to suggest that. But if there was any way to associate a tag/label/class identifier to a group of elements so I could do something like...
//GET DESCRIPTION ITEMS
descList = [];
descItems = app.activeDocument.textFrames.item("description");
for ( i = 0; i < descItems.length; i ++ ) {
descList.push( translateText( descItems.contents ) );
}
//GET PRICE ITEMS
priceList = [];
priceItems = app.activeDocument.textFrames.item("price");
for ( i = 0; i < priceItems .length; i ++ ) {
priceList .push( formatPrice( priceItems.contents ) );
}
//GET IMAGE ITEMS
imageList = [];
imageItems = app.activeDocument.textFrames.item("image");
for ( i = 0; i < imageItems .length; i ++ ) {
imageList .push( getCoordinates( imageItems ) );
}
function translateText( textString ) { ... }
function formatPrice( priceString ) { ... }
function getCoordinates( imageItem ) { ... }
Again, I have little to no experience with inDesign directly beyond the past few days, but it seems like it was a very practical feature to be able to group items and retrieve a list of them. I don't see why this would have been removed in the more recent versions.
Is it a reasonable approach to consider getting a version of CS4, and trying to open the file in that just to run it through a script like this?
Thank you again,
I truly appreciate you taking the time to provide such an informative reply.
Copy link to clipboard
Copied
aarong18402343 wrote
Thank you so much for the detailed response.
Just to clarify, in these later versions of inDesign, there is no way to group items and then get an array/list of those group items via script?
…
If you identified a group you'll get an array of all page items of a group with:
var allItemsOfGroup = group.allPageItems;
If you want to identify text frames you best resolve the items as you loop.
for( var n=0;n<allItemsOfGroup.length;n++ )
{
var currentItem = allItemsOfGroup.getElements()[0];
if( currentItem.constructor.name == "TextFrame" && currentItem.label == "MyLabel" )
{
/* do something*/
};
};
Regards,
Uwe
Copy link to clipboard
Copied
This sounds promising!
But how are items added to a group? Is this done with the items name through scripting as well?
I also wanted to ask about names vs tags regarding tables. Our flyers currently have lists of products just in a text box.
000-000-000 title quantity price
000-000-000 title quantity price
000-000-000 title quantity price
I was going to suggest we use tables,
1. So I can distinguish between rows for the image map, to link to different products
2. So I can distinguish between the columns, to know what to translate (text) and what to format (currency)
3. So it's hopefully slightly easier for our designer to adjust styling and column widths, etc. if needed
But to further tease me with how convenient tags/labels would be for me in this specific instance, it looked like the name is attached to the table, so rows and columns can't have their own names, but they can be given different tags.
Is that correct?
Sorry for all the newbie questions. You have been incredibly helpful.
Copy link to clipboard
Copied
Cells and tables can be labeled. Property label, value String.
Property name isn't worth a try, because it's not unique and tied to a cell's position in the grid of rows and columns.
Boy, you'll have a steep lerning curve especially with InDesign tables.
Regards,
Uwe
Copy link to clipboard
Copied
Laubender wrote
Boy, you'll have a steep lerning curve especially with InDesign tables.
I am starting to realize this 😕
I'm installing our previous CS4 version right now to see if it's easy enough to just open the file to run the script.
But if not it sounds like my best bet will be to have a conversation about using a more deliberate naming structure for the elements we are looking to map or translate.
Thanks again for all the help.
You have probably saved me hours of additional research and trial.
Copy link to clipboard
Copied
I hope you already realized this:
There is DOM documentation available by Jongware for InDesign CS to CS6.
Especiall look into the chm files for excellent searchability.
For the latest available InDesign DOM documentation which is for CC 2018 ( not CC 2018.1) look here:
https://www.indesignjs.de/extendscriptAPI/indesign-latest/#about.html
Best,
Uwe
Copy link to clipboard
Copied
https://forums.adobe.com/people/Guild+-+Office+Pro wrote
…
I'm installing our previous CS4 version right now to see if it's easy enough to just open the file to run the script. …
If the script in not meant to run with CS4 that's no good idea. The designers will hate you if they are forced to work with CS4 when they are currently on CC 2017.1. Better concentrate on version CC 2017.1.
Regards,
Uwe
Copy link to clipboard
Copied
I managed to get and update the element's contents pulled via XML tags using xpaths in our current InDesign version
//GET LIST OF 'Title' ELEMENTS
var doc = app.activeDocument;
var xmlTag = doc.xmlElements[0];
var titleTag = xmlTag.evaluateXPathExpression("//Title")
for(var i=0;i<titleTag.length;i++)
{
//GET CONTENTS
alert('content ' + i + ': ' + titleTag.xmlContent.contents);
//UPDATE CONTENTS
titleTag.contents = "Translation of : " + titleTag.contents;
}
But I want to pull the translated text (and alternate pricing, etc.) from a spreadsheet. Ideally using the product number as an identifier.
Ex:
Code EnglishTitle FrenchTitle PriceLvl1 PriceLvl2
000-000 itemA itemÀ 1.99 2.99
I thought the most logical approach would be to use the product code as the element's name.
However, every attempt I've made to get the name using the XML object has returned blank values or given errors.
//GET LIST OF 'Title' ELEMENTS
var doc = app.activeDocument;
var xmlTag = doc.xmlElements[0];
var titleTag = xmlTag.evaluateXPathExpression("//Title")
for(var i=0;i<titleTag.length;i++)
{
//GET CONTENTS
alert('content ' + i + ' : ' + titleTag.xmlContent.contents);
//GET NAME
alert('name ' + i + ' : ' + titleTag.xmlContent.name); //BLANK
alert('name ' + i + ' : ' + titleTag.name); //ERROR (Object does not support the property or method 'name')
}
My current 'quick fix' workaround for this is to check all the textframe elements to find contents that match the XML object, then I can get that textFrame's name to work with.
//GET LIST OF 'Title' ELEMENTS
var doc = app.activeDocument;
var xmlTag = doc.xmlElements[0];
var titleTag = xmlTag.evaluateXPathExpression("//Title")
for(var i=0;i<titleTag.length;i++)
{
//GET CONTENTS
alert('content ' + i + ': ' + titleTag.xmlContent.contents);
//FIND TEXTFRAME MATCH
for (var j=0; j<app.activeDocument.textFrames.length; j++)
{
if(app.activeDocument.textFrames
{
alert("Found Match - " + app.activeDocument.textFrames
app.activeDocument.textFrames
}
}
}
This allows me to get the textframe name, but it is clearly not an efficient approach, as it has to loop through all textframes for each XML tag I modify. And if anything shares the same contents (which is entirely possible with prices) it could confuse the two elements.
Is there a way to get the textframe's name attribute (if that's the correct terminology for inDesign) from the associated XML element?
Copy link to clipboard
Copied
Hi,
don't know if this is the case with your sample, but XML explicitly disallows numbers as the first character of an element name.
Regards,
Uwe
Copy link to clipboard
Copied
Oh, yes I have been putting all my element names in tag brackets/guillemets to avoid this issue.
Ex: <000-223>
Copy link to clipboard
Copied
Hi,
You might want to investigate insert/extract label. Labels are very flexible in that just about any text can be inserted into and extracted from a label. insertLabel uses a name/value pair. extractLabel requires the name to get the text stored. You can even insert a complete script (written as plain text) and run the inserted script using doScript.
For example:
var myScript = "alert ('Hello')";
var selRef = app.selection[0];
selRef.insertLabel("script", myScript);
//later as part of another script, extract and run the inserted script
var aScript = selRef.extractLabel("script");
app.doScript(aScript);
Just a thought.
Copy link to clipboard
Copied
Hi,
the main problem of our OP will stay. How to efficiently label or name the items.
If there is a scheme for this one could write a script that does exactly this without involving the user very much.
On the other hand there are translation software suits that are using memory systems for phrases and other standard expressions that are working with IDML. Maybe that's the best way to go regarding translations.
Best,
Uwe
Copy link to clipboard
Copied
I have done a little research into translation software. But other people in the company have worked out the translations already, so I thought simply pulling the data, swapping it and plugging it back in would be the easiest approach on my end.
If there are some suits/plugins/scripts that would translate directly from the file that might still be worth considering. Our French clients have been a little 'particular' about the translation in the past (Quebec French / France French) so I know some of our board doesn't want to rely fully on automated translations. But still something I may look into more.
I was really hoping I would also be able to address the image mapping that I mentioned in my first post.
I originally put together / came across a script to pull image coordinates. But it did all graphics.
I was hoping if our designer was able to tag items, I could use those identifiers to determine what I want to get the coordinates of, and use for the image map. That way customers could click on the images or text to view a product.
Copy link to clipboard
Copied
Thanks for the response.
If I'm following the suggestion correctly; it would still require me to address each item by name through scripting.
I'm trying to avoid using the name, as there are just so many to work with. And I think a much higher mistake of typos and human error.
I did come across some info on adding labels to items through scripting in CS5+, but I don't think really it addresses my issue.
I appreciate the suggestion though.