translate.storage.pocommon

Package translate :: Package storage :: Module pocommon |
[hide private]
[frames] | no frames]

# Source Code for Module translate.storage.pocommon

      1  #!/usr/bin/env python
      2  # -*- coding: utf-8 -*-
      3  #
      4  # Copyright 2002-2011 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  import re
     23  import urllib
     24
     25  from translate.storage import base
     26  from translate.storage import poheader
     27  from translate.storage.workflow import StateEnum as state
     28
     29  msgid_comment_re = re.compile("_: (.*?)\n")
     30
     31
     32 -def extract_msgid_comment(text):
     33      """The one definitive way to extract a msgid comment out of an unescaped
     34      unicode string that might contain it.
     35
     36      @rtype: unicode"""
     37      msgidcomment = msgid_comment_re.match(text)
     38      if msgidcomment:
     39          return msgidcomment.group(1)
     40      return u""
     41
     42
     43 -def quote_plus(text):
     44      """Quote the query fragment of a URL; replacing ' ' with '+'"""
     45      return urllib.quote_plus(text.encode("utf-8"))
     46
     47
     48 -def unquote_plus(text):
     49      """unquote('%7e/abc+def') -> '~/abc def'"""
     50      return urllib.unquote_plus(text).decode('utf-8')
     51
     52
     53 -class pounit(base.TranslationUnit):
     54      S_FUZZY_OBSOLETE = state.OBSOLETE-1
     55      S_OBSOLETE = state.OBSOLETE
     56      S_UNTRANSLATED = state.EMPTY
     57      S_FUZZY = state.NEEDS_WORK
     58      S_TRANSLATED = state.UNREVIEWED
     59
     60      STATE = {
     61          S_FUZZY_OBSOLETE: (S_FUZZY_OBSOLETE, state.OBSOLETE),
     62          S_OBSOLETE: (state.OBSOLETE, state.EMPTY),
     63          S_UNTRANSLATED: (state.EMPTY, state.NEEDS_WORK),
     64          S_FUZZY: (state.NEEDS_WORK, state.UNREVIEWED),
     65          S_TRANSLATED: (state.UNREVIEWED, state.MAX),
     66      }
     67
     68 -    def adderror(self, errorname, errortext):
     69          """Adds an error message to this unit."""
     70          text = u'(pofilter) %s: %s' % (errorname, errortext)
     71          # Don't add the same error twice:
     72          if text not in self.getnotes(origin='translator'):
     73              self.addnote(text, origin="translator")
     74
     75 -    def geterrors(self):
     76          """Get all error messages."""
     77          notes = self.getnotes(origin="translator").split('\n')
     78          errordict = {}
     79          for note in notes:
     80              if '(pofilter) ' in note:
     81                  error = note.replace('(pofilter) ', '')
     82                  errorname, errortext = error.split(': ', 1)
     83                  errordict[errorname] = errortext
     84          return errordict
     85
     86 -    def markreviewneeded(self, needsreview=True, explanation=None):
     87          """Marks the unit to indicate whether it needs review. Adds an optional explanation as a note."""
     88          if needsreview:
     89              reviewnote = "(review)"
     90              if explanation:
     91                  reviewnote += " " + explanation
     92              self.addnote(reviewnote, origin="translator")
     93          else:
     94              # Strip (review) notes.
     95              notestring = self.getnotes(origin="translator")
     96              notes = notestring.split('\n')
     97              newnotes = []
     98              for note in notes:
     99                  if not '(review)' in note:
    100                      newnotes.append(note)
    101              newnotes = '\n'.join(newnotes)
    102              self.removenotes()
    103              self.addnote(newnotes, origin="translator")
    104
    105 -    def istranslated(self):
    106          return super(pounit, self).istranslated() and not self.isobsolete() and not self.isheader()
    107
    108 -    def istranslatable(self):
    109          return not (self.isheader() or self.isblank() or self.isobsolete())
    110
    111 -    def hasmarkedcomment(self, commentmarker):
    112          raise NotImplementedError
    113
    114 -    def isreview(self):
    115          return self.hasmarkedcomment("review") or self.hasmarkedcomment("pofilter")
    116
    117 -    def isobsolete(self):
    118          return self.STATE[self.S_FUZZY_OBSOLETE][0] <= self.get_state_n() < self.STATE[self.S_OBSOLETE][1]
    119
    120 -    def isfuzzy(self):
    121          # implementation specific fuzzy detection, must not use get_state_n()
    122          raise NotImplementedError()
    123
    124 -    def markfuzzy(self, present=True):
    125          if present:
    126              self.set_state_n(self.STATE[self.S_FUZZY][0])
    127          else:
    128              self.set_state_n(self.STATE[self.S_TRANSLATED][0])
    129          # set_state_n will check if target exists
    130
    131 -    def makeobsolete(self):
    132          if self.isfuzzy():
    133              self.set_state_n(self.STATE[self.S_FUZZY_OBSOLETE][0])
    134          else:
    135              self.set_state_n(self.STATE[self.S_OBSOLETE][0])
    136
    137 -    def resurrect(self):
    138          self.set_state_n(self.STATE[self.S_TRANSLATED][0])
    139          if not self.gettarget():
    140              self.set_state_n(self.STATE[self.S_UNTRANSLATED][0])
    141
    142 -    def _domarkfuzzy(self, present=True):
    143          raise NotImplementedError()
    144
    145 -    def get_state_n(self):
    146          value = super(pounit, self).get_state_n()
    147          if value <= self.S_OBSOLETE:
    148              return value
    149          if self.target:
    150              if self.isfuzzy():
    151                  return self.S_FUZZY
    152              else:
    153                  return self.S_TRANSLATED
    154          else:
    155              return self.S_UNTRANSLATED
    156
    157 -    def set_state_n(self, value):
    158          super(pounit, self).set_state_n(value)
    159          has_target = False
    160          if self.hasplural():
    161              for string in self.target.strings:
    162                  if string:
    163                      has_target = True
    164                      break
    165          else:
    166              has_target = bool(self.target)
    167          if has_target:
    168              isfuzzy = self.STATE[self.S_FUZZY][0] <= value < self.STATE[self.S_FUZZY][1] or \
    169                      self.STATE[self.S_FUZZY_OBSOLETE][0] <= value < self.STATE[self.S_FUZZY_OBSOLETE][1]
    170              self._domarkfuzzy(isfuzzy) # Implementation specific fuzzy-marking
    171          else:
    172              super(pounit, self).set_state_n(self.S_UNTRANSLATED)
    173              self._domarkfuzzy(False)
    174
    175
    176 -def encodingToUse(encoding):
    177      """Tests whether the given encoding is known in the python runtime, or returns utf-8.
    178      This function is used to ensure that a valid encoding is always used."""
    179      if encoding == "CHARSET" or encoding == None:
    180          return 'utf-8'
    181      return encoding
    182  #    if encoding is None: return False
    183  #    return True
    184  #    try:
    185  #        tuple = codecs.lookup(encoding)
    186  #    except LookupError:
    187  #        return False
    188  #    return True
    189
    190
    191 -class pofile(poheader.poheader, base.TranslationStore):
    192      Name = _("Gettext PO file") # pylint: disable-msg=E0602
    193      Mimetypes = ["text/x-gettext-catalog", "text/x-gettext-translation", "text/x-po", "text/x-pot"]
    194      Extensions = ["po", "pot"]
    195      # We don't want windows line endings on Windows:
    196      _binary = True
    197
    198 -    def __init__(self, inputfile=None, encoding=None):
    199          super(pofile, self).__init__(unitclass=self.UnitClass)
    200          self.units = []
    201          self.filename = ''
    202          self._encoding = encodingToUse(encoding)
    203          if inputfile is not None:
    204              self.parse(inputfile)
    205          else:
    206              self.init_headers()
    207