ƪbUdZddlZddlZddlmZmZddlmZmZdZ dZ Gdde Z Gd d Z Gd d Zdd Zej dZdZddZ ddZdZy)z babel.messages.pofile ~~~~~~~~~~~~~~~~~~~~~ Reading and writing of files in the ``gettext`` PO (portable object) format. :copyright: (c) 2013-2022 by the Babel Team. :license: BSD, see LICENSE for more details. N)CatalogMessage)wraptext_cmpcXd}tjdj||ddS)zReverse `escape` the given string. >>> print(unescape('"Say:\\n \\"hello, world!\\"\\n"')) Say: "hello, world!" :param string: the string to unescape cL|jd}|dk(ry|dk(ry|dk(ry|S)Nn t r )group)matchms 7/usr/lib/python3/dist-packages/babel/messages/pofile.pyreplace_escapesz!unescape..replace_escapess2 KKN 8 #X #Xz \\([\\trn"])r )recompilesub)stringrs runescapers+  ::o & * *?F1RL IIrcd|vrG|j}|jdr|dd}tt|}dj |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 ""r N) splitlines startswithmaprjoin)r escaped_linesliness r denormalizer%*sX* v~))+   T ")!"-MHm,wwu~rc"eZdZdZfdZxZS) PoFileErrorzDException thrown by PoParser when an invalid po file is encountered.cXt||d|||_||_||_y)Nz on )super__init__cataloglinelineno)selfmessager+r,r- __class__s rr*zPoFileError.__init__Ks0 G9D12   r)__name__ __module__ __qualname____doc__r* __classcell__)r0s@rr'r'IsNrr'cXeZdZdZdZdZdZeZdZdZ dZ dZ d Z d Z d Zd Zy )_NormalizedStringcBg|_|D]}|j|yN)_strsappend)r.argsargs rr*z_NormalizedString.__init__Ts$  C KK  rcV|jj|jyr9)r:r;strip)r.ss rr;z_NormalizedString.appendYs !'')$rcTdjtt|jS)Nr)r"r!rr:r.s rr%z_NormalizedString.denormalize\swws8TZZ011rc,t|jSr9)boolr:rBs r __nonzero__z_NormalizedString.__nonzero___sDJJrcTtjj|jSr9)oslinesepr"r:rBs r__repr__z_NormalizedString.__repr__dszztzz**rcD|sytt|t|S)Nr )rstrr.others r__cmp__z_NormalizedString.__cmp__gsCIs5z**rc*|j|dkDSNrrNrLs r__gt__z_NormalizedString.__gt__m||E"Q&&rc*|j|dkSrPrQrLs r__lt__z_NormalizedString.__lt__prSrc*|j|dk\SrPrQrLs r__ge__z_NormalizedString.__ge__s||E"a''rc*|j|dkSrPrQrLs r__le__z_NormalizedString.__le__vrXrc*|j|dk(SrPrQrLs r__eq__z_NormalizedString.__eq__yrXrc*|j|dk7SrPrQrLs r__ne__z_NormalizedString.__ne__|rXrN)r1r2r3r*r;r%rE__bool__rIrNrRrUrWrZr\r^rrr7r7RsE %2 H++ ''((((rr7cZeZdZdZgdZddZdZdZdZddZ ddZ d Z d Z d Z d Zy ) 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_pluralcj||_||_d|_d|_||_|j yrP)r+ignore_obsoletecounteroffset abort_invalid_reset_message_state)r.r+rhrks rr*zPoFileParser.__init__s3 .  * !!#rcg|_g|_g|_g|_g|_g|_d|_d|_d|_d|_ d|_ y)NF) messages translations locationsflags user_comments auto_commentscontextobsoletein_msgid in_msgstr in_msgctxtrBs rrlz!PoFileParser._reset_message_statesR     rc P|jjt|jdkDrt d|jD}n|jdj }t |ttfrt|jjDcgc]}d}}|jD]O\}}||jjk\r|jd|jd=|j ||<Qt |}n |jddj }|jr|jj }nd}t||t|jt!|j"|j$|j&|jdz|}|j(r&|j*s)||jj(|<n||j|<|xj,dz c_|j/ycc}w)z Add a message to the catalog based on the current parser state and clear the state ready to process the next message. r c3<K|]}|jywr9)r%).0rs r z,PoFileParser._add_message..sAa!--/Asrrz5msg has more translations than num_plurals of catalogN)r-rt)rosortlenrntupler% isinstancelistranger+ num_plurals_invalid_pofilerjrtrrpsetrqrsrrrurhrirl)r.rc_ridx translationrer/s r _add_messagezPoFileParser._add_messages  t}}  !A4==AAEMM!$002E edE] +"' (@(@"ABQbBFB$($5$5 8 [$,,222((dkk;rs)557s  8 6]F&&q)!,88:F <<ll..0GG%dnn)=s4::,,d.@.@WX")+ ==''/6 %%e,")DLL    !!#-Cs$ H#c>|jr|jyyr9)rnrrBs r_finish_current_messagez$PoFileParser._finish_current_messages ==     rcr|jdr|j||y|j|||y)N")r !_process_string_continuation_line_process_keyword_line)r.r-r,rus r_process_message_linez"PoFileParser._process_message_lines0 ??3   2 24 @  & &vtX >rc|jD]4} |j|r |t|dvr|t|d}n6|j ||dy|dvr|j ||_|dk(r||_|dvr3d|_d|_ |jjt|y|d k(rd|_ d|_ |jd rH|d djd d \}}|jjt!|t|gy|jjd t|gy|dk(rd|_t||_yy#t$r|j ||dYywxYw)N) [z$Keyword must be followed by a stringz0Start of line didn't match any expected keyword.)rcrerc)rcrfFTrdrr ]rre) _keywordsr r~ IndexErrorrrrurjrxrvrnr;r7rwsplitrointrt)r.r-r,rukeywordr=rmsgs rrz"PoFileParser._process_keyword_lines~~ G [??7+S\0Bj0Ps7|}-C   v/a b  * *  ( ( *   g  DK / /#DO DM MM !23!7 8  !DM!DN~~c"qr7==a0S!!((#c(4Ec4J)KL!!((!->s-C)DE  !"DO,S1DL"= [$$T63YZ [s/E''FFc|jr|jd}nL|jr|jdd}n-|jr |j }n|j ||dy|j|y)Nrr z6*BCNN))8T*:; <!"X  %QR)//4 0 !!$**,/ 0 !"X  %12hnn&G""))'2    % %d12hnn&6 7&! !s F  FFct|D]\}}|j}t|ts%|j |j j }|sN|jdrL|ddjdr&|j||ddjd|j||j|||j|js|js|js |jr[|j j#t%d|j&j#d t%dg|j)yyy) z Reads from the file-like object `fileobj` and adds any po file units found in it to the `Catalog` supplied to the constructor. #r N~rT)rurr) enumerater?rrKdecoder+charsetr rrrrrirqrrrsrnr;r7ror)r.fileobjr-r,s rparsezPoFileParser.parse!s) &g. 9LFD::sZ$$$$   c4<<v> > j# 299&1*d4jQRrN)FF)F)r1r2r3r4rr*rlrrrrrrrrr`rrrbrbsC I$  !$F ? '2R 86 :Srrbc`t|||}t|||}|j||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 )localedomainr)rk)rrbr)rrrrhrrkr+parsers rread_porIs2^VFGDG '?- PF LL NrzL(\s+|[^\s\w]*\w+[a-zA-Z]-(?=\w+[a-zA-Z])|(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))cd|jddjddjddjdd jd 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\\r z\trz\rr z\nrz\")replace)rs rescapersN FNN40"74/"74/"74/"74/  00rc |r|dkDrt|}g}|jdD]}tt||z|kDrtj |}|j |sEg}d}|rott|ddz |z} || z|kr%|j |j|| z }n"|s|j |jn|ro|j dj||r|j |n|jd}t|dkr t|S|r|ds|d=|dxxdz cc<ddj|Dcgc]}|t|zc}zScc}w) 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 rTrrrr r z"" ) r~rrWORD_SEPrreverser;popr") rprefixwidth prefixlenr$r,chunksbufsizels r normalizersq0 K %%d+ #D6$< 9,u4!- CD vbz 23a7)C!8e+JJvzz|4 AID#&!$ 6::< 8!!LL#/  T") #,!!$' 5zQf~ U2Y "I b T UZZU KT&6$<"7 KL LL Ks+F c Jdfd fddfd } dfd } d} |rd} n|rd} t| D]} | jsZ|rj}r>d kDr9g}|jD]}|t |d z }d j |}|d z| j D] }| | | jD] }| |d|sg} t| jd}|D]h\}}|r(| r&d|jtjd|fz}n#d|jtjdz}||vsX|j|j| dj |d| jr1ddj dgt| jzz| j rZ|rX| d| j d zdt#| j dkDr | d| j dzd| | d |sVtj$j'| D]-} | j D] }| | | | dd /yy#t$r| j}YwxYw)aWrite a ``gettext`` PO (portable object) template file for a given message catalog to the provided file-like object. >>> catalog = Catalog() >>> catalog.add(u'foo %(name)s', locations=[('main.py', 1)], ... flags=('fuzzy',)) >>> 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 rc t||S)N)rr)r)keyrrs r _normalizezwrite_po.._normalizesV599rct|tr|jjd}j |y)Nbackslashreplace)rrKencoderwrite)textr+rs r_writezwrite_po.._writes. dC ;;w0BCD drczrdkDr}nd}t||D]}d|d|jd!y)NrLrrr )rr?)rr_widthr,rrs r_write_commentz write_po.._write_comment sA UQYFFWf- 8D 6 7 8rc t|jttfr|jr|d|j|d|d|jd|d|d|jd|dt j D]'} |j|}d||||fz)y|jr|d|j|d|d|j|d|d |jxsd|dy#t$rd}YwxYw) Nzmsgctxt r zmsgid rz msgid_plural r rz%smsgstr[%d] %s zmsgstr ) ridrrrtrrrr)r/rrrrrr+s r_write_messagez write_po.._write_messagesD gjj4- 06+5goov+NPQ VZ 1 v-NO P  7::a=&9 W001  $^^C0F*CFF!;.  6+5goov+NPQ VZ F-KL M  7>>#7R@ " F s*D?? E  E Nr/r)sort_byrz# )rsubsequent_indentr r)rcH|dt|dtxr|dxsdfS)Nrr r)rr)xs rzwrite_po..Ps,!A$ 1Q48M8VRSTURV8\Z\1]rrz%s:%d/z%srrz#%s z, zmsgid %s|r zmsgid_plural %sz#~ )r)_sort_messagesrheader_commentrrr"rrrssortedrp TypeErrorrrGsepr;rq previous_idr~ruvalues)rr+r no_location omit_header sort_output sort_by_filerhinclude_previousinclude_linenorrrr/comment_headerr$r,rlocsrpfilenamer-rrrs``` @@rwrite_pors\: 86G !'7;3zz$33N*557>DXd%8<>>E>"'E!2 >E) *,, $G 7 # $,, 0G 73 / 0D  ."7#4#4']_ %. * &n'8+;+;BFFC+H&*QQH$x'7'7'DDH4'KK)  * 388D># 6 == 7TYYtfW]].C'CDD E   #3 : 73F3Fq3I(JJ"% '7&&'!+0:''*4  wt g3j %    # # %  G#00 (w' ( 75 1 4L  3 .#--  .sJ  J"!J"czt|}|dk(r|j|S|dk(r|jd|S)z Sort the given message iterable by the given criteria. Always returns a list. :param messages: An iterable of Messages. :param sort_by: Sort by which criteria? Options are `message` and `location`. :return: list[Message] r/rc|jSr9)rp)rs rrz _sort_messages..s AKKrr)rr})rnrs rrrusCH~H)  O J  / 0 Or)NNFNF)rr)rFFFFFFT)r4rGrbabel.messages.catalogrr babel.utilrrrr% Exceptionr'r7rbrrrrrrrr`rrrs  3%J. >)+(+(^ESESP2j 2:: 0$:MzINDI48^Br