o
    mi                     @  sl  U 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l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 erwddl m!Z! e"e#e"df B e$e" B Z%de&d< g dZ'd6ddZ(e)dej*Z+d7ddZ,d8d"d#Z-G d$d% d%Z.G d&d' d'e/Z0d(Z1d9d*d+Z2d:d;d2d3Z3G d4d5 d5Z4dS )<z
babel.messages.catalog
~~~~~~~~~~~~~~~~~~~~~~

Data structures for message catalogs.

:copyright: (c) 2013-2026 by the Babel Team.
:license: BSD, see LICENSE for more details.
    )annotationsN)IterableIterator)copy)SequenceMatcher)message_from_string)nlargest)	Formatter)TYPE_CHECKING)__version__)LocaleUnknownLocaleError)format_datetime)
get_plural)LOCALTZ_cmp)	TypeAlias.r   
_MessageID)DEFAULT_HEADERPYTHON_FORMATCatalogMessageTranslationError   333333?c                 C  s   |dkst d|d|  krdksn t d|g }tdd}||  |D ]"}|| | |krM| |krM| |krM|| |f q+t||}dd	 |D S )
zA modified version of ``difflib.get_close_matches``.

    It just passes ``autojunk=False`` to the ``SequenceMatcher``, to work
    around https://github.com/python/cpython/issues/90825.
    r   zn must be > 0: g        g      ?zcutoff must be in [0.0, 1.0]: F)Zautojunkc                 S  s   g | ]\}}|qS  r   ).0Zscorexr   r   P/home/kim/smarthome/.venv/lib/python3.10/site-packages/babel/messages/catalog.py
<listcomp>D   s    z%get_close_matches.<locals>.<listcomp>)	
ValueErrorr   Zset_seq2Zset_seq1Zreal_quick_ratioZquick_ratioratioappendr   )wordpossibilitiesncutoffresultsr   r   r   r   get_close_matches+   s    



r)   z
    \%
        (?:\(([\w]*)\))?
        (
            [-#0\ +]?(?:\*|[\d]+)?
            (?:\.(?:\*|[\d]+))?
            [hlL]?
        )
        ([diouxXeEfFgGcrs%])
stringstrreturnboolc                 C  sR   d| vrdS t  }zd}|| D ]
}|d d urd}qW |S  ty(   Y dS w )N{F   T)r	   parser    )r*   fmtZfield_name_seentr   r   r   _has_python_brace_formatV   s   r3   valuedatetime.datetimec                 C  s   t d| }tj|dd}|d}|d ura|d |dd  }}|d d |dd  }}t| d}t|}	t|}
|	d	 }||
7 }||9 }tjtj|d
d|dd}|j|d}|S )Nz+^(?P<datetime>.*?)(?P<tzoffset>[+-]\d{4})?$datetimez%Y-%m-%d %H:%Mtzoffsetr   r/      1<   )minuteszEtc/GMTz+d)offsetnametzinfo)	rematchr6   strptimegroupinttimezone	timedeltareplace)r4   rA   dtr7   Zplus_minus_srestZhours_offset_sZmins_offset_sZ
plus_minusZhours_offsetZmins_offsetZnet_mins_offsetr   r   r   _parse_datetime_headeri   s$   


rJ   c                   @  s   e Zd ZdZ								d>d?ddZd@ddZdAddZdBd!d"ZdBd#d$ZdBd%d&Z	dBd'd(Z
dBd)d*ZdBd+d,ZdCd-d.ZdDd/d0ZdEdFd4d5ZedGd6d7ZedGd8d9ZedGd:d;ZedGd<d=ZdS )Hr   z0Representation of a single message in a catalog. r   Nidr   r*   _MessageID | None	locationsIterable[tuple[str, int]]flagsIterable[str]auto_commentsuser_commentsprevious_idlineno
int | Nonecontext
str | Noner,   Nonec
           
      C  s   || _ |s
| jr
d}|| _|rtt|ng | _t|| _|r*| j	r*| j
d n| jd |r<| jr<| j
d n| jd |rKtt|ng | _|rWtt|ng | _|rlt|trf|g| _n	t|| _ng | _|| _|	| _dS )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
        )rK   rK   zpython-formatzpython-brace-formatN)rL   pluralizabler*   listdictfromkeysrN   setrP   python_formatadddiscardpython_brace_formatrR   rS   
isinstancer+   rT   rU   rW   )
selfrL   r*   rN   rP   rR   rS   rT   rU   rW   r   r   r   __init__   s*   






zMessage.__init__r+   c                 C  s&   dt | j d| jdt| jdS )N< z	 (flags: z)>)type__name__rL   r[   rP   rd   r   r   r   __repr__   s   &zMessage.__repr__otherobjectrD   c                 C  s   dd }t || ||S )z0Compare Messages, taking into account plural idsc                 S  s4   t | tr| jr| jd | jpdfS | j| jpdfS )Nr   rK   )rc   r   rZ   rL   rW   )objr   r   r   values_to_compare   s   z*Message.__cmp__.<locals>.values_to_compare)r   )rd   rl   ro   r   r   r   __cmp__   s   zMessage.__cmp__r-   c                 C  s   |  |dkS Nr   rp   rd   rl   r   r   r   __gt__      zMessage.__gt__c                 C  s   |  |dk S rq   rr   rs   r   r   r   __lt__   ru   zMessage.__lt__c                 C  s   |  |dkS rq   rr   rs   r   r   r   __ge__   ru   zMessage.__ge__c                 C  s   |  |dkS rq   rr   rs   r   r   r   __le__   ru   zMessage.__le__c                 C  s   |  |dkS rq   rr   rs   r   r   r   __eq__   ru   zMessage.__eq__c                 C  s   |  |dkS rq   rr   rs   r   r   r   __ne__   ru   zMessage.__ne__c                 C  s   t |tsJ | j|jkS )z[Checks whether messages are identical, taking into account all
        properties.
        )rc   r   __dict__rs   r   r   r   is_identical   s   zMessage.is_identicalc                 C  sH   t t| jt| jt| jt| jt| jt| jt| j| j	| j
d	S )N)	rL   r*   rN   rP   rR   rS   rT   rU   rW   )r   r   rL   r*   rN   rP   rR   rS   rT   rU   rW   rj   r   r   r   clone   s   zMessage.clonecatalogCatalog | Nonelist[TranslationError]c                 C  sZ   ddl m} g }|D ] }z|||  W q
 ty* } z|| W Y d}~q
d}~ww |S )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)Zbabel.messages.checkersr   r   r"   )rd   r~   r   errorscheckerer   r   r   check   s   
zMessage.checkc                 C  s
   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rP   rj   r   r   r   r   
  s   
zMessage.fuzzyc                 C  s   t | jttfS )zWhether the message is plurizable.

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

        :type:  `bool`)rc   rL   r[   tuplerj   r   r   r   rZ     s   
zMessage.pluralizablec                 C  s@   | j }t|ttfr|D ]
}t|r dS qdS tt|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`TF)rL   rc   r[   r   r   searchr-   rd   ZidsrL   r   r   r   r_   %  s   

zMessage.python_formatc                 C  s8   | j }t|ttfr|D ]	}t|r dS qdS t|S )zWhether the message contains Python f-string parameters.

        >>> Message('Hello, {name}!').python_brace_format
        True
        >>> Message(('One apple', '{count} apples')).python_brace_format
        True

        :type:  `bool`TF)rL   rc   r[   r   r3   r   r   r   r   rb   7  s   
zMessage.python_brace_format)rK   r   r   r   r   r   NN)rL   r   r*   rM   rN   rO   rP   rQ   rR   rQ   rS   rQ   rT   r   rU   rV   rW   rX   r,   rY   r,   r+   )rl   rm   r,   rD   )rl   rm   r,   r-   )rl   r   r,   r-   )r,   r   N)r~   r   r,   r   )r,   r-   )ri   
__module____qualname____doc__re   rk   rp   rt   rv   rw   rx   ry   rz   r|   r}   r   propertyr   rZ   r_   rb   r   r   r   r   r      s<    
6









r   c                   @  s   e Zd ZdZdS )r   z_Exception thrown by translation checkers when invalid message
    translations are encountered.N)ri   r   r   r   r   r   r   r   r   J  s    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.
#dict[str, str]c                 C  s&   ddl m} | }| |d< t| S )Nr   )r   content-type)email.messager   r\   
get_params)r4   r   mr   r   r   parse_separated_headerW  s   r   utf-8strictr(   str | bytesencodingr   c                 C  s,   t | tr| S t | tr| ||S t| S r   )rc   r+   bytesdecode)r(   r   r   r   r   r   _force_text`  s
   

r   c                   @  s  e Zd ZdZddeddddddddddfdrddZdsddZdtddZdudd Ze	eeZ
e	eZdvd"d#Zdwd%d&Ze	eed'd(Zdxd*d+Zdyd.d/Ze	eed0d(Ze	dzd2d3Ze	dvd4d5Ze	dvd6d7Zd{d:d;Zdzd<d=Zd|d?d@ZdvdAdBZd}dCdDZd~dFdGZddIdJZ		K	K	K	K	K		dddWdXZddZd[Zddd]d^Zddd_d`Z	a	a		dddgdhZ ddkdlZ!	dddmdnZ"ddpdqZ#dS )r   z$Representation of a message catalog.NTlocaleLocale | str | NonedomainrX   header_commentprojectversioncopyright_holdermsgid_bugs_addresscreation_datedatetime.datetime | str | Nonerevision_date6datetime.datetime | datetime.time | float | str | Nonelast_translatorlanguage_teamcharsetr   r-   r,   rY   c                 C  s   || _ || _|| _i | _|pd| _|pd| _|pd| _|pd| _|
p#d| _	 |p)d| _		 |p/d| _
|du r<tjt}nt|tjrK|jsK|jtd	}|| _|	du rUd
}	nt|	tjrd|	jsd|	jtd	}	|	| _|| _i | _d| _d| _dS )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>r   Nr>   zYEAR-MO-DA HO:MI+ZONE)r   r   _header_comment	_messagesr   r   r   r   r   r   r   r6   nowr   rc   r?   rG   r   r   r   obsolete_num_plurals_plural_expr)rd   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   re   k  s6   $







zCatalog.__init__c                 C  s   |d u rd | _ d | _d S t|trt|| _ || _d S t|tr<t|| _ z	t|| _W d S  ty;   d | _Y d S w td|)NzD`locale` must be a Locale, a locale identifier string, or None; got )_locale_identifier_localerc   r   r+   r0   r   	TypeErrorrd   r   r   r   r   _set_locale  s(   



zCatalog._set_localeLocale | Nonec                 C     | j S r   )r   rj   r   r   r   _get_locale     zCatalog._get_localec                 C  r   r   )r   rj   r   r   r   _get_locale_identifier  r   zCatalog._get_locale_identifierr+   c                 C  s   | j }tjtd}t| jdr| jd}|d| jd| j	d|d| j
}| jr4| jjn| j}|rB|d| d}|S )	Nz%Ystrftimer   r   YEARr   zTranslations templatez translations)r   r6   r   r   r   hasattrr   rG   r   r   r   r   Zenglish_namelocale_identifier)rd   commentyearZlocale_namer   r   r   _get_header_comment  s   

zCatalog._get_header_commentr*   c                 C  s
   || _ d S r   )r   )rd   r*   r   r   r   _set_header_comment  s   
zCatalog._set_header_commenta      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`
    )doclist[tuple[str, str]]c                 C  s  t | jtjtjttfrt| jddd}n| j}| j}| jr+d|v r+|	dt
| j}d| j d| j fd| jfdt| jdddfd	|fd
| jfg}| jrX|dt
| jf |d|f | jd url|d| jf |ddd| j fdddt dfg7 }|S )Nzyyyy-MM-dd HH:mmZen)r   LANGUAGEzProject-Id-Versionrg   zReport-Msgid-Bugs-TozPOT-Creation-DatezPO-Revision-DatezLast-TranslatorZLanguagezLanguage-TeamzPlural-Forms)zMIME-Versionz1.0zContent-Typeztext/plain; charset=)zContent-Transfer-Encoding8bitzGenerated-ByzBabel 
)rc   r   r6   timerD   floatr   r   r   rG   r+   r   r   r   r   r   r"   r   plural_formsr   r   )rd   r   r   headersr   r   r   _get_mime_headers	  s8   
zCatalog._get_mime_headersr   Iterable[tuple[str, str]]c                 C  sF  |D ]\}}t | | jd}t || jd}|dkr/|d}d|d d | _|d | _q|dkr7|| _q|dkr?|| _q|dkrQ|	dd	}| 
|pNd  q|d
krY|| _q|dkrmt|}d|v rl|d  | _q|dkrtd| }t|dd| _|dd| _q|dkrt|| _q|dkrd|vrt|| _qd S )N)r   zproject-id-versionrg   zreport-msgid-bugs-tozlast-translatorlanguage-_zlanguage-teamr   r   zplural-formsz ;Znpluralsr8   plural(n != 1)zpot-creation-datezpo-revision-dater   )r   lowerr   splitjoinr   r   r   r   rG   r   r   r   rD   getr   r   rJ   r   r   )rd   r   r=   r4   partsparamsr   r   r   _set_mime_headers+  s@   

zCatalog._set_mime_headersa      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
    >>> from datetime import datetime
    >>> 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`
    rD   c                 C  .   | j du r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`Nr8   r   )r   r   r   )rd   numr   r   r   num_plurals  s   

zCatalog.num_pluralsc                 C  r   )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`Nr   r/   )r   r   r   )rd   exprr   r   r   plural_expr  s   
zCatalog.plural_exprc                 C  s   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   rj   r   r   r   r     s   
zCatalog.plural_formsrL   r   c                 C  s   |  || jv S )z?Return whether the catalog has a message with the specified ID._key_forr   rd   rL   r   r   r   __contains__  s   zCatalog.__contains__c                 C  s
   t | jS )zeThe number of messages in the catalog.

        This does not include the special ``msgid ""`` entry.)lenr   rj   r   r   r   __len__  s   
zCatalog.__len__Iterator[Message]c                 c  sr    g }| j D ]\}}|| d|  qt }| jr |dhO }tdd||dV  | jD ]}| j| V  q.dS )zIterates through all the entries in the catalog, in the order they
        were added, yielding a `Message` object for every entry.

        :rtype: ``iterator``z: r   rK   r   r   N)mime_headersr"   r^   r   r   r   r   )rd   bufr=   r4   rP   keyr   r   r   __iter__  s   

zCatalog.__iter__c                 C  s4   d}| j rd| j  }dt| j d| j| dS )NrK   rg   rf   >)r   rh   ri   r   r   r   r   r   rk     s   zCatalog.__repr__c                 C  s   |  | dS )z)Delete the message with the specified ID.N)deleter   r   r   r   __delitem__  s   zCatalog.__delitem__r   c                 C  s
   |  |S )zUReturn the message with the specified ID.

        :param id: the message ID
        )r   r   r   r   r   __getitem__  s   
zCatalog.__getitem__messagec                 C  s0  t |ts	J d| ||j}| j|}|rZ|jr&|js&|j|_|j|_t	t
g |j|j|_t	t
g |j|j|_t	t
g |j|j|_| j|jO  _dS |dkrxt|j | _ddd |jD | _|j| _dS t |t	tfrt |jt	tfsJ dt|j || j|< dS )a  Add or update the message with the specified ID.

        >>> catalog = Catalog()
        >>> catalog['foo'] = Message('foo')
        >>> catalog['foo']
        <Message '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['foo'] = Message('foo', locations=[('main.py', 1)])
        >>> catalog['foo'].locations
        [('main.py', 1)]
        >>> catalog['foo'] = Message('foo', locations=[('utils.py', 5)])
        >>> catalog['foo'].locations
        [('main.py', 1), ('utils.py', 5)]

        :param id: the message ID
        :param message: the `Message` object
        zexpected a Message objectrK   r   c                 s  s    | ]
}d |   V  qdS )z# N)rstrip)r   cr   r   r   	<genexpr>  s    z&Catalog.__setitem__.<locals>.<genexpr>zExpected sequence but got N)rc   r   r   rW   r   r   rZ   rL   r*   r[   r\   r]   rN   rR   rS   rP   r   itemsr   r   r   r   r   rh   )rd   rL   r   r   currentr   r   r   __setitem__  s(   zCatalog.__setitem__r   rM   rN   rO   rP   rQ   rR   rS   rT   rU   rV   rW   c
                 C  s*   t ||t|||||||	d	}
|
| |< |
S )aq  Add or update the message with the specified ID.

        >>> catalog = Catalog()
        >>> catalog.add('foo')
        <Message ...>
        >>> catalog['foo']
        <Message '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
        )rU   rW   )r   r[   )rd   rL   r*   rN   rP   rR   rS   rT   rU   rW   r   r   r   r   r`     s   %zCatalog.add0Iterable[tuple[Message, list[TranslationError]]]c                 c  s0    | j  D ]}|j| d}|r||fV  qdS )a\  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: ``generator`` of ``(message, errors)``
        )r~   N)r   valuesr   )rd   r   r   r   r   r   r   B  s   	
zCatalog.checkMessage | Nonec                 C  s   | 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   )rd   rL   rW   r   r   r   r   P  s   zCatalog.getc                 C  s&   |  ||}|| jv r| j|= dS dS )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   rd   rL   rW   r   r   r   r   r   X  s   
zCatalog.deleteFtemplateno_fuzzy_matchingupdate_header_commentkeep_user_commentsupdate_creation_datec                   sJ  j  i _ i }|s-D ]}|r,| jr,|}| j}	||	f||< qt  d fdd	}
|D ]E}|jr|j|j}|v rU|
||| q=|s}t||	 d
}|r}|d }|| \}}|durv||f}|
||| q=||j< q=D ]}|s| vr| j
|< q|r|j_|r|j_dS dS )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', 'blau', locations=[('main.py', 98)])
        <Message ...>
        >>> catalog.add('head', 'Kopf', locations=[('util.py', 33)])
        <Message ...>
        >>> catalog.add(('salad', 'salads'), ('Salat', '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
        'blau'
        >>> msg2.locations
        [('main.py', 100)]

        >>> msg3 = catalog['salad']
        >>> msg3.string
        ('Salat', '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
        :param update_header_comment: whether to copy the header comment from the template
        :param keep_user_comments: whether to keep user comments from the old catalog
        :param update_creation_date: whether to copy the creation date from the template
        r   r   oldkeytuple[str, str] | strnewkeyr,   rY   c                   sd  |   } d}||kr/d} | |}|d usJ t|jtr(|jg| _nt|j| _n|d }|d us;J |j	| _	rM|j
rMtt|j
| _
t| jttfrt| j	ttfsqd}t| j	gdgt| jd   | _	n(t| j	jkrd}t| j	d t|j	 | _	nt| j	ttfrd}| j	d | _	|  j|jO  _|r|  jdhO  _| | j< d S )NFTrK   r/   r   r   )r}   r`   r   rc   rL   r+   rT   r[   popr*   rS   r\   r]   r   r   r   rP   )r   r  r  r   ZoldmsgZfuzzy_matchesr  messages	remainingrd   r   r   _merge  s@   


zCatalog.update.<locals>._merger/   r   N)r   r   r  r  r  r  r,   rY   )r   r   r*   r   rW   _to_fuzzy_match_keyr^   rL   r)   keysr   r   r   )rd   r  r  r  r  r  Zfuzzy_candidatesmsgidr   Zctxtr  r   matchesZmodified_keyr  Znewctxtr   r
  r   updateb  sT   ?

)
zCatalog.updater   r  c                 C  s$   t |tr
|d }n|}|  S )z?Converts a message key to a string suitable for fuzzy matching.r   )rc   r   r   strip)rd   r   Zmatchkeyr   r   r   r    s   

zCatalog._to_fuzzy_match_keyc                 C  s.   |}t |ttfr|d }|dur||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   N)rc   r[   r   r   r   r   r   r     s   	zCatalog._key_forrl   c                 C  sp   t |tsJ | j |j B D ]}| |}||}|du s*|du s*||s- dS qt| jt|jkS )z\Checks if catalogs are identical, taking into account messages and
        headers.
        NF)rc   r   r   r  r   r|   r\   r   )rd   rl   r   Z	message_1Z	message_2r   r   r   r|     s   

zCatalog.is_identical)r   r   r   rX   r   rX   r   rX   r   rX   r   rX   r   rX   r   r   r   r   r   rX   r   rX   r   rX   r   r-   r,   rY   )r   r   r,   rY   )r,   r   )r,   rX   r   )r*   rX   r,   rY   )r,   r   )r   r   r,   rY   )r,   rD   )rL   r   r,   r-   )r,   r   )rL   r   r,   rY   )rL   r   r,   r   )rL   r   r   r   r,   rY   )Nr   r   r   r   r   NN)rL   r   r*   rM   rN   rO   rP   rQ   rR   rQ   rS   rQ   rT   r   rU   rV   rW   rX   r,   r   )r,   r   r   )rL   r   rW   rX   r,   r   )rL   r   rW   rX   r,   rY   )FFTT)r  r   r  r-   r  r-   r  r-   r  r-   r,   rY   )r   r  r,   r+   )rL   r   rW   rX   r,   r  )rl   r   r,   r-   )$ri   r   r   r   r   re   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rk   r   r   r   r`   r   r   r   r  r  r   r|   r   r   r   r   r   h  s    
F





%
"$8






1
3 
r   )r   r   )r*   r+   r,   r-   )r4   r+   r,   r5   )r4   r+   r,   r   )r   r   )r(   r   r   r+   r   r+   r,   r+   )5r   
__future__r   r6   r@   collections.abcr   r   r   difflibr   emailr   heapqr   r*   r	   typingr
   Zbabelr   r   Z
babel.corer   r   Zbabel.datesr   Zbabel.messages.pluralsr   Z
babel.utilr   r   Ztyping_extensionsr   r+   r   r[   r   __annotations____all__r)   compileVERBOSEr   r3   rJ   r   	Exceptionr   r   r   r   r   r   r   r   r   <module>   sD    
 
	


! A
	