Bug 6268: Fix check_po for python3
svn: r20933
This commit is contained in:
parent
c8708ae3bc
commit
edc74447d1
872
po/check_po
872
po/check_po
@ -41,558 +41,558 @@ all_coverage = {}
|
||||
all_template_coverage = {}
|
||||
|
||||
def strip_quotes(st):
|
||||
if len(st) >= 2 and st[0] == '"' and st[len(st)-1] == '"':
|
||||
st = st.strip()[1:-1]
|
||||
return st
|
||||
if len(st) >= 2 and st[0] == '"' and st[len(st)-1] == '"':
|
||||
st = st.strip()[1:-1]
|
||||
return st
|
||||
|
||||
class CheckException( Exception ):
|
||||
pass
|
||||
pass
|
||||
|
||||
# This is a base class for all checks
|
||||
class Check:
|
||||
def __init__( self ):
|
||||
self.msgs = []
|
||||
def diag( self ):
|
||||
if len( self.msgs ):
|
||||
print
|
||||
print self.diag_header
|
||||
for m in self.msgs:
|
||||
m.diag()
|
||||
def summary( self ):
|
||||
print "%-20s%d" % ( self.summary_text, len(self.msgs) )
|
||||
def __init__( self ):
|
||||
self.msgs = []
|
||||
def diag( self ):
|
||||
if len( self.msgs ):
|
||||
print
|
||||
print(self.diag_header)
|
||||
for m in self.msgs:
|
||||
m.diag()
|
||||
def summary( self ):
|
||||
print("%-20s%d" % ( self.summary_text, len(self.msgs) ))
|
||||
|
||||
class Check_fmt( Check ):
|
||||
def __init__( self, fmt ):
|
||||
Check.__init__( self )
|
||||
self.diag_header = "-------- %s mismatches --------------" % fmt
|
||||
self.summary_text = "%s mismatches:" % fmt
|
||||
self.fmt = fmt
|
||||
def __init__( self, fmt ):
|
||||
Check.__init__( self )
|
||||
self.diag_header = "-------- %s mismatches --------------" % fmt
|
||||
self.summary_text = "%s mismatches:" % fmt
|
||||
self.fmt = fmt
|
||||
|
||||
def __process( self, msg, msgid, msgstr ):
|
||||
cnt1 = msgid.count( self.fmt )
|
||||
cnt2 = msgstr.count( self.fmt )
|
||||
if cnt1 != cnt2:
|
||||
self.msgs.append( msg )
|
||||
def __process( self, msg, msgid, msgstr ):
|
||||
cnt1 = msgid.count( self.fmt )
|
||||
cnt2 = msgstr.count( self.fmt )
|
||||
if cnt1 != cnt2:
|
||||
self.msgs.append( msg )
|
||||
|
||||
def process( self, msg ):
|
||||
msgid = msg.msgid
|
||||
msgstr = msg.msgstr[0]
|
||||
self.__process( msg, msgid, msgstr )
|
||||
def process( self, msg ):
|
||||
msgid = msg.msgid
|
||||
msgstr = msg.msgstr[0]
|
||||
self.__process( msg, msgid, msgstr )
|
||||
|
||||
if msg.msgidp and len(msg.msgstr) >= 2:
|
||||
msgid = msg.msgidp
|
||||
msgstr = msg.msgstr[1]
|
||||
self.__process( msg, msgid, msgstr )
|
||||
if msg.msgidp and len(msg.msgstr) >= 2:
|
||||
msgid = msg.msgidp
|
||||
msgstr = msg.msgstr[1]
|
||||
self.__process( msg, msgid, msgstr )
|
||||
|
||||
class Check_named_fmt( Check ):
|
||||
# A pattern to find all %()
|
||||
find_named_fmt_pat = re.compile('% \( \w+ \) \d* \D', re.VERBOSE)
|
||||
# A pattern to find all %()
|
||||
find_named_fmt_pat = re.compile('% \( \w+ \) \d* \D', re.VERBOSE)
|
||||
|
||||
def __init__( self ):
|
||||
Check.__init__( self )
|
||||
self.diag_header = "-------- %() name mismatches --------------"
|
||||
self.summary_text = "%() name mismatches:"
|
||||
def __init__( self ):
|
||||
Check.__init__( self )
|
||||
self.diag_header = "-------- %() name mismatches --------------"
|
||||
self.summary_text = "%() name mismatches:"
|
||||
|
||||
def __process( self, msg, msgid, msgstr ):
|
||||
# Same number of named formats?
|
||||
fmts1 = self.find_named_fmt_pat.findall( msgid )
|
||||
fmts2 = self.find_named_fmt_pat.findall( msgstr )
|
||||
if len( fmts1 ) != len( fmts2 ):
|
||||
self.msgs.append( msg )
|
||||
else:
|
||||
# Do we have the same named formats?
|
||||
fmts1.sort()
|
||||
fmts2.sort()
|
||||
if fmts1 != fmts2:
|
||||
self.msgs.append( msg )
|
||||
def __process( self, msg, msgid, msgstr ):
|
||||
# Same number of named formats?
|
||||
fmts1 = self.find_named_fmt_pat.findall( msgid )
|
||||
fmts2 = self.find_named_fmt_pat.findall( msgstr )
|
||||
if len( fmts1 ) != len( fmts2 ):
|
||||
self.msgs.append( msg )
|
||||
else:
|
||||
# Do we have the same named formats?
|
||||
fmts1.sort()
|
||||
fmts2.sort()
|
||||
if fmts1 != fmts2:
|
||||
self.msgs.append( msg )
|
||||
|
||||
def process( self, msg ):
|
||||
msgid = msg.msgid
|
||||
msgstr = msg.msgstr[0]
|
||||
self.__process( msg, msgid, msgstr )
|
||||
def process( self, msg ):
|
||||
msgid = msg.msgid
|
||||
msgstr = msg.msgstr[0]
|
||||
self.__process( msg, msgid, msgstr )
|
||||
|
||||
if msg.msgidp and len(msg.msgstr) >= 2:
|
||||
msgid = msg.msgidp
|
||||
msgstr = msg.msgstr[1]
|
||||
self.__process( msg, msgid, msgstr )
|
||||
if msg.msgidp and len(msg.msgstr) >= 2:
|
||||
msgid = msg.msgidp
|
||||
msgstr = msg.msgstr[1]
|
||||
self.__process( msg, msgid, msgstr )
|
||||
|
||||
class Check_missing_sd( Check ):
|
||||
# A pattern to find %() without s or d
|
||||
# Here is a command to use for testing
|
||||
# print re.compile('% \( \w+ \) \d* (\D|$)', re.VERBOSE).findall( '%(event_name)s: %(place)s%(endnotes)s. ' )
|
||||
find_named_fmt_pat2 = re.compile('% \( \w+ \) \d* (\D|$)', re.VERBOSE)
|
||||
# A pattern to find %() without s or d
|
||||
# Here is a command to use for testing
|
||||
# print(re.compile('% \( \w+ \) \d* (\D|$)', re.VERBOSE).findall( '%(event_name)s: %(place)s%(endnotes)s. ' ))
|
||||
find_named_fmt_pat2 = re.compile('% \( \w+ \) \d* (\D|$)', re.VERBOSE)
|
||||
|
||||
def __init__( self ):
|
||||
Check.__init__( self )
|
||||
self.diag_header = "-------- %() without 's' or 'd' mismatches --------------"
|
||||
self.summary_text = "%() missing s/d:"
|
||||
def process( self, msg ):
|
||||
for msgstr in msg.msgstr:
|
||||
fmts = self.find_named_fmt_pat2.findall( msgstr )
|
||||
for f in fmts:
|
||||
if not f in ('s', 'd'):
|
||||
self.msgs.append( msg )
|
||||
break
|
||||
def __init__( self ):
|
||||
Check.__init__( self )
|
||||
self.diag_header = "-------- %() without 's' or 'd' mismatches --------------"
|
||||
self.summary_text = "%() missing s/d:"
|
||||
def process( self, msg ):
|
||||
for msgstr in msg.msgstr:
|
||||
fmts = self.find_named_fmt_pat2.findall( msgstr )
|
||||
for f in fmts:
|
||||
if not f in ('s', 'd'):
|
||||
self.msgs.append( msg )
|
||||
break
|
||||
|
||||
class Check_runaway( Check ):
|
||||
def __init__( self ):
|
||||
Check.__init__( self )
|
||||
self.diag_header = "-------- Runaway context in translation ---------"
|
||||
self.summary_text = "Runaway context:"
|
||||
def __init__( self ):
|
||||
Check.__init__( self )
|
||||
self.diag_header = "-------- Runaway context in translation ---------"
|
||||
self.summary_text = "Runaway context:"
|
||||
|
||||
def __process( self, msg, msgid, msgstr ):
|
||||
# Runaway context. In the translated part we only to see
|
||||
# the translation of the word after the |
|
||||
if msgid.count('|') > 0 and msgstr.count('|') > 0 and msgid != msgstr:
|
||||
self.msgs.append( msg )
|
||||
def __process( self, msg, msgid, msgstr ):
|
||||
# Runaway context. In the translated part we only to see
|
||||
# the translation of the word after the |
|
||||
if msgid.count('|') > 0 and msgstr.count('|') > 0 and msgid != msgstr:
|
||||
self.msgs.append( msg )
|
||||
|
||||
def process( self, msg ):
|
||||
msgid = msg.msgid
|
||||
msgstr = msg.msgstr[0]
|
||||
self.__process( msg, msgid, msgstr )
|
||||
def process( self, msg ):
|
||||
msgid = msg.msgid
|
||||
msgstr = msg.msgstr[0]
|
||||
self.__process( msg, msgid, msgstr )
|
||||
|
||||
if msg.msgidp and len(msg.msgstr) >= 2:
|
||||
msgid = msg.msgidp
|
||||
msgstr = msg.msgstr[1]
|
||||
self.__process( msg, msgid, msgstr )
|
||||
if msg.msgidp and len(msg.msgstr) >= 2:
|
||||
msgid = msg.msgidp
|
||||
msgstr = msg.msgstr[1]
|
||||
self.__process( msg, msgid, msgstr )
|
||||
|
||||
class Check_xml_chars( Check ):
|
||||
# Special XML characters
|
||||
# It is not allowed to have a quote, an ampersand or an angle bracket
|
||||
xml_chars_pat = re.compile( r'<(?!(b>|/b>|i>|/i>|br/>)) | (?<=!(<b|/b|<i|/i|r/))> | " | & (?!(quot|nbsp|gt|amp);)', re.VERBOSE )
|
||||
# Special XML characters
|
||||
# It is not allowed to have a quote, an ampersand or an angle bracket
|
||||
xml_chars_pat = re.compile( r'<(?!(b>|/b>|i>|/i>|br/>)) | (?<=!(<b|/b|<i|/i|r/))> | " | & (?!(quot|nbsp|gt|amp);)', re.VERBOSE )
|
||||
|
||||
def __init__( self ):
|
||||
Check.__init__( self )
|
||||
self.diag_header = "-------- unescaped XML special characters ---------"
|
||||
self.summary_text = "XML special chars:"
|
||||
def __init__( self ):
|
||||
Check.__init__( self )
|
||||
self.diag_header = "-------- unescaped XML special characters ---------"
|
||||
self.summary_text = "XML special chars:"
|
||||
|
||||
def process( self, msg ):
|
||||
msgid = msg.msgid
|
||||
msgstr = msg.msgstr[0]
|
||||
def process( self, msg ):
|
||||
msgid = msg.msgid
|
||||
msgstr = msg.msgstr[0]
|
||||
|
||||
# XML errors
|
||||
# Only look at messages in the tips.xml
|
||||
if msg.is_tips_xml:
|
||||
if self.xml_chars_pat.search( msgstr ):
|
||||
self.msgs.append( msg )
|
||||
# XML errors
|
||||
# Only look at messages in the tips.xml
|
||||
if msg.is_tips_xml:
|
||||
if self.xml_chars_pat.search( msgstr ):
|
||||
self.msgs.append( msg )
|
||||
|
||||
class Check_last_char( Check ):
|
||||
def __init__( self ):
|
||||
Check.__init__( self )
|
||||
self.diag_header = "-------- last character not identical ---------"
|
||||
self.summary_text = "Last character:"
|
||||
def __init__( self ):
|
||||
Check.__init__( self )
|
||||
self.diag_header = "-------- last character not identical ---------"
|
||||
self.summary_text = "Last character:"
|
||||
|
||||
def __process( self, msg, msgid, msgstr ):
|
||||
msgid_last = msgid[-1:]
|
||||
msgstr_last = msgstr[-1:]
|
||||
if msgid_last.isspace() != msgstr_last.isspace():
|
||||
self.msgs.append( msg )
|
||||
elif (msgid_last == '.') != (msgstr_last == '.'):
|
||||
self.msgs.append( msg )
|
||||
def __process( self, msg, msgid, msgstr ):
|
||||
msgid_last = msgid[-1:]
|
||||
msgstr_last = msgstr[-1:]
|
||||
if msgid_last.isspace() != msgstr_last.isspace():
|
||||
self.msgs.append( msg )
|
||||
elif (msgid_last == '.') != (msgstr_last == '.'):
|
||||
self.msgs.append( msg )
|
||||
|
||||
def process( self, msg ):
|
||||
# Last character of msgid? White space? Period?
|
||||
if msg.is_fuzzy:
|
||||
return
|
||||
msgid = msg.msgid
|
||||
msgstr = msg.msgstr[0]
|
||||
self.__process( msg, msgid, msgstr )
|
||||
def process( self, msg ):
|
||||
# Last character of msgid? White space? Period?
|
||||
if msg.is_fuzzy:
|
||||
return
|
||||
msgid = msg.msgid
|
||||
msgstr = msg.msgstr[0]
|
||||
self.__process( msg, msgid, msgstr )
|
||||
|
||||
if msg.msgidp and len(msg.msgstr) >= 2:
|
||||
msgid = msg.msgidp
|
||||
msgstr = msg.msgstr[1]
|
||||
self.__process( msg, msgid, msgstr )
|
||||
if msg.msgidp and len(msg.msgstr) >= 2:
|
||||
msgid = msg.msgidp
|
||||
msgstr = msg.msgstr[1]
|
||||
self.__process( msg, msgid, msgstr )
|
||||
|
||||
class Check_shortcut_trans( Check ):
|
||||
def __init__( self ):
|
||||
Check.__init__( self )
|
||||
self.diag_header = "-------- shortcut key in translation ---------"
|
||||
self.summary_text = "Shortcut in msgstr:"
|
||||
def __init__( self ):
|
||||
Check.__init__( self )
|
||||
self.diag_header = "-------- shortcut key in translation ---------"
|
||||
self.summary_text = "Shortcut in msgstr:"
|
||||
|
||||
def __process( self, msg, msgid, msgstr ):
|
||||
if msgid.count('_') == 0 and msgstr.count('_') > 0:
|
||||
self.msgs.append( msg )
|
||||
def __process( self, msg, msgid, msgstr ):
|
||||
if msgid.count('_') == 0 and msgstr.count('_') > 0:
|
||||
self.msgs.append( msg )
|
||||
|
||||
def process( self, msg ):
|
||||
msgid = msg.msgid
|
||||
msgstr = msg.msgstr[0]
|
||||
self.__process( msg, msgid, msgstr )
|
||||
def process( self, msg ):
|
||||
msgid = msg.msgid
|
||||
msgstr = msg.msgstr[0]
|
||||
self.__process( msg, msgid, msgstr )
|
||||
|
||||
if msg.msgidp and len(msg.msgstr) >= 2:
|
||||
msgid = msg.msgidp
|
||||
msgstr = msg.msgstr[1]
|
||||
self.__process( msg, msgid, msgstr )
|
||||
if msg.msgidp and len(msg.msgstr) >= 2:
|
||||
msgid = msg.msgidp
|
||||
msgstr = msg.msgstr[1]
|
||||
self.__process( msg, msgid, msgstr )
|
||||
|
||||
class Msgid:
|
||||
fuzzy_pat = re.compile( 'fuzzy' )
|
||||
tips_xml_pat = re.compile( r'tips\.xml' )
|
||||
def __init__( self, msgnr, lineno ):
|
||||
self._msgid = [] # For debugging purpose the original text
|
||||
self._msgidp = [] # For debugging purpose the original text
|
||||
self._msgstr = [] # For debugging purpose the original text
|
||||
self.msgid = ''
|
||||
self.msgidp = ''
|
||||
self.msgstr = [] # This is a list to support plural
|
||||
self._cmnt = []
|
||||
self.nr = msgnr
|
||||
self.lineno = lineno
|
||||
self.is_fuzzy = 0
|
||||
self.is_tips_xml = 0
|
||||
fuzzy_pat = re.compile( 'fuzzy' )
|
||||
tips_xml_pat = re.compile( r'tips\.xml' )
|
||||
def __init__( self, msgnr, lineno ):
|
||||
self._msgid = [] # For debugging purpose the original text
|
||||
self._msgidp = [] # For debugging purpose the original text
|
||||
self._msgstr = [] # For debugging purpose the original text
|
||||
self.msgid = ''
|
||||
self.msgidp = ''
|
||||
self.msgstr = [] # This is a list to support plural
|
||||
self._cmnt = []
|
||||
self.nr = msgnr
|
||||
self.lineno = lineno
|
||||
self.is_fuzzy = 0
|
||||
self.is_tips_xml = 0
|
||||
|
||||
def diag( self ):
|
||||
print
|
||||
print "msg nr: %d, lineno: %d%s" % ( self.nr, self.lineno, self.is_fuzzy and " (fuzzy)" or "" )
|
||||
sys.stdout.write( ''.join( self._msgid ) )
|
||||
sys.stdout.write( ''.join( self._msgidp ) )
|
||||
sys.stdout.write( ''.join( self._msgstr ) )
|
||||
def diag( self ):
|
||||
print
|
||||
print("msg nr: %d, lineno: %d%s" % ( self.nr, self.lineno, self.is_fuzzy and " (fuzzy)" or "" ))
|
||||
sys.stdout.write( ''.join( self._msgid ) )
|
||||
sys.stdout.write( ''.join( self._msgidp ) )
|
||||
sys.stdout.write( ''.join( self._msgstr ) )
|
||||
|
||||
def add_msgid( self, line, lineno ):
|
||||
self._msgid.append( line )
|
||||
line = re.sub( r'msgid\s+', '', line )
|
||||
line = line.strip()
|
||||
if line[0] != '"' or line[-1:] != '"':
|
||||
print "ERROR at line %d: Missing quote." % lineno
|
||||
line = strip_quotes( line )
|
||||
self.msgid += line
|
||||
def add_msgid( self, line, lineno ):
|
||||
self._msgid.append( line )
|
||||
line = re.sub( r'msgid\s+', '', line )
|
||||
line = line.strip()
|
||||
if line[0] != '"' or line[-1:] != '"':
|
||||
print("ERROR at line %d: Missing quote." % lineno)
|
||||
line = strip_quotes( line )
|
||||
self.msgid += line
|
||||
|
||||
def add_msgidp( self, line, lineno ):
|
||||
self._msgidp.append( line )
|
||||
line = re.sub( r'msgid_plural\s+', '', line )
|
||||
line = line.strip()
|
||||
if line[0] != '"' or line[-1:] != '"':
|
||||
print "ERROR at line %d: Missing quote." % lineno
|
||||
line = strip_quotes( line )
|
||||
self.msgidp += line
|
||||
def add_msgidp( self, line, lineno ):
|
||||
self._msgidp.append( line )
|
||||
line = re.sub( r'msgid_plural\s+', '', line )
|
||||
line = line.strip()
|
||||
if line[0] != '"' or line[-1:] != '"':
|
||||
print("ERROR at line %d: Missing quote." % lineno)
|
||||
line = strip_quotes( line )
|
||||
self.msgidp += line
|
||||
|
||||
def add_new_msgstr( self, line, lineno ):
|
||||
self.msgstr.append( '' ) # Start a new msgstr
|
||||
self.add_msgstr( line, lineno )
|
||||
def add_new_msgstr( self, line, lineno ):
|
||||
self.msgstr.append( '' ) # Start a new msgstr
|
||||
self.add_msgstr( line, lineno )
|
||||
|
||||
def add_msgstr( self, line, lineno ):
|
||||
self._msgstr.append( line )
|
||||
line = re.sub( r'msgstr(\[\d\])?\s+', '', line )
|
||||
line = line.strip()
|
||||
if line[0] != '"' or line[-1:] != '"':
|
||||
print "ERROR at line %d: Missing quote." % lineno
|
||||
line = strip_quotes( line )
|
||||
self.msgstr[-1] += line
|
||||
def add_msgstr( self, line, lineno ):
|
||||
self._msgstr.append( line )
|
||||
line = re.sub( r'msgstr(\[\d\])?\s+', '', line )
|
||||
line = line.strip()
|
||||
if line[0] != '"' or line[-1:] != '"':
|
||||
print("ERROR at line %d: Missing quote." % lineno)
|
||||
line = strip_quotes( line )
|
||||
self.msgstr[-1] += line
|
||||
|
||||
def add_cmnt( self, line ):
|
||||
self._cmnt.append( line )
|
||||
if not self.is_fuzzy and self.fuzzy_pat.search( line ):
|
||||
self.is_fuzzy = 1
|
||||
if not self.is_tips_xml and self.tips_xml_pat.search( line ):
|
||||
self.is_tips_xml = 1
|
||||
def add_cmnt( self, line ):
|
||||
self._cmnt.append( line )
|
||||
if not self.is_fuzzy and self.fuzzy_pat.search( line ):
|
||||
self.is_fuzzy = 1
|
||||
if not self.is_tips_xml and self.tips_xml_pat.search( line ):
|
||||
self.is_tips_xml = 1
|
||||
|
||||
def create_new_Msgid( msgs, lineno ):
|
||||
msg = Msgid( len(msgs), lineno )
|
||||
msgs.append( msg )
|
||||
return msg
|
||||
msg = Msgid( len(msgs), lineno )
|
||||
msgs.append( msg )
|
||||
return msg
|
||||
|
||||
def read_msgs( fname ):
|
||||
empty_pat = re.compile( r'^ \s* $', re.VERBOSE )
|
||||
comment_pat = re.compile( r'\#', re.VERBOSE )
|
||||
msgid_pat = re.compile( r'msgid \s+ "', re.VERBOSE )
|
||||
msgid_plural_pat = re.compile( r'msgid_plural \s+ "', re.VERBOSE )
|
||||
msgstr_pat = re.compile( r'msgstr (\[\d\])? \s+ "', re.VERBOSE )
|
||||
str_pat = re.compile( r'"', re.VERBOSE )
|
||||
old_pat = re.compile( r'\#~ \s+ ', re.VERBOSE )
|
||||
empty_pat = re.compile( r'^ \s* $', re.VERBOSE )
|
||||
comment_pat = re.compile( r'\#', re.VERBOSE )
|
||||
msgid_pat = re.compile( r'msgid \s+ "', re.VERBOSE )
|
||||
msgid_plural_pat = re.compile( r'msgid_plural \s+ "', re.VERBOSE )
|
||||
msgstr_pat = re.compile( r'msgstr (\[\d\])? \s+ "', re.VERBOSE )
|
||||
str_pat = re.compile( r'"', re.VERBOSE )
|
||||
old_pat = re.compile( r'\#~ \s+ ', re.VERBOSE )
|
||||
|
||||
f = open( fname )
|
||||
lines = f.readlines()
|
||||
|
||||
# parse it like a statemachine
|
||||
NONE = 'NONE' # Nothing detected, yet
|
||||
CMNT = 'CMNT' # Inside comment part
|
||||
MSGID = 'msgid' # Inside msgid part
|
||||
MSGIDP = 'msgid_plural' # Inside msgid_plural part
|
||||
MSGSTR = 'msgstr' # Inside msgstr part
|
||||
STR = 'STR' # A continuation string
|
||||
OLD = 'OLD' # An old pattern with #~
|
||||
f = open( fname )
|
||||
lines = f.readlines()
|
||||
|
||||
global msgs
|
||||
state = NONE
|
||||
msg = None
|
||||
# parse it like a statemachine
|
||||
NONE = 'NONE' # Nothing detected, yet
|
||||
CMNT = 'CMNT' # Inside comment part
|
||||
MSGID = 'msgid' # Inside msgid part
|
||||
MSGIDP = 'msgid_plural' # Inside msgid_plural part
|
||||
MSGSTR = 'msgstr' # Inside msgstr part
|
||||
STR = 'STR' # A continuation string
|
||||
OLD = 'OLD' # An old pattern with #~
|
||||
|
||||
msgs = []
|
||||
for ix, line in enumerate( lines ): # Use line numbers for messages
|
||||
lineno = ix + 1
|
||||
global msgs
|
||||
state = NONE
|
||||
msg = None
|
||||
|
||||
m = empty_pat.match( line )
|
||||
if m:
|
||||
continue # Empty lines are not interesting
|
||||
msgs = []
|
||||
for ix, line in enumerate( lines ): # Use line numbers for messages
|
||||
lineno = ix + 1
|
||||
|
||||
# What's the next state?
|
||||
if old_pat.match( line ):
|
||||
next_state = OLD
|
||||
elif comment_pat.match( line ):
|
||||
next_state = CMNT
|
||||
elif msgid_pat.match( line ):
|
||||
next_state = MSGID
|
||||
elif msgid_plural_pat.match( line ):
|
||||
next_state = MSGIDP
|
||||
elif msgstr_pat.match( line ):
|
||||
next_state = MSGSTR
|
||||
elif str_pat.match( line ):
|
||||
next_state = STR
|
||||
else:
|
||||
print 'WARNING: Unexpected input at %(fname)s:%(lineno)d' % vars()
|
||||
next_state = NONE
|
||||
m = empty_pat.match( line )
|
||||
if m:
|
||||
continue # Empty lines are not interesting
|
||||
|
||||
#print "%(state)d->%(next_state)d\t%(line)s" % vars()
|
||||
if state == NONE:
|
||||
# expect msgid or comment or old stuff
|
||||
if next_state == CMNT:
|
||||
state = CMNT
|
||||
msg = create_new_Msgid( msgs, lineno ) # Start with an empty new item
|
||||
msg.add_cmnt( line )
|
||||
# What's the next state?
|
||||
if old_pat.match( line ):
|
||||
next_state = OLD
|
||||
elif comment_pat.match( line ):
|
||||
next_state = CMNT
|
||||
elif msgid_pat.match( line ):
|
||||
next_state = MSGID
|
||||
elif msgid_plural_pat.match( line ):
|
||||
next_state = MSGIDP
|
||||
elif msgstr_pat.match( line ):
|
||||
next_state = MSGSTR
|
||||
elif str_pat.match( line ):
|
||||
next_state = STR
|
||||
else:
|
||||
print('WARNING: Unexpected input at %(fname)s:%(lineno)d' % vars())
|
||||
next_state = NONE
|
||||
|
||||
elif next_state == MSGID:
|
||||
state = MSGID
|
||||
msg = create_new_Msgid( msgs, lineno ) # Start with an empty new item
|
||||
msg.add_msgid( line, lineno )
|
||||
#print("%(state)d->%(next_state)d\t%(line)s" % vars())
|
||||
if state == NONE:
|
||||
# expect msgid or comment or old stuff
|
||||
if next_state == CMNT:
|
||||
state = CMNT
|
||||
msg = create_new_Msgid( msgs, lineno ) # Start with an empty new item
|
||||
msg.add_cmnt( line )
|
||||
|
||||
elif next_state == MSGIDP:
|
||||
raise CheckException( 'Unexpected %(next_state)s at %(fname)s:%(lineno)d' % vars() )
|
||||
elif next_state == MSGID:
|
||||
state = MSGID
|
||||
msg = create_new_Msgid( msgs, lineno ) # Start with an empty new item
|
||||
msg.add_msgid( line, lineno )
|
||||
|
||||
elif next_state == MSGSTR:
|
||||
print 'WARNING: Wild msgstr at %(fname)s:%(lineno)d' % vars()
|
||||
state = MSGSTR
|
||||
msg = create_new_Msgid( msgs, lineno ) # Start with an empty new item
|
||||
msg.add_new_msgstr( line, lineno )
|
||||
elif next_state == MSGIDP:
|
||||
raise CheckException( 'Unexpected %(next_state)s at %(fname)s:%(lineno)d' % vars() )
|
||||
|
||||
elif next_state == STR:
|
||||
print 'WARNING: Wild string at %(fname)s:%(lineno)d' % vars()
|
||||
elif next_state == MSGSTR:
|
||||
print('WARNING: Wild msgstr at %(fname)s:%(lineno)d' % vars())
|
||||
state = MSGSTR
|
||||
msg = create_new_Msgid( msgs, lineno ) # Start with an empty new item
|
||||
msg.add_new_msgstr( line, lineno )
|
||||
|
||||
elif next_state == OLD:
|
||||
pass # Just skip
|
||||
elif next_state == STR:
|
||||
print('WARNING: Wild string at %(fname)s:%(lineno)d' % vars())
|
||||
|
||||
else:
|
||||
raise CheckException( 'Unexpected state in po parsing (state = %(state)s)' % vars() )
|
||||
elif next_state == OLD:
|
||||
pass # Just skip
|
||||
|
||||
elif state == CMNT:
|
||||
# Expect more comment, or msgid. If msgstr or string it is flagged as error.
|
||||
if next_state == CMNT:
|
||||
if msg:
|
||||
msg.add_cmnt( line )
|
||||
else:
|
||||
# Note. We may need to do something about these comments
|
||||
# Skip for now
|
||||
pass
|
||||
else:
|
||||
raise CheckException( 'Unexpected state in po parsing (state = %(state)s)' % vars() )
|
||||
|
||||
elif next_state == MSGID:
|
||||
state = MSGID
|
||||
if not msg:
|
||||
msg = create_new_Msgid( msgs, lineno ) # Start with an empty new item
|
||||
msg.add_msgid( line, lineno )
|
||||
elif state == CMNT:
|
||||
# Expect more comment, or msgid. If msgstr or string it is flagged as error.
|
||||
if next_state == CMNT:
|
||||
if msg:
|
||||
msg.add_cmnt( line )
|
||||
else:
|
||||
# Note. We may need to do something about these comments
|
||||
# Skip for now
|
||||
pass
|
||||
|
||||
elif next_state == MSGIDP:
|
||||
raise CheckException( 'Unexpected %(next_state)s at %(fname)s:%(lineno)d' % vars() )
|
||||
elif next_state == MSGID:
|
||||
state = MSGID
|
||||
if not msg:
|
||||
msg = create_new_Msgid( msgs, lineno ) # Start with an empty new item
|
||||
msg.add_msgid( line, lineno )
|
||||
|
||||
elif next_state == MSGSTR:
|
||||
print 'WARNING: Wild msgstr at %(fname)s:%(lineno)d' % vars()
|
||||
state = MSGSTR
|
||||
msg = create_new_Msgid( msgs, lineno ) # Start with an empty new item
|
||||
msg.add_new_msgstr( line, lineno )
|
||||
elif next_state == MSGIDP:
|
||||
raise CheckException( 'Unexpected %(next_state)s at %(fname)s:%(lineno)d' % vars() )
|
||||
|
||||
elif next_state == STR:
|
||||
print 'WARNING: Wild string at %(fname)s:%(lineno)d' % vars()
|
||||
elif next_state == MSGSTR:
|
||||
print('WARNING: Wild msgstr at %(fname)s:%(lineno)d' % vars())
|
||||
state = MSGSTR
|
||||
msg = create_new_Msgid( msgs, lineno ) # Start with an empty new item
|
||||
msg.add_new_msgstr( line, lineno )
|
||||
|
||||
elif next_state == OLD:
|
||||
msg = None
|
||||
pass # Just skip
|
||||
elif next_state == STR:
|
||||
print('WARNING: Wild string at %(fname)s:%(lineno)d' % vars())
|
||||
|
||||
else:
|
||||
raise CheckException( 'Unexpected state in po parsing (state = %(state)s)' % vars() )
|
||||
elif next_state == OLD:
|
||||
msg = None
|
||||
pass # Just skip
|
||||
|
||||
elif state == MSGID:
|
||||
# Expect msgstr or msgid_plural or string
|
||||
if next_state == CMNT:
|
||||
# Hmmm. A comment here?
|
||||
print 'WARNING: Unexpted comment at %(fname)s:%(lineno)d' % vars()
|
||||
else:
|
||||
raise CheckException( 'Unexpected state in po parsing (state = %(state)s)' % vars() )
|
||||
|
||||
elif next_state == MSGID:
|
||||
raise CheckException( 'Unexpected %(next_state)s at %(fname)s:%(lineno)d' % vars() )
|
||||
elif state == MSGID:
|
||||
# Expect msgstr or msgid_plural or string
|
||||
if next_state == CMNT:
|
||||
# Hmmm. A comment here?
|
||||
print('WARNING: Unexpted comment at %(fname)s:%(lineno)d' % vars())
|
||||
|
||||
elif next_state == MSGIDP:
|
||||
state = MSGIDP
|
||||
msg.add_msgidp( line, lineno )
|
||||
elif next_state == MSGID:
|
||||
raise CheckException( 'Unexpected %(next_state)s at %(fname)s:%(lineno)d' % vars() )
|
||||
|
||||
elif next_state == MSGSTR:
|
||||
state = MSGSTR
|
||||
msg.add_new_msgstr( line, lineno )
|
||||
elif next_state == MSGIDP:
|
||||
state = MSGIDP
|
||||
msg.add_msgidp( line, lineno )
|
||||
|
||||
elif next_state == STR:
|
||||
# Continuation of msgid, stay in state MSGID
|
||||
msg.add_msgid( line, lineno )
|
||||
elif next_state == MSGSTR:
|
||||
state = MSGSTR
|
||||
msg.add_new_msgstr( line, lineno )
|
||||
|
||||
elif next_state == OLD:
|
||||
msg = None
|
||||
pass # Just skip
|
||||
elif next_state == STR:
|
||||
# Continuation of msgid, stay in state MSGID
|
||||
msg.add_msgid( line, lineno )
|
||||
|
||||
else:
|
||||
raise CheckException( 'Unexpected state in po parsing (state = %(state)s)' % vars() )
|
||||
elif next_state == OLD:
|
||||
msg = None
|
||||
pass # Just skip
|
||||
|
||||
elif state == MSGIDP:
|
||||
# Expect msgstr or string or comment
|
||||
if next_state == CMNT:
|
||||
# Hmmm. A comment here?
|
||||
print 'WARNING: Unexpted comment at %(fname)s:%(lineno)d' % vars()
|
||||
else:
|
||||
raise CheckException( 'Unexpected state in po parsing (state = %(state)s)' % vars() )
|
||||
|
||||
elif next_state == MSGID:
|
||||
raise CheckException( 'Unexpected %(next_state)s at %(fname)s:%(lineno)d' % vars() )
|
||||
elif state == MSGIDP:
|
||||
# Expect msgstr or string or comment
|
||||
if next_state == CMNT:
|
||||
# Hmmm. A comment here?
|
||||
print('WARNING: Unexpted comment at %(fname)s:%(lineno)d' % vars())
|
||||
|
||||
elif next_state == MSGIDP:
|
||||
raise CheckException( 'Unexpected %(next_state)s at %(fname)s:%(lineno)d' % vars() )
|
||||
elif next_state == MSGID:
|
||||
raise CheckException( 'Unexpected %(next_state)s at %(fname)s:%(lineno)d' % vars() )
|
||||
|
||||
elif next_state == MSGSTR:
|
||||
state = MSGSTR
|
||||
msg.add_new_msgstr( line, lineno )
|
||||
elif next_state == MSGIDP:
|
||||
raise CheckException( 'Unexpected %(next_state)s at %(fname)s:%(lineno)d' % vars() )
|
||||
|
||||
elif next_state == STR:
|
||||
# Continuation of msgid_plural, stay in state MSGIDP
|
||||
msg.add_msgidp( line, lineno )
|
||||
elif next_state == MSGSTR:
|
||||
state = MSGSTR
|
||||
msg.add_new_msgstr( line, lineno )
|
||||
|
||||
elif next_state == OLD:
|
||||
msg = None
|
||||
pass # Just skip
|
||||
elif next_state == STR:
|
||||
# Continuation of msgid_plural, stay in state MSGIDP
|
||||
msg.add_msgidp( line, lineno )
|
||||
|
||||
else:
|
||||
raise CheckException( 'Unexpected state in po parsing (state = %(state)s)' % vars() )
|
||||
elif next_state == OLD:
|
||||
msg = None
|
||||
pass # Just skip
|
||||
|
||||
elif state == MSGSTR:
|
||||
# Expect comment, or msgid, or string.
|
||||
if next_state == CMNT:
|
||||
# A comment probably starts a new item
|
||||
state = CMNT
|
||||
msg = create_new_Msgid( msgs, lineno )
|
||||
msg.add_cmnt( line )
|
||||
else:
|
||||
raise CheckException( 'Unexpected state in po parsing (state = %(state)s)' % vars() )
|
||||
|
||||
elif next_state == MSGID:
|
||||
state = MSGID
|
||||
msg = create_new_Msgid( msgs, lineno )
|
||||
msg.add_msgid( line, lineno )
|
||||
elif state == MSGSTR:
|
||||
# Expect comment, or msgid, or string.
|
||||
if next_state == CMNT:
|
||||
# A comment probably starts a new item
|
||||
state = CMNT
|
||||
msg = create_new_Msgid( msgs, lineno )
|
||||
msg.add_cmnt( line )
|
||||
|
||||
elif next_state == MSGIDP:
|
||||
raise CheckException( 'Unexpected %(next_state)s at %(fname)s:%(lineno)d' % vars() )
|
||||
elif next_state == MSGID:
|
||||
state = MSGID
|
||||
msg = create_new_Msgid( msgs, lineno )
|
||||
msg.add_msgid( line, lineno )
|
||||
|
||||
elif next_state == MSGSTR:
|
||||
# New msgstr, probably for plural form
|
||||
# Stay in MSGSTR state
|
||||
msg.add_new_msgstr( line, lineno )
|
||||
elif next_state == MSGIDP:
|
||||
raise CheckException( 'Unexpected %(next_state)s at %(fname)s:%(lineno)d' % vars() )
|
||||
|
||||
elif next_state == STR:
|
||||
msg.add_msgstr( line, lineno )
|
||||
elif next_state == MSGSTR:
|
||||
# New msgstr, probably for plural form
|
||||
# Stay in MSGSTR state
|
||||
msg.add_new_msgstr( line, lineno )
|
||||
|
||||
elif next_state == OLD:
|
||||
msg = None
|
||||
pass # Just skip
|
||||
elif next_state == STR:
|
||||
msg.add_msgstr( line, lineno )
|
||||
|
||||
else:
|
||||
raise CheckException( 'Unexpected state in po parsing (state = %(state)s)' % vars() )
|
||||
elif next_state == OLD:
|
||||
msg = None
|
||||
pass # Just skip
|
||||
|
||||
else:
|
||||
raise CheckException( 'Unexpected state in po parsing (state = %(state)s)' % vars() )
|
||||
else:
|
||||
raise CheckException( 'Unexpected state in po parsing (state = %(state)s)' % vars() )
|
||||
|
||||
# Strip items with just comments. (Can this happen?)
|
||||
msgs1 = []
|
||||
for m in msgs:
|
||||
if not m.msgid and not m.msgstr:
|
||||
#print "INFO: No msgid or msgstr at %s:%s" % ( fname, m.lineno )
|
||||
pass
|
||||
else:
|
||||
msgs1.append( m )
|
||||
msgs = msgs1
|
||||
return msgs
|
||||
else:
|
||||
raise CheckException( 'Unexpected state in po parsing (state = %(state)s)' % vars() )
|
||||
|
||||
# Strip items with just comments. (Can this happen?)
|
||||
msgs1 = []
|
||||
for m in msgs:
|
||||
if not m.msgid and not m.msgstr:
|
||||
#print("INFO: No msgid or msgstr at %s:%s" % ( fname, m.lineno ))
|
||||
pass
|
||||
else:
|
||||
msgs1.append( m )
|
||||
msgs = msgs1
|
||||
return msgs
|
||||
|
||||
def analyze_msgs( args, fname, msgs, nr_templates = None, nth = 0 ):
|
||||
nr_fuzzy = 0
|
||||
nr_untranslated = 0
|
||||
nr_fuzzy = 0
|
||||
nr_untranslated = 0
|
||||
|
||||
checks = []
|
||||
checks.append( Check_fmt( '%s' ) )
|
||||
checks.append( Check_fmt( '%d' ) )
|
||||
checks.append( Check_named_fmt() )
|
||||
checks.append( Check_missing_sd() )
|
||||
checks.append( Check_runaway() )
|
||||
checks.append( Check_xml_chars() )
|
||||
checks.append( Check_last_char() )
|
||||
checks.append( Check_shortcut_trans() )
|
||||
checks = []
|
||||
checks.append( Check_fmt( '%s' ) )
|
||||
checks.append( Check_fmt( '%d' ) )
|
||||
checks.append( Check_named_fmt() )
|
||||
checks.append( Check_missing_sd() )
|
||||
checks.append( Check_runaway() )
|
||||
checks.append( Check_xml_chars() )
|
||||
checks.append( Check_last_char() )
|
||||
checks.append( Check_shortcut_trans() )
|
||||
|
||||
for msg in msgs:
|
||||
msgid = msg.msgid
|
||||
msgstr = msg.msgstr
|
||||
#print
|
||||
#print "msgid: %(msgid)s" % vars()
|
||||
#print "msgstr: %(msgstr)s" % vars()
|
||||
for msg in msgs:
|
||||
msgid = msg.msgid
|
||||
msgstr = msg.msgstr
|
||||
#print
|
||||
#print("msgid: %(msgid)s" % vars())
|
||||
#print("msgstr: %(msgstr)s" % vars())
|
||||
|
||||
if ''.join(msgstr) == '':
|
||||
nr_untranslated += 1
|
||||
continue
|
||||
if ''.join(msgstr) == '':
|
||||
nr_untranslated += 1
|
||||
continue
|
||||
|
||||
if msg.is_fuzzy:
|
||||
nr_fuzzy += 1
|
||||
continue
|
||||
if msg.is_fuzzy:
|
||||
nr_fuzzy += 1
|
||||
continue
|
||||
|
||||
for c in checks:
|
||||
c.process( msg )
|
||||
for c in checks:
|
||||
c.process( msg )
|
||||
|
||||
nr_msgs = len(msgs)
|
||||
if nth > 0:
|
||||
print
|
||||
print "====================================="
|
||||
print "%-20s%s" % ( "File:", fname )
|
||||
print "%-20s%d" % ( "Template total:", nr_templates )
|
||||
print "%-20s%d" % ( "PO total:", nr_msgs )
|
||||
print "%-20s%d" % ( "Fuzzy:", nr_fuzzy )
|
||||
print "%-20s%d" % ( "Untranslated:", nr_untranslated )
|
||||
nr_msgs = len(msgs)
|
||||
if nth > 0:
|
||||
print
|
||||
print("=====================================")
|
||||
print("%-20s%s" % ( "File:", fname ))
|
||||
print("%-20s%d" % ( "Template total:", nr_templates ))
|
||||
print("%-20s%d" % ( "PO total:", nr_msgs ))
|
||||
print("%-20s%d" % ( "Fuzzy:", nr_fuzzy ))
|
||||
print("%-20s%d" % ( "Untranslated:", nr_untranslated ))
|
||||
|
||||
for c in checks:
|
||||
c.summary()
|
||||
for c in checks:
|
||||
c.summary()
|
||||
|
||||
po_coverage = (1.0 - (float(nr_untranslated) / float(nr_msgs))) * 100
|
||||
print "%-20s%5.2f%%" % ( "PO Coverage:", po_coverage )
|
||||
po_coverage = (1.0 - (float(nr_untranslated) / float(nr_msgs))) * 100
|
||||
print("%-20s%5.2f%%" % ( "PO Coverage:", po_coverage ))
|
||||
|
||||
template_coverage = po_coverage * float(nr_msgs) / float(nr_templates)
|
||||
print "%-20s%5.2f%%" % ( "Template Coverage:", template_coverage )
|
||||
template_coverage = po_coverage * float(nr_msgs) / float(nr_templates)
|
||||
print("%-20s%5.2f%%" % ( "Template Coverage:", template_coverage ))
|
||||
|
||||
not_displayed = nr_untranslated + nr_fuzzy
|
||||
translation = (1.0 - (float(not_displayed) / float(nr_templates))) * 100
|
||||
text = "%-20s%5.2f%%" % ( "Localized at:", translation)
|
||||
not_displayed = nr_untranslated + nr_fuzzy
|
||||
translation = (1.0 - (float(not_displayed) / float(nr_templates))) * 100
|
||||
text = "%-20s%5.2f%%" % ( "Localized at:", translation)
|
||||
|
||||
if int(template_coverage*1000) == int(po_coverage*1000):
|
||||
print text
|
||||
else:
|
||||
print text + ' (previous gramps.pot)'
|
||||
if int(template_coverage*1000) == int(po_coverage*1000):
|
||||
print(text)
|
||||
else:
|
||||
print(text + ' (previous gramps.pot)')
|
||||
|
||||
for c in checks:
|
||||
c.diag()
|
||||
for c in checks:
|
||||
c.diag()
|
||||
|
||||
def main():
|
||||
|
||||
|
||||
parser = ArgumentParser( description='This program validates a PO file for GRAMPS.')
|
||||
|
||||
|
||||
parser.add_argument("-s", dest="summary",
|
||||
choices=[file for file in os.listdir('.') if file.endswith('.po')],
|
||||
choices=[file for file in os.listdir('.') if file.endswith('.po')],
|
||||
default=False, help="the summary of check, and if need, it gives details")
|
||||
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
if args.summary:
|
||||
files = sys.argv[2:]
|
||||
|
||||
try:
|
||||
pot_msgs = read_msgs( 'gramps.pot' )
|
||||
nr_templates = len( pot_msgs )
|
||||
nth = 0
|
||||
for fname in files:
|
||||
msgs = read_msgs( fname )
|
||||
analyze_msgs( files, fname, msgs, nr_templates, nth )
|
||||
nth += 1
|
||||
try:
|
||||
pot_msgs = read_msgs( 'gramps.pot' )
|
||||
nr_templates = len( pot_msgs )
|
||||
nth = 0
|
||||
for fname in files:
|
||||
msgs = read_msgs( fname )
|
||||
analyze_msgs( files, fname, msgs, nr_templates, nth )
|
||||
nth += 1
|
||||
|
||||
except CheckException, e:
|
||||
print 'Oops.', e
|
||||
print 'Bailing out'
|
||||
except CheckException as e:
|
||||
print('Oops.', e)
|
||||
print('Bailing out')
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
Loading…
Reference in New Issue
Block a user