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(): return []
     63          if not self.options.includefuzzy and unit.isfuzzy(): return []
     64          if not self.options.includereview and unit.isreview(): return []
     65          failures = self.checker.run_filters(unit)
     66          if failures and self.options.autocorrect:
     67              # we can't get away with bad unquoting / requoting if we're going to change the result...
     68              correction = autocorrect.correct(unit.source, unit.target)
     69              if correction:
     70                  unit.target = correction
     71                  return autocorrect
     72              else:
     73                  # ignore failures we can't correct when in autocorrect mode
     74                  return []
     75          return failures
     76
     77 -    def filterfile(self, transfile):
     78          """Runs filters on a translation store object.
     79          Parameters:
     80              - transfile. A translation store object.
     81          Return value:
     82              - A new translation store object with the results of the filter included."""
     83          newtransfile = type(transfile)()
     84          newtransfile.setsourcelanguage(transfile.sourcelanguage)
     85          newtransfile.settargetlanguage(transfile.targetlanguage)
     86          for unit in transfile.units:
     87              filterresult = self.filterunit(unit)
     88              if filterresult:
     89                  if filterresult != autocorrect:
     90                      for filtername, filtermessage in filterresult.iteritems():
     91                          if self.options.addnotes:
     92                              unit.adderror(filtername, filtermessage)
     93                          if isinstance(filtermessage, checks.SeriousFilterFailure):
     94                              unit.markfuzzy()
     95                  newtransfile.addunit(unit)
     96          if isinstance(newtransfile, poheader):
     97              newtransfile.updateheader(add=True, **transfile.parseheader())
     98          return newtransfile
     99
    100 -class FilterOptionParser(optrecurse.RecursiveOptionParser):
    101      """a specialized Option Parser for filter tools..."""
    102 -    def __init__(self, formats):
    103          """construct the specialized Option Parser"""
    104          optrecurse.RecursiveOptionParser.__init__(self, formats)
    105          self.set_usage()
    106          self.add_option("-l", "--listfilters", action="callback", dest='listfilters',
    107              default=False, callback_kwargs={'dest_value': True},
    108              callback=self.parse_noinput, help="list filters available")
    109
    110 -    def parse_noinput(self, option, opt, value, parser, *args, **kwargs):
    111          """this sets an option to true, but also sets input to - to prevent an error"""
    112          setattr(parser.values, option.dest, kwargs['dest_value'])
    113          parser.values.input = "-"
    114
    115 -    def run(self):
    116          """parses the arguments, and runs recursiveprocess with the resulting options"""
    117          (options, args) = self.parse_args()
    118          if options.filterclass is None:
    119              checkerclasses = [checks.StandardChecker, checks.StandardUnitChecker]
    120          else:
    121              checkerclasses = [options.filterclass, checks.StandardUnitChecker]
    122          checkerconfig = checks.CheckerConfig(targetlanguage=options.targetlanguage)
    123          if options.notranslatefile:
    124              options.notranslatefile = os.path.expanduser(options.notranslatefile)
    125              if not os.path.exists(options.notranslatefile):
    126                  self.error("notranslatefile %r does not exist" % options.notranslatefile)
    127              notranslatewords = [line.strip() for line in open(options.notranslatefile).readlines()]
    128              notranslatewords = dict.fromkeys([key for key in notranslatewords])
    129              checkerconfig.notranslatewords.update(notranslatewords)
    130          if options.musttranslatefile:
    131              options.musttranslatefile = os.path.expanduser(options.musttranslatefile)
    132              if not os.path.exists(options.musttranslatefile):
    133                  self.error("musttranslatefile %r does not exist" % options.musttranslatefile)
    134              musttranslatewords = [line.strip() for line in open(options.musttranslatefile).readlines()]
    135              musttranslatewords = dict.fromkeys([key for key in musttranslatewords])
    136              checkerconfig.musttranslatewords.update(musttranslatewords)
    137          if options.validcharsfile:
    138              options.validcharsfile = os.path.expanduser(options.validcharsfile)
    139              if not os.path.exists(options.validcharsfile):
    140                  self.error("validcharsfile %r does not exist" % options.validcharsfile)
    141              validchars = open(options.validcharsfile).read()
    142              checkerconfig.updatevalidchars(validchars)
    143          options.checkfilter = pocheckfilter(options, checkerclasses, checkerconfig)
    144          if not options.checkfilter.checker.combinedfilters:
    145              self.error("No valid filters were specified")
    146          options.inputformats = self.inputformats
    147          options.outputoptions = self.outputoptions
    148          self.usepsyco(options)
    149          if options.listfilters:
    150              print options.checkfilter.getfilterdocs()
    151          else:
    152              self.recursiveprocess(options)
    153
    154 -def runfilter(inputfile, outputfile, templatefile, checkfilter=None):
    155      """reads in inputfile, filters using checkfilter, writes to outputfile"""
    156      fromfile = factory.getobject(inputfile)
    157      tofile = checkfilter.filterfile(fromfile)
    158      if tofile.isempty():
    159          return 0
    160      outputfile.write(str(tofile))
    161      return 1
    162
    163 -def cmdlineparser():
    164      formats = {"po":("po", runfilter), "pot":("pot", runfilter),
    165              "xliff":("xliff", runfilter), "xlf":("xlf", runfilter),
    166              "tmx":("tmx", runfilter),
    167              None:("po", runfilter)}
    168
    169      parser = FilterOptionParser(formats)
    170      parser.add_option("", "--review", dest="includereview",
    171          action="store_true", default=True,
    172          help="include units marked for review (default)")
    173      parser.add_option("", "--noreview", dest="includereview",
    174          action="store_false", default=True,
    175          help="exclude units marked for review")
    176      parser.add_option("", "--fuzzy", dest="includefuzzy",
    177          action="store_true", default=True,
    178          help="include units marked fuzzy (default)")
    179      parser.add_option("", "--nofuzzy", dest="includefuzzy",
    180          action="store_false", default=True,
    181          help="exclude units marked fuzzy")
    182      parser.add_option("", "--nonotes", dest="addnotes",
    183          action="store_false", default=True,
    184          help="don't add notes about the errors")
    185      parser.add_option("", "--autocorrect", dest="autocorrect",
    186          action="store_true", default=False,
    187          help="output automatic corrections where possible rather than describing issues")
    188      parser.add_option("", "--language", dest="targetlanguage", default=None,
    189          help="set target language code (e.g. af-ZA) [required for spell check and recommended in general]", metavar="LANG")
    190      parser.add_option("", "--openoffice", dest="filterclass",
    191          action="store_const", default=None, const=checks.OpenOfficeChecker,
    192          help="use the standard checks for OpenOffice translations")
    193      parser.add_option("", "--mozilla", dest="filterclass",
    194          action="store_const", default=None, const=checks.MozillaChecker,
    195          help="use the standard checks for Mozilla translations")
    196      parser.add_option("", "--drupal", dest="filterclass",
    197          action="store_const", default=None, const=checks.DrupalChecker,
    198          help="use the standard checks for Drupal translations")
    199      parser.add_option("", "--gnome", dest="filterclass",
    200          action="store_const", default=None, const=checks.GnomeChecker,
    201          help="use the standard checks for Gnome translations")
    202      parser.add_option("", "--kde", dest="filterclass",
    203          action="store_const", default=None, const=checks.KdeChecker,
    204          help="use the standard checks for KDE translations")
    205      parser.add_option("", "--wx", dest="filterclass",
    206          action="store_const", default=None, const=checks.KdeChecker,
    207          help="use the standard checks for wxWidgets translations")
    208      parser.add_option("", "--excludefilter", dest="excludefilters",
    209          action="append", default=[], type="string", metavar="FILTER",
    210          help="don't use FILTER when filtering")
    211      parser.add_option("-t", "--test", dest="limitfilters",
    212          action="append", default=None, type="string", metavar="FILTER",
    213          help="only use test FILTERs specified with this option when filtering")
    214      parser.add_option("", "--notranslatefile", dest="notranslatefile",
    215          default=None, type="string", metavar="FILE",
    216          help="read list of untranslatable words from FILE (must not be translated)")
    217      parser.add_option("", "--musttranslatefile", dest="musttranslatefile",
    218          default=None, type="string", metavar="FILE",
    219          help="read list of translatable words from FILE (must be translated)")
    220      parser.add_option("", "--validcharsfile", dest="validcharsfile",
    221          default=None, type="string", metavar="FILE",
    222          help="read list of all valid characters from FILE (must be in UTF-8)")
    223      parser.passthrough.append('checkfilter')
    224      parser.description = __doc__
    225      return parser
    226
    227 -def main():
    228      parser = cmdlineparser()
    229      parser.run()
    230
    231  if __name__ == '__main__':
    232      main()
    233