diff options
Diffstat (limited to 'msghack.py')
| -rwxr-xr-x | msghack.py | 417 | 
1 files changed, 417 insertions, 0 deletions
| diff --git a/msghack.py b/msghack.py new file mode 100755 index 0000000..358552c --- /dev/null +++ b/msghack.py @@ -0,0 +1,417 @@ +#!/usr/bin/python3 +## -*- coding: utf-8 -*- +## Copyright (C) 2001, 2004, 2008, 2012 Red Hat, Inc. +## Copyright (C) 2001 Trond Eivind Glomsrød <teg@redhat.com> + +## This program 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 3 of the License, or +## (at your option) any later version. + +## This program 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. + +## You should have received a copy of the GNU General Public License +## along with this program.  If not, see <http://www.gnu.org/licenses/>. + +""" +A msghack replacement +""" + +import sys + +class GTMessage: +    """ +    A class containing a message, its msgid and various references pointing at it +    """ + +    def __init__(self,id=None,message=None,refs=[]): +        """ +        The constructor for the GTMessage class +        @self The object instance +        @message The message +        @id The messageid associated with the object +        """ +        self._message=message.strip() +        self._id=id.strip() +        self._refs=[] +        for ref in refs: +            self._refs.append(ref) + +    def __str__(self): +        """ +        Return a string representation of the object +        @self The object instance +        """ +        res="" +        for ref in self._refs: +            res=res+ref+"\n" +        res=res+"msgid %s\nmsgstr %s\n" % (self._id,self._message) +        return res + +    def invertedStrings(self): +        """ +        Returns a string representation, but with msgid and msgstr inverted. +        Note: Don't invert the "" string +        @self The object instance +        """ +        res="" +        for ref in self._refs: +            res=res+ref+"\n" +        if not self._id=="\"\"": +            res=res+"msgid %s\nmsgstr %s\n" % (self._message,self._id) +        else: +            res=res+"msgid %s\nmsgstr %s\n" % (self._id,self._message) +        return res + +    def emptyMsgStrings(self): +        """ +        Return a string representation of the object, but leave the msgstr +        empty - create a pot file from a po file +        Note: Won't remove the "" string +        @self The object instance +        """ +        res="" +        for ref in self._refs: +            res=res+ref+"\n" +        if not self._id=="\"\"": +            res=res+"msgid %s\nmsgstr \"\"\n" % (self._id) +        else: +            res=res+"msgid %s\nmsgstr %s\n" % (self._id,self._message) +        return res +         +    def compareMessage(self,msg): +        """ +        Return  if the messages have identical msgids, 0 otherwise +        @self The object instance +        @msg The message to compare to +        """ + +        if self._id == msg._id: +            return 1 +        return 0 +         + +class GTMasterMessage: +    """ +    A class containing a message, its msgid and various references pointing at it +    The difference between GTMessage and GTMasterMessage is that this class +    can do less operations, but is able to store multiple msgstrs with identifiers +    (usually language, like 'msgst(no)' +    """ + +    def __init__(self,id=None,refs=[]): +        """ +        The constructor for the GTMessage class +        @self The object instance +        @id The messageid associated with the object +        """ +        self._id=id +        self._refs=[] +        self._messages=[] +        for ref in refs: +            self._refs.append(ref) + +    def addMessage(self,message,identifier): +        """ +        Add a new message and identifier to the GTMasterMessage object +        @self The object instance +        @message The message to append +        @identifier The identifier of the message +        """ +        self._messages.append((identifier,message)) + +    def __str__(self): +        """ +        Return a string representation of the object +        @self The object instance +        """ +        res="" +        for ref in self._refs: +            res=res+ref+"\n" +        res=res+"msgid %s\n" % self._id +        for message in self._messages: +            res=res+"msgstr(%s) %s\n" %(message[0],message[1]) +        res=res+"\n" +        return res + +class GTFile: +    """ +    A class containing the GTMessages contained in a file +    """ + +    def __init__(self,filename): +        """ +        The constructor of the GTMFile class +        @self The object instance +        @filename The  file to initialize from +        """ +        self._filename=filename +        self._messages=[] +        self.readFile(filename) + +    def __str__(self): +        """ +        Return a string representation of the object +        @self The object instance +        """ +        res="" +        for message in self._messages: +            res=res+str(message)+"\n" +        return res + +    def invertedStrings(self): +        """ +        Return a string representation of the object, with msgid and msgstr +        swapped. Will remove duplicates... +        @self The object instance +        """ + +        msght={} +        msgar=[] + +        for message in self._messages: +            if message._id=='""' and len(msgar)==0: +                msgar.append(GTMessage(message._id,message._message,message._refs)) +                continue +            msg=GTMessage(message._message,message._id,message._refs) +            if msg._id not in msght: +                msght[msg._id]=msg +                msgar.append(msg) +            else: +                msg2=msght[msg._id] +                for ref in msg._refs: +                    msg2._refs.append(ref) +        res="" +        for message in msgar: +            res=res+str(message)+"\n" +        return res + +    def msgidDupes(self): +        """ +        Search for duplicates in the msgids. +        @self The object instance +        """ +        msgids={} +        res="" +        for message in self._messages: +            msgid=message._id +            if msgid in msgids: +                res=res+"Duplicate: %s\n" % (msgid) +            else: +                msgids[msgid]=1 +        return res + +    def getMsgstr(self,msgid): +        """ +        Return the msgstr matching the given id. 'None' if missing +        @self The object instance +        @msgid The msgid key +        """ + +        for message in self._messages: +            if msgid == message._id: +                return message._message +        return None + +    def emptyMsgStrings(self): +        """ +        Return a string representation of the object, but leave the msgstr +        empty - create a pot file from a po file +        @self The object instance +        """ +         +        res="" +        for message in self._messages: +            res=res+message.emptyMsgStrings()+"\n" +        return res + +             +    def append(self,B): +        """ +        Append entries from dictionary B which aren't +        already present in this dictionary +        @self The object instance +        @B the dictionary to append messages from +        """ + +        for message in B._messages: +            if not self.getMsgstr(message._id): +                self._messages.append(message) +                 + +    def readFile(self,filename): +        """ +        Read the contents of a file into the GTFile object +        @self The object instance +        @filename The name of the file to read +        """ +         +        file=open(filename,"r") +        msgid="" +        msgstr="" +        refs=[] +        lines=[] +        inmsgid=0 +        inmsgstr=0 +        templines=file.readlines() +        for line in templines: +            lines.append(line.strip()) +        for line in lines: +            pos=line.find('"') +            pos2=line.rfind('"') +            if line and line[0]=="#": +                refs.append(line.strip()) +            if inmsgstr==0 and line[:6]=="msgstr": +                msgstr="" +                inmsgstr=1 +                inmsgid=0 +            if inmsgstr==1: +                if pos==-1: +                    inmsgstr=0 +                    #Handle entries with and without "" consistently +                    if msgid[:2]=='""' and len(msgid)>4:  +                        msgid=msgid[2:] +                    if msgstr[:2]=='""' and len(msgstr)>4:  +                        msgstr=msgstr[2:] +                    message=GTMessage(msgid,msgstr,refs) +                    self._messages.append(message) +                    msgstr="" +                    msgid="" +                    refs=[] +                else: +                    msgstr=msgstr+line[pos:pos2+1]+"\n" +            if inmsgid==0 and line[:5]=="msgid": +                msgid="" +                inmsgid=1 +            if inmsgid==1: +                if pos==-1: +                    inmsgid=0 +                else: +                    msgid=msgid+line[pos:pos2+1]+"\n" +        if msgstr and msgid: +            message=GTMessage(msgid,msgstr,refs) +            self._messages.append(message) + + +class GTMaster: +    """ +    A class containing a master catalogue of gettext dictionaries +    """ + +    def __init__(self,dicts): +        """ +        The constructor for the GTMaster class +        @self The object instance +        @dicts An array of dictionaries to merge +        """ +        self._messages=[] +        self.createMaster(dicts) + +    def createMaster(self,dicts): +        """ +        Create the master catalogue +        @self The object instance +        @dicts An array of dictionaries to merge +        """ + +        self._master=dicts[0] +        self._dicts=dicts[1:] + +        for message in self._master._messages: +            gtm=GTMasterMessage(message._id,message._refs) +            gtm.addMessage(message._message,self._master._filename[:-3]) +            for dict in self._dicts: +                res=dict.getMsgstr(message._id) +                if(res): +                    gtm.addMessage(res,dict._filename[:-3]) +            self._messages.append(gtm) + +    def __str__(self): +        """ +        Return a string representation of the object +        @self The object instance +        """ +        res="" +        for message in self._messages: +            res=res+str(message)+"\n" +        return res + +def printUsage(): +    "Print the usage messages" +    print("Usage: " + str(sys.argv[0]) + " [OPTION] file.po [ref.po]\n\ +This program can be used to alter .po files in ways no sane mind would think about.\n\ +    -o                result will be written to FILE\n\ +    --invert          invert a po file by switching msgid and msgstr\n\ +    --master          join any number of files in a master-formatted catalog\n\ +    --empty           empty the contents of the .po file, creating a .pot\n\ +    --append          append entries from ref.po that don't exist in file.po\n\ +\n\ +Note: It is just a replacement of msghack for backward support.\n") + + +if __name__=="__main__": +    output=None +    res=None +    if("-o") in sys.argv: +        if (len(sys.argv)<=sys.argv.index("-o")+1): +                print("file.po and ref.po are not specified!\n") +                printUsage() +                exit(1) +        output=sys.argv[sys.argv.index("-o")+1] +        sys.argv.remove("-o") +        sys.argv.remove(output) +    if("--invert") in sys.argv: +        if (len(sys.argv)<=sys.argv.index("--invert")+1): +            print("file.po is not specified!\n") +            printUsage() +            exit(1) +        file=sys.argv[sys.argv.index("--invert")+1] +        gtf=GTFile(file) +        res1=gtf.msgidDupes() +        if res1: +            sys.stderr.write(res1) +            sys.exit(1) +        res=str(gtf.invertedStrings()) +    elif("--empty") in sys.argv: +        if (len(sys.argv)<=sys.argv.index("--empty")+1): +            print("file.po is not specified!\n") +            printUsage() +            exit(1) +        file=sys.argv[sys.argv.index("--empty")+1] +        gtf=GTFile(file) +        res=str(gtf.emptyMsgStrings()) +    elif("--master") in sys.argv: +        if (len(sys.argv)<=sys.argv.index("--master")+1): +            print("file.po is not specified!\n") +            printUsage() +            exit(1) +        loc=sys.argv.index("--master")+1 +        gtfs=[] +        for file in sys.argv[loc:]: +            gtfs.append(GTFile(file)) +        master=GTMaster(gtfs) +        res=str(master) +    elif("--append") in sys.argv: +        if (len(sys.argv)<=sys.argv.index("--append")+2): +            print("file.po and/or ref.po are not specified!\n") +            printUsage() +            exit(1) +        file=sys.argv[sys.argv.index("--append")+1] +        file2=sys.argv[sys.argv.index("--append")+2] +        gtf=GTFile(file) +        gtf2=GTFile(file2) +        gtf.append(gtf2) +        res=str(gtf) +    else: +        #print("Not implemented: "+str(sys.argv)) +        printUsage() +        sys.exit(1) +    if not output: +        print(res) +    else: +        file=open(output,"w") +        file.write(res) +    sys.exit(0) | 
