aboutsummaryrefslogtreecommitdiffstats
path: root/jython-tosca-parser/src/main/resources/Lib/site-packages/babel-2.3.4-py2.7.egg/babel/messages/pofile.py
diff options
context:
space:
mode:
Diffstat (limited to 'jython-tosca-parser/src/main/resources/Lib/site-packages/babel-2.3.4-py2.7.egg/babel/messages/pofile.py')
-rw-r--r--jython-tosca-parser/src/main/resources/Lib/site-packages/babel-2.3.4-py2.7.egg/babel/messages/pofile.py507
1 files changed, 507 insertions, 0 deletions
diff --git a/jython-tosca-parser/src/main/resources/Lib/site-packages/babel-2.3.4-py2.7.egg/babel/messages/pofile.py b/jython-tosca-parser/src/main/resources/Lib/site-packages/babel-2.3.4-py2.7.egg/babel/messages/pofile.py
new file mode 100644
index 0000000..a775ec0
--- /dev/null
+++ b/jython-tosca-parser/src/main/resources/Lib/site-packages/babel-2.3.4-py2.7.egg/babel/messages/pofile.py
@@ -0,0 +1,507 @@
+# -*- coding: utf-8 -*-
+"""
+ babel.messages.pofile
+ ~~~~~~~~~~~~~~~~~~~~~
+
+ Reading and writing of files in the ``gettext`` PO (portable object)
+ format.
+
+ :copyright: (c) 2013 by the Babel Team.
+ :license: BSD, see LICENSE for more details.
+"""
+
+from __future__ import print_function
+import os
+import re
+
+from babel.messages.catalog import Catalog, Message
+from babel.util import wraptext
+from babel._compat import text_type
+
+
+def unescape(string):
+ r"""Reverse `escape` the given string.
+
+ >>> print(unescape('"Say:\\n \\"hello, world!\\"\\n"'))
+ Say:
+ "hello, world!"
+ <BLANKLINE>
+
+ :param string: the string to unescape
+ """
+ def replace_escapes(match):
+ m = match.group(1)
+ if m == 'n':
+ return '\n'
+ elif m == 't':
+ return '\t'
+ elif m == 'r':
+ return '\r'
+ # m is \ or "
+ return m
+ return re.compile(r'\\([\\trn"])').sub(replace_escapes, string[1:-1])
+
+
+def denormalize(string):
+ r"""Reverse the normalization done by the `normalize` function.
+
+ >>> print(denormalize(r'''""
+ ... "Say:\n"
+ ... " \"hello, world!\"\n"'''))
+ Say:
+ "hello, world!"
+ <BLANKLINE>
+
+ >>> print(denormalize(r'''""
+ ... "Say:\n"
+ ... " \"Lorem ipsum dolor sit "
+ ... "amet, consectetur adipisicing"
+ ... " elit, \"\n"'''))
+ Say:
+ "Lorem ipsum dolor sit amet, consectetur adipisicing elit, "
+ <BLANKLINE>
+
+ :param string: the string to denormalize
+ """
+ if '\n' in string:
+ escaped_lines = string.splitlines()
+ if string.startswith('""'):
+ escaped_lines = escaped_lines[1:]
+ lines = map(unescape, escaped_lines)
+ return ''.join(lines)
+ else:
+ return unescape(string)
+
+
+def read_po(fileobj, locale=None, domain=None, ignore_obsolete=False, charset=None):
+ """Read messages from a ``gettext`` PO (portable object) file from the given
+ file-like object and return a `Catalog`.
+
+ >>> from datetime import datetime
+ >>> from babel._compat import StringIO
+ >>> buf = StringIO('''
+ ... #: main.py:1
+ ... #, fuzzy, python-format
+ ... msgid "foo %(name)s"
+ ... msgstr "quux %(name)s"
+ ...
+ ... # A user comment
+ ... #. An auto comment
+ ... #: main.py:3
+ ... msgid "bar"
+ ... msgid_plural "baz"
+ ... msgstr[0] "bar"
+ ... msgstr[1] "baaz"
+ ... ''')
+ >>> catalog = read_po(buf)
+ >>> catalog.revision_date = datetime(2007, 4, 1)
+
+ >>> for message in catalog:
+ ... if message.id:
+ ... print((message.id, message.string))
+ ... print(' ', (message.locations, sorted(list(message.flags))))
+ ... print(' ', (message.user_comments, message.auto_comments))
+ (u'foo %(name)s', u'quux %(name)s')
+ ([(u'main.py', 1)], [u'fuzzy', u'python-format'])
+ ([], [])
+ ((u'bar', u'baz'), (u'bar', u'baaz'))
+ ([(u'main.py', 3)], [])
+ ([u'A user comment'], [u'An auto comment'])
+
+ .. versionadded:: 1.0
+ Added support for explicit charset argument.
+
+ :param fileobj: the file-like object to read the PO file from
+ :param locale: the locale identifier or `Locale` object, or `None`
+ if the catalog is not bound to a locale (which basically
+ means it's a template)
+ :param domain: the message domain
+ :param ignore_obsolete: whether to ignore obsolete messages in the input
+ :param charset: the character set of the catalog.
+ """
+ catalog = Catalog(locale=locale, domain=domain, charset=charset)
+
+ counter = [0]
+ offset = [0]
+ messages = []
+ translations = []
+ locations = []
+ flags = []
+ user_comments = []
+ auto_comments = []
+ obsolete = [False]
+ context = []
+ in_msgid = [False]
+ in_msgstr = [False]
+ in_msgctxt = [False]
+
+ def _add_message():
+ translations.sort()
+ if len(messages) > 1:
+ msgid = tuple([denormalize(m) for m in messages])
+ else:
+ msgid = denormalize(messages[0])
+ if isinstance(msgid, (list, tuple)):
+ string = []
+ for idx in range(catalog.num_plurals):
+ try:
+ string.append(translations[idx])
+ except IndexError:
+ string.append((idx, ''))
+ string = tuple([denormalize(t[1]) for t in string])
+ else:
+ string = denormalize(translations[0][1])
+ if context:
+ msgctxt = denormalize('\n'.join(context))
+ else:
+ msgctxt = None
+ message = Message(msgid, string, list(locations), set(flags),
+ auto_comments, user_comments, lineno=offset[0] + 1,
+ context=msgctxt)
+ if obsolete[0]:
+ if not ignore_obsolete:
+ catalog.obsolete[msgid] = message
+ else:
+ catalog[msgid] = message
+ del messages[:]
+ del translations[:]
+ del context[:]
+ del locations[:]
+ del flags[:]
+ del auto_comments[:]
+ del user_comments[:]
+ obsolete[0] = False
+ counter[0] += 1
+
+ def _process_message_line(lineno, line):
+ if line.startswith('msgid_plural'):
+ in_msgid[0] = True
+ msg = line[12:].lstrip()
+ messages.append(msg)
+ elif line.startswith('msgid'):
+ in_msgid[0] = True
+ offset[0] = lineno
+ txt = line[5:].lstrip()
+ if messages:
+ _add_message()
+ messages.append(txt)
+ elif line.startswith('msgstr'):
+ in_msgid[0] = False
+ in_msgstr[0] = True
+ msg = line[6:].lstrip()
+ if msg.startswith('['):
+ idx, msg = msg[1:].split(']', 1)
+ translations.append([int(idx), msg.lstrip()])
+ else:
+ translations.append([0, msg])
+ elif line.startswith('msgctxt'):
+ if messages:
+ _add_message()
+ in_msgid[0] = in_msgstr[0] = False
+ context.append(line[7:].lstrip())
+ elif line.startswith('"'):
+ if in_msgid[0]:
+ messages[-1] += u'\n' + line.rstrip()
+ elif in_msgstr[0]:
+ translations[-1][1] += u'\n' + line.rstrip()
+ elif in_msgctxt[0]:
+ context.append(line.rstrip())
+
+ for lineno, line in enumerate(fileobj.readlines()):
+ line = line.strip()
+ if not isinstance(line, text_type):
+ line = line.decode(catalog.charset)
+ if line.startswith('#'):
+ in_msgid[0] = in_msgstr[0] = False
+ if messages and translations:
+ _add_message()
+ if line[1:].startswith(':'):
+ for location in line[2:].lstrip().split():
+ pos = location.rfind(':')
+ if pos >= 0:
+ try:
+ lineno = int(location[pos + 1:])
+ except ValueError:
+ continue
+ locations.append((location[:pos], lineno))
+ else:
+ locations.append((location, None))
+ elif line[1:].startswith(','):
+ for flag in line[2:].lstrip().split(','):
+ flags.append(flag.strip())
+ elif line[1:].startswith('~'):
+ obsolete[0] = True
+ _process_message_line(lineno, line[2:].lstrip())
+ elif line[1:].startswith('.'):
+ # These are called auto-comments
+ comment = line[2:].strip()
+ if comment: # Just check that we're not adding empty comments
+ auto_comments.append(comment)
+ else:
+ # These are called user comments
+ user_comments.append(line[1:].strip())
+ else:
+ _process_message_line(lineno, line)
+
+ if messages:
+ _add_message()
+
+ # No actual messages found, but there was some info in comments, from which
+ # we'll construct an empty header message
+ elif not counter[0] and (flags or user_comments or auto_comments):
+ messages.append(u'')
+ translations.append([0, u''])
+ _add_message()
+
+ return catalog
+
+
+WORD_SEP = re.compile('('
+ r'\s+|' # any whitespace
+ r'[^\s\w]*\w+[a-zA-Z]-(?=\w+[a-zA-Z])|' # hyphenated words
+ r'(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w)' # em-dash
+ ')')
+
+
+def escape(string):
+ r"""Escape the given string so that it can be included in double-quoted
+ strings in ``PO`` files.
+
+ >>> escape('''Say:
+ ... "hello, world!"
+ ... ''')
+ '"Say:\\n \\"hello, world!\\"\\n"'
+
+ :param string: the string to escape
+ """
+ return '"%s"' % string.replace('\\', '\\\\') \
+ .replace('\t', '\\t') \
+ .replace('\r', '\\r') \
+ .replace('\n', '\\n') \
+ .replace('\"', '\\"')
+
+
+def normalize(string, prefix='', width=76):
+ r"""Convert a string into a format that is appropriate for .po files.
+
+ >>> print(normalize('''Say:
+ ... "hello, world!"
+ ... ''', width=None))
+ ""
+ "Say:\n"
+ " \"hello, world!\"\n"
+
+ >>> print(normalize('''Say:
+ ... "Lorem ipsum dolor sit amet, consectetur adipisicing elit, "
+ ... ''', width=32))
+ ""
+ "Say:\n"
+ " \"Lorem ipsum dolor sit "
+ "amet, consectetur adipisicing"
+ " elit, \"\n"
+
+ :param string: the string to normalize
+ :param prefix: a string that should be prepended to every line
+ :param width: the maximum line width; use `None`, 0, or a negative number
+ to completely disable line wrapping
+ """
+ if width and width > 0:
+ prefixlen = len(prefix)
+ lines = []
+ for line in string.splitlines(True):
+ if len(escape(line)) + prefixlen > width:
+ chunks = WORD_SEP.split(line)
+ chunks.reverse()
+ while chunks:
+ buf = []
+ size = 2
+ while chunks:
+ l = len(escape(chunks[-1])) - 2 + prefixlen
+ if size + l < width:
+ buf.append(chunks.pop())
+ size += l
+ else:
+ if not buf:
+ # handle long chunks by putting them on a
+ # separate line
+ buf.append(chunks.pop())
+ break
+ lines.append(u''.join(buf))
+ else:
+ lines.append(line)
+ else:
+ lines = string.splitlines(True)
+
+ if len(lines) <= 1:
+ return escape(string)
+
+ # Remove empty trailing line
+ if lines and not lines[-1]:
+ del lines[-1]
+ lines[-1] += '\n'
+ return u'""\n' + u'\n'.join([(prefix + escape(line)) for line in lines])
+
+
+def write_po(fileobj, catalog, width=76, no_location=False, omit_header=False,
+ sort_output=False, sort_by_file=False, ignore_obsolete=False,
+ include_previous=False):
+ r"""Write a ``gettext`` PO (portable object) template file for a given
+ message catalog to the provided file-like object.
+
+ >>> catalog = Catalog()
+ >>> catalog.add(u'foo %(name)s', locations=[('main.py', 1)],
+ ... flags=('fuzzy',))
+ <Message...>
+ >>> catalog.add((u'bar', u'baz'), locations=[('main.py', 3)])
+ <Message...>
+ >>> from babel._compat import BytesIO
+ >>> buf = BytesIO()
+ >>> write_po(buf, catalog, omit_header=True)
+ >>> print(buf.getvalue().decode("utf8"))
+ #: main.py:1
+ #, fuzzy, python-format
+ msgid "foo %(name)s"
+ msgstr ""
+ <BLANKLINE>
+ #: main.py:3
+ msgid "bar"
+ msgid_plural "baz"
+ msgstr[0] ""
+ msgstr[1] ""
+ <BLANKLINE>
+ <BLANKLINE>
+
+ :param fileobj: the file-like object to write to
+ :param catalog: the `Catalog` instance
+ :param width: the maximum line width for the generated output; use `None`,
+ 0, or a negative number to completely disable line wrapping
+ :param no_location: do not emit a location comment for every message
+ :param omit_header: do not include the ``msgid ""`` entry at the top of the
+ output
+ :param sort_output: whether to sort the messages in the output by msgid
+ :param sort_by_file: whether to sort the messages in the output by their
+ locations
+ :param ignore_obsolete: whether to ignore obsolete messages and not include
+ them in the output; by default they are included as
+ comments
+ :param include_previous: include the old msgid as a comment when
+ updating the catalog
+ """
+ def _normalize(key, prefix=''):
+ return normalize(key, prefix=prefix, width=width)
+
+ def _write(text):
+ if isinstance(text, text_type):
+ text = text.encode(catalog.charset, 'backslashreplace')
+ fileobj.write(text)
+
+ def _write_comment(comment, prefix=''):
+ # xgettext always wraps comments even if --no-wrap is passed;
+ # provide the same behaviour
+ if width and width > 0:
+ _width = width
+ else:
+ _width = 76
+ for line in wraptext(comment, _width):
+ _write('#%s %s\n' % (prefix, line.strip()))
+
+ def _write_message(message, prefix=''):
+ if isinstance(message.id, (list, tuple)):
+ if message.context:
+ _write('%smsgctxt %s\n' % (prefix,
+ _normalize(message.context, prefix)))
+ _write('%smsgid %s\n' % (prefix, _normalize(message.id[0], prefix)))
+ _write('%smsgid_plural %s\n' % (
+ prefix, _normalize(message.id[1], prefix)
+ ))
+
+ for idx in range(catalog.num_plurals):
+ try:
+ string = message.string[idx]
+ except IndexError:
+ string = ''
+ _write('%smsgstr[%d] %s\n' % (
+ prefix, idx, _normalize(string, prefix)
+ ))
+ else:
+ if message.context:
+ _write('%smsgctxt %s\n' % (prefix,
+ _normalize(message.context, prefix)))
+ _write('%smsgid %s\n' % (prefix, _normalize(message.id, prefix)))
+ _write('%smsgstr %s\n' % (
+ prefix, _normalize(message.string or '', prefix)
+ ))
+
+ sort_by = None
+ if sort_output:
+ sort_by = "message"
+ elif sort_by_file:
+ sort_by = "location"
+
+ for message in _sort_messages(catalog, sort_by=sort_by):
+ if not message.id: # This is the header "message"
+ if omit_header:
+ continue
+ comment_header = catalog.header_comment
+ if width and width > 0:
+ lines = []
+ for line in comment_header.splitlines():
+ lines += wraptext(line, width=width,
+ subsequent_indent='# ')
+ comment_header = u'\n'.join(lines)
+ _write(comment_header + u'\n')
+
+ for comment in message.user_comments:
+ _write_comment(comment)
+ for comment in message.auto_comments:
+ _write_comment(comment, prefix='.')
+
+ if not no_location:
+ locs = []
+ for filename, lineno in sorted(message.locations):
+ if lineno:
+ locs.append(u'%s:%d' % (filename.replace(os.sep, '/'), lineno))
+ else:
+ locs.append(u'%s' % filename.replace(os.sep, '/'))
+ _write_comment(' '.join(locs), prefix=':')
+ if message.flags:
+ _write('#%s\n' % ', '.join([''] + sorted(message.flags)))
+
+ if message.previous_id and include_previous:
+ _write_comment('msgid %s' % _normalize(message.previous_id[0]),
+ prefix='|')
+ if len(message.previous_id) > 1:
+ _write_comment('msgid_plural %s' % _normalize(
+ message.previous_id[1]
+ ), prefix='|')
+
+ _write_message(message)
+ _write('\n')
+
+ if not ignore_obsolete:
+ for message in _sort_messages(
+ catalog.obsolete.values(),
+ sort_by=sort_by
+ ):
+ for comment in message.user_comments:
+ _write_comment(comment)
+ _write_message(message, prefix='#~ ')
+ _write('\n')
+
+
+def _sort_messages(messages, sort_by):
+ """
+ Sort the given message iterable by the given criteria.
+
+ Always returns a list.
+
+ :param messages: An iterable of Messages.
+ :param sort_by: Sort by which criteria? Options are `message` and `location`.
+ :return: list[Message]
+ """
+ messages = list(messages)
+ if sort_by == "message":
+ messages.sort()
+ elif sort_by == "location":
+ messages.sort(key=lambda m: m.locations)
+ return messages