[gelöst] Resourcestring mit Enum verknüpfen

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

[gelöst] Resourcestring mit Enum verknüpfen

Beitrag von Michl »

Ein fröhliches Hallo,

ein Beispiel, was ich vor habe:

Code: Alles auswählen

type
  MainPages = (mpCurrentTasks, mpTasks, mpDates);
 
const
  SMainPages: array [Low(MainPages)..High(MainPages)] of TCaption = (
    'Current Tasks',
    'Tasks',
    'Dates');
 
resourcestring
  SCaptionCurrentTasks    = 'Current Tasks';
  SCaptionTasks           = 'Tasks';
  SCaptionDates           = 'Dates'; 
Wenn ich nun per i18n eine .po erstelle, werden die ResourceStrings in diese Datei geschrieben. Ich hatte gehofft, dass die TCaption-Konstanten ebenfalls mit eingefügt würden (da es bei Componenten geht). Dies funktioniert erstmal so nicht.

Der Hintergrund ist der, dass ich später weitere Enums hinzufügen will, doch möglichst nicht zu jedem Enum ein ResourceString per Hand zuordnen will.

Kann man irgendwie Enums mit Resourcestrings verknüpfen?
Was wären alternative Lösungen?

Danke

Michael
Zuletzt geändert von Michl am Di 29. Sep 2015, 20:33, insgesamt 1-mal geändert.

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: Resourcestring mit Enum verknüpfen

Beitrag von Michl »

Ich antworte mir mal selbst. Evtl. hat ja jemand anderes noch eine bessere Lösung?!

Man kann als erstes die Resourcestrings definieren und diese dann dem Array entsprechend den Enums zuordnen. So hat man zwar die Resourcestrings unabhängig der Enums und man muss mit der Zuordnung aufpassen, aber besser als gar keine Lösung:

Code: Alles auswählen

type
  MainPages = (mpCurrentTasks, mpTasks, mpDates);
 
resourcestring
  SCaptionCurrentTasks    = 'Current Tasks';
  SCaptionTasks           = 'Tasks';
  SCaptionDates           = 'Dates';
 
const
  SMainPages: array [Low(MainPages)..High(MainPages)] of string = (
    SCaptionCurrentTasks, SCaptionTasks, SCaptionDates);  

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

TBug
Beiträge: 179
Registriert: Mi 2. Sep 2015, 11:09
OS, Lazarus, FPC: Lazaurus 2.2.4 FPC 3.2.2
CPU-Target: Windows 32/64bit

Re: Resourcestring mit Enum verknüpfen

Beitrag von TBug »

Hast Du einmal darüber nachgedacht eine Hash-Table zu verwenden und als Grundlage zur Verknüpfung den String des Enums zu nehmen, da Du dann auch zum Auffinden des "Übersetzungstextes" zur Programmlaufzeit aus dem Enum-Wert den "Enum-String" ja problemlos ermitteln kannst?

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: Resourcestring mit Enum verknüpfen

Beitrag von Michl »

Mir geht es hauptsächlich darum, Captions für dynamisch erstellte Controls möglichst einfach speichern zu können. Dabei ist mein Hauptproblem, dass wenn ich z.B. in einem halben Jahr später ein Enum hinzufüge, ich nicht vergesse, irgendwo eine Zuweisung zu machen bzw. suchen muss, wo ich diese Zuweisung vornehme. Wenn die Captions bzw. Strings wie oben gepostet zugewiesen werden, ist das mMn recht übersichtlich.

Zur Übersetzung später auffinden brauche ich die Enums bzw. Strings nicht (auch nicht zur Laufzeit), das macht die LCL alles automatisch - finde ich toll! Siehe http://wiki.freepascal.org/Translations ... r_programs. Daher denke ich, hilft mir eine Hash-Tabelle hier nicht wirklich weiter oder ich habe dich falsch verstanden.

Danke auf jeden Fall fürs Mitdenken! Und falls du denkst, dass eine Hashtabelle doch die bessere Wahl ist, dann kannst du mich evtl. auch noch erleuchten und den Vorschlag mit ein wenig (Pseudo)Code untermauern :idea:

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

TBug
Beiträge: 179
Registriert: Mi 2. Sep 2015, 11:09
OS, Lazarus, FPC: Lazaurus 2.2.4 FPC 3.2.2
CPU-Target: Windows 32/64bit

Re: Resourcestring mit Enum verknüpfen

Beitrag von TBug »

Michl hat geschrieben:Zur Übersetzung später auffinden brauche ich die Enums bzw. Strings nicht (auch nicht zur Laufzeit), das macht die LCL alles automatisch
Für was ist denn die Deklaration des Enums denn überhaupt da, wenn es zur Laufzeit dann doch nicht gebraucht wird?

Mach' mal ein kleines Beispiel, damit der Sinn des Enum's überhaupt ersichtlich wird, ausser bei der Erstellung des Arrays SMainPages.

.

wp_xyz
Beiträge: 5153
Registriert: Fr 8. Apr 2011, 09:01

Re: Resourcestring mit Enum verknüpfen

Beitrag von wp_xyz »

Lazarus ist voll von solchen Beispielen. Nimm TFontStyle aus der Graphics-Unit. Hier werden die möglichen Font-Stile aufgezählt: fett, kursiv, unter/-durchstrichen. Wenn du den Wert des akuellen Font-Stils auf der Benutzeroberfläche anzeigen willst, musst du jedem Enum-Element einen String zuordnen. Und wenn du später einmal vielleicht ein neues Enum-Element einführt (z.b. fsSubscript, fsSuperscript), muss auch der beschreibende String aktualisiert werden.

TBug
Beiträge: 179
Registriert: Mi 2. Sep 2015, 11:09
OS, Lazarus, FPC: Lazaurus 2.2.4 FPC 3.2.2
CPU-Target: Windows 32/64bit

Re: Resourcestring mit Enum verknüpfen

Beitrag von TBug »

wp_xyz hat geschrieben:Lazarus ist voll von solchen Beispielen. Nimm TFontStyle aus der Graphics-Unit. Hier werden die möglichen Font-Stile aufgezählt: fett, kursiv, unter/-durchstrichen. Wenn du den Wert des akuellen Font-Stils auf der Benutzeroberfläche anzeigen willst, musst du jedem Enum-Element einen String zuordnen. Und wenn du später einmal vielleicht ein neues Enum-Element einführt (z.b. fsSubscript, fsSuperscript), muss auch der beschreibende String aktualisiert werden.
Wenn ich ein Enum habe

Code: Alles auswählen

TMyEnum =  (myEnum1, myEnum2, MyEnum3);
dann brauch ich aber nicht unbedingt einen zusätzlichen String, welcher mir die Einstellung anzeigt, denn ich kann mir ja den String des Enumwertes zurückgebenlassen.

Also wenn :

Code: Alles auswählen

 
var
  lEnumValue: TMyEnum;
begin
  lEnumValue := myEnum2;
end;
 
Aus lEnumValue kann ich mir den String zurückgeben lassen, welcher dem jetzigen Wert entspricht. Hier also den String "myEnum2" und diesen der Caption zuweisen. Dies verwende ich immer wenn ich Enums habe und eine entsprechende Auswahl in einer Combobox zur Verfügung stellen möchte.

Genauso kann ich wenn ich einen String habe "myEnum2" den Enumwert des Typs TMyEnum ermitteln und diesem dann lEnumValue zuweisen.

Alles ohne einen einzigen weiteren String besitzen zu müssen.
Daher meine Frage, was mit dem Enum überhaupt geschehen soll.

wp_xyz
Beiträge: 5153
Registriert: Fr 8. Apr 2011, 09:01

Re: Resourcestring mit Enum verknüpfen

Beitrag von wp_xyz »

Das einzige, wie man sich die separaten Strings sparen kann, ist den String direkt aus dem Enum abzuleiten via "GetEnumName" (http://www.freepascal.org/docs-html/rtl ... value.html) - ich nehme an, das meinst du. Aber es könnte ja sein, dass der so generierte String nicht "schön" genug für die Benutzeroberfläche ist. Z.B. aus der Unit Math: tpaymenttime = (ptendofperiod,ptstartofperiod) - was hälts du davon, wenn "ptendofperiod" und "ptstartofperiod" in einer Combobox stehen? Besser wären doch "End of period" bzw "Start of period"? Und Michl will's ja eigentlich auch übersetzen können (daher der "resourcestring"), also muss auch die Möglichkeit bestehen, "Ende der Periode" und "Beginn der Periode" in der Combobox verwenden zu können.

TBug
Beiträge: 179
Registriert: Mi 2. Sep 2015, 11:09
OS, Lazarus, FPC: Lazaurus 2.2.4 FPC 3.2.2
CPU-Target: Windows 32/64bit

Re: Resourcestring mit Enum verknüpfen

Beitrag von TBug »

wp_xyz hat geschrieben:Und Michl will's ja eigentlich auch übersetzen können (daher der "resourcestring"), also muss auch die Möglichkeit bestehen, "Ende der Periode" und "Beginn der Periode" in der Combobox verwenden zu können.
Das ist ja schon alles klar aber:

Damit die Zuweisung einen Sinn macht muss er ja irgendwo in seinem Programm auf das Enum zugreifen.
Und da wollte ich ja genau wissen, wo er das Enum nochmals benutzt.

Er muss ja so etwas in der Art haben:

Code: Alles auswählen

 
Caption := SMainPages[Ord(mpTasks)];
 
Oder eben etwas anderes.

Und nur wenn man weiß, wie er aus seinem "Enum einen String" macht, kann man auch eventluell andere Lösungsvorschläge konkretisieren.

.

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: Resourcestring mit Enum verknüpfen

Beitrag von Michl »

TBug hat geschrieben:Damit die Zuweisung einen Sinn macht muss er ja irgendwo in seinem Programm auf das Enum zugreifen.
Und da wollte ich ja genau wissen, wo er das Enum nochmals benutzt.
Mir geht es wie oben geschrieben um Captions von dynamisch erstellten Controls (in meinem Fall TTabSheets). Die Enums dienen mir zur Laufzeit dann nur zur Definition, welches Seite sichtbar ist bzw. bearbeitet werden soll (FCurrentPage).

Die Captions weise ich so zu:

Code: Alles auswählen

procedure InitMainPages;
var
  Page: TMainPages;
  aTabSheet: TTabSheet;
begin
  for Page := Low(TMainPages) to High(TMainPages) do begin
    aTabSheet := PageControl1.AddTabSheet;
    aTabSheet.Caption := SMainPages[Page];
  end;
end;  
Da ich mir immer Minimalbeispiel erstelle um testen, was ich vorhabe, dieses anbei.

Wer Lust hat zu testen, einfach mal normal und mal mit Parameter "--lang fr", "--lang en" oder "--lang de" starten (auch einfach unter Start -> Startparameter einstellbar).

Irgendwie habe ich bei dem Minimalbeispiel allerdings wieder das Problem http://www.lazarusforum.de/viewtopic.php?f=19&t=9041 und ich weiss noch nicht wieso :(
Dateianhänge
OrganizerMinimal.zip
(7.96 KiB) 54-mal heruntergeladen

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

wp_xyz
Beiträge: 5153
Registriert: Fr 8. Apr 2011, 09:01

Re: Resourcestring mit Enum verknüpfen

Beitrag von wp_xyz »

Ich war in einem mehrsprachigen Projekt schon an derselben Baustelle und hatte mich eh gewundert, dass das mit dem array der Resourcestrings funktioniert.

Wenn du aber in dem Array Zeiger auf Strings verwendest, geht's. (Irgendwie müsste es auch mit PChar gehen, aber das habe ich nie hinbekommen).

Code: Alles auswählen

 
unit OrgaDefinitions;
// ....
type
  TMainPages = (mpCurrentTasks, mpTasks, mpDates);
  PString = ^string;      // <---- neu
 
resourcestring
  SCaptionCurrentTasks    = 'Current Tasks';
  SCaptionTasks           = 'Tasks';
  SCaptionDates           = 'Dates';
 
const
  SMainPages: array [Low(TMainPages)..High(TMainPages)] of Pstring = (   // <--- hier PString statt String
    @SCaptionCurrentTasks,    // <--- hier die Adressen eintragen
    @SCaptionTasks,
    @SCaptionDates);
 
---------------------
 
unit OrgMain;
//...
  procedure InitMainPages;
  var
    Page: TMainPages;
    aTabSheet: TTabSheet;
  begin
    for Page := Low(TMainPages) to High(TMainPages) do begin
      aTabSheet := PageControl1.AddTabSheet;
      aTabSheet.Caption := SMainPages[Page]^;    // <--- den Zeiger dereferenzieren
    end;
  end; 
 

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: Resourcestring mit Enum verknüpfen

Beitrag von Michl »

Verstehe ich dich richtig, bei dir geht mein Minimalbsp nicht???

[Edit] ...stimmt, wenn ich mein Minimalbsp unter 1.4.2 kompiliere geht es bei mir auch nicht unter 1.5 mit FPC 3.1.1 schon. Da gab es also eine Entwicklung im Trunc (evtl. hängt das ja mit den neuen Strings zusammen???) :)

Lt. diesem Thread gehe ich davon aus, dass es gewünscht ist, dass es funktioniert: http://borland.newsgroups.archived.at/p ... 15620.html

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

wp_xyz
Beiträge: 5153
Registriert: Fr 8. Apr 2011, 09:01

Re: Resourcestring mit Enum verknüpfen

Beitrag von wp_xyz »

Ich nehme normalerweise 1.5 und fpc 2.6.4. Das Beispielprogramm läuft, aber beim Start ohne "--lang" Parameter ist die Beschriftung der Tabs Englisch. Erst mit meiner Änderung wird sie Deutsch. Aber du hast recht, mit 1.5/3.1.1 ist alles auch ohne die Modifikation richtig.

TBug
Beiträge: 179
Registriert: Mi 2. Sep 2015, 11:09
OS, Lazarus, FPC: Lazaurus 2.2.4 FPC 3.2.2
CPU-Target: Windows 32/64bit

Re: Resourcestring mit Enum verknüpfen

Beitrag von TBug »

Den Sinn des Enums habe ich immer noch nicht begriffen.

Ich hätte das unter Berücksichtigung des von TE vorgegebenen Stils so gelöst:

Code: Alles auswählen

 
unit Unit1;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  ComCtrls;
 
resourcestring
  SCaptionCurrentTasks    = 'Current Tasks';
  SCaptionTasks           = 'Tasks';
  SCaptionDates           = 'Dates';
 
const
  SMainPages: array [0..2] of PString = (
    @SCaptionCurrentTasks,
    @SCaptionTasks,
    @SCaptionDates);
 
 
type
 
  { TForm1 }
 
  TForm1 = class(TForm)
    Button1: TButton;
    PageControl1: TPageControl;
    procedure Button1Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.lfm}
 
{ TForm1 }
 
procedure TForm1.Button1Click(Sender: TObject);
var
  lPage: Integer;
  lTabSheet: TTabSheet;
begin
  for lPage := Low(SMainPages) to High(SMainPages) do
   begin
    lTabSheet := PageControl1.AddTabSheet;
    lTabSheet.Caption := SMainPages[lPage]^;    // <--- den Zeiger dereferenzieren
   end;
end;
 
end.  
 
Durch den Verzicht auf das Enum wäre im ganzen Quellcode nur eine Stelle gewesen, welche erweitert werden müsste, wenn etwas Neues hinzukommt.

.

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: Resourcestring mit Enum verknüpfen

Beitrag von Michl »

Hallo TBug,

ich kann verstehen, dass sich der Sinn in diesem Minimalbeispiel nicht unbedingt erschließt. Dieses war hauptsächlich für mich zum testen, wie ich mein Programm aufbauen will. Dazu mache ich gern Tests, bevor ich mich dann an das eigentliche Projekt mache (war auch gut so, eigentlich wollte ich ein TTabControl statt einem TPageControl nehmen, dieses sieht auf meinem Rechner aber eher bescheiden aus).

Im allgemeinen nutze ich Enums gern um irgenwelche Zustände zu beschreiben. In diesem Fall soll im Enum gespeichert werden, welche Aufgabe gerade getan wird. Diese Angabe (das Enum) benötige ich für den LogThread, Fortschrittsanzeigen, Datenbankinitialisierung, alle möglichen Tools und eben für die Anzeige für den Benutzer (und dieses möglichst in Deutsch und Englisch).

Der Resourcestring ist für mich eher das i-Tüpfelchen und funktioniert ja auch :D

Viele Grüße

Michael

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

Antworten