2024年3月25日月曜日

シンMELの多言語対応

 以前紹介した MELの多言語対応 で使用していたのは、uiResコマンドと displayStringが羅列された .res.melファイルだったのですが、ふと、mayaのUIで日本語訳を調べるために .res.melファイルを検索してみたのですが、全くと言って良いほどヒットしなくなっていました。

 どうやら最近は、uiResコマンドや .res.melファイルではなく、setPluginResourceコマンドと .pres.melファイルを使用するように変わっているようです。

 なので、さっそくMELコマンドのテクニカルドキュメントを見てみることにしました。

 見慣れない resource関係のコマンドが幾つか見つかりました。

 とりあえず setPluginResourceコマンドの概要を読んでみると、registerPluginResourceloadPluginLanguageResourcesgetPluginResourceも関係している必要なコマンドのようです。ですが、予備知識もなく各コマンドの概要を読んでみてもパッとしません。
 そこで、c:\Program Files\Autodesk内をアサってみます。

 どうやら、registerPluginResourcesコマンドで登録し、loadPluginLanguageResourcesコマンド内の setPluginResourceコマンドでローカライズ版をオーバーライド。
 ラベル作成時に getPluginResourceコマンドを使用するみたいです。
 そして、MELコマンドのテクニカルドキュメントには書かれていませんが、~InitStrings.melという初期化スクリプトを起点にローカライズを行っているように見えます。

 とりあえず、sampleInitStrings.melと sample.melを作って動作を確認してみます。

 まずは初期化スクリプト

global proc sampleInitStrings()
{
    // Register script resources
    registerPluginResource("sample","kSampleMenu","Sample Menu");
    
    // Load any localized resources
    loadPluginLanguageResources("sample","sample.pres.mel");
    
}

 ここで、毎度のことながら loadPluginLanguageResourcesが ja_JPフォルダを探すところでエラーが出てしまうので、さくっとスクリプトを自作します。

proc string _getLanguageResourcePath(
    string $file )
{
    string $name = python("'"+$file+"'[:-9]");
    string $script =`whatIs $name`;
    if("Unknown"==$script) return "";
    
    string $tmp[]= python("'"+$script+"'.split(' ')");
    string $dir = dirname($tmp[size($tmp)-1]);
    
    string $ull =`about -ull`;
    
    string $resFile = ($dir+"/"+$ull+"/"+$file);
    
    if(`filetest -f $resFile`) return $resFile;
    
    return "";
    
}


global proc tryLoadLanguageResources(
    string $resFile )
{
    if( !`about -uii`) return;
    
    string $languagePath = _getLanguageResourcePath( $resFile );
    if(""!=$languagePath)
    {
        eval("source \""+ $languagePath+"\"");
        
    }
    
}

 sampleInitStrings.melの7行目を

    tryLoadLanguageResources("sample.pres.mel");

 のように変えます。sample.melと同じフォルダに在る ja_JPフォルダを探して、その中の sample.pres.melを実行し見つからなければ何もしません。

 次に前回と同様、メニューを作成するスクリプトでテストしてみます。

sampleInitStrings();


global proc sample()
{
    global string $gMainWindow;
    if( ""==$gMainWindow || !`window -ex $gMainWindow`) return;
     
    // 旧メニュー削除
    string $menu="sampleMenu_in_mainMenu";
    if(`menu -q -ex $menu`) deleteUI $menu;/* for debug. */
     
    // メニュー作成
    setParent $gMainWindow;
    menu -p $gMainWindow -l (getPluginResource("sample","kSampleMenu")) $menu;
    
}

 1行目で初期化スクリプトを実行しようとしていますが、sampleコマンドを実行しても、この部分はメインプロシージャの外側なので実行されません。なので、この sample.melを正しく動作させるには

source "sample.mel";
sample;

 と、sourceコマンドを挟む必要があります。
 ただ、自作スクリプトを作成している途中で初期化スクリプトを実行してしまうと
 registerPluginResourceコマンドの実行で警告が出てしまうので、displayString -deleteを使うように工夫する必要があるかもしれません。
 裏で警告が出ているのが気持ち悪いですが、

global proc sample()
{
    global string $gMainWindow;
    if( ""==$gMainWindow || !`window -ex $gMainWindow`) return;
    
    // 初期化
    catchQuiet(`sampleInitStrings`);
     
    // 旧メニュー削除
    string $menu="sampleMenu_in_mainMenu";
    if(`menu -q -ex $menu`) deleteUI $menu;/* for debug. */
     
    // メニュー作成
    setParent $gMainWindow;
    menu -p $gMainWindow -l (getPluginResource("sample","kSampleMenu")) $menu;
    
}

 と、7行目のようにメインプロシージャ内に入れ込んでしまっても良いかもしれません。

 そして15行目が getPluginResourceコマンドでラベルを取得している部分です。

  最後に、.pres.melの作成について。
  本来なら pluginResourceUtilコマンドを使うことで、簡単に雛形を作成できるみたいなのですが、プラグインがロードされている事が前提になっているため、MELスクリプトだけの場合では、実行しても普通にエラーで停止してしまいます。

 なので必要な部分だけ抜き出して自作します。

proc printResourceString(
     string $name
    ,string $id
    ,string $value)
{
    string $fmt ="setPluginResource(\"^1s\",\"^2s\",\"^3s\");\n";
    print(`format -s $name -s $id -s $value $fmt`);
    
}


global proc tryGeneratePres(string $name)
{
    if(`about -uii`) error -n "uiLanguage is Localized.";
    
    string $matchPattern =("p_"+$name+".");
    string $matches[] =`displayString -q -k $matchPattern`;
    if(!`size $matches`) error -n"No registered string resources.";
    
    // header
    print("// File "+$name+".pres.mel\n");
    print("// Resources for Script: "+$name+"\n");
    print("// \n");
    print("// ----------------------------\n");
    print("// Registered string resources:\n");
    print("// ----------------------------\n");
    
    for($key in $matches)
    {
        // Look up the string value
        string $resValue =`displayString -q -v $key`;
        
        // Split the id into subparts to get the unique string part
        string $idPart = stringRemovePrefix($key,$matchPattern);
        
        // Encode escape characters in the resource value 
        string $resValueEncoded =`encodeString $resValue`;
        
        // Format and generate the correct initialization string
        printResourceString($name, $idPart, $resValueEncoded);
        
    }
    
}

 これを

tryGeneratePres("sample");

 と実行することで、スクリプトエディタの履歴に雛形が出力されるので、英語部分を各言語に訳したら sample.pres.melという名前のファイルに保存して、ja_JPフォルダに保存します。
 これで日本語版の Mayaで翻訳されたラベルが表示されます。

 また、printではなく displayString -deleteで出力すれば重複解除のスクリプトも作れるような気もします。

 ただ、これを使って多言語化してしまうと、毎回 tryLoadLanguageResources.melを一緒に配布するか、InitStrings.melの中に同じプロシージャを書き込んでおく必要があるけど、昔のままでもメインスクリプトに毎回 .res.melファイルを読み込むプロシージャを描き込んでいるので、別のスクリプトファイルへ分離できるだけマシかなとか、今後どちらを使っていくか悩みどころです。

 あと、mayaのヘルプの
 Maya 開発者ヘルプ > テクニカル ノート > プラグインを国際化する
 にも関連した解説が書かれているので読んでみるのも良いでしょう。



0 件のコメント:

コメントを投稿