首先,必须把所有的INI语言文件的结构统一,这样,我们只要传入INI的文件名,就可以通用了,例如我们可以做一个过程SetLanguage(const FileName:string);,这样只要用SetLanguage('CN.INI')就可以了,第二个需要注意的地方,你应该可以让用户选择语言界面的文件,因此程序启动的时候,应该搜索程序目录下面的所有INI文件,当然,你可以在INI文件里面添加一些附加的东西,例如,判断是否是语言INI文件还是其他的配置文件,显示的文字等等~~~~~,如果你的程序中还使用了类似ShowMessage('File Saved!')之类的语句,那么也应该用变量代替!!!例如:ShowMessage(MSG_FILE_SAVED);然后读取INI的时候,一起读入MSG_FILE_SAVED,这样才能保证所有的信息全部变成相应的语言!如果对于这些嵌入程序的信息你怕一个个很麻烦的话, 可以用数组来做~~~~~~~~~:)。接下来就是翻译文字了,这个就~~~~~~~~免了吧?最重要的一步到了:切换语言!我以前的方法是自己写一个过程,用Lable1.Caption:=Ini.ReadString(....)之类的,$^*$#@&^@*(^@(^$@^,现在想起来,怎么这么弱?:(,真的很笨,嗯咳~~~~~~不许笑,:),这个方法有一个缺点就是如果你添加一个控件就^$#@&*^%@&*了~~~~~~~~~,所以必须找一个更好的方法!看看下面的函数就知道了:
procedure SetLanguage(const FileName:string,Buff:array of string);
使用这个方法对于大多数的情况已经够了,但是有一个不方便的地方是如果动态创建窗体或者控件的话,就不行了~~~~~:(,不过你可以根据你的需要,可以修改上面的过程,然后在每一个窗体的OnCreate中添加代码就可以了,例如你把上面的过程改成对单个窗体的,就可以了:)。如果还有考虑不到的控件,你自己添加好了~~:),对于一些小程序来说,下面的已经够了:
{****************************************
* 模块说明:利用切换INI切换语言函数*
* 作者:Kingron@163.net *
****************************************}
{****************************************
下面的编译指定表示是否导出成一个INI文件
一般的情况下面,没有必要修改,但需要母本
INI的时候,可以把注释去掉
****************************************}
{$IFNDEF INI_EXPORT}
///{$DEFINE INI_EXPORT}
{$ENDIF}
{****************************************
函数参数说明:
FileName:Ini语言文件名
msg:用于程序中的信息的保存数组
IgnoreTagValue:需要忽略的组件的Tag值
使用举例:
var
Msg:array of string;
.....
SetLanguage(ExtractFilePath(ParamStr(0))+'English.Ini',msg,$FF);
那么函数会忽略所有Tag值为$FF的控件
****************************************}
procedure SetLanguage(const FileName: string; var msg: array of string; const IgnoreTagValue: integer = $FFFF);
const
///下面是一些常量
TRANS_SECTION = 'Translations';
MESSAGES = 'Messages';
COMMON = 'Common';
HINT = 'Hint';
CAPTION = 'Caption';
MSG_PRE = 'SS_Msg_';
var
i, j, k : integer;
Component : TComponent;
Control : TControl;
Strings : TStrings;
Id : string;
OldCaption : pchar;
L : integer;
begin
with TIniFile.Create(FileName) do
try
{$IFDEF INI_EXPORT}
WriteString(COMMON, 'Application.Title', Application.Title);
WriteBool(COMMON, 'CheckValid', True);
{$ELSE}
if not ReadBool(COMMON, 'CheckValid', False) then exit; ///不是合法的语言文件
Application.Title := ReadString(COMMON, 'Application.Title', Application.Title);
{$ENDIF}
for i := Low(msg) to High(msg) do ///读取非控件的一些语言元素
{$IFDEF INI_EXPORT}
WriteString(MESSAGES, MSG_PRE + IntToStr(i), msg[i]);
{$ELSE}
msg[i] := ReadString(MESSAGES, MSG_PRE + IntToStr(i), msg[i]);
{$ENDIF}
for i := 0 to Screen.FormCount - 1 do ///遍历程序所有窗体
begin
{$IFDEF INI_EXPORT}
WriteString(TRANS_SECTION, Screen.Forms[i].Name + '.' + CAPTION, Screen.Forms[i].Caption);
WriteString(TRANS_SECTION, Screen.Forms[i].Name + '.' + HINT, Screen.Forms[i].Hint);
{$ELSE}
Screen.Forms[i].Caption := ReadString(TRANS_SECTION, Screen.Forms[i].Name + '.' + CAPTION, Screen.Forms[i].Caption);
Screen.Forms[i].Hint := ReadString(TRANS_SECTION, Screen.Forms[i].Name + '.' + HINT, Screen.Forms[i].Hint);
{$ENDIF}
for j := 0 to Screen.Forms[i].ComponentCount - 1 do ///遍历窗体所有组件
begin
Component := Screen.Forms[i].Components[j] as TComponent;
if Component.Tag = IgnoreTagValue then Continue; ///需要忽略的控件
Id := Screen.Forms[i].Name + '.' + Component.Name + '.';
if Component is TControl then ///普通的控件如:TButton,TSpeedButton,TBitBtn,TCheckBox....
begin
Control := Component as TControl;
/// 下面的代码是用来生成第一个INI文件使用的
{$IFDEF INI_EXPORT}
WriteString(TRANS_SECTION, Id + HINT, Control.Hint);
{$ELSE}
Control.Hint := ReadString(TRANS_SECTION, Id + HINT, Control.Hint);
{$ENDIF}
if Control is TCustomEdit then Continue; ///忽略TMemo,TEdit之类的
if (Component is TCustomListBox) or (Component is TCustomRadioGroup)
or (Component is TCustomComboBox) then /// Listbox,RadioGroup,Combobox必须单独处理
begin
Strings := nil; ///本行用于忽略编译信息
if Component is TCustomListBox then Strings := TCustomListBox(Component).Items;
if Component is TCustomRadioGroup then Strings := TRadioGroup(Component).Items;
if Component is TCustomComboBox then Strings := TCustomComboBox(Component).Items;
for k := 0 to Strings.Count - 1 do ///遍历Items的每一项
{$IFDEF INI_EXPORT}
WriteString(TRANS_SECTION, ID + 'Items.' + IntToStr(k), Strings.Strings[k]);
{$ELSE}
Strings.Strings[k] := ReadString(TRANS_SECTION, ID + 'Items.' + IntToStr(k), Strings.Strings[k]);
{$ENDIF}
end;
if Component is TCustomComboBox then Continue; ///Combobox还有一点儿问题,:-(
L := Control.GetTextLen + 1;
GetMem(OldCaption, L);
Control.GetTextBuf(OldCaption, L);
{$IFDEF INI_EXPORT}
WriteString(TRANS_SECTION, Id + CAPTION, OldCaption);
{$ELSE}
Control.SetTextBuf(pchar(ReadString(TRANS_SECTION, Id + CAPTION, OldCaption)));
{$ENDIF}
FreeMem(OldCaption, L);
continue;
end;
if Component is TMenuItem then /// 处理TMenuItem
begin
{$IFDEF INI_EXPORT}
WriteString(TRANS_SECTION, Id + HINT, TMenuItem(Component).Hint);
WriteString(TRANS_SECTION, Id + CAPTION, TMenuItem(Component).Caption);
{$ELSE}
TMenuItem(Component).Hint := ReadString(TRANS_SECTION, ID + HINT, TMenuItem(Component).Hint);
TMenuItem(Component).Caption := ReadString(TRANS_SECTION, ID + CAPTION, TMenuItem(Component).Caption);
{$ENDIF}
Continue;
end;
if Component is TCustomAction then /// 处理TAction
begin
{$IFDEF INI_EXPORT}
WriteString(TRANS_SECTION, Id + HINT, TCustomAction(Component).Hint);
WriteString(TRANS_SECTION, Id + CAPTION, TCustomAction(Component).Caption);
{$ELSE}
TCustomAction(Component).Hint := ReadString(TRANS_SECTION, ID + HINT, TCustomAction(Component).Hint);
TCustomAction(Component).Caption := ReadString(TRANS_SECTION, CAPTION, TCustomAction(Component).Caption);
{$ENDIF}
Continue;
end;
if Component is TOpenDialog then ///处理TOpenDialog,TSaveDialog,....
begin
{$IFDEF INI_EXPORT}
WriteString(TRANS_SECTION, Id + 'Filter', TOpenDialog(Component).Filter);
WriteString(TRANS_SECTION, Id + 'Title', TOpenDialog(Component).Title);
{$ELSE}
TOpenDialog(Component).Filter := ReadString(TRANS_SECTION, ID + HINT, TOpenDialog(Component).Filter);
TOpenDialog(Component).Title := ReadString(TRANS_SECTION, CAPTION, TOpenDialog(Component).Title);
{$ENDIF}
end;
end;
end;
finally
Free;
end;
end;
25 个解决方案
#1
http://crob.net/delphi/source/mutilan.zip
看我写的源代码,
用资源Dll文件及Ini实现多语言支持
看我写的源代码,
用资源Dll文件及Ini实现多语言支持
#2
高手传授技艺,重点关注
#3
高手传授技艺,重点关注
#4
关注关注
#5
多国语言之step
且说Energy受命之后,在Delphi5前苦苦讨教,这才发觉delphi5的技术比他
想象的还厉害,不禁冷汗直流:如果有什么闪失哪里逃得过这里大狭们的眼
睛啊。不由之间身形已经端了5尺。
Energy颤颤危危的New了一个Application,保存慌忙之间居然没起名字,
凭经验应该叫project1;然后放了一个菜单,一个按钮一个label,不禁暗自
思量到。在多国这够说明问题了吧。
想到CJ不觉在菜单的第一项中填下了caption=CJ,name=mnuChinese;呵呵,
既然有CJ也该有Energy,于是另一项中填下了 caption=Energy,name=mnuEnglish;
然后怎么办???
心中无限惶恐的Energy 调出了delphi的例子Demos\Richedit又看了看,立马又
气粗起来。呵呵,有一样好东西,可是让我可以省事不少,不禁又是一阵得意。
(Energy悄悄地把Demos\Richedit\reinit.pas往自己project目录一拷,在
project中又把它加了进来,自言自语道:50% over)
按他的意思先设置一下需要的语言页常数。
implementation
uses reinit;
const
ENGLISH = (SUBLANG_ENGLISH_UK shl 10) or LANG_ENGLISH;
CHINESE = (SUBLANG_CHINESE_SIMPLIFIED shl 10) or LANG_CHINESE;
{$R *.DFM}
做个初始化
procedure TForm1.FormCreate(Sender: TObject);
begin
mnuEnglish.Tag:=ENGLISH;
mnuChinese.Tag:=CHINESE;
end;
然后嘛(不就是菜单切换嘛)
于是把两了菜单都指到了一个地方
procedure TForm1.mnuLangClick(Sender: TObject);
begin
if LoadNewResourceModule(TComponent(Sender).Tag) <> 0 then
ReinitializeForms;
end;
呵呵;(90% over)
不会吧,让你step,你到现在都没说,就这么尽抄袭代码。Energy委屈的说,谁让
他是课代表的。想起当年是班里总课代表,我不做功课居然就没人做的年月,不禁
又是一阵感慨。
兄弟们还差10%,加油啊!
菜单[Project]-[Languages]-[Add...]
[Next>],选择中文(chs),英语(eng);(我只用了这两种语言);
[Next>],[Next>],[Next>],[Finsih],[Yes]
让你保存dpg时小心目录可能是chs,应该用上一级目录才好。
看到了吗,这是你可以修改所有的东西。别乱改。
其中有一些出错信息之类这里都后,放心改好了,改完后可以作为一个模板文件保留。
下次就不用改了。
请关闭吧!
现在可以看到你的project Manager中有3个项目,project1.exe,porject1.eng,project1.chs
后面两了是资源文件,你可以
1,双击project1.eng -- form1,然后修改一些东西。比如button1的caption="eng";改变一下它
的大小和字体。
2,双击project1.chs -- form1,然后修改一些东西。比如button1的caption="chs";改一下字体。
不过最好不要随意改动form的大小和位置!
选中project1.exe,设定为Activate;
然后(兄弟们99%了)
右键project1.chs--build;
右键project1.eng--build;
右键project1.exe--build;
run
噫,你会发现exe中的界面不起作用了。呵呵,系统自己自动选择了一个语言页嘛。
什么你不要自动,$#$%^%^&,[project]-[Languages]-[set Active];
对了如果要在调出那个grid方式修改的工具可以[view]-[Translation Manager];
好了好了,顺便付上我写了说明的reinit.pas文件其实好好看一下就知道还有更强大
的功能等着你利用呢!
语言页的常数在windows.pas里开始于行218;且
+-----------------------+-------------------------+
| Sublanguage ID | Primary Language ID |
+-----------------------+-------------------------+
15 10 9 0 bit
unit ReInit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms;
procedure ReinitializeForms; //重新设置form
function LoadNewResourceModule(Locale: LCID): Longint; // 调取新的语言资源
implementation
type
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;
// 调取新的语言资源 LCID为语言页;
function LoadNewResourceModule(Locale: LCID): Longint;
var
FileName: array [0..260] of char;
P: PChar;
LocaleName: array[0..4] of Char;
NewInst: Longint;
begin
GetModuleFileName(HInstance, FileName, SizeOf(FileName)); // 别紧张,只是取一下当前
// 的模块名,之所以如此是
// 由于可能本身是个dll。
GetLocaleInfo(Locale, LOCALE_SABBREVLANGNAME, LocaleName, SizeOf(LocaleName)); //取当前使的语言页
P := PChar(@FileName) + lstrlen(FileName); //指针运算而已 //可能是exe :-)
while (P^ <> '.') and (P <> @FileName) do Dec(P); //找到语言页资源文件的后缀
NewInst := 0;
Result := 0;
if P <> @FileName then // 如果找到
begin
Inc(P);
if LocaleName[0] <> #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 // 加载失败,使用原文件
LocaleName[2] := #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;
//重新设置在显示中的所有from,;
procedure ReinitializeForms;
var
Count: Integer;
I: Integer;
Form: TForm;
begin
Count := Screen.FormCount;
for I := 0 to Count - 1 do
begin
Form := Screen.Forms[I];
ReloadInheritedComponent(Form, TForm); //重新刷新所有元件几其父对象
end;
end;
end.
////////////////////////////////
用Delphi 5的Integrated Translation Environment (ITE)可以轻易得完成这个工作。
我们创建一个示意性的工程MultiLanguage, 在Form上放一个Label和一个Button, 分别把Caption赋值为“English Label” 和“English Button”。
选择菜单Project|anguages|Add ..., Delphi显示Add Languages对话框, 选择Next。
从语言列表中选中“英语(美国)” 和“中文(中国)”, 选择Next。
ITE会根据所选的语言创建子目录,目录名称是语言的缩写,选择Next。
第一次增加语言时, Update Mode固ㄎ狢reate new, 选择Next。
选择Finish。
Delphi会自动创建支持不同语言的资源动态库。
Delphi还会自动创建一个工程组, 其中包括原有的MultiLanguages.EXE, 还包括新建的两个资源动态库 (MultiLanguages.enu, MultiLanguages.chs)。 保存工程组。
Delphi启动Translation Manager, 左边是需要翻译的语言, 右边是完成百分比。
选择“中文(中国)”|Forms|Unit1, 在右边第15行和20行填写翻译后的中文。 保存并关闭。
打开Project Manager, 编译MultiLanguages.enu和MultiLanguages.chs, Delphi会在相应的子目录生成资源动态库, 但后缀不是DLL而是ENU和CHS。
且说Energy受命之后,在Delphi5前苦苦讨教,这才发觉delphi5的技术比他
想象的还厉害,不禁冷汗直流:如果有什么闪失哪里逃得过这里大狭们的眼
睛啊。不由之间身形已经端了5尺。
Energy颤颤危危的New了一个Application,保存慌忙之间居然没起名字,
凭经验应该叫project1;然后放了一个菜单,一个按钮一个label,不禁暗自
思量到。在多国这够说明问题了吧。
想到CJ不觉在菜单的第一项中填下了caption=CJ,name=mnuChinese;呵呵,
既然有CJ也该有Energy,于是另一项中填下了 caption=Energy,name=mnuEnglish;
然后怎么办???
心中无限惶恐的Energy 调出了delphi的例子Demos\Richedit又看了看,立马又
气粗起来。呵呵,有一样好东西,可是让我可以省事不少,不禁又是一阵得意。
(Energy悄悄地把Demos\Richedit\reinit.pas往自己project目录一拷,在
project中又把它加了进来,自言自语道:50% over)
按他的意思先设置一下需要的语言页常数。
implementation
uses reinit;
const
ENGLISH = (SUBLANG_ENGLISH_UK shl 10) or LANG_ENGLISH;
CHINESE = (SUBLANG_CHINESE_SIMPLIFIED shl 10) or LANG_CHINESE;
{$R *.DFM}
做个初始化
procedure TForm1.FormCreate(Sender: TObject);
begin
mnuEnglish.Tag:=ENGLISH;
mnuChinese.Tag:=CHINESE;
end;
然后嘛(不就是菜单切换嘛)
于是把两了菜单都指到了一个地方
procedure TForm1.mnuLangClick(Sender: TObject);
begin
if LoadNewResourceModule(TComponent(Sender).Tag) <> 0 then
ReinitializeForms;
end;
呵呵;(90% over)
不会吧,让你step,你到现在都没说,就这么尽抄袭代码。Energy委屈的说,谁让
他是课代表的。想起当年是班里总课代表,我不做功课居然就没人做的年月,不禁
又是一阵感慨。
兄弟们还差10%,加油啊!
菜单[Project]-[Languages]-[Add...]
[Next>],选择中文(chs),英语(eng);(我只用了这两种语言);
[Next>],[Next>],[Next>],[Finsih],[Yes]
让你保存dpg时小心目录可能是chs,应该用上一级目录才好。
看到了吗,这是你可以修改所有的东西。别乱改。
其中有一些出错信息之类这里都后,放心改好了,改完后可以作为一个模板文件保留。
下次就不用改了。
请关闭吧!
现在可以看到你的project Manager中有3个项目,project1.exe,porject1.eng,project1.chs
后面两了是资源文件,你可以
1,双击project1.eng -- form1,然后修改一些东西。比如button1的caption="eng";改变一下它
的大小和字体。
2,双击project1.chs -- form1,然后修改一些东西。比如button1的caption="chs";改一下字体。
不过最好不要随意改动form的大小和位置!
选中project1.exe,设定为Activate;
然后(兄弟们99%了)
右键project1.chs--build;
右键project1.eng--build;
右键project1.exe--build;
run
噫,你会发现exe中的界面不起作用了。呵呵,系统自己自动选择了一个语言页嘛。
什么你不要自动,$#$%^%^&,[project]-[Languages]-[set Active];
对了如果要在调出那个grid方式修改的工具可以[view]-[Translation Manager];
好了好了,顺便付上我写了说明的reinit.pas文件其实好好看一下就知道还有更强大
的功能等着你利用呢!
语言页的常数在windows.pas里开始于行218;且
+-----------------------+-------------------------+
| Sublanguage ID | Primary Language ID |
+-----------------------+-------------------------+
15 10 9 0 bit
unit ReInit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms;
procedure ReinitializeForms; //重新设置form
function LoadNewResourceModule(Locale: LCID): Longint; // 调取新的语言资源
implementation
type
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;
// 调取新的语言资源 LCID为语言页;
function LoadNewResourceModule(Locale: LCID): Longint;
var
FileName: array [0..260] of char;
P: PChar;
LocaleName: array[0..4] of Char;
NewInst: Longint;
begin
GetModuleFileName(HInstance, FileName, SizeOf(FileName)); // 别紧张,只是取一下当前
// 的模块名,之所以如此是
// 由于可能本身是个dll。
GetLocaleInfo(Locale, LOCALE_SABBREVLANGNAME, LocaleName, SizeOf(LocaleName)); //取当前使的语言页
P := PChar(@FileName) + lstrlen(FileName); //指针运算而已 //可能是exe :-)
while (P^ <> '.') and (P <> @FileName) do Dec(P); //找到语言页资源文件的后缀
NewInst := 0;
Result := 0;
if P <> @FileName then // 如果找到
begin
Inc(P);
if LocaleName[0] <> #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 // 加载失败,使用原文件
LocaleName[2] := #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;
//重新设置在显示中的所有from,;
procedure ReinitializeForms;
var
Count: Integer;
I: Integer;
Form: TForm;
begin
Count := Screen.FormCount;
for I := 0 to Count - 1 do
begin
Form := Screen.Forms[I];
ReloadInheritedComponent(Form, TForm); //重新刷新所有元件几其父对象
end;
end;
end.
////////////////////////////////
用Delphi 5的Integrated Translation Environment (ITE)可以轻易得完成这个工作。
我们创建一个示意性的工程MultiLanguage, 在Form上放一个Label和一个Button, 分别把Caption赋值为“English Label” 和“English Button”。
选择菜单Project|anguages|Add ..., Delphi显示Add Languages对话框, 选择Next。
从语言列表中选中“英语(美国)” 和“中文(中国)”, 选择Next。
ITE会根据所选的语言创建子目录,目录名称是语言的缩写,选择Next。
第一次增加语言时, Update Mode固ㄎ狢reate new, 选择Next。
选择Finish。
Delphi会自动创建支持不同语言的资源动态库。
Delphi还会自动创建一个工程组, 其中包括原有的MultiLanguages.EXE, 还包括新建的两个资源动态库 (MultiLanguages.enu, MultiLanguages.chs)。 保存工程组。
Delphi启动Translation Manager, 左边是需要翻译的语言, 右边是完成百分比。
选择“中文(中国)”|Forms|Unit1, 在右边第15行和20行填写翻译后的中文。 保存并关闭。
打开Project Manager, 编译MultiLanguages.enu和MultiLanguages.chs, Delphi会在相应的子目录生成资源动态库, 但后缀不是DLL而是ENU和CHS。
#6
多国语言之step
且说Energy受命之后,在Delphi5前苦苦讨教,这才发觉delphi5的技术比他
想象的还厉害,不禁冷汗直流:如果有什么闪失哪里逃得过这里大狭们的眼
睛啊。不由之间身形已经端了5尺。
Energy颤颤危危的New了一个Application,保存慌忙之间居然没起名字,
凭经验应该叫project1;然后放了一个菜单,一个按钮一个label,不禁暗自
思量到。在多国这够说明问题了吧。
想到CJ不觉在菜单的第一项中填下了caption=CJ,name=mnuChinese;呵呵,
既然有CJ也该有Energy,于是另一项中填下了 caption=Energy,name=mnuEnglish;
然后怎么办???
心中无限惶恐的Energy 调出了delphi的例子Demos\Richedit又看了看,立马又
气粗起来。呵呵,有一样好东西,可是让我可以省事不少,不禁又是一阵得意。
(Energy悄悄地把Demos\Richedit\reinit.pas往自己project目录一拷,在
project中又把它加了进来,自言自语道:50% over)
按他的意思先设置一下需要的语言页常数。
implementation
uses reinit;
const
ENGLISH = (SUBLANG_ENGLISH_UK shl 10) or LANG_ENGLISH;
CHINESE = (SUBLANG_CHINESE_SIMPLIFIED shl 10) or LANG_CHINESE;
{$R *.DFM}
做个初始化
procedure TForm1.FormCreate(Sender: TObject);
begin
mnuEnglish.Tag:=ENGLISH;
mnuChinese.Tag:=CHINESE;
end;
然后嘛(不就是菜单切换嘛)
于是把两了菜单都指到了一个地方
procedure TForm1.mnuLangClick(Sender: TObject);
begin
if LoadNewResourceModule(TComponent(Sender).Tag) <> 0 then
ReinitializeForms;
end;
呵呵;(90% over)
不会吧,让你step,你到现在都没说,就这么尽抄袭代码。Energy委屈的说,谁让
他是课代表的。想起当年是班里总课代表,我不做功课居然就没人做的年月,不禁
又是一阵感慨。
兄弟们还差10%,加油啊!
菜单[Project]-[Languages]-[Add...]
[Next>],选择中文(chs),英语(eng);(我只用了这两种语言);
[Next>],[Next>],[Next>],[Finsih],[Yes]
让你保存dpg时小心目录可能是chs,应该用上一级目录才好。
看到了吗,这是你可以修改所有的东西。别乱改。
其中有一些出错信息之类这里都后,放心改好了,改完后可以作为一个模板文件保留。
下次就不用改了。
请关闭吧!
现在可以看到你的project Manager中有3个项目,project1.exe,porject1.eng,project1.chs
后面两了是资源文件,你可以
1,双击project1.eng -- form1,然后修改一些东西。比如button1的caption="eng";改变一下它
的大小和字体。
2,双击project1.chs -- form1,然后修改一些东西。比如button1的caption="chs";改一下字体。
不过最好不要随意改动form的大小和位置!
选中project1.exe,设定为Activate;
然后(兄弟们99%了)
右键project1.chs--build;
右键project1.eng--build;
右键project1.exe--build;
run
噫,你会发现exe中的界面不起作用了。呵呵,系统自己自动选择了一个语言页嘛。
什么你不要自动,$#$%^%^&,[project]-[Languages]-[set Active];
对了如果要在调出那个grid方式修改的工具可以[view]-[Translation Manager];
好了好了,顺便付上我写了说明的reinit.pas文件其实好好看一下就知道还有更强大
的功能等着你利用呢!
语言页的常数在windows.pas里开始于行218;且
+-----------------------+-------------------------+
| Sublanguage ID | Primary Language ID |
+-----------------------+-------------------------+
15 10 9 0 bit
unit ReInit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms;
procedure ReinitializeForms; //重新设置form
function LoadNewResourceModule(Locale: LCID): Longint; // 调取新的语言资源
implementation
type
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;
// 调取新的语言资源 LCID为语言页;
function LoadNewResourceModule(Locale: LCID): Longint;
var
FileName: array [0..260] of char;
P: PChar;
LocaleName: array[0..4] of Char;
NewInst: Longint;
begin
GetModuleFileName(HInstance, FileName, SizeOf(FileName)); // 别紧张,只是取一下当前
// 的模块名,之所以如此是
// 由于可能本身是个dll。
GetLocaleInfo(Locale, LOCALE_SABBREVLANGNAME, LocaleName, SizeOf(LocaleName)); //取当前使的语言页
P := PChar(@FileName) + lstrlen(FileName); //指针运算而已 //可能是exe :-)
while (P^ <> '.') and (P <> @FileName) do Dec(P); //找到语言页资源文件的后缀
NewInst := 0;
Result := 0;
if P <> @FileName then // 如果找到
begin
Inc(P);
if LocaleName[0] <> #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 // 加载失败,使用原文件
LocaleName[2] := #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;
//重新设置在显示中的所有from,;
procedure ReinitializeForms;
var
Count: Integer;
I: Integer;
Form: TForm;
begin
Count := Screen.FormCount;
for I := 0 to Count - 1 do
begin
Form := Screen.Forms[I];
ReloadInheritedComponent(Form, TForm); //重新刷新所有元件几其父对象
end;
end;
end.
////////////////////////////////
用Delphi 5的Integrated Translation Environment (ITE)可以轻易得完成这个工作。
我们创建一个示意性的工程MultiLanguage, 在Form上放一个Label和一个Button, 分别把Caption赋值为“English Label” 和“English Button”。
选择菜单Project|anguages|Add ..., Delphi显示Add Languages对话框, 选择Next。
从语言列表中选中“英语(美国)” 和“中文(中国)”, 选择Next。
ITE会根据所选的语言创建子目录,目录名称是语言的缩写,选择Next。
第一次增加语言时, Update Mode固ㄎ狢reate new, 选择Next。
选择Finish。
Delphi会自动创建支持不同语言的资源动态库。
Delphi还会自动创建一个工程组, 其中包括原有的MultiLanguages.EXE, 还包括新建的两个资源动态库 (MultiLanguages.enu, MultiLanguages.chs)。 保存工程组。
Delphi启动Translation Manager, 左边是需要翻译的语言, 右边是完成百分比。
选择“中文(中国)”|Forms|Unit1, 在右边第15行和20行填写翻译后的中文。 保存并关闭。
打开Project Manager, 编译MultiLanguages.enu和MultiLanguages.chs, Delphi会在相应的子目录生成资源动态库, 但后缀不是DLL而是ENU和CHS。
且说Energy受命之后,在Delphi5前苦苦讨教,这才发觉delphi5的技术比他
想象的还厉害,不禁冷汗直流:如果有什么闪失哪里逃得过这里大狭们的眼
睛啊。不由之间身形已经端了5尺。
Energy颤颤危危的New了一个Application,保存慌忙之间居然没起名字,
凭经验应该叫project1;然后放了一个菜单,一个按钮一个label,不禁暗自
思量到。在多国这够说明问题了吧。
想到CJ不觉在菜单的第一项中填下了caption=CJ,name=mnuChinese;呵呵,
既然有CJ也该有Energy,于是另一项中填下了 caption=Energy,name=mnuEnglish;
然后怎么办???
心中无限惶恐的Energy 调出了delphi的例子Demos\Richedit又看了看,立马又
气粗起来。呵呵,有一样好东西,可是让我可以省事不少,不禁又是一阵得意。
(Energy悄悄地把Demos\Richedit\reinit.pas往自己project目录一拷,在
project中又把它加了进来,自言自语道:50% over)
按他的意思先设置一下需要的语言页常数。
implementation
uses reinit;
const
ENGLISH = (SUBLANG_ENGLISH_UK shl 10) or LANG_ENGLISH;
CHINESE = (SUBLANG_CHINESE_SIMPLIFIED shl 10) or LANG_CHINESE;
{$R *.DFM}
做个初始化
procedure TForm1.FormCreate(Sender: TObject);
begin
mnuEnglish.Tag:=ENGLISH;
mnuChinese.Tag:=CHINESE;
end;
然后嘛(不就是菜单切换嘛)
于是把两了菜单都指到了一个地方
procedure TForm1.mnuLangClick(Sender: TObject);
begin
if LoadNewResourceModule(TComponent(Sender).Tag) <> 0 then
ReinitializeForms;
end;
呵呵;(90% over)
不会吧,让你step,你到现在都没说,就这么尽抄袭代码。Energy委屈的说,谁让
他是课代表的。想起当年是班里总课代表,我不做功课居然就没人做的年月,不禁
又是一阵感慨。
兄弟们还差10%,加油啊!
菜单[Project]-[Languages]-[Add...]
[Next>],选择中文(chs),英语(eng);(我只用了这两种语言);
[Next>],[Next>],[Next>],[Finsih],[Yes]
让你保存dpg时小心目录可能是chs,应该用上一级目录才好。
看到了吗,这是你可以修改所有的东西。别乱改。
其中有一些出错信息之类这里都后,放心改好了,改完后可以作为一个模板文件保留。
下次就不用改了。
请关闭吧!
现在可以看到你的project Manager中有3个项目,project1.exe,porject1.eng,project1.chs
后面两了是资源文件,你可以
1,双击project1.eng -- form1,然后修改一些东西。比如button1的caption="eng";改变一下它
的大小和字体。
2,双击project1.chs -- form1,然后修改一些东西。比如button1的caption="chs";改一下字体。
不过最好不要随意改动form的大小和位置!
选中project1.exe,设定为Activate;
然后(兄弟们99%了)
右键project1.chs--build;
右键project1.eng--build;
右键project1.exe--build;
run
噫,你会发现exe中的界面不起作用了。呵呵,系统自己自动选择了一个语言页嘛。
什么你不要自动,$#$%^%^&,[project]-[Languages]-[set Active];
对了如果要在调出那个grid方式修改的工具可以[view]-[Translation Manager];
好了好了,顺便付上我写了说明的reinit.pas文件其实好好看一下就知道还有更强大
的功能等着你利用呢!
语言页的常数在windows.pas里开始于行218;且
+-----------------------+-------------------------+
| Sublanguage ID | Primary Language ID |
+-----------------------+-------------------------+
15 10 9 0 bit
unit ReInit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms;
procedure ReinitializeForms; //重新设置form
function LoadNewResourceModule(Locale: LCID): Longint; // 调取新的语言资源
implementation
type
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;
// 调取新的语言资源 LCID为语言页;
function LoadNewResourceModule(Locale: LCID): Longint;
var
FileName: array [0..260] of char;
P: PChar;
LocaleName: array[0..4] of Char;
NewInst: Longint;
begin
GetModuleFileName(HInstance, FileName, SizeOf(FileName)); // 别紧张,只是取一下当前
// 的模块名,之所以如此是
// 由于可能本身是个dll。
GetLocaleInfo(Locale, LOCALE_SABBREVLANGNAME, LocaleName, SizeOf(LocaleName)); //取当前使的语言页
P := PChar(@FileName) + lstrlen(FileName); //指针运算而已 //可能是exe :-)
while (P^ <> '.') and (P <> @FileName) do Dec(P); //找到语言页资源文件的后缀
NewInst := 0;
Result := 0;
if P <> @FileName then // 如果找到
begin
Inc(P);
if LocaleName[0] <> #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 // 加载失败,使用原文件
LocaleName[2] := #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;
//重新设置在显示中的所有from,;
procedure ReinitializeForms;
var
Count: Integer;
I: Integer;
Form: TForm;
begin
Count := Screen.FormCount;
for I := 0 to Count - 1 do
begin
Form := Screen.Forms[I];
ReloadInheritedComponent(Form, TForm); //重新刷新所有元件几其父对象
end;
end;
end.
////////////////////////////////
用Delphi 5的Integrated Translation Environment (ITE)可以轻易得完成这个工作。
我们创建一个示意性的工程MultiLanguage, 在Form上放一个Label和一个Button, 分别把Caption赋值为“English Label” 和“English Button”。
选择菜单Project|anguages|Add ..., Delphi显示Add Languages对话框, 选择Next。
从语言列表中选中“英语(美国)” 和“中文(中国)”, 选择Next。
ITE会根据所选的语言创建子目录,目录名称是语言的缩写,选择Next。
第一次增加语言时, Update Mode固ㄎ狢reate new, 选择Next。
选择Finish。
Delphi会自动创建支持不同语言的资源动态库。
Delphi还会自动创建一个工程组, 其中包括原有的MultiLanguages.EXE, 还包括新建的两个资源动态库 (MultiLanguages.enu, MultiLanguages.chs)。 保存工程组。
Delphi启动Translation Manager, 左边是需要翻译的语言, 右边是完成百分比。
选择“中文(中国)”|Forms|Unit1, 在右边第15行和20行填写翻译后的中文。 保存并关闭。
打开Project Manager, 编译MultiLanguages.enu和MultiLanguages.chs, Delphi会在相应的子目录生成资源动态库, 但后缀不是DLL而是ENU和CHS。
#7
另外字符串的.res资源文件生成方法是
将下面存成文本文件,例如文件名为chinese.txt
STRINGTABLE
BEGIN
1,"确定"
2,"取消"
END
然后运行delphi\bin\brcc32.exe chinese.txt
编译后生成chinese.res
然后将该.res文件加在Dll工程中({$R chinese.res})编译就生成了资源Dll,可在主程序中调用
具体见http://crob.net/delphi/source/mutilan.zip
将下面存成文本文件,例如文件名为chinese.txt
STRINGTABLE
BEGIN
1,"确定"
2,"取消"
END
然后运行delphi\bin\brcc32.exe chinese.txt
编译后生成chinese.res
然后将该.res文件加在Dll工程中({$R chinese.res})编译就生成了资源Dll,可在主程序中调用
具体见http://crob.net/delphi/source/mutilan.zip
#8
To Crob:
我看了你的利用INI的,当场晕倒,你那样的是控件相关的,如果在窗体上面添加一个控件,就要修改代码!!!我以前也是这么做的,:(,后来发现太麻烦,因此就有了上面的过程,这样,你添加一个控件,不影响你的代码!:)。至于DLL的方式,我也知道,不过那样太麻烦。所以我倾向于用INI。
我看了你的利用INI的,当场晕倒,你那样的是控件相关的,如果在窗体上面添加一个控件,就要修改代码!!!我以前也是这么做的,:(,后来发现太麻烦,因此就有了上面的过程,这样,你添加一个控件,不影响你的代码!:)。至于DLL的方式,我也知道,不过那样太麻烦。所以我倾向于用INI。
#9
To kevin_gao:
这个方式:),也知道,我以前也采用过,还是太麻烦,而且更新有问题,界面比较闪烁,还有资源更新的问题,等等,我用过几种方法,还是发现用INI是最方便的。你只要翻译文字即可。:)
这个方式:),也知道,我以前也采用过,还是太麻烦,而且更新有问题,界面比较闪烁,还有资源更新的问题,等等,我用过几种方法,还是发现用INI是最方便的。你只要翻译文字即可。:)
#10
支持一下
#11
谁都认为自己的好,亲生的嘛。
#12
To hellion(恶人):
那倒不是,要不你自己用三种方式测试一下?其实用Delphi自带的资源DLL的方式是最好的,因为可以有事件处理,不过一般用不到。
那倒不是,要不你自己用三种方式测试一下?其实用Delphi自带的资源DLL的方式是最好的,因为可以有事件处理,不过一般用不到。
#13
大家都說得好,值得學習!
#14
这么长的代码,麻烦多写点注释吗?
#15
这么长的代码,多加点 注释
#16
Delphi自带的资源DLL的方式好像还不完善
有些控件例如listview就不能转换
有些控件例如listview就不能转换
#17
看了,存了~~
#18
good,very good;
#19
各位大侠,看看我的帖子
http://www.csdn.net/expert/topic/349/349276.shtm
对不起,占用了老版主的地盘
http://www.csdn.net/expert/topic/349/349276.shtm
对不起,占用了老版主的地盘
#20
这么好的贴子,我提一下
#21
该死!怎么无法给分了?
#22
啊哟,前辈万岁,高手万岁。
#23
啊哟,前辈万岁,高手万岁。
#24
要是我我不考虑用INI文件,我会做成RES文件,用LOADSTR()LOADCRU()等完成.
#25
关注~~关注~~~
看看~~看看~~
看看~~看看~~
#1
http://crob.net/delphi/source/mutilan.zip
看我写的源代码,
用资源Dll文件及Ini实现多语言支持
看我写的源代码,
用资源Dll文件及Ini实现多语言支持
#2
高手传授技艺,重点关注
#3
高手传授技艺,重点关注
#4
关注关注
#5
多国语言之step
且说Energy受命之后,在Delphi5前苦苦讨教,这才发觉delphi5的技术比他
想象的还厉害,不禁冷汗直流:如果有什么闪失哪里逃得过这里大狭们的眼
睛啊。不由之间身形已经端了5尺。
Energy颤颤危危的New了一个Application,保存慌忙之间居然没起名字,
凭经验应该叫project1;然后放了一个菜单,一个按钮一个label,不禁暗自
思量到。在多国这够说明问题了吧。
想到CJ不觉在菜单的第一项中填下了caption=CJ,name=mnuChinese;呵呵,
既然有CJ也该有Energy,于是另一项中填下了 caption=Energy,name=mnuEnglish;
然后怎么办???
心中无限惶恐的Energy 调出了delphi的例子Demos\Richedit又看了看,立马又
气粗起来。呵呵,有一样好东西,可是让我可以省事不少,不禁又是一阵得意。
(Energy悄悄地把Demos\Richedit\reinit.pas往自己project目录一拷,在
project中又把它加了进来,自言自语道:50% over)
按他的意思先设置一下需要的语言页常数。
implementation
uses reinit;
const
ENGLISH = (SUBLANG_ENGLISH_UK shl 10) or LANG_ENGLISH;
CHINESE = (SUBLANG_CHINESE_SIMPLIFIED shl 10) or LANG_CHINESE;
{$R *.DFM}
做个初始化
procedure TForm1.FormCreate(Sender: TObject);
begin
mnuEnglish.Tag:=ENGLISH;
mnuChinese.Tag:=CHINESE;
end;
然后嘛(不就是菜单切换嘛)
于是把两了菜单都指到了一个地方
procedure TForm1.mnuLangClick(Sender: TObject);
begin
if LoadNewResourceModule(TComponent(Sender).Tag) <> 0 then
ReinitializeForms;
end;
呵呵;(90% over)
不会吧,让你step,你到现在都没说,就这么尽抄袭代码。Energy委屈的说,谁让
他是课代表的。想起当年是班里总课代表,我不做功课居然就没人做的年月,不禁
又是一阵感慨。
兄弟们还差10%,加油啊!
菜单[Project]-[Languages]-[Add...]
[Next>],选择中文(chs),英语(eng);(我只用了这两种语言);
[Next>],[Next>],[Next>],[Finsih],[Yes]
让你保存dpg时小心目录可能是chs,应该用上一级目录才好。
看到了吗,这是你可以修改所有的东西。别乱改。
其中有一些出错信息之类这里都后,放心改好了,改完后可以作为一个模板文件保留。
下次就不用改了。
请关闭吧!
现在可以看到你的project Manager中有3个项目,project1.exe,porject1.eng,project1.chs
后面两了是资源文件,你可以
1,双击project1.eng -- form1,然后修改一些东西。比如button1的caption="eng";改变一下它
的大小和字体。
2,双击project1.chs -- form1,然后修改一些东西。比如button1的caption="chs";改一下字体。
不过最好不要随意改动form的大小和位置!
选中project1.exe,设定为Activate;
然后(兄弟们99%了)
右键project1.chs--build;
右键project1.eng--build;
右键project1.exe--build;
run
噫,你会发现exe中的界面不起作用了。呵呵,系统自己自动选择了一个语言页嘛。
什么你不要自动,$#$%^%^&,[project]-[Languages]-[set Active];
对了如果要在调出那个grid方式修改的工具可以[view]-[Translation Manager];
好了好了,顺便付上我写了说明的reinit.pas文件其实好好看一下就知道还有更强大
的功能等着你利用呢!
语言页的常数在windows.pas里开始于行218;且
+-----------------------+-------------------------+
| Sublanguage ID | Primary Language ID |
+-----------------------+-------------------------+
15 10 9 0 bit
unit ReInit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms;
procedure ReinitializeForms; //重新设置form
function LoadNewResourceModule(Locale: LCID): Longint; // 调取新的语言资源
implementation
type
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;
// 调取新的语言资源 LCID为语言页;
function LoadNewResourceModule(Locale: LCID): Longint;
var
FileName: array [0..260] of char;
P: PChar;
LocaleName: array[0..4] of Char;
NewInst: Longint;
begin
GetModuleFileName(HInstance, FileName, SizeOf(FileName)); // 别紧张,只是取一下当前
// 的模块名,之所以如此是
// 由于可能本身是个dll。
GetLocaleInfo(Locale, LOCALE_SABBREVLANGNAME, LocaleName, SizeOf(LocaleName)); //取当前使的语言页
P := PChar(@FileName) + lstrlen(FileName); //指针运算而已 //可能是exe :-)
while (P^ <> '.') and (P <> @FileName) do Dec(P); //找到语言页资源文件的后缀
NewInst := 0;
Result := 0;
if P <> @FileName then // 如果找到
begin
Inc(P);
if LocaleName[0] <> #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 // 加载失败,使用原文件
LocaleName[2] := #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;
//重新设置在显示中的所有from,;
procedure ReinitializeForms;
var
Count: Integer;
I: Integer;
Form: TForm;
begin
Count := Screen.FormCount;
for I := 0 to Count - 1 do
begin
Form := Screen.Forms[I];
ReloadInheritedComponent(Form, TForm); //重新刷新所有元件几其父对象
end;
end;
end.
////////////////////////////////
用Delphi 5的Integrated Translation Environment (ITE)可以轻易得完成这个工作。
我们创建一个示意性的工程MultiLanguage, 在Form上放一个Label和一个Button, 分别把Caption赋值为“English Label” 和“English Button”。
选择菜单Project|anguages|Add ..., Delphi显示Add Languages对话框, 选择Next。
从语言列表中选中“英语(美国)” 和“中文(中国)”, 选择Next。
ITE会根据所选的语言创建子目录,目录名称是语言的缩写,选择Next。
第一次增加语言时, Update Mode固ㄎ狢reate new, 选择Next。
选择Finish。
Delphi会自动创建支持不同语言的资源动态库。
Delphi还会自动创建一个工程组, 其中包括原有的MultiLanguages.EXE, 还包括新建的两个资源动态库 (MultiLanguages.enu, MultiLanguages.chs)。 保存工程组。
Delphi启动Translation Manager, 左边是需要翻译的语言, 右边是完成百分比。
选择“中文(中国)”|Forms|Unit1, 在右边第15行和20行填写翻译后的中文。 保存并关闭。
打开Project Manager, 编译MultiLanguages.enu和MultiLanguages.chs, Delphi会在相应的子目录生成资源动态库, 但后缀不是DLL而是ENU和CHS。
且说Energy受命之后,在Delphi5前苦苦讨教,这才发觉delphi5的技术比他
想象的还厉害,不禁冷汗直流:如果有什么闪失哪里逃得过这里大狭们的眼
睛啊。不由之间身形已经端了5尺。
Energy颤颤危危的New了一个Application,保存慌忙之间居然没起名字,
凭经验应该叫project1;然后放了一个菜单,一个按钮一个label,不禁暗自
思量到。在多国这够说明问题了吧。
想到CJ不觉在菜单的第一项中填下了caption=CJ,name=mnuChinese;呵呵,
既然有CJ也该有Energy,于是另一项中填下了 caption=Energy,name=mnuEnglish;
然后怎么办???
心中无限惶恐的Energy 调出了delphi的例子Demos\Richedit又看了看,立马又
气粗起来。呵呵,有一样好东西,可是让我可以省事不少,不禁又是一阵得意。
(Energy悄悄地把Demos\Richedit\reinit.pas往自己project目录一拷,在
project中又把它加了进来,自言自语道:50% over)
按他的意思先设置一下需要的语言页常数。
implementation
uses reinit;
const
ENGLISH = (SUBLANG_ENGLISH_UK shl 10) or LANG_ENGLISH;
CHINESE = (SUBLANG_CHINESE_SIMPLIFIED shl 10) or LANG_CHINESE;
{$R *.DFM}
做个初始化
procedure TForm1.FormCreate(Sender: TObject);
begin
mnuEnglish.Tag:=ENGLISH;
mnuChinese.Tag:=CHINESE;
end;
然后嘛(不就是菜单切换嘛)
于是把两了菜单都指到了一个地方
procedure TForm1.mnuLangClick(Sender: TObject);
begin
if LoadNewResourceModule(TComponent(Sender).Tag) <> 0 then
ReinitializeForms;
end;
呵呵;(90% over)
不会吧,让你step,你到现在都没说,就这么尽抄袭代码。Energy委屈的说,谁让
他是课代表的。想起当年是班里总课代表,我不做功课居然就没人做的年月,不禁
又是一阵感慨。
兄弟们还差10%,加油啊!
菜单[Project]-[Languages]-[Add...]
[Next>],选择中文(chs),英语(eng);(我只用了这两种语言);
[Next>],[Next>],[Next>],[Finsih],[Yes]
让你保存dpg时小心目录可能是chs,应该用上一级目录才好。
看到了吗,这是你可以修改所有的东西。别乱改。
其中有一些出错信息之类这里都后,放心改好了,改完后可以作为一个模板文件保留。
下次就不用改了。
请关闭吧!
现在可以看到你的project Manager中有3个项目,project1.exe,porject1.eng,project1.chs
后面两了是资源文件,你可以
1,双击project1.eng -- form1,然后修改一些东西。比如button1的caption="eng";改变一下它
的大小和字体。
2,双击project1.chs -- form1,然后修改一些东西。比如button1的caption="chs";改一下字体。
不过最好不要随意改动form的大小和位置!
选中project1.exe,设定为Activate;
然后(兄弟们99%了)
右键project1.chs--build;
右键project1.eng--build;
右键project1.exe--build;
run
噫,你会发现exe中的界面不起作用了。呵呵,系统自己自动选择了一个语言页嘛。
什么你不要自动,$#$%^%^&,[project]-[Languages]-[set Active];
对了如果要在调出那个grid方式修改的工具可以[view]-[Translation Manager];
好了好了,顺便付上我写了说明的reinit.pas文件其实好好看一下就知道还有更强大
的功能等着你利用呢!
语言页的常数在windows.pas里开始于行218;且
+-----------------------+-------------------------+
| Sublanguage ID | Primary Language ID |
+-----------------------+-------------------------+
15 10 9 0 bit
unit ReInit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms;
procedure ReinitializeForms; //重新设置form
function LoadNewResourceModule(Locale: LCID): Longint; // 调取新的语言资源
implementation
type
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;
// 调取新的语言资源 LCID为语言页;
function LoadNewResourceModule(Locale: LCID): Longint;
var
FileName: array [0..260] of char;
P: PChar;
LocaleName: array[0..4] of Char;
NewInst: Longint;
begin
GetModuleFileName(HInstance, FileName, SizeOf(FileName)); // 别紧张,只是取一下当前
// 的模块名,之所以如此是
// 由于可能本身是个dll。
GetLocaleInfo(Locale, LOCALE_SABBREVLANGNAME, LocaleName, SizeOf(LocaleName)); //取当前使的语言页
P := PChar(@FileName) + lstrlen(FileName); //指针运算而已 //可能是exe :-)
while (P^ <> '.') and (P <> @FileName) do Dec(P); //找到语言页资源文件的后缀
NewInst := 0;
Result := 0;
if P <> @FileName then // 如果找到
begin
Inc(P);
if LocaleName[0] <> #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 // 加载失败,使用原文件
LocaleName[2] := #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;
//重新设置在显示中的所有from,;
procedure ReinitializeForms;
var
Count: Integer;
I: Integer;
Form: TForm;
begin
Count := Screen.FormCount;
for I := 0 to Count - 1 do
begin
Form := Screen.Forms[I];
ReloadInheritedComponent(Form, TForm); //重新刷新所有元件几其父对象
end;
end;
end.
////////////////////////////////
用Delphi 5的Integrated Translation Environment (ITE)可以轻易得完成这个工作。
我们创建一个示意性的工程MultiLanguage, 在Form上放一个Label和一个Button, 分别把Caption赋值为“English Label” 和“English Button”。
选择菜单Project|anguages|Add ..., Delphi显示Add Languages对话框, 选择Next。
从语言列表中选中“英语(美国)” 和“中文(中国)”, 选择Next。
ITE会根据所选的语言创建子目录,目录名称是语言的缩写,选择Next。
第一次增加语言时, Update Mode固ㄎ狢reate new, 选择Next。
选择Finish。
Delphi会自动创建支持不同语言的资源动态库。
Delphi还会自动创建一个工程组, 其中包括原有的MultiLanguages.EXE, 还包括新建的两个资源动态库 (MultiLanguages.enu, MultiLanguages.chs)。 保存工程组。
Delphi启动Translation Manager, 左边是需要翻译的语言, 右边是完成百分比。
选择“中文(中国)”|Forms|Unit1, 在右边第15行和20行填写翻译后的中文。 保存并关闭。
打开Project Manager, 编译MultiLanguages.enu和MultiLanguages.chs, Delphi会在相应的子目录生成资源动态库, 但后缀不是DLL而是ENU和CHS。
#6
多国语言之step
且说Energy受命之后,在Delphi5前苦苦讨教,这才发觉delphi5的技术比他
想象的还厉害,不禁冷汗直流:如果有什么闪失哪里逃得过这里大狭们的眼
睛啊。不由之间身形已经端了5尺。
Energy颤颤危危的New了一个Application,保存慌忙之间居然没起名字,
凭经验应该叫project1;然后放了一个菜单,一个按钮一个label,不禁暗自
思量到。在多国这够说明问题了吧。
想到CJ不觉在菜单的第一项中填下了caption=CJ,name=mnuChinese;呵呵,
既然有CJ也该有Energy,于是另一项中填下了 caption=Energy,name=mnuEnglish;
然后怎么办???
心中无限惶恐的Energy 调出了delphi的例子Demos\Richedit又看了看,立马又
气粗起来。呵呵,有一样好东西,可是让我可以省事不少,不禁又是一阵得意。
(Energy悄悄地把Demos\Richedit\reinit.pas往自己project目录一拷,在
project中又把它加了进来,自言自语道:50% over)
按他的意思先设置一下需要的语言页常数。
implementation
uses reinit;
const
ENGLISH = (SUBLANG_ENGLISH_UK shl 10) or LANG_ENGLISH;
CHINESE = (SUBLANG_CHINESE_SIMPLIFIED shl 10) or LANG_CHINESE;
{$R *.DFM}
做个初始化
procedure TForm1.FormCreate(Sender: TObject);
begin
mnuEnglish.Tag:=ENGLISH;
mnuChinese.Tag:=CHINESE;
end;
然后嘛(不就是菜单切换嘛)
于是把两了菜单都指到了一个地方
procedure TForm1.mnuLangClick(Sender: TObject);
begin
if LoadNewResourceModule(TComponent(Sender).Tag) <> 0 then
ReinitializeForms;
end;
呵呵;(90% over)
不会吧,让你step,你到现在都没说,就这么尽抄袭代码。Energy委屈的说,谁让
他是课代表的。想起当年是班里总课代表,我不做功课居然就没人做的年月,不禁
又是一阵感慨。
兄弟们还差10%,加油啊!
菜单[Project]-[Languages]-[Add...]
[Next>],选择中文(chs),英语(eng);(我只用了这两种语言);
[Next>],[Next>],[Next>],[Finsih],[Yes]
让你保存dpg时小心目录可能是chs,应该用上一级目录才好。
看到了吗,这是你可以修改所有的东西。别乱改。
其中有一些出错信息之类这里都后,放心改好了,改完后可以作为一个模板文件保留。
下次就不用改了。
请关闭吧!
现在可以看到你的project Manager中有3个项目,project1.exe,porject1.eng,project1.chs
后面两了是资源文件,你可以
1,双击project1.eng -- form1,然后修改一些东西。比如button1的caption="eng";改变一下它
的大小和字体。
2,双击project1.chs -- form1,然后修改一些东西。比如button1的caption="chs";改一下字体。
不过最好不要随意改动form的大小和位置!
选中project1.exe,设定为Activate;
然后(兄弟们99%了)
右键project1.chs--build;
右键project1.eng--build;
右键project1.exe--build;
run
噫,你会发现exe中的界面不起作用了。呵呵,系统自己自动选择了一个语言页嘛。
什么你不要自动,$#$%^%^&,[project]-[Languages]-[set Active];
对了如果要在调出那个grid方式修改的工具可以[view]-[Translation Manager];
好了好了,顺便付上我写了说明的reinit.pas文件其实好好看一下就知道还有更强大
的功能等着你利用呢!
语言页的常数在windows.pas里开始于行218;且
+-----------------------+-------------------------+
| Sublanguage ID | Primary Language ID |
+-----------------------+-------------------------+
15 10 9 0 bit
unit ReInit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms;
procedure ReinitializeForms; //重新设置form
function LoadNewResourceModule(Locale: LCID): Longint; // 调取新的语言资源
implementation
type
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;
// 调取新的语言资源 LCID为语言页;
function LoadNewResourceModule(Locale: LCID): Longint;
var
FileName: array [0..260] of char;
P: PChar;
LocaleName: array[0..4] of Char;
NewInst: Longint;
begin
GetModuleFileName(HInstance, FileName, SizeOf(FileName)); // 别紧张,只是取一下当前
// 的模块名,之所以如此是
// 由于可能本身是个dll。
GetLocaleInfo(Locale, LOCALE_SABBREVLANGNAME, LocaleName, SizeOf(LocaleName)); //取当前使的语言页
P := PChar(@FileName) + lstrlen(FileName); //指针运算而已 //可能是exe :-)
while (P^ <> '.') and (P <> @FileName) do Dec(P); //找到语言页资源文件的后缀
NewInst := 0;
Result := 0;
if P <> @FileName then // 如果找到
begin
Inc(P);
if LocaleName[0] <> #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 // 加载失败,使用原文件
LocaleName[2] := #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;
//重新设置在显示中的所有from,;
procedure ReinitializeForms;
var
Count: Integer;
I: Integer;
Form: TForm;
begin
Count := Screen.FormCount;
for I := 0 to Count - 1 do
begin
Form := Screen.Forms[I];
ReloadInheritedComponent(Form, TForm); //重新刷新所有元件几其父对象
end;
end;
end.
////////////////////////////////
用Delphi 5的Integrated Translation Environment (ITE)可以轻易得完成这个工作。
我们创建一个示意性的工程MultiLanguage, 在Form上放一个Label和一个Button, 分别把Caption赋值为“English Label” 和“English Button”。
选择菜单Project|anguages|Add ..., Delphi显示Add Languages对话框, 选择Next。
从语言列表中选中“英语(美国)” 和“中文(中国)”, 选择Next。
ITE会根据所选的语言创建子目录,目录名称是语言的缩写,选择Next。
第一次增加语言时, Update Mode固ㄎ狢reate new, 选择Next。
选择Finish。
Delphi会自动创建支持不同语言的资源动态库。
Delphi还会自动创建一个工程组, 其中包括原有的MultiLanguages.EXE, 还包括新建的两个资源动态库 (MultiLanguages.enu, MultiLanguages.chs)。 保存工程组。
Delphi启动Translation Manager, 左边是需要翻译的语言, 右边是完成百分比。
选择“中文(中国)”|Forms|Unit1, 在右边第15行和20行填写翻译后的中文。 保存并关闭。
打开Project Manager, 编译MultiLanguages.enu和MultiLanguages.chs, Delphi会在相应的子目录生成资源动态库, 但后缀不是DLL而是ENU和CHS。
且说Energy受命之后,在Delphi5前苦苦讨教,这才发觉delphi5的技术比他
想象的还厉害,不禁冷汗直流:如果有什么闪失哪里逃得过这里大狭们的眼
睛啊。不由之间身形已经端了5尺。
Energy颤颤危危的New了一个Application,保存慌忙之间居然没起名字,
凭经验应该叫project1;然后放了一个菜单,一个按钮一个label,不禁暗自
思量到。在多国这够说明问题了吧。
想到CJ不觉在菜单的第一项中填下了caption=CJ,name=mnuChinese;呵呵,
既然有CJ也该有Energy,于是另一项中填下了 caption=Energy,name=mnuEnglish;
然后怎么办???
心中无限惶恐的Energy 调出了delphi的例子Demos\Richedit又看了看,立马又
气粗起来。呵呵,有一样好东西,可是让我可以省事不少,不禁又是一阵得意。
(Energy悄悄地把Demos\Richedit\reinit.pas往自己project目录一拷,在
project中又把它加了进来,自言自语道:50% over)
按他的意思先设置一下需要的语言页常数。
implementation
uses reinit;
const
ENGLISH = (SUBLANG_ENGLISH_UK shl 10) or LANG_ENGLISH;
CHINESE = (SUBLANG_CHINESE_SIMPLIFIED shl 10) or LANG_CHINESE;
{$R *.DFM}
做个初始化
procedure TForm1.FormCreate(Sender: TObject);
begin
mnuEnglish.Tag:=ENGLISH;
mnuChinese.Tag:=CHINESE;
end;
然后嘛(不就是菜单切换嘛)
于是把两了菜单都指到了一个地方
procedure TForm1.mnuLangClick(Sender: TObject);
begin
if LoadNewResourceModule(TComponent(Sender).Tag) <> 0 then
ReinitializeForms;
end;
呵呵;(90% over)
不会吧,让你step,你到现在都没说,就这么尽抄袭代码。Energy委屈的说,谁让
他是课代表的。想起当年是班里总课代表,我不做功课居然就没人做的年月,不禁
又是一阵感慨。
兄弟们还差10%,加油啊!
菜单[Project]-[Languages]-[Add...]
[Next>],选择中文(chs),英语(eng);(我只用了这两种语言);
[Next>],[Next>],[Next>],[Finsih],[Yes]
让你保存dpg时小心目录可能是chs,应该用上一级目录才好。
看到了吗,这是你可以修改所有的东西。别乱改。
其中有一些出错信息之类这里都后,放心改好了,改完后可以作为一个模板文件保留。
下次就不用改了。
请关闭吧!
现在可以看到你的project Manager中有3个项目,project1.exe,porject1.eng,project1.chs
后面两了是资源文件,你可以
1,双击project1.eng -- form1,然后修改一些东西。比如button1的caption="eng";改变一下它
的大小和字体。
2,双击project1.chs -- form1,然后修改一些东西。比如button1的caption="chs";改一下字体。
不过最好不要随意改动form的大小和位置!
选中project1.exe,设定为Activate;
然后(兄弟们99%了)
右键project1.chs--build;
右键project1.eng--build;
右键project1.exe--build;
run
噫,你会发现exe中的界面不起作用了。呵呵,系统自己自动选择了一个语言页嘛。
什么你不要自动,$#$%^%^&,[project]-[Languages]-[set Active];
对了如果要在调出那个grid方式修改的工具可以[view]-[Translation Manager];
好了好了,顺便付上我写了说明的reinit.pas文件其实好好看一下就知道还有更强大
的功能等着你利用呢!
语言页的常数在windows.pas里开始于行218;且
+-----------------------+-------------------------+
| Sublanguage ID | Primary Language ID |
+-----------------------+-------------------------+
15 10 9 0 bit
unit ReInit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms;
procedure ReinitializeForms; //重新设置form
function LoadNewResourceModule(Locale: LCID): Longint; // 调取新的语言资源
implementation
type
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;
// 调取新的语言资源 LCID为语言页;
function LoadNewResourceModule(Locale: LCID): Longint;
var
FileName: array [0..260] of char;
P: PChar;
LocaleName: array[0..4] of Char;
NewInst: Longint;
begin
GetModuleFileName(HInstance, FileName, SizeOf(FileName)); // 别紧张,只是取一下当前
// 的模块名,之所以如此是
// 由于可能本身是个dll。
GetLocaleInfo(Locale, LOCALE_SABBREVLANGNAME, LocaleName, SizeOf(LocaleName)); //取当前使的语言页
P := PChar(@FileName) + lstrlen(FileName); //指针运算而已 //可能是exe :-)
while (P^ <> '.') and (P <> @FileName) do Dec(P); //找到语言页资源文件的后缀
NewInst := 0;
Result := 0;
if P <> @FileName then // 如果找到
begin
Inc(P);
if LocaleName[0] <> #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 // 加载失败,使用原文件
LocaleName[2] := #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;
//重新设置在显示中的所有from,;
procedure ReinitializeForms;
var
Count: Integer;
I: Integer;
Form: TForm;
begin
Count := Screen.FormCount;
for I := 0 to Count - 1 do
begin
Form := Screen.Forms[I];
ReloadInheritedComponent(Form, TForm); //重新刷新所有元件几其父对象
end;
end;
end.
////////////////////////////////
用Delphi 5的Integrated Translation Environment (ITE)可以轻易得完成这个工作。
我们创建一个示意性的工程MultiLanguage, 在Form上放一个Label和一个Button, 分别把Caption赋值为“English Label” 和“English Button”。
选择菜单Project|anguages|Add ..., Delphi显示Add Languages对话框, 选择Next。
从语言列表中选中“英语(美国)” 和“中文(中国)”, 选择Next。
ITE会根据所选的语言创建子目录,目录名称是语言的缩写,选择Next。
第一次增加语言时, Update Mode固ㄎ狢reate new, 选择Next。
选择Finish。
Delphi会自动创建支持不同语言的资源动态库。
Delphi还会自动创建一个工程组, 其中包括原有的MultiLanguages.EXE, 还包括新建的两个资源动态库 (MultiLanguages.enu, MultiLanguages.chs)。 保存工程组。
Delphi启动Translation Manager, 左边是需要翻译的语言, 右边是完成百分比。
选择“中文(中国)”|Forms|Unit1, 在右边第15行和20行填写翻译后的中文。 保存并关闭。
打开Project Manager, 编译MultiLanguages.enu和MultiLanguages.chs, Delphi会在相应的子目录生成资源动态库, 但后缀不是DLL而是ENU和CHS。
#7
另外字符串的.res资源文件生成方法是
将下面存成文本文件,例如文件名为chinese.txt
STRINGTABLE
BEGIN
1,"确定"
2,"取消"
END
然后运行delphi\bin\brcc32.exe chinese.txt
编译后生成chinese.res
然后将该.res文件加在Dll工程中({$R chinese.res})编译就生成了资源Dll,可在主程序中调用
具体见http://crob.net/delphi/source/mutilan.zip
将下面存成文本文件,例如文件名为chinese.txt
STRINGTABLE
BEGIN
1,"确定"
2,"取消"
END
然后运行delphi\bin\brcc32.exe chinese.txt
编译后生成chinese.res
然后将该.res文件加在Dll工程中({$R chinese.res})编译就生成了资源Dll,可在主程序中调用
具体见http://crob.net/delphi/source/mutilan.zip
#8
To Crob:
我看了你的利用INI的,当场晕倒,你那样的是控件相关的,如果在窗体上面添加一个控件,就要修改代码!!!我以前也是这么做的,:(,后来发现太麻烦,因此就有了上面的过程,这样,你添加一个控件,不影响你的代码!:)。至于DLL的方式,我也知道,不过那样太麻烦。所以我倾向于用INI。
我看了你的利用INI的,当场晕倒,你那样的是控件相关的,如果在窗体上面添加一个控件,就要修改代码!!!我以前也是这么做的,:(,后来发现太麻烦,因此就有了上面的过程,这样,你添加一个控件,不影响你的代码!:)。至于DLL的方式,我也知道,不过那样太麻烦。所以我倾向于用INI。
#9
To kevin_gao:
这个方式:),也知道,我以前也采用过,还是太麻烦,而且更新有问题,界面比较闪烁,还有资源更新的问题,等等,我用过几种方法,还是发现用INI是最方便的。你只要翻译文字即可。:)
这个方式:),也知道,我以前也采用过,还是太麻烦,而且更新有问题,界面比较闪烁,还有资源更新的问题,等等,我用过几种方法,还是发现用INI是最方便的。你只要翻译文字即可。:)
#10
支持一下
#11
谁都认为自己的好,亲生的嘛。
#12
To hellion(恶人):
那倒不是,要不你自己用三种方式测试一下?其实用Delphi自带的资源DLL的方式是最好的,因为可以有事件处理,不过一般用不到。
那倒不是,要不你自己用三种方式测试一下?其实用Delphi自带的资源DLL的方式是最好的,因为可以有事件处理,不过一般用不到。
#13
大家都說得好,值得學習!
#14
这么长的代码,麻烦多写点注释吗?
#15
这么长的代码,多加点 注释
#16
Delphi自带的资源DLL的方式好像还不完善
有些控件例如listview就不能转换
有些控件例如listview就不能转换
#17
看了,存了~~
#18
good,very good;
#19
各位大侠,看看我的帖子
http://www.csdn.net/expert/topic/349/349276.shtm
对不起,占用了老版主的地盘
http://www.csdn.net/expert/topic/349/349276.shtm
对不起,占用了老版主的地盘
#20
这么好的贴子,我提一下
#21
该死!怎么无法给分了?
#22
啊哟,前辈万岁,高手万岁。
#23
啊哟,前辈万岁,高手万岁。
#24
要是我我不考虑用INI文件,我会做成RES文件,用LOADSTR()LOADCRU()等完成.
#25
关注~~关注~~~
看看~~看看~~
看看~~看看~~