Difference between revisions of "Translations / i18n / localizations for programs/ja"

From Lazarus wiki
Jump to navigationJump to search
m (Fixed syntax highlighting; deleted category included in page template)
 
(6 intermediate revisions by one other user not shown)
Line 5: Line 5:
 
==概要==
 
==概要==
  
このページでは、プログラムで用いる文字列を英語、中国語、ドイツ語、フィンランド語、イタリア語…といった各国語にあわせて変更することができるようにする方法を紹介します。基本的には、次のようになります : 各々のキャプションに ''resourcestring'' (リソース文字列定義)を加え、コンパイルして .rst ファイルないしは .po ファイルを得ます(IDE が自動的に行います)。各国語用にそれぞれ一つの翻訳済み .po  ファイルを生成し、LCL の ''translations'' ユニット内の関数を用いて、プログラムの起動時に、正しいものをロードします。
+
このページでは、プログラムで用いる文字列を英語、中国語、ドイツ語、フィンランド語、イタリア語…といった各国語にあわせて変更することができるようにする方法を紹介します。基本的には、次のようになります。各々のキャプションに ''resourcestring'' (リソース文字列定義)を加え、コンパイルして .rst ファイルないしは .po ファイルを得ます(IDE が自動的に行います)。各国語用にそれぞれ一つの翻訳済み .po  ファイルを作成し、LCL の ''translations'' ユニット内の関数を用いて、プログラムの起動時に、適切なものを読み込みます。
  
 +
==日付、時刻、数値の書式==
  
==Date, time and number format==
+
Linux、BSD、Mac OS X では、時刻や日付、桁区切りなどに対して地域設定があります。右横書きに対応させるには、lpr ファイルあたりの uses 節に clocale ユニットを追加する必要があります。
  
Under Linux, BSD, Mac OS X there are several locales defining things like time and date format or the thousand separator. In order to initialize the RTL you need to iclude the clocale unit in the uses section of your program (lpr file).
+
==リソース文字列==
  
==Resourcestrings==
+
定義例:
 
+
<syntaxhighlight lang=pascal>resourcestring
:
 
<syntaxhighlight>resourcestring
 
 
     Caption1 = 'Some text';
 
     Caption1 = 'Some text';
 
     HelloWorld1 = 'Hello World';</syntaxhighlight>
 
     HelloWorld1 = 'Hello World';</syntaxhighlight>
  
これらは通常の文字列定数と同様に、いかなる文字列にも代入することができます。例えば
+
リソース文字列は通常の文字列定数と同様に、いかなる文字列にも代入することができます。
<syntaxhighlight>Label1.Caption := HelloWorld1;</syntaxhighlight>
+
 
 +
使用例:
 +
<syntaxhighlight lang=pascal>Label1.Caption := HelloWorld1;</syntaxhighlight>
  
コンパイル時にfpc は '''unitname.rst''' を各ユニットに一つ生成します。その中にはリソース文字列のデータ(名前と中身)が含まれます。
+
コンパイル時に FPC は '''ユニット名.rst''' を各ユニットに一つ生成します。その中にはリソース文字列のデータ(名前と中身)が含まれます。
  
 
==.po ファイル==
 
==.po ファイル==
  
生成した .po ファイルを編集するためには、数多くのグラフィカルツールが無料で提供されています。実際 .po ファイルは .rst ファイル同様単なるテキストファイルですが、作者・文字コード・言語・日付といった要素を含んだヘッダのような付随的な要素を含んでいます。FPC をインストールすれば必ず '''rstconv''' というツールがついてきます (Windowsでは rstconv.exe)。このツールは .rst ファイルを .po ファイルに変換します。IDE を使うと、この変換操作を自動的に行うことができます。フリーなツールの例としては kbabel、po-auto-translator、poedit、virtaal があります。
+
生成した .po ファイルを編集するためには、数多くのグラフィカルツールが無料で提供されています。実際 .po ファイルは .rst ファイル同様単なるテキストファイルですが、作者・文字コード・言語・日付といった要素を含んだヘッダのような付随的な要素を含んでいます。FPC をインストールすれば必ず '''rstconv''' というツールがついてきます(Windows では rstconv.exe)。このツールは .rst ファイルを .po ファイルに変換します。IDE を使うと、この変換操作を自動的に行うことができます。フリーなグラフィカルツールの例としては kbabel、po-auto-translator、poedit、virtaal があります。
  
Virtaal has a translation memory containing source-target language pairs for items that you already translated once, and a translation suggestion function that shows already translated terms in various open source software packages. These function may save you a lot of work and improve consistency.
+
virtaal には翻訳メモリ機能があります。翻訳メモリとは、これまでに翻訳された文が原文と対になって集められているもので、さまざまなオープンソースのこれまでの翻訳用語を参考翻訳語として提案します。翻訳作業の軽減と翻訳語の統一に役立つでしょう。(訳注:程度の差はあれ、他のツールにも似たような機能はあります。)
  
 
直接 rstconv を用いる例:
 
直接 rstconv を用いる例:
Line 37: Line 38:
 
それぞれの言語用に .po ファイルをコピーして翻訳する必要があります。LCL の translation ユニットは標準言語コード (en=英語, de=ドイツ語, it=イタリア語, ...) を用いて言語を検索します。例えば、unit1.po のドイツ語版は unit1.de.po となります。つまり、unit1.po ファイルを unit1.de.po、unit1.it.po などなどサポートしようと思っている言語用の名前でコピーして、そのファイルを各国語の翻訳者が編集すればいいわけです。
 
それぞれの言語用に .po ファイルをコピーして翻訳する必要があります。LCL の translation ユニットは標準言語コード (en=英語, de=ドイツ語, it=イタリア語, ...) を用いて言語を検索します。例えば、unit1.po のドイツ語版は unit1.de.po となります。つまり、unit1.po ファイルを unit1.de.po、unit1.it.po などなどサポートしようと思っている言語用の名前でコピーして、そのファイルを各国語の翻訳者が編集すればいいわけです。
  
{{Note|ブラジル人/ポルトガル人へ: Lazarus IDE と LCL はブラジルのポルトガル語(拡張子 'pt_BR.po')だけしか用意しておりません。}}
+
{{Note|ブラジル人/ポルトガル人へ:Lazarus IDE と LCL はブラジルのポルトガル語(拡張子 'pt_BR.po')だけしか用意しておりません。}}
  
==自動的に .po ファイルをアップデートする IDE のオプション==
+
==.po ファイルを自動更新する IDE のオプション==
  
 
*リソース文字列を含むユニットをパッケージないしプロジェクトに加えます。
 
*リソース文字列を含むユニットをパッケージないしプロジェクトに加えます。
*.po ファイルを出力するパスを指定します。これは隔離された単独のディレクトリにしてください。例えば、パッケージ/プロジェクトのディレクトリに language という名前のサブディレクトリを作ります。プロジェクトに追加する場合はプロジェクト→プロジェクトオプション、パッケージの場合はオプション→IDE 統合から行います。
+
*.po ファイルを出力するパスを指定します。これは隔離された単独のディレクトリにしてください。例えば、パッケージ/プロジェクトのディレクトリに language という名前のサブディレクトリを作ります。この指定をプロジェクトに追加する場合はプロジェクト→プロジェクトオプション、パッケージの場合はオプション→IDE 統合から行ってください。
  
このオプションが有効になっている場合、IDE は .rst および .lrt ファイルに含まれている情報を使用して原本となる .po ファイルを生成・更新します(この後に rstconv ツールを使う必要はありません)。これは自動更新処理として行われます。原本の .po ファイル、.rst と .lrt ファイルにすべての項目を集計し、その後に翻訳ファイル .xx.po に対して該当する以下の機能による更新が行われます。
+
このオプションが有効になっている場合、IDE は .rst および .lrt ファイルに含まれている情報を使用して原本となる .po ファイルを生成・更新します(別途 rstconv ツールを使う必要はありません)。これは自動更新処理として行われます。また、原本の .po ファイル、.rst と .lrt ファイルにすべての項目をまとめた後に、翻訳ファイル .xx.po に対して該当する以下の機能による更新が行われます。
  
 
===使われなくなった項目の除去===
 
===使われなくなった項目の除去===
Line 53: Line 54:
  
 
いくつかの理由によって同じ文字列が異なったリソース文字列で使われている場合に、重複項目が生じます。例えば、ファイル lazarus/ide/lazarusidestrconst.pas に 'Gutter' という文字列があるとします。
 
いくつかの理由によって同じ文字列が異なったリソース文字列で使われている場合に、重複項目が生じます。例えば、ファイル lazarus/ide/lazarusidestrconst.pas に 'Gutter' という文字列があるとします。
<syntaxhighlight>  dlfMouseSimpleGutterSect = 'Gutter';
+
<syntaxhighlight lang=pascal>  dlfMouseSimpleGutterSect = 'Gutter';
 
   dlgMouseOptNodeGutter = 'Gutter';
 
   dlgMouseOptNodeGutter = 'Gutter';
 
   dlgGutter = 'Gutter';
 
   dlgGutter = 'Gutter';
Line 70: Line 71:
 
  ・・・
 
  ・・・
  
"#: " で始まる行は重複を考慮したコメントになっていますが、翻訳ツールでこの項目を翻訳しようとすると、繰り返し現れる msgid "Gutter" の行が重複項目と見られ、読み込みや保存時にエラーもしくは警告を発します。関連する複数の状況で使い分けの必要があるため、.po ファイル上における重複項目は少ないながらも存在するのです。msgctxt キーワードは重複項目へ状況(コンテキスト)を追加するのに使われるもので、自動更新処理はコンテキスト("#: " で始まる文の次行)も項目 ID として使用します。上にあった例では、以下のように生成されます。
+
"#: " で始まる行は重複を考慮したコメントになっていますが、翻訳ツールでこの項目を翻訳しようとすると、繰り返し現れる msgid "Gutter" の行が重複項目と見られ、読み込みや保存時にエラーもしくは警告を発します。関連する複数の状況で使い分けの必要があるため、.po ファイル上における重複項目は少ないながらも存在するのです。これらが区別できるよう、msgctxt キーワードが重複項目へ追加されるようになっています("#: " で始まる文の次行)。この状況(コンテキスト)を示すキーワードも含めて項目を識別するものとして使われます。上にあった例では、以下のように生成されます。
  
 
  #: lazarusidestrconsts.dlfmousesimpleguttersect
 
  #: lazarusidestrconsts.dlfmousesimpleguttersect
Line 84: Line 85:
 
  ・・・
 
  ・・・
  
On translated .xx.po files the automatic tool does one additional check: if the duplicated entry was already translated, the new entry gets the old translation, so it appears like being translated automatically.
+
自動更新処理が行われる翻訳ファイル .xx.po に対して一つ確認してもらいたいことがあります。重複項目が既に翻訳されていた場合、新しく追加された項目がまるで自動的に翻訳されたかのように既存の翻訳を奪ってしまうことがあるのです。
  
The automatic detection of duplicates is not yet perfect, duplicate detection is made as items are added to the list and it may happen that some untranslated entries are read first. So it may take several passes to get all duplicates automatically translated by the tool.
+
重複の自動検出はまだ完全ではありません。項目が文字列リソースに追加されたのであれば、重複検出を行い、まずは未翻訳項目を洗い出さなければなりません。自動更新処理ですべての重複項目を翻訳対応させるには、更なる改良を必要としているのです。
  
 
===未確定項目===
 
===未確定項目===
  
 
リソース文字列が変更されると、翻訳されてものにも影響します。例えば、以下に示すようなリソース文字列が最初に定義されていたとします。
 
リソース文字列が変更されると、翻訳されてものにも影響します。例えば、以下に示すようなリソース文字列が最初に定義されていたとします。
(訳注:以下の例は実際の Lazarus の変更履歴を元にしていますが、元の例は日本語ではあまり適切ではないので、別の例を取り上げています。)
+
(訳注:以後の例は実際の Lazarus の変更履歴を基にしていますが、元の例は日本語ではあまり適切ではないので、別の例を取り上げています。)
  
<syntaxhighlight>lisKMToggleViewCallStack = 'Toggle view Call Stack';</syntaxhighlight>
+
<syntaxhighlight lang=pascal>lisKMToggleViewCallStack = 'Toggle view Call Stack';</syntaxhighlight>
  
これに基に作られる .po ファイルの該当項目は以下のようになります。
+
これを基に作られる .po ファイルの該当項目は以下のようになります。
  
 
  #: lazarusidestrconsts.liskmtoggleviewcallstack
 
  #: lazarusidestrconsts.liskmtoggleviewcallstack
Line 109: Line 110:
 
後日、このリソース文字列が以下のように変更されたとします。
 
後日、このリソース文字列が以下のように変更されたとします。
  
<syntaxhighlight>lisKMToggleViewCallStack = 'View Call Stack';</syntaxhighlight>
+
<syntaxhighlight lang=pascal>lisKMToggleViewCallStack = 'View Call Stack';</syntaxhighlight>
  
 
この修正で .po ファイルの項目は以下のようになるでしょう。
 
この修正で .po ファイルの項目は以下のようになるでしょう。
Line 125: Line 126:
 
  msgstr "コールスタックの表示の切り替え"
 
  msgstr "コールスタックの表示の切り替え"
  
In terms of .po file format, the "#," prefix means the entry has a flag (fuzzy) and translator programs may present a special GUI to the translator user for this item. In this case, the flag would mean that the translation in its current state is doubtful and needs to be reviewed more carefully by translator. The "#|" prefix indicates what was the previous untranslated string of this entry and gives the translator a hint why the entry was marked as fuzzy.
+
.po ファイル書式の用語では、"#," で始まる行は項目のフラグ (fuzzy, 未確定) を意味していて、翻訳ツールは翻訳ユーザにそれが確認できるように作られています。このフラグは、現在の翻訳状態では不確かなものであるので翻訳者による詳細な再考が必要であることを意味しています。"#|" で始まる行は、この項目の以前の翻訳を示し、不確定フラグが付いた経緯のヒントを翻訳者に提供するものです。
  
 
==フォーム、データモジュール、フレームの翻訳==
 
==フォーム、データモジュール、フレームの翻訳==
  
プロジェクトやパッケージの国際化(i18n、internationalisationの略)オプションが選択されていれば、IDE はユニットを保存する際、自動的に各フォームにつき一つの .lrt ファイルを生成します。例えば、''unit1.pas'' を保存すると ''unit1.lrt'' ができます。ですから、最初にこのオプションを選択した後で、全てのフォームを一度は開き、少しいじって、保存してください。コンパイル時には、IDE が全ての .lrt ファイルに存在する全ての文字列を集めて国際化ディレクトリの中の単一の .po ファイルにまとめます(プロジェクト名.po ないしは パッケージ名.po)。
+
プロジェクトやパッケージの国際化(i18n、internationalisation の略)オプションが選択されていれば、IDE はユニットを保存する際、自動的に各フォームにつき一つの .lrt ファイルを生成します。例えば、''unit1.pas'' を保存すると ''unit1.lrt'' が作成されます。ですから、このオプションを選択した場合は、すべてのフォームを一度開き、少しいじって、保存しなおしてください。コンパイル時には、IDE が全 .lrt ファイルに対して存在するすべての文字列を集めて国際化ディレクトリの中の単一の .po ファイルにまとめます(プロジェクト名.po ないしは パッケージ名.po)。
  
For the forms to be actually translated at runtime, you have to assign a translator to LRSTranslator (defined in LResources) in the initialization section to one of your units
+
実際のフォームの翻訳の適用は実行時に行われますので、いずれかのユニットの initialization 節で LRSTranslator(LResources に定義されています)を当てがう必要があります。
  
<syntaxhighlight>...
+
<syntaxhighlight lang=pascal>...
 
uses
 
uses
 
   ...
 
   ...
Line 142: Line 143:
 
   LRSTranslator := TPoTranslator.Create('/path/to/the/po/file');</syntaxhighlight>
 
   LRSTranslator := TPoTranslator.Create('/path/to/the/po/file');</syntaxhighlight>
  
<s>However there's no TPoTranslator class (i.e a class that translates using .po files) available in the LCL. This is a possible implementation (partly lifted from DefaultTranslator.pas in the LCL):</s> The following code isn't needed anymore if you use recent Lazarus 0.9.29 snapshots. Simply include DefaultTranslator in Uses clause.
+
<s>しかしながら、TPoTranslator クラスは LCL で利用できるもの(出来合いのクラス)ではありません。実装して使うものです(LCL の DefaultTranslator.pas に存在してはいますが)。</s>以下のコードは Lazarus 0.9.29 以降を使っているのであれば必ずしも必要ではありません。uses 節に DefaultTranslator を追加するだけで済んでしまいます。
  
<syntaxhighlight>unit PoTranslator;
+
<syntaxhighlight lang=pascal>unit PoTranslator;
  
 
{$mode objfpc}{$H+}
 
{$mode objfpc}{$H+}
Line 201: Line 202:
 
end.</syntaxhighlight>
 
end.</syntaxhighlight>
  
Alternatively you can transform the .po file into .mo using msgfmt (isn't needed anymore if you use recent 0.9.29 snapshot) and simply use the DefaultTranslator unit
+
あるいは、以下のように DefaultTranslator ユニットを組み込むだけでも構いません。msgfmt を使って .po ファイルを .mo ファイルへ変換したものでも使えます。
  
<syntaxhighlight>...
+
<syntaxhighlight lang=pascal>...
 
uses
 
uses
 
   ...
 
   ...
 
   DefaultTranslator;</syntaxhighlight>
 
   DefaultTranslator;</syntaxhighlight>
  
which will automatically look in several standard places for a .po file (higher precedence) or .mo file <s>(the disadvantage is that you'll have to keep around both the .mo files for the DefaultTranslator unit and the .po files for TranslateUnitResourceStrings)</s>.
+
DefaultTranslator は .po(こちらが優先)または .mo ファイルを標準の場所から自動的に探し出すものです。このユニットを使用した場合、環境変数 LANG(コマンドラインスイッチ --lang で上書き指定できます)を基に自動的に翻訳ファイルの検出を試みます。探索する場所は以下の通りです(LANG は翻訳表示させたい言語、拡張子は po mo のいずれかです)。
If you use DefaultTranslator, it will try to automatically detect the language based on the LANG environment variable (overridable using the --lang command line switch), then look in these places for the translation (LANG stands for the desired language, ext can be either po or mo):
 
  
*  <Application Directory>/<LANG>/<Application Filename>.<ext>
+
*  <アプリケーションディレクトリ>/<LANG>/<アプリケーションファイル名>.<拡張子>
*  <Application Directory>/languages/<LANG>/<Application Filename>.<ext>
+
*  <アプリケーションディレクトリ>/languages/<LANG>/<アプリケーションファイル名>.<拡張子>
*  <Application Directory>/locale/<LANG>/<Application Filename>.<ext>
+
*  <アプリケーションディレクトリ>/locale/<LANG>/<アプリケーションファイル名>.<拡張子>
*  <Application Directory>/locale/LC_MESSAGES/<LANG/><Application Filename>.<ext>
+
*  <アプリケーションディレクトリ>/locale/LC_MESSAGES/<LANG/><アプリケーションファイル名>.<拡張子>
  
under unix-like systems it will also look in
+
Unix 系システムでは以下の場所も探索対象になります。
  
*  /usr/share/locale/<LANG>/LC_MESSAGES/<Application Filename>.<ext>
+
*  /usr/share/locale/<LANG>/LC_MESSAGES/<アプリケーションファイル名>.<拡張子>
  
as well as using the short part of the language (e.g. if it is "es_ES" or "es_ES.UTF-8" and it doesn't exist it will also try "es")
+
ディレクトリの LANG の部分は短縮表記もできます(例えば、環境変数 LANG が "es_ES" "es_ES.UTF-8" で該当ディレクトリが存在しない場合、"es" でも探索を試みます)。
  
 
==プログラム起動時の処理==
 
==プログラム起動時の処理==
Line 226: Line 226:
 
すべての .po ファイルについて、それぞれに TranslateUnitResourceStrings を呼ばなければなりません。LCL の po ファイルは lclstrconsts です。以下のようにメインフォームの FormCreate などから呼び出します。
 
すべての .po ファイルについて、それぞれに TranslateUnitResourceStrings を呼ばなければなりません。LCL の po ファイルは lclstrconsts です。以下のようにメインフォームの FormCreate などから呼び出します。
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
uses
 
uses
 
  ..., gettext, translations;
 
  ..., gettext, translations;
Line 238: Line 238:
 
   Translations.TranslateUnitResourceStrings('LCLStrConsts', PODirectory + 'lclstrconsts.%s.po', Lang, FallbackLang);
 
   Translations.TranslateUnitResourceStrings('LCLStrConsts', PODirectory + 'lclstrconsts.%s.po', Lang, FallbackLang);
  
   // the following dialog now shows translated buttons:
+
   // ダイアログにあるボタンが翻訳されて表示されます。
 
   MessageDlg('Title', 'Text', mtInformation, [mbOk, mbCancel, mbYes], 0);
 
   MessageDlg('Title', 'Text', mtInformation, [mbOk, mbCancel, mbYes], 0);
 
end;
 
end;
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==Compiling po files into the executable==
+
==po ファイルを実行ファイルに取り込む==
 +
 
 +
.po ファイルをインストールではなくアプリケーションの実行ファイルに取り込みたい場合、以下のようにします。
  
If you don't want to install the .po files, but put all files of the application into the executable, use the following:
+
*新しくユニットを作ります(フォームではありませんよ!)。
 +
*以下のように tools/lazres を使い、.po ファイルを .lrs ファイルへ変換します。
  
*Create a new unit (not a form!).
 
*Convert the .po file(s) to .lrs using tools/lazres:
 
 
<pre>
 
<pre>
 
./lazres unit1.lrs unit1.de.po
 
./lazres unit1.lrs unit1.de.po
 
</pre>
 
</pre>
  
This will create an include file unit1.lrs beginning with
+
これによって、以下の文で始まるファイル unit1.lrs が作成されます。
<syntaxhighlight>LazarusResources.Add('unit1.de','PO',[
+
<syntaxhighlight lang=pascal>LazarusResources.Add('unit1.de','PO',[
 
   ...</syntaxhighlight>
 
   ...</syntaxhighlight>
  
*Add the code:
+
*以下のコードを追加します。
<syntaxhighlight>uses LResources, Translations;
+
<syntaxhighlight lang=pascal>uses LResources, Translations;
  
 
resourcestring
 
resourcestring
Line 281: Line 282:
 
   {$I unit1.lrs}</syntaxhighlight>
 
   {$I unit1.lrs}</syntaxhighlight>
  
* Call TranslateUnitResourceStrings at the beginning of the program. You can do that in the initialization section if you like.
+
* プログラムの最初で TranslateUnitResourceStrings を呼び出します。initialization 節で行っても構いません。
  
==Cross-platform method to determine system language==
+
==プラットフォームに依存しない OS で使われている言語の取得方法==
  
The following function delivers a string that represents the language of the user interface. It supports Linux, Mac OS X and Windows.
+
以下の関数は、ユーザインターフェースで使われている言語名を取得するものです。Linux、Mac OS X、Windows に対応しています。
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
uses
 
uses
   Classes, SysUtils {add additional units that may be needed by your code here}
+
   Classes, SysUtils {必要なユニットを追加します}
 
   {$IFDEF win32}
 
   {$IFDEF win32}
 
   , Windows
 
   , Windows
Line 301: Line 302:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
function GetOSLanguage: string;
 
function GetOSLanguage: string;
{platform-independent method to read the language of the user interface}
+
{プラットフォームに依存しない UI で使われている言語名の読み取り}
 
var
 
var
 
   l, fbl: string;
 
   l, fbl: string;
Line 344: Line 345:
 
IDE の .po ファイルは以下の Lazarus ソースディレクトリにあります。
 
IDE の .po ファイルは以下の Lazarus ソースディレクトリにあります。
 
*lazarus/languages/ - IDE で使われている文字列
 
*lazarus/languages/ - IDE で使われている文字列
*lcl/languages/ - LCL で使われている文字列
+
*lazarus/lcl/languages/ - LCL で使われている文字列
*ideintf/languages/ - IDE インターフェースで使われている文字列
+
*lazarus/components/ideintf/languages/ - IDE インターフェースで使われている文字列
  
 
===翻訳者===
 
===翻訳者===
Line 354: Line 355:
 
新たに翻訳を始める場合は、既に誰かが取り掛かっていないかメーリングリストで尋ねてください。
 
新たに翻訳を始める場合は、既に誰かが取り掛かっていないかメーリングリストで尋ねてください。
  
また、[[Lazarus_Documentation#Translations|Translations]] をよくお読みになってください。
+
また、[[Lazarus_Documentation/ja#翻訳/国際化/地域化|翻訳/国際化/地域化]] をよくお読みになってください。
  
 
(以下訳注追記)
 
(以下訳注追記)
Line 361: Line 362:
  
 
==関連項目==
 
==関連項目==
* [[IDE_Development#Translations.2C_i18n.2C_lrt_files.2C_po_files|IDE Development: Translations, i18n, lrt, po files]]
+
* [[IDE_Development/ja#Translations.2C_i18n.2C_lrt_files.2C_po_files|IDE の開発: Translations, i18n, lrt, po files]]
* [[Getting_translation_strings_right|Getting translation strings right]]
+
* [[Getting_translation_strings_right/ja|適切な翻訳文字列の作成]]
* [[Lazarus_Documentation#Translations|Translations]]
+
* [[Lazarus_Documentation/ja#翻訳/国際化/地域化|翻訳/国際化/地域化]]
 
 
[[Category:Tutorials]]
 
[[Category:Localization]]
 

Latest revision as of 11:29, 1 March 2020

Deutsch (de) English (en) español (es) français (fr) 日本語 (ja) 한국어 (ko) polski (pl) português (pt) русский (ru) 中文(中国大陆)‎ (zh_CN)

日本語版メニュー
メインページ - Lazarus Documentation日本語版 - 翻訳ノート - 日本語障害情報

概要

このページでは、プログラムで用いる文字列を英語、中国語、ドイツ語、フィンランド語、イタリア語…といった各国語にあわせて変更することができるようにする方法を紹介します。基本的には、次のようになります。各々のキャプションに resourcestring (リソース文字列定義)を加え、コンパイルして .rst ファイルないしは .po ファイルを得ます(IDE が自動的に行います)。各国語用にそれぞれ一つの翻訳済み .po ファイルを作成し、LCL の translations ユニット内の関数を用いて、プログラムの起動時に、適切なものを読み込みます。

日付、時刻、数値の書式

Linux、BSD、Mac OS X では、時刻や日付、桁区切りなどに対して地域設定があります。右横書きに対応させるには、lpr ファイルあたりの uses 節に clocale ユニットを追加する必要があります。

リソース文字列

定義例:

resourcestring
    Caption1 = 'Some text';
    HelloWorld1 = 'Hello World';

リソース文字列は通常の文字列定数と同様に、いかなる文字列にも代入することができます。

使用例:

Label1.Caption := HelloWorld1;

コンパイル時に FPC は ユニット名.rst を各ユニットに一つ生成します。その中にはリソース文字列のデータ(名前と中身)が含まれます。

.po ファイル

生成した .po ファイルを編集するためには、数多くのグラフィカルツールが無料で提供されています。実際 .po ファイルは .rst ファイル同様単なるテキストファイルですが、作者・文字コード・言語・日付といった要素を含んだヘッダのような付随的な要素を含んでいます。FPC をインストールすれば必ず rstconv というツールがついてきます(Windows では rstconv.exe)。このツールは .rst ファイルを .po ファイルに変換します。IDE を使うと、この変換操作を自動的に行うことができます。フリーなグラフィカルツールの例としては kbabel、po-auto-translator、poedit、virtaal があります。

virtaal には翻訳メモリ機能があります。翻訳メモリとは、これまでに翻訳された文が原文と対になって集められているもので、さまざまなオープンソースのこれまでの翻訳用語を参考翻訳語として提案します。翻訳作業の軽減と翻訳語の統一に役立つでしょう。(訳注:程度の差はあれ、他のツールにも似たような機能はあります。)

直接 rstconv を用いる例:

 rstconv -i unit1.rst -o unit1.po

翻訳

それぞれの言語用に .po ファイルをコピーして翻訳する必要があります。LCL の translation ユニットは標準言語コード (en=英語, de=ドイツ語, it=イタリア語, ...) を用いて言語を検索します。例えば、unit1.po のドイツ語版は unit1.de.po となります。つまり、unit1.po ファイルを unit1.de.po、unit1.it.po などなどサポートしようと思っている言語用の名前でコピーして、そのファイルを各国語の翻訳者が編集すればいいわけです。

Light bulb  Note: ブラジル人/ポルトガル人へ:Lazarus IDE と LCL はブラジルのポルトガル語(拡張子 'pt_BR.po')だけしか用意しておりません。

.po ファイルを自動更新する IDE のオプション

  • リソース文字列を含むユニットをパッケージないしプロジェクトに加えます。
  • .po ファイルを出力するパスを指定します。これは隔離された単独のディレクトリにしてください。例えば、パッケージ/プロジェクトのディレクトリに language という名前のサブディレクトリを作ります。この指定をプロジェクトに追加する場合はプロジェクト→プロジェクトオプション、パッケージの場合はオプション→IDE 統合から行ってください。

このオプションが有効になっている場合、IDE は .rst および .lrt ファイルに含まれている情報を使用して原本となる .po ファイルを生成・更新します(別途 rstconv ツールを使う必要はありません)。これは自動更新処理として行われます。また、原本の .po ファイル、.rst と .lrt ファイルにすべての項目をまとめた後に、翻訳ファイル .xx.po に対して該当する以下の機能による更新が行われます。

使われなくなった項目の除去

.rst および .lrt で見つからなかった項目は、原本の .po ファイルから削除されます。その次に、原本の .po ファイルで見つからなかったすべての項目も、翻訳ファイル .xx.po から削除されます。こうすることで、使われなくなった項目で .po ファイルが乱されることはなくなり、これらの項目を無駄に翻訳しなくてすむようになります。

重複項目

いくつかの理由によって同じ文字列が異なったリソース文字列で使われている場合に、重複項目が生じます。例えば、ファイル lazarus/ide/lazarusidestrconst.pas に 'Gutter' という文字列があるとします。

  dlfMouseSimpleGutterSect = 'Gutter';
  dlgMouseOptNodeGutter = 'Gutter';
  dlgGutter = 'Gutter';
  dlgAddHiAttrGroupGutter = 'Gutter';

.rst ファイルを経て変換された .po ファイル上では、これらの文字列は同じように見えてしまいます。

#: lazarusidestrconsts.dlfmousesimpleguttersect
msgid "Gutter"
msgstr ""

#: lazarusidestrconsts.dlgaddhiattrgroupgutter
msgid "Gutter"
msgstr ""

・・・

"#: " で始まる行は重複を考慮したコメントになっていますが、翻訳ツールでこの項目を翻訳しようとすると、繰り返し現れる msgid "Gutter" の行が重複項目と見られ、読み込みや保存時にエラーもしくは警告を発します。関連する複数の状況で使い分けの必要があるため、.po ファイル上における重複項目は少ないながらも存在するのです。これらが区別できるよう、msgctxt キーワードが重複項目へ追加されるようになっています("#: " で始まる文の次行)。この状況(コンテキスト)を示すキーワードも含めて項目を識別するものとして使われます。上にあった例では、以下のように生成されます。

#: lazarusidestrconsts.dlfmousesimpleguttersect
msgctxt "lazarusidestrconsts.dlfmousesimpleguttersect"
msgid "Gutter"
msgstr ""

#: lazarusidestrconsts.dlgaddhiattrgroupgutter
msgctxt "lazarusidestrconsts.dlgaddhiattrgroupgutter"
msgid "Gutter"
msgstr ""

・・・

自動更新処理が行われる翻訳ファイル .xx.po に対して一つ確認してもらいたいことがあります。重複項目が既に翻訳されていた場合、新しく追加された項目がまるで自動的に翻訳されたかのように既存の翻訳を奪ってしまうことがあるのです。

重複の自動検出はまだ完全ではありません。項目が文字列リソースに追加されたのであれば、重複検出を行い、まずは未翻訳項目を洗い出さなければなりません。自動更新処理ですべての重複項目を翻訳対応させるには、更なる改良を必要としているのです。

未確定項目

リソース文字列が変更されると、翻訳されてものにも影響します。例えば、以下に示すようなリソース文字列が最初に定義されていたとします。 (訳注:以後の例は実際の Lazarus の変更履歴を基にしていますが、元の例は日本語ではあまり適切ではないので、別の例を取り上げています。)

lisKMToggleViewCallStack = 'Toggle view Call Stack';

これを基に作られる .po ファイルの該当項目は以下のようになります。

#: lazarusidestrconsts.liskmtoggleviewcallstack
msgid "View Call Stack"
msgstr ""

日本語の翻訳をすると以下のようになります。

#: lazarusidestrconsts.liskmtoggleviewcallstack
msgid "Toggle view Call Stack"
msgstr "コールスタックの表示の切り替え"

後日、このリソース文字列が以下のように変更されたとします。

lisKMToggleViewCallStack = 'View Call Stack';

この修正で .po ファイルの項目は以下のようになるでしょう。

#: lazarusidestrconsts.liskmtoggleviewcallstack
msgid "View Call Stack"
msgstr ""

lazarusidestrconsts.liskmtoggleviewcallstack を頼りに項目を識別して、原文の文字列は 'Toggle view Call Stack' から 'View Call Stack' へ変更されます。原文に対して既に翻訳が行われていると、元の訳は新しい意味に合わなくなります。先の例では、新たに 'コールスタックを表示' と訳すほうがより相応しいでしょう。自動更新処理ではこうした状況を、以下のように項目を生成して知らせるようにしています。

#: lazarusidestrconsts.liskmtoggleviewcallstack
#, fuzzy
#| msgid "Toggle view Call Stack"
msgid "View Call Stack"
msgstr "コールスタックの表示の切り替え"

.po ファイル書式の用語では、"#," で始まる行は項目のフラグ (fuzzy, 未確定) を意味していて、翻訳ツールは翻訳ユーザにそれが確認できるように作られています。このフラグは、現在の翻訳状態では不確かなものであるので翻訳者による詳細な再考が必要であることを意味しています。"#|" で始まる行は、この項目の以前の翻訳を示し、不確定フラグが付いた経緯のヒントを翻訳者に提供するものです。

フォーム、データモジュール、フレームの翻訳

プロジェクトやパッケージの国際化(i18n、internationalisation の略)オプションが選択されていれば、IDE はユニットを保存する際、自動的に各フォームにつき一つの .lrt ファイルを生成します。例えば、unit1.pas を保存すると unit1.lrt が作成されます。ですから、このオプションを選択した場合は、すべてのフォームを一度開き、少しいじって、保存しなおしてください。コンパイル時には、IDE が全 .lrt ファイルに対して存在するすべての文字列を集めて国際化ディレクトリの中の単一の .po ファイルにまとめます(プロジェクト名.po ないしは パッケージ名.po)。

実際のフォームの翻訳の適用は実行時に行われますので、いずれかのユニットの initialization 節で LRSTranslator(LResources に定義されています)を当てがう必要があります。

...
uses
  ...
  LResources;
...
...
initialization
  LRSTranslator := TPoTranslator.Create('/path/to/the/po/file');

しかしながら、TPoTranslator クラスは LCL で利用できるもの(出来合いのクラス)ではありません。実装して使うものです(LCL の DefaultTranslator.pas に存在してはいますが)。以下のコードは Lazarus 0.9.29 以降を使っているのであれば必ずしも必要ではありません。uses 節に DefaultTranslator を追加するだけで済んでしまいます。

unit PoTranslator;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, LResources, typinfo, Translations;

type

 { TPoTranslator }

 TPoTranslator=class(TAbstractTranslator)
 private
  FPOFile:TPOFile;
 public
  constructor Create(POFileName:string);
  destructor Destroy;override;
  procedure TranslateStringProperty(Sender:TObject; 
    const Instance: TPersistent; PropInfo: PPropInfo; var Content:string);override;
 end;

implementation

{ TPoTranslator }

constructor TPoTranslator.Create(POFileName: string);
begin
  inherited Create;
  FPOFile:=TPOFile.Create(POFileName);
end;

destructor TPoTranslator.Destroy;
begin
  FPOFile.Free;
  inherited Destroy;
end;

procedure TPoTranslator.TranslateStringProperty(Sender: TObject;
  const Instance: TPersistent; PropInfo: PPropInfo; var Content: string);
var
  s: String;
begin
  if not Assigned(FPOFile) then exit;
  if not Assigned(PropInfo) then exit;
{DO we really need this?}
  if Instance is TComponent then
   if csDesigning in (Instance as TComponent).ComponentState then exit;
{End DO :)}
  if (AnsiUpperCase(PropInfo^.PropType^.Name)<>'TTRANSLATESTRING') then exit;
  s:=FPOFile.Translate(Content, Content);
  if s<>'' then Content:=s;
end;

end.

あるいは、以下のように DefaultTranslator ユニットを組み込むだけでも構いません。msgfmt を使って .po ファイルを .mo ファイルへ変換したものでも使えます。

...
uses
   ...
   DefaultTranslator;

DefaultTranslator は .po(こちらが優先)または .mo ファイルを標準の場所から自動的に探し出すものです。このユニットを使用した場合、環境変数 LANG(コマンドラインスイッチ --lang で上書き指定できます)を基に自動的に翻訳ファイルの検出を試みます。探索する場所は以下の通りです(LANG は翻訳表示させたい言語、拡張子は po か mo のいずれかです)。

  • <アプリケーションディレクトリ>/<LANG>/<アプリケーションファイル名>.<拡張子>
  • <アプリケーションディレクトリ>/languages/<LANG>/<アプリケーションファイル名>.<拡張子>
  • <アプリケーションディレクトリ>/locale/<LANG>/<アプリケーションファイル名>.<拡張子>
  • <アプリケーションディレクトリ>/locale/LC_MESSAGES/<LANG/><アプリケーションファイル名>.<拡張子>

Unix 系システムでは以下の場所も探索対象になります。

  • /usr/share/locale/<LANG>/LC_MESSAGES/<アプリケーションファイル名>.<拡張子>

ディレクトリの LANG の部分は短縮表記もできます(例えば、環境変数 LANG が "es_ES" や "es_ES.UTF-8" で該当ディレクトリが存在しない場合、"es" でも探索を試みます)。

プログラム起動時の処理

すべての .po ファイルについて、それぞれに TranslateUnitResourceStrings を呼ばなければなりません。LCL の po ファイルは lclstrconsts です。以下のようにメインフォームの FormCreate などから呼び出します。

uses
 ..., gettext, translations;

procedure TForm1.FormCreate(Sender: TObject);
var
  PODirectory, Lang, FallbackLang: String;
begin
  PODirectory := '/path/to/lazarus/lcl/languages/';
  GetLanguageIDs(Lang, FallbackLang);
  Translations.TranslateUnitResourceStrings('LCLStrConsts', PODirectory + 'lclstrconsts.%s.po', Lang, FallbackLang);

  // ダイアログにあるボタンが翻訳されて表示されます。
  MessageDlg('Title', 'Text', mtInformation, [mbOk, mbCancel, mbYes], 0);
end;

po ファイルを実行ファイルに取り込む

.po ファイルをインストールではなくアプリケーションの実行ファイルに取り込みたい場合、以下のようにします。

  • 新しくユニットを作ります(フォームではありませんよ!)。
  • 以下のように tools/lazres を使い、.po ファイルを .lrs ファイルへ変換します。
./lazres unit1.lrs unit1.de.po

これによって、以下の文で始まるファイル unit1.lrs が作成されます。

LazarusResources.Add('unit1.de','PO',[
  ...
  • 以下のコードを追加します。
uses LResources, Translations;

resourcestring
  MyCaption = 'Caption';

function TranslateUnitResourceStrings: boolean;
var
  r: TLResource;
  POFile: TPOFile;
begin
  r:=LazarusResources.Find('unit1.de','PO');
  POFile:=TPOFile.Create;
  try
    POFile.ReadPOText(r.Value);
    Result:=Translations.TranslateUnitResourceStrings('unit1',POFile);
  finally
    POFile.Free;
  end;
end;

initialization
  {$I unit1.lrs}
  • プログラムの最初で TranslateUnitResourceStrings を呼び出します。initialization 節で行っても構いません。

プラットフォームに依存しない OS で使われている言語の取得方法

以下の関数は、ユーザインターフェースで使われている言語名を取得するものです。Linux、Mac OS X、Windows に対応しています。

uses
  Classes, SysUtils {必要なユニットを追加します}
  {$IFDEF win32}
  , Windows
  {$ELSE}
  , Unix
    {$IFDEF LCLCarbon}
  , MacOSAll
    {$ENDIF}
  {$ENDIF}
  ;
function GetOSLanguage: string;
{プラットフォームに依存しない UI で使われている言語名の読み取り}
var
  l, fbl: string;
  {$IFDEF LCLCarbon}
  theLocaleRef: CFLocaleRef;
  locale: CFStringRef;
  buffer: StringPtr;
  bufferSize: CFIndex;
  encoding: CFStringEncoding;
  success: boolean;
  {$ENDIF}
begin
  {$IFDEF LCLCarbon}
  theLocaleRef := CFLocaleCopyCurrent;
  locale := CFLocaleGetIdentifier(theLocaleRef);
  encoding := 0;
  bufferSize := 256;
  buffer := new(StringPtr);
  success := CFStringGetPascalString(locale, buffer, bufferSize, encoding);
  if success then
    l := string(buffer^)
  else
    l := '';
  fbl := Copy(l, 1, 2);
  dispose(buffer);
  {$ELSE}
  {$IFDEF LINUX}
  fbl := Copy(GetEnvironmentVariable('LC_CTYPE'), 1, 2);
    {$ELSE}
  GetLanguageIDs(l, fbl);
    {$ENDIF}
  {$ENDIF}
  Result := fbl;
end;

IDE の翻訳

ファイル

IDE の .po ファイルは以下の Lazarus ソースディレクトリにあります。

  • lazarus/languages/ - IDE で使われている文字列
  • lazarus/lcl/languages/ - LCL で使われている文字列
  • lazarus/components/ideintf/languages/ - IDE インターフェースで使われている文字列

翻訳者

  • ドイツ語の翻訳は Joerg Braun 氏によってメンテナンスされています。
  • フィンランド語の翻訳は Seppo Suurtarla 氏によってメンテナンスされています。
  • ロシア語の翻訳は Maxim Ganetsky 氏によってメンテナンスされています。

新たに翻訳を始める場合は、既に誰かが取り掛かっていないかメーリングリストで尋ねてください。

また、翻訳/国際化/地域化 をよくお読みになってください。

(以下訳注追記)

関連項目