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  from translate.storage import base 
 58  from StringIO import StringIO 
 59  import re 
 60  import vobject 
 61   
 62   
63 -class icalunit(base.TranslationUnit):
64 """An ical entry that is translatable"""
65 - def __init__(self, source=None, encoding="UTF-8"):
66 self.location = "" 67 if source: 68 self.source = source 69 super(icalunit, self).__init__(source)
70
71 - def addlocation(self, location):
72 self.location = location
73
74 - def getlocations(self):
75 return [self.location]
76
77 -class icalfile(base.TranslationStore):
78 """An ical file""" 79 UnitClass = icalunit
80 - def __init__(self, inputfile=None, unitclass=icalunit):
81 """construct an ical file, optionally reading in from inputfile.""" 82 self.UnitClass = unitclass 83 base.TranslationStore.__init__(self, unitclass=unitclass) 84 self.units = [] 85 self.filename = '' 86 self._icalfile = None 87 if inputfile is not None: 88 self.parse(inputfile)
89
90 - def __str__(self):
91 _outicalfile = self._icalfile 92 for unit in self.units: 93 for location in unit.getlocations(): 94 match = re.match('\\[(?P<uid>.+)\\](?P<property>.+)', location) 95 for component in self._icalfile.components(): 96 if component.name != "VEVENT": 97 continue 98 if component.uid.value != match.groupdict()['uid']: 99 continue 100 for property in component.getChildren(): 101 if property.name == match.groupdict()['property']: 102 property.value = unit.target 103 104 if _outicalfile: 105 return str(_outicalfile.serialize()) 106 else: 107 return ""
108
109 - def parse(self, input):
110 """parse the given file or file source string""" 111 if hasattr(input, 'name'): 112 self.filename = input.name 113 elif not getattr(self, 'filename', ''): 114 self.filename = '' 115 if hasattr(input, "read"): 116 inisrc = input.read() 117 input.close() 118 input = inisrc 119 if isinstance(input, str): 120 input = StringIO(input) 121 self._icalfile = vobject.readComponents(input).next() 122 else: 123 self._icalfile = vobject.readComponents(open(input)).next() 124 for component in self._icalfile.components(): 125 if component.name == "VEVENT": 126 for property in component.getChildren(): 127 if property.name in ('SUMMARY', 'DESCRIPTION', 'COMMENT', 'LOCATION'): 128 newunit = self.addsourceunit(property.value) 129 newunit.addnote("Start date: %s" % component.dtstart.value) 130 newunit.addlocation("[%s]%s" % (component.uid.value, property.name))
131