kf3W^dZddlmZddlZddlZddlmZddlmZddl m Z ddl m Z m Z ddlmZmZerdd lmZmZdd lmZdd lmZd=dZd=dZGddeZGddZGddZ d>d?d#Zejd$Zd=d%Z d@dAd+Z! dBdCd6Z"dDd<Z#dS)Ez babel.messages.pofile ~~~~~~~~~~~~~~~~~~~~~ Reading and writing of files in the ``gettext`` PO (portable object) format. :copyright: (c) 2013-2023 by the Babel Team. :license: BSD, see LICENSE for more details. ) annotationsN)Iterable) TYPE_CHECKING)Locale)CatalogMessage)_cmpwraptext)IOAnyStr) SupportsWrite)Literalstringstrreturnchd}tjd||ddS)zReverse `escape` the given string. >>> print(unescape('"Say:\\n \\"hello, world!\\"\\n"')) Say: "hello, world!" :param string: the string to unescape c`|d}|dkrdS|dkrdS|dkrdS|S)Nn t r )group)matchms u/builddir/build/BUILD/imunify360-venv-2.3.5/opt/imunify360/venv/lib/python3.11/site-packages/babel/messages/pofile.pyreplace_escapesz!unescape..replace_escapes's@ KKNN 884 #XX4 #XX4z \\([\\trn"])r)recompilesub)rrs runescaper%s;    :o & & * *?F1R4L I IIr cd|vr]|}|dr |dd}tt|}d|St|S)aReverse the normalization done by the `normalize` function. >>> print(denormalize(r'''"" ... "Say:\n" ... " \"hello, world!\"\n"''')) Say: "hello, world!" >>> print(denormalize(r'''"" ... "Say:\n" ... " \"Lorem ipsum dolor sit " ... "amet, consectetur adipisicing" ... " elit, \"\n"''')) Say: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, " :param string: the string to denormalize r""rN) splitlines startswithmapr%join)r escaped_linesliness r denormalizer/4so* v~~))++   T " " .)!""-MHm,,wwu~~r c$eZdZdZd fd ZxZS) PoFileErrorzDException thrown by PoParser when an invalid po file is encountered.messagercatalogrlinelinenointrNonec~t|d|||_||_||_dS)Nz on )super__init__r3r4r5)selfr2r3r4r5 __class__s rr:zPoFileError.__init__VsB G1111222   r ) r2rr3rr4rr5r6rr7)__name__ __module__ __qualname____doc__r: __classcell__)r<s@rr1r1SsCNNr r1cneZdZddZddZddZdd Zdd ZddZddZ ddZ ddZ ddZ ddZ ddZdS)_NormalizedStringargsrrr7cHg|_|D]}||dSN)_strsappend)r;rDargs rr:z_NormalizedString.__init___s7 "   C KK      r sc^|j|dSrF)rGrHstrip)r;rJs rrHz_NormalizedString.appendds& !''))$$$$$r c\dtt|jS)Nr()r,r+r%rGr;s rr/z_NormalizedString.denormalizegs wws8TZ00111r boolc*t|jSrF)rOrGrNs r__bool__z_NormalizedString.__bool__jsDJr cJtj|jSrF)oslinesepr,rGrNs r__repr__z_NormalizedString.__repr__msztz***r otherobjectr6c^|sdStt|t|S)Nr)r rr;rVs r__cmp__z_NormalizedString.__cmp__ps+ 1CIIs5zz***r c4||dkSNrrZrYs r__gt__z_NormalizedString.__gt__v||E""Q&&r c4||dkSr\r]rYs r__lt__z_NormalizedString.__lt__yr_r c4||dkSr\r]rYs r__ge__z_NormalizedString.__ge__|||E""a''r c4||dkSr\r]rYs r__le__z_NormalizedString.__le__rdr c4||dkSr\r]rYs r__eq__z_NormalizedString.__eq__rdr c4||dkSr\r]rYs r__ne__z_NormalizedString.__ne__rdr N)rDrrr7)rJrrr7)rr)rrO)rVrWrr6)rVrWrrO)r=r>r?r:rHr/rQrUrZr^rarcrfrhrjr rrCrC]s %%%%2222    ++++++++ ''''''''((((((((((((((((((r rCcpeZdZdZgdZddd Zdd Zdd ZddZdddZ dddZ ddZ ddZ ddZ ddZdS) PoFileParserzSupport class to read messages from a ``gettext`` PO (portable object) file and add them to a `Catalog` See `read_po` for simple cases. )msgidmsgstrmsgctxt msgid_pluralFr3rignore_obsoleterO abort_invalidrr7ct||_||_d|_d|_||_|dSr\)r3rrcounteroffsetrs_reset_message_state)r;r3rrrss rr:zPoFileParser.__init__s? .  * !!#####r cg|_g|_g|_g|_g|_g|_d|_d|_d|_d|_ d|_ dS)NF) messages translations locationsflags user_comments auto_commentscontextobsoletein_msgid in_msgstr in_msgctxtrNs rrwz!PoFileParser._reset_message_statesV     r c |jt|jdkrt d|jD}n|jd}t |ttfrdt|j j D}|jD]I\}}||j j kr| d|j d2|||<Jt |}n%|jdd}|j r|j nd}t||t|jt!|j|j|j|j dz|}|jr|js||j j|<n ||j |<|xjdz c_|dS) z Add a message to the catalog based on the current parser state and clear the state ready to process the next message. rc3>K|]}|VdSrF)r/).0rs r z,PoFileParser._add_message..s*AAa!--//AAAAAAr rcg|]}dSr(rk)r_s r z-PoFileParser._add_message..sBBBQbBBBr r(z5msg has more translations than num_plurals of catalogN)r5r)rzsortlenrytupler/ isinstancelistranger3 num_plurals_invalid_pofilervrrr{setr|r~r}rrrrurw)r;rnridx translationrpr2s r _add_messagezPoFileParser._add_messages    t}   ! !AA4=AAAAAEEM!$0022E edE] + + ;BB% (@"A"ABBBF$($5 8 8 [$,222((T[:qrrr)5577s 6]]FF&q)!,88::F04 F$,**,,,$%dn)=)=s4:,d.@WX")+++ = *' 7/6 %e,")DL    !!#####r c@|jr|dSdSrF)ryrrNs r_finish_current_messagez$PoFileParser._finish_current_messages. =          r c|dr|||dS||||dS)N")r*!_process_string_continuation_line_process_keyword_line)r;r5r4rs r_process_message_linez"PoFileParser._process_message_linesP ??3   ?  2 24 @ @ @ @ @  & &vtX > > > > >r c|jD]o} ||r0|t|dvr|t|d}nAI#t$r|||dYlwxYw|||ddS|dvr|||_|dkr||_|dvr7d|_d|_ |j t|dS|d krd|_ d|_ |d rY|d dd d \}}|j t!|t|gdS|j d t|gdS|dkrd|_t||_dSdS)N) [z$Keyword must be followed by a stringz0Start of line didn't match any expected keyword.)rnrprn)rnrqFTrorr]rrp) _keywordsr*r IndexErrorrrrrvrrryrHrCrsplitrzr6r)r;r5r4rkeywordrIrmsgs rrz"PoFileParser._process_keyword_lines~  G [??7++S\\0Bj0P0Ps7||}}-CE [ [ [$$T63YZZZZZ [  v/a b b b F * * *  ( ( * * *   g   DK / / /#DO DM M !23!7!7 8 8 8 8 8  !DM!DN~~c"" Fqrr7==a00S!((#c((4Ec4J4J)KLLLLL!((!->s-C-C)DEEEEE  ! !"DO,S11DLLL" !sAA!A54A5c|jr|jd}nC|jr|jdd}n(|jr|j}n|||ddS||dS)Nr!rz6*BCCCCN))8T*:;;;; < <!""X  % % 8QRR))//44 0 0 !!$**,,//// 0 0 !""X  % % 8122hnn&&G 3"))'22222 3 3   % %d122hnn&6&6 7 7 7 7 7s>B B&%B&fileobj IO[AnyStr]ct|D]\}}|}t|ts||jj}|sP|drf|dddr3|||dd d| ||||| |j s{|j s|js|jrh|jt%d|jd t%dg|dSdSdS) z Reads from the file-like object `fileobj` and adds any po file units found in it to the `Catalog` supplied to the constructor. #rN~rT)rr'r) enumeraterLrrdecoder3charsetr*rrrrrur|r}r~ryrHrCrzr)r;rr5r4s rparsezPoFileParser.parse&s &g.. 9 9LFD::<> > j# @&1*@@@@AAAAAr N)FF)r3rrrrOrsrOrr7)rr7)F)rrrr7)r=r>r?r@rr:rwrrrrrrrrrkr rrmrms I$$$$$     $$$$@    ????? '2'2'2'2'2R    88886    :BBBBBBr rmFrrlocalestr | Locale | Nonedomain str | NonerrrOrrsrcxt|||}t|||}|||S)aRead 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 )rrr)rs)rrmr)rrrrrrrsr3parsers rread_porKsDlVFGDDDG '?- P P PF LL Nr zL(\s+|[^\s\w]*\w+[a-zA-Z]-(?=\w+[a-zA-Z])|(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))cd|dddddddd d d zS) 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\\rz\trz\rrz\nrz\")replace)rs rescapers] FNN400"74//"74//"74//"74//  00r r(Lprefixwidthr6c|rW|dkrPt}g}|dD]'}tt||z|krt|}||rg}d}|rtt|ddz |z} || z|kr-|||| z }n*|s'||n||d||||)n|d}t|dkrt|S|r|ds|d=|dxxdz cc<ddfd |DzS) aConvert 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 rTrr!r(rrz"" c4g|]}t|zSrk)r)rr4rs rrznormalize..s$III4 5IIIr ) rr)rWORD_SEPrreverserHpopr,) rrr prefixlenr.r4chunksbufsizelengths ` r normalizers0 (KK %%d++ # #D6$<<  9,u44!--   /CD "!$VF2J%7%7!8!81!>> catalog = Catalog() >>> catalog.add(u'foo %(name)s', locations=[('main.py', 1)], ... flags=('fuzzy',)) >>> catalog.add((u'bar', u'baz'), locations=[('main.py', 3)]) >>> 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 "" #: main.py:3 msgid "bar" msgid_plural "baz" msgstr[0] "" msgstr[1] "" :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)rr)r)keyrrs r _normalizezwrite_po.._normalizesV59999r ct|tr|jd}|dS)Nbackslashreplace)rrencoderwrite)textr3rs r_writezwrite_po.._writesD dC  D;;w0BCCD dr crdkrnd}t||D]&}d|d|d'dS)Nrrrrr)r rL)rr_widthr4rrs r_write_commentz write_po.._write_commentsm 5EAII2Wf-- 2 2D F0v00 000 1 1 1 1 2 2r c t|jttfr|jr |d|j|d|d|jd|d|d|jd|dt jD]B} |j|}n#t$rd}YnwxYw|d|d d ||dCdS|jr |d|j|d|d|j|d|d |jpd|ddS) Nzmsgctxt rmsgid rz msgid_plural rr(zmsgstr[dz] zmsgstr ) ridrrrrrrr)r2rrrrrr3s r_write_messagez write_po.._write_message#s gj4- 0 0 S S&QQ**W_f*M*MQQQRRR FfIIJJwz!}f$E$EIII J J J FfPP::gjmV+L+LPPP Q Q QW011 R R $^C0FF!   FFF &PPPPP**VV2L2LPPPQQQQ  R R S&QQ**W_f*M*MQQQRRR FfFFJJwz6$B$BFFF G G G FfQQZZ0D"f%M%MQQQ R R R R Rs- B;; C  C Nr2r)sort_byrz# )rsubsequent_indentrr)rc\|dt|dtr|dpdfS)Nrrr!)rr6)xs rzwrite_po..Ws/!A$ 1Q48M8M8VRSTURV8\Z\1]r r/rrrrz, r|rzmsgid_plural %sz#~ r)_sort_messagesrheader_commentr)r r,r}r~sortedr{ TypeErrorrrSseprHr| previous_idrrvalues)rr3rrrrrrrrrrrrr2comment_headerr.r4rlocsr{filenamer5rrrs``` @@rwrite_porsMn:::::: 2222222SSSSSSSS&G !'7;;;44z * $3N 2*5577>>DXd%8<>>>>EE!%5!1!1 Fn((( ) ) ), $ $G N7 # # # #, 0 0G N73 / / / / / 7D  ."7#4']']___  . . .#-  .%. * * &#++BFC888n8"*77V777H4''KK))) N388D>># 6 6 6 6 = D FBtyy"!=vgm'<'>BBB C C C   #3  N=G$7$:;;==    7&''!++0::'*44  wt %   # # % %     G#0 ( (w'''' N75 1 1 1 1 F4LLLL  sC33DDryIterable[Message]rLiteral['message', 'location'] list[Message]ct|}|dkr|n|dkr|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] r2rc|jSrF)r{)rs rrz _sort_messages..sAKr r)rr)ryrs rrr}sQH~~H)  J   // 000 Or )rrrr)NNFNF)rrrrrrrrrOrrrsrOrr)r(r)rrrrrr6rr)rFFFFFFT)rrr3rrr6rrOrrOrrOrrOrrrOrrOrrOrr7)ryrrrrr)$r@ __future__rrSr"collections.abcrtypingr babel.corerbabel.messages.catalogrr babel.utilr r r r _typeshedr typing_extensionsrr%r/ Exceptionr1rCrmrr#rrrrrrkr rrsf  #""""" $$$$$$ 33333333%%%%%%%%*!!!!!!!!''''''))))))JJJJ.    >))()()()()()()()(XBBBBBBBBH#'! 99999x 2:  0000$:K:K:K:K:K@!"]]]]]@r