Lesson 17:やっぱり日本語

 前々回で日本語コードの変換が出来るようにしました。これで日本語が扱えるようにはなったのですが、メニュー等の表記は、あたりまえですが英語のままです。
 どうせならメニューやメッセージも日本語化してみましょう。

 今までメニュー等を英語で表記していたのは、標準の開発環境であるBeIDEのエディタが日本語を扱えなかったからです。他の開発環境にしてやれば普通に日本語を扱う事もできるのでしょうが、それはそれで面白くない。やはり、ここはBeIDEのエディタを使った上で、日本語を扱うようにしましょう。

 そこでどうやって日本語を扱うかですが、考えられる方法としては、外部ファイルに日本語を含んだ文字列を作成しておき、実行時にそのファイルから読み込むようにする方法です。この方法ならば日本語の外部ファイルを他のエディタで作成してやれば良いので、プログラム自体には日本語コードが含まれなくてすみます。
 しかし、この方法ですと、外部ファイルの格納されているパスを把握したり、外部ファイルが存在しなかった場合にどうするのか等の問題が発生してしまいます。
 それならば、他にはどういった方法が考えられるのか。そこで思い出すのは、アイコンなどを実行ファイルに含める際に、リソースファイルを作成してリンクした事です。同じように日本語を含んだ文字列をリソースファイルに定義しておき、それを実行ファイルにリンクしてやれば良いでしょう。
 実行ファイルにリンクしたリソースならば、外部ファイルの用に削除されてしまったりする事がない。それにIDで呼び出せるので、プログラムする上でも楽です。

 ではリソースファイルを作るにはどうしたらよいか。実はBeOSにはリソースエディタが用意されています。/boot/develop/tools/experimental/QuickRes/に、QuickResというアプリケーションがあります。これでリソースファイルの作成や編集が行なえます。(experimentalですが、文字列のリソースを作るぶんには、何の問題もありませんでした。)
 直感的に使える簡単なツールですので、とくに使い方の説明はしません。

 どうせならば、日本語も英語も扱えるように、両方のメッセージを登録したリソースファイルを作成します。
 ファイル名は、strings.rsrc。IDは、英語は1001から、日本語は2001から定義し、英語の文字列に対応する日本語の文字列は、英語のIDの1000番増しとしました。また、resmsg.hというヘッダファイルを作成して、メッセージを選択する際に使用する列挙型も作成しました。
 以下に定義した内容を記します。
ID
列挙型英語日本語
文字列ID文字列
rmFile1001File2001ファイル
rmOpen1002Open...2002開く...
rmNewText1003New Text2003新しいテキスト
rmSave1004Save2004保存
rmSaveAs1005Save As...2005名前を付けて保存...
rmCharacterCode1006Character Code2006文字コード
rmUTF81007UTF82007UTF8
rmSJIS1008SJIS2008SJIS
rmJIS1009JIS2009JIS
rmEUC1010EUC2010EUC
rmLF1011LF2011LF
rmCRLF1012CR/LF2012CR/LF
rmClose1013Close2013閉じる
rmQuit1014Quit2014終了
rmEdit1015Edit2015編集
rmUndo1016Undo2016アンドゥ
rmCopy1017Copy2017コピー
rmCut1018Cut2018切り取り
rmPaste1019Paste2019貼り付け
rmSelectAll1020Select All2020全選択
rmSearch1021Search2021検索
rmFind1022Find2022検索
rmFindNext1023Find Next2023次を検索
rmReplaceFindNext1024Replace & Find Next2024置換後次を検索
rmReplaceInSelection1025Replace in Selection2025選択範囲内を置換
rmFileReadFailed1026File read failed!!2026ファイルの読み込みが失敗しました。
rmFileWriteFailed1027File write failed!!2027ファイルの保存が失敗しました。
rmSaveChangesTo1028Save changes to
the document "%s"?
2028編集した文章"%s"を保存しますか?
rmCancel1029Cancel2029キャンセル
rmDontSave1030Don't save2030保存しない
rmReplace1031Replace2031置換
rmIgnoreCase1032Ignore case2032大/小文字を区別しない
rmReplaceAll1033Replace All2033全置換
rmSetting1034Setting2034設定
rmLanguageChange1035Language Change2035言語変更
rmLanguageChanged1036English was selected.\r\nThis setting is used
after the next time.\r
2036日本語を選択しました。\nこの設定は次回から有効になります。
 作成したリソースファイルは、BTinyEditor.rsrcを追加したときと同じように、プロジェクトに追加しておきます。
 リソースの定義ができたら、次は、このリソース(正確には実行ファイルにリンクしたリソース)から文字列を呼び出し方法です。
 実行ファイル(アプリケーション)にリンクされたリソースにアクセスするには、BApplicationクラスのAppResources関数を使用します。BApplicationクラスにはbe_app変数を使用すれば良いので、be_app->AppResources()とすることで、リソースにアクセスするための、BResourcesクラスを取得できます。
 日本語か英語かを判断し、リソースから文字列を取得するのを楽にするために、resmsg関数を作成します。

/**** ファイル名 : resmsg.h ****/

#ifndef RESMSGH
#define RESMSGH
//--------------------------------------------------------------------- 
enum RESMSGID {rmFile=1001,rmOpen,rmNewText,rmSave,rmSaveAs,
               rmCharacterCode,rmUTF8,rmSJIS,rmJIS,rmEUC,rmLF,rmCRLF,
               rmClose,rmQuit,rmEdit,rmUndo,rmCopy,rmCut,rmPaste,
               rmSelectAll,rmSearch,rmFind,rmFindNext,rmReplaceFindNext,
               rmReplaceInSelection,rmFileReadFailed,rmFileWriteFailed,
               rmSaveChangesTo,rmCancel,rmDontSave,rmReplace,
               rmIgnoreCase,rmReplaceAll,rmSetting,rmLanguageChange,
               rmLanguageChanged};
//--------------------------------------------------------------------- 
extern bool usedjapanese;
char *resmsg(enum RESMSGID id);
//--------------------------------------------------------------------- 
#endif

/**** ファイル名 : resmsg.cpp ****/

//--------------------------------------------------------------------- 
#include <Be.h>
#include "resmsg.h"
//--------------------------------------------------------------------- 
bool usedjapanese;
//--------------------------------------------------------------------- 
char *resmsg(enum RESMSGID id)
{
    size_t outSize;
    char *wk;
    int32 i;
        
    i=id;
    i+=usedjapanese?1000:0;
    outSize=256;
    wk=(char *)(be_app->AppResources()->LoadResource(B_STRING_TYPE,
                                                     i,&outSize));
    return wk;
}
//--------------------------------------------------------------------- 

 RESMSGID列挙型は、リソースから文字列を取得する際のIDの取得に用います。グローバル定義したusedjapanese変数は、日本語を使用する場合にはtrueにし、英語を使用する場合はfalseとしておきます。
 resmsg関数は、引数にRESMSGID列挙型の値を渡せば、それに対応した文字列をリソースから取得し、そのポインタを返します。
 具体的には、変数iに引数のidを渡し、更に日本語を使用する場合は、1000付加してリソースのIDを得て、be_app->AppResources()でBResoucesクラスを取得したらIDで文字列の取得を行なっています。

 リソースから文字列を取得する手段を作りましたので、次は、日本語を使用するか、英語を使用するかの選択と、その設定の保存、読み込みを作成します。
 まず、設定の変更ですが、これには新たにSettingメニュー(日本語なら「 設定」)を作成し、その中にLanguage Change(「言語変更」)を作成します。このメニューを選択するたびに、使用する言語を日本語、英語を交互に切りかえるようにします。
 メニューの定義はBEditorViewクラスのコンストラクタで行っていますので、その中にSettingメニューを追加します。更に、ここでresmsg関数を使用して、リソースから文字列の取得を行なってみます。

    BMenu *settingmenu=new BMenu(resmsg(rmSetting));
    settingmenu->AddItem(new BMenuItem(resmsg(rmLanguageChange),
                                       new BMessage(MSG_LANGCHANGE)));
    settingmenu->ItemAt(0)->SetTarget(be_app); 
    mainmenu->AddItem(settingmenu);     

 例によって、MSG_LANGCHANGEはMainWindow.hで定義しておきます。また、BMenuクラスとBMenuItemクラスのコンストラクタでresmsg関数を使いリソースから文字列の取得を行なっています。

 使う言語の設定はアプリケーション全体で共有しますので、設定の保存と読み込みは、BTinyEditorAppクラスで行ないます。そのため、MSG_LANGCHANGEメッセージの送信先もbe_appにしています。
 BTinyEditorAppクラスのMessageReceived関数でMSG_LANGCHANGEメッセージを処理しましょう。

    case MSG_LANGCHANGE:
        {
            usedjapanese=usedjapanese?false:true;
            BAlert *infmsg = new BAlert("Error", 
                                        resmsg(rmLanguageChanged),"OK", 
                                        NULL,NULL,B_WIDTH_AS_USUAL); 
            infmsg->Go(); 
        }
        break;    

 MSG_LANGCHANGEメッセージを受けたら、usedjapaneseの設定を反転して、BAlertクラスで設定を変更した旨のメッセージを表示します。メッセージの内容も当然リソースから取得します。

 設定の保存は、前回作成した設定保存用のリソースファイルに行ないましょう。読み込みはBTinyEditorAppのコンストラクタ、保存はデストラクタで行なえば良いでしょう。

/**** ファイル名 : BTinyEditor.cpp ****/

//--------------------------------------------------------------------- 
BTinyEditorApp::BTinyEditorApp() 
    :BApplication(APPLICATION_SIGNATURE) 
{ 
    BResources res;
    BFile file;

    usedjapanese=false;
    if(file.SetTo(RESOURCEFILEPATH, B_READ_ONLY)==B_OK)
    {
        size_t siz;
        int32 *wk;
            
        res.SetTo(&file);
            
        siz=sizeof(int32);
        wk=(int32 *)res.LoadResource(B_INT32_TYPE,R_JAPANESE,&siz);
        if(wk!=NULL)
        	usedjapanese=(bool)*wk;

        file.Unset();    
    }

    EditorList=new BList(); 
    open_filepanel= new BFilePanel(); 
    findword="";
    replaceword="";
    ignorecase=false;
} 
//--------------------------------------------------------------------- 
BTinyEditorApp::~BTinyEditorApp() 
{ 
    BResources res;
    BFile file(RESOURCEFILEPATH, B_READ_WRITE | B_CREATE_FILE);
    int32 wk;
    
    res.SetTo(&file);

    wk=(int32)usedjapanese;
    res.AddResource(B_INT32_TYPE,R_JAPANESE,&wk,sizeof(wk));

    res.Sync();
    file.Unset();    

    delete open_filepanel; 
        
    for(int i=EditorList->CountItems()-1;i>=0;i--) 
    { 
        BEditorWindow *targetwnd= 
                        ((BEditorWindow *)EditorList->ItemAt(i)); 
        targetwnd->Lock();
        targetwnd->Quit(); 
        EditorList->RemoveItem(targetwnd); 
    } 
    delete EditorList; 
} 
//--------------------------------------------------------------------- 

 ここまで行なえば、言語切替の準備が出きましたので、実際に動かしてSettingメニューから言語変更ができ、それによってSettingメニューの表示が切り替わる事を確認しましょう。表示の切り替えは新しいウィンドウから効果がありますので、アプリケーションを起動しなおすか、New Text等で新しいウィンドウを作成してください。
 コンパイルする前に、resmsg.cppのプロジェクトへの追加と、resmsg.hの組み込みを忘れないでください。

 日本語でメニュー表示できる事を確認したら、他の文字列についても、resmsg関数を使いリソースから取得するようにしましょう。(かなり量があります。)

 これでメニュー等の日本語化もできるようになります。この方法はどんなアプリケーションを作成した場合にも利用できる方法です。使い方次第で、リソースは色々と役に立つ便利な手法ですね。

ソースリスト
圧縮ファイル
R5 Intel環境で確認
BTinyEditor20000710.zip
ソースファイル BTinyEditor.cpp
BTinyEditor.h
BFindWindow.cpp
BFindWindow.h
BMemoView.cpp
BMemoView.h
cccheck.cpp
cccheck.h
main.cpp
MainWindow.cpp
MainWindow.h
resmsg.cpp
resmsg.h

次の項目へ

トップページへ戻る