Change Letter Case

Script for Adobe InDesign

Change matching text to uppercase, lowercase, title case, or sentence case. A recent project I had to convert a directory created in InDesign to HTML for a website. In the layout, the categories and company names used a paragraph style set to all-caps, and the client wanted the same look online. But the Content Management System where it was going didn't have a way to set up classes for the all-caps text decoration. So I made this script to convert the text in the particular paragraph styles to actual capital letters, not just a styling assignment. Then I figured add the character style option and match with GREP, too. Could come in handy in the future.

  • Match with GREP
  • Match by character style
  • Match by paragraph style
  • Adapt open source to customize or create other scripts
Download
Change Letter Case

FREE to download
Please make a contribution

Many scripts are free to download thanks to the support of users. Help me keep developing new scripts by supporting my work. Click the button to make a contribution of any amount. Thank you.

How-to Video

How to use the script

Set options described below, and click the OK button to proceed.

Document — searches all stories of the document that is currently open and the top-most window if multiple documents are open.

Story — searches only the selected story. If no story is selected, the choice is disabled. The user may also choose Document to increase the scope of text searched.

GREP — enter a GREP expression just as in the InDesign Find/Change dialog. Characters that match the GREP expression are changed to the letter case set below.

Character Style — select a character style and characters assigned the style are changed to the letter case set below.

Paragraph Style — select a paragraph style and paragraphs assigned the style are changed to the letter case set below. Changes the entire paragraph.

Change to — the desired letter case. Choices are UPPERCASE, lowercase, Title Case, and Sentence case.

Special handling of Title Case

Letter case is changed using methods that InDesign uses, built-in to the program. Unfortunately, InDesign isn’t too intelligent about converting to Title Case, as it simply capitalizes every word without consideration for articles, prepositions, etc., that should remain lowercase. To overcome this flaw, the script has a list of words to make lowercase after applying Title Case. The script is open source so that anyone may edit the code, including the list of words to make lowercase. Open the script in any text editor and search for “lowerTitleCase”, the name of the variable that is the list of words to keep lowercase in titles (it is very near the top of the code, the second variable declared, after the script title). It’s a simple matter to add additional words if desired. Just ensure each word is on its own line, is wrapped in quotation marks, and all except the last word has a trailing comma. Any words with a period, for example “etc.”, must have the period double-escaped because the character is a regular expression command. The word “etc.” is already in the list. Have a look at the code and see how the period is handled. Do the same for any other words with a period. Any questions contact the author William at any time.

Source code

(download button below)

/*

Change Letter Case
Copyright 2022 William Campbell
All Rights Reserved
https://www.marspremedia.com/contact

Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

*/

(function () {

    var lowerTitleCase = [
        // articles
        "a",
        "an",
        "the",
        // coordinating conjunctions
        "and",
        "but",
        "of",
        "or",
        // prepositions
        "at",
        "by",
        "to",
        // other
        "etc\\."
    ];

    var title = "Change Letter Case";

    if (!/indesign/i.test(app.name)) {
        alert("Script for InDesign", title, false);
        return;
    }

    // Script variables.
    var changecaseModes;
    var characterStyleNames;
    var doc;
    var error;
    var i;
    var letterCase;
    var paragraphStyleNames;

    // Reusable UI variables.
    var g; //  group
    var gc1; // group (column)
    var gc2; // group (column)
    var p; //  panel
    var w; //  window

    // Permanent UI variables.
    var btnCancel;
    var btnOk;
    var inpGrep;
    var listCharacterStyles;
    var listLetterCase;
    var listParagraphStyles;
    var rbSearchDoc;
    var rbSearchStory;

    // SETUP

    // Define script variables.
    changecaseModes = [
        ChangecaseMode.UPPERCASE,
        ChangecaseMode.LOWERCASE,
        ChangecaseMode.TITLECASE,
        ChangecaseMode.SENTENCECASE
    ];
    letterCase = [
        "UPPERCASE",
        "lowercase",
        "Title Case",
        "Sentence case"
    ];
    // Script requires open document.
    if (!app.documents.length) {
        alert("Open a document", title, false);
        return;
    }
    doc = app.activeDocument;
    // Load styles.
    characterStyleNames = getStyleNames(doc.allCharacterStyles);
    paragraphStyleNames = getStyleNames(doc.allParagraphStyles);

    // CREATE USER INTERFACE

    w = new Window("dialog", title);
    w.alignChildren = "fill";
    p = w.add("panel");
    p.alignChildren = "fill";
    // Group of 2 columns.
    g = p.add("group");
    // Groups, columns 1 and 2.
    gc1 = g.add("group");
    gc1.orientation = "column";
    gc1.alignChildren = "left";
    gc2 = g.add("group");
    gc2.orientation = "column";
    gc2.alignChildren = "left";
    // Rows.
    gc1.add("statictext", undefined, "Search:").preferredSize = [-1, 23];
    g = gc2.add("group");
    g.margins = [0, 4, 0, -1];
    rbSearchDoc = g.add("radiobutton", undefined, "Document");
    rbSearchStory = g.add("radiobutton", undefined, "Story");
    gc1.add("statictext", undefined, "GREP:").preferredSize = [-1, 23];
    inpGrep = gc2.add("edittext");
    inpGrep.preferredSize = [250, 23];
    gc1.add("statictext", undefined, "Character Style:").preferredSize = [-1, 23];
    listCharacterStyles = gc2.add("dropdownlist", undefined, characterStyleNames);
    listCharacterStyles.preferredSize = [250, 23];
    // Add empty items so list is minimum two items.
    listCharacterStyles.add("item", " ");
    listCharacterStyles.add("item", " ");
    gc1.add("statictext", undefined, "Paragraph Style:").preferredSize = [-1, 23];
    listParagraphStyles = gc2.add("dropdownlist", undefined, paragraphStyleNames);
    listParagraphStyles.preferredSize = [250, 23];
    // Add empty items so list is minimum two items.
    listParagraphStyles.add("item", " ");
    listParagraphStyles.add("item", " ");
    gc1.add("statictext", undefined, "Change to:").preferredSize = [-1, 23];
    listLetterCase = gc2.add("dropdownlist", undefined, letterCase);
    listLetterCase.preferredSize = [250, 23];

    // Action Buttons
    g = w.add("group");
    g.alignment = "center";
    btnOk = g.add("button", undefined, "OK");
    btnCancel = g.add("button", undefined, "Cancel");

    // Panel Copyright
    p = w.add("panel");
    p.add("statictext", undefined, "Copyright 2022 William Campbell");

    // Event handlers
    listParagraphStyles.onChange = function () {
        if (this.selection.text === " ") {
            this.selection = null;
        }
    };
    listCharacterStyles.onChange = function () {
        if (this.selection.text === " ") {
            this.selection = null;
        }
    };
    btnOk.onClick = function () {
        w.close(1);
    };
    btnCancel.onClick = function () {
        w.close(0);
    };

    // SET SEARCH SCOPE

    rbSearchDoc.value = true;
    rbSearchStory.enabled = false;
    if (app.selection.length) {
        // Get story if one is selected.
        try {
            if (app.selection[0].parentStory) {
                // Enable and set story choice.
                rbSearchStory.enabled = true;
                rbSearchStory.value = true;
            }
        } catch (_) {
            // Ignore.
        }
    }

    // DISPLAY THE DIALOG

    if (w.show() == 1) {
        try {
            app.doScript(process, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, title);
        } catch (e) {
            error = error || e;
            alert("An error has occurred.\nLine " + error.line + ": " + error.message, title, true);
        }
    }

    //====================================================================
    //               END PROGRAM EXECUTION, BEGIN FUNCTIONS
    //====================================================================

    function getStyleNames(o) {
        var a = [];
        var i;
        var name;
        for (i = 0; i < o.length; i++) {
            name = o[i].name;
            // Ignore names that begin with bracket.
            if (/^\[/.test(name)) continue;
            a.push(name);
        }
        a.sort(function (a, b) {
            // Case insensitive.
            var aLow = a.toLowerCase();
            var bLow = b.toLowerCase();
            if (aLow < bLow) return -1;
            if (aLow > bLow) return 1;
            return 0;
        });
        return a;
    }

    function itemByName(o, name) {
        var i;
        for (i = 0; i < o.length; i++) {
            if (name == o[i].name) {
                return o[i];
            }
        }
        return null;
    }

    function process() {
        var changecaseMode;
        var story;
        var titleCase;
        // Preserve preferences.
        var preserve = {
            findChangeTextOptions: app.findChangeTextOptions.properties,
            findGrepPreferences: app.findGrepPreferences.properties,
            findTextPreferences: app.findTextPreferences.properties
        };
        try {
            // Set find change text options.
            app.findChangeTextOptions.properties = {
                includeFootnotes: true,
                includeHiddenLayers: true,
                includeLockedLayersForFind: true,
                includeLockedStoriesForFind: true,
                includeMasterPages: false
            };
            app.findGrepPreferences.findWhat = inpGrep.text;
            if (listCharacterStyles.selection) {
                app.findGrepPreferences.appliedCharacterStyle = itemByName(doc.allCharacterStyles, listCharacterStyles.selection.text);
            }
            if (listParagraphStyles.selection) {
                app.findGrepPreferences.appliedParagraphStyle = itemByName(doc.allParagraphStyles, listParagraphStyles.selection.text);
            }
            if (listLetterCase.selection) {
                changecaseMode = changecaseModes[listLetterCase.selection.index];
                titleCase = (listLetterCase.selection.index == 2);
                if (rbSearchStory.value) {
                    // Story only.
                    story = app.selection[0].parentStory;
                    processStory();
                } else {
                    // Entire document.
                    for (i = 0; i < doc.stories.length; i++) {
                        story = doc.stories[i];
                        if (story.length) {
                            processStory();
                        }
                    }
                }
            }
        } catch (e) {
            error = e;
            throw e;
        } finally {
            // Restore preferences.
            app.findChangeTextOptions.properties = preserve.findChangeTextOptions;
            app.findGrepPreferences.properties = preserve.findGrepPreferences;
            app.findTextPreferences.properties = preserve.findTextPreferences;
        }

        function processStory() {
            var i;
            var m;
            var matches;
            var pattern;
            matches = story.findGrep();
            for (m = 0; m < matches.length; m++) {
                matches[m].texts[0].changecase(changecaseMode);
                if (titleCase) {
                    for (i = 0; i < lowerTitleCase.length; i++) {
                        pattern = new RegExp("(\\s)" + lowerTitleCase[i] + "(\\s)", "gi");
                        if (pattern.test(matches[m].contents)) {
                            matches[m].contents = matches[m].contents.replace(pattern, RegExp.$1 + lowerTitleCase[i] + RegExp.$2);
                        }
                    }
                }
            }
        }

    }

})();
Many scripts are free to download thanks to the support of users. Help me keep developing new scripts by supporting my work. Click the button to make a contribution of any amount. Thank you.
Download
Change Letter Case

For help installing scripts, see How to Install and Use Scripts in Adobe Creative Cloud Applications.

Also available for hire to program custom solutions. Contact William for more information.

IMPORTANT: by downloading any of the scripts on this page you agree that the software is provided without any warranty, express or implied. USE AT YOUR OWN RISK. Always make backups of important data.