AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Delphi [Mehrsprachigkeit] String als Property/Eigenschaft verwenden
Thema durchsuchen
Ansicht
Themen-Optionen

[Mehrsprachigkeit] String als Property/Eigenschaft verwenden

Ein Thema von Partikelecho · begonnen am 23. Feb 2012 · letzter Beitrag vom 24. Feb 2012
Antwort Antwort
Partikelecho

Registriert seit: 2. Dez 2011
14 Beiträge
 
Delphi 6 Enterprise
 
#1

[Mehrsprachigkeit] String als Property/Eigenschaft verwenden

  Alt 23. Feb 2012, 08:29
Hallo Leute,

Meine Aufgabe ist es ein Konzept zu erstellen, mit dem ich Mehrsprachigkeit in verschiedene Anwendungen integrieren kann.

bisherige Funktionsweise:
- Die Übersetzungstexte befinden sich in einer Datenbanktabelle (TEXT_ID, TEXT_GERMAN, TEXT_ENGLISH, ...)
- weitere Tabellen enthalten einmal die Komponenten, die einen zu übersetzenden Text enthalten und einmal die Eigenschaften, die Übersetzungen enthalten können (Caption, Hint, Items, Text, ShortCut, ...)

So kann ich im Quellcode über eine Abfrage die nötigen Informationen herausziehen, um das Programm zu übersetzen:
1. Welche Sprache soll es sein
2. Welcher Text muss welcher Eigenschaft und welcher Komponente zugeordnet werden

Ich habe bisher alles soweit realisiert und Arbeite gerade an der Routine, die die neuen Captions etc. zuweisen soll.

Meine Frage:
Die Namen der Eigenschaften kommen als Strings, wie kann ich diese nun nutzen?
Bei Komponenten ist das ja einfach über FindComponent() machbar, aber bei Eigenschaften habe ich nichts konkretes gefunden außer man solle die "RTTI" bemühen - wozu ich auch nur unzureichende Anleitungen finde.

Wie gesagt, der Rest steht.
Ich habe eine Funktion, die eine Liste mit den Komponenten erstellt, die einen Übersetzungstext POTENTIELL halten können und diese wird mit dem Datenbankbestand an Komponenten, Eigenschaften und zugehörigen Texten abgeglichen.
Ihr sollt mir natürlich keinen Code vorschreiben.

Geändert von Partikelecho (23. Feb 2012 um 08:39 Uhr) Grund: Konkretisierung des Titels
  Mit Zitat antworten Zitat
Benutzerbild von s.h.a.r.k
s.h.a.r.k

Registriert seit: 26. Mai 2004
3.159 Beiträge
 
#2

AW: [Mehrsprachigkeit] String als Property/Eigenschaft verwenden

  Alt 23. Feb 2012, 08:42
Du nutzt Delphi 6 für deine Aufgabe? Wäre gut, das vorher zu wissen, da es ab Delphi 2010 eine wesentlich verbesserte RTTI gibt.
»Remember, the future maintainer is the person you should be writing code for, not the compiler.« (Nick Hodges)
  Mit Zitat antworten Zitat
Lemmy

Registriert seit: 8. Jun 2002
Ort: Berglen
2.381 Beiträge
 
Delphi 10.4 Sydney
 
#3

AW: [Mehrsprachigkeit] String als Property/Eigenschaft verwenden

  Alt 23. Feb 2012, 08:59
Hi,

warum machst Du es nicht, wie alle anderen auch? Text der nicht in den Komponenten steht sondern, z.b. für Fehlermeldungen verwendet werden soll als Resourcestring definieren:

Delphi-Quellcode:
resourcestring
  caText1='Hallo Welt';
das kommt in den Interface-Teil der entsprechenden Unit ggf. auch eine/mehrere spezielle Units machen die diese Konstanten halten. Dann kannst Du die Ressourcen entweder über ein eigenes Tool auslesen und übersetzen oder mit entsprechenden kommerziellen Tools. Die Texte von Komponenten usw. kannst Du über die Resourcen auch direkt ändern.

WEnn Du es mit deinem Weg weiter machen willst und noch Delphi 6 verwendest, dann schau dir mal die Unit TypInfo an, das Tutorial zeigt dir grob die Verwendung der alten RTTI. Wenn Du hauptsächlich visuelle Komponenten übersetzen willst, reicht diese aus, da die Texte in den mir bekannten Komponenten alle als published deklariert sind, was für die alte RTTI schlicht notwendig ist.

Grüße
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.343 Beiträge
 
Delphi 11 Alexandria
 
#4

AW: [Mehrsprachigkeit] String als Property/Eigenschaft verwenden

  Alt 23. Feb 2012, 11:50
Du könntest mal hier nachlesen:
http://www.delphipraxis.net/103865-m...3D-123%3B.html
http://www.delphipraxis.net/102953-b...genschaft.html

Für eine spätere Lokalisierung habe ich mir allerdings tsilang vorgemerkt. Das scheint mir sehr komfortabel zu sein.
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
Benutzerbild von Bummi
Bummi

Registriert seit: 15. Jun 2010
Ort: Augsburg Bayern Süddeutschland
3.470 Beiträge
 
Delphi XE3 Enterprise
 
#5

AW: [Mehrsprachigkeit] String als Property/Eigenschaft verwenden

  Alt 23. Feb 2012, 12:00
Datenbankbasiert hätte ich folgendes anzubieten:

Delphi-Quellcode:
procedure TTemplate.Translate;
begin
{$IFDEF WriteTrans}
  WriteRTTITranslation(Self,Self.Classname,'');
{$ELSE}
  ReadRTTITranslation(DM.ADSLang, Self, 'D'); // anpassen auf Variable
{$ENDIF}
end;






unit Translation;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DB, ADODB, StdCtrls, TypInfo, ComCtrls, Menus;

  Procedure ReadRTTITranslation(Lang: TAdoDataset; TheForm: TForm; const Language: String);
  procedure ReadResourceTrans(Lang:TadoDataset;Const Language:String);
  Procedure WriteRTTITranslation(TheOwner:TComponent;const TheOwnerString,TheSubOwner:String);
  procedure WriteResourceTrans;

implementation

uses
  DMp, ConstsAndGlobals;


Procedure WriteRTTI(Const Owner,Comp,Prop,Value:String;IsTStrings:Boolean);
begin
  if not DM.AC.Connected then
    Exit;
  if Pos('..',Comp)=0 then
    DM.AC.Execute('P_AddUpdateFormLanguageValues '+QuotedStr(C_APPName)+','+
        QuotedStr(Owner)+','+QuotedStr(Comp)+','+QuotedStr(Prop)+','+IntToStr(Integer(IsTStrings))+','+QuotedStr(Value));
end;


Procedure ReadRTTITranslation(Lang: TAdoDataset; TheForm: TForm; const Language: String);
var
  TheComp : TComponent;
  CN,CNP : String;
  PropInfo : PPropInfo;
  cap,Prop : String;
begin
  if not Lang.Connection.Connected then Exit;

  Lang.Close;
  Lang.Parameters.ParamByName('Application').Value:=C_APPName;
  Lang.Parameters.ParamByName('FormClassName').Value:=TheForm.ClassName;
  Lang.Parameters.ParamByName('Language').Value:=Language;
  Lang.Open;
  While not Lang.Eof do
  begin
    TheComp := TheForm;
    try
    CN:=Lang.FieldByName('ComponentName').asString;

    if Length(CN)>0 then
      begin
        While (Pos('.',CN)>0) and Assigned(TheComp) do
          begin
          CNP:=Copy(CN,1,pos('.',CN)-1);
          CN:=Copy(CN,pos('.',CN)+1,Length(CN));
          if Pos('*',CNP)>0 then TheComp:=TheComp.Components[StrToInt(Copy(CNP,2,Length(CNP)))]
          else TheComp:=TheComp.FindComponent(CNP);
          end;
        if Assigned(TheComp) then
          begin
          if Pos('*',CN)>0 then TheComp:=TheComp.Components[StrToInt(Copy(CN,2,Length(CN)))]
          else TheComp:=TheComp.FindComponent(CN);
          end;
      end;
    IF Assigned(TheComp) then
      begin
        if Lang.FieldByName('IsClassType').asBoolean then
          begin
          PropInfo := GetPropInfo(TheComp,Lang.FieldbyName('Property').Value);
          if Assigned(PropInfo) then
            begin
            try
            if (not (TheComp is TMainMenu)) and (not (TheComp is TPopupMenu)) and (not (TheComp is TPageControl)) then //and ((not ((TheComp is TDBRadioGroup) or (TheComp is TRadioGroup)))) then
            TStrings(GetOrdProp(TheComp,PropInfo)).Text:=Lang.FieldbyName('Value').Value;
            except
              ON E:Exception do MessageDLG( E.Message+#13#10+TheComp.Name + ' - ' + Lang.FieldbyName('Property').Value,mtError,[mbok],0);
            end;
            end;
          end
        else
          begin
          cap:= Lang.FieldbyName('Value').Value;
          Prop:=Lang.FieldbyName('Property').Value;
          SetPropValue(TheComp,Lang.FieldbyName('Property').Value,Lang.FieldbyName('Value').Value);
          end;
      end;
    except
     ON E:Exception do
      MessageDLG( E.Message+#13#10+TheComp.Name + ' - ' + Lang.FieldbyName('Property').Value,mtError,[mbok],0);
    end;
    Lang.Next;
    end;

end;


procedure ReadResourceTrans(Lang:TadoDataset;Const Language:String);
const
  C_Resources='RESOURCE';
  Procedure SetIfFind(Const vname:String;Var Vari:String);
    begin
    if Lang.Locate('ComponentName',vname,[]) then Vari:=Lang.Fieldbyname('Value').Value;
    end;
begin
// G_Language:=Language;
  if not Lang.Connection.Connected then Exit;
  Lang.Close;
  Lang.Parameters.ParamByName('Application').Value := C_APPName;
  Lang.Parameters.ParamByName('FormClassName').Value := C_Resources;
  Lang.Parameters.ParamByName('Language').Value := Language;
  Lang.Open;
  {$I SetIfFind.txt}
end;


Procedure WriteRTTITranslation(TheOwner:TComponent;const TheOwnerString,TheSubOwner:String);
Type
TParseValues=Array [0..5] of String;
Const
// properities which are interesting for translation
ParseValues:TParseValues=('Caption','Hint','DisplayLabel','Text','Lines','Items');
var
  PropInfo: PPropInfo;
  i,j:Integer;
  pv,TheComp,SB:String;
  isTStrings:Boolean;
begin
  if Length(TheSubOwner)=0 then // collect properties of the form
    begin
      for j:=0 to High(ParseValues) do
              begin
              isTStrings:=false;
              PropInfo := GetPropInfo(TheOwner.ClassInfo,ParseValues[j]);
              if Assigned(PropInfo) then
                 begin
                     if PropType(TheOwner,ParseValues[j])=tkClass then
                       begin
                       if (TPersistent(GetOrdProp(TheOwner,PropInfo)) is TStrings) then PV:=TStrings(GetOrdProp(TheOwner,PropInfo)).Text;
                       isTStrings:=True;
                       end
                     else pv:=GetPropValue(TheOwner,ParseValues[j],false);
                     if length(PV)>0 then
                        begin
                        WriteRTTI(TheOwnerString,'',ParseValues[j],pv,isTStrings);
                        end;

                 end;
              end;
    end;
  For i:=0 to TheOwner.ComponentCount-1 do // collect properties of components and subcomponents of the form
      begin
          begin
          for j:=0 to High(ParseValues) do
              begin
              isTStrings:=false;
              PropInfo := GetPropInfo(TheOwner.Components[i].ClassInfo,ParseValues[j]);
              if Assigned(PropInfo) then
                 begin
                 if TheOwner.Components[i].ComponentCount>0 then // recursion needed
                    begin
                    if Length(TheSubOwner)>0 then SB:=TheSubOwner+'.'+TheOwner.Components[i].Name else SB:=TheOwner.Components[i].Name;
                    WriteRTTITranslation(TheOwner.Components[i],TheOwnerString,SB);
                    end;
                 //else
                     begin
                     if PropType(TheOwner.Components[i],ParseValues[j])=tkClass then
                       begin
                       if (TPersistent(GetOrdProp(TheOwner.Components[i],PropInfo)) is TStrings) then PV:=TStrings(GetOrdProp(TheOwner.Components[i],PropInfo)).Text;
                       isTStrings:=True;
                       end
                     else pv:=GetPropValue(TheOwner.Components[i],ParseValues[j],false);
                     if length(PV)>0 then
                        begin
                        if TheOwner.Components[i].name<>'then TheComp:=TheOwner.Components[i].name else TheComp:='*'+IntToStr(i);
                        if Length(TheSubOwner)>0 then TheComp:=TheSubOwner+'.'+TheComp;
                        WriteRTTI(TheOwnerString,TheComp,ParseValues[j],pv,isTStrings);
                        end;
                     end;

                 end;
              end;
          end;
      end;
end;



procedure WriteResourceTrans;
const
  C_Resources='RESOURCE';
  Procedure SetIfFind(const CName:String; Value:String);
  begin
    WriteRTTI(C_Resources, CName, '',Value,false);
  end;
begin
  if Paramstr(1)='/debugthen
  begin
    {$I SetIfFind.txt}
  end;
end;



end.
Thomas Wassermann H₂♂
Das Problem steckt meistens zwischen den Ohren
DRY DRY KISS
H₂ (wenn bei meinen Snipplets nichts anderes angegeben ist Lizenz: WTFPL)
  Mit Zitat antworten Zitat
Iwo Asnet

Registriert seit: 11. Jun 2011
313 Beiträge
 
#6

AW: [Mehrsprachigkeit] String als Property/Eigenschaft verwenden

  Alt 23. Feb 2012, 12:25
TsiLang kostet nicht viel und macht sich beim ersten Einsatz doppelt und dreifach bezahlt.
GNU GetText für Delphi ist umme und wohl auch zu gebrauchen.

Daneben kannst Du auch noch Localizer verwenden. Wenn Du im Lotto gewonnen hast oder auch mit anderen Programmiersprachen arbeitest.

Und wenn du was lernen willst und viel Zeit hast, schreib Dir was Eigenes.
  Mit Zitat antworten Zitat
Partikelecho

Registriert seit: 2. Dez 2011
14 Beiträge
 
Delphi 6 Enterprise
 
#7

AW: [Mehrsprachigkeit] String als Property/Eigenschaft verwenden

  Alt 24. Feb 2012, 07:42
@shark
Genau, ich nutze Delphi 6 Enterprise.
Die aktuelle Delphi-Version wird bei uns erst in den nächsten Monaten integriert.

@Lemmy
Die Aufgabe habe ich so gestellt bekommen. Weitere vorgaben sind zum Beispiel, dass der Bestand an Sprachtexten vom Endanwender pflegbar sein soll und es auch eine Historie geben soll. Da eignet sich meiner Meinung nach eine datenbank-basierte Lösung am Besten.

Die Unit TypInfo verwende ich schon, z.B. um die Liste mit Komponenten zu erstellen, die eine bestimmte Eigenschaft haben.

Dumm von mir, dass ich dadurch nicht auf die Funktion SetPropValue gekommen bin, die genau das macht, was ich suche. Ich konnte mein Konzept anhand meines Demoprojekts jetzt vervollständigen.

@stahli
Auf deinen ersten Link konnte ich leider auf Arbeit nicht zugreifen, da tatsächlich der Teilstring 'xxx' in URLs blockiert wird. /fazialpalmier

Was den zweiten Link betrifft, dass habe ich schon in meiner Anwendung realisiert, danke.

@Bummi
Hui, dass macht auf mich einen ziemlich mächtigen Eindruck. Ehrlich gesagt schaffe ich es gerade nicht mit meiner Konzentration mich da durch zu arbeiten. Vor allem, da ich schon den Großteil erstellt habe. Ich werde mir das aber mal merken und später - bei erweitertem Horizont - noch einmal zu Gemüte führen. Danke.

@Iwo Asnet
Alternative Programme sind in meiner Situation leider keine Lösung, da ich die Aufgabe mit oben genannten Vorgaben bekommen habe und dementsprechend ausführen muss. Außerdem lerne ich dabei am meisten.

Noch einmal an alle:
Danke für die Hilfe, letzlich hatte ich die Lösung schon als Unit eingebunden und habe sie aber nicht erkannt. Jetzt funktioniert im Demoprojekt alles laut Vorgabe.

Hier einmal die Prozedur, die ich verwende, um die Komponenten zu übersetzen:

- an den Parameter 'lang' wird die Bezeichnung der Sprache übergeben, die auch als Spaltenbezeichnung in der Tabelle für die Sprachtexte verwendet wird (z.B. 'GERMAN')
- ListComponents listet alle Komponenten des Formulars, die Text-Eigenschaften erhalten können
- die Select-Abfrage liefert als Ergebnis alle Informationen, die zum Übersetzen benötigt werden
- für alle Einträge, die die Abfrage als Ergebnis liefert werden die Einträge der StringList (durch ListComponents generiert) abgeglichen

Delphi-Quellcode:
procedure TFRM_Main.SetTranslation(const lang: String);
var
  SL: TStringList;
  Text, Prop: String;
  Comp: TComponent;
  time: Cardinal;
begin
  time := GetTickCount;
  SL := ListComponents;
  with QRY_Container do
  begin
    Close;
    SQL.Clear;
    SQL.Add('SELECT T.'+lang+', C.COMP_LABEL, P.PROP_NAME FROM '+texts+' T');
    SQL.Add('INNER JOIN '+master+' M ON T.TEXT_ID = M.TEXT_ID');
    SQL.Add('INNER JOIN '+props+' P ON P.PROP_ID = M.PROP_ID');
    SQL.Add('INNER JOIN '+comps+' C ON C.COMP_ID = M.COMP_ID;');
    Open;
  end;
  while not QRY_Container.Eof do
  begin
    Text := QRY_Container.Fields.Fields[0].AsString;
    Comp := FindComponent(QRY_Container.Fields.Fields[1].AsString);
    Prop := QRY_Container.Fields.Fields[2].AsString;
    if SL.IndexOf(QRY_Container.Fields.Fields[1].AsString) <> -1 then
    begin
      if Comp is TMenuItem then
        SetPropValue(Comp,Prop,Text)
      else if Comp is TListBox then
        QRY_Container.Next
      else if (Comp is TComboBox) and (Prop = 'Items') then
        QRY_Container.Next
      else if (Comp is TMainMenu) then
        QRY_Container.Next
      else if Comp is TControl then
        SetPropValue(Comp,Prop,Text);
    end;
    QRY_Container.Next;
  end;
  SL.Free;
  time := GetTickCount - time;
  ShowMessage('Fertig nach '+IntToStr(time)+' ms.');
end;

Geändert von Partikelecho (24. Feb 2012 um 08:17 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort

 

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:40 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz