1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15   
 16   
 17   
 18   
 19   
 20   
 21   
 22  """class that handles all header functions for a header in a po file""" 
 23   
 24  from translate.misc import dictutils 
 25  from translate import __version__ 
 26  import re 
 27  import time 
 28   
 29  author_re = re.compile(r".*<\S+@\S+>.*\d{4,4}") 
 30   
 32      """Parses an input string with the definition of a PO header and returns  
 33      the interpreted values as a dictionary""" 
 34      headervalues = dictutils.ordereddict() 
 35      for line in input.split("\n"): 
 36          if not line or ":" not in line: 
 37              continue 
 38          key, value = line.split(":", 1) 
 39           
 40          key = str(key.strip()) 
 41          headervalues[key] = value.strip() 
 42      return headervalues 
  43   
 44 -def update(existing, add=False, **kwargs): 
  75   
 76   
 78      """This class implements functionality for manipulation of po file headers. 
 79      This class is a mix-in class and useless on its own. It must be used from all 
 80      classes which represent a po file""" 
 81   
 82      x_generator = "Translate Toolkit %s" % __version__.ver 
 83   
 84      header_order = [ 
 85          "Project-Id-Version", 
 86          "Report-Msgid-Bugs-To", 
 87          "POT-Creation-Date", 
 88          "PO-Revision-Date", 
 89          "Last-Translator", 
 90          "Language-Team", 
 91          "MIME-Version", 
 92          "Content-Type", 
 93          "Content-Transfer-Encoding", 
 94          "Plural-Forms", 
 95          "X-Generator", 
 96          ] 
 97   
 99          """Returns the timezone as a string in the format [+-]0000, eg +0200.""" 
100          if time.daylight: 
101              tzoffset = time.altzone 
102          else: 
103              tzoffset = time.timezone 
104   
105          hours, minutes = time.gmtime(abs(tzoffset))[3:5] 
106          if tzoffset > 0: 
107              hours *= -1 
108          tz = str("%+d" % hours).zfill(3) + str(minutes).zfill(2) 
109          return tz 
 110   
111   
113          """create a header for the given filename. arguments are specially handled, kwargs added as key: value 
114          pot_creation_date can be None (current date) or a value (datetime or string) 
115          po_revision_date can be None (form), False (=pot_creation_date), True (=now), or a value (datetime or string) 
116   
117          @return: Dictionary with the header items 
118          @rtype: dict 
119          """ 
120          if project_id_version is None: 
121              project_id_version = "PACKAGE VERSION" 
122          if pot_creation_date is None or pot_creation_date == True: 
123              pot_creation_date = time.strftime("%Y-%m-%d %H:%M") + self.tzstring() 
124          if isinstance(pot_creation_date, time.struct_time): 
125              pot_creation_date = time.strftime("%Y-%m-%d %H:%M", pot_creation_date) + self.tzstring() 
126          if po_revision_date is None: 
127              po_revision_date = "YEAR-MO-DA HO:MI+ZONE" 
128          elif po_revision_date == False: 
129              po_revision_date = pot_creation_date 
130          elif po_revision_date == True: 
131              po_revision_date = time.strftime("%Y-%m-%d %H:%M") + self.tzstring() 
132          if isinstance(po_revision_date, time.struct_time): 
133              po_revision_date = time.strftime("%Y-%m-%d %H:%M", po_revision_date) + self.tzstring() 
134          if last_translator is None: 
135              last_translator = "FULL NAME <EMAIL@ADDRESS>" 
136          if language_team is None: 
137              language_team = "LANGUAGE <LL@li.org>" 
138          if mime_version is None: 
139              mime_version = "1.0" 
140          if report_msgid_bugs_to is None: 
141              report_msgid_bugs_to = "" 
142   
143          defaultargs = dictutils.ordereddict() 
144          defaultargs["Project-Id-Version"] = project_id_version 
145          defaultargs["Report-Msgid-Bugs-To"] = report_msgid_bugs_to 
146          defaultargs["POT-Creation-Date"] = pot_creation_date 
147          defaultargs["PO-Revision-Date"] = po_revision_date 
148          defaultargs["Last-Translator"] = last_translator 
149          defaultargs["Language-Team"] = language_team 
150          defaultargs["MIME-Version"] = mime_version 
151          defaultargs["Content-Type"] = "text/plain; charset=%s" % charset 
152          defaultargs["Content-Transfer-Encoding"] = encoding 
153          if plural_forms: 
154              defaultargs["Plural-Forms"] = plural_forms 
155          defaultargs["X-Generator"] = self.x_generator 
156   
157          return update(defaultargs, add=True, **kwargs) 
 158   
160          """Returns the header element, or None. Only the first element is allowed 
161          to be a header. Note that this could still return an empty header element, 
162          if present.""" 
163          if len(self.units) == 0: 
164              return None 
165          candidate = self.units[0] 
166          if candidate.isheader(): 
167              return candidate 
168          else: 
169              return None 
 170   
178   
196   
198          """returns the nplural and plural values from the header""" 
199          header = self.parseheader() 
200          pluralformvalue = header.get('Plural-Forms', None) 
201          if pluralformvalue is None: 
202              return None, None 
203          nplural = re.findall("nplurals=(.+?);", pluralformvalue) 
204          plural = re.findall("plural=(.+?);?$", pluralformvalue) 
205          if not nplural or nplural[0] == "INTEGER": 
206              nplural = None 
207          else: 
208              nplural = nplural[0] 
209          if not plural or plural[0] == "EXPRESSION": 
210              plural = None 
211          else: 
212              plural = plural[0] 
213          return nplural, plural 
 214   
220   
222          """Merges another header with this header. 
223           
224          This header is assumed to be the template. 
225           
226          @type otherstore: L{base.TranslationStore} 
227           
228          """ 
229   
230          newvalues = otherstore.parseheader() 
231          self.updateheader( 
232              Project_Id_Version = newvalues['Project-Id-Version'], 
233              PO_Revision_Date   = newvalues['PO-Revision-Date'], 
234              Last_Translator    = newvalues['Last-Translator'], 
235              Language_Team      = newvalues['Language-Team'], 
236              Plural_Forms       = newvalues['Plural-Forms'] 
237          ) 
 238   
240          """Add contribution comments 
241          """ 
242          header = self.header() 
243          if not header: 
244              return 
245          prelines = [] 
246          contriblines = [] 
247          postlines = [] 
248          contribexists = False 
249          incontrib = False 
250          outcontrib = False 
251          for line in header.getnotes("translator").split('\n'): 
252              line = line.strip() 
253              if line == u"FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.": 
254                  incontrib = True 
255                  continue 
256              if author_re.match(line): 
257                  incontrib = True 
258                  contriblines.append(line) 
259                  continue 
260              if line == "" and incontrib: 
261                  incontrib = False 
262                  outcontrib = True 
263              if incontrib: 
264                  contriblines.append(line) 
265              elif not outcontrib: 
266                  prelines.append(line) 
267              else: 
268                  postlines.append(line) 
269   
270          year = time.strftime("%Y") 
271          contribexists = False 
272          for line in contriblines: 
273              if name in line and (email is None or email in line): 
274                  contribexists = True 
275                  break 
276          if not contribexists: 
277               
278              if email: 
279                  contriblines.append("%s <%s>, %s" % (name, email, year)) 
280              else: 
281                  contriblines.append("%s, %s" % (name, year)) 
282   
283          header.removenotes() 
284          header.addnote("\n".join(prelines)) 
285          header.addnote("\n".join(contriblines)) 
286          header.addnote("\n".join(postlines)) 
  287