sakura/Resource Database System

Last-modified: 2008-04-14 (月) 18:48:58

Resource Database System

サクラエディタで言語別にリソースを切り替える仕組みを実装します。

リソース管理クラスの作成

リソース管理クラス(CRcDb)は、次の2個のファイルから構成されます。

  • CRcDb.cpp
  • CRcDb.h

リソース管理クラスはプロセスに唯一であり、CProcessクラスで管理されます。
簡単に呼び出せるようマクロを定義します。
リソース管理クラスの主なメソッドは次の通りです。
詳細はヘッダファイルを参照してください。

static CRcDb* GetInstance( void );

CRcDbオブジェクトを取得します。

[heart] 例:
CRcDb* lpcRcDb = CRcDb::GetInstance();

HINSTANCE RCDB_GetRcDbInstance( void );

リソースDLLのインスタンスを取得します。
リソースDLLを指定していない場合は、アプリケーションのインスタンスを返します。

[heart] 例:
HINSTANCE hInstance = CRcDb::GetInstance()->GetRcDbInstance();
HINSTANCE hInstance = RCDB_GetRcDbInstance();

[hatena] m_hInstance自体を切り替える方法が簡単ですが、アプリケーション本体のインスタンスを指定しないと正しく動作しないものもありますので注意が必要です。

BOOL Initialize( LCID uLangId = 1041 );

リソースDLLをオープンします。
すでにリソースDLLをオープンしている場合は、クローズしてからオープンします。
CProcessクラス生成時に既定の言語でいったん初期化します。

[heart] 例:
CRcDb::GetInstance()->Initialize(); //引数省略時は1041です。
CRcDb::GetInstance()->Initialize( 1033 );

個別にリソースDLLをオープン・クローズする場合は、OpenRcDb, CloseRcDbメソッドを呼び出します。

BOOL SetLanguage( LCID uLangId = 1041 );

言語を切り替えます。
設定ファイルを読み込んだ直後にこの関数を呼び出して設定言語に切り替えます。

Load系Wrapper

リソースを切り替える関数Wrapper群です。
以下のWrapperがあります。

LoadMenu, LoadBitmap, LoadAccelerators, LoadCursor, LoadIcon, LoadResource, FindResource, LoadImage, LoadString, DialogBoxParam, CreateDialogParam

Wrapperメソッドには、元のLoad系関数にあるInstance引数がありません。

[heart] 例:
HMENU hMenu = RCDB_LoadMenu( MAKEINTRESOURCE( IDM_MENU1 ) );

PropertySheetのWrapper

プロパティシート(PropertySheet)もインスタンスを切り替える必要があります。
ただし、インスタンスは構造体で指定します。

[heart] 例:
PROPSHEETHEADER.hInstance = RCDB_GetRcDbInstance();
PROPSHEETPAGE.hInstance = RCDB_GetRcDbInstance();

通常の文字列リソース

  • LPCTSTR RCDB_GetString( IDS_STR_EXAMPLE, _T("Example1") );
  • int RCDB_GetStringWithCopy( IDS_STR_EXAMPLE, _T("Example1"), lpBuffer, cchMaxBuffer );

メニュー文字列リソース

F_*で定義されたメニュー用の文字列は次のような書式文字列に書き直します。

  • 書式
    Name,Menu
    Name,UnChecked,Checked,Compatible
  • メソッド
    LPCTSTR RCDB_GetMenuString();
    LPCTSTR RCDB_GetMenuUnCheckedString();
    LPCTSTR RCDB_GetMenuCheckedString();
    LPCTSTR RCDB_GetMenuCompatibleString();
    int RCDB_GetMenuStringWithCopy();
    int RCDB_GetMenuUnCheckedStringWithCopy();
    int RCDB_GetMenuCheckedStringWithCopy();
    int RCDB_GetMenuCompatibleStringWithCopy();

[heart] 例:
"新規,新規(&N)"
"情報の表示/非表示,情報の表示(&S),情報の非表示(&H),情報の表示/非表示(&T)"
LPCTSTR lpMenu = RCDB_GetMenuString( IDS_MENU_EXAMPLE, _T("情報の表示(&S)") );
LPCTSTR lpName = RCDB_GetDefaultString( IDS_MENU_EXAMPLE, _T("情報の表示/非表示") );
LPCTSTR lpUnChecked = RCDB_GetUnCheckedString( IDS_MENU_EXAMPLE, _T("情報の表示(&S)") );
LPCTSTR lpChecked = RCDB_GetCheckedString( IDS_MENU_EXAMPLE, _T("情報の非表示(&H)") );
LPCTSTR lpCompatible = RCDB_GetCompatibleString( IDS_MENU_EXAMPLE, _T("情報の表示/非表示(&T)") );

[tip] MenuとUnCheckedは同じ文字列です。

列挙型文字列リソース

列挙型で管理すると都合の良い文字列です。
const配列で固定で管理されている場合に、プログラムは配列番号でアクセスします。
この配列番号に対応するよう列挙型文字列リソースを定義します。
また、リストビューのカラムヘッダ文字列を定義します。

  • 書式
    Count,Enum1,Enum2,...
  • メソッド
    LPCTSTR RCDB_GetEnumString();
    int RCDB_GetEnumStringWithCopy();

[heart] 例:
"3,Enum1,Enum2,Enum3"
LPCTSTR lpEnum1 = RCDB_GetEnumString( IDS_ENUM_EXAMPLE, _T("Enum1"), 0 );
LPCTSTR lpEnum2 = RCDB_GetEnumString( IDS_ENUM_EXAMPLE, _T("Enum2"), 1 );

[tip] Countと後に続く文字列の個数が合わない場合、0個(文字列なし)として扱われます。

言語の設定ダイアログの作成

  • リソース
    リソースDLLに設定されている IDS_RCDB_LANG=10000 の文字列リソースを読み込み判断します。
    IDS_RCDB_LANG文字列リソースの書式は"Sakura-Editor,LangId,Name"です。
    DLLの命名規則はsakura_rc_%u.dllです。
    %uの部分が言語IDです。

[heart] 例:

#define
IDS_RCDB_LANG = "Sakura-Editor,0,Application Default(Japanese)"
IDS_RCDB_LANG = "Sakura-Editor,1033,English(US)"
IDS_RCDB_LANG = "Sakura-Editor,1041,Japanese"

[star]
言語IDは、このリソース文字列の2番目の数値が使用されます。
rcファイルで使用される言語IDとは直接の関係はありません。
たとえば、一部だけを英語化したい場合、設定ダイアログの言語IDは99999かもしれませんが、Visual Studioで扱うrcファイルの言語は1041です。

  • 画面
    リソースは言語IDで管理するので、同じ言語に対するリソースは1個しかありません。
    複数の言語リソースを使い分けたい場合は、未使用の言語IDを自己責任で使ってください。
lang-setting.png

(最新の画面ではバージョン情報表示あり)

[tip]
実行ファイルにあるリソースは、言語ID=0として表示されます。
バージョンの異なるリソースも表示されますが、選択した場合は不正動作する可能性があることを警告します。

[tip]
現在の方式では、1つのリソースDLLで複数の言語(たとえば、日本語、英語、中国語が混在するメニュー)を管理できません。
Visual Studio自体はこのようなリソースDLLを作成できます。
このような複数の言語を混在させたリソースDLLで動作可能にするには、CRcDbクラスでリソースを検索する仕組みを修正する必要があります(多分...)。
( (^^; 試したことがないので、わからないです)

ダイアログ類のリソース化

基本的にリソース化されています。
表示する言語が変わると、表示幅を調整する必要があります。
ダイアログに後から表示する情報については、その他の文字列のリソース化でリソース化する必要があります。
以下の関数Wrapperを使用します。

  • メソッド
    DialogBoxParam
    CreateDialogParam

[heart]
通常は CDialog クラスを継承するため、CDialogクラスを修正しておけば自動的にWrapperメソッドが使用されます。

その他の文字列のリソース化

後々混乱しないよう、リソースマップを作成します。
簡単に識別できるよう、プレフィックスを統一します。

  • IDS_STR_* : 15000~15999
    通常文字列です。
  • IDS_MENU_* : 29900~29999
    F_*以外でメニュー関係に使われるリソース(F_*と同じ書式を持つ)です。
  • IDS_ENUM_* : 29000~29899
    列挙型リソースです。
  • IDS_MSG_* : 28000~28999
    MessageBoxで使うメッセージ関係の文字列です。
  • その他のプレフィックス
    • IDS_CONFIRM_* : 問い合わせするもの(例: IDS_CONFIRM_FORMAT_DELETE="%sを削除しますか?")
    • *_FORMAT_* : %s,%d等の出力書式を持っているもの(例: IDS_MSG_FORMAT_DELETE="%sを削除") [#ie311253]
    • *_BRACKET_* : 括弧で括ってある文字列(例: IDS_STR_UNTITLED_BRACKET="(Untitled)") [#j21ca301]
    • *__* : 前後に空白があるもの(例: IDS_STR__CLASS=" Class", IDS_STR_CLASS_="Class ") [#j179132f]
    • \n : 改行は\nで行う
    • 文字列終端 : 文字列終端は\nを付けない
    • () : 半角文字を使う

日本語リソース化

sakura.exeは日本語リソースを持ちます。
上記の方法でリソース化します。

英語リソース化

sakura_rc_1033.dllとして英語リソースを作成します。
sakura.exeを英語化したい場合は、次のマクロを1033に変更します。

#define

#if

#define

#else

#define

#endif

また、既定言語で定義された部分では次のようにコーディングします。

const LPCTSTR tbl[] = {
RCDB_USE_DEFAULT( _T("日本語"), _T("Japanese") ),
RCDB_USE_DEFAULT( _T("英語"), _T("English(US)") ),
NULL
};

[tip] 注意
設定ファイルの識別キーを変更してしまうと、異なる言語で保存された設定ファイルを読み込めなくなります。

ヘルプのリソース化

HTML Helpを英語化します。
この英語化には力技が必要です。
翻訳ソフトに頼りましょう。

  • ヘルプ本体の英語化
    ほぼ英語化したものが本Wikiにあります。
    これをHTML形式に取り込みます。
  • ツールチップの英語化
    ツールチップ(Cshelp.txt)を英語化する必要があります。

[heart] 参考
Visual Studio上でHTMLヘルプのビルドができます。
HTMLファイルはUTF-8に切り替える必要があるかもしれません。

その他

  • Debugビルド
    Debugビルドした場合、リソースWrapperを呼び出す際に指定されたチェック文字列と比較が行われます。
    リソース化の手順に誤りがある場合、実行時にエラーメッセージが表示されます。
    ただし、既定言語が日本語の場合のみです。
    チェックを行いたくない場合やできない場合は、チェック文字列にNULLを指定してください。
  • Releaseビルド
    Releaseビルドした場合、チェック文字列は削除されてビルドに含まれません。
  • 起動時の対応
    設定ファイルが読み込まれるまでの間は、当然のことですが既定の言語で動作します。
    プロセスの生成、設定ファイルの読み込みエラーに関するメッセージ類は、リソースに頼るコーディングをしていても、既定の言語になります。
  • 整理すべきこと
    日本語文字列が非常に多くの場所で使われています。
    その他文字列やメッセージ文字列について、複数のコーダーによって無規則状態で作成されているため一貫性がありません。
    リソース化する際に統一すべきです。
    (--; 命名規則が面倒。同じメッセージがあるか確認が面倒。統一が面倒。あまりにも量が多いので(メニュー文字列のような)誤修正の発生を防ぐ方法が必要。
  • フォント
    完全な英語環境(英語OS)で動作させようとした場合、フォントを変更する必要があるかもしれません。
  • "MS P ゴシック" --> "MS P Gothic" --> "MS UI Gothic" ?
  • "MS ゴシック" --> "MS Gothic"
  • "MS 明朝" --> "MS Mincho" --> "MS UI Gothic" ?

これらについても既定の言語の切り替えコーディングは必要です。
言語切り替え時にも、リソースで切り替えます。

filesakura_rc_1033.zip [詳細] filelang-setting.png [詳細]
JavaScript を有効にしてください