Package translate :: Package storage :: Module ical

[hide private]
[frames] | no frames]

# Source Code for Module translate.storage.ical

      1  #!/usr/bin/env python
      2  # -*- coding: utf-8 -*-
      3  #
      4  # Copyright 2007-2008 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  """Class that manages iCalender files for translation
     23
     24     Implementation
     25     ==============
     26     iCalendar files follow the U{RFC2445<http://tools.ietf.org/html/rfc2445>}
     27     specification.
     28
     29     The iCalendar specification uses the following naming conventions:
     30       - Component: an event, journal entry, timezone, etc
     31       - Property: a property of a component: summary, description, start time, etc
     32       - Attribute: an attribute of a property, e.g. language
     33
     34     The following are localisable in this implementation:
     35       - VEVENT component: SUMMARY, DESCRIPTION, COMMENT and LOCATION properties
     36
     37     While other items could be localised this is not seen as important until use
     38     cases arise.  In such a case simply adjusting the component.name and
     39     property.name lists to include these will allow expanded localisation.
     40
     41     LANGUAGE Attribute
     42     ------------------
     43     While the iCalendar format allows items to have a language attribute this is
     44     not used. The reason being that for most of the items that we localise they
     45     are only allowed to occur zero or once.  Thus 'summary' would ideally
     46     be present in multiple languages in one file, the format does not allow
     47     such multiple entries.  This is unfortunate as it prevents the creation
     48     of a single multilingual iCalendar file.
     49
     50     Future Format Support
     51     =====================
     52     As this format used U{vobject<http://vobject.skyhouseconsulting.com/>} which
     53     supports various formats including U{vCard<http://en.wikipedia.org/wiki/VCard>}
     54     it is possible to expand this format to understand those if needed.
     55
     56  """
     57  import re
     58  from StringIO import StringIO
     59
     60  import vobject
     61
     62  from translate.storage import base
     63
     64
     65 -class icalunit(base.TranslationUnit):
     66      """An ical entry that is translatable"""
     67
     68 -    def __init__(self, source=None, encoding="UTF-8"):
     69          self.location = ""
     70          if source:
     71              self.source = source
     72          super(icalunit, self).__init__(source)
     73
     74 -    def addlocation(self, location):
     75          self.location = location
     76
     77 -    def getlocations(self):
     78          return [self.location]
     79
     80
     81 -class icalfile(base.TranslationStore):
     82      """An ical file"""
     83      UnitClass = icalunit
     84
     85 -    def __init__(self, inputfile=None, unitclass=icalunit):
     86          """construct an ical file, optionally reading in from inputfile."""
     87          self.UnitClass = unitclass
     88          base.TranslationStore.__init__(self, unitclass=unitclass)
     89          self.units = []
     90          self.filename = ''
     91          self._icalfile = None
     92          if inputfile is not None:
     93              self.parse(inputfile)
     94
     95 -    def __str__(self):
     96          _outicalfile = self._icalfile
     97          for unit in self.units:
     98              for location in unit.getlocations():
     99                  match = re.match('\\[(?P<uid>.+)\\](?P<property>.+)', location)
    100                  for component in self._icalfile.components():
    101                      if component.name != "VEVENT":
    102                          continue
    103                      if component.uid.value != match.groupdict()['uid']:
    104                          continue
    105                      for property in component.getChildren():
    106                          if property.name == match.groupdict()['property']:
    107                              property.value = unit.target
    108
    109          if _outicalfile:
    110              return str(_outicalfile.serialize())
    111          else:
    112              return ""
    113
    114 -    def parse(self, input):
    115          """parse the given file or file source string"""
    116          if hasattr(input, 'name'):
    117              self.filename = input.name
    118          elif not getattr(self, 'filename', ''):
    119              self.filename = ''
    120          if hasattr(input, "read"):
    121              inisrc = input.read()
    122              input.close()
    123              input = inisrc
    124          if isinstance(input, str):
    125              input = StringIO(input)
    126              self._icalfile = vobject.readComponents(input).next()
    127          else:
    128              self._icalfile = vobject.readComponents(open(input)).next()
    129          for component in self._icalfile.components():
    130              if component.name == "VEVENT":
    131                  for property in component.getChildren():
    132                      if property.name in ('SUMMARY', 'DESCRIPTION', 'COMMENT', 'LOCATION'):
    133                          newunit = self.addsourceunit(property.value)
    134                          newunit.addnote("Start date: %s" % component.dtstart.value)
    135                          newunit.addlocation("[%s]%s" % (component.uid.value, property.name))
    136