![]() |
mehrsprachige Resourcen nutzen
Im Zuge einer mehrsprachigen Unterstütung
und da ![]() 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:
wird z.B. so verwendet;
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;
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:
Code 2 (ohne Exception):
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)^, ...);
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:
DefaultLang die Sprache in der eure Anwendung hauptsächlich perstellt wurde
Var LangResList: TEnumResRec;
Language: Integer; LangResList.hModule := ...; LangResList.ResType := ...; LangResList.ResName := ...; Language := FindResourceLang(LangResList); If Language < 0 Then {Error} ... 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:
wurde keine Resource gefungen, so wird eine Exception ausgelößt und für RT_STRING ein Fehlertext zurückgegeben
GUILang
ThreadLangID UserDefaultLangID SystemDefaultLangID GUILang (ignore SUBLANG_*) ThreadLangID (ignore SUBLANG_*) UserDefaultLangID (ignore SUBLANG_*) SystemDefaultLangID (ignore SUBLANG_*) DefaultLang (ignore SUBLANG_*) LANG_NEUTRAL erste gefungene Sprache 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:
diese ließe sich ganz gut über die Sprachnamen (welche man natürlich mit speichern müßte) machen:
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}
Delphi-Quellcode:
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.
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 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:
aber da gibt's Probleme mit den Untersprachen (SUBLANG_*)
GUILang
GUILang (ignore SUBLANG_*) ThreadLangID ThreadLangID (ignore SUBLANG_*) UserDefaultLangID UserDefaultLangID (ignore SUBLANG_*) SystemDefaultLangID SystemDefaultLangID (ignore SUBLANG_*) DefaultLang (ignore SUBLANG_*) LANG_NEUTRAL erste gefungene Sprache 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 :gruebel: [edit=sakura] Anhang auf Wunsch entfernt, neuer weiter unten. Mfg, sakura[/edit] |
Re: mehrsprachige Resourcen nutzen
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; |
Re: mehrsprachige Resourcen nutzen
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 :stupid: ) 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. :angel: Ich schau mich aber noch etwas bei dir um. |
Re: mehrsprachige Resourcen nutzen
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! |
Re: mehrsprachige Resourcen nutzen
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 |
Re: mehrsprachige Resourcen nutzen
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. |
Re: mehrsprachige Resourcen nutzen
Zitat:
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:
einige Beispielaufrufe:
[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] ...
Delphi-Quellcode:
[edit=sakura] Anhang auf Wunsch entfernt, neuer weiter unten. Mfg, sakura[/edit]
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 |
Re: mehrsprachige Resourcen nutzen
Zitat:
|
Re: mehrsprachige Resourcen nutzen
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 :-D
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 * *) |
Re: mehrsprachige Resourcen nutzen
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: ![]() here: ![]() ![]() Hope this helps! |
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:57 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