Jacktiger再学Delphi

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 :: 管理 ::

首先向大家表示很抱歉自己写博不是很积极,两个原因,我不愿意转贴别人的东西,总想自己能有一点原创的研究心得贡献给大家,二是自己文笔很一般,大家看起来可能觉得枯燥无味。

我的研究点大部分是与自己做的或者要做的东西有关,所以有时候很羡慕万一老师能有大量时间研究自己感兴趣的东西,想当年自己也在大学作为老师混了一年啊,可惜最后还是沦落江湖中。

最近考虑的是软件多语言版在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 =メッセージテスト

 

posted on 2009-11-22 18:51  Jacktiger再学Delphi  阅读(1723)  评论(0)    收藏  举报