Autor Beitrag
Silent Bob
Hält's aus hier
Beiträge: 9



BeitragVerfasst: Di 29.10.02 09:24 
Hallo

für meine Diplomarbeit sollte die Software, die ich zu entwickeln habe unter anderem mehrsprachig sein. Gibt es in Delphi dafür eine einfach zu handhabende Unterstützung und wenn ja wie funktioniert sie? Wenn es keine gibt, was gibt es sonst für Lösungsansätze?

Besten Dank für die Hilfe und einen schönen Tag

_________________
"Ich dachte alles wird gut, aber das ist lange her"
FriFra
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 557

Win XP Prof, Win XP Home,Win Server 2003,Win 98SE,Win 2000,Win NT4,Win 3.11,Suse Linux 7.3 Prof,Suse Linux 8.0 Prof
D2k5 Prof, D7 Prof, D5 Standard, D3 Prof, K3 Prof
BeitragVerfasst: Di 29.10.02 10:34 
Ich habe mal irgendwo diese Unit gefunden:
ausblenden volle Höhe Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
unit Lang;

interface

uses
windows,controls,sysutils;

Function INLanguage(English,German:String):String;

implementation

{call inLanguage like this to get the German text else return english
if you use different coutntry codes you can do more}

{






# FGetLanguageSettings 














 # Author: Walter Verhoeven
 # Date:   14.Sep.2000
 # Coming From: InLanguage
 #  Next Event: NONE
 #  Parameters: NONE
 #   Objective: See the users regional settings and return Country #number code
 #   Change:
 #     DD-MMM-YYYYY ¦Programmer
 #                1)
 




























}

Function FGetLanguageSettings:Integer;
Var
OutputBuffer: Pchar;
SelectedLCID: LCID;               //DWORD constand in Windows.pas
begin
  OutputBuffer:= StrAlloc(4);     //alocate memory for the PChar
  Try
    Try
     SelectedLCID:= GetUserDefaultLCID;
     GetLocaleInfo(SelectedLCID,LOCALE_ICOUNTRY,OutputBuffer,3);
     Result:= StrToInt(OutputBuffer);
    Except
     Result:= 49;   //german
     Abort;

    End;
  Finally
   StrDispose(OutputBuffer);   //alway's free the memory alocated
  End;
end;
{






 INLanguage 



















# # Author: Walter Verhoeven
 # Date:   .Jun.2000
 # Coming From:
 #  Next Event: FGetLanguageSettings
 #  Parameters: Eglish and german text
 #   Objective: provide a method to return
 #              english or german results based on the
 # users window prefered language setting.
 #   Change:
 #     DD-MMM-YYYYY ¦Programmer
 #                1)
 































}
Function INLanguage(English,German:String):String;
begin
    Case FGetLanguageSettings of
     49: Result:=German ;   //Return the german string
     43: Result:=German ;   // if the pC has a german preferance
     41: Result:=German ;
    352: Result:=German ;
   Else
     Result:= English;      //if not german then english
   End;
end;

end.


Aufruf:
ausblenden Quelltext
1:
Label1.Caption:=InLanguage('MyLabel','Mein Label);					


Ich habe mir das ganze noch um die optionale verwendung einer ini-datei erweitert, damit ich andere Sprachen einfach über eine Textdatei einbinden kann, aber das ist etwas viel Code...
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Di 29.10.02 11:20 
Man könnte auch über Zeichenfolgentabellen gehen, die man eine Ressourcen-Datei packt. Da legt man für jede Sprache eine an. Die gleichen Zeichenfolgen in den verschiedenen Sprachen haben dann jeweils die gleiche ID. Natürtlich muß man dann alles von Hand laden, jedes Label, jedes Item einer Listbox usw. Muß man bei dem anderen Vorschlag auch, nur nimmt dir hier das System die Entscheidung ab welche Sprache genommen wird.
Ich habe mal eine Screenshot der Ressourcen-Datei meines FileSplitters im geöffneten VC gemacht. (Der ist schon auf englischen, deutschen, französischen und chinesischen Systemen gelaufen. Auf den deutschen Systemen in deutsch und auf den restlichen in englisch eben.) Da siehst du was ich meine. Legst du noch eine neutrale Sprache an, wird die immer gewählt, wenn nichts anderes paßt.
user defined image

Laden der Strings geht so:
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
function LoadStr(ID: DWORD): String;
var
  buffer: array[0..255] of Char;
begin
  LoadString(hInstance, ID, buffer, 255);
  result := String(buffer);
end;


Und so kannst du zur Laufzeit die Sprache umschalten:
ausblenden Quelltext
1:
2:
SetThreadLocale(DWORD(Word(SORT_DEFAULT) shl 16)
    or DWORD(Word(SUBLANG_ENGLISH_US) shl 10) or DWORD(Word(LANG_ENGLISH)));


Meiner Meinung nach die einfachste Möglichkeit und wenn du dann noch das VC zur Hand hast ein Kinderspiel. Wenn du dir die Ressourcen-Dateien selber schreiebn mußt ist das auch kein Beinbruch, mußt nur in Erfahrung bringen, wie die aussehen müssen.
neojones
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 1206
Erhaltene Danke: 1



BeitragVerfasst: Di 29.10.02 11:48 
In der INI-Datei "LanINI" stehen die Einträge so drin:
[Deutsch]
1cap=OK
1hint=Drück das für okay
2cap=Abbrechen
2hint=Drück das wenn Du ein Weichei bist

[English]
1cap=OK
1hint=Click this for okay
2cap=Cancel
2hint=Click this if you are a looser

Und der folgende Code geht alle Componenten des Programmes durch und ändert die Beschriftung und den Hint. Vorteil: Die Sprache lässt sich auch zur Laufzeit umstellen.

Zum praktischen Einsatz: Das Tool myAdmin (coded by meinereiner) benutzt diese Routine zimelich erfolgreich.


ausblenden volle Höhe Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
procedure TFMain.ChangeLan(const lan: String);
var i, j: Integer;
    c: TObject;
begin
     LanINI := TINIFile.Create(ProgVerz + '\lan.ini');

     WITH Application DO begin
        FOR i := 0 to ComponentCount - 1 DO BEGIN
            FOR j := 0 TO Components[i].ComponentCount - 1 DO BEGIN
                c := Components[i].Components[j];
                If (c is TLabel) then begin
                   If (c AS TLabel).Tag <> 0 then begin
                      (c AS TLabel).Caption := LanINI.ReadString(lan, IntToStr((c AS TLabel).Tag)+'cap', '');
                   end;
                end;

                If (c is TPanel) then begin
                   If (c AS TPanel).Tag <> 0 then begin
                      (c AS TPanel).Caption := LanINI.ReadString(lan, IntToStr((c AS TPanel).Tag)+'cap', '');
                   end;
                end;

                If (c is TXPButton) then begin
                   If (c AS TXPButton).Tag <> 0 then begin
                      (c AS TXPButton).Caption := LanINI.ReadString(lan, IntToStr((c AS TXPButton).Tag)+'cap', '');
                      (c AS TXPButton).Hint := LanINI.ReadString(lan, IntToStr((c AS TXPButton).Tag)+'hint', '');
                   end;
                end;

                If (c is TCheckBox) then begin
                   If (c AS TCheckBox).Tag <> 0 then begin
                      (c AS TCheckBox).Caption := LanINI.ReadString(lan, IntToStr((c AS TCheckBox).Tag)+'cap', '');
                   end;
                end;

                If (c is TMenuItem) then begin
                   If (c AS TMenuItem).Tag <> 0 then begin
                      (c AS TMenuItem).Caption := LanINI.ReadString(lan, IntToStr((c AS TMenuItem).Tag)+'cap', '');
                   end;
                end;

                If (c is TGroupBox) then begin
                   If (c AS TGroupBox).Tag <> 0 then begin
                      (c AS TGroupBox).Caption := LanINI.ReadString(lan, IntToStr((c AS TGroupBox).Tag)+'cap', '');
                   end;
                end;

                If (c is TImage) then begin
                   If (c AS TImage).Tag <> 0 then begin
                      (c AS TImage).Hint := LanINI.ReadString(lan, IntToStr((c AS TImage).Tag)+'hint', '');
                   end;
                end;

                If (c is TRadioGroup) then begin
                   If (c AS TRadioGroup).Tag <> 0 then begin
                      (c AS TRadioGroup).Caption := LanINI.ReadString(lan, IntToStr((c AS TRadioGroup).Tag)+'cap', '');
                   end;
                end;

                If (c is TTabSheet) then begin
                   If (c AS TTabSheet).Tag <> 0 then begin
                      (c AS TTAbSheet).Caption := LanINI.ReadString(lan, IntToStr((c AS TTabSheet).Tag) + 'cap', '');
                   end;
                end;

                If (c is TSpeedButton) then begin
                   If (c AS TSpeedButton).Tag <> 0 then begin
                      (c AS TSpeedButton).Caption := LanINI.ReadString(lan, IntToStr((c AS TSpeedButton).Tag)+'cap', '');
                      (c AS TSpeedButton).Hint := LanINI.ReadString(lan, IntToStr((c AS TSpeedButton).Tag)+'hint', '');
                   end;
                end;

                If (c is TButton) then begin
                   If (c AS TButton).Tag <> 0 then begin
                      (c AS TButton).Caption := LanINI.ReadString(lan, IntToStr((c AS TButton).Tag)+'cap', '');
                      (c AS TButton).Hint := LanINI.ReadString(lan, IntToStr((c AS TButton).Tag)+'hint', '');
                   end;
                end;
                If (c is TBitBtn) then begin
                   If (c AS TBitBtn).Tag <> 0 then begin
                      (c AS TBitBtn).Caption := LanINI.ReadString(lan, IntToStr((c AS TBitBtn).Tag)+'cap', '');
                      (c AS TBitBtn).Hint := LanINI.ReadString(lan, IntToStr((c AS TBitBtn).Tag)+'hint', '');
                   end;
                end;
            END;
        END;
     end;
end;


Viele Grüße,

Matthias

_________________
Ha! Es compiliert! Wir können ausliefern!
Matthias
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 121



BeitragVerfasst: Di 29.10.02 17:07 
Hy,

auch ich habe mir mal gedanken zu dem Thema gemacht und meine eigene Lösung erstellt.

1. wollt ich, dass der Kunde dass Programm auch selbst übersetzen kann
2. Ich habe keine lust alle Texte von Hand zu initialisieren
3. Bei Programmänderungen sollten die Änderungen einfach einzupflegen sein
4. Die default Sprachdatei soll möglichst automatisch erstellt werden
5. Beliebig viele Srachen sollten möglich sein
6. Sprachumschaltun während das Programm läuft

Resourcen zu verwenden ist parktisch und üblich jedoch bedeutet es für 1 und 2 einen erhöhten Aufwand.

Deshalb habe ich mich auch für Ini-Dateien entschieden. Bei mir gibt es für jede Sprache eine und eine weitere, über die ich das Sprachmenü erstelle und somit mit beliebig vielen Sprachen arbeiten kann.

Als Index für den Text verwende ich die Eigenschaft Tag, die jede Kompo hat. Ist diese ungleich 0 muß der Inhalt Übersetzt werden. Das Übersetzen übernimmt eine allgemeine Routine, die im OnShow Ereignis eines Formulars aufgerufen wird. Der Rest läuft automatisch, ähnlich wie in dem Beispiel meine Namens Vetters.

Die default Datei wird erstellt, in dem über bedingte Compilierung die Sprachdatei geschrieben anstatt gelesen wird.

ciao

Matthias
Silent Bob Threadstarter
Hält's aus hier
Beiträge: 9



BeitragVerfasst: Di 29.10.02 17:24 
Besten Dank an alle .... ich denk ich werde es ebenfalls mit der Ini-File Variante lösen, da sie mir einfach und schnell realsierbar scheint .... und die Zeit drängt eben ....

Habt nen schönen Abend

_________________
"Ich dachte alles wird gut, aber das ist lange her"
Aya
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1964
Erhaltene Danke: 15

MacOSX 10.6.7
Xcode / C++
BeitragVerfasst: Mi 30.10.02 16:45 
Hi,

also ich hab jetzt einfach mal nicht gelesen was meine Vorgänger alles geschrieben haben... aber, bei dem satz "Für meine Diplomarbeit..." *gg* Sollte man wenn man das Diplom darin macht nicht sowas schon alleine hinbekommen?? *duckt sich hastig*

Aber nochmal die lösung wie ich sie immer verwende.. (und nein, ich hab kein Diplom, hab auch niemals Informatik oder dergleichen studiert, bzw irgendwo auf ner Schule oder ähnlichem gelernt *g*)

Nehmen wir an du hast 3 Sprachen, Deutsch, Englisch, Holländisch.

Machst du dafür einfach 3 INI Dateien, "Deutsch.ini", "Englisch.ini", "Holland.ini"... (Holland.ini daher weil Holländisch so lang ist und nen ä drin hat... :) )

Jetzt unterteilst du deine INI datei in mehrere sektionen.. z.B. "MainMenu", "Frame1" etc.. jenachdem wie dein Programm aufgebaut ist, und darin machst du einfach für jede Caption etc einen eintrag den du dann in einer funktion LoadLanguage(Language: String); lädst...

dann machst du dir irgendwo im MainMenü oder sonstwo einen eintrag "Sprache" mit den 3 unterspalten, und jedesmal wenn man eine auswählt wird die funktion LoadLanguage mit der entsprechenden sprache geladen... :)

Wenn du es dann ganz perfekt machen willst machst du beim ini.ReadString() am ende einen Default wert hin, somit hast du sogar eine Standartsprache für den fall das man die INI Dateien löscht... :)

und wenn es noch perfekter sein soll.. verschlüsselst du die INI Datei (denn es gibt viele Newbies die gern einfach dann die Texte es Prog's ändern und ihre namen hinkritzeln etc.)

und wenn es noch viel viel perfekter sein soll *gg* bzw das ganze mit sehr wenig code gelöst sein soll... nenn die einträge in der INI so wie das z.B. Laben auf deiner Form heißt... :)
//INI
[Main]
Label1=Hallo
//INI Ende

So, und das ganze rufst du ab indem du dir zuerst in einer StringList die ganzen namen der einträge in [Main] lädst... die arbeitest du von oben nach unten in einer forschleife durch und mit jedemeintrag dann
ausblenden Quelltext
1:
TLabel(FindComponent(StringList.Strings[i])).Caption:=ini.ReadString('Main',StringList.Strings[i],'');					


ok, es gibt keinen Default wert mehr, aber du hast das ganze sprachproblem mit 5 Zeilen code gelöst :)

Au'revoir,
Aya

PS: Bekomm ich auch nen Diplom? :roll:
Silent Bob Threadstarter
Hält's aus hier
Beiträge: 9



BeitragVerfasst: Mi 30.10.02 19:19 
Tja ... was soll ich dazu sagen ..... die Mehrsprachigkeit der Software ist eine kleine Wunschanforderung am Rande. Dies über irgendwelche einzulesende Text-Files zu lösen leuchtet ein. Doch ich hab's eben noch nie zuvor gemacht und dachte deswegen mal nachzufragen schadet nichts. Denn dieses Problem haben vor mir schon zig-tausende gelöst und sich darüber den Kopf zerbrochen. Wollte einfach mal schauen welch' elegante Lösungen sich der eine oder andere wache Geist schon ausgedacht hat.

In diesem Sinne
Silent Bob

_________________
"Ich dachte alles wird gut, aber das ist lange her"