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 makeindex(self):
     57          """makes an index of the oo keys that are used in the source file"""
     58          self.index = {}
     59          for ookey, theoo in self.o.ookeys.iteritems():
     60              sourcekey = oo.makekey(ookey, self.long_keys)
     61              self.index[sourcekey] = theoo
     62
     63 -    def readoo(self, of):
     64          """read in the oo from the file"""
     65          oosrc = of.read()
     66          self.o = oo.oofile()
     67          self.o.parse(oosrc)
     68          self.makeindex()
     69
     70 -    def handleunit(self, unit):
     71          # TODO: make this work for multiple columns in oo...
     72          locations = unit.getlocations()
     73          # technically our formats should just have one location for each entry...
     74          # but we handle multiple ones just to be safe...
     75          for location in locations:
     76              subkeypos = location.rfind('.')
     77              subkey = location[subkeypos+1:]
     78              key = location[:subkeypos]
     79              # this is just to handle our old system of using %s/%s:%s instead of %s/%s#%s
     80              key = key.replace(':', '#')
     81              # this is to handle using / instead of \ in the sourcefile...
     82              key = key.replace('\\', '/')
     83              key = oo.normalizefilename(key)
     84              if self.index.has_key(key):
     85                  # now we need to replace the definition of entity with msgstr
     86                  theoo = self.index[key] # find the oo
     87                  self.applytranslation(key, subkey, theoo, unit)
     88              else:
     89                  print >> sys.stderr, "couldn't find key %s from po in %d keys" % (key, len(self.index))
     90                  try:
     91                      sourceunitlines = str(unit)
     92                      if isinstance(sourceunitlines, unicode):
     93                          sourceunitlines = sourceunitlines.encode("utf-8")
     94                      print >> sys.stderr, sourceunitlines
     95                  except:
     96                      print >> sys.stderr, "error outputting source unit %r" % (str(unit),)
     97
     98 -    def applytranslation(self, key, subkey, theoo, unit):
     99          """applies the translation from the source unit to the oo unit"""
    100          if not self.includefuzzy and unit.isfuzzy():
    101              return
    102          makecopy = False
    103          if self.languages is None:
    104              part1 = theoo.lines[0]
    105              if len(theoo.lines) > 1:
    106                  part2 = theoo.lines[1]
    107              else:
    108                  makecopy = True
    109          else:
    110              part1 = theoo.languages[self.languages[0]]
    111              if self.languages[1] in theoo.languages:
    112                  part2 = theoo.languages[self.languages[1]]
    113              else:
    114                  makecopy = True
    115          if makecopy:
    116              part2 = oo.ooline(part1.getparts())
    117          unquotedid = unit.source
    118          unquotedstr = unit.target
    119          # If there is no translation, we don't want to add a line
    120          if len(unquotedstr) == 0:
    121              return
    122          if isinstance(unquotedstr, unicode):
    123              unquotedstr = unquotedstr.encode("UTF-8")
    124          # finally set the new definition in the oo, but not if its empty
    125          if len(unquotedstr) > 0:
    126              setattr(part2, subkey, unquotedstr)
    127          # set the modified time
    128          if self.timestamp_str:
    129              part2.timestamp = self.timestamp_str
    130          if self.languages:
    131              part2.languageid = self.languages[1]
    132          if makecopy:
    133              theoo.addline(part2)
    134
    135 -    def convertstore(self, sourcestore):
    136          self.p = sourcestore
    137          # translate the strings
    138          for unit in self.p.units:
    139              # there may be more than one element due to msguniq merge
    140              if filter.validelement(unit, self.p.filename, self.filteraction):
    141                  self.handleunit(unit)
    142          # return the modified oo file object
    143          return self.o
    144
    145 -def getmtime(filename):
    146      import stat
    147      return time.localtime(os.stat(filename)[stat.ST_MTIME])
    148
    149 -class oocheckfilter(pofilter.pocheckfilter):
    150 -    def validelement(self, unit, filename, filteraction):
    151          """Returns whether or not to use unit in conversion. (filename is just for error reporting)"""
    152          if filteraction == "none": return True
    153          filterresult = self.filterunit(unit)
    154          if filterresult:
    155              if filterresult != autocorrect:
    156                  for filtername, filtermessage in filterresult.iteritems():
    157                      location = unit.getlocations()[0].encode('utf-8')
    158                      if filtername in self.options.error:
    159                          print >> sys.stderr, "Error at %s::%s: %s" % (filename, location, filtermessage)
    160                          return not filteraction in ["exclude-all", "exclude-serious"]
    161                      if filtername in self.options.warning or self.options.alwayswarn:
    162                          print >> sys.stderr, "Warning at %s::%s: %s" % (filename, location, filtermessage)
    163                          return not filteraction in ["exclude-all"]
    164          return True
    165
    166 -class oofilteroptions:
    167      error = ['variables', 'xmltags', 'escapes']
    168      warning = ['blank']
    169      #To only issue warnings for tests listed in warning, change the following to False:
    170      alwayswarn = True
    171      limitfilters = error + warning
    172      #To use all available tests, uncomment the following:
    173      #limitfilters = []
    174      #To exclude certain tests, list them in here:
    175      excludefilters = {}
    176      includefuzzy = False
    177      includereview = False
    178      includeheader = False
    179      autocorrect = False
    180
    181  options = oofilteroptions()
    182  filter = oocheckfilter(options, [checks.OpenOfficeChecker, checks.StandardUnitChecker], checks.openofficeconfig)
    183
    184 -def convertoo(inputfile, outputfile, templatefile, sourcelanguage=None, targetlanguage=None, timestamp=None, includefuzzy=False, multifilestyle="single", filteraction=None):
    185      inputstore = factory.getobject(inputfile)
    186      inputstore.filename = getattr(inputfile, 'name', '')
    187      if not targetlanguage:
    188          raise ValueError("You must specify the target language")
    189      if not sourcelanguage:
    190          if targetlanguage.isdigit():
    191              sourcelanguage = "01"
    192          else:
    193              sourcelanguage = "en-US"
    194      languages = (sourcelanguage, targetlanguage)
    195      if templatefile is None:
    196          raise ValueError("must have template file for oo files")
    197      else:
    198          convertor = reoo(templatefile, languages=languages, timestamp=timestamp, includefuzzy=includefuzzy, long_keys=multifilestyle != "single", filteraction=filteraction)
    199      outputstore = convertor.convertstore(inputstore)
    200      # TODO: check if we need to manually delete missing items
    201      outputfile.write(str(outputstore))
    202      return True
    203
    204 -def main(argv=None):
    205      from translate.convert import convert
    206      formats = {("po", "oo"):("oo", convertoo), ("xlf", "oo"):("oo", convertoo), ("po", "sdf"):("sdf", convertoo)}
    207      # always treat the input as an archive unless it is a directory
    208      archiveformats = {(None, "output"): oo.oomultifile, (None, "template"): oo.oomultifile}
    209      parser = convert.ArchiveConvertOptionParser(formats, usetemplates=True, description=__doc__, archiveformats=archiveformats)
    210      parser.add_option("-l", "--language", dest="targetlanguage", default=None,
    211              help="set target language code (e.g. af-ZA) [required]", metavar="LANG")
    212      parser.add_option("", "--source-language", dest="sourcelanguage", default=None,
    213              help="set source language code (default en-US)", metavar="LANG")
    214      parser.add_option("-T", "--keeptimestamp", dest="timestamp", default=None, action="store_const", const=0,
    215              help="don't change the timestamps of the strings")
    216      parser.add_option("", "--nonrecursiveoutput", dest="allowrecursiveoutput", default=True, action="store_false", help="don't treat the output oo as a recursive store")
    217      parser.add_option("", "--nonrecursivetemplate", dest="allowrecursivetemplate", default=True, action="store_false", help="don't treat the template oo as a recursive store")
    218      parser.add_option("", "--filteraction", dest="filteraction", default="none", metavar="ACTION",
    219              help="action on pofilter failure: none (default), warn, exclude-serious, exclude-all")
    220      parser.add_fuzzy_option()
    221      parser.add_multifile_option()
    222      parser.passthrough.append("sourcelanguage")
    223      parser.passthrough.append("targetlanguage")
    224      parser.passthrough.append("timestamp")
    225      parser.passthrough.append("filteraction")
    226      parser.run(argv)
    227
    228  if __name__ == '__main__':
    229      main()
    230