IDE: updating po files using codetools file caches

git-svn-id: trunk@34334 -
This commit is contained in:
mattias 2011-12-20 22:09:06 +00:00
parent 87b8887d73
commit 1b781cdb35
3 changed files with 198 additions and 46 deletions

View File

@ -32,7 +32,7 @@ interface
uses
Classes, SysUtils, GetText, LCLProc, Translations,
IDEProcs, FileProcs, avl_tree,
CodeToolManager, DirectoryCacher,
CodeToolManager, DirectoryCacher, CodeCache,
LazarusIDEStrConsts;
{ IDE Language (Human, not computer) }
@ -64,6 +64,8 @@ type
property Count: integer read FCount;
property Items[Index: integer]: TLazarusTranslation read GetItems; default;
end;
PPOFile = ^TPOFile;
// translate all resource strings
procedure TranslateResourceStrings(const BaseDirectory, CustomLang: string);
@ -77,6 +79,12 @@ procedure CollectTranslations(const LazarusDir: string);
function ConvertRSTFiles(RSTDirectory, PODirectory: string;
POFilename: string = '' // set POFilename to gather all rst into one po file
): Boolean;
procedure UpdatePoFileAndTranslations(SrcFiles: TStrings;
const POFilename: string);
procedure UpdateBasePoFile(SrcFiles: TStrings;
const POFilename: string; POFile: PPOFile = nil);
function FindTranslatedPoFiles(const BasePOFilename: string): TStringList;
procedure UpdateTranslatedPoFile(const BasePOFile: TPOFile; TranslatedFilename: string);
var
LazarusTranslations: TLazarusTranslations = nil;
@ -250,7 +258,7 @@ begin
for i:=0 to Items.Count-1 do begin
Item:=PItem(Items[i]);
if (not Item^.NeedUpdate) or (Item^.RSTFileList.Count=0) then continue;
UpdatePoFile(Item^.RSTFileList, Item^.OutputFilename);
UpdatePoFileAndTranslations(Item^.RSTFileList, Item^.OutputFilename);
end;
Result:=true;
except
@ -271,6 +279,148 @@ begin
end;
end;
procedure UpdatePoFileAndTranslations(SrcFiles: TStrings;
const POFilename: string);
var
BasePOFile: TPOFile;
TranslatedFiles: TStringList;
TranslatedFilename: String;
begin
BasePOFile:=nil;
UpdateBasePoFile(SrcFiles,POFilename,@BasePOFile);
if BasePOFile=nil then exit;
TranslatedFiles:=nil;
try
TranslatedFiles:=FindTranslatedPoFiles(POFilename);
if TranslatedFiles=nil then exit;
for TranslatedFilename in TranslatedFiles do begin
if FileAgeCached(TranslatedFilename)>=FileAgeCached(POFilename) then
continue;
UpdateTranslatedPoFile(BasePOFile,TranslatedFilename);
end;
finally
TranslatedFiles.Free;
BasePOFile.Free;
end;
end;
procedure UpdateBasePoFile(SrcFiles: TStrings;
const POFilename: string; POFile: PPOFile);
var
BasePOFile: TPOFile;
i: Integer;
Filename: String;
POBuf: TCodeBuffer;
FileType: TStringsType;
SrcBuf: TCodeBuffer;
SrcLines: TStringList;
OldChangeStep: Integer;
begin
POBuf:=CodeToolBoss.LoadFile(POFilename,true,false);
SrcLines:=TStringList.Create;
BasePOFile := TPOFile.Create;
try
if POBuf<>nil then
BasePOFile.ReadPOText(POBuf.Source);
BasePOFile.Tag:=1;
// Update po file with lrt or/and rst files
for i:=0 to SrcFiles.Count-1 do begin
Filename:=SrcFiles[i];
if CompareFileExt(Filename,'.lrt',false)=0 then
FileType:=stLrt
else if CompareFileExt(Filename,'.rst',false)=0 then
FileType:=stRst
else
continue;
SrcBuf:=CodeToolBoss.LoadFile(Filename,true,false);
if SrcBuf=nil then continue;
SrcLines.Text:=SrcBuf.Source;
BasePOFile.UpdateStrings(SrcLines,FileType);
end;
SrcLines.Clear;
BasePOFile.SaveToStrings(SrcLines);
if POBuf=nil then begin
POBuf:=CodeToolBoss.CreateFile(POFilename);
if POBuf=nil then exit;
end;
OldChangeStep:=POBuf.ChangeStep;
//debugln(['UpdateBasePoFile ',POFilename,' Modified=',POBuf.Source<>SrcLines.Text]);
POBuf.Source:=SrcLines.Text;
if (not POBuf.IsVirtual) and (OldChangeStep<>POBuf.ChangeStep) then begin
debugln(['UpdateBasePoFile saving ',POBuf.Filename]);
POBuf.Save;
end;
finally
SrcLines.Free;
if POFile<>nil then
POFile^:=BasePOFile
else
BasePOFile.Free;
end;
end;
function FindTranslatedPoFiles(const BasePOFilename: string): TStringList;
var
Path: String;
Name: String;
NameOnly: String;
Dir: TCTDirectoryCache;
Files: TStrings;
Filename: String;
begin
Result:=TStringList.Create;
Path:=ExtractFilePath(BasePOFilename);
Name:=ExtractFileName(BasePOFilename);
NameOnly:=ExtractFileNameOnly(Name);
Dir:=CodeToolBoss.DirectoryCachePool.GetCache(Path);
Files:=TStringList.Create;
try
Dir.GetFiles(Files,false);
for Filename in Files do begin
if CompareFilenames(Filename,Name)=0 then continue;
if CompareFileExt(Filename,'.po',false)<>0 then continue;
if (CompareFilenames(LeftStr(Filename,length(NameOnly)),NameOnly)<>0)
then
continue;
Result.Add(Path+Filename);
end;
finally
Files.Free;
Dir.Release;
end;
end;
procedure UpdateTranslatedPoFile(const BasePOFile: TPOFile;
TranslatedFilename: string);
var
POBuf: TCodeBuffer;
POFile: TPOFile;
Lines: TStringList;
OldChangeStep: Integer;
begin
POFile := TPOFile.Create;
Lines:=TStringList.Create;
try
POBuf:=CodeToolBoss.LoadFile(TranslatedFilename,true,false);
if POBuf<>nil then
POFile.ReadPOText(POBuf.Source);
POFile.Tag:=1;
POFile.UpdateTranslation(BasePOFile);
POFile.SaveToStrings(Lines);
OldChangeStep:=POBuf.ChangeStep;
//debugln(['UpdateTranslatedPoFile ',POBuf.Filename,' Modified=',POBuf.Source<>Lines.Text]);
POBuf.Source:=Lines.Text;
if (not POBuf.IsVirtual) and (OldChangeStep<>POBuf.ChangeStep) then begin
//debugln(['UpdateTranslatedPoFile saving ',POBuf.Filename]);
POBuf.Save;
end;
finally
Lines.Free;
POFile.Free;
end;
end;
{-------------------------------------------------------------------------------
TranslateResourceStrings

View File

@ -4365,7 +4365,7 @@ begin
if Files.Tree.Count=0 then exit(mrOk);
Files.GetNames(FileList);
try
UpdatePoFile(FileList, POFilename);
UpdatePoFileAndTranslations(FileList, POFilename);
Result := mrOk;
except
on E:EPOFileError do begin

View File

@ -124,6 +124,7 @@ type
procedure Report;
procedure CreateHeader;
procedure UpdateStrings(InputLines:TStrings; SType: TStringsType);
procedure SaveToStrings(OutLst: TStrings);
procedure SaveToFile(const AFilename: string);
procedure UpdateItem(const Identifier: string; Original: string);
procedure UpdateTranslation(BasePOFile: TPOFile);
@ -148,7 +149,6 @@ var
// if you don't use UTF-8, install a proper widestring manager and set this
// to false.
// translate resource strings for one unit
function TranslateUnitResourceStrings(const ResUnitName, BaseFilename,
Lang, FallbackLang: string):TTranslateUnitResult; overload;
@ -167,6 +167,12 @@ function UpdatePoFile(Files: TStrings; const POFilename: string): boolean;
implementation
function ComparePOItems(Item1, Item2: Pointer): Integer;
begin
Result := CompareText(TPOFileItem(Item1).IdentifierLow,
TPOFileItem(Item2).IdentifierLow);
end;
function UTF8ToSystemCharSet(const s: string): string; inline;
begin
if SystemCharSetIsUTF8 then
@ -178,7 +184,6 @@ begin
{$ENDIF}
end;
function StrToPoStr(const s:string):string;
var
SrcPos, DestPos: Integer;
@ -975,32 +980,8 @@ begin
RemoveUntaggedModules;
end;
procedure TPOFile.RemoveTaggedItems(aTag: Integer);
procedure TPOFile.SaveToStrings(OutLst: TStrings);
var
Item: TPOFileItem;
i: Integer;
begin
// get rid of all entries that have Tag=aTag
for i:=FItems.Count-1 downto 0 do begin
Item := TPOFileItem(FItems[i]);
if Item.Tag<>aTag then
Continue;
FIdentifierLowToItem.Remove(Item.IdentifierLow);
//FOriginalToItem.Remove(Item.Original); // isn't this tricky?
FItems.Delete(i);
Item.Free;
end;
end;
function ComparePOItems(Item1, Item2: Pointer): Integer;
begin
result := CompareText(TPOFileItem(Item1).IdentifierLow,
TPOFileItem(Item2).IdentifierLow);
end;
procedure TPOFile.SaveToFile(const AFilename: string);
var
OutLst: TStringList;
j: Integer;
procedure WriteLst(const AProp, AValue: string );
@ -1010,7 +991,7 @@ var
begin
if (AValue='') and (AProp='') then
exit;
FHelperList.Text:=AValue;
if FHelperList.Count=1 then begin
if AProp='' then OutLst.Add(FHelperList[0])
@ -1029,7 +1010,7 @@ var
end;
end;
end;
procedure WriteItem(Item: TPOFileItem);
begin
WriteLst('',Item.Comments);
@ -1045,31 +1026,52 @@ var
WriteLst('msgstr', StrToPoStr(Item.Translation));
OutLst.Add('');
end;
begin
if FHeader=nil then
CreateHeader;
if FHelperList=nil then
FHelperList:=TStringList.Create;
// write header
WriteItem(FHeader);
// Sort list of items by identifier
FItems.Sort(@ComparePOItems);
for j:=0 to Fitems.Count-1 do
WriteItem(TPOFileItem(FItems[j]));
end;
procedure TPOFile.RemoveTaggedItems(aTag: Integer);
var
Item: TPOFileItem;
i: Integer;
begin
// get rid of all entries that have Tag=aTag
for i:=FItems.Count-1 downto 0 do begin
Item := TPOFileItem(FItems[i]);
if Item.Tag<>aTag then
Continue;
FIdentifierLowToItem.Remove(Item.IdentifierLow);
//FOriginalToItem.Remove(Item.Original); // isn't this tricky?
FItems.Delete(i);
Item.Free;
end;
end;
procedure TPOFile.SaveToFile(const AFilename: string);
var
OutLst: TStringList;
begin
OutLst := TStringList.Create;
try
// write header
WriteItem(FHeader);
// Sort list of items by identifier
FItems.Sort(@ComparePOItems);
for j:=0 to Fitems.Count-1 do
WriteItem(TPOFileItem(FItems[j]));
SaveToStrings(OutLst);
OutLst.SaveToFile(UTF8ToSys(AFilename));
finally
OutLst.Free;
end;
end;
function SkipLineEndings(var P: PChar; var DecCount: Integer): Integer;