LCL Unicode Support/ja

From Lazarus wiki
Jump to navigationJump to search

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

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

イントロダクション

Lazarusは開発においてUnicode標準をもっとサポートする必要があります。ほとんどの場合、Windows環境においてです。 ここに、Lazarusでユニコードサポートをもっときちんとやりたい人のために、いくつかの基本的な情報を示します。このページは積極的に修正、拡張、変更していってください。

すでにユニコード標準や、DelphiでのWideStringの経験がある人にとって、Unicodeをサポートするプログラムを書く際に、このページの情報は助けになるでしょう。 以前の非ラテン言語(西方の)での利用方法や、多くの種類のキャラクタセットにとっても、また、助けになるでしょう。

注意:細かい実装については、いま議論の最中ですので、この文書の内容は変わる可能性があります。

実装のガイドライン

要求事項

Lazarusの精神は、"Write once, Compile everywhere."です。 これは、理想的には、ユニコードを使うアプリケーションでは、ターゲットにむけた条件定義などがなく、1つのユニコードをサポートするソースコードで、すべてのターゲットのプログラムを生成できる、ということです。

LCLの"interface"の部分はターゲットプラットホームがユニコードをサポートするよう、ターゲットプラットホームのためのユニコードサポートを実装するべきです。そして、同時に、アプリケーションプログラマからは、プラットホームに依存している実装を隠蔽しなくてはなりません。

Lazarusに関して言えることは、アプリケーションコードとLCLの境界における内部的な文字列の通信は、LCLとWidgetsetsと同様に、古典的な(バイト並びの)stringで成り立っている、ということです。 論理的には、それらの保持には、UTF-8を使ってエンコードされているべきです。

Unicodeへの移行

LazarusではAnsiエンコーディングが、もっともよく利用されています。なぜなら、今日のGtk1とWin32のインターフェースでは、それがデフォルトでだからです。近い将来、すべてのwidgetsetはUTF-8をサポートするようになり、全てのアプリケーションはutf-8でかかれ、オブジェクトインスペクタはutf-8で動作し、utf-8に変換された文字列をインターフェースに直接渡せるようになるでしょう。

Gtk 2やQt,WinCE(将来的にはWin32U)などのように、人々が完全に動かないウイジェットセット向けのソフトウエアを開発するとき、彼らはGtkやwin32のようなもっと安定したウイジェットセットでコンパイルされたIDEを使います。 iso文字列をutf-8のためのウジェットセットに渡すような、こういった矛盾を解決するためには、ターゲットウイジェットと同じエンコーディング上で動作するIDEを使うことが必要です。これはつまり、私達はUnicodeに移行するために安定したUTF-8のIDEを必要としています。

現在、私達はエンコーディングに関して、いくつかのウイジェットセットのグループをもっています。

  • ANSIエンコーディングのインターフェース: win32 , gtk (1)
  • UTF-8エンコーディングのインターフェース: gtk (1), gtk2, qt, fpGUI
  • 現在はANSIエンコーディングだが、将来的にはUTF-8への移行が必要なインターフェース: win32, wince


gtk 1 は、ANSIとUTF-8の両方のグループであることに注意してください。理由は、Gtk1では、環境変数でそれらを決めることができるからです。 最新のLazarusでは、Win32,WinCE,gtk向けにコンパイルされた既存のソフトウエアは良く動きます。しかし、他のwidgetsetでは、エンコーディングの問題に直面します。

そして、UTF-8を使う新しいソフトウエアでは、Unicodeグループのウイジェットセットを使ってコンパイルされたものに限って動くでしょう。

重要な点は、ターゲットと同じグループでコンパイルされているIDEを使うということです。なぜなら、IDEはウイジェットセットのエンコーディングを使ってコンパイルされているからです。そして、それはターゲット向けのエンコーディングをおこなうLFMやLRSファイルを生成することができません。

ロードマップ

今、ロードマップを作成して、実行に移す時です。私達は、ガイドラインをもっています。 次のような実現可能な計画をたてました。2つのグループに仕事を分ける計画です。 1つ目は、優先的に主要な柱となる仕事を、2番目はそれ以外の仕事を計画しています。

私達が、Lazarusはユニコードが使えるよ、といえる前に、すべての主要な仕事は完全に実装されていなくてはなりません。そして、そのことが、私達の努力の最も向かう方向です。

2番目の仕事は、あったらいいな、というものです。しかし、誰かがそれらのために奉仕をしない限り、実装されることはないでしょう。

優先的に主要な仕事

Win32 Widgetset に UTF-8をサポートさせる

ノート:このステップでは、私達はすべての32ビットWindowsのバージョンを同時にターゲットとしています。この努力でつくられるすべてのコードは、この作業によって発生するバグを避けられるよう、現在のwin32インターフェースとIFDEFによって分離されるでしょう。 移行する時期になれば、IFDEFはユニコードだけが残るように除去されます。

どのようにWin9xのユニコードをサポートするかの詳細は、まだ討論中です。

状態:まだ実装されていない


Gtk 2 キーボード関数をUTF-8で動くように更新する

ノート:

状態:まだ実装されていない


Lazarus IDE が正しくWin32 ウイジェットセットで動いてUTF-8をサポートするようにする

ノート:

状態:まだ実装されていない


Lazarus IDE が正しくGtk2 ウイジェットセットで動いてUTF-8をサポートするようにする

ノート:

状態:まだ実装されていない


2番目の(その他の)仕事

Windows CE ウイジェットセットをUTF-8を使うように更新する


ノート:文字列の変換ルーチンは winceproc.ppに集約されています。多くのテストが必要です。

状態:まだ実装されていない


Gtk 1 キーボード関数をUTF-8で動くように更新する

Notes:

状態:まだ実装されていない

ユニコードの要点

Unicode standard maps integers from 0 to 10FFFF(h) to characters. Each such mapping is called a code point. In other words, Unicode characters are in principle defined for code points from U+000000 to U+10FFFF (0 to 1 114 111).

There are three schemes for representing Unicode code points as unique byte sequences. These schemes are called Unicode transformation formats: UTF-8, UTF-16 and UTF-32. The conversions between all of them are possible. Here are their basic properties:

                           UTF-8 UTF-16 UTF-32
Smallest code point [hex] 000000 000000 000000
Largest code point  [hex] 10FFFF 10FFFF 10FFFF
Code unit size [bits]          8     16     32
Minimal bytes/character        1      2      4
Maximal bytes/character        4      4      4

UTF-8 has several important and useful properties: It is interpreted as a sequence of bytes, so that the concept of lo- and hi-order byte does not exist. Unicode characters U+0000 to U+007F (ASCII) are encoded simply as bytes 00h to 7Fh (ASCII compatibility). This means that files and strings which contain only 7-bit ASCII characters have the same encoding under both ASCII and UTF-8. All characters >U+007F are encoded as a sequence of several bytes, each of which has the two most significant bits set. No byte sequence of one character is contained within a longer byte sequence of another character. This allows easy search for substrings. The first byte of a multibyte sequence that represents a non-ASCII character is always in the range C0h to FDh and it indicates how many bytes follow for this character. All further bytes in a multibyte sequence are in the range 80h to BFh. This allows easy resynchronization and robustness.

UTF-16 has the following most important properties: It uses a single 16-bit word to encode characters from U+0000 to U+d7ff, and a pair of 16-bit words to encode any of the remaining Unicode characters.

Finally, any Unicode character can be represented as a single 32-bit unit in UTF-32.

For more, see: Unicode FAQ - Basic questions, Unicode FAQ - UTF-8, UTF-16, UTF-32 & BOM, Wikipedia: UTF-8 [1]

Lazarusコンポーネントライブラリのアーキテクチャの要点

LCL(Lazarusコンポーネントライブラリ)は2つの部分からできています。

  1. A target platform independent part, which implements a class hierarchy analogous to Delphi VCL;
  2. "Interfaces" - a part that implements the interface to APIs of each target platform.

The communication between the two parts is done by an abstract class TWidgetset. Each widgetset is implemented by its own class derived from TWidgetset.

The GTK 1 widgetset is the oldest. In this widgetset the string encoding is determined by the LANG environment variable, which is usually a iso The ISO-8859-n group of single byte encodings. Recently (as of Mandriva 2007, for example), many distributions have being shipping Gtk 1 configured for UTF-8. Our Gtk 1 interface lacks proper support for UTF-8 on the keyboard handling routines, so this is a big problem, that increases the need for Lazarus to implement cross-platform Unicode support.

Gtk2 widgetset only works with UTF-8 encoding, but the keyboard code of the interface is still based on the old gtk 1 code, so it does not support UTF-8 completely.

The win32 interface is setup with ansi widgets, so it is currently not possible to use Unicode with win32.

Qt interface is prepared for UTF-8. Qt itself uses UCS-2 as native encoding, but the lazarus interface for Qt converts from UTF-8 to UCS-2.

Windows CE only support UCS-2 as character encoding, but our interface for it currently converts strings from ISO to UCS-2 before calling the Windows API. This is very easy to fix, as all conversion code is concentrated on a few routines on the winceproc.pp file.

For more, see: Internals of the LCL

win32インターフェースでUnicodeを有効にする

方針

First, and most importantly, all Unicode patches for the Win32 interface must be enclosed by IFDEF WindowsUnicodeSupport, to avoid breaking the existing ANSI interface. After this stabilizes, all ifdefs will be removed and only the Unicode part will remain. At this moment all existing programs that use ANSI characters will need migration to Unicode.

Windows platforms <=Win9x are based on ISO code page standards and only partially support Unicode. Windows platforms starting with WinNT and Windows CE fully support Unicode. Win 9x and NT offer two parallel sets of API functions: the old ANSI enabled *A and the new, Unicode enabled *W. *W functions accept wide strings, i.e. UTF-16 encoded strings, as parameters. Windows CE only uses Wide API functions.

Windows 9xに存在するワイド文字列関数

いくつかのWide系API関数はWindows9xにも存在します。ここに、そのような関数のリストを示します。: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/mslu/winprog/other_existing_unicode_support.asp

変換例:

  GetTextExtentPoint32(hdcNewBitmap, LPSTR(ButtonCaption),
Length(ButtonCaption), TextSize);

これは、次のようにします。

var
  WideCaption: WideString;

  ....

  {$ifdef WindowsUnicodeSupport}
    WideCaption := Utf8Decode(ButtonCaption);
    GetTextExtentPoint32W(hdcNewBitmap, PWideChar(WideCaption), Length(WideCaption), TextSize);
  {$else}
    GetTextExtentPoint32(hdcNewBitmap, LPSTR(ButtonCaption), Length(ButtonCaption), TextSize);
  {$endif}
end;

AnsiとWideのバージョンが必要な関数

最初の変換例:

function TGDIWindow.GetTitle: String;
var
 l: Integer;
begin
   l := Windows.GetWindowTextLength(Handle);
   SetLength(Result, l);
   Windows.GetWindowText(Handle, @Result[1], l);
end;

これは、次のようにします。

function TGDIWindow.GetTitle: String;
var
 l: Integer;
 AnsiBuffer: string;
 WideBuffer: WideString;
begin

{$ifdef WindowsUnicodeSupport}

 if UnicodeEnabledOS then
 begin
   l := Windows.GetWindowTextLengthW(Handle);
   SetLength(WideBuffer, l);
   l := Windows.GetWindowTextW(Handle, @WideBuffer[1], l);
   SetLength(WideBuffer, l);
   Result := Utf8Encode(WideBuffer);
 end
 else
 begin
   l := Windows.GetWindowTextLength(Handle);
   SetLength(AnsiBuffer, l);
   l := Windows.GetWindowText(Handle, @AnsiBuffer[1], l);
   SetLength(AnsiBuffer, l);
   Result := AnsiToUtf8(AnsiBuffer);
 end;

{$else}

   l := Windows.GetWindowTextLength(Handle);
   SetLength(Result, l);
   Windows.GetWindowText(Handle, @Result[1], l);

{$endif}

end;

ロードマップ

下記は、チェックすべきユニットのリストです。

  • "win32callback.inc"
  • "win32def.pp"
  • "win32int.pp"
  • "win32lclintf.inc"
  • "win32lclintfh.inc"
  • "win32listsl.inc"
  • "win32listslh.inc"
  • "win32memostrings.inc"
  • "win32object.inc"
  • "win32proc.pp"
  • "win32winapi.inc"
  • "win32winapih.inc"
  • "win32wsactnlist.pp"
  • "win32wsarrow.pp"
  • "win32wsbuttons.pp"
  • "win32wscalendar.pp"
  • "win32wschecklst.pp"
  • "win32wsclistbox.pp"
  • "win32wscomctrls.pp"
  • "win32wscontrols.pp"
  • "win32wscustomlistview.inc"
  • "win32wsdbctrls.pp"
  • "win32wsdbgrids.pp"
  • "win32wsdialogs.pp"
  • "win32wsdirsel.pp"
  • "win32wseditbtn.pp"
  • "win32wsextctrls.pp"
  • "win32wsextdlgs.pp"
  • "win32wsfilectrl.pp"
  • "win32wsforms.pp"
  • "win32wsgrids.pp"
  • "win32wsimglist.pp"
  • "win32wsmaskedit.pp"
  • "win32wsmenus.pp"
  • "win32wspairsplitter.pp"
  • "win32wsspin.pp"
  • "win32wsstdctrls.pp"
  • "win32wstoolwin.pp"
  • "winext.pas"