読者です 読者をやめる 読者になる 読者になる

つくねの手帳

C++およびAndroidアプリ開発メインで何か書きたい

Qt 同じ単語に複数の翻訳をあてるのに少し頑張った話1

C++ Qt

この記事はQt4.8.4基準で記載します。

Qtにはソース上の文字列を拾い上げて、翻訳用のファイルを作っておくことで、プログラム実行時に動的言語変換ができます。
具体的な手順は割愛しますが、

QLabel text;
text.setText(tr("string"));

のように、trでくくった文字列をlupdateで抜き出し、xml形式の.tsファイルを生成します。
その.tsファイルをQtLinguistで手動翻訳し、lreleaseで.qmファイルを作り、その.qmファイルをプログラムで読み込みます。


.qmファイルがどのように生成されているかわからないので、実際に動作させてみて確かめただけなのですが、.tsファイル上に同じ単語が複数ある場合、別々な翻訳をしても、一番上に書かれたもので表示されてしまうようです。

QLabel text;
text.setText(tr("start")); // スタートと表示したい

QLabel text2;
text2.setText(tr("start")); // 開始と表示したい

このような場合、以下のように.tsファイルを記述しても、一律スタートと表示されてしまいます。

<!-- 日本語でスタートと表示したいやつ。 -->
    <message>
        <location filename="xxx" line=""/>
        <source>start</source>
        <translation type="unfinished">スタート</translation>
    </message>

<!-- 日本語で開始と表示したいやつ。 -->
    <message>
        <location filename="xxx" line=""/>
        <source>start</source>
        <translation type="unfinished">開始</translation>
    </message>


そこで、ソース上に書く文字列は識別用のIDとしてユニークなものとして扱う手段を取りました。

下準備として、以下のものを用意しました。
・文字列を指定するenum
enumに対応する文字列 QT_TR_NOOP("")の形で記載
・指定されたenumから文字列をsetText(tr(""));へ渡すラッパー関数

typedef enum
{
  E_TEXT_1,
  E_TEXT_2
}stringId;


QString* stringData[] = 
{
  QT_TR_NOOP("E_TEXT_1"),
  QT_TR_NOOP("E_TEXT_2"),
};
void setStringId(stringId id)
{
  this->m_pLabel->setText(tr(stringData[id])); //実際は配列直指定はやめましょう
}

かなりざっくり書きましたが、いままで""でくくって文字列としていた場所をenumの文字列で書くイメージです。

この場合、文字列が増えるたびにenum、文字列定義、.ts/.qmファイル作成が発生してとても面倒です。
そこで、.ts/.qmファイル作成まで自動でやってしまえ!というのが次回のお話。