多国語リーソース切替え


■ 概略
 皆さんの中でも、特に仕事で多国語を扱ったアプリケーションを作成したことのある人がいるかと思います。
そんな時、リソースを多国語化したり、また、リソースDLL(サテライトDLL)を作成したりローカライズするのが通常です。
今回のサンプルは、それらの切り替えの処理をメニューに入れ、それにより動的にアプリケーションのリソースを変更するものです。
今回は、日本語と英語を扱った例です。(それ以外知りませんので)
下の画面は、それぞれ日本語と英語の画面です。


日本語の画面


英語の画面

■ 英語リソースDLLの作成
 プログラムの説明の前に、英語版リソースDLLの作成方法を簡単に説明します。
まず新規作成で、MFC AppWizard (dll)のプロジェクトを作成します。(loctest_eng)
この例では、メインのプロジェクト(loctest)へ追加して作成してあります。これは、loctestを開いた状態で、現在のプロジェクトへ追加をチェックして作成します。
作成後は、プロジェクトは空なのでloctestからリソースをコピーします。
この後、ダイアログなどのリソースを英文化していきます。
また、各リソースのプロパティを英語(アメリカ)にします。
全て、変更したらビルドしてDLLを作成します。リソースDLLはデバッグの必要が無いので、リリース版のみ作成すれば良いです。
 ちなみに、英語版のときSDI、MDIはデフォルトのストリングテーブルのデータが多いです。そこで、このサンプル作成時は、これらとは別に英語版でloctestを作りそのストリングテーブルをDLLのプロジェクトにコピーして作成しました。
 また、リソースDLLと本体との関係は、リソースIDで結ばれています。リソースIDはresource.hに入っていますが、私はいつも編集後に本体のresource.hをDLL側にコピーしています。
このとき、コピーした後に、resource.hをエディターで開き、3行目のリソース ファイル名をDLLの名前に変更します。
// Used by loctest_eng.rc
VCでこのコメント行を見ているようです。
■ プログラムの説明
 この例では、メニューにより前項で作成したリソースDLLを読込んだり、破棄したりしてリソースを切り替えていますが、切り替える必要が無い場合(多くはこちらだと思いますが)は、起動時にこの処理を1度だけ行えばリソースの変更は終了です。
CLocTestAppのInitInstance内に、この処理がコメントしてあります。

 リソースの切り替えは、CMainFrame内で全て行われています。
以下は、日本語から英語の処理です。
void CMainFrame::OnEnglish() 
{
    m_hEnglish = LoadLibrary( "loctest_eng.dll");
    if ( m_hEnglish)        // 言語DLLが見つかった.
    {
        AfxSetResourceHandle( m_hEnglish);
        ChangeAppearance(); // メニューの変更.
    }
    else                    // 言語DLLが無い.
    {
        AfxMessageBox( "Can not find resource dll!");
    }
}
ここでは、LoadLibrary関数によりDLLを読込んでいます。
読込が成功したら、AfxSetResourceHandleにより読込んだリソースをセットします。
その後、ChangeAppearanceでメニュー・ツールバーを変更します。
 次は、英語から日本語の処理です。
void CMainFrame::OnJapanese() 
{
    if ( m_hEnglish)
    {
        FreeLibrary( m_hEnglish);
        m_hEnglish = NULL;
        AfxSetResourceHandle( m_hDefault);
        ChangeAppearance();     // メニューの変更.
    }
}
日本語に戻す場合は、この例ではデフォルトのリソースは日本語なので、英語のDLLを削除しデフォルトのリソースのハンドルをセットしなおします。
セットしただけでは、メニューとツールバーは変わりません。以下の関数でそれらを変更します。
void CMainFrame::ChangeAppearance()
{
    if ( m_pNewMenu)
    {
        delete m_pNewMenu;                  // 現在のメニューを削除.
    }

    m_pNewMenu = new CMenu;                 // 新しいメニューを作成.

    m_pNewMenu->LoadMenu( IDR_MAINFRAME);   // メニューを読み込む.
    SetMenu( m_pNewMenu);                   // メニューをセット.

    m_wndToolBar.LoadToolBar( IDR_MAINFRAME);   // ツールバーをリロード.
}
今回、ここだけ引っかかったのですが、メニューはデフォルトのものは削除できないようです。
従って、起動時のみデフォルトのメニューが使われ、後は変更時に新しいメニューを作成して再読込するようにしました。
ツールバーに関しては、再読込するだけでうまくいくようです。
また、ステータスバー、アクセラレーターに関しては本体と同じなので今回は何も処理をしていません。

 最後に、システムダイアログですが、英語版にしてもウィンドウズが日本語環境だとキャンセルボタンや、下の画面のように、はい、いいえなどは日本語のままです。


■ ファイルのダウンロード
(MFC6.0 プロジェクトファィル 41KB)