Mc@sLdZddlmZddlmZddlmZddlmZddlmZddl Z ddl Z ddl m Z dd lmZdd lmZdd lmZdd lmZmZmZmZmZmZd ddgZdZe jdZd efdYZ de!fdYZ"dZ#defdYZ$dS(s%Data structures for message catalogs.i(t parse_header(tdatetime(tget_close_matches(tmessage_from_string(tcopyN(t __version__(tLocale(tformat_datetime(t get_plural(todicttdistincttsettLOCALTZtUTCtFixedOffsetTimezonetMessagetCatalogtTranslationErrorsrestructuredtext ens(?x) \% (?:\(([\w]*)\))? ( [-#0\ +]?(?:\*|[\d]+)? (?:\.(?:\*|[\d]+))? [hlL]? ) ([diouxXeEfFgGcrs%]) cBseZdZddddddddZdZdZdZddZdZ e e dd Z d Z e e dd Z d Z e e dd Z RS(s0Representation of a single message in a catalog.uc Cs||_| r"|jr"d}n||_tt||_t||_|rq|jrq|jj dn|jj dtt||_ tt||_ t |tr|g|_nt||_||_dS(s4Create 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 ``(filenname, 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 us python-formatN(uu(tidt pluralizabletstringtlistR t locationsR tflagst python_formattaddtdiscardt auto_commentst user_commentst isinstancet basestringt previous_idtlineno( tselfRRRRRRRR ((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyt__init__1s   cCs&dt|j|jt|jfS(Ns<%s %r (flags: %r)>(ttypet__name__RRR(R!((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyt__repr__TscCst|tr|j}|j}|rH|rHt|jd|jdS|ret|jd|jS|rt|j|jdSnt|j|jS(s0Compare Messages, taking into account plural idsi(RRRtcmpR(R!tobjtpluralt obj_plural((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyt__cmp__Xs   c CsCttt|j|j|j|j|j|j|j |j fS(N( RtmapRRRRRRRRR (R!((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pytclonees  cCs_ddlm}g}xB|D]:}y|||Wqtk rV}|j|qXqW|S(sRun 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. i(tcheckers(tbabel.messages.checkersR-Rtappend(R!tcatalogR-terrorstcheckerte((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pytcheckks  cCs d|jkS(Ntfuzzy(R(R!((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyR5~stdocs Whether the translation is fuzzy. >>> Message('foo').fuzzy False >>> msg = Message('foo', 'foo', flags=['fuzzy']) >>> msg.fuzzy True >>> msg :type: `bool` cCst|jttfS(N(RRRttuple(R!((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyRss Whether the message is plurizable. >>> Message('foo').pluralizable False >>> Message(('foo', 'bar')).pluralizable True :type: `bool` cCsY|j}t|ttfs*|g}nttdg|D]}tj|^q:S(N( RRRR7tbooltfiltertNonet PYTHON_FORMATtsearch(R!tidsR((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyRs  s Whether 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` (((((N( R$t __module__t__doc__R:R"R%R*R,R4R5tpropertyRR(((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyR.s  "         cBseZdZRS(s_Exception thrown by translation checkers when invalid message translations are encountered.(R$R>R?(((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyRsu# Translations template for PROJECT. # Copyright (C) YEAR ORGANIZATION # This file is distributed under the same license as the PROJECT project. # FIRST AUTHOR , YEAR. #cBsXeZdZddeddddddddded ZdZdZe eeddZ dZ dZ e e e dd Z d Ze edd Zd Ze edd ZdZe eddZdZdZdZdZdZdZdZdddddd ddZdZedZdZRS(!s$Representation of a message catalog.sutf-8c Cs}||_|r!tj|}n||_||_t|_|pHd|_|pWd|_|pfd|_ |pud|_ | pd|_ | pd|_ | pd|_ |d krtjt}n.t|tr|j r|jdt}n||_| d krtjt} n.t| trI| j rI| jdt} n| |_| |_t|_d |_d |_d S( s0Initialize 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 :param fuzzy: the fuzzy bit on the catalog header tPROJECTtVERSIONt ORGANIZATIONs EMAIL@ADDRESSsFULL NAME sLANGUAGE sutf-8ttzinfoN(tdomainRtparsetlocalet_header_commentR t _messagestprojecttversiontcopyright_holdertmsgid_bugs_addresstlast_translatort language_teamtcharsetR:RtnowR RRDtreplacet creation_datet revision_dateR5tobsoletet _num_pluralst _plural_expr(R!RGREtheader_commentRJRKRLRMRSRTRNRORPR5((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyR"s6           cCs|j}|jd|jjd|jjd|jjdjd|j}|jr||jdd|jj}n|S(NRARBtYEARs%YRCsTranslations templates%s translations( RHRRRJRKRTtstrftimeRLRGt english_name(R!tcomment((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyt_get_header_comments   cCs ||_dS(N(RH(R!R((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyt_set_header_commentsR6s 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` cCshg}|jdd|j|jff|jd|jf|jdt|jdddf|jdkr|jd|jd|jdn||jdt|jdddf|jd |j f|jd |j j dt |jf|jd|j f|jd|jdd|jf|jd|jddtf|S(NsProject-Id-Versions%s %ssReport-Msgid-Bugs-TosPOT-Creation-Datesyyyy-MM-dd HH:mmZRGtensPO-Revision-DatesYEAR-MO-DA HO:MI+ZONEsLast-TranslatorsFULL NAME s Language-TeamsLANGUAGE tLANGUAGEs Plural-Formss MIME-Versions1.0s Content-Typestext/plain; charset=%ssContent-Transfer-Encodingt8bits Generated-Bys Babel %s (sPO-Revision-DatesYEAR-MO-DA HO:MI+ZONE(sLast-TranslatorsFULL NAME (s Language-TeamsLANGUAGE (s MIME-Versions1.0(sContent-Transfer-EncodingRa(R/RJRKRMRRSRGR:RTRNRORRtstrt plural_formsRPRB(R!theaders((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyt_get_mime_headers's2            cCsox^|D]V\}}|jdkrt|\}}d|krY|dj|_nPqqWx|D]\}}|jj|j}|j|j}|dkr|jd}dj|d |_|d|_qh|dkr||_qh|dkr||_ qh|d kr'||_ qh|d kr|td |\}}t |j d d |_ |j dd|_qh|dkrjtjd|d\}}}tj|d} tj| } |d|d} } | d | d } }t | d}t | }t |}|d}||7}||9}t|}tj| }|jd||_qh|dkrhd|krgtjd|d\}}}tj|d} tj| } |d|d} } | d | d } }t | d}t | }t |}|d}||7}||9}t|}tj| }|jd||_qgqhqhWdS(Ns content-typeRPsproject-id-versiont u isreport-msgid-bugs-toslast-translators language-teams plural-formss ;tnpluralsiR(s(n != 1)spot-creation-dates ([+-]\d{4})$is%Y-%m-%d %H:%Mit1i<RDspo-revision-dateRY(tlowerRRPtdecodetsplittjoinRJRKRMRNROtinttgetRVRWtrettimetstrptimetmktimeRRt fromtimestampRRRSRT(R!Rdtnametvaluetmimetypetparamstpartst_ttzoffsettttttst plus_minus_strestthours_offset_st mins_offset_st plus_minust hours_offsett mins_offsettnet_mins_offsettdt((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyt_set_mime_headersCsl                        s 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: >>> 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-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` cCsG|jdkr@d}|jr4t|jd}n||_n|jS(Nii(RVR:RGR(R!tnum((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyt num_pluralss   s The number of plurals used by the catalog or locale. >>> Catalog(locale='en').num_plurals 2 >>> Catalog(locale='ga').num_plurals 3 :type: `int` cCsG|jdkr@d}|jr4t|jd}n||_n|jS(Ns(n != 1)i(RWR:RGR(R!texpr((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyt plural_exprs   s 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 : 2)' :type: `basestring` cCsd|j|jfS(Nsnplurals=%s; plural=%s(RR(R!((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyRcss Return 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` cCs|j||jkS(s?Return whether the catalog has a message with the specified ID.(t_key_forRI(R!R((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyt __contains__scCs t|jS(snThe number of messages in the catalog. This does not include the special ``msgid ""`` entry. (tlenRI(R!((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyt__len__sccsg}x.|jD]#\}}|jd||fqWt}|jr_|tdgO}ntddj|d|Vx|jD]}|j|VqWdS(sIterates through all the entries in the catalog, in the order they were added, yielding a `Message` object for every entry. :rtype: ``iterator`` s%s: %sR5us RN(t mime_headersR/R R5RRlRI(R!tbufRtRuRtkey((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyt__iter__s  cCs<d}|jrd|j}ndt|j|j|fS(Nts %ss <%s %r%s>(RGR#R$RE(R!RG((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyR%s cCs/|j|}||jkr+|j|=ndS(s)Delete the message with the specified ID.N(RRI(R!RR((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyt __delitem__scCs|jj|j|S(sReturn the message with the specified ID. :param id: the message ID :return: the message with the specified ID, or `None` if no such message is in the catalog :rtype: `Message` (RIRnR(R!R((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyt __getitem__scCst|tstd|j|}|jj|}|r|jrp|j rp|j|_|j|_nt t |j |j |_ t t |j |j |_ t t |j |j |_ |j|jO_|}n|dkrYt|jj|j}|j|_djg|j D]}d|^q.|_|j|_nVt|t tfrt|jt tfstdt|jn||j|>> 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 sexpected a Message objectRs s# %ssExpected sequence but got %sN(RRtAssertionErrorRRIRnRRRRR RRRRRtencodeRPtitemsRRlRXR5R7R#(R!RtmessageRtcurrentRdR\((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyt __setitem__)s2       #c Cs2t||t|||||d|||>> 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 ``(filenname, 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 R N(RR( R!RRRRRRRR ((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyR\sccsDx=|jjD],}|jd|}|r||fVqqWdS(sBRun 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: ``iterator`` R0N(RItvaluesR4(R!RR1((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyR4xs c sjjt_g}|segD](}|r4|jr4j|^q4}ntfd}x|D]}|jrj|j}|kr||||q*|tkrt|j j |d}|r|||d|qqn||j>> 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 >>> 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 cs|j}t}||kryt}j|j|}t|jtrd|jg|_qt |j|_nj |d}|j |_ t|jt t fr@t|j t t fst}t |j gdgt|jd|_ qqt|j jkrqt}t |j t|j  |_ qqn1t|j t t frqt}|j d|_ n|j|jO_|r|jtdgO_n||jR?R:tDEFAULT_HEADERRR"R]R^R@RXReRRRRRcRRRR%RRRRR4RRR(((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyRsF   8     S /             3   s(%R?tcgiRRtdifflibRtemailRRRoRptbabelRRBt babel.coreRt babel.datesRtbabel.messages.pluralsRt babel.utilR R R R R Rt__all__t __docformat__tcompileR;tobjectRt ExceptionRRR(((s:/usr/lib/python2.7/site-packages/babel/messages/catalog.pyts(  . ~