Sign in Join
Wiki copytemporary

Translations / i18n / localizations for programs/ja: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11## 概要
22
33このページでは、プログラムで用いる文字列を英語、中国語、ドイツ語、フィンランド語、イタリア語…といった各国語にあわせて変更することができるようにする方法を紹介します。基本的には、次のようになります。各々のキャプションに *resourcestring* (リソース文字列定義)を加え、コンパイルして .rst ファイルないしは .po ファイルを得ます(IDE が自動的に行います)。各国語用にそれぞれ一つの翻訳済み .po ファイルを作成し、LCL の *translations* ユニット内の関数を用いて、プログラムの起動時に、適切なものを読み込みます。
44
55## 日付、時刻、数値の書式
66
77Linux、BSD、Mac OS X では、時刻や日付、桁区切りなどに対して地域設定があります。右横書きに対応させるには、lpr ファイルあたりの uses 節に clocale ユニットを追加する必要があります。
88
99## リソース文字列
1010
1111定義例:
1212
1313``` pascal
1414resourcestring
1515 Caption1 = 'Some text';
1616 HelloWorld1 = 'Hello World';
1717```
1818
1919リソース文字列は通常の文字列定数と同様に、いかなる文字列にも代入することができます。
2020
2121使用例:
2222
2323``` pascal
2424Label1.Caption := HelloWorld1;
2525```
2626
2727コンパイル時に FPC は **ユニット名.rst** を各ユニットに一つ生成します。その中にはリソース文字列のデータ(名前と中身)が含まれます。
2828
2929## .po ファイル
3030
3131生成した .po ファイルを編集するためには、数多くのグラフィカルツールが無料で提供されています。実際 .po ファイルは .rst ファイル同様単なるテキストファイルですが、作者・文字コード・言語・日付といった要素を含んだヘッダのような付随的な要素を含んでいます。FPC をインストールすれば必ず **rstconv** というツールがついてきます(Windows では rstconv.exe)。このツールは .rst ファイルを .po ファイルに変換します。IDE を使うと、この変換操作を自動的に行うことができます。フリーなグラフィカルツールの例としては kbabel、po-auto-translator、poedit、virtaal があります。
3232
3333virtaal には翻訳メモリ機能があります。翻訳メモリとは、これまでに翻訳された文が原文と対になって集められているもので、さまざまなオープンソースのこれまでの翻訳用語を参考翻訳語として提案します。翻訳作業の軽減と翻訳語の統一に役立つでしょう。(訳注:程度の差はあれ、他のツールにも似たような機能はあります。)
3434
3535直接 rstconv を用いる例:
3636
37-` rstconv -i unit1.rst -o unit1.po`
37+```text
38+ rstconv -i unit1.rst -o unit1.po
39+```
3840
3941## 翻訳
4042
4143それぞれの言語用に .po ファイルをコピーして翻訳する必要があります。LCL の translation ユニットは標準言語コード (en=英語, de=ドイツ語, it=イタリア語, ...) を用いて言語を検索します。例えば、unit1.po のドイツ語版は unit1.de.po となります。つまり、unit1.po ファイルを unit1.de.po、unit1.it.po などなどサポートしようと思っている言語用の名前でコピーして、そのファイルを各国語の翻訳者が編集すればいいわけです。
4244
4345> **Note:** ブラジル人/ポルトガル人へ:Lazarus IDE と LCL はブラジルのポルトガル語(拡張子 'pt_BR.po')だけしか用意しておりません。
4446
4547## .po ファイルを自動更新する IDE のオプション
4648
4749- リソース文字列を含むユニットをパッケージないしプロジェクトに加えます。
4850- .po ファイルを出力するパスを指定します。これは隔離された単独のディレクトリにしてください。例えば、パッケージ/プロジェクトのディレクトリに language という名前のサブディレクトリを作ります。この指定をプロジェクトに追加する場合はプロジェクト→プロジェクトオプション、パッケージの場合はオプション→IDE 統合から行ってください。
4951
5052このオプションが有効になっている場合、IDE は .rst および .lrt ファイルに含まれている情報を使用して原本となる .po ファイルを生成・更新します(別途 rstconv ツールを使う必要はありません)。これは自動更新処理として行われます。また、原本の .po ファイル、.rst と .lrt ファイルにすべての項目をまとめた後に、翻訳ファイル .xx.po に対して該当する以下の機能による更新が行われます。
5153
5254### 使われなくなった項目の除去
5355
5456.rst および .lrt で見つからなかった項目は、原本の .po ファイルから削除されます。その次に、原本の .po ファイルで見つからなかったすべての項目も、翻訳ファイル .xx.po から削除されます。こうすることで、使われなくなった項目で .po ファイルが乱されることはなくなり、これらの項目を無駄に翻訳しなくてすむようになります。
5557
5658### 重複項目
5759
5860いくつかの理由によって同じ文字列が異なったリソース文字列で使われている場合に、重複項目が生じます。例えば、ファイル lazarus/ide/lazarusidestrconst.pas に 'Gutter' という文字列があるとします。
5961
6062``` pascal
6163 dlfMouseSimpleGutterSect = 'Gutter';
6264 dlgMouseOptNodeGutter = 'Gutter';
6365 dlgGutter = 'Gutter';
6466 dlgAddHiAttrGroupGutter = 'Gutter';
6567```
6668
6769.rst ファイルを経て変換された .po ファイル上では、これらの文字列は同じように見えてしまいます。
6870
69-`#: lazarusidestrconsts.dlfmousesimpleguttersect`\
70-`msgid "Gutter"`\
71-`msgstr ""`\
71+```text
72+#: lazarusidestrconsts.dlfmousesimpleguttersect
73+msgid "Gutter"
74+msgstr ""
7275
73-`#: lazarusidestrconsts.dlgaddhiattrgroupgutter`\
74-`msgid "Gutter"`\
75-`msgstr ""`\
76+#: lazarusidestrconsts.dlgaddhiattrgroupgutter
77+msgid "Gutter"
78+msgstr ""
7679
77-`・・・`
80+・・・
81+```
7882
7983"#: " で始まる行は重複を考慮したコメントになっていますが、翻訳ツールでこの項目を翻訳しようとすると、繰り返し現れる msgid "Gutter" の行が重複項目と見られ、読み込みや保存時にエラーもしくは警告を発します。関連する複数の状況で使い分けの必要があるため、.po ファイル上における重複項目は少ないながらも存在するのです。これらが区別できるよう、msgctxt キーワードが重複項目へ追加されるようになっています("#: " で始まる文の次行)。この状況(コンテキスト)を示すキーワードも含めて項目を識別するものとして使われます。上にあった例では、以下のように生成されます。
8084
81-`#: lazarusidestrconsts.dlfmousesimpleguttersect`\
82-`msgctxt "lazarusidestrconsts.dlfmousesimpleguttersect"`\
83-`msgid "Gutter"`\
84-`msgstr ""`\
85+```text
86+#: lazarusidestrconsts.dlfmousesimpleguttersect
87+msgctxt "lazarusidestrconsts.dlfmousesimpleguttersect"
88+msgid "Gutter"
89+msgstr ""
8590
86-`#: lazarusidestrconsts.dlgaddhiattrgroupgutter`\
87-`msgctxt "lazarusidestrconsts.dlgaddhiattrgroupgutter"`\
88-`msgid "Gutter"`\
89-`msgstr ""`\
91+#: lazarusidestrconsts.dlgaddhiattrgroupgutter
92+msgctxt "lazarusidestrconsts.dlgaddhiattrgroupgutter"
93+msgid "Gutter"
94+msgstr ""
9095
91-`・・・`
96+・・・
97+```
9298
9399自動更新処理が行われる翻訳ファイル .xx.po に対して一つ確認してもらいたいことがあります。重複項目が既に翻訳されていた場合、新しく追加された項目がまるで自動的に翻訳されたかのように既存の翻訳を奪ってしまうことがあるのです。
94100
95101重複の自動検出はまだ完全ではありません。項目が文字列リソースに追加されたのであれば、重複検出を行い、まずは未翻訳項目を洗い出さなければなりません。自動更新処理ですべての重複項目を翻訳対応させるには、更なる改良を必要としているのです。
96102
97103### 未確定項目
98104
99105リソース文字列が変更されると、翻訳されてものにも影響します。例えば、以下に示すようなリソース文字列が最初に定義されていたとします。 (訳注:以後の例は実際の Lazarus の変更履歴を基にしていますが、元の例は日本語ではあまり適切ではないので、別の例を取り上げています。)
100106
101107``` pascal
102108lisKMToggleViewCallStack = 'Toggle view Call Stack';
103109```
104110
105111これを基に作られる .po ファイルの該当項目は以下のようになります。
106112
107-`#: lazarusidestrconsts.liskmtoggleviewcallstack`\
108-`msgid "View Call Stack"`\
109-`msgstr ""`
113+```text
114+#: lazarusidestrconsts.liskmtoggleviewcallstack
115+msgid "View Call Stack"
116+msgstr ""
117+```
110118
111119日本語の翻訳をすると以下のようになります。
112120
113-`#: lazarusidestrconsts.liskmtoggleviewcallstack`\
114-`msgid "Toggle view Call Stack"`\
115-`msgstr "コールスタックの表示の切り替え"`
121+```text
122+#: lazarusidestrconsts.liskmtoggleviewcallstack
123+msgid "Toggle view Call Stack"
124+msgstr "コールスタックの表示の切り替え"
125+```
116126
117127後日、このリソース文字列が以下のように変更されたとします。
118128
119129``` pascal
120130lisKMToggleViewCallStack = 'View Call Stack';
121131```
122132
123133この修正で .po ファイルの項目は以下のようになるでしょう。
124134
125-`#: lazarusidestrconsts.liskmtoggleviewcallstack`\
126-`msgid "View Call Stack"`\
127-`msgstr ""`
135+```text
136+#: lazarusidestrconsts.liskmtoggleviewcallstack
137+msgid "View Call Stack"
138+msgstr ""
139+```
128140
129141lazarusidestrconsts.liskmtoggleviewcallstack を頼りに項目を識別して、原文の文字列は 'Toggle view Call Stack' から 'View Call Stack' へ変更されます。原文に対して既に翻訳が行われていると、元の訳は新しい意味に合わなくなります。先の例では、新たに 'コールスタックを表示' と訳すほうがより相応しいでしょう。自動更新処理ではこうした状況を、以下のように項目を生成して知らせるようにしています。
130142
131-`#: lazarusidestrconsts.liskmtoggleviewcallstack`\
132-`#, fuzzy`\
133-`#| msgid "Toggle view Call Stack"`\
134-`msgid "View Call Stack"`\
135-`msgstr "コールスタックの表示の切り替え"`
143+```text
144+#: lazarusidestrconsts.liskmtoggleviewcallstack
145+#, fuzzy
146+#| msgid "Toggle view Call Stack"
147+msgid "View Call Stack"
148+msgstr "コールスタックの表示の切り替え"
149+```
136150
137151.po ファイル書式の用語では、"#," で始まる行は項目のフラグ (fuzzy, 未確定) を意味していて、翻訳ツールは翻訳ユーザにそれが確認できるように作られています。このフラグは、現在の翻訳状態では不確かなものであるので翻訳者による詳細な再考が必要であることを意味しています。"#\|" で始まる行は、この項目の以前の翻訳を示し、不確定フラグが付いた経緯のヒントを翻訳者に提供するものです。
138152
139153## フォーム、データモジュール、フレームの翻訳
140154
141155プロジェクトやパッケージの国際化(i18n、internationalisation の略)オプションが選択されていれば、IDE はユニットを保存する際、自動的に各フォームにつき一つの .lrt ファイルを生成します。例えば、*unit1.pas* を保存すると *unit1.lrt* が作成されます。ですから、このオプションを選択した場合は、すべてのフォームを一度開き、少しいじって、保存しなおしてください。コンパイル時には、IDE が全 .lrt ファイルに対して存在するすべての文字列を集めて国際化ディレクトリの中の単一の .po ファイルにまとめます(プロジェクト名.po ないしは パッケージ名.po)。
142156
143157実際のフォームの翻訳の適用は実行時に行われますので、いずれかのユニットの initialization 節で LRSTranslator(LResources に定義されています)を当てがう必要があります。
144158
145159``` pascal
146160...
147161uses
148162 ...
149163 LResources;
150164...
151165...
152166initialization
153167 LRSTranslator := TPoTranslator.Create('/path/to/the/po/file');
154168```
155169
156170しかしながら、TPoTranslator クラスは LCL で利用できるもの(出来合いのクラス)ではありません。実装して使うものです(LCL の DefaultTranslator.pas に存在してはいますが)。以下のコードは Lazarus 0.9.29 以降を使っているのであれば必ずしも必要ではありません。uses 節に DefaultTranslator を追加するだけで済んでしまいます。
157171
158172``` pascal
159173unit PoTranslator;
160174
161175{$mode objfpc}{$H+}
162176
163177interface
164178
165179uses
166180 Classes, SysUtils, LResources, typinfo, Translations;
167181
168182type
169183
170184 { TPoTranslator }
171185
172186 TPoTranslator=class(TAbstractTranslator)
173187 private
174188 FPOFile:TPOFile;
175189 public
176190 constructor Create(POFileName:string);
177191 destructor Destroy;override;
178192 procedure TranslateStringProperty(Sender:TObject;
179193 const Instance: TPersistent; PropInfo: PPropInfo; var Content:string);override;
180194 end;
181195
182196implementation
183197
184198{ TPoTranslator }
185199
186200constructor TPoTranslator.Create(POFileName: string);
187201begin
188202 inherited Create;
189203 FPOFile:=TPOFile.Create(POFileName);
190204end;
191205
192206destructor TPoTranslator.Destroy;
193207begin
194208 FPOFile.Free;
195209 inherited Destroy;
196210end;
197211
198212procedure TPoTranslator.TranslateStringProperty(Sender: TObject;
199213 const Instance: TPersistent; PropInfo: PPropInfo; var Content: string);
200214var
201215 s: String;
202216begin
203217 if not Assigned(FPOFile) then exit;
204218 if not Assigned(PropInfo) then exit;
205219{DO we really need this?}
206220 if Instance is TComponent then
207221 if csDesigning in (Instance as TComponent).ComponentState then exit;
208222{End DO :)}
209223 if (AnsiUpperCase(PropInfo^.PropType^.Name)<>'TTRANSLATESTRING') then exit;
210224 s:=FPOFile.Translate(Content, Content);
211225 if s<>'' then Content:=s;
212226end;
213227
214228end.
215229```
216230
217231あるいは、以下のように DefaultTranslator ユニットを組み込むだけでも構いません。msgfmt を使って .po ファイルを .mo ファイルへ変換したものでも使えます。
218232
219233``` pascal
220234...
221235uses
222236 ...
223237 DefaultTranslator;
224238```
225239
226240DefaultTranslator は .po(こちらが優先)または .mo ファイルを標準の場所から自動的に探し出すものです。このユニットを使用した場合、環境変数 LANG(コマンドラインスイッチ --lang で上書き指定できます)を基に自動的に翻訳ファイルの検出を試みます。探索する場所は以下の通りです(LANG は翻訳表示させたい言語、拡張子は po か mo のいずれかです)。
227241
228242- \<アプリケーションディレクトリ\>/\<LANG\>/\<アプリケーションファイル名\>.\<拡張子\>
229243- \<アプリケーションディレクトリ\>/languages/\<LANG\>/\<アプリケーションファイル名\>.\<拡張子\>
230244- \<アプリケーションディレクトリ\>/locale/\<LANG\>/\<アプリケーションファイル名\>.\<拡張子\>
231245- \<アプリケーションディレクトリ\>/locale/LC_MESSAGES/\<LANG/\>\<アプリケーションファイル名\>.\<拡張子\>
232246
233247Unix 系システムでは以下の場所も探索対象になります。
234248
235249- /usr/share/locale/\<LANG\>/LC_MESSAGES/\<アプリケーションファイル名\>.\<拡張子\>
236250
237251ディレクトリの LANG の部分は短縮表記もできます(例えば、環境変数 LANG が "es_ES" や "es_ES.UTF-8" で該当ディレクトリが存在しない場合、"es" でも探索を試みます)。
238252
239253## プログラム起動時の処理
240254
241255すべての .po ファイルについて、それぞれに TranslateUnitResourceStrings を呼ばなければなりません。LCL の po ファイルは lclstrconsts です。以下のようにメインフォームの FormCreate などから呼び出します。
242256
243257``` pascal
244258uses
245259 ..., gettext, translations;
246260
247261procedure TForm1.FormCreate(Sender: TObject);
248262var
249263 PODirectory, Lang, FallbackLang: String;
250264begin
251265 PODirectory := '/path/to/lazarus/lcl/languages/';
252266 GetLanguageIDs(Lang, FallbackLang);
253267 Translations.TranslateUnitResourceStrings('LCLStrConsts', PODirectory + 'lclstrconsts.%s.po', Lang, FallbackLang);
254268
255269 // ダイアログにあるボタンが翻訳されて表示されます。
256270 MessageDlg('Title', 'Text', mtInformation, [mbOk, mbCancel, mbYes], 0);
257271end;
258272```
259273
260274## po ファイルを実行ファイルに取り込む
261275
262276.po ファイルをインストールではなくアプリケーションの実行ファイルに取り込みたい場合、以下のようにします。
263277
264278- 新しくユニットを作ります(フォームではありませんよ!)。
265279- 以下のように tools/lazres を使い、.po ファイルを .lrs ファイルへ変換します。
266280
267281 ./lazres unit1.lrs unit1.de.po
268282
269283これによって、以下の文で始まるファイル unit1.lrs が作成されます。
270284
271285``` pascal
272286LazarusResources.Add('unit1.de','PO',[
273287 ...
274288```
275289
276290- 以下のコードを追加します。
277291
278292``` pascal
279293uses LResources, Translations;
280294
281295resourcestring
282296 MyCaption = 'Caption';
283297
284298function TranslateUnitResourceStrings: boolean;
285299var
286300 r: TLResource;
287301 POFile: TPOFile;
288302begin
289303 r:=LazarusResources.Find('unit1.de','PO');
290304 POFile:=TPOFile.Create;
291305 try
292306 POFile.ReadPOText(r.Value);
293307 Result:=Translations.TranslateUnitResourceStrings('unit1',POFile);
294308 finally
295309 POFile.Free;
296310 end;
297311end;
298312
299313initialization
300314 {$I unit1.lrs}
301315```
302316
303317- プログラムの最初で TranslateUnitResourceStrings を呼び出します。initialization 節で行っても構いません。
304318
305319## プラットフォームに依存しない OS で使われている言語の取得方法
306320
307321以下の関数は、ユーザインターフェースで使われている言語名を取得するものです。Linux、Mac OS X、Windows に対応しています。
308322
309323``` pascal
310324uses
311325 Classes, SysUtils {必要なユニットを追加します}
312326 {$IFDEF win32}
313327 , Windows
314328 {$ELSE}
315329 , Unix
316330 {$IFDEF LCLCarbon}
317331 , MacOSAll
318332 {$ENDIF}
319333 {$ENDIF}
320334 ;
321335```
322336
323337``` pascal
324338function GetOSLanguage: string;
325339{プラットフォームに依存しない UI で使われている言語名の読み取り}
326340var
327341 l, fbl: string;
328342 {$IFDEF LCLCarbon}
329343 theLocaleRef: CFLocaleRef;
330344 locale: CFStringRef;
331345 buffer: StringPtr;
332346 bufferSize: CFIndex;
333347 encoding: CFStringEncoding;
334348 success: boolean;
335349 {$ENDIF}
336350begin
337351 {$IFDEF LCLCarbon}
338352 theLocaleRef := CFLocaleCopyCurrent;
339353 locale := CFLocaleGetIdentifier(theLocaleRef);
340354 encoding := 0;
341355 bufferSize := 256;
342356 buffer := new(StringPtr);
343357 success := CFStringGetPascalString(locale, buffer, bufferSize, encoding);
344358 if success then
345359 l := string(buffer^)
346360 else
347361 l := '';
348362 fbl := Copy(l, 1, 2);
349363 dispose(buffer);
350364 {$ELSE}
351365 {$IFDEF LINUX}
352366 fbl := Copy(GetEnvironmentVariable('LC_CTYPE'), 1, 2);
353367 {$ELSE}
354368 GetLanguageIDs(l, fbl);
355369 {$ENDIF}
356370 {$ENDIF}
357371 Result := fbl;
358372end;
359373```
360374
361375## IDE の翻訳
362376
363377### ファイル
364378
365379IDE の .po ファイルは以下の Lazarus ソースディレクトリにあります。
366380
367381- lazarus/languages/ - IDE で使われている文字列
368382- lazarus/lcl/languages/ - LCL で使われている文字列
369383- lazarus/components/ideintf/languages/ - IDE インターフェースで使われている文字列
370384
371385### 翻訳者
372386
373387- ドイツ語の翻訳は Joerg Braun 氏によってメンテナンスされています。
374388- フィンランド語の翻訳は Seppo Suurtarla 氏によってメンテナンスされています。
375389- ロシア語の翻訳は Maxim Ganetsky 氏によってメンテナンスされています。
376390
377391新たに翻訳を始める場合は、既に誰かが取り掛かっていないかメーリングリストで尋ねてください。
378392
379393また、[[Lazarus Documentation/ja|翻訳/国際化/地域化]] をよくお読みになってください。
380394
381395(以下訳注追記)
382396
383397- [FreeML](http://www.freeml.com/info/lazarus@freeml.com) - Lazarus/FreePascal 日本語メーリングリスト
384398- [[Japanese Localization Notes|翻訳ノート(日本語)]] - 日本語の翻訳ノート
385399
386400## 関連項目
387401
388402- [[IDE Development/ja|IDE の開発: Translations, i18n, lrt, po files]]
389403- [[Getting translation strings right/ja|適切な翻訳文字列の作成]]
390404- [[Lazarus Documentation/ja|翻訳/国際化/地域化]]
391405
392406---
393407*From the Free Pascal wiki, page "Translations / i18n / localizations for programs/ja", as it stood on 2020-03-01 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history