SXUL によるリソース管理

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
フランス語
1
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 が動いてい
2
るか、は意識する必要がありません。「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
SIMPLE_STRINGS_ID
SIMPLE_DIALOG_ID
TEXT
SXUL
SXUL
SXUL
SXUL
"..¥¥..¥¥sample¥¥resources¥¥sxuls¥¥simple_window.ja.sxul"
"..¥¥..¥¥sample¥¥resources¥¥sxuls¥¥simple_strings_id.ja.sxul"
"..¥¥..¥¥sample¥¥resources¥¥sxuls¥¥simple_dialog_id.ja.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
3
/////////////////////////////////////////////////////////////////////////////
//
// SXUL
//
SIMPLE_WINDOW
SIMPLE_STRINGS_ID
SIMPLE_DIALOG_ID
TEXT
SXUL
SXUL
SXUL
SXUL
"..¥¥..¥¥sample¥¥resources¥¥sxuls¥¥simple_window.en.sxul"
"..¥¥..¥¥sample¥¥resources¥¥sxuls¥¥simple_strings_id.en.sxul"
"..¥¥..¥¥sample¥¥resources¥¥sxuls¥¥simple_dialog_id.en.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」を入れている例です。
4
ファイル名がそのままリソース識別名になりますので、間違えないようにしてください。
Xcode では、そのままでは SXUL がどのファイルなのか、というのが分かりません。ですので、明
示的に割り当ててあげる必要があります。
左端にある「Groups & Files」より、[xplugins] - [Resources] - [sxuls] のツリーノードを選択します。
その後、右に出る「sxul(de)」∼「sxul(zh_CN)」までをすべて選択してください。
5
ターゲットとなるプロジェクト(ここでは HelloShade)を開き、[HelloShade] - [Copy Bundle
Resources] 内に、上記で選択した状態の「sxul(de)」などをドラッグ&ドロップします。すると、プ
ロジェクト内に「sxuls(de)」∼「sxuls(zh_CN)」が追加されます。これで、プロジェクトが SXUL
ファイルを参照することができるようになります。
6
後は、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"?>
7
<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 を使わずに英語で表示したほうが無難かも。
終わりに
8
このように、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/」に入れるようにしてください。
9