|
|
GnuGetText tools for Delphi |
All strings that are to be translated into other languages must be marked in the source text so that they can be clearly found by dxgettext when scanning the files.
Texts that are defined in a form, such as Caption, Hint and Text, are automatically recognized by dxgettext. The TranslateComponent function (see below) must be specified in the OnCreate event of the form in the source code of the associated unit.
All texts defined in a resourcestring section are automatically recognized
and replaced by the respective translation during runtime.
Example:
resourcestring
msg = 'Hello, World';
...
Strings to be translated must be specified as an argument of one of the following
functions so that they are recognized by dxgettext:
_(<string>), gettext(<string>) and dgettext(<domain><string>).
The functions are defined in the unit GnuGetText.
Examples:
gettext('Hello, World'); // text definition for domain "default"
_('Hello, World'); // short form of function "gettext"
dgettext('domain','Hello, World'); // same as "gettext" but for another domain
...
Some additions are required in the project's dpr file if other than
the standard domain default are used and if certain components or classes,
such as TFont, are to be excluded from the translation.
Example:
program sample;
uses
GnuGetText in 'GnuGetText.pas', // contains the functions called below
Vcl.Forms,
SampleMain in 'SampleMain.pas' {frmMerge};
begin
TP_GlobalIgnoreClass(TFont); // exclude classes from translation
AddDomains(['delphi10','units']); // define additional text domains
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TfrmMain, frmMain);
Application.Run;
end.
First, the GnuGetText unit must be specified in the uses clause, as the functions to be called are defined in it. If required, one of the following functions can then be inserted before the application is initialized:
Descriptions of other possible functions can be found in the detailed description.
In units that use a form, the texts used in the form must be replaced with the respective translations when the form is created. To do this, the TranslateComponent procedure must be called in the OnCreate event of the form.
Examples:
procedure TMyForm.FormCreate (Sender: TObject);
begin
TranslateComponent (self);
...
end;
|
procedure TMyForm.FormCreate (Sender: TObject);
begin
TranslateComponent (self,'units');
...
end;
|
If the GnuGetText unit is included in the uses clause of the project file
as described above, the user's display language of the system is automatically
determined during its initialization (program section initialization)
and saved as the default language. If the user wishes to use a different language,
this can be done in the dpr file before application initialization by
calling the Uselanguage procedure.
Example:
program sample;
uses
GnuGetText in 'GnuGetText.pas',
...
begin
AddDomains(['delphi10','units']);
UseLanguage('de');
...
end.
First, the new language must be registered in the GnuGetText system.
Then the TranslateComponent procedure must be called for each form used.
Example:
procedure ChangeLanguage (NewLangCode : LanguageString);
var
i : integer;
begin
UseLanguage(NewLangCode);
with Application do for i:=0 to ComponentCount-1 do if (Components[i] is TForm) then
ReTranslateComponent(Components[i]);
end;
The translations can either be loaded from the mo files when the program is started or integrated into the exe file as a resources. Both methods described below allow shared use if several exe files in a project group use the same translations.
When creating the installation package, make sure that the subdirectory structure described below is created exactly when installing the program.
This is somewhat convoluted and is best explained by the following
example. First of all, there is a subdirectory locale in the directory
with the executable program (exe file). Below this there is a further
subdirectory for each supported language, the name of which must correspond to
the abbreviation according to ISO639 (e.g. de, es, it).
In each of these language-specific subdirectories there is then a further subdirectory
LC_MESSAGES, which finally contains the mo files (default.mo and
possibly those for other text domains) with the respective translations.
The following example will clarify the structure:
<Exe directory>\
> locale\
> de\
> LC_MESSAGES\
> default.mo
> delphi10.mo
> es\
> LC_MESSAGES\
> default.mo
> delphi10.mo
...
To do this, a resource file is added to the Delphi project. This is done either with Project ⇒ Add to project... (Shift+F11) if the rc file has already been created with an external editor, or the object gallery is opened with File ⇒ New ⇒ More... to create a new resource. Select Text file and .rc resource file and enter the required code in the Delphi text editor. In both cases, the Delphi system automatically inserts a corresponding entry in the dpr file so that the resource is automatically updated and loaded each time the program is compiled.
All entries in the resource file are of type RCDATA. The following identifiers are used:
These are:
Example:
IDR_LANGUAGES RCDATA "languages\\language.cfg" IDR_TRANS_DE_LANGUAGES RCDATA "..\\Common\\Languages\\de\\languages.mo" IDR_TRANS_DE_DEFAULT RCDATA "languages\\de\\default.mo" IDR_TRANS_DE_DELPHI10 RCDATA "..\\Common\\Languages\\de\\delphi10.mo" IDR_TRANS_DE_DIALOGS RCDATA "..\\Common\\Languages\\de\\dialogs.mo" IDR_TRANS_DE_UNITS RCDATA "..\\Common\\Languages\\de\\units.mo"
If several exe files in a project group use the same translations, it is sufficient to create this rc file (e.g. languages.rc) only once and add it to each project in the group.
The LangUtils.pas unit provides some additional auxiliary functions:
To initialize the language management, the InitTranslation function is called in the project's dpr file. There are several overloaded versions:
The call parameters have the following meaning:
[Language]
LangID=xx (z.B. de, en, etc.)The function must be called in the dpr file of the project before Application.Initialize. It loads the required language resources (either from external or embedded mo files). Then, it searches for a preset language in the above-mentioned cfg file or in the command line (see below). If no of these settings is found, the language used by the system is selected.
The system checks whether the command line contains the /la:xx option when the program is called (xx is the two-letter code of the country, e.g. de). This setting has priority over a language selection in the cfg file.
A program menu (TMainMenu or TPopupMenu) can be extended by a list of the languages provided so that a different language can be selected simply by clicking on one of these menu items. This list is displayed in the selected language (see below). The LangUtils unit provides the TLanguageList class for this purpose. Some additions are required in the main unit:
interface
uses ..., LangUtils, ...
...
type
TMainForm = class(TForm)
...
private
...
Languages : TLanguageList;
procedure SetLanguageClick(Sender : TObject; Language : TLangCodeString);
...
end;
...
procedure TfrmMain.FormCreate(Sender: TObject);
begin
...
Languages:=TLanguageList.Create(PrgPath,LangName);
with Languages do begin
Menu:=itmLanguage;
LoadLanguageNames(SelectedLanguage);
OnLanguageItemClick:=SetLanguageClick;
end;
...
procedure TfrmMain.SetLanguageClick(Sender : TObject; Language : TLangCodeString);
begin
if not AnsiSameStr(SelectedLanguage,Language) then begin
Languages.SelectedLanguageCode:=Language;
ChangeLanguage(Language);
Languages.LoadLanguageNames(Language);
...
end;
end;
The application directory (exe file) contains a language.cfg file with the English names of the languages to be supported (see below, left column). The list may also contain entries for languages that are not yet supported but are intended for later expansion. They are identified at the beginning of the line by the "#" character to deactivate them. Corresponding files with the same name and the translated language designations are located in the same subdirectories as the mo files (LC_MESSAGES, see above). The two right-hand columns below contain examples. The "#" character does not need to be inserted here, as this is taken from the original English list.
Example:
# International language codes #da=Danish de=German en=English es=Spanish #fi=Finnish fr=French #hr=Croatian hu=Hungarian it=Italian nl=Dutch |
# German da=Dänisch de=Deutsch en=Englisch es=Spanisch fi=Finnisch fr=Französisch hr=Kroatisch hu=Ungarisch it=Italienisch nl=Holländisch |
# French da=Danois de=Allemand en=Anglais es=Espagnol fi=Finnois fr=Français hr=Croate hu=Hongrois it=Italien nl=Néerlandais |
The line IDR_LANGUAGES RCDATA“languages\\language.cfg” is added to the resource file (see above). The structure of this file is described in the previous section (see above). The translations of the language identifiers are included as mo files for the LANGUAGES text domain. Accordingly, a line with the identifier IDR_TRANS_xx_LANGUAGES RCDATA is added to the resource file for each of the languages to be supported (xx = two-letter code of the country).
Example:
IDR_LANGUAGES RCDATA "languages\\language.cfg" IDR_TRANS_DE_LANGUAGES RCDATA "..\\Common\\Languages\\de\\languages.mo" IDR_TRANS_FR_LANGUAGES RCDATA "..\\Common\\Languages\\fr\\languages.mo" ...