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