Socke hat geschrieben:Werden .po-Files, die als Ressource eingebunden sind, automatisch (mit DefaultTranslator) verwendet?
Nein. So eine Funktion ist willkommen.
Socke hat geschrieben:Werden .po-Files, die als Ressource eingebunden sind, automatisch (mit DefaultTranslator) verwendet?
Mattias hat geschrieben:Nein. So eine Funktion ist willkommen.
Code: Alles auswählen
(* Changes:
* 1 - Initial Version with po files
* 2 - Also accept mo files with gettext and set LRSTranslator
*)
uses
Translations, resource, lazutf8, LResources, LCLTranslator, gettext;
(* Create and assing a translator for form resouces from a po resource
* Requires patch from http://bugs.freepascal.org/view.php?id=27616
*)
procedure SetLRSTranslatorFromResouce(const aResName: String; aModule: TFPResourceHMODULE;
aResouceType: PChar);
var
rs: TResourceStream;
po: TPOFile;
Trls: TUpdateTranslator;
mo: TMOFile;
begin
rs := TResourceStream.Create(aModule, aResName, aResouceType);
try
if UpperCase(RightStr(aResName, 2)) = 'PO' then
begin
po := TPOFile.Create(rs, False);
Trls := TPOTranslator.Create(po);
end else
begin
mo := TMOFile.Create(rs);
Trls := TDefaultTranslator.Create(mo);
end;
LRSTranslator.Free;
LRSTranslator := Trls;
finally
rs.Destroy;
end;
end;
(* Generic/Minimal translation from resouce streams with maximum parameters
*)
procedure TranslateUnitFromResource(const aUnit, aResouceName: String;
aInstance: TFPResourceHMODULE; aResouceType: PChar);
var
po: TPOFile;
rs: TResourceStream;
mo: TMOFile;
begin
po := nil;
mo := nil;
rs := TResourceStream.Create(aInstance, aResouceName, aResouceType);
try
if UpperCase(RightStr(aResouceName, 2)) = 'PO' then
begin
po := TPOFile.Create(rs, False);
Translations.TranslateUnitResourceStrings(aUnit, po);
end else
begin
mo := TMOFile.Create(rs);
gettext.TranslateUnitResourceStrings(aUnit, mo);
end;
finally
po.Free;
mo.Free;
rs.Destroy;
end;
end;
(* Enumerates all RT_RCDATA resouces to a TStringList
*)
function EnumPoResources({%H-}ModuleHandle : TFPResourceHMODULE; ResourceType, ResourceName : PChar; lParam : PtrInt) : LongBool; stdcall;
var
l: TStringList;
ftype: String;
begin
Assert(ResourceType = PChar(RT_RCDATA), Format('Invalid resouce type, got %d expected %d.', [PtrInt(ResourceType), RT_RCDATA]));
Assert(lParam <> 0, 'String list not assigned.');
l := TStringList(lParam);
Assert(l is TStrings, Format('Got list class %s expected descendant of %s.', [l.ClassName, TStrings.ClassName]));
ftype := upcase(RightStr(String(ResourceName), 2));
if (ftype = 'PO') or (ftype = 'MO') then
l.Add(ResourceName);
Result := True;
end;
(* Expects resouce name format: <UNIT>.<LANGUAGE>.PO
* with <UNIT> = Unit name
* <LANGUAGE> = language code ('de_DE' or 'de')
* resouce name is used case insensitive
*
* thus a resouce name is at least 7 characters long
*)
procedure TranslateAllUnitsFromResource;
var
ResourceNames: TStringList;
ResName: String;
LangDelim: SizeInt;
Lang: String;
T: String;
PoUnitName: String;
PoLangCode: String;
PoLangCodeLen: Integer;
appname: String;
begin
// only one way to get a language ID, for full comatibiltiy,
// LCLTranslator.FindLocaleFileName() should be split up
Lang := '';
T := '';
LazGetLanguageIDs(Lang, T);
Lang := UpperCase(Lang); // case insensitive
T := UpperCase(T); // case insensitive
appname := ExtractFileNameOnly(Paramstr(0));
appname := Uppercase(appname);
ResourceNames := TStringList.Create;
try
EnumResourceNames(HINSTANCE, PChar(RT_RCDATA), @EnumPoResources, PtrInt(ResourceNames));
for ResName in ResourceNames do
begin
if Length(ResName) < 7 then
Continue;
ResName := UpperCase(ResName); // case insensitive
Assert(
(RightStr(ResName, 2) = 'PO') or
(RightStr(ResName, 2) = 'MO'),
'Unexpected resouce name.'
);
LangDelim := Pos('.', ResName);
PoUnitName := Copy(ResName, 1, LangDelim - 1);
Assert(Length(PoUnitName) >= 1, 'Empty unit name.');
PoLangCodeLen := Length(ResName) - LangDelim - Length('.PO');
PoLangCode := Copy(ResName, LangDelim+1, PoLangCodeLen);
if Length(PoLangCode) = 0 then
continue; // No language code found
if (PoLangCode = Lang) or (PoLangCode = T) then
begin
// always translate the "Unit". it may also be the project file (.lpr)
TranslateUnitFromResource(PoUnitName, ResName, HINSTANCE, PChar(RT_RCDATA));
// Translator for form resources
if PoUnitName = appname then
SetLRSTranslatorFromResouce(ResName, HInstance, Pchar(RT_RCDATA));
end;
end;
finally
ResourceNames.Destroy;
end;
end;
Mattias hat geschrieben:Nein. So eine Funktion ist willkommen.
Socke hat geschrieben:Die LCL sammelt in der Unit LCLStrConsts alle Ressoucen-Strings; für diese Unit gibt es entsprechende .po-Dateien.
Wenn ich für ein Projekt in den Projekteinstellung i18n einschalte, wird nur eine .po-Datei für die gesamte Anwendung erstellt. Warum sind die Ressoucen-Strings aus LCLStrConsts hier nicht enthalten?
Socke hat geschrieben:Wie wird bestimmt, welche Ressoucen-Strings in welcher .po-Datei geschrieben werden? Wie sieht das bei (mehreren) Packages aus?
Socke hat geschrieben:Was ist mit der Übersetzung der RTL (RTLConsts) - wo liegen die .po-Dateien hierzu?
Mattias hat geschrieben:Mattias hat geschrieben:Nein. So eine Funktion ist willkommen.
Zum Beispiel so:
http://wiki.lazarus.freepascal.org/Tran ... executable
Mattias hat geschrieben:Die IDE erzeugt eine .po Datei pro Projekt und pro Package.
Socke hat geschrieben:Ich könnte mir auch vorstellen, dass pro Unit eine .po-Datei gewünscht wird - diesen Weg müsste man derzeit ohne die IDE beschreiten.
Mattias hat geschrieben:Socke hat geschrieben:Ich könnte mir auch vorstellen, dass pro Unit eine .po-Datei gewünscht wird - diesen Weg müsste man derzeit ohne die IDE beschreiten.
Das könnte man ja optional machen. Patches sind willkommen.
ruewa hat geschrieben:Dort enthalten ist auch eine Unit, die das Ganze weitgehend automatisiert.
ruewa hat geschrieben:Leider versickert sowas hier allzu lautlos, ich selber tu mich ja schon schwer, es wiederzufinden...
Socke hat geschrieben:Ich hatte nie verstanden, warum hier im Forum eine eigene WissensDB aufgebaut werden soll, wenn doch schon recht viel im Wiki vorhanden ist.