Package translate :: Package convert :: Module po2oo
[hide private]
[frames] | no frames]

Source Code for Module translate.convert.po2oo

  1  #!/usr/bin/env python 
  2  # -*- coding: utf-8 -*- 
  3  #  
  4  # Copyright 2004-2006 Zuza Software Foundation 
  5  #  
  6  # This file is part of translate. 
  7  # 
  8  # translate is free software; you can redistribute it and/or modify 
  9  # it under the terms of the GNU General Public License as published by 
 10  # the Free Software Foundation; either version 2 of the License, or 
 11  # (at your option) any later version. 
 12  #  
 13  # translate is distributed in the hope that it will be useful, 
 14  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 15  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 16  # GNU General Public License for more details. 
 17  # 
 18  # You should have received a copy of the GNU General Public License 
 19  # along with translate; if not, write to the Free Software 
 20  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 21  # 
 22   
 23  """convert Gettext PO localization files to an OpenOffice.org (SDF) localization file 
 24   
 25  see: http://translate.sourceforge.net/wiki/toolkit/po2oo for examples and  
 26  usage instructions 
 27  """ 
 28   
 29  import sys 
 30  import os 
 31  from translate.storage import oo 
 32  from translate.storage import factory 
 33  from translate.filters import pofilter 
 34  from translate.filters import checks 
 35  from translate.filters import autocorrect  
 36  import time 
 37   
38 -class reoo:
39 - def __init__(self, templatefile, languages=None, timestamp=None, includefuzzy=False, long_keys=False, filteraction="exclude"):
40 """construct a reoo converter for the specified languages (timestamp=0 means leave unchanged)""" 41 # languages is a pair of language ids 42 self.long_keys = long_keys 43 self.readoo(templatefile) 44 self.languages = languages 45 self.filteraction = filteraction 46 if timestamp is None: 47 self.timestamp = time.strptime("2002-02-02 02:02:02", "%Y-%m-%d %H:%M:%S") 48 else: 49 self.timestamp = timestamp 50 if self.timestamp: 51 self.timestamp_str = time.strftime("%Y-%m-%d %H:%M:%S", self.timestamp) 52 else: 53 self.timestamp_str = None 54 self.includefuzzy = includefuzzy
55
56 - def makekey(self, ookey):
57 """converts an oo key tuple into a key identifier for the source file""" 58 project, sourcefile, resourcetype, groupid, localid, platform = ookey 59 sourcefile = sourcefile.replace('\\','/') 60 if self.long_keys: 61 sourcebase = os.path.join(project, sourcefile) 62 else: 63 sourceparts = sourcefile.split('/') 64 sourcebase = "".join(sourceparts[-1:]) 65 if len(groupid) == 0 or len(localid) == 0: 66 fullid = groupid + localid 67 else: 68 fullid = groupid + "." + localid 69 if resourcetype: 70 fullid = fullid + "." + resourcetype 71 key = "%s#%s" % (sourcebase, fullid) 72 return oo.normalizefilename(key)
73
74 - def makeindex(self):
75 """makes an index of the oo keys that are used in the source file""" 76 self.index = {} 77 for ookey, theoo in self.o.ookeys.iteritems(): 78 sourcekey = self.makekey(ookey) 79 self.index[sourcekey] = theoo
80
81 - def readoo(self, of):
82 """read in the oo from the file""" 83 oosrc = of.read() 84 self.o = oo.oofile() 85 self.o.parse(oosrc) 86 self.makeindex()
87
88 - def handleunit(self, unit):
89 # TODO: make this work for multiple columns in oo... 90 locations = unit.getlocations() 91 # technically our formats should just have one location for each entry... 92 # but we handle multiple ones just to be safe... 93 for location in locations: 94 subkeypos = location.rfind('.') 95 subkey = location[subkeypos+1:] 96 key = location[:subkeypos] 97 # this is just to handle our old system of using %s/%s:%s instead of %s/%s#%s 98 key = key.replace(':', '#') 99 # this is to handle using / instead of \ in the sourcefile... 100 key = key.replace('\\', '/') 101 key = oo.normalizefilename(key) 102 if self.index.has_key(key): 103 # now we need to replace the definition of entity with msgstr 104 theoo = self.index[key] # find the oo 105 self.applytranslation(key, subkey, theoo, unit) 106 else: 107 print >> sys.stderr, "couldn't find key %s from po in %d keys" % (key, len(self.index)) 108 try: 109 sourceunitlines = str(unit) 110 if isinstance(sourceunitlines, unicode): 111 sourceunitlines = sourceunitlines.encode("utf-8") 112 print >> sys.stderr, sourceunitlines 113 except: 114 print >> sys.stderr, "error outputting source unit %r" % (str(unit),)
115
116 - def applytranslation(self, key, subkey, theoo, unit):
117 """applies the translation from the source unit to the oo unit""" 118 if not self.includefuzzy and unit.isfuzzy(): 119 return 120 makecopy = False 121 if self.languages is None: 122 part1 = theoo.lines[0] 123 if len(theoo.lines) > 1: 124 part2 = theoo.lines[1] 125 else: 126 makecopy = True 127 else: 128 part1 = theoo.languages[self.languages[0]] 129 if self.languages[1] in theoo.languages: 130 part2 = theoo.languages[self.languages[1]] 131 else: 132 makecopy = True 133 if makecopy: 134 part2 = oo.ooline(part1.getparts()) 135 unquotedid = unit.source 136 unquotedstr = unit.target 137 # If there is no translation, we don't want to add a line 138 if len(unquotedstr) == 0: 139 return 140 if isinstance(unquotedstr, unicode): 141 unquotedstr = unquotedstr.encode("UTF-8") 142 # finally set the new definition in the oo, but not if its empty 143 if len(unquotedstr) > 0: 144 setattr(part2, subkey, unquotedstr) 145 # set the modified time 146 if self.timestamp_str: 147 part2.timestamp = self.timestamp_str 148 if self.languages: 149 part2.languageid = self.languages[1] 150 if makecopy: 151 theoo.addline(part2)
152
153 - def convertstore(self, sourcestore):
154 self.p = sourcestore 155 # translate the strings 156 for unit in self.p.units: 157 # there may be more than one element due to msguniq merge 158 if filter.validelement(unit, self.p.filename, self.filteraction): 159 self.handleunit(unit) 160 # return the modified oo file object 161 return self.o
162
163 -def getmtime(filename):
164 import stat 165 return time.localtime(os.stat(filename)[stat.ST_MTIME])
166
167 -class oocheckfilter(pofilter.pocheckfilter):
168 - def validelement(self, unit, filename, filteraction):
169 """Returns whether or not to use unit in conversion. (filename is just for error reporting)""" 170 if filteraction == "none": return True 171 filterresult = self.filterunit(unit) 172 if filterresult: 173 if filterresult != autocorrect: 174 for filtername, filtermessage in filterresult.iteritems(): 175 location = unit.getlocations()[0].encode('utf-8') 176 if filtername in self.options.error: 177 print >> sys.stderr, "Error at %s::%s: %s" % (filename, location, filtermessage) 178 return not filteraction in ["exclude-all", "exclude-serious"] 179 if filtername in self.options.warning or self.options.alwayswarn: 180 print >> sys.stderr, "Warning at %s::%s: %s" % (filename, location, filtermessage) 181 return not filteraction in ["exclude-all"] 182 return True
183
184 -class oofilteroptions:
185 error = ['variables', 'xmltags', 'escapes'] 186 warning = ['blank'] 187 #To only issue warnings for tests listed in warning, change the following to False: 188 alwayswarn = True 189 limitfilters = error + warning 190 #To use all available tests, uncomment the following: 191 #limitfilters = [] 192 #To exclude certain tests, list them in here: 193 excludefilters = {} 194 includefuzzy = False 195 includereview = False 196 includeheader = False 197 autocorrect = False
198 199 options = oofilteroptions() 200 filter = oocheckfilter(options, [checks.OpenOfficeChecker, checks.StandardUnitChecker], checks.openofficeconfig) 201
202 -def convertoo(inputfile, outputfile, templatefile, sourcelanguage=None, targetlanguage=None, timestamp=None, includefuzzy=False, multifilestyle="single", filteraction=None):
203 inputstore = factory.getobject(inputfile) 204 inputstore.filename = getattr(inputfile, 'name', '') 205 if not targetlanguage: 206 raise ValueError("You must specify the target language") 207 if not sourcelanguage: 208 if targetlanguage.isdigit(): 209 sourcelanguage = "01" 210 else: 211 sourcelanguage = "en-US" 212 languages = (sourcelanguage, targetlanguage) 213 if templatefile is None: 214 raise ValueError("must have template file for oo files") 215 else: 216 convertor = reoo(templatefile, languages=languages, timestamp=timestamp, includefuzzy=includefuzzy, long_keys=multifilestyle != "single", filteraction=filteraction) 217 outputstore = convertor.convertstore(inputstore) 218 # TODO: check if we need to manually delete missing items 219 outputfile.write(str(outputstore)) 220 return True
221
222 -def main(argv=None):
223 from translate.convert import convert 224 formats = {("po", "oo"):("oo", convertoo), ("xlf", "oo"):("oo", convertoo), ("po", "sdf"):("sdf", convertoo)} 225 # always treat the input as an archive unless it is a directory 226 archiveformats = {(None, "output"): oo.oomultifile, (None, "template"): oo.oomultifile} 227 parser = convert.ArchiveConvertOptionParser(formats, usetemplates=True, description=__doc__, archiveformats=archiveformats) 228 parser.add_option("-l", "--language", dest="targetlanguage", default=None, 229 help="set target language code (e.g. af-ZA) [required]", metavar="LANG") 230 parser.add_option("", "--source-language", dest="sourcelanguage", default=None, 231 help="set source language code (default en-US)", metavar="LANG") 232 parser.add_option("-T", "--keeptimestamp", dest="timestamp", default=None, action="store_const", const=0, 233 help="don't change the timestamps of the strings") 234 parser.add_option("", "--nonrecursiveoutput", dest="allowrecursiveoutput", default=True, action="store_false", help="don't treat the output oo as a recursive store") 235 parser.add_option("", "--nonrecursivetemplate", dest="allowrecursivetemplate", default=True, action="store_false", help="don't treat the template oo as a recursive store") 236 parser.add_option("", "--filteraction", dest="filteraction", default="none", metavar="ACTION", 237 help="action on pofilter failure: none (default), warn, exclude-serious, exclude-all") 238 parser.add_fuzzy_option() 239 parser.add_multifile_option() 240 parser.passthrough.append("sourcelanguage") 241 parser.passthrough.append("targetlanguage") 242 parser.passthrough.append("timestamp") 243 parser.passthrough.append("filteraction") 244 parser.run(argv)
245 246 if __name__ == '__main__': 247 main() 248