diff options
author | graemeg <graemeg@ae50a9b5-8222-0410-bf8d-8a13f76226bf> | 2008-03-17 23:03:33 +0000 |
---|---|---|
committer | graemeg <graemeg@ae50a9b5-8222-0410-bf8d-8a13f76226bf> | 2008-03-17 23:03:33 +0000 |
commit | 794326298c08cfa70d719523d7369ceb5a492c5c (patch) | |
tree | 40aead449836f7c7fd31b8914e6e7b69731efdb2 /tools | |
parent | bdd8e19e6d571fde005f06af11e87a68da923ed7 (diff) | |
download | fpGUI-794326298c08cfa70d719523d7369ceb5a492c5c.tar.xz |
* Created new directories for translations and tools used for localization.
Diffstat (limited to 'tools')
-rwxr-xr-x | tools/build_tools.bat | 4 | ||||
-rwxr-xr-x | tools/localize.sh | 53 | ||||
-rw-r--r-- | tools/updatepofiles.pas | 446 |
3 files changed, 503 insertions, 0 deletions
diff --git a/tools/build_tools.bat b/tools/build_tools.bat new file mode 100755 index 00000000..30d83028 --- /dev/null +++ b/tools/build_tools.bat @@ -0,0 +1,4 @@ + +fpc -O2 -Xs -XX -Sh -FUunits -oupdatepofiles.exe updatepofiles.pas + + diff --git a/tools/localize.sh b/tools/localize.sh new file mode 100755 index 00000000..f150a48d --- /dev/null +++ b/tools/localize.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +# +# Usage: sh localize.sh +# +# This script should be executed after adding new resource strings and after +# updating the translated .po files. +# +# This script +# - converts all compiled .rst files to .po files, +# - updates all translated xx.po files +# + +# enable for debugging +#set -x +set -e + +if [ ! -x updatepofiles.exe ]; then + ./build_tools.bat +fi + +if [ "@"$FPCTARGET == "@" ]; then + FPCTARGET=`fpc -iTP`-`fpc -iTO` + if [ $FPCTARGET == "-" ]; then + FPCTARGET="" + fi +fi + +RSTFILES=( + ".. gfx_constants fpgui" +# "ideintf objinspstrconsts" +# "components/codetools codetoolsstrconsts" +# "lcl lclstrconsts" +) + +for idx in ${!RSTFILES[@]}; do + LINE=(${RSTFILES[idx]}) + RSTDIR=${LINE[0]} + RSTFILE=${LINE[1]} + POFILE=${LINE[2]:-$RSTFILE} + +# RST=`find $RSTDIR/{units,lib}/$FPCTARGET -name $RSTFILE.rst | xargs ls -1t | head -1`; + RST=`find $RSTDIR/{units,lib} -name $RSTFILE.rst | xargs ls -1t | head -1`; + + if [ "@"$RST != "@" ]; then + echo $RSTDIR/languages/$POFILE.po +# rstconv -c UTF-8 -i $RST -o $RSTDIR/languages/$POFILE.po + rstconv -i $RST -o $RSTDIR/languages/$POFILE.po + ./updatepofiles.exe $RSTDIR/languages/$POFILE.po + fi +done + +exit 0 + diff --git a/tools/updatepofiles.pas b/tools/updatepofiles.pas new file mode 100644 index 00000000..7b1d66df --- /dev/null +++ b/tools/updatepofiles.pas @@ -0,0 +1,446 @@ +{ + *************************************************************************** + * * + * This source is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This code is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * General Public License for more details. * + * * + * A copy of the GNU General Public License is available on the World * + * Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also * + * obtain it by writing to the Free Software Foundation, * + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * * + *************************************************************************** + + Author: Mattias Gaertner + + Name: + updatepofiles - updates po files. + + Synopsis: + updatepofiles filename1.po [filename2.po ... filenameN.po] + + Description: + updatepofiles deletes doubles in the po file and merges new strings into + all translated po files (filename1.po.xx) + + Modifications: + Graeme Geldenhuys (2008-03-17): Removed all dependencies to Lazarus units. +} + +program UpdatePoFiles; + +{$mode objfpc}{$H+} + +{$ifdef Windows} + {$define CaseInsensitiveFilenames} +{$endif} + + +uses + Classes, SysUtils, AvL_Tree; + +const + UTF8FileHeader = #$ef#$bb#$bf; + +type + TMsgItem = record + Comment: string; + ID: string; + Str: string; + end; + PMsgItem = ^TMsgItem; + +function CompareMsgItems(Data1, Data2: pointer): integer; +var + MsgItem1: PMsgItem; + MsgItem2: PMsgItem; +begin + MsgItem1:=PMsgItem(Data1); + MsgItem2:=PMsgItem(Data2); + Result:=CompareStr(MsgItem1^.ID,MsgItem2^.ID); +end; + +procedure DisposeMsgTree(var Tree: TAVLTree); +var + Node: TAVLTreeNode; + MsgItem: PMsgItem; +begin + Node:=Tree.FindLowest; + while Node<>nil do begin + MsgItem:=PMsgItem(Node.Data); + Dispose(MsgItem); + Node:=Tree.FindSuccessor(Node); + end; + Tree.Free; + Tree:=nil; +end; + +function GetAllFilesMask: string; +begin + {$IFDEF WINDOWS} + Result:='*.*'; + {$ELSE} + Result:='*'; + {$ENDIF} +end; + +function CompareFilenames(const Filename1, Filename2: string): integer; +begin + {$IFDEF CaseInsensitiveFilenames} + Result:=AnsiCompareText(Filename1, Filename2); + {$ELSE} + Result:=CompareStr(Filename1, Filename2); + {$ENDIF} +end; + + +type + TPoFile = class + public + Tree: TAVLTree; + Header: TStringList; + UTF8Header: string; + constructor Create; + destructor Destroy; override; + end; + +{ TPoFile } + +constructor TPoFile.Create; +begin + Tree:=TAVLTree.Create(@CompareMsgItems); + Header:=TStringList.Create; +end; + +destructor TPoFile.Destroy; +begin + DisposeMsgTree(Tree); + Header.Free; + inherited Destroy; +end; + +//============================================================================== +var + Files: TStringList; + Prefix: string; + +procedure IncPrefix; +begin + Prefix:=Prefix+' '; +end; + +procedure DecPrefix; +begin + Prefix:=LeftStr(Prefix,length(Prefix)-2); +end; + +function ParamsValid: boolean; +var + i: Integer; + Filename: String; + Ext: String; + Name: string; +begin + Result:=false; + if ParamCount<1 then exit; + for i:=1 to ParamCount do begin + Filename:=ParamStr(1); + if not FileExists(Filename) then begin + writeln('ERROR: file not found: ',FileName); + exit; + end; + Ext:=ExtractFileExt(Filename); + if (Ext<>'.po') then begin + writeln('ERROR: invalid extension: ',Filename); + exit; + end; + Name:=ExtractFileName(Filename); + Name:=LeftStr(Name,length(Name)-length(Ext)); + if Pos('.',Name)>0 then begin + writeln('ERROR: invalid unitname: ',Name); + exit; + end; + if Files=nil then Files:=TStringList.Create; + Files.Add(Filename); + end; + Result:=true; +end; + +function ReadMessageItem(SrcFile: TStringList; var Line: integer): PMsgItem; +var + s: string; +begin + New(Result); + while Line<SrcFile.Count do begin + s:=SrcFile[Line]; + if (s<>'') and (s[1]='#') then begin + Result^.Comment:=Result^.Comment+copy(s,2,length(s)); + end + else if (LeftStr(s,7)='msgid "') then begin + // read ID + Result^.ID:=copy(s,8,length(s)-8); + inc(Line); + while Line<SrcFile.Count do begin + s:=SrcFile[Line]; + if (s<>'') and (s[1]='"') then begin + Result^.ID:=Result^.ID+#10+copy(s,2,length(s)-2); + inc(Line); + end else + break; + end; + // read Str + if Line<SrcFile.Count then begin + s:=SrcFile[Line]; + if LeftStr(s,8)='msgstr "' then begin + Result^.Str:=copy(s,9,length(s)-9); + inc(Line); + while Line<SrcFile.Count do begin + s:=SrcFile[Line]; + if (s<>'') and (s[1]='"') then begin + Result^.Str:=Result^.Str+#10+copy(s,2,length(s)-2); + inc(Line); + end else + break; + end; + end; + end; + exit; + end; + inc(Line); + end; +end; + +procedure WriteMessageItem(MsgItem: PMsgItem; DestFile: TStringList); + + procedure WriteItem(const Prefix: string; Str: string); + var + s: String; + p: Integer; + begin + s:=Prefix+' "'; + p:=1; + while (p<=length(Str)) do begin + if Str[p]=#10 then begin + // a new line + s:=s+copy(Str,1,p-1)+'"'; + DestFile.Add(s); + Str:=copy(Str,p+1,length(Str)); + p:=1; + // start new line + s:='"'; + end else + inc(p); + end; + if (Str<>'') or (s<>'"') then begin + s:=s+Str+'"'; + DestFile.Add(s); + end; + end; + +begin + if MsgItem^.Comment<>'' then + DestFile.Add('#'+MsgItem^.Comment); + WriteItem('msgid',MsgItem^.ID); + WriteItem('msgstr',MsgItem^.Str); + DestFile.Add(''); +end; + +function ReadPoFile(const Filename: string): TPoFile; +var + SrcFile: TStringList; + MsgItem: PMsgItem; + Line: Integer; +begin + Result:=TPoFile.Create; + + // read source .po file + //writeln(Prefix,'Loading ',Filename,' ...'); + SrcFile:=TStringList.Create; + SrcFile.LoadFromFile(Filename); + + if (SrcFile.Count>0) and (copy(SrcFile[0],1,3)=UTF8FileHeader) then begin + Result.UTF8Header:=copy(SrcFile[0],1,3); + SrcFile[0]:=copy(SrcFile[0],4,length(SrcFile[0])); + end; + + Line:=0; + while Line<SrcFile.Count do begin + if (SrcFile[Line]='') then begin + // empty line + inc(Line); + end + else begin + // message + MsgItem:=ReadMessageItem(SrcFile,Line); + // ignore doubles + if (Result.Tree.FindKey(MsgItem,@CompareMsgItems)<>nil) then begin + Dispose(MsgItem); + continue; + end; + // add message + Result.Tree.Add(MsgItem); + end; + end; + + SrcFile.Free; +end; + +procedure WritePoFile(PoFile: TPoFile; const Filename: string); +var + DestFile: TStringList; + Node: TAVLTreeNode; + MsgItem: PMsgItem; + Save: Boolean; + OldDestFile: TStringList; +begin + //writeln(Prefix,'Saving ',Filename,' ...'); + DestFile:=TStringList.Create; + if (PoFile.Header.Count>0) then begin + DestFile.Add('msgid ""'); + DestFile.Add('msgstr ""'); + DestFile.AddStrings(PoFile.Header); + DestFile.Add(''); + end; + Node:=PoFile.Tree.FindLowest; + while Node<>nil do begin + MsgItem:=PMsgItem(Node.Data); + WriteMessageItem(MsgItem,DestFile); + Node:=PoFile.Tree.FindSuccessor(Node); + end; + if (PoFile.UTF8Header<>'') and (DestFile.Count>0) then + DestFile[0]:=PoFile.UTF8Header+DestFile[0]; + Save:=true; + if FileExists(Filename) then begin + OldDestFile:=TStringList.Create; + OldDestFile.LoadFromFile(Filename); + if OldDestFile.Text=DestFile.Text then Save:=false; + OldDestFile.Free; + end; + if Save then + DestFile.SaveToFile(Filename); + DestFile.Free; +end; + +function FindAllTranslatedPoFiles(const Filename: string): TStringList; +var + Path: String; + Name: String; + NameOnly: String; + Ext: String; + FileInfo: TSearchRec; + CurExt: String; +begin + Result:=TStringList.Create; + Path:=ExtractFilePath(Filename); + Name:=ExtractFilename(Filename); + Ext:=ExtractFileExt(Filename); + NameOnly:=LeftStr(Name,length(Name)-length(Ext)); + if SysUtils.FindFirst(Path+GetAllFilesMask,faAnyFile,FileInfo)=0 then begin + repeat + if (FileInfo.Name='.') or (FileInfo.Name='..') or (FileInfo.Name='') + or (CompareFilenames(FileInfo.Name,Name)=0) then continue; + CurExt:=ExtractFileExt(FileInfo.Name); + if (CompareFilenames(CurExt,'.po')<>0) + or (CompareFilenames(LeftStr(FileInfo.Name,length(NameOnly)),NameOnly)<>0) + then + continue; + Result.Add(Path+FileInfo.Name); + until SysUtils.FindNext(FileInfo)<>0; + end; + SysUtils.FindClose(FileInfo); +end; + +procedure MergePoTrees(SrcTree, DestTree: TAVLTree); +var + SrcNode, DestNode: TAVLTreeNode; + SrcMsgItem, DestMsgItem: PMsgItem; + OldNode: TAVLTreeNode; +begin + // add all message items from SrcTree into DestTree + SrcNode:=SrcTree.FindLowest; + while SrcNode<>nil do begin + SrcMsgItem:=PMsgItem(SrcNode.Data); + DestNode:=DestTree.FindKey(SrcMsgItem,@CompareMsgItems); + if DestNode<>nil then begin + // ID already exists -> update comment + DestMsgItem:=PMsgItem(DestNode.Data); + DestMsgItem^.Comment:=SrcMsgItem^.Comment; + end else begin + // new ID -> add new message item to DestTree + New(DestMsgItem); + DestMsgItem^.Comment:=SrcMsgItem^.Comment; + DestMsgItem^.ID:=SrcMsgItem^.ID; + DestMsgItem^.Str:=SrcMsgItem^.Str; + DestTree.Add(DestMsgItem); + end; + SrcNode:=SrcTree.FindSuccessor(SrcNode); + end; + // remove all old messages in DestTree + DestNode:=DestTree.FindLowest; + while DestNode<>nil do begin + DestMsgItem:=PMsgItem(DestNode.Data); + OldNode:=DestNode; + DestNode:=DestTree.FindSuccessor(DestNode); + if (DestMsgItem^.ID<>'') + and (SrcTree.FindKey(DestMsgItem,@CompareMsgItems)=nil) then begin + // unused message -> delete it + writeln('Deleting unused message "',DestMsgItem^.ID,'"'); + Dispose(DestMsgItem); + DestTree.Delete(OldNode); + end; + end; +end; + +procedure UpdatePoFile(const Filename: string); +var + SrcFile, DestFile: TPoFile; + DestFiles: TStringList; + i: Integer; +begin + writeln('Loading ',Filename,' ...'); + SrcFile:=ReadPoFile(Filename); + DestFiles:=FindAllTranslatedPoFiles(Filename); + IncPrefix; + for i:=0 to DestFiles.Count-1 do begin + writeln(Prefix,'Updating ',DestFiles[i]); + IncPrefix; + DestFile:=ReadPoFile(DestFiles[i]); + MergePoTrees(SrcFile.Tree,DestFile.Tree); + WritePoFile(DestFile,DestFiles[i]); + DestFile.Free; + DecPrefix; + end; + DecPrefix; + DestFiles.Free; + SrcFile.Free; +end; + +procedure UpdateAllPoFiles; +var + i: Integer; +begin + for i:=0 to Files.Count-1 do begin + UpdatePoFile(Files[i]); + end; +end; + +begin + Prefix:=''; + Files:=nil; + if not ParamsValid then begin + writeln('Usage: ',ExtractFileName(ParamStr(0)) + ,' filename1.po [filename2.po ... filenameN.po]'); + exit; + end else begin + UpdateAllPoFiles; + end; + Files.Free; +end. + |