Langine 1.02版 发布
返回 Back
相对上一个版本来说,1.02版添加了较多的东西。

首先是听取了网友“角落的青苔”的意见,为每个控件分别增设了LangStrByName系列函数 ,这样一来大家就不必非得要计算MD5值来作为字符串的名字了。

此外就是添加了设计时的辅助功能。
·为TSelectLanguageDialog添加了一个“Test Dialog”的菜单(与其他的Dialog控件一样);
·为TLanguageTerminal添加了一个“Retrieve Text” 菜单,点击后你可以看到本窗体的所有可视控件的标准文本属性。我想这个功能在你编写语言文件的时候会比较实用。如下图:
 
 
请点击这里下载Langine 1.02版!
 
Langine 1.01版 发布
返回 Back
本次的修改并不多,只是给 TLanguageTerminal 添加了一个 OnUpdate : TNotifyEvent 事件。该事件发生在语言终端完成对窗体的更新之后,用于通知用户处理一些需要手动更新的内容。

此外Langine不再自动记录所用到的字符串常量以节省内存,所以大家在使用Langine自动生成语言包的时候可能会发现所使用的字符串常量不再出现在生成好的文件里。对于这一点只好委屈各位手动将字符串常量添加到语言包中。

点击这里下载Langine 1.01版!
 
Langine应用程序多语言引擎 1.0
返回 Back
因为身在异国,有时候真的觉得为每种语言进行一次编译是一件非常痛苦的事情。而Borland本身的多语言引擎又很不争气,上上下下爬满了虫子……无奈之下只好根据自己的经验和需求做了一个。

新的引擎(姑且命名为Langine吧,取Language和Engine的词头词尾)其实并没有做很多的事情。翻译工作还是要您自己来做的,不过Langine能够帮您把翻译好的语言文件(目前采用一个Ini来存储)自动装载到您的应用程序中;也支持让用户在程序运行时切换语言。
 
控件一览:
 
使用说明:
由上面可以看到,Langine由三个控件组成。按照从左到右的顺序分别是:TLanguageTerminalTLanguageEngine 以及 TSelectLanguageDialog。除此之外,作为真正引擎核心而存在的接口 ILanguageEngine 您也应该有所了解。
 
TLanguageTerminal
顾名思义,TLanguageTerminal 是一个语言终端,用来显示和管理程序界面的语言。在一般的情况下,您只要将控件放置到您的窗体上即可。

控件属性
属性名称 类型
 AutoUpdate  Boolean
设置成True的时候,语言终端就能感知系统语言设置的变化并自动将当前窗体的切换成当前语言。
 LanguageEngine  TLanguageEngine
指向一个语言引擎控件。这样一来语言终端将能够把自己绑定在系统的第二套语言引擎上,具体方法见 TLanguageEngine 的说明。
 SectionPrefix  String
辅助指定本窗体在语言文件中的位置。一般来说,存储在语言文件中的文本是以父窗体的类名来进行归类的。您可以用这个属性来区分存储在不同模块中的同一类名的窗体(比如说存储在主程序和Dll中的同名窗体)。

例如:窗体的类名是 TForm1,那么一般说来该窗体的语言文本将被存储在 [TForm1] 的节内。假如您设置的 SectionPrefix 是 main,那么该窗体在语言文件中就被存在 [main.TForm1] 的节内。

TLanguageEngine
语言引擎控件一般情况下是内部全局语言引擎的一个外壳。通过它您可以方便的对内部真正的引擎核心进行设置。

控件属性
属性名称 类型
 SubDirectory  String
在默认的情况下,语言引擎会在可执行文件的当前目录下寻找所需要的语言文件。但是为了方便语言文件的管理,您也可以把这些文件放到当前目录的一个子目录下。

假如可执行文件的位置是 c:\myprogram\,您的 SubDirectory 设置是 languages。那么,语言引擎就会到 c:\myprogram\languages\ 去寻找所需要的文件。这一设置会影响下面的 TSelectLanguageDialog 的显示结果。
 Engine  ILanguageEngine
Engine 属性提供 TLanguageEngine 控件宿主的信息。它一般会指向一个全局的内部引擎核心。通常您并不需要这个属性。可是如果当您使用 OnGetLanguageEngine 来实现系统内的第二个引擎的时候,Engine 属性就能够让您知道该控件是寄生在哪一个内核实例之上。

TSelectLanguageDialog
像其它的对话框控件一样,您可以通过一个简单的 Execute 方法来让用户选择他的应用程序语言。

控件属性
属性名称 类型
 AutoUpdate  Boolean
设置成 True 的时候,控件将自动取得当前的语言设置并将用户选择的结果直接应用到系统中。设成 False 的时候,它只是简单的显示语言列表并加亮 Language 属性指定的语言,然后在用户选择后将结果存储在自己的 Language 属性中。您事后必须手动的将这个设置应用到系统中使其生效。
 LanguageEngine  TLanguageEngine
指向一个语言引擎控件。这样一来语言终端将能够把自己绑定在系统的第二套语言引擎上,具体方法见 TLanguageEngine 的说明。
 ShowAllLanguages  Boolean
当该属性被设置成 True 的时候,对话框会把所有的语言都列出来。当他被设成 False 的时候,对话框将只显示那些在语言引擎指定路径中存在的语言。
ShowLanguageIds Boolean
该属性是专门为了开发者而准备的。只是让您知道哪种语言对应的语言ID是多少而已。
Language TLanguageId
该属性只在运行时有效。您可以通过这个属性取得用户在对话框中选择的结果。
 
关于接口 ILanguageEngine
这一节的内容其实是最重要的一节,它将有助于您理解 Langine 的实现原理。因为尚处在开发中,所以并不是所有的方法都会一直有效的。蛋糕在这里只是说一下重要的几个部分。

1、关于内核的唯一性
ILanguageEngine 的接口实例将在第一次被引用的时候自动创建。之后在整个程序的运行中这一实例将一直存在,直至程序结束被自动释放掉。为了实现该实例的唯一性,我在 LangineHost 单元中导出了一系列的函数以使同一进程的其他模块也能够共享这个实例。

为了使各个模块能够方便的取得内核的实例。我在LangineIntf 单元中写了一个函数 GetGlobalLanguageEngine 来做这件事情。所以从使用的角度上说上您只要引用 LangineIntf 单元,您就能够取得这一实例,而不用关心它是在什么地方被实现的。

但是!!!函数 GetGlobalLanguageEngine 能够起作用的前提是主程序把 LangineHost 中的函数正确导出了。所以(这也许是您在 Langine 中唯一被迫要做的事情)请在主程序的随便某一个地方引用 LangineHost 单元,而在其他的模块(比如说 Dll )中不要引用它,当然在主窗体或者工程文件中都是个不错的主意。否则内核的实例将永远不会被自动创建。

2、几个重要的方法
function GetSource : WideString;
procedure SetSource(AValue : WideString);
property Source : WideString read GetSource write SetSource;
这两个方法使您能够操纵引擎内核读取某一个语言文件(该文件不一定要在默认的路径下)。并使得所在的路径成为默认的搜索路径。AValue的内容是一个文件名。
 
function GetSourcePath : WideString;
procedure SetSourcePath(AValue : WideString);
property SourcePath : WideString read GetSourcePath write SetSourcePath;
SourcePath属性能够设置引擎的默认搜索路径。该路径在您使用下面的 Language 属性进行语言切换的时候被自动引用。
 
function TryGetLanguageId(var ALanguageId : TLanguageId) : Boolean;
function GetLanguageId : TLanguageId;
procedure SetLanguageId(ALanguageId : TLanguageId);
property Language : TLanguageId read GetLanguageId write SetLanguageId;
函数 TryGetLanguageId 试图从当前语言文件中分辨出是哪一种语言来。所凭借的依据有两条:第一条是存储在语言文件 [default] 节中的 LanguageId 字段。第二则是语言文件的扩展名。如果语种信息无法取得,则函数返回False。

Language 属性能够让您很快的进行语言的设置。您可以配合 Windows API 的 GetUserDefaultLangID 取得当前操作系统的语言后将其赋给 Language 属性来将语言切换到当前的 Windows 系统语言。
 
function ILanguageEngine.LanguageString(ASection, AValue : WideString) : WideString;
function LangStr(AString : String) : String; overload;
function LangStr(ASection, AString : String) : String; overload;

function TLanguageEngine.LangStr(AString : String) : String; overload;
function TLanguageEngine.LangStr(ASection, AString : String) : String; overload;

function TLanguageTerminal.LangStr(AString : String) : String; overload;
function TLanguageTerminal.LangStr(ASection, AString : String) : String; overload;
在上面的方法中,ILanguageEngine 的 LanguageString 是其它所有方法的根源。它定义了一个引擎内部的字符串常量。其作用类似于原有的 resourcestring 关键字。您可以用它来定义一个所谓的“资源字符串”。

其实LanguageString 所作的事情并不多,它不过是把一个原文(由AString参数指定,通常是英文)映射成一个固定长度的字符串(我采用的是MD5),然后从给定或默认的节中读出该字符串对应的译文而已。所以您表面上看起来的是:您给出一个英文原文,然后函数返回的是一个已经翻译成当前语言的译文。

它们之间只有一些非本质的区别:
·LanguageString 是最基本的函数,另外的几个函数都直接或间接的调用了它,它读出由ASection指定的节中的译文。如果您没有指定ASection,那么引擎会自己指派一个节。这个节通常是 [resourcestring]。如果语言文件中没有该字符串的译文,那么函数将直接返回 AString。
·其后的两个 LangStr 函数是为了简化调用而存在的。它们调用的实际上是系统默认内核的实例的 LanguageString 方法。如果该实例不存在或者语言文件中并没有该字符串的译文,那么函数将直接返回 AString。
·TLanguageEngine 控件中的 LangStr 方法会自动把调用定向到它的宿主引擎上。鉴于该引擎实例往往是唯一的,所以这两个方法做的事情根上面的 LangStr 没有任何区别。
·TLanguageTerminal 控件中的 LangStr 方法实际上也是做同样的事情。只不过在您没有指定 ASection 的时候,该函数会采用控件所在的节来查找该字符串而不是一般情况下的 [resourcestring] 节。
 
下载链接:
2004.07.06 【Langine 测试版】本地下载
2004.07.07 【Langine 应用程序和语言文件范例】本地下载
解压后直接用文本编辑器打开其中的文件,相信大家很快就会一目了然的。
返回 Back