Package elisa :: Package extern :: Module msgfmt
[hide private]
[frames] | no frames]

Source Code for Module elisa.extern.msgfmt

  1  # -*- coding: iso-8859-1 -*- 
  2  # Written by Martin v. Löwis <loewis@informatik.hu-berlin.de> 
  3   
  4  """Generate binary message catalog from textual translation description. 
  5   
  6  This program converts a textual Uniforum-style message catalog (.po file) into 
  7  a binary GNU catalog (.mo file).  This is essentially the same function as the 
  8  GNU msgfmt program, however, it is a simpler implementation. 
  9   
 10  Usage: msgfmt.py [OPTIONS] filename.po 
 11   
 12  Options: 
 13      -o file 
 14      --output-file=file 
 15          Specify the output file to write to.  If omitted, output will go to a 
 16          file named filename.mo (based off the input file name). 
 17   
 18      -h 
 19      --help 
 20          Print this message and exit. 
 21   
 22      -V 
 23      --version 
 24          Display version information and exit. 
 25  """ 
 26   
 27  import sys 
 28  import os 
 29  import getopt 
 30  import struct 
 31  import array 
 32   
 33  __version__ = "1.1" 
 34   
 35  MESSAGES = {} 
 36   
 37   
38 -def usage(code, msg=''):
39 print >> sys.stderr, __doc__ 40 if msg: 41 print >> sys.stderr, msg 42 sys.exit(code)
43 44 45
46 -def add(id, str, fuzzy):
47 "Add a non-fuzzy translation to the dictionary." 48 global MESSAGES 49 if not fuzzy and str: 50 MESSAGES[id] = str
51 52 53
54 -def generate():
55 "Return the generated output." 56 global MESSAGES 57 keys = MESSAGES.keys() 58 # the keys are sorted in the .mo file 59 keys.sort() 60 offsets = [] 61 ids = strs = '' 62 for id in keys: 63 # For each string, we need size and file offset. Each string is NUL 64 # terminated; the NUL does not count into the size. 65 offsets.append((len(ids), len(id), len(strs), len(MESSAGES[id]))) 66 ids += id + '\0' 67 strs += MESSAGES[id] + '\0' 68 output = '' 69 # The header is 7 32-bit unsigned integers. We don't use hash tables, so 70 # the keys start right after the index tables. 71 # translated string. 72 keystart = 7*4+16*len(keys) 73 # and the values start after the keys 74 valuestart = keystart + len(ids) 75 koffsets = [] 76 voffsets = [] 77 # The string table first has the list of keys, then the list of values. 78 # Each entry has first the size of the string, then the file offset. 79 for o1, l1, o2, l2 in offsets: 80 koffsets += [l1, o1+keystart] 81 voffsets += [l2, o2+valuestart] 82 offsets = koffsets + voffsets 83 output = struct.pack("Iiiiiii", 84 0x950412deL, # Magic 85 0, # Version 86 len(keys), # # of entries 87 7*4, # start of key index 88 7*4+len(keys)*8, # start of value index 89 0, 0) # size and offset of hash table 90 output += array.array("i", offsets).tostring() 91 output += ids 92 output += strs 93 MESSAGES={} 94 return output
95 96 97
98 -def make(filename, outfile):
99 ID = 1 100 STR = 2 101 102 # Compute .mo name from .po name and arguments 103 if filename.endswith('.po'): 104 infile = filename 105 else: 106 infile = filename + '.po' 107 if outfile is None: 108 outfile = os.path.splitext(infile)[0] + '.mo' 109 110 try: 111 lines = open(infile).readlines() 112 except IOError, msg: 113 print >> sys.stderr, msg 114 sys.exit(1) 115 116 section = None 117 fuzzy = 0 118 119 # Parse the catalog 120 lno = 0 121 for l in lines: 122 lno += 1 123 # If we get a comment line after a msgstr, this is a new entry 124 if l[0] == '#' and section == STR: 125 add(msgid, msgstr, fuzzy) 126 section = None 127 fuzzy = 0 128 # Record a fuzzy mark 129 if l[:2] == '#,' and 'fuzzy' in l: 130 fuzzy = 1 131 # Skip comments 132 if l[0] == '#': 133 continue 134 # Now we are in a msgid section, output previous section 135 if l.startswith('msgid'): 136 if section == STR: 137 add(msgid, msgstr, fuzzy) 138 section = ID 139 l = l[5:] 140 msgid = msgstr = '' 141 # Now we are in a msgstr section 142 elif l.startswith('msgstr'): 143 section = STR 144 l = l[6:] 145 # Skip empty lines 146 l = l.strip() 147 if not l: 148 continue 149 # XXX: Does this always follow Python escape semantics? 150 l = eval(l) 151 if section == ID: 152 msgid += l 153 elif section == STR: 154 msgstr += l 155 else: 156 print >> sys.stderr, 'Syntax error on %s:%d' % (infile, lno), \ 157 'before:' 158 print >> sys.stderr, l 159 sys.exit(1) 160 # Add last entry 161 if section == STR: 162 add(msgid, msgstr, fuzzy) 163 164 # Compute output 165 output = generate() 166 167 try: 168 open(outfile,"wb").write(output) 169 except IOError,msg: 170 print >> sys.stderr, msg
171 172 173
174 -def main():
175 try: 176 opts, args = getopt.getopt(sys.argv[1:], 'hVo:', 177 ['help', 'version', 'output-file=']) 178 except getopt.error, msg: 179 usage(1, msg) 180 181 outfile = None 182 # parse options 183 for opt, arg in opts: 184 if opt in ('-h', '--help'): 185 usage(0) 186 elif opt in ('-V', '--version'): 187 print >> sys.stderr, "msgfmt.py", __version__ 188 sys.exit(0) 189 elif opt in ('-o', '--output-file'): 190 outfile = arg 191 # do it 192 if not args: 193 print >> sys.stderr, 'No input file given' 194 print >> sys.stderr, "Try `msgfmt --help' for more information." 195 return 196 197 for filename in args: 198 make(filename, outfile)
199 200 201 if __name__ == '__main__': 202 main() 203