GNU Gettext for Delphi, C++ and Kylix

http://sourceforge.net/projects/dxgettext/

Description

GNU GetText translation tools for Borland Delphi and Borland C++ Builder

http://downloads.sourceforge.net/project/dxgettext/For%20Delphi%20and%20C%2B%2B%20Builder/1.2.2/dxgettext-1.2.2.exe

Bugfixes and improvements to gnugettext.pas

These changes are in the subversion repository on SourceForge.

使Delphi支持多语言的一种途径, 使用方法:

http://dybdahl.dk/dxgettext/docs/howto.php

How to do a translation

This document applies to the latest version.
If you haven't got the latest version, please download it now.

1) Modify your source code.

Add gnugettext.pas to your project.

Add gnugettext to the uses clause of all units that contains forms.

Add the following line to the OnFormCreate event of your forms:

TranslateComponent (self);

Add typical ignores just before the TranslateComponent (self) you put in the main form.

Typical ignores

These are typical ignores in a program when using TranslateProperties().
You can copy and paste from this page to your application.
Please note that only published properties of objects are subject to translation,
whereas properties that are private, protected or public are automatically ignored.

If you find something that is missing on this pages, don't hesitate to tell us.

VCL, important ones

TP_GlobalIgnoreClassProperty(TAction,'Category'); 
TP_GlobalIgnoreClassProperty(TControl,'HelpKeyword');
TP_GlobalIgnoreClassProperty(TNotebook,'Pages');

VCL, not so important

These are normally not needed.

TP_GlobalIgnoreClassProperty(TControl,'ImeName');
TP_GlobalIgnoreClass(TFont);

Database (DB unit)

Field names and table names often tend to have names that are also used for
other purposes elsewhere in the program. Therefore, it is very wise
to add this somewhere in your program if you are using databases.

TP_GlobalIgnoreClassProperty(TField,'DefaultExpression');
TP_GlobalIgnoreClassProperty(TField,'FieldName');
TP_GlobalIgnoreClassProperty(TField,'KeyFields');
TP_GlobalIgnoreClassProperty(TField,'DisplayName');
TP_GlobalIgnoreClassProperty(TField,'LookupKeyFields');
TP_GlobalIgnoreClassProperty(TField,'LookupResultField');
TP_GlobalIgnoreClassProperty(TField,'Origin');
TP_GlobalIgnoreClass(TParam);
TP_GlobalIgnoreClassProperty(TFieldDef,'Name');

MIDAS/Datasnap

TP_GlobalIgnoreClassProperty(TClientDataset,'CommandText');
TP_GlobalIgnoreClassProperty(TClientDataset,'Filename');
TP_GlobalIgnoreClassProperty(TClientDataset,'Filter');
TP_GlobalIgnoreClassProperty(TClientDataset,'IndexFieldnames');
TP_GlobalIgnoreClassProperty(TClientDataset,'IndexName');
TP_GlobalIgnoreClassProperty(TClientDataset,'MasterFields');
TP_GlobalIgnoreClassProperty(TClientDataset,'Params');
TP_GlobalIgnoreClassProperty(TClientDataset,'ProviderName');

Database controls

TP_GlobalIgnoreClassProperty(TDBComboBox,'DataField');
TP_GlobalIgnoreClassProperty(TDBCheckBox,'DataField');
TP_GlobalIgnoreClassProperty(TDBEdit,'DataField');
TP_GlobalIgnoreClassProperty(TDBImage,'DataField');
TP_GlobalIgnoreClassProperty(TDBListBox,'DataField');
TP_GlobalIgnoreClassProperty(TDBLookupControl,'DataField');
TP_GlobalIgnoreClassProperty(TDBLookupControl,'KeyField');
TP_GlobalIgnoreClassProperty(TDBLookupControl,'ListField');
TP_GlobalIgnoreClassProperty(TDBMemo,'DataField');
TP_GlobalIgnoreClassProperty(TDBRadioGroup,'DataField');
TP_GlobalIgnoreClassProperty(TDBRichEdit,'DataField');
TP_GlobalIgnoreClassProperty(TDBText,'DataField');

Interbase Express (IBX)

TP_GlobalIgnoreClass(TIBDatabase);
TP_GlobalIgnoreClass(TIBDatabase);
TP_GlobalIgnoreClass(TIBTransaction);
TP_GlobalIgnoreClassProperty(TIBSQL,'UniqueRelationName');

Borland Database Engine

TP_GlobalIgnoreClass(TSession);
TP_GlobalIgnoreClass(TDatabase);

ADO components

TP_GlobalIgnoreClass (TADOConnection);
TP_GlobalIgnoreClassProperty(TADOQuery,'CommandText');
TP_GlobalIgnoreClassProperty(TADOQuery,'ConnectionString');
TP_GlobalIgnoreClassProperty(TADOQuery,'DatasetField');
TP_GlobalIgnoreClassProperty(TADOQuery,'Filter');
TP_GlobalIgnoreClassProperty(TADOQuery,'IndexFieldNames');
TP_GlobalIgnoreClassProperty(TADOQuery,'IndexName');
TP_GlobalIgnoreClassProperty(TADOQuery,'MasterFields');
TP_GlobalIgnoreClassProperty(TADOTable,'IndexFieldNames');
TP_GlobalIgnoreClassProperty(TADOTable,'IndexName');
TP_GlobalIgnoreClassProperty(TADOTable,'MasterFields');
TP_GlobalIgnoreClassProperty(TADOTable,'TableName');
TP_GlobalIgnoreClassProperty(TADODataset,'CommandText');
TP_GlobalIgnoreClassProperty(TADODataset,'ConnectionString');
TP_GlobalIgnoreClassProperty(TADODataset,'DatasetField');
TP_GlobalIgnoreClassProperty(TADODataset,'Filter');
TP_GlobalIgnoreClassProperty(TADODataset,'IndexFieldNames');
TP_GlobalIgnoreClassProperty(TADODataset,'IndexName');
TP_GlobalIgnoreClassProperty(TADODataset,'MasterFields');

ActiveX stuff

TP_GlobalIgnoreClass (TWebBrowser);

TMS Software

It is not possible to read all string properties of TAdvStringGrid's subcomponents
without generating an exception. Therefore,
this class should not be handled by translateproperties().

TP_GlobalIgnoreClass (TAdvStringGrid);

2) Extract the text to be translated into .po files:

Click with the right mouse button on the file folder that contains your Delphi source code,
and choose "GG Extract translations to template".

This will create a file named default.po with all the texts to be translated.
Because it has no translations in it, it is named a "translation template".

3) Preparing the translation

If you haven't translated anything yet, copy your .po file to a subfolder and proceed to step 4).

If you have an old translation of your program, click with the right mouse button on that old translation,
and choose to "Merge template". Here, you must specify the .po file that was generated in step 2).
This will update your old .po file to contain the new texts, and it will remove unnecessary translations.

4) Translate the .po files with poedit

The easiest way to translate, is to install poedit. It is a free tool, so just get it and install it -
it is available for Windows, Macintosh and Linux. It is very easy to use,
and when you click the save button, it saves the .po file
but also automatically writes an .mo file each time.

5) Deploy your application like this:

The .mo file is a compact, binary file that is much faster for lookups than .po files.
It's the one you deploy with your application.

FileDescription
appdir/application.exe Your application
appdir/locale/da/LC_MESSAGES/default.mo Danish translations
appdir/locale/de/LC_MESSAGES/default.mo German translations
appdir/locale/de_AT/LC_MESSAGES/default.mo German translations for Austria

The directory names for the different languages are
either just the two-letter ISO 639 language code or
a combination of the ISO 639 language code and the ISO 3166 country code.

In the above example, if the program was running on a German computer,
it would first search for the de_DE directory, and then for the de directory because de_DE does not exist.

6) Consider to make a single-file version

You can avoid all the .mo files by including them inside your .exe file.
In order to do this, you must first make sure that the above works,
and then you right click the .exe file and choose "GG Embed translations":

This will append all the .mo files to the .exe file
in a way that makes the .exe file self-contained.

Important tips

  • If you did everything above, you will have translated all strings
    in your user interface and all resourcestrings.
    Using resourcestrings works great, but it works much better
    if you would consider to use the _() syntax instead.
  • GNU gettext is designed for translating English language programs to other languages.
    It is possible to translate from other languages, too,
    but then the program will be limited to run on computers
    that use the same character set in ansistrings. 

用GNU Gettext实现delphi多语言界面

http://www.360doc.com/content/12/1219/13/9200790_255069867.shtml

为了使程序能在不同的window版本中不乱码,可以使用delphi2010编写,已默认支持UNICODE。
而多语言界面,delphi 程序可借助GNU Gettext for Delphi and C++ Builder实现。
SVN中的版本确定可使用于delphi 2010, 源码注释中有
“$LastChangedDate: 2010-07-27 18:06:35 +0800 (星期二, 27 七月 2010)”字样就明白了。

sourceforge上的安装程序有点老,源码需要从SVN中check out出来,
但首先还是使用安装文件dxgettext-1.2.2.exe,它会在右键中增加菜单,
并且设置po文件的默认打开程序等,省去很多的麻烦。
之后将svn中的源码编译一遍,分别替换dxgettext-1.2.2.exe安装目录里的可执行程序。

大致步骤(只总结我使用到的,详细的可参照文档):

1. 将gnugettext.pas加入.dpr工程文件中
2. 设置使用的语言(在form显示之前,我放在.dpr中)
   UseLanguage(‘zh_CN’);
3. 启用翻译,我放在FormCreate中.
   TranslateComponent(self);
4. 右击源码目录,在菜单中选择生成po模板,
   使用poEdit做翻译,并编译为mo文件.
5. 最后的目录结构如下:
   rootDir/Hello.exe
          /locale/zh_CN/LC_MESSAGES/default.mo //中文语言包
          /locale/en/LC_MESSAGES/default.mo //英文语言包
6. 也可以比较变态地把*.mo直接打包进exe程序,很“清爽”。

不过打包工具需要从svn中获取源码重新编译,sourceforge上打包好的版本太老了。

Delphi使用xgettext支持多语言

http://hi.baidu.com/jhting/item/0fde24f86bbd65c20cd1c8c5

Delphi中使用xgettext 支持多语言

产品需要支持中文、英文,以前在python的一个项目中使用过GNU开发的xgettext这个开源的工具,
感觉还是很好用的,灵活也很好控制。所以打算在Delphi里也使用它来支持多语言。

下载dxgettext

在Delphi里同样有已经写好的一个开源的工具了 dxgettext.上网下载一个dxgettext,下载后只要引用其中的gnugettext.pas 文件即可.

我下载的gnugettext.pas 版本是Revision: 1.176.2.10. http://dybdahl.dk/dxgettext/ 是作者的主页.

Delphi工程中使用dxgettext

引用gnugettext.pas这个文件后,要使用dxgettext,开始有一些初始的设置,在工程dpr文件中设置,类似下面的.  

begin

  Application.Initialize;

  TP_GlobalIgnoreClass(TFont);  

  Application.CreateForm(TForm1, Form1);

  Application.Run;

End.

 

TP_GlobalIgnoreClass 指定那些类不会被翻译.
我们也可以指定具体的类的属性不被翻译:如:TP_Ignore (self, 'Listbox1.Items')

其它的可以看一下作者网页上的手册,有详尽的说明. 

在一个窗口中,如果有一些内容要翻译,那么在这个窗体创建时我们需要加入TranslateComponent 
这个过程,不然这个窗体的翻译不会生效.

像以下这样的:

procedure TfMain.FormCreate(Sender: TObject);

begin

  TranslateComponent(self);

End;

TranslateComponent会把指定的组件及其子组件都加到翻译的对像列表中.

也还有一些其它的方法可以加到翻译中去. 

基本就是这些工作,现在我们要窗口的按钮能支持多语言.可以这样定义tbutton的caption:

Button1.Caption := _('按钮测试');

就这样就OK了. 

做po文件和mo文件就和xgettext是一样的了.  

在运行目录下 locale\en\LC_MESSAGES 我创建了这样的目录,来保存英文mo文件

如po 文件内容

"Project-Id-Version: PACKAGE VERSION\n"

"POT-Creation-Date: 2012-04-12 12:58\n"

"PO-Revision-Date: 2012-04-16 09:41+0800\n"

"Last-Translator: \n"

"MIME-Version: 1.0\n"

"Content-Type: text/plain; charset=utf-8\n"

"Content-Transfer-Encoding: 8bit\n"

"X-Generator: dxgettext 1.2.2\n"

"Language-Team: \n" 

#. Programmer's name for it: dtlServerPage

#. Programmer's name for it: dtlOcxPage

#: PEAQENVRWebocx_TLB.pas:365

#: PEAQENVRWebocx_TLB.pas:367

msgid "按钮测试"

msgstr "Button test" 

这样我的窗口中的Button就有文件和中文的支持了.把po转成 mo文件.就完成了. 

Delphi中多语言切换

要切换语言使用 UseLanguage过程即可,如我要切换到英文 

UseLanguage('en'); 这样一句就行了

如果要切换回默认的

UseLanguage('default'); 即可.

如果实时多语言切换,问题来了,当我们这样切换时,窗口中的按钮呀什么的都没有刷新,
需要把窗口关闭\打开,才把语言更改过来.什么窗口.控件repain都不行.

我现在使用的方法是:

self.Hide;

self.Show;

把窗体隐藏,再显示,这样才能把语言刷新过来,不过这样用户也感觉不到有什么问题,
我的窗体hide,show里并不存在处理大的计算.

不知有没有更好的办法呢?

语言自定义的扩展

像我们使用的很多软件,有的用户都可以扩展其对语言的支持.

我需要做成这样的需求,如果新加一语言的支持,不用改程序,只要把语言文件mo放在安装的相应目录下即可.

我们在程序加载时读多语言文件的目录locale,遍历这个目录下的所有文件,在程序中动态创建一个子菜单,
这样用户可以选择一个语言,就切换到那种语言.

而新加一种语言的支持,我们只要在咯locale目录下创建一个对应的目录即可.

如何为你的程序添加多语支持

http://blog.sqlitedeveloper.com/content/

%E5%A6%82%E4%BD%95%E4%B8%BA%E4%BD%A0%E7%9A%84%E7%A8%8B%E5%BA%8F%E6%B7%BB%E5%8A%A0%E5%A4%9A%E8%AF%AD%E6%94%AF%E6%8C%81

有很多商业的程序可以用来添加多语支持,不过我觉得GNU GetText For Delphi比较简单好用。

下载一个GNU GetText For Delphi,安装后运行它的命令行工具dxgettext来提取用于翻译的字符串。

dxgettext -b c:\source\myprogram --delphi -r

上面命令执行后,会在myprogram目录下生成一个default.po文件。

然后执行msgmkignore来提取不需要翻译的字符串

msgmkignore default.po -o ignore.po

最后使用msgremove从翻译模板文件中删除不需要翻译的字符串。

msgremove default.po -i ignore.po -o output.po

之后,可以用免费的poEdit来翻译生成的output.po文件。 

翻译完之后,执行msgfmt output.po -o default.mo将po文件编译为MO文件。 

最后,在你的Delphi程序中引入gettext For Delphi的单元文件,调用其中的方法在运行时进行翻译,
这里就不展开说了,GNU GetText的文档中写得很清楚。

 

 

 

posted @ 2013-06-08 23:02  IAmAProgrammer  阅读(1195)  评论(0编辑  收藏  举报