AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

mehrsprachige Resourcen nutzen

Ein Thema von himitsu · begonnen am 26. Dez 2007 · letzter Beitrag vom 29. Feb 2008
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.116 Beiträge
 
Delphi 12 Athens
 
#1

mehrsprachige Resourcen nutzen

  Alt 26. Dez 2007, 20:25
Im Zuge einer mehrsprachigen Unterstütung
und da MSDN-Library durchsuchenLoadString keine Sprachauswahl bietet,
hab ich mir, nach mehreren Anläufen, folgenden Code einfallen lassen.

Die verschiedenen Sprachen liegen dabei alle im selben Ressourcenbereich.

Man braucht dafür nur meine Funktion und die nötigen Resourcen in der Anwendung (über .hModule kann auch eine externe Resource angegeben, z.B. eine DLL).
FindResourceLang sucht dann die vorhandenen Sprachen und bietet über Result den Index zur automatischen Vorauswahl.

Im zurückgegebenem Array stehen dann alle gefundenen Sprachresourcen, wo man sich nach Lust und Laune oder über den Index(Result) bediehnen kann.


Code 1:
Delphi-Quellcode:
Type TResTableString = packed Record
    Len: Word;
    Text: packed Array[0..0] of WideChar;
  End;
  PResTableString = ^TResTableString;
  TEnumResRec = packed Record
    hModule: THandle;
    ResType: PWideChar;
    ResName: PWideChar;
    LangIDs: packed Array of packed Record
      LangID: LANGID;
      Case Byte of
        0: (P: Pointer; Len: Integer);
        1: (Text: PResTableString); // RT_STRING
    End;
  End;
  PEnumResRec = ^TEnumResRec;

Const DefaultLang = LANG_ENGLISH or (SUBLANG_ENGLISH_US shl 10);

Var GUILang: LANGID = LANG_NEUTRAL or (SUBLANG_NEUTRAL shl 10);
  ResErrorStr: WideString;

Function FindResourceLang(Var LangResList: TEnumResRec): Integer;
  Function EnumResLangProcW(hModule: THandle; lpszType, lpszName: PWideChar; wIDLanguage: LANGID; lParam: PEnumResRec): LongBool; StdCall;
    Var hRes: HRSRC;
      hResLoad: THandle;
      ResP: PResTableString;
      ResL, i, i2: Integer;

    Begin
      Result := True;
      If lpszType = PWideChar(RT_STRING) Then Begin
        hRes := FindResourceExW(lParam^.hModule, lParam^.ResType,
                      MakeIntResourceW(Integer(lParam^.ResName) shr 4 + 1), wIDLanguage);
        hResLoad := LoadResource(lParam^.hModule, hRes);
        ResL := SizeOfResource(lParam^.hModule, hRes);
        ResP := LockResource(hResLoad);
        If ResP = nil Then Exit;
        i := ResL;
        For i2 := 1 to Integer(lParam^.ResName) and $0F do Begin
          Dec(i, (ResP^.Len + 1) * 2);
          Inc(PWideChar(ResP), ResP^.Len + 1);
          If i <= 0 Then Exit;
        End;
        If (ResP^.Len = 0) or ((ResP^.Len + 1) * 2 > i) Then Exit;
        ResL := ResP^.Len + 2;
      End Else Begin
        hRes := FindResourceExW(lParam^.hModule, lParam^.ResType, lParam^.ResName, wIDLanguage);
        hResLoad := LoadResource(lParam^.hModule, hRes);
        ResL := SizeOfResource(lParam^.hModule, hRes);
        ResP := LockResource(hResLoad);
      End;
      i := Length(lParam^.LangIDs);
      SetLength(lParam^.LangIDs, i + 1);
      lParam^.LangIDs[i].LangID := wIDLanguage;
      lParam^.LangIDs[i].P := ResP;
      lParam^.LangIDs[i].Len := ResL;
    End;

  Var ResName: PWideChar;
    LangX, MaskX: LANGID;
    i, i2: Integer;
    S, S2: WideString;

  Begin
    Result := -1;
    LangResList.LangIDs := nil;
    If (Cardinal(LangResList.ResName) <= $0000FFFF) and (LangResList.ResType = PWideChar(RT_STRING)) Then
      ResName := MakeIntResourceW(Integer(LangResList.ResName) shr 4 + 1)
    Else ResName := LangResList.ResName;
    EnumResourceLanguagesW(LangResList.hModule, LangResList.ResType, ResName, @EnumResLangProcW, Integer(@LangResList));
    If LangResList.LangIDs = nil Then Begin
      If Cardinal(LangResList.ResName) < $0000FFFF Then S := IntToStrT(Integer(LangResList.ResName))
      Else S := WideString('''') + LangResList.ResName + WideString('''');
      Case Integer(LangResList.ResType) of
        Integer(RT_STRING): Begin
          Result := 0;
          ResErrorStr := #0'[Resource ' + S + ' (' + 'RT_STRING' + ') not found]';
          ResErrorStr[1] := WideChar(Length(ResErrorStr) - 1);
          SetLength(LangResList.LangIDs, 1);
          LangResList.LangIDs[0].LangID := LANG_NEUTRAL or (SUBLANG_NEUTRAL shl 10);
          LangResList.LangIDs[0].Text := @ResErrorStr[1];
          LangResList.LangIDs[0].Len := Length(ResErrorStr) - 1;
          Exit;
        End;
        Integer(nil): S2 := WideString('''') + WideString('''');
        Integer(RT_CURSOR): S2 := 'RT_CURSOR';
        Integer(RT_BITMAP): S2 := 'RT_BITMAP';
        Integer(RT_ICON): S2 := 'RT_ICON';
        Integer(RT_MENU): S2 := 'RT_MENU';
        Integer(RT_DIALOG): S2 := 'RT_DIALOG';
        Integer(RT_FONTDIR): S2 := 'RT_FONTDIR';
        Integer(RT_FONT): S2 := 'RT_FONT';
        Integer(RT_ACCELERATOR): S2 := 'RT_ACCELERATOR';
        Integer(RT_RCDATA): S2 := 'RT_RCDATA';
        Integer(RT_MESSAGETABLE): S2 := 'RT_MESSAGETABLE';
        12..$FFFF: S2 := IntToStrT(Integer(LangResList.ResType));
        Else S2 := WideString('''') + LangResList.ResType + WideString('''');
      End;
      Exception(888, ['Resource ' + S + ' (type ' + S2 + ') not found.']);
    End;

    MaskX := $FFFF;
    For i2 := 0 to 9 do Begin
      Case i2 of
        0, 4: If GUILang = LANG_NEUTRAL or (SUBLANG_NEUTRAL shl 10) Then Continue Else LangX := GUILang;
        1, 5: LangX := Word(GetThreadLocale);
        2, 6: LangX := GetUserDefaultLangID;
        3, 7: LangX := GetSystemDefaultLangID;
        8: LangX := DefaultLang;
        Else LangX := LANG_NEUTRAL or (SUBLANG_NEUTRAL shl 10);
      End;
      If (i2 = 4) or (LangX and not $03FF = 0) Then MaskX := $03FF;
      For i := High(LangResList.LangIDs) downto 0 do
        If LangResList.LangIDs[i].LangID and MaskX = LangX and MaskX Then
          Result := i;
      If Result >= 0 Then Break;
    End;
    If Result < 0 Then Result := 0;
  End;
wird z.B. so verwendet;
Delphi-Quellcode:
Var LangResList: TEnumResRec;
  Language: Integer;
  StrBuffer: Array[0..1023] of WideChar;
  i: Integer;

LangResList.hModule := HInstance;
LangResList.ResType := PWideChar(RT_STRING);
LangResList.ResName := {MakeIntResourceW(MsgID)};
Language := FindResourceLang(LangResList);

i := Min(Integer(LangResList.LangIDs[Language].Text^.Len * 2), SizeOf(StrBuffer) - 2);
CopyMemory(@StrBuffer, @LangResList.LangIDs[Language].Text^.Text, i);
StrBuffer[i div 2] := #0;
Delphi-Quellcode:
Var LangResList: TEnumResRec;
  Language: Integer;

LangResList.hModule := HInstance;
LangResList.ResType := PWideChar(RT_DIALOG);
LangResList.ResName := {MakeIntResourceW(DlgID)};
Language := FindResourceLang(LangResList);
Result := DialogBoxIndirectParamW(HInstance, PDlgTemplate(LangResList.LangIDs[Language].P)^, ...);
Code 2 (ohne Exception):
Delphi-Quellcode:
Type TResTableString = packed Record
    Len: Word;
    Text: packed Array[0..0] of WideChar;
  End;
  PResTableString = ^TResTableString;
  TEnumResRec = packed Record
    hModule: THandle;
    ResType: PWideChar;
    ResName: PWideChar;
    LangIDs: packed Array of packed Record
      LangID: LANGID;
      Case Byte of
        0: (P: Pointer; Len: Integer);
        1: (Text: PResTableString); // RT_STRING
    End;
  End;
  PEnumResRec = ^TEnumResRec;

Const DefaultLang = LANG_ENGLISH or (SUBLANG_ENGLISH_US shl 10);

Var GUILang: LANGID = LANG_NEUTRAL or (SUBLANG_NEUTRAL shl 10);

Function FindResourceLang(Var LangResList: TEnumResRec): Integer;
  Function EnumResLangProcW(hModule: THandle; lpszType, lpszName: PWideChar; wIDLanguage: LANGID; lParam: PEnumResRec): LongBool; StdCall;
    Var hRes: HRSRC;
      hResLoad: THandle;
      ResP: PResTableString;
      ResL, i, i2: Integer;

    Begin
      Result := True;
      If lpszType = PWideChar(RT_STRING) Then Begin
        hRes := FindResourceExW(lParam^.hModule, lParam^.ResType,
                      MakeIntResourceW(Integer(lParam^.ResName) shr 4 + 1), wIDLanguage);
        hResLoad := LoadResource(lParam^.hModule, hRes);
        ResL := SizeOfResource(lParam^.hModule, hRes);
        ResP := LockResource(hResLoad);
        If ResP = nil Then Exit;
        i := ResL;
        For i2 := 1 to Integer(lParam^.ResName) and $0F do Begin
          Dec(i, (ResP^.Len + 1) * 2);
          Inc(PWideChar(ResP), ResP^.Len + 1);
          If i <= 0 Then Exit;
        End;
        If (ResP^.Len = 0) or ((ResP^.Len + 1) * 2 > i) Then Exit;
        ResL := ResP^.Len + 2;
      End Else Begin
        hRes := FindResourceExW(lParam^.hModule, lParam^.ResType, lParam^.ResName, wIDLanguage);
        hResLoad := LoadResource(lParam^.hModule, hRes);
        ResL := SizeOfResource(lParam^.hModule, hRes);
        ResP := LockResource(hResLoad);
      End;
      i := Length(lParam^.LangIDs);
      SetLength(lParam^.LangIDs, i + 1);
      lParam^.LangIDs[i].LangID := wIDLanguage;
      lParam^.LangIDs[i].P := ResP;
      lParam^.LangIDs[i].Len := ResL;
    End;

  Var ResName: PWideChar;
    LangX, MaskX: LANGID;
    i, i2: Integer;

  Begin
    Result := -1;
    LangResList.LangIDs := nil;
    If (Cardinal(LangResList.ResName) <= $0000FFFF) and (LangResList.ResType = PWideChar(RT_STRING)) Then
      ResName := MakeIntResourceW(Integer(LangResList.ResName) shr 4 + 1)
    Else ResName := LangResList.ResName;
    EnumResourceLanguagesW(LangResList.hModule, LangResList.ResType, ResName, @EnumResLangProcW, Integer(@LangResList));
    If LangResList.LangIDs = nil Then Exit;

    MaskX := $FFFF;
    For i2 := 0 to 9 do Begin
      Case i2 of
        0, 4: If GUILang = LANG_NEUTRAL or (SUBLANG_NEUTRAL shl 10) Then Continue Else LangX := GUILang;
        1, 5: LangX := Word(GetThreadLocale);
        2, 6: LangX := GetUserDefaultLangID;
        3, 7: LangX := GetSystemDefaultLangID;
        8: LangX := DefaultLang;
        Else LangX := LANG_NEUTRAL or (SUBLANG_NEUTRAL shl 10);
      End;
      If (i2 = 4) or (LangX and not $03FF = 0) Then MaskX := $03FF;
      For i := High(LangResList.LangIDs) downto 0 do
        If LangResList.LangIDs[i].LangID and MaskX = LangX and MaskX Then
          Result := i;
      If Result >= 0 Then Break;
    End;
    If Result < 0 Then Result := 0;
  End;
Delphi-Quellcode:
Var LangResList: TEnumResRec;
  Language: Integer;

LangResList.hModule := ...;
LangResList.ResType := ...;
LangResList.ResName := ...;
Language := FindResourceLang(LangResList);
If Language < 0 Then {Error}
...
DefaultLang die Sprache in der eure Anwendung hauptsächlich perstellt wurde
also die wo möglichst alle Resourcen vorhanden sind
Tipp: Englisch macht sich gut, damit erhöht sich die Wahrscheinlichkeit daß jemand, dessen Sprache nicht unterstützt wird, dennoch was entziffern kann (Englisch ist ja angeblich 'ne Weltsprache)
GUILang kann vom Programmierer zur Auswahl der Sprache passend definiert werden.
ResErrorStr wird intern zum Speichern des Fehlertextes benötigt.

Nach einer passenden Sprache wird in dieser Reinfolge gesucht:
Code:
GUILang
ThreadLangID
UserDefaultLangID
SystemDefaultLangID

GUILang (ignore SUBLANG_*)
ThreadLangID (ignore SUBLANG_*)
UserDefaultLangID (ignore SUBLANG_*)
SystemDefaultLangID (ignore SUBLANG_*)
DefaultLang (ignore SUBLANG_*)
LANG_NEUTRAL

erste gefungene Sprache
wurde keine Resource gefungen, so wird eine Exception ausgelößt und für RT_STRING ein Fehlertext zurückgegeben
oder es kommt der Rückgabewert -1 (beim zweiten Code).


in der Ressourcendatei (.RC) sähe es dann z.B. so aus:
Code:
STRINGTABLE
  LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
  BEGIN
    123 "an example text"
  END

STRINGTABLE
  LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
  BEGIN
    123 "ein Beispieltext"
  END

100 DIALOGEX 0, 0, 193, 122
  STYLE   ...
  FONT    ...
  LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
  CAPTION "..."
  BEGIN
    ...
  END


Zum auslesen vorhandener Sprachen kann die selbe Funktion mißbraucht werden:
Delphi-Quellcode:
Var LangResList: TEnumResRec;

LangResList.hModule := HInstance;
LangResList.ResType := ...; // vorhandene Resource,
LangResList.ResName := ...; // von welcher die Sprachen ausgelesenwerden
FindResourceLang(LangResList);
For i := 0 to High(LangResList.LangIDs) do
  {LangResList.LangIDs[i].LangID}
diese ließe sich ganz gut über die Sprachnamen (welche man natürlich mit speichern müßte) machen:
Delphi-Quellcode:
Var LangResList: TEnumResRec;
  S: WideString;

LangResList.hModule := HInstance;
LangResList.ResType := PWideChar(RT_STRING);
LangResList.ResName := MakeIntResourceW(100);
FindResourceLang(LangResList);
For i := 0 to High(LangResList.LangIDs) do Begin
  SetLength(S, LangResList.LangIDs[i].Text^.Len);
  CopyMemory(@S[1], @LangResList.LangIDs[i].Text^.Text,
    LangResList.LangIDs[i].Text^.Len * 2);
  List.Add(S, LangResList.LangIDs[i].LangID);
End;

// STRINGTABLE
// LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
// BEGIN
// 100 "english"
// ...
// END
//
// STRINGTABLE
// LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
// BEGIN
// 100 "Deutsch"
// ...
// END
//
// STRINGTABLE
// LANGUAGE LANG_GERMAN, SUBLANG_GERMAN_SWISS
// BEGIN
// 100 "schweizer Deutsch"
// ...
// END
Man könnte zwar die LangID entziffern und darüber den Sprachnamen erhalten, aber dafür bräuchte man dann in der Anwendung eine Liste aller möglichen LANG_* und SUBLANG_* Kombinationen.
Außerdem finde ich es besser den Sprachnamen in der entsprechenden Sprache zu speichern.
Windows hat da zwar auch irgendwo 'ne Liste, aber diese ist nur in der Systemsprache (von Windows) vorhanden.
(oder wer von euch kann alle Sprachen, um dann rauszufinden was dann in 'ner Liste "deutsch" heißt?)
PS: das Menü zur Sprachänderung sollte entweder Bildlich gekennzeichnet oder in englich (können ja wohl die Meißten) benannt sein.


Im Anhang hab ich das Ganze mal in ein Demoprojekt ausgelagert und unter Anderem auch mal eine LoadStringLangW erstellt, sowie eine Unterstütung für mehrere Resourcendateien entwickelt.


Das ganze funktioniert zwar (hab's "erfolgreich" in 'nem Projekt drin), aber für Verbesserungen bin ich dennoch dankbar.

vorallem die Reinfolge der Sprachen der Autoauswahl beschäftigt mich immernoch sehr.
So wäre es z.. auch möglich,
Code:
GUILang
GUILang (ignore SUBLANG_*)
ThreadLangID
ThreadLangID (ignore SUBLANG_*)
UserDefaultLangID
UserDefaultLangID (ignore SUBLANG_*)
SystemDefaultLangID
SystemDefaultLangID (ignore SUBLANG_*)
DefaultLang (ignore SUBLANG_*)
LANG_NEUTRAL
erste gefungene Sprache
aber da gibt's Probleme mit den Untersprachen (SUBLANG_*)

wenn z.B. Chinesisch-Simple ausgewählt wird und nur Chinesich-Traditional gefunden wird, aber der Benutzer das Trationale nicht lesen kann, dann wär's ja blöd ihm dieses zu präsentieren

[edit=sakura] Anhang auf Wunsch entfernt, neuer weiter unten. Mfg, sakura[/edit]
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Dezipaitor

Registriert seit: 14. Apr 2003
Ort: Stuttgart
1.701 Beiträge
 
Delphi 7 Professional
 
#2

Re: mehrsprachige Resourcen nutzen

  Alt 26. Dez 2007, 21:08
In der JWSCL befindet sich auch so eine Funktion. Sie lädt ein Resourcestring von einer bestimmten SprachID.

Delphi-Quellcode:
unit JwsclStrings;
function LoadLocalizedString(const Index : Cardinal; const PrimaryLanguageId, SubLanguageId : Word; Instance : HInst = 0) : TJwString;
Christian
Windows, Tokens, Access Control List, Dateisicherheit, Desktop, Vista Elevation?
Goto: JEDI API LIB & Windows Security Code Library (JWSCL)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.116 Beiträge
 
Delphi 12 Athens
 
#3

Re: mehrsprachige Resourcen nutzen

  Alt 29. Dez 2007, 09:17
Hab mir jetzt erstmal 'nen gaaanz kleinen Einblick genommen
und im Prinziep ist deine Funktion garnicht so schlecht
(Arbeitet ja fast wie meine, beim Auslesen ... halt laut MSDN )

Allerdings hab ich (vorwiegend für mich) eine automatische Srachauswahl drin, so daß sich das Programm(diese Funktion) versucht selber auf auf die System-/Benutzersprache einzustellen
und gerade dieses nutze ich.

Nja und ich hab diese Funktion ja auch noch so gestaltet, daß sie nicht nur auf Strings anwendbar ist.

Aber gegen die Delphiimplemantetion (vorallem) der RessourceStrings ist Beides um Längen besser.



Ich schau mich aber noch etwas bei dir um.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Dezipaitor

Registriert seit: 14. Apr 2003
Ort: Stuttgart
1.701 Beiträge
 
Delphi 7 Professional
 
#4

Re: mehrsprachige Resourcen nutzen

  Alt 29. Dez 2007, 12:53
Naja ich habe nur ein LoadString für andere Sprachen gesucht. Meist kennt man ja die Sprachresourcen sowieso. Aber es wäre natürlich deutlich besser die verfügbaren SprachIDs dynamisch verwenden zu könne.
Ich frage mich halt warum MS es verpasst hat, Mehrsprachigkeit dynamisch zu unterstützen. Also deutsche Anwendung unter englischem OS. Macht vielleicht auf dem ersten Blick keinen Sinn, aber bei mir an der Uni gibt es nur englische Windowsversionen (neben Linux natürlich) - dort sind automatisch alle Anwendungen auch englisch.
Meine Meinung: Freie Sprachauswahl für alle!
Christian
Windows, Tokens, Access Control List, Dateisicherheit, Desktop, Vista Elevation?
Goto: JEDI API LIB & Windows Security Code Library (JWSCL)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.116 Beiträge
 
Delphi 12 Athens
 
#5

Re: mehrsprachige Resourcen nutzen

  Alt 29. Dez 2007, 14:44
nja, alles Einheitlich halt?

deutsches Windows = deutsche Programme
englisches Windows = englische Programme

und wer ein englisches Windows bediehtn, der sollte (idealer Weise) auch englisch können und somit das englischsprachige Programm dann auch ._.


nja, aber aus diesem Grund hatte ich dann (gab's anfangs noch nicht und ist erst im Zuge der Veröffentlichungsvorbereitung hierfür entstanden), eine Sprachauswahl nachgerüstet.

Aktuelle "Version" ist wärend der Arbeit am FileSplitter entstanden und da dieser Erstens selber keine Daten speichert und auch kein Menü besitzt, ist dort eine Automatische auswahl besser (noch 'nen Sparchauswahldialog beim Programmstart wär blöd).

und da ich auch keine Hellseher programmiere, kann man doch nur über die Windows-/BenutzerSprache auswählen?

PS: irgendwie ist es doch möglich einem englischem Windows zu sagen, daß das/die Programme in deutsch sein sollen.
> ThreadLangID(ThreadLocale), UserDefaultLangID und SystemDefaultLangID

z.B. UserDefaultLangID und die Programme (also LoadString) sollte das Deutsche auslesen
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Dezipaitor

Registriert seit: 14. Apr 2003
Ort: Stuttgart
1.701 Beiträge
 
Delphi 7 Professional
 
#6

Re: mehrsprachige Resourcen nutzen

  Alt 29. Dez 2007, 23:24
In Vista kann man einstellen, welche Sprache ein Benutzer verwendet. Aber nur wenn die Sprache auch installiert ist.

Heutzutage sollte ein gutes Programm dynamisch die Sprache wechseln können. Die Daten aus der Resource dann zu laden ist halt ohne die entsprechende Fkt sehr aufwendig. Resourcen können zudem leicht zu einem Übersetzungsbüro gesendet werden, ohne dass man gleich den Quellcode mitschicken muss.
Christian
Windows, Tokens, Access Control List, Dateisicherheit, Desktop, Vista Elevation?
Goto: JEDI API LIB & Windows Security Code Library (JWSCL)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.116 Beiträge
 
Delphi 12 Athens
 
#7

Re: mehrsprachige Resourcen nutzen

  Alt 3. Jan 2008, 03:40
Zitat von Dezipaitor:
Heutzutage sollte ein gutes Programm dynamisch die Sprache wechseln können. ... Resourcen können zudem leicht zu einem Übersetzungsbüro gesendet werden, ohne dass man gleich den Quellcode mitschicken muss.
drum mach ich mir ja die ganze Arbeit
und bis auf einige wenige Fehlermeldungen ist im aktuellem Programm nun auch alles in die .rc/.res-Datei ausgelagert.

Für zukünftige Programme muß ich mir noch überlegen sowas (z.B. wie dein großes Werk) einzusetzen,
aber in dem kleine, Programm wäre das für mich viel zu groß für dieses minimalistische Programm.

Außerdem bräuchte ich dann wieder ein paar Zusatzfunktion zu LoadLocalizedString
- rausfinden was für Psrachen vorhanden sind
- auswählen welche Sprache verwendet werden soll
(irgendwie muß man ja erstmal PrimaryLanguageId und SubLanguageId festlegen)

Dann mal 'ne Frage: Warum hast du PrimaryLanguageId und SubLanguageId getrennt und nicht zusammen als als LANGID definiert?


Im Anhang mal mein neues Demo-/Testprojekt, wo nun auch mal ein paar Wrapper-Funktionen für FindResourceLang enthalten sind.
ComboBox=0 für automatische Auswahl, sonst entsprechende Sprache

Hab mich nun entschieden die "Fehlerbehandlung" aus FindResourceLang rauszunehmen.

(Haupt)Funktionen:
Code:
[b]Const[/b] frDefaultLang = LANG_ENGLISH or (SUBLANG_ENGLISH_US shl 10);

[b]Var[/b] frGUILang: LANGID = LANG_NEUTRAL or (SUBLANG_NEUTRAL shl 10);

[b]Function[/b] FindResourceLang([b]Var LangResList: TEnumResRec[/b]): Integer;
[b]Function[/b] FindResourceLangEx([b]Var LangResList: TEnumResRecEx[/b]): Integer;

[color=blue]// wrapper functions for FindResourceLang(Ex)[/color]

[b]Function[/b] LoadStringLangW(hModule: HINST; [b]uID: LongWord[/b];
  [b]lpBuffer: PWideChar[/b]; nBufferMax: Integer; Lang: LANGID): Integer;
[b]Function[/b] LoadStringLangW(hModules: TResLangModules; [b]uID: LongWord[/b];
  [b]lpBuffer: PWideChar[/b]; nBufferMax: Integer; Lang: LANGID): Integer;

[b]Function[/b] LoadStringLangW(hModule: HINST; [b]uID: LongWord[/b]; Lang: LANGID): [b]WideString[/b];
[b]Function[/b] LoadStringLangW(hModules: TResLangModules; [b]uID: LongWord[/b]; Lang: LANGID): [b]WideString[/b];

[b]Function[/b] LoadResourceLang(hModule: HINST; [b]ResType: PWideChar[/b];
  [b]ResName: PWideChar[/b]; Lang: LANGID; [b]Out ResSize: LongInt[/b]): [b]Pointer[/b];
[b]Function[/b] LoadResourceLang(hModules: TResLangModules; [b]ResType: PWideChar[/b];
  [b]ResName: PWideChar[/b]; Lang: LANGID; [b]Out ResSize: LongInt[/b]): [b]Pointer[/b];

[color=blue]// wrapper functions for FindResourceLang(Ex) with error string[/color]
...

[color=blue]// wrapper functions for FindResourceLang(Ex) with exception
// check result of FindResourceLang(Ex), LoadStringLangW and LoadResourceLang[/color]
...
einige Beispielaufrufe:
Delphi-Quellcode:
S := LoadStringLangW(HInstance, {StringID}, {LangID});

If LoadStringLangW(HInstance, {StringID}, @Buffer, Length(Buffer), {LangID}) > 0 Then
  S := PWideChar(@Buffer);

Modules := frClearModules;
Modules[0] := HInstance;
Modules[1] := GetModuleHandle('LangDLL.dll');
If LoadStringLangW(Modules, {StringID}, @Buffer, Length(Buffer), {LangID}) > 0 Then
  S := PWideChar(@Buffer);

P := LoadResourceLang(HInstance, {ResType}, {ResID}, {LangID}, ResLen);
If P <> nil Then Begin
  //P = pointer to resource
  //ResLen = size of resource

S := LoadStringLangW(HInstance, {StringID}, {LangID});
Try
  // If S = '' Then Raise ...
  CheckResourceLang({StringID}, S);
Except

i := LoadStringLangW(HInstance, {StringID}, @Buffer, Length(Buffer), {LangID});
Try
  // If i = 0 Then Raise ...
  CheckResourceLang(103, i);
  //Buffer = String
Except

LangResList.hModule := HInstance;
LangResList.ResType := {ResType};
LangResList.ResName := {ResID};
i := FindResourceLang(LangResList);
Try
  // If i < 0 Then Raise ...
  CheckResourceLang(LangResList, i);
  //LangResList.LangIDs = Strings
Except

LangResList.hModule := HInstance;
LangResList.ResType := {ResType};
LangResList.ResName := {ResID};
FindResourceLang(LangResList);
Try
  // If Length(LangResList.LangIDs) = 0 Then Raise ...
  CheckResourceLang(LangResList);
  //LangResList.LangIDs = Strings
Except
[edit=sakura] Anhang auf Wunsch entfernt, neuer weiter unten. Mfg, sakura[/edit]
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Dezipaitor

Registriert seit: 14. Apr 2003
Ort: Stuttgart
1.701 Beiträge
 
Delphi 7 Professional
 
#8

Re: mehrsprachige Resourcen nutzen

  Alt 3. Jan 2008, 12:21
Zitat von himitsu:
Dann mal 'ne Frage: Warum hast du PrimaryLanguageId und SubLanguageId getrennt und nicht zusammen als als LANGID definiert?
Weil das so von MS kommt. Es gibt ja in Deutsch auch mehrere Subtypen, z.B. Schweiz, Liechtenstein usw.
Christian
Windows, Tokens, Access Control List, Dateisicherheit, Desktop, Vista Elevation?
Goto: JEDI API LIB & Windows Security Code Library (JWSCL)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.116 Beiträge
 
Delphi 12 Athens
 
#9

Re: mehrsprachige Resourcen nutzen

  Alt 3. Jan 2008, 12:49
hab's zwar nich auf die Schnelle im MSDN gefunden, aber hier was aus der Windows.pas

LANGID kann beides enthalten ... intern rechnest du es ja auch zusammen
und an die meisten WinAPIs gibt man es auch zusammen weiter.


language ID [16 bit] = Sublanguage ID + Primary Language ID

Code:
{ Translated from WINNT.H (only things needed for API calls) }

{line 510}
(*
 *  Language IDs.
 *
    ...
 *)

{ Primary language IDs. }

  LANG_*

{ Sublanguage IDs. }

  { The name immediately following SUBLANG_ dictates which primary
    language ID that sublanguage ID can be combined with to form a
    valid language ID. }

  SUBLANG_*

{ Sorting IDs. }

  SORT_*


(*
 *  A language ID is a 16 bit value which is the combination of a
 *  primary language ID and a secondary language ID. The bits are
 *  allocated as follows:
 *
 *       [color=#ff0000]+-----------------------+-------------------------+[/color]
 *       [color=#ff0000]|     Sublanguage ID   |   Primary Language ID  |[/color]
 *       [color=#ff0000]+-----------------------+-------------------------+[/color]
 *        15                   10 9                       0   bit
 *
 *
 *
 *  A locale ID is a 32 bit value which is the combination of a
 *  language ID, a sort ID, and a reserved area. The bits are
 *  allocated as follows:
 *
 *       +-------------+---------[color=#7f0000]+-------------------------+[/color]
 *       |   Reserved | Sort ID [color=#7f0000]|      Language ID       |[/color]
 *       +-------------+---------[color=#7f0000]+-------------------------+[/color]
 *        31         20 19     16 15                      0   bit
 *
 *)
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Benutzerbild von Remko
Remko

Registriert seit: 10. Okt 2006
Ort: 's-Hertogenbosch, Die Niederlande
222 Beiträge
 
RAD-Studio 2010 Arc
 
#10

Re: mehrsprachige Resourcen nutzen

  Alt 4. Jan 2008, 08:59
Interesting thread. As Dezipaitor says Windows Vista offers multiple languages on a system, this is called MUI (Multilingual User Interface) by Microsoft. Windows 2000 and higher have special corporate MUI versions with the same functionality. This is used often in Terminal Server or Citrix environments where multiple users log on to the same system.

So it's important to determine the correct language for the user (and not the system!) and to foresee adjustment of the language during process execution. One approach could be to extract resource strings from microsoft DLL's and EXE in which case you don't have to provide the translations. This might be a risk though as they could change in future Windows versions (this doesn't seem to happen often though).

Some Microsoft applications, like Office, also provide MUI. More info on MUI can be found here: http://www.microsoft.com/globaldev/r...e/muizone.mspx and
here: Application Compatibility in Windows MUI and perhaps the most important one here: Writing Win32 Multilingual User Interface Applications.

Hope this helps!
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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 05:30 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