LCL Unicode Support/zh CN
│
Deutsch (de) │
English (en) │
español (es) │
français (fr) │
日本語 (ja) │
한국어 (ko) │
русский (ru) │
中文(中国大陆) (zh_CN) │
中文(台灣) (zh_TW) │
介绍
Lazarus对Unicode的支援还需要进一步开发,尤其是在Windows平台上。以下提供一些基本的资讯,让想要加强Lazarus对Unicode支援的人参考,如果您发现这些资讯有误、不足或过时了,请您不吝修正、补充或更新它,谢谢。
如果您已经初步了解Unicode的标准,且您已经在Delphi上面有使用过WideString这个型别来撰写程式,会有助于您理解Lazarus对Unicode支援的加强工作。如果您使用过非Latin编码的字元集来撰写脚本语言,也会有些帮助的。
请注意: 实作的细节部分目前还在讨论中,这部分的文件随时都有可能更新。
本文初版由User:Dennies翻译正体中文页面转换而来。 '元件'一词英文为:component,简体界面中译为'组件'。
程式实作规范
需求
Lazarus的精神是”一次编写,到处'编译'” (JAVA的精神则是‘一次编写,到处‘执行’)。根据Lazarus的精神,表示在理想状态下,一个支援Unicode的应用程式,应该只有一份能够支援Unicode的程式码,而不用为各种不同的语系作不同的原始码,或者资源档。更不用在程式码里面使用条件定义(IFDEF)为不同的作业系统/不同语系作编译的定义。
在LCL的 “interface”宣告部分,已经可以支援各种相容于Unicode的作业系统,让程式人员可以不用去管每个系统上面对Unicode要怎么处理的繁琐细节。
而Lazarus本身需要注意的,则是在Lazarus内部用来沟通的字串 (例如应用程式跟LCL,以及 LCL跟视窗元件之间),都是透过Pascal的原始string (string里的每个字元都是1个Byte,而Unicode是多个Byte的字元集)。因此,逻辑上来说,Lazarus的程式码就必须以UTF-8编码来储存,才能保留住所有Unicode的相关资讯。
和Unicode进行整合
目前绝大多数版本的Lazarus使用的是Ansi编码,因为这是Gtk1预设的编码法,也是Win32目前的预设编码法,Windows 2000以后的Windows作业系统虽然都已经能够相容于Unicode,但预设的编码法仍然是Ansi,这个情形在不久的未来恐怕会有所改变,所有的视窗元件都会支援UTF-8,而所有的应用程式在传递资料给介面时,也都需要先转换成 UTF-8了,当然,这得依赖各种IDE的作者在元件检视器里面更改程式码才能作到。
当我们在还没完全支援Unicode的视窗元件上面开发程式的时候(例如 Gtk 2, Qt, WinCE, 或许也包含将会出现的Win32U),我们是使用IDE来对比较稳定的视窗元件进行编译的 (例如Gtk跟Win32)。为了保持一致性(例如以ISO字元编码把资料传递给UTF-8的视窗元件),让IDE跟视窗元件使用一致的编码是必要的,这也就表示在能够制作出Unicode的应用程式前,我们将会需要一个稳定的UTF-8的IDE程式。
目前我们有几组不同的视觉元件,分别使用以下的编码法:
- 使用ANSI编码法: win32跟 gtk (1) 介面
- 使用 UTF-8 编码法: gtk (1), gtk2, qt, fpGUI, carbin
- 目前还使用ANSI编码,但需要升级到UTF-8编码: win32, wince
请留意,gtk 1同时属于ANSI跟UTF-8的阵营喔,这是因为gtk 1的编码法,是可以从Gtk 1的环境变数里面加以控制的。
正如目前的Lazarus一样,大多数的应用程式目前都能正常运作,如果用win32, wince或gtk介面重新编译,就得面对要编译其他视窗元件时,使用不同编码的窘境了。而支援UTF-8的应用程式在重新编译给使用Unicode的视窗元件时,就没有这个问题。
很重要的一点是,当您要编译程式时,请记得使用跟您要编译的程式相同编码法的IDE来作。这是因为IDE在进行程式编译的时候,IDE是用它被编译时的编码法来产生LFM跟LRS档案的,而不是我们想要什么编码法,它就能自动切换过去的,这点非常重要,不可不察。
发展路线
目前我们已经有了准则,所以该建立发展路线,并加以实现的时候了。 为此,我们建立了以下的计划,我们的计划是把工作分为两个群组,一个是主要工作,另一个是次要工作。
所有的主要工作都必须在我们宣布Lazarus支援之前完成,这些工作会被当成我们工作中的主要确认部分。
次要工作则是该作,但没有自愿者想作,或者为这些工作定出范围之前不会进行的。
主要工作
使 Win32 视窗元件支援 UTF-8
备注: 在这个步骤中,我们会将所有的32 bits Windows作业系统同时当成目标,这阶段中所有写出来的程式码都会在目前的win32介面中用IFDEF来区隔,以避免在主要的介面中产生问题。在过渡时期结束之后,IFDEF的宣告就会全部移除,只留下Unicode的支援。
状态: 部分已完成。
更新 Gtk 2 的键盘程式码,使得UTF-8能够被支援
备注:
状态: 几乎已完成。部分gtk2预先定义的功能,让使用者自订的部分还没有完成,但我不知道哪几个语系会使用者这些功能。
让Lazarus IDE能正确的跟Win32 Unicode视窗元件运作并支援UTF-8
备注:
状态: 已完成。除了字元对应表,目前字元对应表仍旧只显示255个字元,但反正目前所有的OS都已经提供了很好的Unicode字元对应表,所以这应该也不是那么重要了。
让Lazarus IDE能正确的跟Gtk 2视窗元件运作并支援UTF-8
备注:
状态: 已完成。还有些gtk2介面的问题,但这已经跟UTF-8无关了
次要工作
升级Windows CE的视窗元件,使它能使用UTF-8
备注: 字串转换的程式码已经集中在winceproc.pp这个档案里面,还需要许多测试。
状态: 尚未开始
升级Gtk 1键盘功能,让它能使用UTF-8
备注:
状态: 尚未开始
完成synedit对由右到左(RTL)的文字显示的支援
备注: RTL是指由右到左的输入法,例如阿拉伯文。
状态: 尚未开始
Unicode 须知
Unicode的标准是将整数的0到10FFFF(十六进位)对应为文字。每一个对应关系,称为一个个的编码点(code point)。换句话说,Unicode的字元原则上是定义了U+000000到U+10FFFF个编码点(用十进位来算,是 0到1,114,111)。
要表现Unicode的编码点的位元顺序,一共有三种方法。这些方法被称为Unicode转换格式(Unicode transformation formats)分别是: UTF-8, UTF-16和UTF-32。这三种格式之间是可以相互转换的,以下是这些格式的基本说明:
(原文)
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 UTF-16 UTF-32 最小编码点 [十六进位] 000000 000000 000000 最大编码点 [十六进位] 10FFFF 10FFFF 10FFFF 单位编码Size [bits] 8 16 32 占用位元组量(最少) 1 2 4 占用位元组量(最多) 4 4 4
UTF-8 包含几个重要且有用的属性:它是以Byte的顺序进行解译的,所以没有Hi-Byte跟Lo-Byte的差别(其它双位元组的多国语系字元编码都有这样的问题)。 Unicode对字元的定义中,从U+0000到U+007F (ASCII)正好就是直接对应到00h到7Fh,可以跟ASCII直接相容。这意味着使用7-bit ASCII字元的档案或字串,在传递ASCII跟UTF-8的时候,是完全相同的编码方式。而编码点大于U+007F的字元则是依照位元组的顺序进行编码,正好每两个Byte就能代表一个Unicode的字元。因此不会出现一个字元的Byte使用或涵盖到别的字元的资料,也使得制作子字串的搜寻功能简单多了。代表非ASCII字元的位元组中,第一个Byte的内容一定必须在C0h到FDh之间,并且说明这个Unicode字元是使用了几个Bytes来记录的。所有在第一个Byte之后的资料,都一定落在80h到BFh之间,这样的规则也使得自动化与重新修复文件的程序变得更简单。
UTF-16则包含了以下重要的属性: 它只使用16 bit的Word对从U+0000到U+d7ff这些字元进行编码,而其余的Unicode字元编码,则会使用成对的16-bit Words。
最后,任何一个Unicode字元都可以用32-bit为单位的资料来表现,就称为UTF-32.
如果您需要更多的资料,请参阅: Unicode FAQ - Basic questions, Unicode FAQ - UTF-8, UTF-16, UTF-32 & BOM, Wikipedia: UTF-8 [1]
Lazarus 元件库架构须知
LCL包含了两个部分:
- 跟编译目标作业平台无关的部分,这部分是使用跟Delphi VCL相似的类别架构来实现的。
- "Interfaces" – 使用各编译目标作业平台相关的API来实现的。
介于两个部分之间的沟通,则是透过TWidgetset这个抽象类别来达成的,每个Widgetset的实现都是从TWidgetset这个父类别衍生而来的。
GTK 1的视觉元件是最旧的版本。在该版本的视觉元件当中,字元的编码是以”LANG”这个环境变数来决定的,通常是” ISO-8859-n”这一类的单位元字串编码。近几年内建GTK 1的系统,已经开始把预设字元编码设定为UTF-8了,例如2007年的Mandriva就是一例。在Lazarus的Gtk 1介面中,还少了支援UTF-8的键盘控制功能,这是个大问题,如果不解决的话,Lazarus将无法真正支援跨平台Unicode相容的目标。
Gtk2的视觉元件只能使用UTF-8编码,并且完全支援UTF-8的各项要求。
Win32介面在预设时,使用的是ANSI编码的视觉元件,目前已经开始进行修改,让它能够支援UTF-8,但因为还没完成,所以预设是不使用UTF-8的,也因此目前在Win32介面的视觉元件上,暂时还无法使用Unicode。
Qt介面已经完成了支援UTF-8的准备,在Qt介面中,原生的字元编码是使用UTF-16,但Lazarus的Qt介面会把UTF-8转换为UTF-16,所以在支援上没有问题。
Windows CE只支援UTF-16的字元编码,但Lazarus的Windows CE介面则是在呼叫Windows API之前,先把ISO字元转换为UTF-16编码,所以这部分还算容易修改,就像目前我们把所有的字元转换函式集中放在winceproc.pp里面一样。
如果您需要更多资讯,请参考: LCL内部资讯
让win32介面相容于Unicode
编译能使用Unicode的LCL-Win32函式库
要使Windows版的LCL函式库能使用Unicode,您得先到Lazarus的选单中"Tools" --> "Configure Build Lazarus"进行设定。
请在"Options"的栏位中加上” –dWindowsUnicodeSupport”这个设定值,并把所有的建置对象都选为NONE,只留下LCL的设定选项是Clean+Build,然后再设定win32为要建置的视觉元件(widgetset),按下”Build”按键,即可将LCL重新编译为与Unicode相容的版本了。
完成后,您就可以把您已完成的应用程式重新编译,编译完成后,它们也都能够支援Unicode了。
准则
首先,也是最重要的,所有为Win32介面进行的增补工作,都必须被包在 IFDEF WindowsUnicodeSupport这个编译条件式里面,以避免破坏了现有的ANSI介面,等到Unicode相容修正的专案稳定之后,这些IFDEF的编译条件式就会一起被拿掉,而只留下Unicode相容的程式码。在目前这个时间点上,所有现存使用ANSI标准编码的程式,都还得由程式设计人员将之升级,才能与Unicode相容。
Windows平台 <= Win9x只支援ISO系列的字元编码标准,并只有部分功能支援Unicode。Windows系列的平台,是从Windows NT跟Windows CE开始完全支援Unicode的(也同时还支援ISO系列编码,算是双轨并行),Win9x跟NT的API里面,每一个功能都同时提供了两个函式,一个是ANSI编码的(函式名称结尾都会加个A),另一个则是Unicode相容的(函式名称结尾则是会加个W)。
- W的函式中如果需要传递字串参数,接受的字串必须是WideString,例如UTF-16字串,而Windows CE只使用 *W的API。
在Windows 9x上面,Unicode系列函式的呈现
有些Unicode系列的API也会呈现在Windows 9x平台上,以下就是这些Unicode系列API的列表: 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);
要改为:
{$ifdef WindowsUnicodeSupport} GetTextExtentPoint32W(hdcNewBitmap, PWideChar(Utf8Decode(ButtonCaption)), Length(WideCaption), TextSize); {$else} GetTextExtentPoint32(hdcNewBitmap, LPSTR(ButtonCaption), Length(ButtonCaption), TextSize); {$endif}
需要转换ANSI跟Unicode版本的函式
第一个简单的转换范例:
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;
Roadmap 未来发展计划
在相容于Unicode的延伸计划中,什么是必须要作的:
- TForm, TButton, TLabel
- 大多数的控制项
- 选单元件
- LCLIntf.ExtTextOut 以及大多数和字串相关的WinAPI
- 以TStrings为基础的控制项. 例如: TComboBox, TListBox等等
- SynEdit 显示与输入UTF-8字元必须正确
要支援Unicode的话,目前已知的问题:
- SynEdit不支援由右到左显示的字元
- 在编辑器上面双击非ANSI编码的字元时,被双击的字不会被选取,反而是被双击的字左方的其他字会被选取起来
- 复制贴上Unicode字元的时候,如果当时的视窗环境不是使用Unicode为编码字元的话,复制贴上的动作会不正确
- MessageBox上面的按键文字就算已经翻译完成,也无法正确显示Unicode字元。这已经在IDE上面测试过了,不过也可能单纯的就只是IDE的问题而已。
- 在Project option设定应用程式Title的时候,如果设定为Unicode的字串,显示可能不正确。
在重新检视程式码之后,下列的问题需要进行测试,因为这些程式码似乎无法相容于Unicode:
- 在PrepareCreateWindow (Win32WSControls这个单元档里面) 的这行程式:
StrCaption := PChar(AWinControl.Caption);
- (还有一些问题是没有被确认的,如果经过确认的话,就会一道列在上述的清单里面)
需要检查的Unit档的清单:
- "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"- Felipe"win32wseditbtn.pp"- Felipe"win32wsextctrls.pp"- Felipe"win32wsextdlgs.pp"- Felipe"win32wsfilectrl.pp"- Felipe"win32wsforms.pp"- Felipe"win32wsgrids.pp"- Felipe"win32wsimglist.pp"- Felipe"win32wsmaskedit.pp"- Felipe"win32wsmenus.pp"- Felipe"win32wspairsplitter.pp"- Felipe"win32wsspin.pp"- Felipe"win32wsstdctrls.pp"- Felipe"win32wstoolwin.pp"- Felipe"winext.pas"- Felipe
荧幕截图
额外参考
- UTF-8 - Description of UTF-8 strings