![]() |
[Mehrsprachigkeit] String als Property/Eigenschaft verwenden
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. |
AW: [Mehrsprachigkeit] String als Property/Eigenschaft verwenden
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.
|
AW: [Mehrsprachigkeit] String als Property/Eigenschaft verwenden
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:
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.
resourcestring
caText1='Hallo Welt'; WEnn Du es mit deinem Weg weiter machen willst und noch Delphi 6 verwendest, dann schau dir mal die Unit TypInfo an, das ![]() Grüße |
AW: [Mehrsprachigkeit] String als Property/Eigenschaft verwenden
Du könntest mal hier nachlesen:
![]() ![]() Für eine spätere Lokalisierung habe ich mir allerdings ![]() |
AW: [Mehrsprachigkeit] String als Property/Eigenschaft verwenden
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)='/debug' then begin {$I SetIfFind.txt} end; end; end. |
AW: [Mehrsprachigkeit] String als Property/Eigenschaft verwenden
TsiLang kostet nicht viel und macht sich beim ersten Einsatz doppelt und dreifach bezahlt.
![]() Daneben kannst Du auch noch ![]() Und wenn du was lernen willst und viel Zeit hast, schreib Dir was Eigenes. |
AW: [Mehrsprachigkeit] String als Property/Eigenschaft verwenden
@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; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:09 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz