
­­­­­­­­­­­­­­­­­­
<!DOCTYPE html>
<html>
3
HXM                 @   s   d Z ddlmZ ddlZddlZddlmZmZ ddlm	Z	 ddl
mZ dd Zd	d
 ZG dd deZG dd deZdddZejdZdd ZdddZd ddZdd ZdS )!z
    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.
    )print_functionN)CatalogMessage)wraptext)	text_typec             C   s"   dd }t jdj|| dd S )zReverse `escape` the given string.

    >>> print(unescape('"Say:\\n  \\"hello, world!\\"\\n"'))
    Say:
      "hello, world!"
    <BLANKLINE>

    :param string: the string to unescape
    c             S   s2   | j d}|dkrdS |dkr"dS |dkr.dS |S )N   n
t	r)group)matchm r   /usr/lib/python3.6/pofile.pyreplace_escapes    s    
z!unescape.<locals>.replace_escapesz\\([\\trn"])r   )recompilesub)stringr   r   r   r   unescape   s    

r   c             C   sF   d| kr:| j  }| jdr&|dd }tt|}dj|S t| S dS )a  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
    r	   z""r   N )
splitlines
startswithmapr   join)r   Zescaped_lineslinesr   r   r   denormalize-   s    


r    c               @   s,   e Zd Zdd Zdd Zdd Zdd Zd	S )
_NormalizedStringc             G   s"   g | _ x|D ]}| j| qW d S )N)_strsappend)selfargsargr   r   r   __init__N   s    
z_NormalizedString.__init__c             C   s   | j j|j  d S )N)r"   r#   strip)r$   sr   r   r   r#   S   s    z_NormalizedString.appendc             C   s   dj tt| jS )Nr   )r   r   r   r"   )r$   r   r   r   r    V   s    z_NormalizedString.denormalizec             C   s
   t | jS )N)boolr"   )r$   r   r   r   __nonzero__Y   s    z_NormalizedString.__nonzero__N)__name__
__module____qualname__r'   r#   r    r+   r   r   r   r   r!   L   s   r!   c               @   sr   e Zd ZdZddddgZdddZd	d
 Zdd Zdd ZdddZ	dddZ
dd Zdd Zdd Zdd ZdS )PoFileParserzSupport class to  read messages from a ``gettext`` PO (portable object) file
    and add them to a `Catalog`

    See `read_po` for simple cases.
    msgidmsgstrmsgctxtmsgid_pluralFc             C   s$   || _ || _d| _d| _| j  d S )Nr   )catalogignore_obsoletecounteroffset_reset_message_state)r$   r4   r5   r   r   r   r'   k   s
    zPoFileParser.__init__c             C   sF   g | _ g | _g | _g | _g | _g | _d | _d| _d| _d| _	d| _
d S )NF)messagestranslations	locationsflagsuser_commentsauto_commentscontextobsoletein_msgid	in_msgstr
in_msgctxt)r$   r   r   r   r8   r   s    z!PoFileParser._reset_message_statec          
   C   s@  | j j  t| jdkr.tdd | jD }n| jd j }t|ttfrdd t| j	j
D }x<| j D ]2\}}|| j	j
kr| jd| jd qh|j ||< qhW t|}n| j d d j }| jr| jj }nd}t||t| jt| j| j| j| jd |d	}| jr| js&|| j	j|< n
|| j	|< |  jd7  _| j  dS )
z
        Add a message to the catalog based on the current parser state and
        clear the state ready to process the next message.
        r   c             S   s   g | ]}|j  qS r   )r    ).0r   r   r   r   
<listcomp>   s    z-PoFileParser._add_message.<locals>.<listcomp>r   c             S   s   g | ]}d qS )r   r   )rD   _r   r   r   rE      s    r   z5msg has more translations than num_plurals of catalogN)linenor?   )r:   sortlenr9   tupler    
isinstancelistranger4   num_plurals_invalid_pofiler7   r?   r   r;   setr<   r>   r=   r@   r5   r6   r8   )r$   r0   r   idxZtranslationr2   messager   r   r   _add_message   s2    


zPoFileParser._add_messagec             C   s   | j r| j  d S )N)r9   rS   )r$   r   r   r   _finish_current_message   s    z$PoFileParser._finish_current_messagec             C   s*   |j dr| j|| n| j||| d S )N")r   !_process_string_continuation_line_process_keyword_line)r$   rG   liner@   r   r   r   _process_message_line   s    
z"PoFileParser._process_message_linec             C   s  xL| j D ]0}|j|r|t| dkr|t|d  }P qW | j||d d S |dkr^| j  || _|dkrr|| _|dkrd| _d| _| j	j
t| n|d	kr d| _d| _|jdr|d
d  jdd
\}}| jj
t|t|g n| jj
dt|g n|dkrd| _t|| _d S )N [z0Start of line didn't match any expected keyword.r0   r2   r3   FTr1   r   ]r   )rZ   r[   )r0   r2   )r0   r3   )	_keywordsr   rI   rO   rT   r@   r7   rC   rA   r9   r#   r!   rB   splitr:   intr?   )r$   rG   rX   r@   keywordr&   rQ   msgr   r   r   rW      s2    


z"PoFileParser._process_keyword_linec             C   sV   | j r| jd }n6| jr(| jd d }n | jr6| j}n| j||d d S |j| d S )Nr   z<Got line starting with " but not in msgid, msgstr or msgctxtr   r   )rA   r9   rB   r:   rC   r?   rO   r#   )r$   rX   rG   r)   r   r   r   rV      s    z.PoFileParser._process_string_continuation_linec             C   s>  | j   |dd  jdrx|dd  j j D ]p}|jd}|dkryt||d d  }W n tk
rt   w0Y nX | jj|d | |f q0| jj|d f q0W n|dd  jdrx|dd  j jdD ]}| j	j|j
  qW nP|dd  jdr"|dd  j
 }|r:| jj| n| jj|dd  j
  d S )Nr   :   r   ,.)rT   r   lstripr^   rfindr_   
ValueErrorr;   r#   r<   r(   r>   r=   )r$   rX   locationposrG   flagcommentr   r   r   _process_comment   s&    
zPoFileParser._process_commentc             C   s   xt |D ]\}}|j }t|ts2|j| jj}|s8q
|jdr~|dd jdrr| j||dd j	 dd q| j
| q
| j|| q
W | j  | j r| js| js| jr| jjtd | jjd	tdg | j  dS )
z
        Reads from the file-like object `fileobj` and adds any po file
        units found in it to the `Catalog` supplied to the constructor.
        #r   N~rc   T)r@   z""r   )	enumerater(   rK   r   decoder4   charsetr   rY   rf   rm   rT   r6   r<   r=   r>   r9   r#   r!   r:   rS   )r$   fileobjrG   rX   r   r   r   parse   s     

zPoFileParser.parsec             C   s"   t d| t dj|d | d S )NzWARNING:z!WARNING: Problem on line {0}: {1}r   )printformat)r$   rX   rG   ra   r   r   r   rO     s    
zPoFileParser._invalid_pofileN)F)F)F)r,   r-   r.   __doc__r]   r'   r8   rS   rT   rY   rW   rV   rm   rt   rO   r   r   r   r   r/   ]   s   
#

&r/   Fc             C   s&   t |||d}t||}|j|  |S )aT  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.
    )localedomainrr   )r   r/   rt   )rs   rx   ry   r5   rr   r4   parserr   r   r   read_po  s    .

r{   zL(\s+|[^\s\w]*\w+[a-zA-Z]-(?=\w+[a-zA-Z])|(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))c             C   s0   d| j ddj ddj ddj dd	j d
d S )zEscape 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
    z"%s"\z\\r   z\tr   z\rr	   z\nrU   z\")replace)r   r   r   r   escapeV  s
    r~   r   L   c       
         s>  |r|dkrt  }g }x| jdD ]}t t|| |krtj|}|j  x|rg }d}xX|rt t|d
 d | }	||	 |k r|j|j  ||	7 }q^|s|j|j  P q^W |jdj| qPW q$|j| q$W n
| jd}t |dkrt| S |r"|d  r"|d= |d  d7  < ddj fdd	|D  S )a  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
    r   Trc   r   r   r	   z""
c                s   g | ]} t | qS r   )r~   )rD   rX   )prefixr   r   rE     s    znormalize.<locals>.<listcomp>r   r   r   r   )	rI   r   r~   WORD_SEPr^   reverser#   popr   )
r   r   widthZ	prefixlenr   rX   ZchunksZbufsizelr   )r   r   	normalizeh  s6    


r   Tc
                sT  d fdd	 fddd!fdd	}
d" fdd		}d
}|rLd}n|rTd}xt |dD ]}|js|rvqdj}rdkrg }x"|j D ]}|t|dd7 }qW dj|}|d  x|jD ]}|
| qW x|jD ]}|
|dd qW |srg }xZt|j	D ]L\}}|rB|	rB|j
d|jtjd|f  n|j
d|jtjd  qW |
dj|dd |jrddjdgt|j   |jr|r|
d |jd  dd t|jdkr|
d |jd  dd || d qdW |sPxJt jj |dD ]4}x|jD ]}|
| q$W ||dd d qW d
S )#a  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
    :param include_lineno: include line number in the location comment
    r   c                s   t | | dS )N)r   r   )r   )keyr   )r   r   r   
_normalize  s    zwrite_po.<locals>._normalizec                s&   t | tr| j jd} j|  d S )Nbackslashreplace)rK   r   encoderr   write)text)r4   rs   r   r   _write  s    
zwrite_po.<locals>._writec                sB   rdkr}nd}x&t | |D ]} d||j f  q"W d S )Nr   r   z#%s %s
)r   r(   )rl   r   Z_widthrX   )r   r   r   r   _write_comment  s
    z write_po.<locals>._write_commentc                s  t | jttfr| jr.d| | j|f  d| | jd |f  d| | jd |f  xtjD ]D}y| j| }W n tk
r   d}Y nX d|| ||f  qrW nT| jrڈd| | j|f  d| | j|f  d| | jpd|f  d S )	Nz%smsgctxt %s
z%smsgid %s
r   z%smsgid_plural %s
r   r   z%smsgstr[%d] %s
z%smsgstr %s
)	rK   idrL   rJ   r?   rM   rN   r   
IndexError)rR   r   rQ   r   )r   r   r4   r   r   _write_message  s(    
z write_po.<locals>._write_messageNrR   ri   )sort_byr   z# )r   Zsubsequent_indentr	   re   )r   z%s:%d/z%srZ   rb   z#%s
z, zmsgid %s|r   zmsgid_plural %sz#~ )r   )r   )r   )_sort_messagesr   Zheader_commentr   r   r   r=   r>   sortedr;   r#   r}   ossepr<   Zprevious_idrI   r@   values)rs   r4   r   Zno_locationZomit_headerZsort_outputZsort_by_filer5   Zinclude_previousZinclude_linenor   r   r   rR   Zcomment_headerr   rX   rl   ZlocsfilenamerG   r   )r   r   r4   rs   r   r   write_po  sf    .

r   c             C   s6   t | } |dkr| j  n|dkr2| jdd d | S )z
    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]
    rR   ri   c             S   s   | j S )N)r;   )r   r   r   r   <lambda>G  s    z _sort_messages.<locals>.<lambda>)r   )rL   rH   )r9   r   r   r   r   r   9  s    

r   )NNFN)r   r   )r   FFFFFFT)rw   Z
__future__r   r   r   Zbabel.messages.catalogr   r   Z
babel.utilr   Zbabel._compatr   r   r    objectr!   r/   r{   r   r   r~   r   r   r   r   r   r   r   <module>   s(    ?
4

=  
 