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

# Source Code for Module translate.storage.csvl10n

      1  #!/usr/bin/env python
      2  # -*- coding: utf-8 -*-
      3  #
      4  # Copyright 2002-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 comma-separated values (.csv) files (csvunit)
     23  or entire files (csvfile) for use with localisation
     24  """
     25
     26  import csv
     27
     28  from translate.misc import sparse
     29  from translate.storage import base
     30
     31 -class SimpleDictReader:
     32 -    def __init__(self, fileobj, fieldnames):
     33          self.fieldnames = fieldnames
     34          self.contents = fileobj.read()
     35          self.parser = sparse.SimpleParser(defaulttokenlist=[",", "\n"], whitespacechars="\r")
     36          self.parser.stringescaping = 0
     37          self.parser.quotechars = '"'
     38          self.tokens = self.parser.tokenize(self.contents)
     39          self.tokenpos = 0
     40
     41 -    def __iter__(self):
     42          return self
     43
     44 -    def getvalue(self, value):
     45          """returns a value, evaluating strings as neccessary"""
     46          if (value.startswith("'") and value.endswith("'")) or (value.startswith('"') and value.endswith('"')):
     47              return sparse.stringeval(value)
     48          else:
     49              return value
     50
     51 -    def next(self):
     52          lentokens = len(self.tokens)
     53          while self.tokenpos < lentokens and self.tokens[self.tokenpos] == "\n":
     54              self.tokenpos += 1
     55          if self.tokenpos >= lentokens:
     56              raise StopIteration()
     57          thistokens = []
     58          while self.tokenpos < lentokens and self.tokens[self.tokenpos] != "\n":
     59              thistokens.append(self.tokens[self.tokenpos])
     60              self.tokenpos += 1
     61          while self.tokenpos < lentokens and self.tokens[self.tokenpos] == "\n":
     62              self.tokenpos += 1
     63          fields = []
     64          # patch together fields since we can have quotes inside a field
     65          currentfield = ''
     66          fieldparts = 0
     67          for token in thistokens:
     68              if token == ',':
     69                  # a field is only quoted if the whole thing is quoted
     70                  if fieldparts == 1:
     71                      currentfield = self.getvalue(currentfield)
     72                  fields.append(currentfield)
     73                  currentfield = ''
     74                  fieldparts = 0
     75              else:
     76                  currentfield += token
     77                  fieldparts += 1
     78          # things after the last comma...
     79          if fieldparts:
     80              if fieldparts == 1:
     81                  currentfield = self.getvalue(currentfield)
     82              fields.append(currentfield)
     83          values = {}
     84          for fieldnum in range(len(self.fieldnames)):
     85              if fieldnum >= len(fields):
     86                  values[self.fieldnames[fieldnum]] = ""
     87              else:
     88                  values[self.fieldnames[fieldnum]] = fields[fieldnum]
     89          return values
     90
     91 -class csvunit(base.TranslationUnit):
     92      spreadsheetescapes = [("+", "\\+"), ("-", "\\-"), ("=", "\\="), ("'", "\\'")]
     93 -    def __init__(self, source=None):
     94          super(csvunit, self).__init__(source)
     95          self.comment = ""
     96          self.source = source
     97          self.target = ""
     98
     99 -    def add_spreadsheet_escapes(self, source, target):
    100          """add common spreadsheet escapes to two strings"""
    101          for unescaped, escaped in self.spreadsheetescapes:
    102              if source.startswith(unescaped):
    103                  source = source.replace(unescaped, escaped, 1)
    104              if target.startswith(unescaped):
    105                  target = target.replace(unescaped, escaped, 1)
    106          return source, target
    107
    108 -    def remove_spreadsheet_escapes(self, source, target):
    109          """remove common spreadsheet escapes from two strings"""
    110          for unescaped, escaped in self.spreadsheetescapes:
    111              if source.startswith(escaped):
    112                  source = source.replace(escaped, unescaped, 1)
    113              if target.startswith(escaped):
    114                  target = target.replace(escaped, unescaped, 1)
    115          return source, target
    116
    117 -    def fromdict(self, cedict):
    118          self.comment = cedict.get('location', '').decode('utf-8')
    119          self.source = cedict.get('source', '').decode('utf-8')
    120          self.target = cedict.get('target', '').decode('utf-8')
    121          if self.comment is None:
    122              self.comment = ''
    123          if self.source is None:
    124              self.source = ''
    125          if self.target is None:
    126              self.target = ''
    127          self.source, self.target = self.remove_spreadsheet_escapes(self.source, self.target)
    128
    129 -    def todict(self, encoding='utf-8'):
    130          comment, source, target = self.comment, self.source, self.target
    131          source, target = self.add_spreadsheet_escapes(source, target)
    132          if isinstance(comment, unicode):
    133              comment = comment.encode(encoding)
    134          if isinstance(source, unicode):
    135              source = source.encode(encoding)
    136          if isinstance(target, unicode):
    137              target = target.encode(encoding)
    138          return {'location':comment, 'source': source, 'target': target}
    139
    140 -class csvfile(base.TranslationStore):
    141      """This class represents a .csv file with various lines.
    142      The default format contains three columns: location, source, target"""
    143      UnitClass = csvunit
    144      Name = _("Comma Separated Value")
    145      Mimetypes  = ['text/comma-separated-values', 'text/csv']
    146      Extensions = ["csv"]
    147 -    def __init__(self, inputfile=None, fieldnames=None):
    148          base.TranslationStore.__init__(self, unitclass = self.UnitClass)
    149          self.units = []
    150          if fieldnames is None:
    151              self.fieldnames = ['location', 'source', 'target']
    152          else:
    153              if isinstance(fieldnames, basestring):
    154                  fieldnames = [fieldname.strip() for fieldname in fieldnames.split(",")]
    155              self.fieldnames = fieldnames
    156          self.filename = getattr(inputfile, 'name', '')
    157          if inputfile is not None:
    158              csvsrc = inputfile.read()
    159              inputfile.close()
    160              self.parse(csvsrc)
    161
    162 -    def parse(self, csvsrc):
    163          csvfile = csv.StringIO(csvsrc)
    164          reader = SimpleDictReader(csvfile, self.fieldnames)
    165          for row in reader:
    166              newce = self.UnitClass()
    167              newce.fromdict(row)
    168              self.addunit(newce)
    169
    170 -    def __str__(self):
    171          """convert to a string. double check that unicode is handled somehow here"""
    172          source = self.getoutput()
    173          if isinstance(source, unicode):
    174              return source.encode(getattr(self, "encoding", "UTF-8"))
    175          return source
    176
    177 -    def getoutput(self):
    178          csvfile = csv.StringIO()
    179          writer = csv.DictWriter(csvfile, self.fieldnames)
    180          for ce in self.units:
    181              cedict = ce.todict()
    182              writer.writerow(cedict)
    183          csvfile.reset()
    184          return "".join(csvfile.readlines())
    185