Haiku OS アプリケーションのローカライズ

Haiku OS アプリケーションを C++ で実装したときにローカライズを提供する方法について説明します。

公式で提供する方法以外にも po ファイルを使った方法などがあります。ここでは、標準 API による方法について述べます。

シグネチャ

プログラムなどにシグネチャを割り当てます。他のプログラムと衝突しないように選んでください。

BApplication クラスのインスタンス化時に渡すものと同じです。以下に例を示します。

#include <Application.h>

#define APP_SIGNATURE "application/x-vnd.AquaSKK-Preference"

class SKKPreferenceApp : public BApplication
{
public:
    SKKPreferenceApp();
    virtual ~SKKPreferenceApp() {};
};

SKKPreferenceApp::SKKPreferenceApp()
    : BApplication(APP_SIGNATURE)
{
}

この例でのシグネチャは x-vnd.AquaSKK-Preference です。application/ の部分はシグネチャには含めません。

このシグネチャを使用してプログラムとローカライズリソースを結びつけます。

ファイルの種類

以下のような種類のファイルを取り扱います。

種類 説明
C++ ローカライズする文字列を含むソースコード
pre ソースコードをまとめたファイル
catkeys 候補とチェックサムを含むタブ区切りテキストファイル
catalog ローカライズ用変換済みバイナリ
rdef リソース定義テキストファイル
rsrc 変換済みバイナリリソースファイル

プログラム

以下のようなプログラムでローカライズ用リソースを作成します。

プログラム 説明
collectcatkeys pre ファイルから候補を抽出して catkeys ファイル出力
linkcatkeys catkeys ファイルから catalog ファイルを生成
rc rdef を rsrc ファイルへ変換
xres rsrc を実行フィルなどに結合

ソースコードでの候補マーキング

C++ ソースコード中でローカライズする文字列を指定します。

// 必要なヘッダのインクルード
#include <Catalog.h>

// コンテキストの定義
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "App-Preference"

printf(B_TRANSLATE("Hello"));

Catalog.h をインクルードしてコンテキストなどを定義しておきます。その後、B_TRANSLATE などのマクロでローカライズ候補を指定します。

B_TRANSLATE などのマクロは B_COLLECTING_CATKEYS が定義されていると定義内容が変更され、pre ファイルを生成するときのマーキングが有効になります。普通にコンパイルするときには B_COLLECTING_CATKEYS を定義してはいけません。

マーキングの種類

以下のようなマクロが定義されています。用途に応じて使い分けてください。

マクロ 説明
B_TRANSLATE(string) 翻訳させる。現在のコンテキスト
B_TRANSLATE_CONTEXT(string, context) 指定のコンテキストで翻訳
B_TRANSLATE_COMMENT コメント付き
B_TRANSLATE_ALL(string, context, comment) コンテキストとコメントの両方を指定
B_TRANSLATE_ID(id) リソース ID 参照?
B_TRANSLATE_SYSTEM_NAME(string) システムリソースから翻訳
B_TRANSLATE_MARK(string) 翻訳マーキングのみ
その他 Catalog.h参照

B_TRANSLATE_MARK は Catalog.h に説明のあるとおり、翻訳候補としてマークされますが、実行時には翻訳されません。B_TRANSLATE などに渡して自分で翻訳後の文字列を取得してください。静的文字列配列の要素を翻訳用の catkeys に含めたいときに利用します。

候補の抽出用ファイル生成

候補抽出用にまとめた pre ファイルを生成します。これはヘッダファイルの内容もまとめて一つのファイルにしたものです。

ファイルを一つにまとめるには以下のようにコンパイラプリプロセッサを利用します。

gcc -E -x c++ -DB_COLLECTING_CATKEYS -I./ app.cpp

-E オプションでプリプロセッサのみ実行します。-x c++C++ を指定しています。 -DB_COLLECTING_CATKEYS を指定して候補抽出ようマクロに切り替えます。

処理時にエラーが出た場合、大抵はインクルードパスが不足しています。

これで生成されたファイルに含まれる # から始まる行が悪さをすることがあるため、以下のようなスクリプトでそのような行を削除してしまうとよいでしょう。

# gen_pre.py
import sys
import argparse
import subprocess

def gen_pre(parser, includes, outpath, input_paths):
    inc = ["-I" + i for i in includes]
    data = []
    args = [parser, '-E', '-x', 'c++', 
            '-DB_COLLECTING_CATKEYS', '-DOS_LINUX', '-DOS_HAIKU']
    args.extend(inc)
    args.extend(input_paths)
    p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    if p.poll() is None:
        out = p.stdout.read()
        data.extend([line for line in out.split("\n") 
                        if not line.startswith("#")])
    else:
        print(p.stderr.read())
        return -1
    with open(outpath, "w") as f:
        f.write("\n".join(data))
    return 0

def main():
    parser = argparse.ArgumentParser(
                description='Generates pre file from B_TRANSLATE.')
    parser.add_argument('--parser',
                help='C compiler')
    parser.add_argument('--outpath', 
                help='pre file')
    parser.add_argument('--includes', nargs='+',
                help='Include dirs')
    parser.add_argument('--inputpath', nargs='+',
                help='C++ files to be extracted')
    args = parser.parse_args()
    return gen_pre(args.parser, args.includes, args.outpath, args.inputpath)

if __name__ == '__main__':
    sys.exit(main())

この Python スクリプトは以下のように実行します。

python gen_pre.py --parser gcc --outpath out.pre --includes ../ --inputpath foo.cpp

catkeys ファイル生成

pre ファイルから候補を抜き出した catkeys ファイルを生成します。

collectcatkeys -s SIGNATURE -o en.catkeys out.pre

catkeys ファイルには元の文字列から生成されたチェックサムが含まれているため、元の文字列を変更するとファイルが壊れてしまいます。ソースコードローカライズする文字列を変更したときは、pre ファイルを経由して catkeys ファイルを生成しなおしてください。

翻訳

en.catkeys ファイルを ja.catkeys としてコピーします。このファイルを翻訳します。

catkeys ファイルは以下のような構造をしています。

バージョン 言語 シグネチャ チェックサム
1   English x-vnd.AquaSKK-Preference    948131552
Select location...  Preference      Select location...
Enable  Preference      Enable
元文字列 コンテキスト コメント 翻訳後文字列

各項目はタブで区切られています。言語名は変更しなくても問題ありません。

タブ区切りテキストのため、テキストエディタで編集できます。日本語が表示できてタブが可視化できるエディタをおすすめします。

CatKeysEditor で翻訳できますが、保存されないバグなどがあるようです。

catalog ファイル生成

catkeys ファイルを翻訳した後、catalog ファイルへ変換します。

linkcatkeys -o ja.catalog -s SIGNATURE -l ja ja.catkeys

-l オプションで言語名を指定します。ファイル名は言語名.catalog としておきます。

catalog ファイル配置

catalog ファイルは指定の場所に配置してシステムが読み込めるようにします。

システムまたは非パッケージ用の配置場所があります。

# システム
/boot/system/data/locale/catalogs/SIGNATURE/ja.catalog
# 非パッケージ
/boot/home/config/non-packaged/data/locale/catalogs/SIGNATURE/ja.catalog

テストやパッケージ化セずに配布するアプリケーションでは非パッケージ用の場所に配置すると良いでしょう。

rdef ファイル定義

アプリケーションの実行ファイルにリソースに関する情報を追加しますが、その内容を定義するのが rdef ファイルです。

resource app_signature "application/x-vnd.App-Preference";
resource app_name_catalog_entry "x-vnd.App-Preference:System name:apppref";

ここで必要となるのはシグネチャです。アプリケーション、ローカライズ用 catkeys ファイルとシグネチャを合わせてください。

app.rdef などとして保存しておきます。

rdef ファイルではファイルアイコンなども指定できますが、ここでは説明を割愛します。

rdef ファイルを rsrc に変換

rdef ファイルをバイナリの rsrc ファイルに変換します。

rc -o app.rsrc app.rdef

rsrc を埋め込み

rsrc ファイルをアプリケーションの実行ファイルに埋め込みます。

xres -o app app.rsrc

ここでは、すでに存在する実行ファイル app に app.rsrc ファイルを埋め込んでいます。app ファイルが上書きされるので注意してください。リソースを埋め込んだ後のファイルを別ファイルにしたい場合、事前に実行ファイルをコピーしてください。


ロケールを合わせてアプリケーションを実行すると文字列がローカライズされた状態でプログラムが起動します。