![]() |
GnuGetText-Werkzeuge für Delphi |
Alle Strings, die in andere Sprachen übersetzt werden sollen, müssen im Quelltext so gekennzeichnet sein, dass sie von dxgettext beim Durchsuchen der Dateien eindeutig gefunden werden.
Texte, die in einem Formular definiert sind, wie z.B. Caption, Hint und Text werden von dxgettext automatisch erkannt. Im Quelltext der zugehörigen Unit muss die Funktion TranslateComponent (siehe unten) im OnCreate-Ereignis des Formulars angegeben werden.
Alle in einer Sektion resourcestring definierten Texte werden automatisch erkannt und
während der Laufzeit durch die jeweilige Übersetzung ersetzt.
Beispiel:
resourcestring msg = 'Hello, World'; ...
Zu übersetzende Strings müssen als Argument einer der folgenden Funktionen angegeben werden,
damit sie von dxgettext erkannt werden:
_(<string>), gettext(<string>) und dgettext(<domain><string>).
Die Funktionen sind in der Unit GnuGetText definiert.
Beispiele:
gettext('Hello, World'); // Textdefinition für die Standarddomäne "default" _('Hello, World'); // Kurzform der Funktion "gettext" dgettext('domain','Hello, World'); // wie "gettext" aber mit anderer Domäne ...
In der dpr-Datei des Projekts sind einige Ergänzungen erforderlich, wenn
neben der Standarddomäne default auch andere verwendet werden und, wenn
bestimmte Komponenten oder Klassen , wie z.B. TFont von der Übersetzung
ausgeschlossen werden sollen.
Beispiel:
program sample; uses GnuGetText in 'GnuGetText.pas', // enthält die unten aufgerufenen Funktionen Vcl.Forms, SampleMain in 'SampleMain.pas' {frmMerge}; begin TP_GlobalIgnoreClass(TFont); // Ausschluss von Klassen von der Übersetzung AddDomains(['delphi10','units']); // Definition zusätzlicher Textdomänen Application.Initialize; Application.MainFormOnTaskbar := True; Application.CreateForm(TfrmMain, frmMain); Application.Run; end.
Als erstes muss die Unit GnuGetText in der uses-Klausel angegeben werden, da in ihr die aufzurufenden Funktionen definiert sind. Je nach Bedarf kann dann vor der Initialisierung der Anwendung eine der folgenden Funktionen eingefügt werden:
Die Beschreibungen von weiteren möglichen Funktionen findet man in der ausführlichen englischen Beschreibung.
In Units, die ein Formular verwenden, müssen beim Erstellen die im Formular verwendeten Texte durch die jeweiligen Übersetzungen ersetzt werden. Dazu wird die Prozedur TranslateComponent im OnCreate-Ereignis des Formulars aufgerufen.
Beispiele:
procedure TMyForm.FormCreate (Sender: TObject); begin TranslateComponent (self); ... end; |
procedure TMyForm.FormCreate (Sender: TObject); begin TranslateComponent (self,'units'); ... end; |
Wenn die Unit GnuGetText, wie oben beschrieben, in die uses-Klausel
der Projekt-Datei eingebunden ist, wird bei ihrer Initialisierung (Programmabschnitt initialization)
automatisch die vom Benutzer im System eingestellte Anzeigesprache ermittelt und
als Standardsprache gespeichert. Wenn der Benutzer eine andere Sprache verwenden möchte,
kann er dies in der dpr-Datei vor der Anwendungsinitialisierung durch
Aufruf der Prozedur Uselanguage erreichen.
Beispiel:
program sample; uses GnuGetText in 'GnuGetText.pas', ... begin AddDomains(['delphi10','units']); UseLanguage('de'); ... end.
Zunächst muss die neue Sprache im GnuGetText-System registriert werden.
Dann muss für jedes verwendete Formular die Prozedur TranslateComponent
aufgerufen werden.
Beispiel:
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;
Die Übersetzungen können entweder aus den mo-Dateien beim Start des Programms geladen oder als Ressourcen in die exe-Datei eingebunden werden. Beide nachfolgend beschriebenen Verfahren erlauben, wenn mehrere exe-Dateien einer Projektgruppe die gleichen Übersetzungen verwenden, eine gemeinsame Benutzung.
Bei der Erstellung des Installationspakets ist darauf zu achten, dass bei der Installation des Programms exakt die im Nachfolgenden beschriebene Unterverzeichnisstruktur angelegt wird.
Sie ist ein wenig unübersichtlich und erklärt sich am besten durch
das nachfolgende Beispiel. Zunächst gibt es im Verzeichnis mit dem ausführbaren Programm
(exe-Datei) ein Unterverzeichnis locale. Darunter befindet sich
für jede unterstützte Sprache ein weiteres Unterverzeichnis, dessen Name dem
Kürzel nach ISO639 (z.B. de, es, it) entsprechen muss.
In jedem dieser sprachspezifischen Unterverzeichnisse gibt es dann ein weiteres
Unterverzeichnis LC_MESSAGES, in dem sich schließlich die mo-Dateien
(default.mo und evtl. die für weitere Textdomänen) mit den jeweiligen
Übersetzungen befinden.
Das nachfolgende Beispiel erläutert die Struktur:
<Exe-Verzeichnis>\ > locale\ > de\ > LC_MESSAGES\ > default.mo > delphi10.mo > es\ > LC_MESSAGES\ > default.mo > delphi10.mo ...
Dazu wird dem Delphi-Projekt eine Ressourcendatei hinzugefügt. Dies geschieht entweder mit Projekt ⇒ Dem Projekt hinzufügen... (Umsch+F11), wenn die rc-Datei bereits mit einem externen Editor erstellt wurde, oder es wird mit Datei ⇒ Neu ⇒ Weitere... die Objektgalerie geöffnet, um eine neue Ressource zu erstellen. Man wählt dort Textdatei und .rc - Ressourcendatei und gibt den erforderlichen Code im Delphi-Texteditor ein. Das Delphi-System fügt in beiden Fällen automatisch einen entsprechenden Eintrag in die dpr-Datei ein, so dass die Ressource automatisch bei jeder Compilierung aktualisiert und geladen wird.
Alle Einträge in der Ressourcendatei sind vom Typ RCDATA. Es werden folgende Bezeichner verwendet:
Dabei sind:
Beispiel:
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"
Wenn mehrere exe-Dateien einer Projektgruppe die gleichen Übersetzungen verwenden, genügt es diese rc-Datei (z.B. languages.rc) nur einmal zu erstellen und jedem Projekt der Gruppe hinzuzufügen.
Einige weitere Hilfsfunktionen stellt die Unit LangUtils.pas bereit:
Zur Initialisierung der Sprachenverwaltung wird in der dpr-Datei des Projekts die Funktion InitTranslation aufgerufen. Es gibt mehrere überladene Versionen:
Die Aufruf-Parameter haben folgende Bedeutung:
[Language] LangID=xx (z.B. de, en, etc.)
Die Funktion muss in der dpr-Datei des Projektes vor Application.Initialize aufgerufen werden. Sie lädt die erforderlichen Sprach-Ressourcen (entweder aus externen oder in eingebetteten mo-Dateien). Außerdem sucht sie in der o.g. cfg-Datei oder in der Befehlszeile (s.u.) nach einer voreingestellten Sprache. Wird keine dieser Einstellungen gefunden, wird die vom System verwendete Sprache ausgewählt.
Es wird geprüft, ob die Befehlszeile beim Aufruf des Programms die Option /la:xx enthält (xx ist der Zwei-Buchstaben-Code des Landes, z.B. de). Diese Einstellung hat Vorrang vor einer Sprachauswahl in der cfg-Datei.
Ein Programm-Menü (TMainMenu oder TPopupMenu) kann durch eine Liste der bereitgestellten Sprachen erweitert werden, so dass die Auswahl einer anderen Sprache einfach durch Klick auf einen dieser Menüeinträge erfolgt. Diese Liste wird in der jeweils ausgewählten Sprache angezeigt (s.u.). Die Unit LangUtils stellt dazu die Klasse TLanguageList zur Verfügung. In der Haupt-Unit sind dazu einige Ergänzungen erforderlich:
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;
Beispiel:
# 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 |
Der Ressourcen-Datei (s.o.) wird die Zeile IDR_LANGUAGES RCDATA "languages\\language.cfg" hinzugefügt. Der Aufbau dieser Datei ist im vorhergehenden Abschnitt (s.o.) beschrieben. Die Übersetzungen der Sprachbezeichner werden als mo-Dateien für die Text-Domäne LANGUAGES eingebunden. Entsprechend wird für jede der zu unterstützenden Sprachen in die Ressourcen-Datei eine Zeile mit dem Bezeichner IDR_TRANS_xx_LANGUAGES RCDATA eingefügt (xx = Zwei-Buchstaben-Code des Landes).
Beispiel:
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" ...