389
procedure TranslateUnitResourceStrings(const ResUnitName, BaseFilename,
390
Lang, FallbackLang: string);
412
function TranslateUnitResourceStrings(const ResUnitName, BaseFilename,
413
Lang, FallbackLang: string):TTranslateUnitResult;
392
if (ResUnitName='') or (BaseFilename='') then exit;
394
//debugln('TranslateUnitResourceStrings BaseFilename="',BaseFilename,'"');
395
if (FallbackLang<>'') then
396
TranslateUnitResourceStrings(ResUnitName,Format(BaseFilename,[FallbackLang]));
398
TranslateUnitResourceStrings(ResUnitName,Format(BaseFilename,[Lang]));
415
Result:=turOK; //Result: OK
416
if (ResUnitName='') or (BaseFilename='') then
417
Result:=turEmptyParam //Result: empty Parameter
419
//debugln('TranslateUnitResourceStrings BaseFilename="',BaseFilename,'"');
420
if (FallbackLang<>'') and FileExistsUTF8(Format(BaseFilename,[FallbackLang])) then
421
TranslateUnitResourceStrings(ResUnitName,Format(BaseFilename,[FallbackLang]))
423
Result:=turNoFBLang; //Result: missing FallbackLang file
424
if (Lang<>'') and FileExistsUTF8(Format(BaseFilename,[Lang])) then
425
TranslateUnitResourceStrings(ResUnitName,Format(BaseFilename,[Lang]))
427
Result:=turNoLang; //Result: missing Lang file
401
431
function TranslateResourceStrings(po: TPOFile): boolean;
572
593
LineStart: PChar;
574
595
Identifier: String;
575
MsgID,MsgStr,PrevMsgID: String;
577
597
Comments: String;
581
i, CollectedIndex: Integer;
582
601
OldLineStartPos: PtrUInt;
606
Msg: array[TMsg] of string;
586
608
procedure ResetVars;
591
614
Identifier := '';
596
CollectedIndex := ciNone;
599
procedure StoreCollectedLine;
601
case CollectedIndex of
602
ciMsgID: MsgID := Line;
603
ciMsgStr: MsgStr := Line;
604
ciPrevMsgID: PrevMsgID := Line;
606
CollectedIndex := ciNone;
609
620
procedure AddEntry;
611
622
Item: TPOFileItem;
614
624
if Identifier<>'' then begin
615
625
// check for unresolved duplicates in po file
616
Item := TPOFileItem(FOriginalToItem.Data[MsgID]);
626
Item := TPOFileItem(FOriginalToItem.Data[Msg[mid]]);
617
627
if (Item<>nil) then begin
618
628
// fix old duplicate context
619
629
if Item.Context='' then
620
Item.Context:=Item.Identifier;
630
Item.Context:=Item.IdentifierLow;
621
631
// set context of new duplicate
623
Context := Identifier;
633
Msg[mctx] := Identifier;
624
634
// if old duplicate was translated and
625
635
// new one is not, provide a initial translation
627
MsgStr := Item.Translation;
637
Msg[mstr] := Item.Translation;
629
Add(Identifier,MsgID,MsgStr,Comments,Context,Flags,PrevMsgID);
639
Add(Identifier,Msg[mid],Msg[mstr],Comments,Msg[mctx],Flags,PrevMsgID);
632
if (Line<>'') and (FHeader=nil) then begin
633
FHeader := TPOFileItem.Create('',MsgID,Line);
642
if (Msg[CurMsg]<>'') and (FHeader=nil) then begin
643
FHeader := TPOFileItem.Create('',Msg[mid],Msg[CurMsg]);
634
644
FHeader.Comments:=Comments;
639
function TestPrefixStr(AIndex: Integer): boolean;
646
ciMsgStr: s:=sMsgStr;
647
ciPrevMsgId: s:=sPrevMsgId;
650
result := CompareMem(LineStart, pchar(s), L);
653
CollectedIndex := AIndex;
654
Line:=UTF8CStringToUTF8String(LineStart+L,LineLen-L-1);
659
650
if Txt='' then exit;
670
CollectedIndex := ciNone;
672
659
while LineStart<TextEnd do begin
673
660
LineEnd:=LineStart;
674
661
while (not (LineEnd^ in [#0,#10,#13])) do inc(LineEnd);
675
662
LineLen:=LineEnd-LineStart;
676
663
if LineLen>0 then begin
677
if CompareMem(LineStart,sCommentIdentifier,3) then begin
679
Identifier:=copy(s,LineStart-p+4,LineLen-3);
680
// the RTL creates identifier paths with point instead of colons
682
for i:=1 to length(Identifier) do
683
if Identifier[i]=':' then
685
end else if TestPrefixStr(ciMsgId) then begin
686
end else if TestPrefixStr(ciMsgStr) then begin
687
end else if TestPrefixStr(ciPrevMsgId) then begin
688
end else if CompareMem(LineStart, sMsgCtxt,9) then begin
689
Context:= Copy(LineStart, 10, LineLen-10);
690
end else if CompareMem(LineStart, sFlags, 3) then begin
691
Flags := copy(LineStart, 4, LineLen-3);
692
end else if (LineStart^='"') then begin
693
if (MsgID='') and CompareMem(LineStart,sCharSetIdentifier,35) then
695
FCharSet:=copy(LineStart,36,LineLen-38);
696
if SysUtils.CompareText(FCharSet,'UTF-8')<>0 then begin
697
// convert encoding to UTF-8
698
OldLineStartPos:=PtrUInt(LineStart-PChar(s))+1;
699
NewSrc:=ConvertEncoding(copy(s,OldLineStartPos,length(s)),
700
FCharSet,EncodingUTF8);
701
// replace text and update all pointers
702
s:=copy(s,1,OldLineStartPos-1)+NewSrc;
706
LineStart:=p+(OldLineStartPos-1);
708
while (not (LineEnd^ in [#0,#10,#13])) do inc(LineEnd);
709
LineLen:=LineEnd-LineStart;
712
Line := Line + UTF8CStringToUTF8String(LineStart+1,LineLen-2);
713
end else if CompareMem(LineStart, sPrevStr, 4) then begin
714
Line := Line + UTF8CStringToUTF8String(LineStart+5,LineLen-6);
715
end else if LineStart^='#' then begin
717
Comments := Comments + LineEnding;
718
Comments := Comments + Copy(LineStart, 1, LineLen);
670
if LineStart[2]=' ' then begin
673
Identifier:=copy(s,LineStart-p+4,LineLen-3);
674
// the RTL creates identifier paths with point instead of colons
676
for i:=1 to length(Identifier) do
677
if Identifier[i]=':' then
682
if IsKey(LineStart,'#| msgid "') then begin
683
PrevMsgID:=PrevMsgID+GetUTF8String(LineStart+length('#| msgid "'),LineEnd-1);
685
end else if IsKey(LineStart, '#| "') then begin
686
Msg[CurMsg] := Msg[CurMsg] + GetUTF8String(LineStart+length('#| "'),LineEnd-1);
690
if LineStart[2]=' ' then begin
692
Flags := GetUTF8String(LineStart+3,LineEnd);
696
if not Handled then begin
699
Comments := Comments + LineEnding;
700
Comments := Comments + GetUTF8String(LineStart+1,LineEnd);
705
if (LineStart[1]='s') and (LineStart[2]='g') then begin
708
if IsKey(LineStart,'msgid "') then begin
710
Msg[CurMsg]:=Msg[CurMsg]+GetUTF8String(LineStart+length('msgid "'),LineEnd-1);
714
if IsKey(LineStart,'msgstr "') then begin
716
Msg[CurMsg]:=Msg[CurMsg]+GetUTF8String(LineStart+length('msgstr "'),LineEnd-1);
720
if IsKey(LineStart, 'msgctxt "') then begin
722
Msg[CurMsg]:=Msg[CurMsg]+GetUTF8String(LineStart+length('msgctxt "'), LineEnd-1);
730
and IsKey(LineStart,'"Content-Type: text/plain; charset=') then
732
FCharSet:=GetUTF8String(LineStart+length('"Content-Type: text/plain; charset='),LineEnd);
733
if SysUtils.CompareText(FCharSet,'UTF-8')<>0 then begin
734
// convert encoding to UTF-8
735
OldLineStartPos:=PtrUInt(LineStart-PChar(s))+1;
736
NewSrc:=ConvertEncoding(copy(s,OldLineStartPos,length(s)),
737
FCharSet,EncodingUTF8);
738
// replace text and update all pointers
739
s:=copy(s,1,OldLineStartPos-1)+NewSrc;
743
LineStart:=p+(OldLineStartPos-1);
745
while (not (LineEnd^ in [#0,#10,#13])) do inc(LineEnd);
746
LineLen:=LineEnd-LineStart;
750
Msg[CurMsg]:=Msg[CurMsg]+GetUTF8String(LineStart+1,LineEnd-1);
722
757
LineStart:=LineEnd+1;
723
while (LineStart<TextEnd) and (LineStart^ in [#10,#13]) do inc(LineStart);
758
while (LineStart^ in [#10,#13]) do inc(LineStart);
734
769
if (not FAllEntries) and (TranslatedValue='') then exit;
735
Item:=TPOFileItem.Create(Identifier,OriginalValue,TranslatedValue);
770
Item:=TPOFileItem.Create(lowercase(Identifier),OriginalValue,TranslatedValue);
736
771
Item.Comments:=Comments;
737
772
Item.Context:=Context;
738
773
Item.Flags:=Flags;
739
774
Item.PreviousID:=PreviousID;
741
776
FItems.Add(Item);
743
//debugln('TPOFile.Add %8x Tag=%d Id="%s" Org="%s" Trn="%s"',
744
// [ptrint(Item),FTag,Identifier,dbgstr(OriginalValue),dbgstr(TranslatedValue)]);
745
FIdentifierToItem.Add(Identifier,Item);
778
//debugln(['TPOFile.Add Identifier=',Identifier,' Orig="',dbgstr(OriginalValue),'" Transl="',dbgstr(TranslatedValue),'"']);
779
FIdentifierLowToItem[Item.IdentifierLow]:=Item;
746
780
P := Pos('.', Identifier);
748
FIdentVarToItem.Add(copy(Identifier, P+1, Length(IDentifier)), Item);
750
//if FIdentifierToItem.Data[UpperCase(Identifier)]=nil then raise Exception.Create('');
751
FOriginalToItem.Add(OriginalValue,Item);
752
//if FOriginalToItem.Data[OriginalValue]=nil then raise Exception.Create('');
782
FIdentLowVarToItem.Add(copy(Item.IdentifierLow, P+1, Length(Item.IdentifierLow)), Item);
784
if OriginalValue<>'' then
785
FOriginalToItem.Add(OriginalValue,Item);
755
788
function TPOFile.Translate(const Identifier, OriginalValue: String): String;
757
790
Item: TPOFileItem;
759
Item:=TPOFileItem(FIdentifierToItem.Data[Identifier]);
792
Item:=TPOFileItem(FIdentifierLowToItem[lowercase(Identifier)]);
761
794
Item:=TPOFileItem(FOriginalToItem.Data[OriginalValue]);
762
795
if Item<>nil then begin
1003
1012
WriteLst('msgstr', StrToPoStr(Item.Translation));
1004
1013
OutLst.Add('');
1008
1017
if FHeader=nil then
1011
1020
if FHelperList=nil then
1012
1021
FHelperList:=TStringList.Create;
1026
// Sort list of items by identifier
1027
FItems.Sort(@ComparePOItems);
1029
for j:=0 to Fitems.Count-1 do
1030
WriteItem(TPOFileItem(FItems[j]));
1033
procedure TPOFile.RemoveTaggedItems(aTag: Integer);
1038
// get rid of all entries that have Tag=aTag
1039
for i:=FItems.Count-1 downto 0 do begin
1040
Item := TPOFileItem(FItems[i]);
1041
if Item.Tag<>aTag then
1043
FIdentifierLowToItem.Remove(Item.IdentifierLow);
1044
FOriginalToItem.Remove(Item.Original, Item);
1050
procedure TPOFile.SaveToFile(const AFilename: string);
1052
OutLst: TStringList;
1014
1054
OutLst := TStringList.Create;
1019
// Sort list of items by identifier
1020
FItems.Sort(@ComparePOItems);
1022
for j:=0 to Fitems.Count-1 do
1023
WriteItem(TPOFileItem(FItems[j]));
1025
//if not DirectoryExistsUTF8(ExtractFileDir(AFilename)) then
1026
// ForceDirectoriesUTF8(ExtractFileDir(AFilename));
1056
SaveToStrings(OutLst);
1028
1057
OutLst.SaveToFile(UTF8ToSys(AFilename));
1036
1063
function SkipLineEndings(var P: PChar; var DecCount: Integer): Integer;