
Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­Â�Â­
<!DOCTYPE html>
<html>
3
H¶ÜXðM  ã               @   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 )z¿Reverse `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 )ÚPoFileParserz–Support 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ƒr¨d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r˜d| _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ƒr¦xˆ|dd … jƒ jƒ D ]p}|jdƒ}|dkr�y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ƒrêx€|dd … jƒ jdƒD ]}| j	j|j
ƒ ƒ qÐW 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à   xŒt |ƒ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 )zõ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
    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rÜt ˆ ƒ}g }xÌ| jdƒD ]²}t t|ƒƒ| |krÌtj|ƒ}|jƒ  x†|rÈg }d}xX|r´t 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rút| ƒ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}�x¦t ˆ|d�D �]”}|jsÆ|rvqdˆj}ˆrºˆdkrºg }x"|jƒ D ]}|t|ˆdd�7 }q–W dj|ƒ}ˆ|d ƒ x|jD ]}|
|ƒ qÎW x|jD ]}|
|dd� qæW |�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 ƒ x¨tˆ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

=  
 