
    ƪb                     2   d Z ddlZddlmZ ddlmZ ddlmZmZ ddl	m
Z
 ddlmZ ddlmZ dd	lmZ dd
lmZmZ ddlmZ ddlmZ ddlmZmZmZmZ g dZ ej<                  dej>                        Z d Z! G d d      Z" G d de#      Z$dZ% G d d      Z&y)z
    babel.messages.catalog
    ~~~~~~~~~~~~~~~~~~~~~~

    Data structures for message catalogs.

    :copyright: (c) 2013-2022 by the Babel Team.
    :license: BSD, see LICENSE for more details.
    N)parse_header)OrderedDict)datetimetime)get_close_matches)message_from_string)copy)__version__)LocaleUnknownLocaleError)format_datetime)
get_plural)distinctLOCALTZFixedOffsetTimezone_cmp)MessageCatalogTranslationErrorz
    \%
        (?:\(([\w]*)\))?
        (
            [-#0\ +]?(?:\*|[\d]+)?
            (?:\.(?:\*|[\d]+))?
            [hlL]?
        )
        ([diouxXeEfFgGcrs%])
c                 j   t        j                  d|       }t        j                  |j	                  d      d      }|j	                  d      }|d|d   |dd  }}|d d |dd  }}t        |dz         }t        |      }	t        |      }
|	d	z  }||
z  }||z  }t        |      }|j                  |
      }|S )Nz+^(?P<datetime>.*?)(?P<tzoffset>[+-]\d{4})?$r   z%Y-%m-%d %H:%Mtzoffsetr         1<   tzinfo)rematchr   strptimegroupintr   replace)valuer   dtr   plus_minus_sresthours_offset_smins_offset_s
plus_minushours_offsetmins_offsetnet_mins_offsets               8/usr/lib/python3/dist-packages/babel/messages/catalog.py_parse_datetime_headerr/   )   s    HHCUKE			5;;z24D	EB {{:&H%a[(12,d(,Ra$qr( +,
>*-( '+;&:% '7 ZZxZ(I    c                       e Zd ZdZ	 	 ddZd Zd Zd Zd Zd Z	d	 Z
d
 Zd Zd Zd ZddZed        Zed        Zed        Zy)r   z0Representation of a single message in a catalog.Nc
                    || _         |s| j                  rd}|| _        t        t	        |            | _        t        |      | _        |r(| j                  r| j                  j                  d       n| j                  j                  d       t        t	        |            | _        t        t	        |            | _        t        |t              r	|g| _        nt        |      | _        || _        |	| _        y)a_  Create the message object.

        :param id: the message ID, or a ``(singular, plural)`` tuple for
                   pluralizable messages
        :param string: the translated message string, or a
                       ``(singular, plural)`` tuple for pluralizable messages
        :param locations: a sequence of ``(filename, lineno)`` tuples
        :param flags: a set or sequence of flags
        :param auto_comments: a sequence of automatic comments for the message
        :param user_comments: a sequence of user comments for the message
        :param previous_id: the previous message ID, or a ``(singular, plural)``
                            tuple for pluralizable messages
        :param lineno: the line number on which the msgid line was found in the
                       PO file, if any
        :param context: the message context
        ) r3   zpython-formatN)idpluralizablestringlistr   	locationssetflagspython_formatadddiscardauto_commentsuser_comments
isinstancestrprevious_idlinenocontext)
selfr4   r6   r8   r:   r>   r?   rB   rC   rD   s
             r.   __init__zMessage.__init__J   s    $ $++Fhy12Z
$$$JJNN?+JJ/!(="9:!(="9:k3' +}D#K0Dr0   c                 z    dt        |       j                  d| j                  dt        | j                        dS )N< z	 (flags: z)>)type__name__r4   r7   r:   rE   s    r.   __repr__zMessage.__repr__o   s+    (,T
(;(;TWW(,TZZ(8: 	:r0   c                 8    d }t         ||        ||            S )z0Compare Messages, taking into account plural idsc                     t        | t              r+| j                  r| j                  d   | j                  xs dfS | j                  | j                  xs dfS )Nr   r3   )r@   r   r5   r4   rD   )objs    r.   values_to_comparez*Message.__cmp__.<locals>.values_to_compareu   sH    #w'C,<,<vvay#++"333663;;,",,r0   )r   )rE   otherrQ   s      r.   __cmp__zMessage.__cmp__s   s"    	- %d+->u-EFFr0   c                 *    | j                  |      dkD  S Nr   rS   rE   rR   s     r.   __gt__zMessage.__gt__{       ||E"Q&&r0   c                 *    | j                  |      dk  S rU   rV   rW   s     r.   __lt__zMessage.__lt__~   rY   r0   c                 *    | j                  |      dk\  S rU   rV   rW   s     r.   __ge__zMessage.__ge__       ||E"a''r0   c                 *    | j                  |      dk  S rU   rV   rW   s     r.   __le__zMessage.__le__   r^   r0   c                 *    | j                  |      dk(  S rU   rV   rW   s     r.   __eq__zMessage.__eq__   r^   r0   c                 *    | j                  |      dk7  S rU   rV   rW   s     r.   __ne__zMessage.__ne__   r^   r0   c                 X    t        |t              sJ | j                  |j                  k(  S )z[Checks whether messages are identical, taking into account all
        properties.
        )r@   r   __dict__rW   s     r.   is_identicalzMessage.is_identical   s'     %)))}}..r0   c                     t        t        t        | j                  | j                  | j
                  | j                  | j                  | j                  | j                  | j                  | j                  f	       S N)r   mapr	   r4   r6   r8   r:   r>   r?   rB   rC   rD   rL   s    r.   clonezMessage.clone   s^    D477DKK#'::t/A/A#'#5#5t7G7G#';;#> ? @ 	@r0   c                     ddl m} g }|D ]  }	  |||         |S # t        $ r}|j                  |       Y d}~0d}~ww xY w)a  Run various validation checks on the message.  Some validations
        are only performed if the catalog is provided.  This method returns
        a sequence of `TranslationError` objects.

        :rtype: ``iterator``
        :param catalog: A catalog instance that is passed to the checkers
        :see: `Catalog.check` for a way to perform checks for all messages
              in a catalog.
        r   )checkersN)babel.messages.checkersrm   r   append)rE   catalogrm   errorscheckeres         r.   checkzMessage.check   sR     	5 	!G!&	!
  $ !a  !s   		A ;A c                     d| j                   v S )a   Whether the translation is fuzzy.

        >>> Message('foo').fuzzy
        False
        >>> msg = Message('foo', 'foo', flags=['fuzzy'])
        >>> msg.fuzzy
        True
        >>> msg
        <Message 'foo' (flags: ['fuzzy'])>

        :type:  `bool`fuzzyr:   rL   s    r.   rv   zMessage.fuzzy   s     $**$$r0   c                 B    t        | j                  t        t        f      S )zWhether the message is plurizable.

        >>> Message('foo').pluralizable
        False
        >>> Message(('foo', 'bar')).pluralizable
        True

        :type:  `bool`)r@   r4   r7   tuplerL   s    r.   r5   zMessage.pluralizable   s     $''D%=11r0   c                 p    | j                   }t        |t        t        f      s|g}t	        d |D              S )zWhether the message contains Python-style parameters.

        >>> Message('foo %(name)s bar').python_format
        True
        >>> Message(('foo %(name)s', 'foo %(name)s')).python_format
        True

        :type:  `bool`c              3   F   K   | ]  }t         j                  |        y wri   )PYTHON_FORMATsearch).0r4   s     r.   	<genexpr>z(Message.python_format.<locals>.<genexpr>   s     :=''+:s   !)r4   r@   r7   ry   any)rE   idss     r.   r;   zMessage.python_format   s3     gg#e}-%C:c:::r0   )r3    r   r   r   r   NNri   )rK   
__module____qualname____doc__rF   rM   rS   rX   r[   r]   r`   rb   rd   rg   rk   rt   propertyrv   r5   r;   r   r0   r.   r   r   G   s    :MOHL#J:G''((((/@& % % 	2 	2 ; ;r0   r   c                       e Zd ZdZy)r   z_Exception thrown by translation checkers when invalid message
    translations are encountered.N)rK   r   r   r   r   r0   r.   r   r      s    %r0   r   z# Translations template for PROJECT.
# Copyright (C) YEAR ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#c                   D   e Zd ZdZddeddddddddddfdZd Zd Zd Z e	ee      Z
 e	e      Zd Zd	 Z e	eed
      Zd Zd!dZd Z e	eed      Ze	d        Ze	d        Ze	d        Zd Zd Zd Zd Zd Zd Zd Z	 	 d"dZd Zd#dZd#dZ d$dZ!d#dZ"d  Z#y)%r   z$Representation of a message catalog.NTc                 X   || _         || _        || _        t               | _        |xs d| _        |xs d| _        |xs d| _        |xs d| _        |
xs d| _	        	 |xs d| _
        	 |xs d| _        |t        j                  t              }n2t        |t              r"|j                   s|j#                  t        	      }|| _        |	d
}	n2t        |	t              r"|	j                   s|	j#                  t        	      }	|	| _        || _        t               | _        d| _        d| _        y)aD  Initialize the catalog object.

        :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 header_comment: the header comment as string, or `None` for the
                               default header
        :param project: the project's name
        :param version: the project's version
        :param copyright_holder: the copyright holder of the catalog
        :param msgid_bugs_address: the email address or URL to submit bug
                                   reports to
        :param creation_date: the date the catalog was created
        :param revision_date: the date the catalog was revised
        :param last_translator: the name and email of the last translator
        :param language_team: the name and email of the language team
        :param charset: the encoding to use in the output (defaults to utf-8)
        :param fuzzy: the fuzzy bit on the catalog header
        PROJECTVERSIONORGANIZATIONzEMAIL@ADDRESSzFULL NAME <EMAIL@ADDRESS>zLANGUAGE <LL@li.org>utf-8Nr   zYEAR-MO-DA HO:MI+ZONE)domainlocale_header_commentr   	_messagesprojectversioncopyright_holdermsgid_bugs_addresslast_translatorlanguage_teamcharsetr   nowr   r@   r   r#   creation_daterevision_daterv   obsolete_num_plurals_plural_expr)rE   r   r   header_commentr   r   r   r   r   r   r   r   r   rv   s                 r.   rF   zCatalog.__init__   s   2 -$+)+) 0 BN"4"G.M2M<*D.D:)' $LL1Mx09M9M)111AM* 3Mx09M9M)111AM*
#  r0   c                 4   |d | _         d | _        y t        |t              rt	        |      | _         || _        y t        |t              r,t	        |      | _         	 t        j
                  |      | _        y t        d|z        # t        $ r
 d | _        Y y w xY w)NzF`locale` must be a Locale, a locale identifier string, or None; got %r)_locale_identifier_localer@   r   rA   parser   	TypeErrorrE   r   s     r.   _set_localezCatalog._set_locale"  s    >&*D#DLff%&)&kD#!DLfc"&)&kD#$%||F3 `ciijj	 & $#$s   B BBc                     | j                   S ri   )r   rL   s    r.   _get_localezCatalog._get_locale7  s    ||r0   c                     | j                   S ri   )r   rL   s    r.   _get_locale_identifierzCatalog._get_locale_identifier:  s    &&&r0   c                    | j                   }t        j                  t              j	                  d      }t        | j                  d      r| j                  j	                  d      }|j                  d| j                        j                  d| j                        j                  d|      j                  d| j                        }| j                  r| j                  j                  n| j                  }|r|j                  dd|z        }|S )	Nz%Ystrftimer   r   YEARr   zTranslations templatez%s translations)r   r   r   r   r   hasattrr   r#   r   r   r   r   english_namelocale_identifier)rE   commentyearlocale_names       r.   _get_header_commentzCatalog._get_header_comment@  s    &&||G$--d34%%z2%%..t4D//)T\\:!')T\\:!'&$/!'.$2G2GH 	 48;;t{{//DDZDZoo&=?PS^?^_Gr0   c                     || _         y ri   )r   )rE   r6   s     r.   _set_header_commentzCatalog._set_header_commentN  s
    %r0   a      The header comment for the catalog.

    >>> catalog = Catalog(project='Foobar', version='1.0',
    ...                   copyright_holder='Foo Company')
    >>> print(catalog.header_comment) #doctest: +ELLIPSIS
    # Translations template for Foobar.
    # Copyright (C) ... Foo Company
    # This file is distributed under the same license as the Foobar project.
    # FIRST AUTHOR <EMAIL@ADDRESS>, ....
    #

    The header can also be set from a string. Any known upper-case variables
    will be replaced when the header is retrieved again:

    >>> catalog = Catalog(project='Foobar', version='1.0',
    ...                   copyright_holder='Foo Company')
    >>> catalog.header_comment = '''\
    ... # The POT for my really cool PROJECT project.
    ... # Copyright (C) 1990-2003 ORGANIZATION
    ... # This file is distributed under the same license as the PROJECT
    ... # project.
    ... #'''
    >>> print(catalog.header_comment)
    # The POT for my really cool Foobar project.
    # Copyright (C) 1990-2003 Foo Company
    # This file is distributed under the same license as the Foobar
    # project.
    #

    :type: `unicode`
    )docc           	      h   g }|j                  d| j                  d| j                  f       |j                  d| j                  f       |j                  dt	        | j
                  dd      f       t        | j                  t        t        t        t        f      r*|j                  dt	        | j                  dd      f       n|j                  d| j                  f       |j                  d	| j                  f       | j                  r&|j                  d
t        | j                        f       | j                  rOd| j                  v rA|j                  d| j                  j!                  dt        | j                              f       n|j                  d| j                  f       | j"                  |j                  d| j$                  f       |j                  d       |j                  dd| j&                  z  f       |j                  d       |j                  ddt(        z  f       |S )NzProject-Id-VersionrI   zReport-Msgid-Bugs-TozPOT-Creation-Datezyyyy-MM-dd HH:mmZen)r   zPO-Revision-DatezLast-TranslatorLanguageLANGUAGEzLanguage-TeamzPlural-Forms)zMIME-Versionz1.0zContent-Typeztext/plain; charset=%s)zContent-Transfer-Encoding8bitzGenerated-Byz	Babel %s
)ro   r   r   r   r   r   r@   r   r   time_r"   floatr   r   rA   r   r#   r   plural_formsr   r   )rE   headerss     r.   _get_mime_headerszCatalog._get_mime_headersr  s   ,#'<<>@ 	A.0G0GHI+'(:(:<O/356 	7 d((8UC*GHNN.+D,>,>,?NO P NN.0B0BCD)4+?+?@A!!NNJD,B,B(CDE!!zT5G5G'GNNO ..66z7:4;Q;Q7RTU V NNOT-?-?@A;;"NNND,=,=>?./04<<?A 	B<=w(>?@r0   c                     t        |t              r|S t        |t              r|j                  ||      S t        |      S ri   )r@   rA   bytesdecode)rE   sencodingrq   s       r.   _force_textzCatalog._force_text  s5    aHa88Hf--1vr0   c                 *   |D ]  \  }}| j                  |j                         | j                        }| j                  || j                        }|dk(  r5|j                  d      }dj	                  |d d       | _        |d   | _        |dk(  r|| _        |dk(  r|| _        |dk(  r$|j                  dd	      }| j                  |       |d
k(  r|| _        |dk(  r-t        |      \  }}d|v s|d   j                         | _        |dk(  rJt        d|z         \  }}t        |j                  dd            | _        |j                  dd      | _        Z|dk(  rt#        |      | _        q|dk(  sxd|vs~t#        |      | _         y )N)r   zproject-id-versionrI   zreport-msgid-bugs-tozlast-translatorlanguage-_zlanguage-teamzcontent-typer   zplural-formsz ;npluralsr   plural(n != 1)zpot-creation-datezpo-revision-dater   )r   lowerr   splitjoinr   r   r   r   r#   r   r   r   r"   getr   r   r/   r   r   )rE   r   namer$   partsmimetypeparamsr   s           r.   _set_mime_headerszCatalog._set_mime_headers  s   " 	GKD%##DJJL4<<#HD$$UT\\$BE++C(#yys4$Ry//*/'**',$#c3/  '(%*"'#/#6 &&#))#4#:#:#<DL'(6	6$'

:q(A$B!$*JJx$D!,,%;E%B"++&)?)FD&;	Gr0   a      The MIME headers of the catalog, used for the special ``msgid ""`` entry.

    The behavior of this property changes slightly depending on whether a locale
    is set or not, the latter indicating that the catalog is actually a template
    for actual translations.

    Here's an example of the output for such a catalog template:

    >>> from babel.dates import UTC
    >>> created = datetime(1990, 4, 1, 15, 30, tzinfo=UTC)
    >>> catalog = Catalog(project='Foobar', version='1.0',
    ...                   creation_date=created)
    >>> for name, value in catalog.mime_headers:
    ...     print('%s: %s' % (name, value))
    Project-Id-Version: Foobar 1.0
    Report-Msgid-Bugs-To: EMAIL@ADDRESS
    POT-Creation-Date: 1990-04-01 15:30+0000
    PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE
    Last-Translator: FULL NAME <EMAIL@ADDRESS>
    Language-Team: LANGUAGE <LL@li.org>
    MIME-Version: 1.0
    Content-Type: text/plain; charset=utf-8
    Content-Transfer-Encoding: 8bit
    Generated-By: Babel ...

    And here's an example of the output when the locale is set:

    >>> revised = datetime(1990, 8, 3, 12, 0, tzinfo=UTC)
    >>> catalog = Catalog(locale='de_DE', project='Foobar', version='1.0',
    ...                   creation_date=created, revision_date=revised,
    ...                   last_translator='John Doe <jd@example.com>',
    ...                   language_team='de_DE <de@example.com>')
    >>> for name, value in catalog.mime_headers:
    ...     print('%s: %s' % (name, value))
    Project-Id-Version: Foobar 1.0
    Report-Msgid-Bugs-To: EMAIL@ADDRESS
    POT-Creation-Date: 1990-04-01 15:30+0000
    PO-Revision-Date: 1990-08-03 12:00+0000
    Last-Translator: John Doe <jd@example.com>
    Language: de_DE
    Language-Team: de_DE <de@example.com>
    Plural-Forms: nplurals=2; plural=(n != 1);
    MIME-Version: 1.0
    Content-Type: text/plain; charset=utf-8
    Content-Transfer-Encoding: 8bit
    Generated-By: Babel ...

    :type: `list`
    c                     | j                   -d}| j                  rt        | j                        d   }|| _         | j                   S )zThe number of plurals used by the catalog or locale.

        >>> Catalog(locale='en').num_plurals
        2
        >>> Catalog(locale='ga').num_plurals
        5

        :type: `int`r   r   )r   r   r   )rE   nums     r.   num_pluralszCatalog.num_plurals  sC     $C{{ -a0 #D   r0   c                     | j                   -d}| j                  rt        | j                        d   }|| _         | j                   S )aW  The plural expression used by the catalog or locale.

        >>> Catalog(locale='en').plural_expr
        '(n != 1)'
        >>> Catalog(locale='ga').plural_expr
        '(n==1 ? 0 : n==2 ? 1 : n>=3 && n<=6 ? 2 : n>=7 && n<=10 ? 3 : 4)'
        >>> Catalog(locale='ding').plural_expr  # unknown locale
        '(n != 1)'

        :type: `str`r   r   )r   r   r   )rE   exprs     r.   plural_exprzCatalog.plural_expr  sC     $D{{!$++.q1 $D   r0   c                 <    d| j                   d| j                  dS )zReturn the plural forms declaration for the locale.

        >>> Catalog(locale='en').plural_forms
        'nplurals=2; plural=(n != 1);'
        >>> Catalog(locale='pt_BR').plural_forms
        'nplurals=2; plural=(n > 1);'

        :type: `str`z	nplurals=z	; plural=;)r   r   rL   s    r.   r   zCatalog.plural_forms  s     -1,<,<d>N>NOOr0   c                 <    | j                  |      | j                  v S )z?Return whether the catalog has a message with the specified ID._key_forr   rE   r4   s     r.   __contains__zCatalog.__contains__  s    }}R DNN22r0   c                 ,    t        | j                        S )zeThe number of messages in the catalog.

        This does not include the special ``msgid ""`` entry.)lenr   rL   s    r.   __len__zCatalog.__len__   s     4>>""r0   c              #     K   g }| j                   D ]  \  }}|j                  |d|        t               }| j                  r|dhz  }t	        ddj                  |      |       | j                  D ]  }| j                  |     yw)zIterates through all the entries in the catalog, in the order they
        were added, yielding a `Message` object for every entry.

        :rtype: ``iterator``z: rv   r3   
rw   N)mime_headersro   r9   rv   r   r   r   )rE   bufr   r$   r:   keys         r.   __iter__zCatalog.__iter__&  s     
 ,, 	1KD%JJ4/0	1::gYEc499S>77>> 	&C..%%	&s   BBc                     d}| j                   rd| j                   z  }dt        |       j                  d| j                  |dS )Nr3   z %srH   rI   >)r   rJ   rK   r   r   s     r.   rM   zCatalog.__repr__5  s8    ;;T[[(F"4j114;;GGr0   c                 &    | j                  |       y)z)Delete the message with the specified ID.N)deleter   s     r.   __delitem__zCatalog.__delitem__;  s    Br0   c                 $    | j                  |      S )zUReturn the message with the specified ID.

        :param id: the message ID
        )r   r   s     r.   __getitem__zCatalog.__getitem__?  s    
 xx|r0   c                 F   t        |t              sJ d       | j                  ||j                        }| j                  j                  |      }|r|j                  r.|j                  s"|j                  |_        |j                  |_        t        t        |j                  |j                  z               |_        t        t        |j                  |j                  z               |_        t        t        |j                  |j                  z               |_        |xj                  |j                  z  c_        |}y|dk(  ryt        |j                        j!                         | _        dj%                  |j                  D cg c]  }d|z  j'                          c}      | _        |j*                  | _        yt        |t        t,        f      r=t        |j                  t        t,        f      sJ dt/        |j                        z         || j                  |<   yc c}w )a  Add or update the message with the specified ID.

        >>> catalog = Catalog()
        >>> catalog[u'foo'] = Message(u'foo')
        >>> catalog[u'foo']
        <Message u'foo' (flags: [])>

        If a message with that ID is already in the catalog, it is updated
        to include the locations and flags of the new message.

        >>> catalog = Catalog()
        >>> catalog[u'foo'] = Message(u'foo', locations=[('main.py', 1)])
        >>> catalog[u'foo'].locations
        [('main.py', 1)]
        >>> catalog[u'foo'] = Message(u'foo', locations=[('utils.py', 5)])
        >>> catalog[u'foo'].locations
        [('main.py', 1), ('utils.py', 5)]

        :param id: the message ID
        :param message: the `Message` object
        zexpected a Message objectr3   r   z# %szExpected sequence but got %sN)r@   r   r   rD   r   r   r5   r4   r6   r7   r   r8   r>   r?   r:   r   itemsr   r   rstripr   rv   ry   rJ   )rE   r4   messager   currentcs         r.   __setitem__zCatalog.__setitem__F  s   , '7+H-HH+mmB0..$$S)##G,@,@$ZZ
!( $Xg.?.?.5.?.?/@ &A !BG$('2G2G292G2G3H *I %JG!$('2G2G292G2G3H *I %JG!MMW]]*MG2X 3GNN C I I KD"&))070E0E-Gqfqj-@-@-B -G #HD DJ"tUm,!'..4-@ J2T'..5IIJ@")DNN3-Gs   Hc
                 J    t        ||t        |      ||||||		      }
|
| |<   |
S )at  Add or update the message with the specified ID.

        >>> catalog = Catalog()
        >>> catalog.add(u'foo')
        <Message ...>
        >>> catalog[u'foo']
        <Message u'foo' (flags: [])>

        This method simply constructs a `Message` object with the given
        arguments and invokes `__setitem__` with that object.

        :param id: the message ID, or a ``(singular, plural)`` tuple for
                   pluralizable messages
        :param string: the translated message string, or a
                       ``(singular, plural)`` tuple for pluralizable messages
        :param locations: a sequence of ``(filename, lineno)`` tuples
        :param flags: a set or sequence of flags
        :param auto_comments: a sequence of automatic comments
        :param user_comments: a sequence of user comments
        :param previous_id: the previous message ID, or a ``(singular, plural)``
                            tuple for pluralizable messages
        :param lineno: the line number on which the msgid line was found in the
                       PO file, if any
        :param context: the message context
        )rC   rD   )r   r7   )rE   r4   r6   r8   r:   r>   r?   rB   rC   rD   r   s              r.   r<   zCatalog.addx  s6    6 "fd9oum'V")+ Rr0   c              #      K   | j                   j                         D ]  }|j                  |       }|s||f  yw)aB  Run various validation checks on the translations in the catalog.

        For every message which fails validation, this method yield a
        ``(message, errors)`` tuple, where ``message`` is the `Message` object
        and ``errors`` is a sequence of `TranslationError` objects.

        :rtype: ``iterator``
        )rp   N)r   valuesrt   )rE   r   rq   s      r.   rt   zCatalog.check  sA      ~~,,. 	&G]]4]0Fvo%	&s   2>	>c                 X    | j                   j                  | j                  ||            S )zReturn the message with the specified ID and context.

        :param id: the message ID
        :param context: the message context, or ``None`` for no context
        )r   r   r   )rE   r4   rD   s      r.   r   zCatalog.get  s$     ~~!!$--G"<==r0   c                 `    | j                  ||      }|| j                  v r| j                  |= yy)zDelete the message with the specified ID and context.

        :param id: the message ID
        :param context: the message context, or ``None`` for no context
        Nr   rE   r4   rD   r   s       r.   r   zCatalog.delete  s1     mmB($.. s# !r0   c                 *     j                   j                         t                _         g }|s=D ci c]2  }|r.|   j                  r j	                  |      |   j
                  4 }}t                fd}|D ]  }|j                  s j	                  |j                  |j
                        }	|	v r |||	|	       E|slt        |	t              r|	d   }
n|	}
t        |
j                         j                         |j                         d      }|r|d   }||   }|||f} ||||	       | |j                  <    D ]  }|s|vs
|    j                  |<    |r|j                   _        |j                    _        yc c}w )a  Update the catalog based on the given template catalog.

        >>> from babel.messages import Catalog
        >>> template = Catalog()
        >>> template.add('green', locations=[('main.py', 99)])
        <Message ...>
        >>> template.add('blue', locations=[('main.py', 100)])
        <Message ...>
        >>> template.add(('salad', 'salads'), locations=[('util.py', 42)])
        <Message ...>
        >>> catalog = Catalog(locale='de_DE')
        >>> catalog.add('blue', u'blau', locations=[('main.py', 98)])
        <Message ...>
        >>> catalog.add('head', u'Kopf', locations=[('util.py', 33)])
        <Message ...>
        >>> catalog.add(('salad', 'salads'), (u'Salat', u'Salate'),
        ...             locations=[('util.py', 38)])
        <Message ...>

        >>> catalog.update(template)
        >>> len(catalog)
        3

        >>> msg1 = catalog['green']
        >>> msg1.string
        >>> msg1.locations
        [('main.py', 99)]

        >>> msg2 = catalog['blue']
        >>> msg2.string
        u'blau'
        >>> msg2.locations
        [('main.py', 100)]

        >>> msg3 = catalog['salad']
        >>> msg3.string
        (u'Salat', u'Salate')
        >>> msg3.locations
        [('util.py', 42)]

        Messages that are in the catalog but not in the template are removed
        from the main collection, but can still be accessed via the `obsolete`
        member:

        >>> 'head' in catalog
        False
        >>> list(catalog.obsolete.values())
        [<Message 'head' (flags: [])>]

        :param template: the reference catalog, usually read from a POT file
        :param no_fuzzy_matching: whether to use fuzzy matching of message IDs
        c                 4   | j                         } d}||k7  rld}j                  |       j                  |      }t        |j                  t
              r|j                  g| _        n-t        |j                        | _        nj                  |d       }|j                  | _	        r#t        t        |j                              | _        t        | j                  t        t        f      rt        | j                  t        t        f      s;d}t        | j                  gdgt        | j                        dz
  z  z         | _	        nt        | j                        	j                  k7  rid}t        | j                  d t        |j                               | _	        n6t        | j                  t        t        f      rd}| j                  d   | _	        | xj                  |j                  z  c_        |r| xj                  dhz  c_        | 	| j                  <   y )NFTr3   r   r   rv   )rk   r<   r   r@   r4   rA   rB   r7   popr6   r   r?   ry   r   r   r:   )
r   oldkeynewkeyrv   oldmsgfuzzy_matcheskeep_user_commentsmessages	remainingrE   s
        r.   _mergezCatalog.update.<locals>._merge  s   mmoGE!!&)!f-fii-+199+G'*.vyy/G'"vt4#]]GN!(,Xf6J6J-K(L%'**tUm4!'..4-@ E%* (SES_q5H,IJ&GN (D,<,<< E%*7>>:M3v}};M+N%OGNGNNT5M:!(!2MMV\\)M(+&Dr0   r   r   N)r   r	   r   r6   r   rD   r9   r4   r@   ry   r   r   stripkeysr   r   r   )rE   templateno_fuzzy_matchingupdate_header_commentr
  fuzzy_candidatesmsgidr  r   r   matchkeymatchesr  newctxtr	  r  r  s   `   `         @@@r.   updatezCatalog.update  s   j >>MMO	$   & 8E?3I3I e$huo&=&==    !	' !	'F   	/GzzmmGJJ@(?7C-,%c51'*1vH'*H"3HNN4D4J4J4L4D4I4I4KQ#P"%,QZF&6v&>G&2)/"7FC8$'.D$-	/0  	8E E$>'0'7e$	8 ! #+"9"9D &33Y s   7Fc                 L    |}t        |t        t        f      r|d   }|||f}|S )zThe key for a message is just the singular ID even for pluralizable
        messages, but is a ``(msgid, msgctxt)`` tuple for context-specific
        messages.
        r   )r@   r7   ry   r  s       r.   r   zCatalog._key_forC  s4    
 cD%=)Q%C.C
r0   c                 b   t        |t              sJ | j                  j                         |j                  j                         z  D ];  }| j	                  |      }|j	                  |      }|||j                  |      r; y t        | j                        t        |j                        k(  S )z\Checks if catalogs are identical, taking into account messages and
        headers.
        F)r@   r   r   r  r   rg   dictr   )rE   rR   r   	message_1	message_2s        r.   rg   zCatalog.is_identicalO  s     %)))>>&&(5??+?+?+AA 	CI		#I!$ --i8	 D%%&$u/A/A*BBBr0   )r   strict)Nr   r   r   r   r   NNri   )FFT)$rK   r   r   r   DEFAULT_HEADERrF   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rM   r   r   r   r<   rt   r   r   r  r   rg   r   r0   r.   r   r      s6   ."4td$(#TT	8!tk*' k;/F !78& 13F M 	NB@G@ -/@ 1G 1	Lf ! !  ! !$ 	P 	P3#&H0*d JLCGB&>$H4T
Cr0   r   )'r   r   cgir   collectionsr   r   r   r   difflibr   emailr   r	   babelr
   r   
babel.corer   r   babel.datesr   babel.messages.pluralsr   
babel.utilr   r   r   r   __all__compileVERBOSEr|   r/   r   	Exceptionr   r  r   r   r0   r.   <module>r-     s    
  # , % %  ( 1 ' - C C
4 

 	 ZZ	<N; N;b%y %
x	C x	Cr0   