首先向大家表示很抱歉自己写博不是很积极,两个原因,我不愿意转贴别人的东西,总想自己能有一点原创的研究心得贡献给大家,二是自己文笔很一般,大家看起来可能觉得枯燥无味。
我的研究点大部分是与自己做的或者要做的东西有关,所以有时候很羡慕万一老师能有大量时间研究自己感兴趣的东西,想当年自己也在大学作为老师混了一年啊,可惜最后还是沦落江湖中。
最近考虑的是软件多语言版在delphi中实现。从盒子下了一个古董的多语言程序原型。
Delphi2009本身增加了对多语言的支持,但大家对它的评价不高,我想更多的人还是喜欢用INI文件来解决这个问题。
读写INI文件就不说了,这里注意的是针对于不同系统要按对应语言编码保存INI文件,原来的例子只有中文和英文两个切换,而且都保存为GB2312编码了。这可能跟大多数人理解的多语言就是中英两种语言有关。为了试验,我增加了日语。
另外为了感觉正规点,可以把ini的扩展名改成lng。这样就有了English.lng,Chinese.lng,Japanese.lng三个资源文件。
做实验的时候还考虑系统启动,比如刚开始显示logo的时候就能判断出用户正使用的操作系统,从而能自动切换显示正确的语言界面呢?答案是肯定的。
WINAPI里有一个SysLocale.PriLangID可以取得用户正使用的系统语言ID,但对于英语,汉语,阿拉伯语这些语言它还有不同的SubLangID,因为英语里面有美国英语,英国英语,加拿大英语等等,正常我们所说的英语就是美国英语,它的常量就是SUBLANG_ENGLISH_US,而汉语就更复杂了,有简体中文,繁体中文(台湾),繁体中文(香港)。例子中我们所指的汉语就是我们的简体中文,它的常量就是SUBLANG_CHINESE_SIMPLIFIED,日语就简单了,只有一种,所以用PriLangID判断即可。
判断好系统语言后,在FormShow的时候就设定显示语言。原例子是写在FormCreate中了,但实际运用中,经常有动态切换界面语言的场合,所以我觉得写在FormShow中更合理一些。
procedure TForm1.SetActiveLanguage(LanguageName:string); //LanguageName分别为"Chinese","Jpanese","English"。
const
Translations='Translations';
Messages='Messages';
var
frmComponent:TComponent;
i:Integer;
begin
with TInifile.Create(ExtractFilePath(ParamStr(0))+LanguageName+'.lng') do
begin
for i:=0 to ComponentCount-1 do
begin
frmComponent:=Components[i];
if frmComponent is TLabel then
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;
动态切换语言界面实现后,想到一个附带的界面设计问题。因为不同语言切换后字符串长度不同,因此界面设计的时候,最好提前考虑到界面显示的效果。比如显示成纵向的key-value形式。或者留足够的空间以适应不同语言的显示。对于开发桌面程序的人来说,一个好的UI设计是成功的一半。
写到这里才发现不能上传附件。
原代码请到盒子下载。
http://www.2ccc.com/article.asp?articleid=10
请用下面的Unit文件替换
--------------------------------------------------
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Menus, IniFiles;
Const
//ENGLISH = (SUBLANG_ENGLISH_US shl 10) or LANG_ENGLISH;
//CHINESE = (SUBLANG_CHINESE_SIMPLIFIED shl 10) or LANG_CHINESE;
//TCHINESE =(SUBLANG_CHINESE_TRADITIONAL SHL 10) OR LANG_CHINESE;
ENGLISH = SUBLANG_ENGLISH_US;
CHINESE = SUBLANG_CHINESE_SIMPLIFIED;
TCHINESE = SUBLANG_CHINESE_TRADITIONAL;
JAPANESE = LANG_JAPANESE;
type
TForm1 = class(TForm)
MainMenu1: TMainMenu;
File1: TMenuItem;
Exit1: TMenuItem;
Label1: TLabel;
Button1: TButton;
CheckBox1: TCheckBox;
CheckBox2: TCheckBox;
Button2: TButton;
Label2: TLabel;
ComboBox1: TComboBox;
Label3: TLabel;
procedure ComboBox1Change(Sender: TObject);
procedure Exit1Click(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure FormShow(Sender: TObject);
private
function SearchLanguagePack: TStrings;
procedure SetActiveLanguage(LanguageName: string);
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
M1:String;
implementation
{$R *.DFM}
function TForm1.SearchLanguagePack:TStrings;
var
ResultStrings:TStrings;
DosError:integer;
SearchRec:TsearchRec;
begin
ResultStrings:=TStringList.Create;
DosError:=FindFirst(ExtractFilePath(ParamStr(0))+'*.lng', faAnyFile, SearchRec);
while DosError=0 do
begin
{ 返回的文件名并去掉末尾的.ini字穪E}
ResultStrings.Add(ChangeFileExt(SearchRec.Name,''));
DosError:=FindNext(SearchRec);
end;
FindClose(SearchRec);
Result:=ResultStrings;
end;
procedure TForm1.SetActiveLanguage(LanguageName:string);
const
Translations='Translations';
Messages='Messages';
var
frmComponent:TComponent;
i:Integer;
begin
with TInifile.Create(ExtractFilePath(ParamStr(0))+LanguageName+'.lng') do
begin
for i:=0 to ComponentCount-1 do
begin
frmComponent:=Components[i];
if frmComponent is TLabel then
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;
procedure TForm1.ComboBox1Change(Sender: TObject);
begin
SetActiveLanguage(ComboBox1.Text);
end;
procedure TForm1.FormShow(Sender: TObject);
begin
If SysLocale.SubLangID=CHINESE then
begin
SetActiveLanguage('Chinese');
end
Else
If SysLocale.PriLangID=JAPANESE then
begin
SetActiveLanguage('Japanese');
end
Else
If SysLocale.SubLangID=English then
begin
SetActiveLanguage('English');
end;
ComboBox1.Items.AddStrings(SearchLanguagePack);
end;
procedure TForm1.Exit1Click(Sender: TObject);
begin
Close;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(M1);
end;
end.
Japanese.lng的内容,注意保存为日语编码
----------------------------------------------------
[Translations]
;
Label1.Caption =文字1
Label2.Caption =文字2
Label3.Caption =言語
Button1.Caption =ボタン1
Button2.Caption =ボタン2
Button1.Hint =ボタン1_提示
Button2.Hint =ボタン2_提示
CheckBox1.Caption =チェックボックス1
CheckBox2.Caption =チェックボックス2
File1.Caption =ファイル
Exit1.Caption =終了
;
[Messages]
;
M1 =メッセージテスト

浙公网安备 33010602011771号