关于DELPHI程序多语言支持的问题.doc_第1页
关于DELPHI程序多语言支持的问题.doc_第2页
关于DELPHI程序多语言支持的问题.doc_第3页
关于DELPHI程序多语言支持的问题.doc_第4页
关于DELPHI程序多语言支持的问题.doc_第5页
已阅读5页,还剩6页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

-仅供学习参考-关于DELPHI程序多语言支持的问题写DELPHI程序,是如何实现繁体化的?是如何开发英文版的?是通过外挂语言包吗?我完整地说一下我的问题:我写一个DELPHI程序,开发环境是是简体中文版本win xp系统+ Delphi 7的。现在想做一个繁体版本以及其他非简体中文版本的出来。此时遇到这几个问题:1、在非简体中文系统中均出现乱码或界面文字错位。2、而且语言包速度太慢了,每次启动要预读一下语言文件进行界面翻译,工程量大的时候明显感到启动速度下降了3、因为工程量比较大,逐一设置“提示内容”及“界面内容”的语言包比较麻烦,所以不想用ini文件或dll资源库的语言包形式请问各位DELPHI高手你们是怎么做的?有没有一劳永逸的方法?听说DELPHI内置的多国语言功能, 有没有用法帮助?还有没有其他一些好用简单强大的Unicode语言包控件?-Delphi的多语言是这么用的,但是添加多语言后编译连接速度很慢,有时候10来分钟。可以把你的Delphi的窗体文件分给翻译来翻译,如果是Delphi7,需要先用Conver.exe来转换为文本格式。1、Project-New Application 创建你的中文版软件。2、Project-Language-Add 添加你的语言,比如美国英语(ENU)。或者File-New-Others-Dll Wizard3、保存后生成多个文件夹。4、Project-Build All5、程序目录下生成和工程文件同名的语言文件:MyExe.ENU;MyExe.CHN,软件发布需要带这些文件。6、把软件里面所有字符串定义为资源字符串。resourcestringC_AppTitle = xx管理系统;C_Error = 错误;C_Warning = 警告;7、在软件中用如下代码切换语言:const/定义你得多语言:ENGLISH = (SUBLANG_ENGLISH_US shl 10) or LANG_ENGLISH;CHINESE = (SUBLANG_CHINESE_SIMPLIFIED shl 10) or LANG_CHINESE;usesReInit; .if LoadNewResourceModule(ENGLISH) 0 thenbeginReInitializeForms();end;更多请参考Delphi帮助,里面写得更清楚。我以前也用INI文件做多语言,感觉挺好用,Delphi带得这个多语言感觉编译起来太慢,而且总需要Build半天。利用INI文件实现界面无闪烁多语言切换程序运行时,我们查找当前目录下所有的语言配置文件(*.ini),为了达到这个目的,我编写了如下的函数搜索目录下所有的语言配置文件的文件名,然后将文件名去掉ini扩展名保存返回: function TForm1.SearchLanguagePack:TStrings; var ResultStrings:TStrings; DosError:integer; SearchRec:TsearchRec; begin ResultStrings:=TStringList.Create; DosError:=FindFirst(ExtractFilePath(ParamStr(0)+*.ini, faAnyFile, SearchRec); while DosError=0 do begin 返回的文件名并去掉末尾的.ini字符 ResultStrings.Add(ChangeFileExt(SearchRec.Name,); DosError:=FindNext(SearchRec); end; FindClose(SearchRec); Result:=ResultStrings; end; 在Form建立的事件中添加代码,将目录下所有的语言文件名加入选择列表框中。 procedure TForm1.FormCreate(Sender: TObject); begin ComboBox1.Items.AddStrings(SearchLanguagePack); end; 程序的重点在如何切换语言,在ComboBox1的OnChange事件中进行切换操作。 这里我写了SetActiveLanguage过程用于实现这一操作。 procedure TForm1.ComboBox1Change(Sender: TObject); begin SetActiveLanguage(ComboBox1.Text); end; 其中SetActiveLanguage代码如下: procedure TForm1.SetActiveLanguage(LanguageName:string); const Translations=Translations; Messages=Messages; var frmComponent:TComponent; i:Integer; begin with TInifile.Create(ExtractFilePath(ParamStr(0)+LanguageName+.ini) do begin for i:=0 to ComponentCount-1 do 遍历Form组件 begin frmComponent:=Componentsi; if frmComponent is TLabel then 如果组件为TLabel型则当作TLabel处理,以下同 begin (frmComponent as TLabel).Caption:= ReadString(Translations,frmComponent.Name +.Caption,(frmComponent as TLabel).Caption); end; if frmComponent is TCheckBox then begin (frmComponent as TCheckBox).Caption:= ReadString(Translations,frmComponent.Name +.Caption,(frmComponent as TCheckBox).Caption); end; if frmComponent is TButton then begin (frmComponent as TButton).Caption:= ReadString(Translations,frmComponent.Name +.Caption,(frmComponent as TButton).Caption); (frmComponent as TButton).Hint:= ReadString(Translations,frmComponent.Name +.Hint,(frmComponent as TButton).Hint); end; if frmComponent is TMenuItem then begin (frmComponent as TMenuItem).Caption:= ReadString(Translations,frmComponent.Name +.Caption,(frmComponent as TMenuItem).Caption); end; end; M1:=ReadString(Messages,M1,M1); end; end; 在这个过程中,我们遍历了Form中的所有组件,根据他们的类别和组件名动态的从ini配置文件中读出应该显示的语言文字。 用遍历组件的方法比一个一个写出具体的组件维护起来要方便很多,代码的适应性也更强。 其中M1为一个字符串变量,这样提示消息也能切换,比如在Button1的Click事件中 procedure TForm1.Button1Click(Sender: TObject); begin ShowMessage(M1); end; 就可以根据不同的语言给出不同的提示文字。 好了,整个工程就做完了,你可以运行测试一下,是不是切换迅速而且无闪烁。Delphi实现多语言界面关键字:多语言界面,Delphi,国际化,本地化。 随着Internet在全球的普及,一个软件开发者,开发出来的产品可以随意发布到全球各个角落,然而与此同时,开发出来的产品也面临着一个新的问题:如 何实现各种不同的语言界面,甚至根据最终用户的操作系统的语言版本,自动更改语言界面?难道为每一个不同的语言编写一个不同的版本?不,完全没有必要。 Delphi 5.0作为一个优秀的快速RAD开发工具,可以很容易地实现国际化支持,因为Delphi 5.0内置了对多语言界面的支持。 一个程序,如果需要不同的语言版本,那么应该有一下几点需要注意的地方:1. 必须允许你的程序代码能够处理好各种语言字符串,例如如果要中文化,必须能够处理双字节。2. 你必须设计好你的程序界面,以便能够使你的程序界面元素有足够的空间显示语言文字信息。一般说来,在50个字节以内的英文单词所表达的意思,用其他的语言 来描述的话,长度要超过50字节,但中文是一个例外。特别对于几个字节的英文单词,其他的语言的长度几乎百分之百要超过英文的长度!因此,必须在控件中留 出足够的长度以便在更改语言之后,还能显示全部的语言文字信息。3. 你必须翻译所有的资源。本文将着重讨论如何用Delphi 5.0实现多语言的支持和切换,界面设计和上述要求不在本文讨论范围之内。要 为程序添加语言支持,只要在Delphi主菜单项Project下面选择LanguagesAdd即可。点击之后出现语言向导,读者按照向导进行操作 即可。向导结束之后,会生成一个工程组文件(BPG),最后出现Translation Manager,软件开发者可以在这里翻译所有语言的所有资源,包括字体、位置、文字等等。说明一下:你可以随时随地用Project下面的 Languages子菜单的功能来添加、删除、修改各种界面元素。做完上述工作之后,我们现在就差切换语言的代码了。为了切换语言,大家 可以使用下面的一个单元,单元中提供了两个函数,用来更换语言界面元素,其中LoadNewResourceModule是用来修改文字信息等 等,ReinitializeForms用来重新刷新窗体和控件以保证同步。/文件名:MaltiLan.pasunit MaltiLan;interfaceuses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms;procedure ReinitializeForms;function LoadNewResourceModule(Locale: LCID): Longint;implementationtype TAsInheritedReader = class(TReader) Public procedure ReadPrefix(var Flags: TFilerFlags; var AChildPos: Integer); Override; end;procedure TAsInheritedReader.ReadPrefix(var Flags: TFilerFlags; var AChildPos: Integer);begin inherited ReadPrefix(Flags, AChildPos); Include(Flags, ffInherited);end;function SetResourceHInstance(NewInstance: Longint): Longint;var CurModule: PLibModule;begin CurModule := LibModuleList; Result := 0; while CurModule nil do begin if CurModule.Instance = HInstance then begin if CurModule.ResInstance CurModule.Instance then FreeLibrary(CurModule.ResInstance); CurModule.ResInstance := NewInstance; Result := NewInstance; Exit; end; CurModule := CurModule.Next; end;end;function LoadNewResourceModule(Locale: LCID): Longint;var FileName: array0.260 of char; P: PChar; LocaleName: array0.4 of Char; NewInst: Longint;begin GetModuleFileName(HInstance, FileName, SizeOf(FileName); GetLocaleInfo(Locale, LOCALE_SABBREVLANGNAME, LocaleName, SizeOf(LocaleName); P := PChar(FileName) + lstrlen(FileName); while (P .) and (P FileName) do Dec(P); NewInst := 0; Result := 0; if P FileName then begin Inc(P); if LocaleName0 #0 then begin / Then look for a potential language/country translation lstrcpy(P, LocaleName); NewInst := LoadLibraryEx(FileName, 0, LOAD_LIBRARY_AS_DATAFILE); if NewInst = 0 then begin / Finally look for a language only translation LocaleName2 := #0; lstrcpy(P, LocaleName); NewInst := LoadLibraryEx(FileName, 0, LOAD_LIBRARY_AS_DATAFILE); end; end; end; if NewInst 0 then Result := SetResourceHInstance(NewInst)end;function InternalReloadComponentRes(const ResName: string; HInst: THandle; var Instance: TComponent): Boolean;var HRsrc: THandle; ResStream: TResourceStream; AsInheritedReader: TAsInheritedReader;begin avoid possible EResNotFound exception if HInst = 0 then HInst := HInstance; HRsrc := FindResource(HInst, PChar(ResName), RT_RCDATA); Result := HRsrc 0; if not Result then Exit; ResStream := TResourceStream.Create(HInst, ResName, RT_RCDATA); try AsInheritedReader := TAsInheritedReader.Create(ResStream, 4096); try Instance := AsInheritedReader.ReadRootComponent(Instance); finally AsInheritedReader.Free; end; finally ResStream.Free; end; Result := True;end;function ReloadInheritedComponent(Instance: TComponent; RootAncestor: TClass): Boolean; function InitComponent(ClassType: TClass): Boolean; begin Result := False; if (ClassType = TComponent) or (ClassType = RootAncestor) then Exit; Result := InitComponent(ClassType.ClassParent); Result := InternalReloadComponentRes(ClassType.ClassName, FindResourceHInstance( FindClassHInstance(ClassType), Instance) or Result; end;begin Result := InitComponent(Instance.ClassType);end;procedure ReinitializeForms;var Count: Integer; I: Integer; Form: TForm;begin Count := Screen.FormCount; for I := 0 to Count - 1 do begin Form := Screen.FormsI; ReloadInheritedComponent(Form, TForm); end;end;end.测试程序窗体单元文件如下:/单元文件名:unit1.pasunit Unit1;interfaceuses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Menus, MLanTool, ExtCtrls, StdCtrls;type TForm1 = class(TForm) MainMenu1: TMainMenu; File1: TMenuItem; Exit1: TMenuItem; Language1: TMenuItem; Chese1: TMenuItem; English1: TMenuItem; Button1: TButton; Memo1: TMemo; ListBox1: TListBox; GroupBox1: TGroupBox; Panel1: TPanel; procedure Exit1Click(Sender: TObject); procedure Chese1Click(Sender: TObject); procedure English1Click(Sender: TObject); Private Private declarations Public Public declarations end;var Form1: TForm1;implementation$R *.DFMconst ENGLISH = (SUBLANG_ENGLISH_US shl 10) or LANG_ENGLISH; CHINESE = (SUBLANG_CHINESE_SIMPLIFIED shl 10) or LANG_CHINESE;procedure TForm1.Exit1Click(Sender: TObject);begin Close;end;procedure TForm1.Chese1Click(Sender: TObject);begin if LoadNewResourceModule(CHINESE) 0 then ReinitializeForms;end;procedure TForm1.English1Click(Sender: TObject);begin if LoadNewResourceModule(ENGLISH) 0 then ReinitializeForms;end;end.如果要自动切换语言,只要在FormCreate事件中添加如下代码即可: if LoadNewResourceModule(SysLocale.DefaultLCID) 0 then ReinitializeForms;说明一点:在程序完成的时候,你应该用Luanguages子菜单的Update Resources DLL功能更新所有的窗体和代码,然后用Build All Project编译所有的文件,这样才能保证你的程序正常运行。所有的源代码可以到下载。后 记:其实用INI文件也可以实现多语言界面的切换,好处是可以方便大家随时添加不同的语言文件,但是,对于一个大型的程序来说,用INI是不现实的。用 INI实现语言界面的程序,大家可以到下载源代 码和测试程序。干净搞定delphi多语言-兼论设计模式随着全球化程度加深,软件越来越像蒲公英,到处飘散、扎根。这其中要解决的是不同语言的显示问题。我们当然希望一套程序,可以不修改代码就可以支持不同的语言,不要去维护很多的版本。 首先要谈到的一个问题是乱码问题,因为delphi win32到11.x版还是不支持unicode,所以一般使用Ansi码,有这样几种情况会显示乱码:使用的语言文字与系统当前设定的语言不一样;比如简体版QQ在繁体操作系统(或简体操作系统的区域设置中“非Unicode程序的语言”设定为繁体)就是乱码。即使改变Font.Charset,某些元件仍然会出现乱码,如StatusBar。因此,在越南文版的windows显示越南文,在伊朗文版的windows显示伊朗文,不要在越南文版windows显示伊朗文,在伊朗文版windows显示越南文,这样就能确保没有乱码问题。好在一般这样的错位用法也不多见。系统没有安装你要显示的语言的语言包; 如果你要保证完全无乱码,必须考虑使用unicode码,使用成套的支持unicode的元件,如tnt,但它在UI变现上比较单一,你不可能不使用别的元件。 言归正传,首先,看看哪些地方的字串需要实现多语言,并来看看各种实现方法的优劣。 1、界面上的元件,如TButton的Caption; 2、主动弹出的消息,如ShowMessage(Are you sure?),Raise Exception.Create(Error!); 3、例外错误举发的报告信息,如f/0引起的exception; 4、第3方元件包内部的上述字串; 实现多语言的方法很多,列举一二: 1、delphi自带的Resource生成工具 此工具把专案的dfm文件里的所有字串以及pas中定义为ResourceString的字串列举出来,按不同的语言编译成不同的Resource,专案编译前先选语言,每种语言编译成一个exe(此处有误, exe中是Base Language 的资源, 每种语言编译成一个资源Dll, 文件名跟程序同名, 后缀不是Dll, 而是locale的代码, 如enu, eng, 前两个表示语言, 第三个表示国家)。这个工具使用很不方便,不是一个完整的解决方案,跟Borland的Midas的demo一样(TClientDataSet通过ProviderName连接到RemoteDatamodule的TDataSetProvider,实际开发Erp系统时,谁会放100个TDataSetProvider连接到100个TDataSet?),只是一个原理尚通的示范。首先,由于dfm本身也是资源文件的一部分,因此每次修改都要“Update Resource DLLs.”,如修改Button1为Button2,如果你忘了,运行时就会报“找不到资源Button1的错误”(这个好像并没有什么麻烦的);提供的字典编辑画面中,除了字串,还有Left/Top等资料(这个确实不方便,东西太多了);字典不能重用,在一个模组翻译了,在第2个模组还要再翻译相同的词。其次,每种语言一个exe/bpl,如果你的系统是Package切割,bpl也是每种语言一个,还要小心别把不同语言的bpl组合在了一起,到时候一个画面显示中文,一个显示德文(有一个可能是乱码)就惨了。 再次,在作bpl组装的系统时,第3方元件如果没有提供多语言的方案,你就需要修改第3方元件,但一般我们不这样干,因为第3方元件会随时更新,难道每次人家更新你也再更新人家。因此,一般都没有人使用Delphi本身提供的这个方案(除了作demo)。 2、Resource dll方式 用单独的ResourceDll,用LoadResString等函数获得翻译字串,但你要到处写这个函数来一一替换,特别是Form上的字串,噢,会累死人。字典可以重用。 3、网上讨论很多的ini文件方式 此方法是写个替换的引擎,在运行时从ini文件读取语言字串来替换画面元件的显示文字。这个方法比第一种进步很多,不需要每种语言编译一个exe了,只要提供不同的ini文件就好;画面修改时如果ini没有同步更新也不会出现致命错误,最多就是某个文字没有转换;引擎也提供了字串转换函数,因此也可以处理主动弹出的消息。这个方法在文件格式上有三种不同的实现: (1)、编号=字串 每个字串从1开始编号,1,2,3,4.,很麻烦,代码要修改,当然运行时切换语言没问题。 (2)、元件.属性=字串 这种实现把元件instance一一对应,用RTTI来判断属性,替换很精确,也可以运行时切换语言。不足之处是,略显呆板,多个元件相同的字串会多次列出;没有扩展性,表现TListView的Columns等复杂元件时比较吃力。 (3)、旧字串=新字串 不管元件的instance,ini是纯粹的语言对照表,或者叫字典,扩展性、运行时切换语言可能在引擎里。不足之处是不能处理一词多义。 总的说来,这种方式有很大进步,但为了用ini文件,大家还要费力的破解64k的限制,更专业的方式是使用自定义的文件格式。 在简单性方面,无疑是这种自定义的转换引擎,旧字串=新字串的文件格式来得方便,借助字典管理工具,字典文件可以重复使用,也可以提供给专业翻译公司翻译。那么剩下的问题在引擎上,如何方便,最好用户不写一行代码;如何扩展性强,支持任意的第三方元件;如何有弹性,同一个画面有多种语言的文字,同一个词可以转换成不同的意思.4、给每个元件类继承一个子类,在子类的Loaded方法里转换文字。由于要处理的都是叶级元件(虽然TLabel、TPanel都是从TCustomControl来,但不能只处理TCustomControl),工作量比较大;对旧有程序除了换元件无能为力。 5、为每个元件类注册一个转换函数,引擎遍历Container,为每个元件找到血源最近的转换函数,调用这个函数转换这个元件的文字。这样可以不必处理叶结点,只需在恰当的元件层上注册函数;不必改动旧有程序。設計時For

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论