o ^hU@sdZddlmZddlZddlZddlmZmZddlm Z ddl m Z m Z ddZ d d ZGd d d eZGd ddeZGdddeZd ddZedZddZd!ddZ   d"ddZddZdS)#z babel.messages.pofile ~~~~~~~~~~~~~~~~~~~~~ Reading and writing of files in the ``gettext`` PO (portable object) format. :copyright: (c) 2013-2019 by the Babel Team. :license: BSD, see LICENSE for more details. )print_functionN)CatalogMessage)wraptext) text_typecmpcCs"dd}td||ddS)zReverse `escape` the given string. >>> print(unescape('"Say:\\n \\"hello, world!\\"\\n"')) Say: "hello, world!" :param string: the string to unescape cSs2|d}|dkr dS|dkrdS|dkrdS|S)Nn t r )group)matchmr7/usr/lib/python3/dist-packages/babel/messages/pofile.pyreplace_escapes s z!unescape..replace_escapesz \\([\\trn"])r)recompilesub)stringrrrrunescapes  rcCsBd|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 startswithmaprjoin)r escaped_lineslinesrrr denormalize-s    r#cs eZdZdZfddZZS) PoFileErrorzDException thrown by PoParser when an invalid po file is encountered.cs0tt|dj||d||_||_||_dS)Nz{message} on {lineno})messagelineno)superr$__init__formatcatalogliner&)selfr%r*r+r& __class__rrr(Ns zPoFileError.__init__)__name__ __module__ __qualname____doc__r( __classcell__rrr-rr$Lsr$c@speZdZddZddZddZddZeZd d Zd d Z d dZ ddZ ddZ ddZ ddZddZdS)_NormalizedStringcGsg|_|D]}||qdSN)_strsappend)r,argsargrrrr(Ws z_NormalizedString.__init__cCs|j|dSr5)r6r7strip)r,srrrr7\sz_NormalizedString.appendcCsdtt|jS)Nr)r rrr6r,rrrr#_sz_NormalizedString.denormalizecCs t|jSr5)boolr6r<rrr __nonzero__bs z_NormalizedString.__nonzero__cCstj|jSr5)oslinesepr r6r<rrr__repr__gz_NormalizedString.__repr__cCs|sdStt|t|S)Nr)rrr,otherrrr__cmp__jsz_NormalizedString.__cmp__cCs||dkSNrrErCrrr__gt__prBz_NormalizedString.__gt__cCs||dkSrFrGrCrrr__lt__srBz_NormalizedString.__lt__cCs||dkSrFrGrCrrr__ge__vrBz_NormalizedString.__ge__cCs||dkSrFrGrCrrr__le__yrBz_NormalizedString.__le__cCs||dkSrFrGrCrrr__eq__|rBz_NormalizedString.__eq__cCs||dkSrFrGrCrrr__ne__rBz_NormalizedString.__ne__N)r/r0r1r(r7r#r>__bool__rArErHrIrJrKrLrMrrrrr4Us r4c@sneZdZdZgdZdddZddZdd Zd d Zdd d Z 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_pluralFcCs*||_||_d|_d|_||_|dSrF)r*ignore_obsoletecounteroffset abort_invalid_reset_message_state)r,r*rTrWrrrr(s  zPoFileParser.__init__cCsFg|_g|_g|_g|_g|_g|_d|_d|_d|_d|_ d|_ dS)NF) messages translations locationsflags user_comments auto_commentscontextobsoletein_msgid in_msgstr in_msgctxtr<rrrrXs z!PoFileParser._reset_message_statec Cs8|jt|jdkrtdd|jD}n|jd}t|ttfrRddt|j j D}|jD]\}}||j j krF| d|j dq3|||<q3t|}n |jdd}|j rd|j }nd}t||t|jt|j|j|j|j d|d }|jr|js||j j|<n||j |<|jd7_|dS) z Add a message to the catalog based on the current parser state and clear the state ready to process the next message. rcSsg|]}|qSr)r#).0rrrr sz-PoFileParser._add_message..rcSsg|]}dqSrr)rd_rrrresrz5msg has more translations than num_plurals of catalogN)r&r_)rZsortlenrYtupler# isinstancelistranger* num_plurals_invalid_pofilerVr_rr[setr\r^r]r`rTrUrX)r,rPridx translationrRr%rrr _add_messages6       zPoFileParser._add_messagecCs|jr |dSdSr5)rYrsr<rrr_finish_current_messages z$PoFileParser._finish_current_messagecCs,|dr |||dS||||dS)N")r!_process_string_continuation_line_process_keyword_line)r,r&r+r`rrr_process_message_lines z"PoFileParser._process_message_linec CsH|jD],}z||r|t|dvr|t|d}WnWqty/|||dYqw|||ddS|dvrA|||_|dkrK||_|dvr_d|_d|_ |j t |dS|d krd|_ d|_ |d r|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.)rPrRrP)rPrSFTrQrzr]rrR) _keywordsrri IndexErrorrortr`rVrcrarYr7r4rbsplitrZintr_)r,r&r+r`keywordr9rqmsgrrrrws>   z"PoFileParser._process_keyword_linecCsV|jr |jd}n|jr|jdd}n|jr|j}n |||ddS||dS)Nrrz|dddr8|j||dd ddq| |q|||q| |j sm|j sU|jsU|jro|jtd|jd tdg|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)r`rr) enumerater:rkrdecoder*charsetrrxrrrtrUr\r]r^rYr7r4rZrs)r,fileobjr&r+rrrparse$s"    zPoFileParser.parsecCs8|jr t||j||td|td|d|dS)NzWARNING:z!WARNING: Problem on line {0}: {1}r)rWr$r*printr))r,r+r&rrrrroAs zPoFileParser._invalid_pofileN)FF)F)r/r0r1r2r|r(rXrsrtrxrwrvrrrorrrrrOs  #  )  rOFcCs*t|||d}t|||d}|||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 babel._compat 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)rW)rrOr)rrrrTrrWr*parserrrrread_poHs/ rzL(\s+|[^\s\w]*\w+[a-zA-Z]-(?=\w+[a-zA-Z])|(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))cCs0d|dddddddd d d S) 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\nruz\")replace)rrrrescapes rrLc s0|rj|dkrjt}g}|dD]W}tt|||krct|}||rbg}d}|rXtt|dd|} || |krL|||| 7}n |sU||n|s.|d||s(q||qn|d}t|dkryt|S|r|ds|d=|dd7<ddfd d |DS) 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 rTrrrrr z"" csg|]}t|qSr)r)rdr+prefixrrresznormalize..) rirrWORD_SEPr~reverser7popr ) rrwidth prefixlenr"r+chunksbufsizelrrr normalizes>         rTc  sRd#fdd fddd#fdd } d#fdd } d } |r&d } n|r*d } t| d D]} | js^|r8q0j}rXdkrXg}|D] }|t|dd7}qGd|}|d| jD]}| |qa| jD]}| |ddqk|sg}z t| j ddd}Wn t y| j }Ynw|D]#\}}|r| r| d| t jd|fq| d| t jdq| d|dd| jrшdddgt| j| jr|r| d| jdddt| jd kr| d!| jd dd| | dq0|s%tj| d D]} | jD]}| |q| | d"ddq d Sd S)$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 babel._compat 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 rcst||dS)N)rr)r)keyr)rrr _normalizerBzwrite_po.._normalizecs&t|tr |jd}|dS)Nbackslashreplace)rkrencoderwrite)text)r*rrr_writes zwrite_po.._writecs>r dkr }nd}t||D] }d||fqdS)Nrrz#%s %s )rr:)rr_widthr+)rrrr_write_comment s z write_po.._write_commentc st|jttfr\|jrd||j|fd||jd|fd||jd|ftjD]!}z|j|}Wn tyLd}Ynwd||||fq8dS|jrkd||j|fd||j|fd||jpd|fdS) Nz %smsgctxt %s z %smsgid %s rz%smsgid_plural %s rrz%smsgstr[%d] %s z %smsgstr %s ) rkidrlrjr_rmrnrr})r%rrqr)rrr*rr_write_messages6       z write_po.._write_messageNr%r)sort_byrz# )rsubsequent_indentr rrcSs"|dt|dtr|dpdfS)Nrrr)rkr)xrrrOs"zwrite_po..rz%s:%d/z%sryrz#%s z, zmsgid %s|rzmsgid_plural %sz#~ rf)_sort_messagesrheader_commentrrr r]r^sortedr[ TypeErrorr7rr?sepr\ previous_idrir`values)rr*r no_location omit_header sort_output sort_by_filerTinclude_previousinclude_linenorrrr%comment_headerr"r+rlocsr[filenamer&r)rrr*rrrwrite_pos.                 rcCs8t|}|dkr||S|dkr|jddd|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%rcSs|jSr5)r[)rrrrrsz _sort_messages..r)rlrh)rYrrrrrrs r)NNFNF)rr)rFFFFFFT)r2 __future__rr?rbabel.messages.catalogrr babel.utilr babel._compatrrrr# Exceptionr$objectr4rOrrrrrrrrrrrs.   / E 5 =