comparison babel/messages/catalog.py @ 108:8ea225f33f28

Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
author cmlenz
date Thu, 14 Jun 2007 09:49:00 +0000
parents 4b42e23644e5
children 7a5a7bf39d3d
comparison
equal deleted inserted replaced
107:4b42e23644e5 108:8ea225f33f28
12 # history and logs, available at http://babel.edgewall.org/log/. 12 # history and logs, available at http://babel.edgewall.org/log/.
13 13
14 """Data structures for message catalogs.""" 14 """Data structures for message catalogs."""
15 15
16 from datetime import datetime 16 from datetime import datetime
17 from email import message_from_string
17 import re 18 import re
18 try: 19 try:
19 set 20 set
20 except NameError: 21 except NameError:
21 from sets import Set as set 22 from sets import Set as set
22 import time 23 import time
23 24
24 from babel import __version__ as VERSION 25 from babel import __version__ as VERSION
25 from babel.core import Locale 26 from babel.core import Locale
26 from babel.messages.plurals import PLURALS 27 from babel.messages.plurals import PLURALS
27 from babel.util import odict, LOCALTZ, UTC 28 from babel.util import odict, LOCALTZ, UTC, FixedOffsetTimezone
28 29
29 __all__ = ['Message', 'Catalog'] 30 __all__ = ['Message', 'Catalog']
30 __docformat__ = 'restructuredtext en' 31 __docformat__ = 'restructuredtext en'
31 32
32 PYTHON_FORMAT = re.compile(r'\%(\([\w]+\))?[diouxXeEfFgGcrs]').search 33 PYTHON_FORMAT = re.compile(r'\%(\([\w]+\))?[diouxXeEfFgGcrs]').search
43 pluralizable messages 44 pluralizable messages
44 :param string: the translated message string, or a 45 :param string: the translated message string, or a
45 ``(singular, plural)`` tuple for pluralizable messages 46 ``(singular, plural)`` tuple for pluralizable messages
46 :param locations: a sequence of ``(filenname, lineno)`` tuples 47 :param locations: a sequence of ``(filenname, lineno)`` tuples
47 :param flags: a set or sequence of flags 48 :param flags: a set or sequence of flags
48 :param comments: a sequence of translator comments for the message 49 :param auto_comments: a sequence of automatic comments for the message
50 :param user_comments: a sequence of user comments for the message
49 """ 51 """
50 self.id = id 52 self.id = id
51 if not string and self.pluralizable: 53 if not string and self.pluralizable:
52 string = (u'', u'') 54 string = (u'', u'')
53 self.string = string 55 self.string = string
147 149
148 self.project = project or 'PROJECT' #: the project name 150 self.project = project or 'PROJECT' #: the project name
149 self.version = version or 'VERSION' #: the project version 151 self.version = version or 'VERSION' #: the project version
150 self.copyright_holder = copyright_holder or 'ORGANIZATION' 152 self.copyright_holder = copyright_holder or 'ORGANIZATION'
151 self.msgid_bugs_address = msgid_bugs_address or 'EMAIL@ADDRESS' 153 self.msgid_bugs_address = msgid_bugs_address or 'EMAIL@ADDRESS'
152 self.last_translator = last_translator #: last translator name + email 154
155 self.last_translator = last_translator or 'FULL NAME <EMAIL@ADDRESS>'
156 """Name and email address of the last translator."""
157
153 self.charset = charset or 'utf-8' 158 self.charset = charset or 'utf-8'
154 159
155 if creation_date is None: 160 if creation_date is None:
156 creation_date = datetime.now(LOCALTZ) 161 creation_date = datetime.now(LOCALTZ)
157 elif isinstance(creation_date, datetime) and not creation_date.tzinfo: 162 elif isinstance(creation_date, datetime) and not creation_date.tzinfo:
184 # Translations template for Foobar. 189 # Translations template for Foobar.
185 # Copyright (C) 2007 Foo Company 190 # Copyright (C) 2007 Foo Company
186 # This file is distributed under the same license as the Foobar project. 191 # This file is distributed under the same license as the Foobar project.
187 # FIRST AUTHOR <EMAIL@ADDRESS>, 2007. 192 # FIRST AUTHOR <EMAIL@ADDRESS>, 2007.
188 # 193 #
189 194
190 :type: `unicode` 195 :type: `unicode`
191 """) 196 """)
192 197
193 def mime_headers(self): 198 def _get_mime_headers(self):
194 headers = [] 199 headers = []
195 headers.append(('Project-Id-Version', 200 headers.append(('Project-Id-Version',
196 '%s %s' % (self.project, self.version))) 201 '%s %s' % (self.project, self.version)))
197 headers.append(('Report-Msgid-Bugs-To', self.msgid_bugs_address)) 202 headers.append(('Report-Msgid-Bugs-To', self.msgid_bugs_address))
198 headers.append(('POT-Creation-Date', 203 headers.append(('POT-Creation-Date',
211 headers.append(('Content-Type', 216 headers.append(('Content-Type',
212 'text/plain; charset=%s' % self.charset)) 217 'text/plain; charset=%s' % self.charset))
213 headers.append(('Content-Transfer-Encoding', '8bit')) 218 headers.append(('Content-Transfer-Encoding', '8bit'))
214 headers.append(('Generated-By', 'Babel %s\n' % VERSION)) 219 headers.append(('Generated-By', 'Babel %s\n' % VERSION))
215 return headers 220 return headers
216 mime_headers = property(mime_headers, doc="""\ 221
222 def _set_mime_headers(self, headers):
223 for name, value in headers:
224 name = name.lower()
225 if name == 'project-id-version':
226 parts = value.split(' ')
227 self.project = ' '.join(parts[:-1])
228 self.version = parts[-1]
229 elif name == 'report-msgid-bugs-to':
230 self.msgid_bugs_address = value
231 elif name == 'last-translator':
232 self.last_translator = value
233 elif name == 'pot-creation-date':
234 # FIXME: this should use dates.parse_datetime as soon as that
235 # is ready
236 value, tzoffset, _ = re.split('[+-](\d{4})$', value, 1)
237 tt = time.strptime(value, '%Y-%m-%d %H:%M')
238 ts = time.mktime(tt)
239 tzoffset = FixedOffsetTimezone(int(tzoffset))
240 self.creation_date = datetime.fromtimestamp(ts, tzoffset)
241
242 mime_headers = property(_get_mime_headers, _set_mime_headers, doc="""\
217 The MIME headers of the catalog, used for the special ``msgid ""`` entry. 243 The MIME headers of the catalog, used for the special ``msgid ""`` entry.
218 244
219 The behavior of this property changes slightly depending on whether a locale 245 The behavior of this property changes slightly depending on whether a locale
220 is set or not, the latter indicating that the catalog is actually a template 246 is set or not, the latter indicating that the catalog is actually a template
221 for actual translations. 247 for actual translations.
378 current.locations.extend(message.locations) 404 current.locations.extend(message.locations)
379 current.auto_comments.extend(message.auto_comments) 405 current.auto_comments.extend(message.auto_comments)
380 current.user_comments.extend(message.user_comments) 406 current.user_comments.extend(message.user_comments)
381 current.flags |= message.flags 407 current.flags |= message.flags
382 message = current 408 message = current
409 elif id == '':
410 # special treatment for the header message
411 headers = message_from_string(message.string.encode(self.charset))
412 self.mime_headers = headers.items()
383 else: 413 else:
384 if isinstance(id, (list, tuple)): 414 if isinstance(id, (list, tuple)):
385 assert isinstance(message.string, (list, tuple)) 415 assert isinstance(message.string, (list, tuple))
386 self._messages[key] = message 416 self._messages[key] = message
387 417
401 pluralizable messages 431 pluralizable messages
402 :param string: the translated message string, or a 432 :param string: the translated message string, or a
403 ``(singular, plural)`` tuple for pluralizable messages 433 ``(singular, plural)`` tuple for pluralizable messages
404 :param locations: a sequence of ``(filenname, lineno)`` tuples 434 :param locations: a sequence of ``(filenname, lineno)`` tuples
405 :param flags: a set or sequence of flags 435 :param flags: a set or sequence of flags
406 :param comments: a list of translator comments 436 :param auto_comments: a sequence of automatic comments
437 :param user_comments: a sequence of user comments
407 """ 438 """
408 self[id] = Message(id, string, list(locations), flags, auto_comments, 439 self[id] = Message(id, string, list(locations), flags, auto_comments,
409 user_comments) 440 user_comments)
410 441
411 def _key_for(self, id): 442 def _key_for(self, id):
Copyright (C) 2012-2017 Edgewall Software