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