Package translate :: Package storage :: Module properties

[hide private]
[frames] | no frames]

# Source Code for Module translate.storage.properties

      1  #!/usr/bin/env python
      2  # -*- coding: utf-8 -*-
      3  #
      4  # Copyright 2004-2006 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  """classes that hold units of .properties files (propunit) or entire files
     23  (propfile) these files are used in translating Mozilla and other software
     24
     25  @note: The following {.properties file
     26  description<http://java.sun.com/j2se/1.4.2/docs/api/java/util/Properties.html#load(java.io.Reader)>}
     27  and {example <http://www.exampledepot.com/egs/java.util/Props.html>} give some
     28  good references to the .properties specification.  A simple summary of what is
     29  permissible follows.
     30
     31  # a comment
     32  ! a comment
     33
     34  a = a string
     35  b = a string with escape sequences \t \n \r \\ \" \' \ (space) \u0123
     36  c = a string with a continuation line \
     37      continuation line
     38  d.e.f = another string
     39
     40  """
     41
     42  from translate.storage import base
     43  from translate.misc import quote
     44  import re
     45
     46  # the rstripeols convert dos <-> unix nicely as well
     47  # output will be appropriate for the platform
     48
     49  eol = "\n"
     50
     51 -class propunit(base.TranslationUnit):
     52      """an element of a properties file i.e. a name and value, and any comments
     53      associated"""
     54 -    def __init__(self, source=""):
     55          """construct a blank propunit"""
     56          super(propunit, self).__init__(source)
     57          self.name = ""
     58          self.value = ""
     59          self.comments = []
     60          self.source = source
     61
     62 -    def setsource(self, source):
     63          """Sets the source AND the target to be equal"""
     64          self.value = quote.mozillapropertiesencode(source or "")
     65
     66 -    def getsource(self):
     67          value = quote.mozillapropertiesdecode(self.value)
     68          value = value.lstrip(" ")
     69          rstriped = value.rstrip(" ")
     70          if rstriped and rstriped[-1] != "\\":
     71              value = rstriped
     72
     73          value = re.sub("\\\\ ", " ", value)
     74          return value
     75
     76      source = property(getsource, setsource)
     77
     78 -    def settarget(self, target):
     79          """Note: this also sets the .source attribute!"""
     80          # TODO: shouldn't this just call the .source property? no quoting done here...
     81          self.source = target
     82
     83 -    def gettarget(self):
     84          return self.source
     85      target = property(gettarget, settarget)
     86
     87 -    def __str__(self):
     88          """convert to a string. double check that unicode is handled somehow here"""
     89          source = self.getoutput()
     90          if isinstance(source, unicode):
     91              return source.encode(getattr(self, "encoding", "UTF-8"))
     92          return source
     93
     94 -    def getoutput(self):
     95          """convert the element back into formatted lines for a .properties file"""
     96          if self.isblank():
     97              return "".join(self.comments + ["\n"])
     98          else:
     99              if "\\u" in self.value:
    100                  self.value = quote.mozillapropertiesencode(quote.mozillapropertiesdecode(self.value))
    101              return "".join(self.comments + ["%s=%s\n" % (self.name, self.value)])
    102
    103 -    def getlocations(self):
    104          return [self.name]
    105
    106 -    def addnote(self, note, origin=None):
    107          self.comments.append(note)
    108
    109 -    def getnotes(self, origin=None):
    110          return '\n'.join(self.comments)
    111
    112 -    def removenotes(self):
    113          self.comments = []
    114
    115 -    def isblank(self):
    116          """returns whether this is a blank element, containing only comments..."""
    117          return not (self.name or self.value)
    118
    119 -class propfile(base.TranslationStore):
    120      """this class represents a .properties file, made up of propunits"""
    121      UnitClass = propunit
    122 -    def __init__(self, inputfile=None):
    123          """construct a propfile, optionally reading in from inputfile"""
    124          super(propfile, self).__init__(unitclass = self.UnitClass)
    125          self.filename = getattr(inputfile, 'name', '')
    126          if inputfile is not None:
    127              propsrc = inputfile.read()
    128              inputfile.close()
    129              self.parse(propsrc)
    130
    131 -    def parse(self, propsrc):
    132          """read the source of a properties file in and include them as units"""
    133          newunit = propunit()
    134          inmultilinevalue = False
    135          for line in propsrc.split("\n"):
    136              # handle multiline value if we're in one
    137              line = quote.rstripeol(line)
    138              if inmultilinevalue:
    139                  newunit.value += line.lstrip()
    140                  # see if there's more
    141                  inmultilinevalue = (newunit.value[-1:] == '\\')
    142                  # if we're still waiting for more...
    143                  if inmultilinevalue:
    144                      # strip the backslash
    145                      newunit.value = newunit.value[:-1]
    146                  if not inmultilinevalue:
    147                      # we're finished, add it to the list...
    148                      self.addunit(newunit)
    149                      newunit = propunit()
    150              # otherwise, this could be a comment
    151              elif line.strip()[:1] == '#':
    152                  # add a comment
    153                  line = quote.escapecontrols(line)
    154                  newunit.comments.append(line+"\n")
    155              elif not line.strip():
    156                  # this is a blank line...
    157                  if str(newunit).strip():
    158                      self.addunit(newunit)
    159                      newunit = propunit()
    160              else:
    161                  equalspos = line.find('=')
    162                  # if no equals, just ignore it
    163                  if equalspos == -1:
    164                      continue
    165                  # otherwise, this is a definition
    166                  else:
    167                      newunit.name = line[:equalspos].strip()
    168                      newunit.value = line[equalspos+1:].lstrip()
    169                      # backslash at end means carry string on to next line
    170                      if newunit.value[-1:] == '\\':
    171                          inmultilinevalue = True
    172                          newunit.value = newunit.value[:-1]
    173                      else:
    174                          self.addunit(newunit)
    175                          newunit = propunit()
    176          # see if there is a leftover one...
    177          if inmultilinevalue or len(newunit.comments) > 0:
    178              self.addunit(newunit)
    179
    180 -    def __str__(self):
    181          """convert the units back to lines"""
    182          lines = []
    183          for unit in self.units:
    184              lines.append(str(unit))
    185          return "".join(lines)
    186
    187  if __name__ == '__main__':
    188      import sys
    189      pf = propfile(sys.stdin)
    190      sys.stdout.write(str(pf))
    191