Package translate :: Package filters :: Module pofilter

[hide private]
[frames] | no frames]

# Source Code for Module translate.filters.pofilter

      1  #!/usr/bin/env python
      2  #
      3  # Copyright 2004-2007 Zuza Software Foundation
      4  #
      5  # This file is part of translate.
      6  #
      7  # translate is free software; you can redistribute it and/or modify
      8  # it under the terms of the GNU General Public License as published by
      9  # the Free Software Foundation; either version 2 of the License, or
     10  # (at your option) any later version.
     11  #
     12  # translate is distributed in the hope that it will be useful,
     13  # but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15  # GNU General Public License for more details.
     16  #
     17  # You should have received a copy of the GNU General Public License
     18  # along with translate; if not, write to the Free Software
     19  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     20
     21  """Perform quality checks on Gettext PO, XLIFF and TMX localization files
     22
     23  Snippet files whenever a test fails.  These can be examined, corrected and
     24  merged back into the originals using pomerge
     25
     26  See: http://translate.sourceforge.net/wiki/toolkit/pofilter for examples and
     27  usage instructions and http://translate.sourceforge.net/wiki/toolkit/pofilter_tests
     28  for full descriptions of all tests
     29  """
     30
     31  from translate.storage import factory
     32  from translate.storage.poheader import poheader
     33  from translate.filters import checks
     34  from translate.filters import autocorrect
     35  from translate.misc import optrecurse
     36
     37  import os
     38
     39 -class pocheckfilter:
     40 -    def __init__(self, options, checkerclasses=None, checkerconfig=None):
     41          # excludefilters={}, limitfilters=None, includefuzzy=True, includereview=True, autocorrect=False):
     42          """builds a checkfilter using the given checker (a list is allowed too)"""
     43          if checkerclasses is None:
     44              checkerclasses = [checks.StandardChecker, checks.StandardUnitChecker]
     45          self.checker = checks.TeeChecker(checkerconfig=checkerconfig, \
     46                  excludefilters=options.excludefilters, \
     47                  limitfilters=options.limitfilters, \
     48                  checkerclasses=checkerclasses, \
     49                  languagecode=checkerconfig.targetlanguage
     50          )
     51          self.options = options
     52
     53 -    def getfilterdocs(self):
     54          """lists the docs for filters available on checker..."""
     55          filterdict = self.checker.getfilters()
     56          filterdocs = ["%s\t%s" % (name, filterfunc.__doc__) for (name, filterfunc) in filterdict.iteritems()]
     57          filterdocs.sort()
     58          return "\n".join(filterdocs)
     59
     60 -    def filterunit(self, unit):
     61          """runs filters on an element"""
     62          if unit.isheader():
     63              return []
     64          if not self.options.includefuzzy and unit.isfuzzy():
     65              return []
     66          if not self.options.includereview and unit.isreview():
     67              return []
     68          failures = self.checker.run_filters(unit)
     69          if failures and self.options.autocorrect:
     70              # we can't get away with bad unquoting / requoting if we're going to change the result...
     71              correction = autocorrect.correct(unit.source, unit.target)
     72              if correction:
     73                  unit.target = correction
     74                  return autocorrect
     75              else:
     76                  # ignore failures we can't correct when in autocorrect mode
     77                  return []
     78          return failures
     79
     80 -    def filterfile(self, transfile):
     81          """Runs filters on a translation store object.
     82          Parameters:
     83              - transfile. A translation store object.
     84          Return value:
     85              - A new translation store object with the results of the filter included."""
     86          newtransfile = type(transfile)()
     87          newtransfile.setsourcelanguage(transfile.sourcelanguage)
     88          newtransfile.settargetlanguage(transfile.targetlanguage)
     89          for unit in transfile.units:
     90              filterresult = self.filterunit(unit)
     91              if filterresult:
     92                  if filterresult != autocorrect:
     93                      for filtername, filtermessage in filterresult.iteritems():
     94                          if self.options.addnotes:
     95                              unit.adderror(filtername, filtermessage)
     96                          if isinstance(filtermessage, checks.SeriousFilterFailure):
     97                              unit.markfuzzy()
     98                  newtransfile.addunit(unit)
     99          if isinstance(newtransfile, poheader):
    100              newtransfile.updateheader(add=True, **transfile.parseheader())
    101          return newtransfile
    102
    103 -class FilterOptionParser(optrecurse.RecursiveOptionParser):
    104      """a specialized Option Parser for filter tools..."""
    105 -    def __init__(self, formats):
    106          """construct the specialized Option Parser"""
    107          optrecurse.RecursiveOptionParser.__init__(self, formats)
    108          self.set_usage()
    109          self.add_option("-l", "--listfilters", action="callback", dest='listfilters',
    110              default=False, callback_kwargs={'dest_value': True},
    111              callback=self.parse_noinput, help="list filters available")
    112
    113 -    def parse_noinput(self, option, opt, value, parser, *args, **kwargs):
    114          """this sets an option to true, but also sets input to - to prevent an error"""
    115          setattr(parser.values, option.dest, kwargs['dest_value'])
    116          parser.values.input = "-"
    117
    118 -    def run(self):
    119          """parses the arguments, and runs recursiveprocess with the resulting options"""
    120          (options, args) = self.parse_args()
    121          if options.filterclass is None:
    122              checkerclasses = [checks.StandardChecker, checks.StandardUnitChecker]
    123          else:
    124              checkerclasses = [options.filterclass, checks.StandardUnitChecker]
    125          checkerconfig = checks.CheckerConfig(targetlanguage=options.targetlanguage)
    126          if options.notranslatefile:
    127              options.notranslatefile = os.path.expanduser(options.notranslatefile)
    128              if not os.path.exists(options.notranslatefile):
    129                  self.error("notranslatefile %r does not exist" % options.notranslatefile)
    130              notranslatewords = [line.strip() for line in open(options.notranslatefile).readlines()]
    131              notranslatewords = dict.fromkeys([key for key in notranslatewords])
    132              checkerconfig.notranslatewords.update(notranslatewords)
    133          if options.musttranslatefile:
    134              options.musttranslatefile = os.path.expanduser(options.musttranslatefile)
    135              if not os.path.exists(options.musttranslatefile):
    136                  self.error("musttranslatefile %r does not exist" % options.musttranslatefile)
    137              musttranslatewords = [line.strip() for line in open(options.musttranslatefile).readlines()]
    138              musttranslatewords = dict.fromkeys([key for key in musttranslatewords])
    139              checkerconfig.musttranslatewords.update(musttranslatewords)
    140          if options.validcharsfile:
    141              options.validcharsfile = os.path.expanduser(options.validcharsfile)
    142              if not os.path.exists(options.validcharsfile):
    143                  self.error("validcharsfile %r does not exist" % options.validcharsfile)
    144              validchars = open(options.validcharsfile).read()
    145              checkerconfig.updatevalidchars(validchars)
    146          options.checkfilter = pocheckfilter(options, checkerclasses, checkerconfig)
    147          if not options.checkfilter.checker.combinedfilters:
    148              self.error("No valid filters were specified")
    149          options.inputformats = self.inputformats
    150          options.outputoptions = self.outputoptions
    151          self.usepsyco(options)
    152          if options.listfilters:
    153              print options.checkfilter.getfilterdocs()
    154          else:
    155              self.recursiveprocess(options)
    156
    157 -def runfilter(inputfile, outputfile, templatefile, checkfilter=None):
    158      """reads in inputfile, filters using checkfilter, writes to outputfile"""
    159      fromfile = factory.getobject(inputfile)
    160      tofile = checkfilter.filterfile(fromfile)
    161      if tofile.isempty():
    162          return 0
    163      outputfile.write(str(tofile))
    164      return 1
    165
    166 -def cmdlineparser():
    167      formats = {"po":("po", runfilter), "pot":("pot", runfilter),
    168              "xliff":("xliff", runfilter), "xlf":("xlf", runfilter),
    169              "tmx":("tmx", runfilter),
    170              None:("po", runfilter)}
    171
    172      parser = FilterOptionParser(formats)
    173      parser.add_option("", "--review", dest="includereview",
    174          action="store_true", default=True,
    175          help="include units marked for review (default)")
    176      parser.add_option("", "--noreview", dest="includereview",
    177          action="store_false", default=True,
    178          help="exclude units marked for review")
    179      parser.add_option("", "--fuzzy", dest="includefuzzy",
    180          action="store_true", default=True,
    181          help="include units marked fuzzy (default)")
    182      parser.add_option("", "--nofuzzy", dest="includefuzzy",
    183          action="store_false", default=True,
    184          help="exclude units marked fuzzy")
    185      parser.add_option("", "--nonotes", dest="addnotes",
    186          action="store_false", default=True,
    187          help="don't add notes about the errors")
    188      parser.add_option("", "--autocorrect", dest="autocorrect",
    189          action="store_true", default=False,
    190          help="output automatic corrections where possible rather than describing issues")
    191      parser.add_option("", "--language", dest="targetlanguage", default=None,
    192          help="set target language code (e.g. af-ZA) [required for spell check and recommended in general]", metavar="LANG")
    193      parser.add_option("", "--openoffice", dest="filterclass",
    194          action="store_const", default=None, const=checks.OpenOfficeChecker,
    195          help="use the standard checks for OpenOffice translations")
    196      parser.add_option("", "--mozilla", dest="filterclass",
    197          action="store_const", default=None, const=checks.MozillaChecker,
    198          help="use the standard checks for Mozilla translations")
    199      parser.add_option("", "--drupal", dest="filterclass",
    200          action="store_const", default=None, const=checks.DrupalChecker,
    201          help="use the standard checks for Drupal translations")
    202      parser.add_option("", "--gnome", dest="filterclass",
    203          action="store_const", default=None, const=checks.GnomeChecker,
    204          help="use the standard checks for Gnome translations")
    205      parser.add_option("", "--kde", dest="filterclass",
    206          action="store_const", default=None, const=checks.KdeChecker,
    207          help="use the standard checks for KDE translations")
    208      parser.add_option("", "--wx", dest="filterclass",
    209          action="store_const", default=None, const=checks.KdeChecker,
    210          help="use the standard checks for wxWidgets translations")
    211      parser.add_option("", "--excludefilter", dest="excludefilters",
    212          action="append", default=[], type="string", metavar="FILTER",
    213          help="don't use FILTER when filtering")
    214      parser.add_option("-t", "--test", dest="limitfilters",
    215          action="append", default=None, type="string", metavar="FILTER",
    216          help="only use test FILTERs specified with this option when filtering")
    217      parser.add_option("", "--notranslatefile", dest="notranslatefile",
    218          default=None, type="string", metavar="FILE",
    219          help="read list of untranslatable words from FILE (must not be translated)")
    220      parser.add_option("", "--musttranslatefile", dest="musttranslatefile",
    221          default=None, type="string", metavar="FILE",
    222          help="read list of translatable words from FILE (must be translated)")
    223      parser.add_option("", "--validcharsfile", dest="validcharsfile",
    224          default=None, type="string", metavar="FILE",
    225          help="read list of all valid characters from FILE (must be in UTF-8)")
    226      parser.passthrough.append('checkfilter')
    227      parser.description = __doc__
    228      return parser
    229
    230 -def main():
    231      parser = cmdlineparser()
    232      parser.run()
    233
    234  if __name__ == '__main__':
    235      main()
    236