ホーム

OFF-SOFT.net

OFF-SOFT.net

ウェブやソフトウェアに関するサポート&情報サイトです。サイト構築からソフトウェアの作成、利用まであなたの助けになるかも・・・・しれません。たぶん・・。

Qt (5) QtLinguistとtsファイルを調べる

公開日| 2009年05月26日 | コメントはまだありません。
概要 :
 Qtでは、標準で国際化に対応しています。(多言語機能を持っています)
 この機能は、wxWidgetのpoファイルにそっくりです。また、C++Builder (VCL)で対応しているとうな多言語(国際化)機能にも似ています。

 VC++では、リソースファイルの切り替えなどでこれを実現しますが、 Qtでは、それをXMLファイル(tsファイル)で編集してバイナリ(pmファイル)へ変更したものを使います。 このテキストファイルからpoファイルへの変換を行うwxWidgetと感覚は同じです。

 ソースコードからXMLファイルを自動で出力してくれる機能は、C++Builder (VCL)にも似ています。 C++Builder (VCL)では、GUIからきれいにできていたと思いますが、Qtでは、コマンドラインから実行します。

 今回の記事では、Qtアプリケーションの画面を英語から日本語へ切り替えることについて記述します。

関連サイト: http://doc.trolltech.com/4.5/i18n.html

ここで使用したサンプルソースコード:

多言語対応の手順
多言語対応の手順は、以下の手順で行います。

  • 多言語対応したい文字列について、ソースコードを編集する
  • ソースコード(プロジェクト)からtsファイル(翻訳ファイル)を出力し、翻訳する
  • tsファイル(翻訳ファイル)からpmファイルへ変換し、実行ファイルと同じディレクトリへコピーする

では、早速、ソースコードの編集から、やってみましょう。

多言語対応したい文字列について、ソースコードを編集する
多言語対応するために、以下のことを行わなければなりません。
  • 多言語対応する文字列を変換するように指定する
  • メインルーチンで、このアプリケーションで翻訳実行を行うように指示する
今回使うソースコードは、Qt(2)シグナルとスロットを調べるで用いたメニューのある画面を使います。

オリジナルのソースコードは以下のようなものでした。
メニューを表示する度に、"Exit"というメニューアイテムが、有効・無効表示を変化させるものです。

[mainwindow.h]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
 
#include <QtGui>
 
class MainWindow : public QWidget
{
	Q_OBJECT
 
public:
	MainWindow();
 
private slots:
	void updateMenus();
 
private:
	QMenuBar *m_menu;
	QMenu *m_fileMenu;
	QAction *m_exit_act;
 
	bool m_active;
};
#endif

[mainwindow.cpp]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include "mainwindow.h"
 
MainWindow::MainWindow()
{
	m_menu = new QMenuBar( this );
 
	m_fileMenu = m_menu->addMenu(tr("&File"));
 
	m_exit_act = m_fileMenu->addAction("E&xit" );
	m_exit_act->setShortcut(tr("Ctrl+Q"));
	m_exit_act->setStatusTip(tr("Exit the application"));
 
	connect(m_exit_act, SIGNAL(triggered()), 
	         qApp, SLOT(closeAllWindows()));
	connect(m_fileMenu, SIGNAL(aboutToShow()),
	         this, SLOT(updateMenus()));
 
    setWindowTitle(tr("SampleWindow"));
 
	m_active=true;
}
 
void MainWindow::updateMenus()
{
	m_exit_act->setEnabled(m_active);
	m_active=!m_active;
}

[mainwindow.cpp]
1
2
3
4
5
6
7
8
9
10
11
#include <QApplication>
 
#include "mainwindow.h"
 
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MainWindow mainWin;
    mainWin.show();
    return app.exec();
}

実は、このソースコードの中には、既に多言語対応のためのコードが一部入っています。

mainwindow.cppの7行目に"tr("&File")"とあります。この"tr"が、多言語対応のための一つのコードです。
これは、以下のことを実行しています。
  • 多言語対応する文字列を変換するように指定する

簡単ですね。翻訳したい文字に常に"tr()"で囲えば良いのです。

もし、翻訳した文字列が、QObjectを継承していない場合、上記のコードでは、コンパイルエラーとなります。
その場合、 "QObject::tr()"とするか、 クラス定義で、"Q_DECLARE_TR_FUNCTIONS"を埋め込めば、同じように"tr()"で囲えます。
以下は、Q_DECLARE_TR_FUNCTIONSを埋め込んだ例です。

1
2
3
4
5
6
7
8
 class MyClass
 {
     Q_DECLARE_TR_FUNCTIONS(MyClass)
 
 public:
     MyClass();
     ...
 };

また、namespaceを使っている場合、ソースコードの先頭に以下のコメントを埋め込まないと正しく翻訳されません。

1
/* TRANSLATOR NAMESPACE::CLASSNAME */

NAMESPACE:namespaceで使っている名前
CLASSNAME:クラスの名前

例えば、上記のMyClassであれば、以下のよにします。
1
2
3
4
5
6
7
8
9
10
11
#include "MyClass.h"
/* TRANSLATOR TESTNAME::MyClass */
 
using namespace TESTNAME;
 
MyClass::MyClass()
{
   :
}
   :
   :


ここでは、以下の文字列が翻訳対象と指定されていることになります。
	"&File"	
	"Ctrl+Q"	
	"Exit the application"	
	"SampleWindow"	
	
ここで、以下の文字列は、翻訳対象でないことに注意してください。
	"E&xit"

次に、メインルーチンで、このアプリケーションで翻訳実行を行うように指示してみましょう。

[mainwindow.cpp]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <QApplication>
 
#include "mainwindow.h"
 
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
 
 
 
 
 
    MainWindow mainWin;
    mainWin.show();
    return app.exec();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <QApplication>
 
#include "mainwindow.h"
 
int main(int argc, char *argv[])
{
	QApplication app(argc, argv);
 
	QTranslator myappTranslator;
	myappTranslator.load("test_ja");
	app.installTranslator(&myappTranslator);
 
	MainWindow mainWin;
	mainWin.show();
	return app.exec();
}

9行目から10行目まに、コードが追加されました。

ここで、やっていることが、このアプリケーションで"test_ja.pm"というファイルを元に 翻訳するという指定を行っています。

ユーザがつかっている言語を自動的に判断し、その言語で表示させるには、上記の9 - 10行を以下のようにします。

1
2
3
4
5
6
7
8
	QTranslator qtTranslator;
	qtTranslator.load("qt_" + QLocale::system().name(),
	     QLibraryInfo::location(QLibraryInfo::TranslationsPath));
	app.installTranslator(&qtTranslator);
 
	QTranslator myappTranslator;
	myappTranslator.load("test_" + QLocale::system().name());
	app.installTranslator(&myappTranslator);

前半部分は、Qtで使っている文字を変換する宣言をしています。
"QLocale::system().name()"は、ユーザが使っている言語を意味します。
例えば、日本は、"ja_JP"という文字列が出力されます。
後半部分は、"test_"の後に言語文字を指定して、そのファイルで変換するように指定しています。

この指定で、日本語環境の場合、test_ja.pm,test_ja_JP.pmを自動的に探してくれます。

このコードは、サンプルに含まれています。

ソースコード(プロジェクト)からtsファイル(翻訳ファイル)を出力し、翻訳する

先に埋め込んだソースコード(プロジェクト)からtsファイル(翻訳ファイル)を出力します。
やり方は、以下のコマンドを投入するだけです。
※このコマンドを投入する前に、プロジェクトファイル(proファイル)を作成しておく必要があります。

(以下は、参考までに、プロジェクトファイルを作成するまでのコマンドです)
1
2
3
4
C:\Program Files\Microsoft Visual Studio 9.0\VC> cd C:\temp
C:\temp> qmake -project
C:\temp> qmake
C:\temp> 

(以下は、プロジェクトファイルからtsファイルを作成するまでのコマンドです)
1
2
C:\temp> lupdate -pro temp.pro -ts test_ja.ts
C:\temp> 

上記のコマンドパラメータをプロジェクトファイルのみとすることができます。
先のプロジェクトファイルに以下を追記します。

これを保存すると、以下のコマンドパラメータのみで同じ作業を行うことができます。
TRANSLATIONS += test_ja.ts

1
2
C:\temp> lupdate temp.pro
C:\temp> 
また、この作業を1回行っておけば、次回qmakeでプロジェクトファイルを作り直しても test_ja.tsがありますので、自動的に、プロジェクトファイルへ追加されます。
つまり、上記のプロジェクトファイルへの追記は、1回だけすみます。


なお、lupdateコマンドは、追加された文字(文章)は、追加し、既にtsファイルにある文字(文章)ものは、 何もしません。つまり、翻訳文を上書きすることはありません。

以下のようなXMLファイル(test_ja.ts)が出力されたと思います。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.0">
<context>
    <name>MainWindow</name>
    <message>
        <location filename="mainwindow.cpp" line="8"/>
        <source>&File</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location filename="mainwindow.cpp" line="11"/>
        <source>Ctrl+Q</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location filename="mainwindow.cpp" line="12"/>
        <source>Exit the application</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location filename="mainwindow.cpp" line="17"/>
        <source>SampleWindow</source>
        <translation type="unfinished"></translation>
    </message>
</context>
</TS>

翻訳文を以下のタグの間に埋めれば良いだけです。
1
<translation type="unfinished"></translation>

例えば、以下のような埋め込めば良いです。
1
2
3
        <location filename="mainwindow.cpp" line="8"/>
        <source>&File</source>
        <translation type="unfinished">ファイル(&F)(</translation>

今回は、QtLinguistというツールがありますので、それを使ってみましょう。
QtLinguistというツールは、以下のディレクトリあると思います。
ダブルクリックで起動しましょう。
%Qtインストールディレクトリ%\qt\bin\linguist.exe



早速、先に作成したtsファイルを読み込んでみましょう。


このように、翻訳元言語と翻訳先言語を指定する画面が表示されますので、以下のように指定します。
翻訳元言語:English
翻訳先言語:Japanease
この指定は、ほとんど影響がないようです。
ただ、今後、どのように影響するかわかりませんので、設定しておく方が無難だと思います。


上記のよな画面が表示されます。
?:コンテンツ名(セクション名やクラス名のようなものです)
ここでは、MainWindowしかクラスがありませんので、一つです。

?:コンテンツ対応の翻訳文字です。

?:コンテンツ対応の翻訳文字が、ソースコードのどこに記載があるか表示します。
画面の中で記載されている場合は、その画面イメージが表示されます。

?:コンテンツ対応の翻訳文字に対する翻訳後の文字を編集します。
ここで、指定した文字が、翻訳結果として画面に表示されます。

ここでは、以下の文字列を以下のように翻訳しましょう。
	"&File"		-->	ファイル(&F)
	"Ctrl+Q"	-->	none
	"Exit the application"	-->	アプリケーションを終了します。
	"SampleWindow"	-->	サンプルウィンドウ

?で入力を終えたら、保存しましょう。

tsファイル(翻訳ファイル)からpmファイルへ変換し、実行ファイルと同じディレクトリへコピーする
先のQtLinguistから、pmファイルへ変換します。

メニューから[ファイル] - [リリース]をクリックすると、自動で、test_ja.pmファイルを作成します。
以下のようにコマンドラインからも変換することができます。
1
2
C:\temp> lrelease test_ja.ts
C:\temp> 

変換したtest_ja.pmファイルを、実行ファイルと同じディレクトリへコピーします。

では、実際にコンパイルして実行してみましょう。
以下のようにタイトルとメニューが日本語に変換されたと思います。


サンプルのソースコードでは、MainWindowにステータスバーを表示して、以下の翻訳も確認できるようにしています。
	"Exit the application"	-->	アプリケーションを終了します。

"tr()"で括るやり方以外にもマクロを使用した、ダイナミックにテーブルを使うやり方があります。
ただ、これを使う意味があるかは、疑問が残ります。
このマクロの中身は、単純に文字列のテーブルを作成しているに過ぎません。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//	transfer language map
struct __greeting3 {
	const char *source; const char *comment;
};
 
static __greeting3  transfer_strings3[] =
{
	 QT_TRANSLATE_NOOP3("classname_sample3", "Hello3", "hello"),
	 QT_TRANSLATE_NOOP3("classname_sample3", "Hello3", "goodbye")
};
 
static const char *transfer_strings2[] = {
     QT_TRANSLATE_NOOP("MainWindow", "Hello2"),
     QT_TRANSLATE_NOOP("MainWindow", "Goodbye2")
};
 
static const char *transfer_strings1[] = {
     QT_TR_NOOP("Hello1"),
     QT_TR_NOOP("Goodbye1")
};

このテーブルを用いるためには、変換するためのメソッドが必要になります。
以下は、その例です。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//	transfer language method
QString MainWindow::transfer1(int type)
{
	return tr(transfer_strings1[type]);
}
QString MainWindow::transfer2(int type)
{
	return tr(transfer_strings2[type]);
}
QString MainWindow::transfer3(int type)
{
	return tr(transfer_strings3[type].source,
	    transfer_strings3[type].comment );
}

これを用いるのは、クラスやアプリケーション全体で同じ文字を挿入するのを防ぐためなどに管理したい場合なのかもしれません。

ただ、個人的には、用いることが少ないような気がします。
一応、サンプルに中に、上記のようなものも含めました。色んなスコープでうまくいかない場合も含めて検証できると思います。

いかがだったでしょうか。 今回の記事は、一部のソースコードや、使い方は、判りやすいように、また、具体的に変更していますが、ほとんど、関連サイトに記載のものです。
非常に、基本的で、重要なところでしたので、あえて記事にしておきました。

関連サイト: http://doc.trolltech.com/4.5/i18n.html

何かお気づきの点があれば、コメントいただければ幸いです。

もっと、Qt関連について詳しく知りたい方は、以下の本なども良いと思います。
Qtに関する日本語の本が少ないですね。「入門書」は、さすがに、このページを読まれるくらいの方は不要だと思います。
やっぱり、本+ネット+試してみる!!の3本柱でやっていく以外にないように思います。


コメント

コメントをどうぞ







  • はてなブックマークへ追加する
  • Facebookでシェアする
  • twitter でつぶやく
  • Google Plusでシェアする
  • Pocketでシェアする
ページトップへ