Delphi 集成开发环境的中文化
西安交通大学计算机系刘明华
----Delphi从1995年推出到如今已经历了4个版本,但Inprise公司似乎从没有试图把Delphi界面进行本地化。对于国内许多Delphi用户来说,我们毕竟对中文的感觉比对异国文字要亲切得多,我们更希望自己所喜爱的Delphi换上用我们自己的文字装扮的界面。笔者通过对Delphi环境内部的探索与研究,摸索出一种汉化Delphi的极为巧妙的途径。现在,我们竟然可以在Delphi的集成开发环境中自由地切换中文和英文了!
----实现原理
----Delphi在启动时(运行Delphi32.exe),它首先创建它的主窗口,之后开始加载集成开发环境的设计时包(Design-timePackages),以便向组件板安装组件和创建属性编辑器。Delphi的包(扩展名为*.BPL)是一种特殊的动态连结库,它可以与应用程序中的其它模块可以共享全局数据。
----为Delphi提供集成开发环境的是Delphi32.exe这个程序,它是使用Delphi的类库建立的,故而它具有Delphi程序的典型特点。由于集成开发环境(Delphi32.exe)用到了许多设计时包,所以,这些包中的代码便可以访问Delphi32.exe中的全局数据;Delphi32.exe中的Application对象是一个全局对象,因此,它对设计时包中的代码是可见的。通过Delphi32.exe的Application对象,我们便可以访问程序的主窗口、菜单等许多重要的属性。
----Delphi中有一类被称为Expert或者Wizard的模块,它们的主要用途是为了更方便的创建应用程序或者构件的,Expert的代码被编译在Delphi的运行时包中。我们可以编写一个特别的Expert来实现对集成开发环境的修改。为了实现Delphi一启动就能换上中文界面,我们可以设法使Expert中的某些代码在Delphi加载包后就立即运行。
----构造Expert
----所有的Expert都继承自一个名为TIExpert的虚基类。这是一个比较简单的类,它在exptintf单元中的定义如下:
TIExpert=class(TInterface)
public
{ExpertUIstrings}
functionGetName:string;virtual;stdcall;abstract;
functionGetAuthor:string;virtual;stdcall;abstract;
functionGetComment:string;virtual;stdcall;abstract;
functionGetPage:string;virtual;stdcall;abstract;
functionGetGlyph:HICON;virtual;stdcall;abstract;
functionGetStyle:TExpertStyle;virtual;stdcall;abstract;
functionGetState:TExpertState;virtual;stdcall;abstract;
functionGetIDString:string;virtual;stdcall;abstract;
functionGetMenuText:string;virtual;stdcall;abstract;
{LaunchtheExpert}
procedureExecute;virtual;stdcall;abstract;
end;
----Expert必须实现TIExpert虚基类中所定义的纯虚函数,这些函数将被Delphi集成开发环境调用。Delphi在安装Wizard时将以如下顺序调用Expert中的方法:GetName,GetIDString,GetStyle,GetState,GetMenuText。其中GetName方法只在Expert初始化时被调用一次,其它一些方法则会被调用多次。
----本文中为了简单起见,笔者所给的例子只翻译了File,Edit,Search和View这几个菜单。你可以向例子中增添少许代码把其它的菜单也进行翻译。
----在编译并安装好该Expert后,你的Delphi便可以在中英文界面之间切换了(从Help菜单中选择"中文菜单/English")。
----Expert的单元代码(Localize.PAS)及其注释如下:
unit Localize;
//
//Chinese Localization of Delphi
//Written Jan 1999 by SimonM.LIU
//The author can be reached at:
//email:minghua_liu@263.net or simon_liu@263.net
interface
uses
ExptIntf, Windows, Messages, classes, Forms, menus, Extctrls,
ShellAPI, comctrls, controls, Dialogs, ToolIntf, SysUtils;
type
TChinese = class(TIExpert)
public
function GetStyle: TExpertStyle; override;
function GetName: string; override;
function GetAuthor: string; override;
function GetComment: string; override;
function GetPage: string; override;
function GetGlyph: HICON; override;
function GetState: TExpertState; override;
function GetIDString: string; override;
function GetMenuText: string; override;
procedure Execute; override;
end;
var
//中/英文菜单项
Citems : array[0..10]of String =
('文件', '编辑', '查找', '查看', '工程',
'运行', '组件', '数据库', '工具', '工作组', '帮助');
Items : array[0..10]of String =
('&File', '&Edit', '&Search', '&View', '&Project',
'&Run', '&Component', '&Database',
'&Tools', '&Workgroups', '&Help');
CFileItems : array[0..20]of String =
('新建...', '新建程序', '新建窗体', '新建单元', '-', '打开...',
'打开工程', '重新打开', '-', '保存', '另存为', '工程另存为',
'全部保存', '关闭', '全部关闭', '-', '引用单元', '-', '打印', '-', '退出');
CEditItems : array[0..20]of String =
('撤销', '恢复', '-', '剪贴', '拷贝', '粘贴', '删除', '全选',
'-', '与格子对齐', '放至最前', '放至最后',
'对齐...', '大小...', '比例...', '顺序...',
'创建次序...', 'Flip C&hildren', '锁住控件',
'-', '增加至Interface...');
CSearchItems : array[0..9]of String =
('查找...', '在所有文件查找...', '替换...',
'再查找', '递增查找', '-', '跳至第...行',
'查找错误...', '-', '浏览符号...');
CViewItems : array[0..17]of String =
('项目管理器', '对象观察器', '对齐样式', '浏览器', ' 代码浏览 ',' 组件列表 ',' 窗口列表... ',' 调试窗口 ',' - ',
'切换Form/Unit', '单元...', '窗体...',
'类型库', '-', '新的编辑窗口', '-', '工具条', '显示为Form');
FileItems : array[0..20]of String =
('&New...', 'New Applica&tion', 'New&Form',
'New &Unit', '-', '&Open...', 'Open Pro&ject...',
'&Reopen', '-', '&Save', 'Save &As...',
'Sav&e Project As...', 'Sa&ve All', '&Close',
'C&lose All', '-', '&Use Unit...',
'-', '&Print...', '-', 'E&xit');
EditItems : array[0..20]of String =
('&Undelete', '&Redo', '-', 'Cu&t', '&Copy', '&Paste',
'&Delete', 'Se&lect All', '-', 'Align to &Grid',
'Bring to &Front', 'Send to &Back', '&Align...',
'&Size...', 'Scal&e...', 'Tab O&rder...',
'Creatio&n Order...', 'Flip C&hildren',
'Loc&k Controls', '-', 'Add T&o Interface...');
SearchItems : array[0..9]of String = ('&Find...',
'Fin&d in Files...', '&Replace...',
'&Search Again', '&Incremental Search',
'-', '&Goto Line Number...',
'Find &Error...', '-', 'Browse S&ymbol...');
ViewItems : array[0..17]of String =
('&Project Manager', '&Object Inspector',
'&Alignment Palette', '&Browser', 'Code E&xplorer',
'&Component List', '&Window List...',
'&Debug Windows', '-', 'To&ggle Form/Unit',
'&Units...', '&Forms...', '&Type Library', '-',
'New &Edit Window', '-', 'Toolba&rs', '&View as Form');
//当前界面是否为中文
IsChinese : Bool = False;
MenuItem, SubItem : TMenuItem;
MainMenu : TMainMenu;
Form : TForm;
procedure Register;
implementation
function TChinese.GetName: string;
begin
Result := 'Chinese Delphi';
//更改Delphi的标题
Application.Title := '中文Delphi';
//更改Delphi的图标
Application.Icon.Handle := ExtractIcon(hInstance, 'Shell32.dll', 41);
//用变量Form指向Delphi程序的Application对象的主窗口
Form := Application.MainForm;
//获取主窗口的主菜单
MainMenu := (Form.FindComponent('MainMenu1')) as TMainMenu;
//如果你不想Delphi一启动就进入中文界面,则需去掉下行语句
Execute;
end;
function TChinese.GetStyle: TExpertStyle;
begin
Result := esStandard;
end;
function TChinese.GetAuthor: string;
begin
Result := 'SimonMLIU';
end;
function TChinese.GetComment: string;
begin
Result := 'Chinese Delphi interface';
end;
function TChinese.GetPage: string;
begin
Result := '';
end;
function TChinese.GetGlyph: HICON;
begin
Result := 0;
end;
function TChinese.GetState: TExpertState;
begin
Result := [esEnabled];
end;
function TChinese.GetIDString: string;
//返回用于标识该Wizard的串
begin
Result := 'SimonLiu.First Wizard';
end;
function TChinese.GetMenuText: string;
//此处返回的串将出现在Help菜单中
begin
Result := '中文界面/English';
end;
procedure TChinese.Execute;
var
i: integer;
begin
IsChinese := not IsChinese;
if isChinese
then Application.Title := '中文Delphi'
else Application.Title := 'English Delphi';
for i := 0 to MainMenu.Items.Count - 1 do
begin
MenuItem := MainMenu.Items[i];
if IsChinese then MenuItem.Caption := CItems[i]
else MenuItem.Caption := Items[i];
end;
//File菜单的中/英文转换
MenuItem := MainMenu.Items[0];
for i := 0 to MenuItem.Count - 1 do
begin
SubItem := MenuItem.Items[i];
if IsChinese then SubItem.Caption := CFileItems[i]
else SubItem.Caption := FileItems[i];
end;
//Edit菜单的中/英文转换
MenuItem := MainMenu.Items[1];
for i := 0 to MenuItem.Count - 1 do
begin
SubItem := MenuItem.Items[i];
if IsChinese then SubItem.Caption := CEditItems[i]
else SubItem.Caption := EditItems[i];
end;
//Search菜单的中/英文转换
MenuItem := MainMenu.Items[2];
for i := 0 to MenuItem.Count - 1 do
begin
SubItem := MenuItem.Items[i];
if IsChinese then SubItem.Caption := CSearchItems[i]
else SubItem.Caption := SearchItems[i];
end;
//View菜单的中/英文转换
MenuItem := MainMenu.Items[3];
for i := 0 to MenuItem.Count - 1 do
begin
SubItem := MenuItem.Items[i];
SubItem := MenuItem.Items[i];
if IsChinese then SubItem.Caption := CViewItems[i]
else SubItem.Caption := ViewItems[i];
end;
//以下两行使Delphi在改变菜单后自动调整好各项菜单项的大小。
ShowWindow(Form.Handle, SW_MAXIMIZE);
ShowWindow(Form.Handle, SW_RESTORE);
if IsChinese
then
Application.MessageBox('Delphi中文版','Delphi', MB_ICONINFORMATION)
else
Application.MessageBox('Chinese Delphi!','Delphi', MB_ICONINFORMATION);
end;
procedure Register;
begin
RegisterLibraryExpert(TChinese.Create);
end;
end.
----安装Expert:①选择菜单Componet|InstallComponent;②把Localize.pas单元安装到一个新的Package中。
----卸载Expert:选择菜单Componet|InstallPackages,卸载你不想使用的包。
----Delphi的版本
----以上所说的Delphi均指Inprise公司1998年秋季推出的Delphi4.0。由于各种Delphi版本所提供的菜单不尽相同,所以把上述代码移植到Delphi2.0、3.0等版本时,需要对菜单项的数目和菜单文字作一些相应的调整。
----用大致相同的方法笔者编写了一个可以在多种语言之间进行切换的Delphi"插件"(如图所示)。不同的是它不再是建立在TIExpert的基础上的了。鉴于篇幅原因,在此就不详细介绍它的实现过程了,笔者准备将它放到http://delphians.yeah.net站点上。如果读者有兴趣更多地了解这方面知识,可以通过电子邮件与我联系(simon_liu@263.net)。
----通讯地址:西安交通大学9649#
----邮政编码:710049
----电子邮件:minghua_liu@263.net
-中国计算机世界出版服务公司版权所有