トップ 差分 一覧 ソース 検索 ヘルプ PDF RSS ログイン

sxul_shade8sdk

SXULによるリソース管理

多言語対応のアプリケーションの場合、表示するテキストは言語によって切り替える必要があります。プログラムにダイレクトに埋め込むと、別の言語対応を行う場合に苦労してしまいます。この場合は、文字列やウィンドウなどを「リソース」としてプログラムから分離します。XOOPS(PHPプログラム)や最近のJavaプログラムでも一般的に使われるようになっている方法です。

Shadeでも同じで、現在はShadeの日本語版・英語版・中国語版などがあります。ユーザ視点から見ると、一言語だけしか使わないのが普通でしょうから問題ないですがプラグインやShade本体を作る側から見ると、この管理をしっかりしないと大変なことになりそうなのが分かるかと思います。

それで、Shade8で追加されたのが「SXUL」という仕組みです。残念ながらSDKドキュメントでは詳しいことが書いておりません。そこで、このサイトで補間してみることにします。

SXUL

なんの略なんでしょうね、「Shade Exなんとか Universal Language」でしょうか・・・(^_^;;。これはドキュメントにも無いので適当に想像してください。

何をするものかというと、ウィンドウ(window_interface)やダイアログ(dialog_interface)の定義・デザインを言語ごとにXML形式で記述して、Shadeにてリソース管理をする仕組みです。で、Shadeの開発の方にお聞きしたところ 文字列自身も扱えるよ、とのことでした。てっきりウィンドウ管理用のリソースと思って触ってなかったのですが、文字列だけのリソースもSXULで管理できるようです。

極端に言うと、プログラムロジック部では言語依存部分(日本語表示・英語への切り替えなど)は分離してしまいSXULに分けてしまうことができます。あくまでもプログラム・プラグイン内部の仕組みでありますので、Shadeを使う側からみると、過去のShadeと何が変わったのかは分かりにくいかと思います。

しかし、プラグインを作る側から見ると非常に大きな変更ともいえるかもしれません。

SXULで扱える言語(ロケール)について

現在のShadeで言うと、日本語と英語ですね。ただ、OSXのプラグインSDKのディレクトリ名から判断すると、以下のものを作成することができそうです。

識別名言語名
deドイツ語
en英語
esスペイン語
frフランス語
ja日本語
zh_CN中国語 (簡体字)

このようなロケールは、Javaでも同等のものが定義されています。Javaというか、UTF-8で扱うことができる言語が指定できます。WindowsとOSXでは、SXULのファイル名やディレクトリ構成が異なりますので注意してください。

プラグインソースからのSXUL文字列の参照

「文字列としてのリソース」をSXULを使って実現する方法を説明します。SXULを扱う場合は、文字コードとしてはすべて「UTF-8」で処理します。ただし、ソース自身は(コメント以外)言語・コード依存するものではありませんのでこれは不問です。

ShadeプラグインをUTF-8で管理する

グローバル関数の「get_text_encoding」にて、日本語の場合は「plugin_interface::japanese_encoding」を返す(この場合は、文字列はSHIFT_JISで処理しないといけない)、それ以外はUTF-8で、という指定をしてました。

extern "C" int STDCALL get_text_encoding (shade_interface *shade, void *) {
  return shade->is_japanese_mode() ? plugin_interface::japanese_encoding : 0;
}

これは不要になります。記述しないとすべて0(つまりUTF-8)を返すことになりますので、この部分をコメントアウトします。

//extern "C" int STDCALL get_text_encoding (shade_interface *shade, void *) {
//  return shade->is_japanese_mode() ? plugin_interface::japanese_encoding : 0;
//}

SXULの文字列取り出し

ヘッダ部分でstringinterface.hをインクルードします。SXULで文字列を扱うには、strings_interfaceを使用します。

#include "stringsinterface.h"

たとえば、「HelloWorldStrings」というリソース識別名(後述)から2番目に指定された文字列を取得する場合は、以下のように「strings_interface」を作成して「get_string(2)」で文字列を取得してきます。元のSXULファイルはUTF-8で保存していますので、そのままUTF-8形式の文字列を取得することができます。

compointer<strings_interface> strings(shade->create_strings_interface("HelloWorldStrings"));

// SXULのXMLファイルより2番目の文字列を取得
shade->message(strings->get_string(2));

日本語・英語などはSXULファイルごとに分離されていますので、どの言語でShadeが動いているか、は意識する必要がありません。「shade->create_strings_interface("HelloWorldStrings"));」の部分での"HelloWorldStrings"はりソースとして割り当てられている識別名です。Windowsでは大文字と小文字の区別はないようです。Windowsではプロジェクトのリソース(script2.rc)として、"HelloWorldStrings"の名称がSXULのファイルに結び付けられています。

プラグインのソース部からはこれだけです。シンプルですね。ただし、「では、どのSXULファイルをリソースとして参照するのか」というのをプロジェクトに結びつけるのがやっかいです。これはOSごとに違いますので、Windowsの場合、OSXの場合、のそれぞれを見ていくことにします。

プロジェクトにSXULファイルを割り当てる(Windowsの場合)

Windowsの「Visual C++ .NET 2003」では、開発環境のGUIにてリソースを割り当てることができるのですが、これではうまいことSXULを割り当てることができません。

リソースファイルである「script2.rc」を直接いじっていきます。プラグインSDKの「win\plugins\script2.rc」をテキストエディタで開きます。

script2.rcの編集

/////////////////////////////////////////////////////////////////////////////
// 日本語 resources
 
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_JPN)
#ifdef _WIN32
LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT
#pragma code_page(932)
#endif //_WIN32
 
/////////////////////////////////////////////////////////////////////////////
//
// SXUL
//
 
SIMPLE_WINDOW     SXUL   "..\\..\\sample\\resources\\sxuls\\simple_window.ja.sxul"
SIMPLE_STRINGS_ID SXUL   "..\\..\\sample\\resources\\sxuls\\simple_strings_id.ja.sxul"
SIMPLE_DIALOG_ID  SXUL   "..\\..\\sample\\resources\\sxuls\\simple_dialog_id.ja.sxul"
TEXT              SXUL   "..\\..\\sample\\resources\\sxuls\\text.ja.sxul"

のように書かれているものが2箇所あります。「// 日本語 resources」のところの「SIMPLE_WINDOW」「SIMPLE_STRINGS_ID」「SIMPLE_DIALOG_ID」が、サンプルプラグインで利用しているリソースです。順番に、window_interfaceの定義/dialog_interfaceの定義/文字列リソースの定義、となります。どの識別名がどのSXULファイルに対応しているのか、というのが分かるかと思います。実際のリソースの編集は「xxxx.ja.sxul」ファイルをいじるとよいです。.NETでのリソースでは、あくまでもリソース識別名とファイルを結び付けているだけです。

ちょっと下を見ると、今度は英語リソースの記述があります。

/////////////////////////////////////////////////////////////////////////////
// 英語 (米国) resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32

/////////////////////////////////////////////////////////////////////////////
//
// SXUL
//

SIMPLE_WINDOW     SXUL   "..\\..\\sample\\resources\\sxuls\\simple_window.en.sxul"
SIMPLE_STRINGS_ID SXUL   "..\\..\\sample\\resources\\sxuls\\simple_strings_id.en.sxul"
SIMPLE_DIALOG_ID  SXUL   "..\\..\\sample\\resources\\sxuls\\simple_dialog_id.en.sxul"
TEXT              SXUL   "..\\..\\sample\\resources\\sxuls\\text.en.sxul"

識別名は日本語の場合とまったく同じですが、「xxxxx.en.sxul」とjaがenになってます。このSXULファイルでは英語の文字列を指定しています。

新たに「HELLOWORLDSTRINGS」という識別名を加えて、日本語を「HelloWorldStrings.ja.sxul」、英語を「HelloWorldStrings.en.sxul」とします。

// 日本語 resources
...
HELLOWORLDSTRINGS SXUL   "..\\..\\sample\\resources\\sxuls\\HelloWorldStrings.ja.sxul"
...

// 英語 (米国) resources
...
HELLOWORLDSTRINGS SXUL   "..\\..\\sample\\resources\\sxuls\\HelloWorldStrings.en.sxul"

後は、プラグインソースで

compointer<strings_interface> strings(shade->create_strings_interface("HelloWorldStrings"));

にて、「HELLOWORLDSTRINGS」のリソースを読み込み、

// SXULのXMLファイルより2番目の文字列を取得
shade->message(strings->get_string(2));

でUTF-8の文字列を取得しています。

プロジェクトにSXULファイルを割り当てる(OSXの場合)

Windowsとは構成が違います。

リソースであるSXULファイルは、

macos/plugins/ja.lproj/sxutils/simple_strings_id.sxul
macos/plugins/en.lproj/sxutils/simple_strings_id.sxul

のように分かれています。Windowsのようにファイル名が「xxxx.ja.sxul」となるのではなく、ディレクトリ名が「ja.lproj/sxutils/xxxx.sxul」となっています。プラグインSDKではディレクトリはあらかじめ用意されていますので、言語が異なる場合は「ファイル名は同じで中身を変えて」言語別ディレクトリにSXULファイルを放り込んでいきます。

ここに、日本語の「HelloWorldStrings.sxul」を入れている例です。

ファイル名がそのままリソース識別名になりますので、間違えないようにしてください。

Xcodeでは、そのままではSXULがどのファイルなのか、というのが分かりません。ですので、明示的に割り当ててあげる必要があります。

左端にある「Groups & Files」より、[xplugins] - [Resources] - [sxuls]のツリーノードを選択します。その後、右に出る「sxul(de)」〜「sxul(zh_CN)」までをすべて選択してください。

ターゲットとなるプロジェクト(ここではHelloShade)を開き、[HelloShade] - [Copy Bundle Resources]内に、上記で選択した状態の「sxul(de)」などをドラッグ&ドロップします。すると、プロジェクト内に「sxuls(de)」〜「sxuls(zh_CN)」が追加されます。これで、プロジェクトがSXULファイルを参照することができるようになります。

後は、Windowsの場合と同様に、プラグインソースで

compointer<strings_interface> strings(shade->create_strings_interface("HelloWorldStrings"));
shade->message(strings->get_string(2));

のようにすることで文字列リソース類を参照することができるようになります。

SXULファイルの中身

最後に、SXULファイルの中身についてです。

「HelloWorldStrings.ja.sxul」(OSXでは「macos/plugins/ja.lproj/sxutils/HelloWorldStrings.sxul」)

<?xml version="1.0" encoding="utf-8"?>
<strings>
  <string value="はろ〜Shade"/>
  <string value="SXULを使った簡単なプラグイン"/>
  <string value="SXULを使った表示を行います。"/>
  <string value="こんにちわ世界!!"/>
</strings>

普通のXMLファイル形式です。1行目はUTF-8であることを明示する部分でそのまま記述します。<strings>タブ内に<string value="xxxx" />で文字列を記述します。文字コードは「UTF-8」で保存するようにしてください。

文字列リソースは、列挙する順番がプラグインソース部で「strings->get_string(index);」としたときの第一引数のindexに対応します。上記だと、0番目が"はろ〜Shade"、1番目が"SXULを使った簡単なプラグイン"と続きます。

英語リソースは構成が同じでvalueだけ英語になってます。

「HelloWorldStrings.en.sxul」(OSXでは「macos/plugins/en.lproj/sxutils/HelloWorldStrings.sxul」)

<?xml version="1.0" encoding="utf-8"?>
<strings>
  <string value="HelloShade"/>
  <string value="Easy plug-in that uses SXUL."/>
  <string value="The display that uses SXUL is done."/>
  <string value="Hello World!!"/>
</strings>

以下のようにプラグインソースから文字列を取得してメッセージウィンドウに結果を表示する場合、

compointer<strings_interface> strings(shade->create_strings_interface("HelloWorldStrings"));
shade->message(strings->get_string(2));

Shadeが英語モードの場合は「The display that uses SXUL is done.」、日本語モードの場合は「SXULを使った表示を行います。」が表示されることになります。

グローバル関数「get_name」ではSXULは使えない?

メニューの項目名を日本語・英語切り替えしたい場合に、

extern "C" const char * STDCALL get_name (const IID &iid, int i,
   shade_interface *shade, void *) {
    if (iid == plugin_iid) {
       compointer<strings_interface> strings(shade->create_strings_interface("HelloWorldStrings"));
       return strings->get_string(0);
    }
    return 0;
}

として利用しようとすると、プラグイン自身が認識できなくなってしまいました。対応してないのかなぁ、SXULを使わずに英語で表示したほうが無難かも。

終わりに

このように、SXULを使用することで言語依存する部分は分離してしまうことができるようになっています。その他、文字列だけではなくて バージョン情報はtext.ja.sxul(OSXではmacos/plugins/ja.lproj/sxutils/text.sxul)に表記、window_interfaceでのウィンドウデザインの定義もSXULで実装できます。

まだ使いやすいものではないですが、リソースを有効利用することで開発が効率アップするための仕組みが強化されるといいですね。

個人的には、Windows/OSXによって SXULのファイル構成が異なる・ファイル名が異なるのはあまりよろしくないと思います。できれば、WindowsのソースやSXULファイルをポンとOSXのXcodeに放り込むと、同じような動作をするOSX版のプラグインがビルドできる、などの可搬性がほしいところです。といっても、プログラムのリソースの仕組み(実行ファイルまたは動的ライブラリにマージされる)の都合上、一筋縄では行かない部分ではありますが・・・。

SXULを使ったプラグインインターフェース「HelloShade」のソースコードを以下においておきました。Shadeのプラグインメニューから「HelloShade」を選択すると、メッセージウィンドウにSXULより取得した文字列が表示されます。

HelloShade_sxul_src_20051202.zip(3KB)

HelloShadeのプラグインソース
HelloShade.cpp
英語のSXULリソース
resources/sxuls/HelloWorldStrings.en.sxul
日本語のSXULリソース
resources/sxuls/HelloWorldStrings.ja.sxul

OSXでは、SXULリソースを「HelloWorldStrings.sxul」にリネームして「macos/plugins/en.lproj/sxutils/」「macos/plugins/ja.lproj/sxutils/」に入れるようにしてください。

Future's Laboratory 技術格納庫 2004-2013 Yutaka Yoshisaka.