
    ƪbU                         d Z ddlZddlZddlmZmZ ddlmZmZ d Z	d Z
 G d de      Z G d	 d
      Z G d d      ZddZ ej                   d      Zd ZddZ	 	 	 ddZd Zy)z
    babel.messages.pofile
    ~~~~~~~~~~~~~~~~~~~~~

    Reading and writing of files in the ``gettext`` PO (portable object)
    format.

    :copyright: (c) 2013-2022 by the Babel Team.
    :license: BSD, see LICENSE for more details.
    N)CatalogMessage)wraptext_cmpc                 X    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                 L    | j                  d      }|dk(  ry|dk(  ry|dk(  ry|S )N   n
t	r)group)matchms     7/usr/lib/python3/dist-packages/babel/messages/pofile.pyreplace_escapesz!unescape.<locals>.replace_escapes   s2    KKN8#X#X    z\\([\\trn"])r	   )recompilesub)stringr   s     r   unescaper      s+    	 ::o&**?F1RLIIr   c                     d| v rG| j                         }| j                  d      r|dd }t        t        |      }dj	                  |      S t        |       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   ""r	   N )
splitlines
startswithmapr   join)r   escaped_linesliness      r   denormalizer%   *   sX    * v~))+T")!"-MHm,wwu~r   c                   "     e Zd ZdZ fdZ xZS )PoFileErrorzDException thrown by PoParser when an invalid po file is encountered.c                 X    t         |   | d|        || _        || _        || _        y )Nz on )super__init__cataloglinelineno)selfmessager+   r,   r-   	__class__s        r   r*   zPoFileError.__init__K   s0    G9D12	r   )__name__
__module____qualname____doc__r*   __classcell__)r0   s   @r   r'   r'   I   s    N r   r'   c                   X    e Zd Zd Zd Zd Zd ZeZd Zd Z	d Z
d Zd	 Zd
 Zd Zd Zy)_NormalizedStringc                 B    g | _         |D ]  }| j                  |        y N)_strsappend)r.   argsargs      r   r*   z_NormalizedString.__init__T   s$    
 	CKK	r   c                 V    | j                   j                  |j                                y r9   )r:   r;   strip)r.   ss     r   r;   z_NormalizedString.appendY   s    

!'')$r   c                 T    dj                  t        t        | j                              S )Nr   )r"   r!   r   r:   r.   s    r   r%   z_NormalizedString.denormalize\   s    wws8TZZ011r   c                 ,    t        | j                        S r9   )boolr:   rB   s    r   __nonzero__z_NormalizedString.__nonzero___   s    DJJr   c                 T    t         j                  j                  | j                        S r9   )oslinesepr"   r:   rB   s    r   __repr__z_NormalizedString.__repr__d   s    zztzz**r   c                 D    |syt        t        |       t        |            S )Nr	   )r   strr.   others     r   __cmp__z_NormalizedString.__cmp__g   s    CIs5z**r   c                 *    | j                  |      dkD  S Nr   rN   rL   s     r   __gt__z_NormalizedString.__gt__m       ||E"Q&&r   c                 *    | j                  |      dk  S rP   rQ   rL   s     r   __lt__z_NormalizedString.__lt__p   rS   r   c                 *    | j                  |      dk\  S rP   rQ   rL   s     r   __ge__z_NormalizedString.__ge__s       ||E"a''r   c                 *    | j                  |      dk  S rP   rQ   rL   s     r   __le__z_NormalizedString.__le__v   rX   r   c                 *    | j                  |      dk(  S rP   rQ   rL   s     r   __eq__z_NormalizedString.__eq__y   rX   r   c                 *    | j                  |      dk7  S rP   rQ   rL   s     r   __ne__z_NormalizedString.__ne__|   rX   r   N)r1   r2   r3   r*   r;   r%   rE   __bool__rI   rN   rR   rU   rW   rZ   r\   r^    r   r   r7   r7   R   sE    
%2  H++''((((r   r7   c                   Z    e Zd ZdZg dZddZd Zd Zd ZddZ	ddZ
d	 Zd
 Zd Zd Zy)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_pluralc                 j    || _         || _        d| _        d| _        || _        | j                          y rP   )r+   ignore_obsoletecounteroffsetabort_invalid_reset_message_state)r.   r+   rh   rk   s       r   r*   zPoFileParser.__init__   s3    .*!!#r   c                     g | _         g | _        g | _        g | _        g | _        g | _        d | _        d| _        d| _        d| _	        d| _
        y )NF)messagestranslations	locationsflagsuser_commentsauto_commentscontextobsoletein_msgid	in_msgstr
in_msgctxtrB   s    r   rl   z!PoFileParser._reset_message_state   sR    
r   c           
      P   | j                   j                          t        | j                        dkD  rt	        d | j                  D              }n| j                  d   j                         }t        |t        t        f      rt        | j                  j                        D cg c]  }d }}| j                   D ]O  \  }}|| j                  j                  k\  r| j                  d| j                  d       =|j                         ||<   Q t	        |      }n | j                   d   d   j                         }| j                  r| j                  j                         }nd}t        ||t        | j                        t!        | j"                        | j$                  | j&                  | j                  dz   |      }| j(                  r&| j*                  s)|| j                  j(                  |<   n|| j                  |<   | xj,                  dz  c_        | j/                          yc c}w )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              3   <   K   | ]  }|j                           y wr9   )r%   ).0r   s     r   	<genexpr>z,PoFileParser._add_message.<locals>.<genexpr>   s     Aa!--/As   r   r   z5msg has more translations than num_plurals of catalogN)r-   rt   )ro   sortlenrn   tupler%   
isinstancelistranger+   num_plurals_invalid_pofilerj   rt   r   rp   setrq   rs   rr   ru   rh   ri   rl   )r.   rc   _r   idxtranslationre   r/   s           r   _add_messagezPoFileParser._add_message   s   
 	 t}}!A4==AAEMM!$002EedE]+"'(@(@"ABQbBFB$($5$5 8 [$,,222((dkk;rs)557s	8
 6]F&&q)!,88:F<<ll..0GG%dnn)=s4::,,d.@.@WX")+ ==''/6%%e,")DLL!!#- Cs   $	H#c                 >    | j                   r| j                          y y r9   )rn   r   rB   s    r   _finish_current_messagez$PoFileParser._finish_current_message   s    == r   c                 r    |j                  d      r| j                  ||       y | j                  |||       y )N")r    !_process_string_continuation_line_process_keyword_line)r.   r-   r,   ru   s       r   _process_message_linez"PoFileParser._process_message_line   s0    ??3224@&&vtX>r   c                    | j                   D ]4  }	 |j                  |      r |t        |         dv r|t        |      d  } n6 | j	                  ||d       y |dv r| j                          || _        |dk(  r|| _        |dv r3d| _        d| _	        | j                  j                  t        |             y |d	k(  rd| _	        d| _        |j                  d
      rH|dd  j                  dd      \  }}| j                  j                  t!        |      t        |      g       y | j                  j                  dt        |      g       y |dk(  rd| _        t        |      | _        y y # t        $ r | j	                  ||d       Y yw xY w)N) [z$Keyword must be followed by a stringz0Start of line didn't match any expected keyword.)rc   re   rc   )rc   rf   FTrd   r   r	   ]r   re   )	_keywordsr    r~   
IndexErrorr   r   ru   rj   rx   rv   rn   r;   r7   rw   splitro   intrt   )r.   r-   r,   ru   keywordr=   r   msgs           r   r   z"PoFileParser._process_keyword_line   s   ~~ 		G[??7+S\0Bj0Ps7|}-C			   v/ab**((*  g DK//#DO DMMM  !23!78 !DM!DN~~c"qr7==a0S!!((#c(4Ec4J)KL!!((!->s-C)DE	!"DO,S1DL "=  [$$T63YZ[s   /E''FFc                     | j                   r| j                  d   }nL| j                  r| j                  d   d   }n-| j                  r| j
                  }n| j                  ||d       y |j                  |       y )Nr   r	   z<Got line starting with " but not in msgid, msgstr or msgctxt)rv   rn   rw   ro   rx   rt   r   r;   )r.   r,   r-   r@   s       r   r   z.PoFileParser._process_string_continuation_line   sd    ==b!A^^!!"%a(A__A  v/no	r   c                 4   | j                          |dd  j                  d      r|dd  j                         j                         D ]h  }|j	                  d      }|dk\  r3	 t        ||dz   d        }| j                  j                  |d | |f       L| j                  j                  |d f       j y |dd  j                  d      rQ|dd  j                         j                  d      D ]+  }| j                  j                  |j                                - y |dd  j                  d      r2|dd  j                         }|r| j                  j                  |       y y | j                  j                  |dd  j                                y # t        $ r Y Pw xY w)Nr	   :   r   ,.)r   r    lstripr   rfindr   
ValueErrorrp   r;   rq   r?   rs   rr   )r.   r,   locationposr-   flagcomments          r   _process_commentzPoFileParser._process_comment  sz   $$&8s# HOO-335 	<nnS)!8!!$XcAgh%7!8 NN))8DS>6*BCNN))8T*:;	< !"X  %QR)//4 0

!!$**,/0!"X  %12hnn&G""))'2  %%d12hnn&67 & ! !s    F

	FFc                    t        |      D ]  \  }}|j                         }t        |t              s%|j	                  | j
                  j                        }|sN|j                  d      rL|dd j                  d      r&| j                  ||dd j                         d       | j                  |       | j                  ||        | j                          | j                  s| j                  s| j                  s| j                  r[| j                   j#                  t%        d             | j&                  j#                  d	t%        d      g       | j)                          yyy)
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~r   T)ru   r   r   )	enumerater?   r   rK   decoder+   charsetr    r   r   r   r   ri   rq   rr   rs   rn   r;   r7   ro   r   )r.   fileobjr-   r,   s       r   parsezPoFileParser.parse!  s)    &g. 	9LFD::<DdC({{4<<#7#78s#8&&s+..vtABx7HSW.X))$/**648	9 	$$& ||t/A/ATEWEWMM  !25!9:$$a):5)A%BC FX|r   c                     t        |t              sJ | j                  rt        || j                  ||      t        d|       t        dj                  |dz   t        |                   y )NzWARNING:z!WARNING: Problem on line {0}: {1}r	   )r   rK   rk   r'   r+   printformatrepr)r.   r,   r-   r   s       r   r   zPoFileParser._invalid_pofile>  sZ    $$$$c4<<v>>j# 	299&1*d4jQRr   N)FF)F)r1   r2   r3   r4   r   r*   rl   r   r   r   r   r   r   r   r   r`   r   r   rb   rb      sC    I$ !$F ?'2R
86 :Sr   rb   c                 `    t        |||      }t        |||      }|j                  |        |S )a  Read messages from a ``gettext`` PO (portable object) file from the given
    file-like object and return a `Catalog`.

    >>> from datetime import datetime
    >>> from io 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.
    :param abort_invalid: abort read if po file is invalid
    )localedomainr   )rk   )r   rb   r   )r   r   r   rh   r   rk   r+   parsers           r   read_por   I  s2    ^ VFGDG'?-PF
LLNr   zL(\s+|[^\s\w]*\w+[a-zA-Z]-(?=\w+[a-zA-Z])|(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))c                     d| j                  dd      j                  dd      j                  dd      j                  dd	      j                  d
d      z  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\nr   z\")replace)r   s    r   escaper     sN     FNN40"74/"74/"74/"74/	0 0r   c           
         |r|dkD  rt        |      }g }| j                  d      D ]  }t        t        |            |z   |kD  rt        j	                  |      }|j                          |sEg }d}|rot        t        |d               dz
  |z   }	||	z   |k  r%|j                  |j                                ||	z  }n"|s|j                  |j                                n|ro|j                  dj                  |             |r|j                  |        n| j                  d      }t        |      dk  rt        |       S |r|d   s|d= |dxx   dz  cc<   ddj                  |D cg c]  }|t        |      z    c}      z   S c c}w )	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   Tr   r   r   r	   r   z""
)	r~   r   r   WORD_SEPr   reverser;   popr"   )
r   prefixwidth	prefixlenr$   r,   chunksbufsizels
             r   	normalizer     sq   0 K	%%d+ 	#D6$< 9,u4!- CD vbz 23a7)C!8e+JJvzz|4 AID#& !$

6::< 8! ! LL#/   T")	#, !!$'
5zQf~ U2Y"Ib	T	UZZU KT&6$<"7 KLLL Ks   +F	
c
           
      J    dfd	 fddfd	}
dfd	}d}|rd}n|rd}t        |	      D ]  }|j                  sZ|rj                  }r>d
kD  r9g }|j                         D ]  }|t	        |d      z  } dj                  |      } |dz          |j                  D ]
  } |
|        |j                  D ]  } |
|d        |sg }	 t        |j                  d       }|D ]h  \  }}|r(|	r&d|j                  t        j                  d      |fz  }n#d|j                  t        j                  d      z  }||vsX|j                  |       j  |
dj                  |      d       |j                  r1 ddj                  dgt        |j                        z         z         |j                   rZ|rX |
d |j                   d
         z  d       t#        |j                         dkD  r  |
d |j                   d         z  d        ||        d        |sVt        j$                  j'                         |	      D ]-  }|j                  D ]
  } |
|         ||d        d       / yy# t        $ r |j                  }Y w xY w)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 io 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                      t        | |      S )N)r   r   )r   )keyr   r   s     r   
_normalizezwrite_po.<locals>._normalize  s    V599r   c                     t        | t              r| j                  j                  d      } j	                  |        y )Nbackslashreplace)r   rK   encoder   write)textr+   r   s    r   _writezwrite_po.<locals>._write  s.    dC ;;w0BCDdr   c                 z    rdkD  r}nd}t        | |      D ]  } d|d|j                         d       ! y )Nr   L   r   r   r   )r   r?   )r   r   _widthr,   r   r   s       r   _write_commentz write_po.<locals>._write_comment
  sA     UQYFFWf- 	8D67	8r   c           
         t        | j                  t        t        f      r| j                  r |d | j                  |      d        |d | j                  d   |      d        |d | j                  d   |      d       t        j                        D ]'  }	 | j                  |   } d|| ||      fz         ) y | j                  r |d | j                  |      d        |d | j                  |      d        |d	 | j                  xs d|      d       y # t        $ r d}Y w xY w)
Nzmsgctxt r   zmsgid r   zmsgid_plural r	   r   z%smsgstr[%d] %s
zmsgstr )	r   idr   r   rt   r   r   r   r   )r/   r   r   r   r   r   r+   s       r   _write_messagez write_po.<locals>._write_message  sD   gjj4-06+5goov+NP QVZ

1v-NOP
7::a=&9  W001  $^^C0F *CFF!;.   6+5goov+NP QVZ

F-KLM
7>>#7R@  "  F s   *D??EENr/   r   )sort_byr   z# )r   subsequent_indentr   r   )r   c                 H    | d   t        | d   t              xr | d   xs dfS )Nr   r	   r   )r   r   )xs    r   <lambda>zwrite_po.<locals>.<lambda>P  s,    !A$
1Q48M8VRSTURV8\Z\1] r   r   z%s:%d/z%sr   r   z#%s
z, zmsgid %s|r	   zmsgid_plural %sz#~ )r   )_sort_messagesr   header_commentr   r   r"   rr   rs   sortedrp   	TypeErrorr   rG   sepr;   rq   previous_idr~   ru   values)r   r+   r   no_locationomit_headersort_outputsort_by_filerh   include_previousinclude_linenor   r   r   r/   comment_headerr$   r,   r   locsrp   filenamer-   r   r   r   s   ```                    @@r   write_por     s   \:
86 G	!'7; 3zz$33N*557 >DXd%8<> >E> "'E!2>E)*,, 	$G7#	$,, 	0G73/	0 D."7#4#4']_	
 %. * &n'8+;+;BFFC+H&*QQH$x'7'7'DDH4'KK)* 388D>#6==7TYYtfW]].C'CDDE#3:
73F3Fq3I(JJ"%'7&&'!+0:''*4   	wtg3j %##%
 	G #00 (w'(7514L	 3  .#--	.s   J		J"!J"c                 z    t        |       } |dk(  r| j                          | S |dk(  r| j                  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]
    r/   r   c                     | j                   S r9   )rp   )r   s    r   r   z _sort_messages.<locals>.<lambda>  s
    AKK r   r   )r   r}   )rn   r   s     r   r   r   u  sC     H~H) O 
J	/0Or   )NNFNF)r   r   )r   FFFFFFT)r4   rG   r   babel.messages.catalogr   r   
babel.utilr   r   r   r%   	Exceptionr'   r7   rb   r   r   r   r   r   r   r   r`   r   r   <module>r      s   	 
 	 3 %J. >) +( +(^ES ESP2j 2::  0$:Mz INDI48^Br   