kfUdZddlmZddlZddlZddlmZddlmZm Z ddl m Z ddl m Z ddl mZdd lmZdd lmZdd lmZdd lmZmZdd lmZddlmZddlmZmZm Z m!Z!er!ddl"m#Z#e$e%e$dfze&e$zZ'de(d<gdZ)d'dZ*ej+dej,Z-d(dZ.GddZ/Gd d!e0Z1d"Z2d)d$Z3Gd%d&Z4dS)*z babel.messages.catalog ~~~~~~~~~~~~~~~~~~~~~~ Data structures for message catalogs. :copyright: (c) 2013-2023 by the Babel Team. :license: BSD, see LICENSE for more details. ) annotationsN) OrderedDict)IterableIterator)copy)SequenceMatcher)message_from_string)nlargest) TYPE_CHECKING) __version__)LocaleUnknownLocaleError)format_datetime) get_plural)LOCALTZFixedOffsetTimezone_cmpdistinct) TypeAlias.r _MessageID)MessageCatalogTranslationError333333?c|dkstd|d|cxkrdksntd|g}td}|||D]}||||krY||krA||kr)|||ft||}d|DS) 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. rzn must be > 0: gg?zcutoff must be in [0.0, 1.0]: F)autojunkcg|]\}}|Sr).0scorexs v/builddir/build/BUILD/imunify360-venv-2.3.5/opt/imunify360/venv/lib/python3.11/site-packages/babel/messages/catalog.py z%get_close_matches..:s % % %(%A % % %) ValueErrorrset_seq2set_seq1real_quick_ratio quick_ratioratioappendr )word possibilitiesncutoffresultsr"s r#get_close_matchesr3#s  q550100111 &    C    D&DDEEE F'''AJJt ** 1    6 ) ) ==??f $ $ 7799   MM17799a. ) ) )a F % %f % % %%r%z \% (?:\(([\w]*)\))? ( [-#0\ +]?(?:\*|[\d]+)? (?:\.(?:\*|[\d]+))? [hlL]? ) ([diouxXeEfFgGcrs%]) valuestrreturndatetime.datetimectjd|}tj|dd}|d}||d|dd}}|dd|dd}}t |d}t |} t |} | d z} | | z } | |z} t | }|| }|S) Nz+^(?P.*?)(?P[+-]\d{4})?$datetimez%Y-%m-%d %H:%Mtzoffsetr1<tzinfo)rematchr9strptimegroupintrreplace) r4rBdtr: plus_minus_sresthours_offset_s mins_offset_s plus_minus hours_offset mins_offsetnet_mins_offsets r#_parse_datetime_headerrPIs HCU K KE   # #EKK $;$;=M N NB{{:&&H%a[(122,d (,RaR$qrr( L+++,, >** -(( '+;&:%'77ZZxZ ( ( Ir%ceZdZdZ d-d.dZd/dZd0dZd1dZd1dZd1d Z d1d!Z d1d"Z d1d#Z d2d$Z d3d%Zd4d5d)Zed6d*Zed6d+Zed6d,ZdS)7rz0Representation of a single message in a catalog.rNidrstring_MessageID | None locationsIterable[tuple[str, int]]flags Iterable[str] auto_comments user_comments previous_idlineno int | Nonecontext str | Noner6Nonec "||_|s |jrd}||_tt ||_t ||_|r"|jr|j dn|j dtt ||_ tt ||_ t|tr |g|_nt||_||_| |_dS)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 )rRrRz python-formatN)rS pluralizablerTlistrrVsetrX python_formatadddiscardrZr[ isinstancer5r\r]r_) selfrSrTrVrXrZr[r\r]r_s r#__init__zMessage.__init__js8 $+ F hy1122ZZ  0$$ 0 JNN? + + + + J   / / /!(="9"9::!(="9"9:: k3 ' ' 1 +}D  #K00D   r%r5cldt|jd|jdt|jdS)N< z (flags: z)>)type__name__rSrdrXrjs r#__repr__zMessage.__repr__s8S4::&SSSST$*=M=MSSSSr%otherobjectrEcLd}t||||S)z0Compare Messages, taking into account plural idsct|tr|jr|jd|jpdfS|j|jpdfS)NrrR)rirrcrSr_)objs r#values_to_comparez*Message.__cmp__..values_to_comparesJ#w'' 4C,< 4vay#+"33363;,", ,r%)r)rjrsrxs r#__cmp__zMessage.__cmp__s; - - -%%d++->->u-E-EFFFr%boolc4||dkSNrryrjrss r#__gt__zMessage.__gt__||E""Q&&r%c4||dkSr|r}r~s r#__lt__zMessage.__lt__rr%c4||dkSr|r}r~s r#__ge__zMessage.__ge__||E""a''r%c4||dkSr|r}r~s r#__le__zMessage.__le__rr%c4||dkSr|r}r~s r#__eq__zMessage.__eq__rr%c4||dkSr|r}r~s r#__ne__zMessage.__ne__rr%cPt|tsJ|j|jkS)z[Checks whether messages are identical, taking into account all properties. )rir__dict__r~s r# is_identicalzMessage.is_identicals)%)))))}..r%cttt|j|j|j|j|j|j|j |j |j f SN) rmaprrSrTrVrXrZr[r\r]r_rqs r#clonez Message.clonesND47DK#':t/A#'#5t7G#'; #>??@ @r%catalogCatalog | Nonelist[TranslationError]cddlm}g}|D];} |||#t$r}||Yd}~4d}~wwxYw|S)aRun 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.checkersrrr,)rjrrerrorscheckeres r#checkz Message.checks 544444)+ ! !G !&&&&# ! ! ! a         ! s  A?Acd|jvS)aWhether the translation is fuzzy. >>> Message('foo').fuzzy False >>> msg = Message('foo', 'foo', flags=['fuzzy']) >>> msg.fuzzy True >>> msg :type: `bool`fuzzyrXrqs r#rz Message.fuzzys$*$$r%cDt|jttfS)zWhether the message is plurizable. >>> Message('foo').pluralizable False >>> Message(('foo', 'bar')).pluralizable True :type: `bool`)rirSrdtuplerqs r#rczMessage.pluralizables$'D%=111r%c|j}t|ttfs|g}t d|DS)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`c3JK|]}t|VdSr) PYTHON_FORMATsearch)r rSs r# z(Message.python_format..s0::=''++::::::r%)rSrirdrany)rjidss r#rfzMessage.python_formatsEg#e}-- %C::c::::::r%)rRrrrrrNN)rSrrTrUrVrWrXrYrZrYr[rYr\rr]r^r_r`r6rar6r5)rsrtr6rE)rsrtr6rz)rsrr6rz)r6rr)rrr6r)r6rz)rp __module__ __qualname____doc__rkrrryrrrrrrrrrpropertyrrcrfrr%r#rrgs:: %'/1!')')"$!"-----^TTTTGGGG''''''''((((((((((((((((////@@@@ & % % %X % 2 2 2X 2 ; ; ;X ; ; ;r%rceZdZdZdS)rz_Exception thrown by translation checkers when invalid message translations are encountered.N)rprrrrr%r#rrs%%%%r%rz# Translations template for PROJECT. # Copyright (C) YEAR ORGANIZATION # This file is distributed under the same license as the PROJECT project. # FIRST AUTHOR , YEAR. #dict[str, str]cnddlm}|}||d<t|S)Nr)r content-type) email.messagerdict get_params)r4rms r#parse_separated_headerrs?%%%%%% AAn    r%c eZdZdZddeddddddddddf d]dZd^dZd_dZd`dZe eeZ e eZ dadZ dbd!Z e e e d"#Zdcd%Zddded,Zdfd/Ze eed0#Ze dgd2Ze dad3Ze dad4Zdhd7Zdgd8Zdid:Zdad;Zdjd<Zdkd>Zdld@Z dmdndMZdodOZdpdqdQZdpdrdRZ dsdtdXZ!dpdudZZ"dvd\Z#dS)wrz$Representation of a message catalog.NTlocalestr | Locale | Nonedomainr`header_commentprojectversioncopyright_holdermsgid_bugs_address creation_datedatetime.datetime | str | None revision_date6datetime.datetime | datetime.time | float | str | Nonelast_translator language_teamcharsetrrzr6rac||_||_||_t|_|pd|_|pd|_|pd|_|pd|_| pd|_ | pd|_ | pd|_ |%tj t}nzLANGUAGE utf-8Nr?zYEAR-MO-DA HO:MI+ZONE)rr_header_commentr _messagesrrrrrrrr9nowrrir@rFrrrobsolete _num_plurals _plural_expr)rjrrrrrrrrrrrrrs r#rkzCatalog.__init__s[H  -FQmm+) +) 0 BN"4"G.M2M<*D.D:)'  $-11'::MM  x'8 9 9 B-BV B)111AAM*  3MM  x'8 9 9 B-BV B)111AAM* FQ]]   r%Locale | str | Nonech|d|_d|_dSt|trt ||_||_dSt|trHt ||_ tj||_n#t $r d|_YnwxYwdStd|)NzD`locale` must be a Locale, a locale identifier string, or None; got )_locale_identifier_localerir r5parser TypeErrorrjrs r# _set_localezCatalog._set_locale_s >&*D #DL F ff % % &)&kkD #!DL F fc " " &)&kkD # $%|F33 % $ $ $#  $ Fi_eiijjjs/B BB Locale | Nonec|jSr)rrqs r# _get_localezCatalog._get_localets |r%c|jSr)rrqs r#_get_locale_identifierzCatalog._get_locale_identifierws &&r%r5c |j}tjtd}t |jdr|jd}|d|jd|j d|d|j }|j r |j j n|j }|r|d|d}|S) Nz%YstrftimerrYEARrzTranslations templatez translations)rr9rrrhasattrrrFrrrr english_namelocale_identifier)rjcommentyear locale_names r#_get_header_commentzCatalog._get_header_comment}s& $$W--66t<< 4%z 2 2 5%..t44D//)T\::!')T\::!'&$//!'.$2GHH 48;Zt{//DDZ  ^oo&=+?\?\?\]]Gr%rTc||_dSr)r)rjrTs r#_set_header_commentzCatalog._set_header_comments%r%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 , .... # 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` )doclist[tuple[str, str]]c tg}|d|jd|jf|d|jf|dt |jddft |jtjtj ttfr-|dt |jddfn|d|jf|d |j f|j r)|d t|j f|j rLd |jvrC|d |jd t|j fn|d |jf|j|d |jf|d|dd|jf|d|ddt(df|S)NzProject-Id-VersionrnzReport-Msgid-Bugs-TozPOT-Creation-Datezyyyy-MM-dd HH:mmZen)rzPO-Revision-DatezLast-TranslatorLanguageLANGUAGEz Language-Teamz Plural-Forms)z MIME-Versionz1.0z Content-Typeztext/plain; charset=)zContent-Transfer-Encoding8bitz Generated-ByzBabel  )r,rrrrrrirr9timerEfloatrrr5rrFr plural_formsrr)rjheaderss r#_get_mime_headerszCatalog._get_mime_headerssq)+,.N.N .N.NOPPP.0GHIII+'(:,?NNNO P P P P NN.0BC D D D)4+?@AAA  ! F NNJD,B(C(CD E E E  ! BzT5G'G'G NNO .66z7:4;Q7R7RTTU V V V V NNOT-?@ A A A ; " NNND,=> ? ? ?.///(Mt|(M(MNOOO<===(<(<(<(<=>>>r%rstrictr2 str | bytesencodingrct|tr|St|tr|||St|Sr)rir5bytesdecode)rjr2rrs r# _force_textzCatalog._force_textsJ a   H a   .88Hf-- -1vv r%rIterable[tuple[str, str]]c|D]\}}|||j}|||j}|dkrE|d}d|dd|_|d|_|dkr||_|dkr||_|dkr,| dd }| ||d kr||_ |d kr4t|}d |vr|d |_1|d krWtd|}t|dd|_|dd|_|dkrt#||_|dkrd|vrt#||_dS)N)rzproject-id-versionrnzreport-msgid-bugs-tozlast-translatorlanguage-_z language-teamrrz plural-formsz ;npluralsr<plural(n != 1)zpot-creation-datezpo-revision-dater)rlowerrsplitjoinrrrrrFrrrrEgetrrrPrr)rjrnamer4partsparamss r#_set_mime_headerszCatalog._set_mime_headerss" G GKD%##DJJLL4<#HHD$$UT\$BBE+++ C(("xxcrc 33 $Ry ///*/''***',$$## c3//  ''''((%*""''/66&&#))#4#:#:#<#>> 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 Language-Team: LANGUAGE 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 ', ... language_team='de_DE ') >>> 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 Language: de_DE Language-Team: de_DE 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` rEcr|j*d}|jrt|jd}||_|jS)zThe number of plurals used by the catalog or locale. >>> Catalog(locale='en').num_plurals 2 >>> Catalog(locale='ga').num_plurals 5 :type: `int`Nr<r)rrr)rjnums r# num_pluralszCatalog.num_plurals(sA   $C{ 1 --a0 #D   r%cr|j*d}|jrt|jd}||_|jS)aWThe 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`Nrr;)rrr)rjexprs r# plural_exprzCatalog.plural_expr9sA   $D{ 2!$+..q1 $D   r%c(d|jd|jdS)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=;)rrrqs r#rzCatalog.plural_formsLs$J4+IId6FIIIIr%rSrc:|||jvS)z?Return whether the catalog has a message with the specified ID._key_forrrjrSs r# __contains__zCatalog.__contains__Xs}}R  DN22r%c*t|jS)zeThe number of messages in the catalog. This does not include the special ``msgid ""`` entry.)lenrrqs r#__len__zCatalog.__len__\s4>"""r%Iterator[Message]c#Kg}|jD]\}}||d| t}|jr|dhz}t dd||V|jD]}|j|VdS)zIterates through all the entries in the catalog, in the order they were added, yielding a `Message` object for every entry. :rtype: ``iterator``z: rrRrrN) mime_headersr,rerrr r)rjbufr r4rXkeys r#__iter__zCatalog.__iter__bs , + +KD% JJ$))%)) * * * * :  gY Eb$))C..666666> & &C.% % % % % & &r%cld}|jr d|j}dt|jd|j|dS)NrRrnrm>)rrorprrs r#rrzCatalog.__repr__qsI ; '&&&FA4::&AAAAAAAr%c0||dS)z)Delete the message with the specified ID.N)deleters r# __delitem__zCatalog.__delitem__ws Br%rc,||S)zUReturn the message with the specified ID. :param id: the message ID )r rs r# __getitem__zCatalog.__getitem__{s xx||r%messagect|ts Jd|||j}|j|}|r|jr|js|j|_|j|_tt|j |j z|_ tt|j |j z|_ tt|j |j z|_ |xj|jzc_|}dS|dkrbt|j|_dd|j D|_|j|_dSt|tt*fr@t|jtt*fsJdt-|j||j|<dS)aAdd or update the message with the specified ID. >>> catalog = Catalog() >>> catalog[u'foo'] = Message(u'foo') >>> catalog[u'foo'] 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 zexpected a Message objectrRrc<g|]}d|S)z# )rstrip)r cs r#r$z'Catalog.__setitem__..s(,^,^,^1X!XX__->->,^,^,^r%zExpected sequence but got N)rirrr_rr rcrSrTrdrrVrZr[rXr itemsr"r rrrro)rjrSr-r$currents r# __setitem__zCatalog.__setitem__s,'7++HH-HHH+mmB00.$$S))  *# 0G,@ 0$Z !( $Xg.?.5.?/@&A&A!B!BG $('2G292G3H*I*I%J%JG !$('2G292G3H*I*I%J%JG ! MMW] *MMGGG 2XX 3GN C C I I K KD "&)),^,^H],^,^,^"_"_D  DJJJ"tUm,, H!'.4-@@HHGgn1E1EGGHH@")DN3   r%rrUrVrWrXrYrZr[r\r]r^r_c Zt||t|||||||  } | ||<| S)atAdd or update the message with the specified ID. >>> catalog = Catalog() >>> catalog.add(u'foo') >>> catalog[u'foo'] 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 )r]r_)rrd) rjrSrTrVrXrZr[r\r]r_r-s r#rgz Catalog.addsCJ"fd9ooum'V")+++Rr%0Iterable[tuple[Message, list[TranslationError]]]c#~K|jD] }||}|r||fV!dS)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)`` )rN)rvaluesr)rjr-rs r#rz Catalog.checks[~,,.. & &G]]4]00F &vo%%% & &r%Message | Nonec^|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 )rr r)rjrSr_s r#r z Catalog.gets( ~!!$--G"<"<===r%cX|||}||jvr |j|=dSdS)zDelete the message with the specified ID and context. :param id: the message ID :param context: the message context, or ``None`` for no context NrrjrSr_r$s r#r)zCatalog.deletes< mmB(( $. s### ! r%Ftemplateno_fuzzy_matchingupdate_header_commentkeep_user_commentscjt_g}|sei}D]`}|r\|jrO|}|j}|} ||f|| <atd fd } |D]} | j rΉ| j | j}|vr| | ||;|st|tr |d } n|} t| | d } | r'| d } || \}}|||f}| | ||| | j <؉D]}|s|vr|j|<|r |j_|j_d S) aUpdate the catalog based on the given template catalog. >>> from babel.messages import Catalog >>> template = Catalog() >>> template.add('green', locations=[('main.py', 99)]) >>> template.add('blue', locations=[('main.py', 100)]) >>> template.add(('salad', 'salads'), locations=[('util.py', 42)]) >>> catalog = Catalog(locale='de_DE') >>> catalog.add('blue', u'blau', locations=[('main.py', 98)]) >>> catalog.add('head', u'Kopf', locations=[('util.py', 33)]) >>> catalog.add(('salad', 'salads'), (u'Salat', u'Salate'), ... locations=[('util.py', 38)]) >>> 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()) [] :param template: the reference catalog, usually read from a POT file :param no_fuzzy_matching: whether to use fuzzy matching of message IDs r-roldkeytuple[str, str] | strnewkeyr6rac*|}d}||krrd}||}|Jt|jt r|jg|_n4t|j|_n|d}|J|j |_ r&tt|j |_ t|jttfrt|j ttfs9d}t|j gdgt|jdz zz|_ nt|j  jkr5d}t|j dt|j |_ n5t|j ttfrd}|j d|_ |xj|jzc_|r|xjdhzc_| |j<dS)NFTrRr;rr)rrgr rirSr5r\rdpoprTrr[rrrrX) r-rBrDroldmsg fuzzy_matchesr@messages remainingrjs r#_mergezCatalog.update.._mergeIsmmooGE!!&)))!f--)))fi--:+19+G''*.vy//G''"vt44)))#]GN! M(,Xf6J-K-K(L(L%'*tUm44 3!'.4-@@P E%* (RDC OOa4G,HI&&GNN((D,<<< E%*7>:M3v};M;M:M+N%O%OGNGNT5M:: 3!(!2 MMV\ )MM + '* &D   r%rr;N)r-rrBrCrDrCr6ra)rrrrTrr_rstriprerSrirr3keysrrr)rjr=r>r?r@fuzzy_candidatesmsgidr$ctxt modified_keyrKr-matchkeymatchesrDnewctxtrHrIrJs` ` @@@r#updatezCatalog.updatesNv>MMOO $  A! ! A AAXe_3A--..C#E?2D#&99;;#4#4#6#6L694[$\2 # '# '# '# '# '# '# '# '# '# 'J  / /Gz /mmGJ@@(??F7C----,%%c511+'*1vHH'*H"3HNN4D4D4J4J4L4L4D4I4I4K4KQ#P#P"%+21:L.>|.LOFG&2)/"F7FC888$'.D$ 8 8E  8E$>$>'0'7 e$  :#+"9D &3r%rCc^|}t|ttfr|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)rirdrr<s r#rzCatalog._key_fors<  cD%= ) ) Q%C  .C r%rsc|t|tsJ|j|jzD]H}||}||}||||sdSIt |jt |jkS)z\Checks if catalogs are identical, taking into account messages and headers. NF)rirrrMr rrr")rjrsr$ message_1 message_2s r#rzCatalog.is_identicals%)))))>&&((5?+?+?+A+AA  C I #I!$ --i88%uu%D%&&$u/A*B*BBBr%)rrrr`rr`rr`rr`rr`rr`rrrrrr`rr`rr`rrzr6ra)rrr6ra)r6r)r6r`r)rTr`r6ra)r6r)rr)r2rrr5rr5r6r5)rrr6ra)r6rE)rSrr6rz)r6r )rSrr6ra)rSrr6r)rSrr-rr6ra)NrrrrrNN)rSrrTrUrVrWrXrYrZrYr[rYr\rr]r^r_r`r6r)r6r6r)rSrr_r`r6r9)rSrr_r`r6ra)FFT) r=rr>rzr?rzr@rzr6ra)rSrr_r`r6rC)rsrr6rz)$rprrrDEFAULT_HEADERrkrrrrrrrrrrrrr"rrrrrr%rrr*r,r4rgrr r)rUrrrr%r#rrsJ..'+!%3""'+)-8>>>>$$$$$#(&+#' S4S4S4S4S4j     CCCCCCr%r)rr)r4r5r6r7)r4r5r6r)5r __future__rr9rA collectionsrcollections.abcrrrdifflibremailr heapqr typingr babelr r babel.corer r babel.datesrbabel.messages.pluralsr babel.utilrrrrtyping_extensionsrr5rrdr__annotations____all__r3compileVERBOSErrPr ExceptionrrZrrrr%r#rms#""""" ######........######%%%%%% ((((((11111111''''''------CCCCCCCCCCCC>++++++%S/1DI=J==== 4 4 4&&&&4 Z