From c453f846c40e485d9bfd1b7cf1f5b623ce556a92 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Tue, 29 May 2012 18:48:29 +0200 Subject: gettext: import from rawhide --- msghack.py | 421 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 421 insertions(+) create mode 100755 msghack.py (limited to 'msghack.py') diff --git a/msghack.py b/msghack.py new file mode 100755 index 0000000..8d700e9 --- /dev/null +++ b/msghack.py @@ -0,0 +1,421 @@ +#!/usr/bin/python +## -*- coding: utf-8 -*- +## Copyright (C) 2001, 2008 Red Hat, Inc. +## Copyright (C) 2001 Trond Eivind Glomsrød + +## v0.2 - 2001-08-21 + +## 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 2 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, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +""" +A msghack replacement +""" + +import string +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=string.strip(message) + self._id=string.strip(id) + 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 not msght.has_key(msg._id): + 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 msgids.has_key(msgid): + 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(string.strip(line)) + for line in lines: + pos=string.find(line,'"') + pos2=string.rfind(line,'"') + if line and line[0]=="#": + refs.append(string.strip(line)) + 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) -- cgit