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