DTPab

印刷やデザイン、アドビ製アプリやスクリプトなど、雑多な技術ブログ

InDesignの標準機能「大文字と小文字の変更」の不具合

大した内容ではないのですが、ちょっとしたInDesignの不具合を見つけました。けっこう限定的なので普段の組版へはあまり大きな影響はないと思います。結果として2つの不具合を紹介しますが、恐らく原因は同じです。

では本題です。
InDesignの書式メニューに、「大文字と小文字の変更」メニューというのがあり、その中に4つの機能があります(下図)。

f:id:uske_S:20180313233310p:plain

この4つの機能が、言語設定次第でおかしな挙動をします。

不具合1:「単語の先頭のみ大文字」が単語の間も大文字になる

画像のようなテキストを用意し、文全体を選択して「単語の先頭のみ大文字」を実行した結果です。上側の青い囲みは言語設定「英語:米国」、下側の赤い囲みは部分的に「日本語」にしています。

f:id:uske_S:20180313233329p:plain

このように、単語の先頭以外でも大文字になってしまうところがあります。これがひとつめの不具合(仕様?)です。
単語の先頭以外で大文字になってしまう原因は「言語設定の変わり目」の部分です。これはあくまで仮説ですが、「quidem」が「QUIdeM」となってしまうのは
q:英語 ←単語の先頭!
u:日本語 ←(言語が変わったから)単語の先頭!
i:英語 ←(言語が変わったから)単語の先頭!
d:英語 …単語の途中
e:英語 …単語の途中
m:日本語 ←(言語が変わったから)単語の先頭!
というアルゴリズムが潜んでいるのでは、ということです。こう考えると結果と辻褄が合うのです。
仮にもしこの仮設が正しいとすると、言語の境目を単語の先頭と捉えることが「アプリケーションの仕様」と(納得はできないものの)理解することもできます。実際、これについては僕はもう仕方のないことなのだろうと諦めています^^;

不具合2:選択範囲を超えて「大文字と小文字の変換」が実行される

僕が不具合だと感じたのはこちらのほうです。これも言語設定次第で起きます。

f:id:uske_S:20180313233349p:plain

このように、選択範囲の次の文字まで処理が及んでしまいます。画像では「すべて大文字に」で試しましたが、「文章の先頭のみ大文字」以外の3つの機能で同じようになります。これはさすがに「不具合」と言っていいんじゃないでしょうか。

解決策

いまのところ、根本的な解決策は見つかっていません。言語設定を一時的に同じ設定にした上で、この機能で大文字・小文字の変換を行い、元の言語設定に戻す、というくらいしかないのが現状です。もう、それだったら手入力で打ち替えるよ!という気さえします。
まぁでもせっかくなのでその一連の処理をスクリプトで実装してみました。

//実行するアクション4つのどれかを入れる
//すべて大文字:"$ID/To Uppercase"
//すべて小文字:"$ID/To Lowercase"
//タイトルケース(単語の先頭のみ大文字):"$ID/Title Case"
//センテンスケース(文の先頭のみ大文字):"$ID/Sentence Case"
var command = "$ID/To Uppercase";

!function (){
    var myDoc = app.activeDocument;
    var mySel = myDoc.selection[0];
    var lang = []; //文字毎の言語設定を入れる配列
    var ja = app.languagesWithVendors.itemByName("Japanese"); //「日本語」設定
    var c = mySel.characters; //選択範囲内の文字
    var endChar = mySel.parentStory.characters[ c[-1].index + 1 ]; //選択範囲の次の文字
    
    //--言語設定の抽出と統一--//
    for (var i=0, len=c.length; i<len; i++){
        lang.push(c[i].appliedLanguage); //文字の言語設定を一旦保存
        c[i].appliedLanguage = ja; //日本語設定で統一
        }
    
    //選択範囲の次の文字まで処理が及んでしまう不具合に対応させるため、選択範囲の次の文字も言語設定を統一
    if (endChar.isValid){
        lang.push(endChar.appliedLanguage); //選択範囲の次の文字が存在すれば同様に言語設定を保存
        endChar.appliedLanguage = ja;
        }
    
    //一応try構文に入れた
    try{ app.menuActions.item(command).invoke(); } //メニューアクションの実行
    finally {
        for (var i=0; i<len; i++){
            c[i].appliedLanguage = lang[i]; //保存しておいた言語設定を戻す
            }
        if (endChar.isValid) endChar.appliedLanguage = lang[lang.length-1]; //戻す
        }
    }(command);


まず冒頭のcommand変数に、実行したいアクション名を入れてください。直前にコメントアウトしてある4つが利用可能です。

var ja = app.languagesWithVendors.itemByName("Japanese"); //「日本語」設定

この部分ですが、itemByNameメソッドがロケール対応していません。なのでitemByName("日本語")ではエラーになります。Japaneseなんて分かりやすかったから良かったですけど、そうじゃなかったら分からなかった…。

 var endChar = mySel.parentStory.characters[ c[-1].index + 1 ]; //選択範囲の次の文字

Charactersはコレクションオブジェクトなので、引数に-1を渡すと最後のメンバーを返してくれます。それを利用して、最後の文字(c[-1])の1つ後ろ(c[-1].index + 1)をこのような形で指定しました。

for (var i=0, len=c.length; i<len; i++){
    lang.push(c[i].appliedLanguage); //文字の言語設定を一旦保存
    c[i].appliedLanguage = ja; //日本語設定で統一
    }

このfor文では、文字に充てている言語設定(Character.appliedLanguage)を一旦lang変数にpush(配列の末尾に追加)して、それから言語設定を「日本語」に変えています。ここは「日本語」でないとうまくいかない場合があるので注意です。
というのも、例えば1文字目と同じ言語設定に統一したい…と思ってもその文字が和文だと、例えば「英語:米国」などはスクリプトから簡単に設定できません。逆に、文字が欧文(半角英数字)でも「日本語」を充てることはできるので、今回は統一して(一時的に)言語設定を「日本語」にしてしまう処理にしました。

//一応try構文に入れた
try{ app.menuActions.item(command).invoke(); } //メニューアクションの実行
finally {
    for (var i=0; i<len; i++){
        c[i].appliedLanguage = lang[i]; //保存しておいた言語設定を戻す
        }
    if (endChar.isValid) endChar.appliedLanguage = lang[lang.length-1]; //戻す
    }

ここでやっとメニューアクションを実行します。もしメニューアクションの実行に失敗しても、変えてしまった言語設定は戻したいので、try・finally構文で言語設定を戻します。もし選択範囲の後に文字が存在する場合は、その言語設定もあわせて戻します。
メニューアクションの実行前に一旦同じ言語設定(選択範囲の次の文字まで)にしているので、上に挙げたような不具合はこれで回避できます。

補足

言語設定について補足です。
例えば言語設定「英語:米国」が充てられている「a」という半角欧文を全角の欧文「a」に打ち変えると、言語設定は強制的に「日本語」になります。この状態から再び半角の「a」にしても、何もしなければ言語設定は「日本語」のままです。
ということでこれは一例ですが、欧文の言語設定を変えたい場合は、言語設定を変更する正規表現スタイルを用意するといいと思います。
正規表現を [\l\u]+ などとし*1、充当文字スタイルには言語設定を「英語:米国」などとする正規表現スタイルです。こうすると、先の例のような場合の「a」から「a」という作業だけで「日本語」から任意の言語設定に変えることができるようになります。

以上、InDesignの言語設定と「大文字と小文字の変更」コマンドにまつわる不具合のお話でした。

*1:[a-zA-Z]+とかでも悪くないのですが、これだとドイツ語なんかの「ü」などに対応できません。