<s> """<STR_LIT>""" <EOL> import re <EOL> import time <EOL> from cgi import parse_header <EOL> from datetime import datetime , time as time_ <EOL> from difflib import get_close_matches <EOL> from email import message_from_string <EOL> from copy import copy <EOL> from babel import __version__ as VERSION <EOL> from babel . core import Locale <EOL> from babel . dates import format_datetime <EOL> from babel . messages . plurals import get_plural <EOL> from babel . util import odict , distinct , LOCALTZ , FixedOffsetTimezone <EOL> from babel . _compat import string_types , number_types , PY2 , cmp <EOL> __all__ = [ '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' ] <EOL> PYTHON_FORMAT = re . compile ( r'''<STR_LIT>''' ) <EOL> def _parse_datetime_header ( value ) : <EOL> match = re . match ( r'<STR_LIT>' , value ) <EOL> tt = time . strptime ( match . group ( '<STR_LIT>' ) , '<STR_LIT>' ) <EOL> ts = time . mktime ( tt ) <EOL> dt = datetime . fromtimestamp ( ts ) <EOL> tzoffset = match . group ( '<STR_LIT>' ) <EOL> if tzoffset is not None : <EOL> plus_minus_s , rest = tzoffset [ <NUM_LIT:0> ] , tzoffset [ <NUM_LIT:1> : ] <EOL> hours_offset_s , mins_offset_s = rest [ : <NUM_LIT:2> ] , rest [ <NUM_LIT:2> : ] <EOL> plus_minus = int ( plus_minus_s + '<STR_LIT:1>' ) <EOL> hours_offset = int ( hours_offset_s ) <EOL> mins_offset = int ( mins_offset_s ) <EOL> net_mins_offset = hours_offset * <NUM_LIT> <EOL> net_mins_offset += mins_offset <EOL> net_mins_offset *= plus_minus <EOL> tzoffset = FixedOffsetTimezone ( net_mins_offset ) <EOL> dt = dt . replace ( tzinfo = tzoffset ) <EOL> return dt <EOL> class Message ( object ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , id , string = u'<STR_LIT>' , locations = ( ) , flags = ( ) , auto_comments = ( ) , <EOL> user_comments = ( ) , previous_id = ( ) , lineno = None , context = None ) : <EOL> """<STR_LIT>""" <EOL> self . id = id <EOL> if not string and self . pluralizable : <EOL> string = ( u'<STR_LIT>' , u'<STR_LIT>' ) <EOL> self . string = string <EOL> self . locations = list ( distinct ( locations ) ) <EOL> self . flags = set ( flags ) <EOL> if id and self . python_format : <EOL> self . flags . add ( '<STR_LIT>' ) <EOL> else : <EOL> self . flags . discard ( '<STR_LIT>' ) <EOL> self . auto_comments = list ( distinct ( auto_comments ) ) <EOL> self . user_comments = list ( distinct ( user_comments ) ) <EOL> if isinstance ( previous_id , string_types ) : <EOL> self . previous_id = [ previous_id ] <EOL> else : <EOL> self . previous_id = list ( previous_id ) <EOL> self . lineno = lineno <EOL> self . context = context <EOL> def __repr__ ( self ) : <EOL> return '<STR_LIT>' % ( type ( self ) . __name__ , self . id , <EOL> list ( self . flags ) ) <EOL> def __cmp__ ( self , obj ) : <EOL> """<STR_LIT>""" <EOL> def values_to_compare ( ) : <EOL> if isinstance ( obj , Message ) : <EOL> plural = self . pluralizable <EOL> obj_plural = obj . pluralizable <EOL> if plural and obj_plural : <EOL> return self . id [ <NUM_LIT:0> ] , obj . id [ <NUM_LIT:0> ] <EOL> elif plural : <EOL> return self . id [ <NUM_LIT:0> ] , obj . id <EOL> elif obj_plural : <EOL> return self . id , obj . id [ <NUM_LIT:0> ] <EOL> return self . id , obj . id <EOL> this , other = values_to_compare ( ) <EOL> return cmp ( this , other ) <EOL> def __gt__ ( self , other ) : <EOL> return self . __cmp__ ( other ) > <NUM_LIT:0> <EOL> def __lt__ ( self , other ) : <EOL> return self . __cmp__ ( other ) < <NUM_LIT:0> <EOL> def __ge__ ( self , other ) : <EOL> return self . __cmp__ ( other ) >= <NUM_LIT:0> <EOL> def __le__ ( self , other ) : <EOL> return self . __cmp__ ( other ) <= <NUM_LIT:0> <EOL> def __eq__ ( self , other ) : <EOL> return self . __cmp__ ( other ) == <NUM_LIT:0> <EOL> def __ne__ ( self , other ) : <EOL> return self . __cmp__ ( other ) != <NUM_LIT:0> <EOL> def clone ( self ) : <EOL> return Message ( * map ( copy , ( self . id , self . string , self . locations , <EOL> self . flags , self . auto_comments , <EOL> self . user_comments , self . previous_id , <EOL> self . lineno , self . context ) ) ) <EOL> def check ( self , catalog = None ) : <EOL> """<STR_LIT>""" <EOL> from babel . messages . checkers import checkers <EOL> errors = [ ] <EOL> for checker in checkers : <EOL> try : <EOL> checker ( catalog , self ) <EOL> except TranslationError as e : <EOL> errors . append ( e ) <EOL> return errors <EOL> @ property <EOL> def fuzzy ( self ) : <EOL> """<STR_LIT>""" <EOL> return '<STR_LIT>' in self . flags <EOL> @ property <EOL> def pluralizable ( self ) : <EOL> """<STR_LIT>""" <EOL> return isinstance ( self . id , ( list , tuple ) ) <EOL> @ property <EOL> def python_format ( self ) : <EOL> """<STR_LIT>""" <EOL> ids = self . id <EOL> if not isinstance ( ids , ( list , tuple ) ) : <EOL> ids = [ ids ] <EOL> return any ( PYTHON_FORMAT . search ( id ) for id in ids ) <EOL> class TranslationError ( Exception ) : <EOL> """<STR_LIT>""" <EOL> DEFAULT_HEADER = u"""<STR_LIT>""" <EOL> if PY2 : <EOL> def _parse_header ( header_string ) : <EOL> headers = message_from_string ( header_string . encode ( '<STR_LIT:utf8>' ) ) <EOL> decoded_headers = { } <EOL> for name , value in headers . items ( ) : <EOL> name = name . decode ( '<STR_LIT:utf8>' ) <EOL> value = value . decode ( '<STR_LIT:utf8>' ) <EOL> decoded_headers [ name ] = value <EOL> return decoded_headers <EOL> else : <EOL> _parse_header = message_from_string <EOL> class Catalog ( object ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , locale = None , domain = None , header_comment = DEFAULT_HEADER , <EOL> project = None , version = None , copyright_holder = None , <EOL> msgid_bugs_address = None , creation_date = None , <EOL> revision_date = None , last_translator = None , language_team = None , <EOL> charset = None , fuzzy = True ) : <EOL> """<STR_LIT>""" <EOL> self . domain = domain <EOL> if locale : <EOL> locale = Locale . parse ( locale ) <EOL> self . locale = locale <EOL> self . _header_comment = header_comment <EOL> self . _messages = odict ( ) <EOL> self . project = project or '<STR_LIT>' <EOL> self . version = version or '<STR_LIT>' <EOL> self . copyright_holder = copyright_holder or '<STR_LIT>' <EOL> self . msgid_bugs_address = msgid_bugs_address or '<STR_LIT>' <EOL> self . last_translator = last_translator or '<STR_LIT>' <EOL> """<STR_LIT>""" <EOL> self . language_team = language_team or '<STR_LIT>' <EOL> """<STR_LIT>""" <EOL> self . charset = charset or '<STR_LIT:utf-8>' <EOL> if creation_date is None : <EOL> creation_date = datetime . now ( LOCALTZ ) <EOL> elif isinstance ( creation_date , datetime ) and not creation_date . tzinfo : <EOL> creation_date = creation_date . replace ( tzinfo = LOCALTZ ) <EOL> self . creation_date = creation_date <EOL> if revision_date is None : <EOL> revision_date = '<STR_LIT>' <EOL> elif isinstance ( revision_date , datetime ) and not revision_date . tzinfo : <EOL> revision_date = revision_date . replace ( tzinfo = LOCALTZ ) <EOL> self . revision_date = revision_date <EOL> self . fuzzy = fuzzy <EOL> self . obsolete = odict ( ) <EOL> self . _num_plurals = None <EOL> self . _plural_expr = None <EOL> def _get_header_comment ( self ) : <EOL> comment = self . _header_comment <EOL> year = datetime . now ( LOCALTZ ) . strftime ( '<STR_LIT>' ) <EOL> if hasattr ( self . revision_date , '<STR_LIT>' ) : <EOL> year = self . revision_date . strftime ( '<STR_LIT>' ) <EOL> comment = comment . replace ( '<STR_LIT>' , self . project ) . replace ( '<STR_LIT>' , self . version ) . replace ( '<STR_LIT>' , year ) . replace ( '<STR_LIT>' , self . copyright_holder ) <EOL> if self . locale : <EOL> comment = comment . replace ( '<STR_LIT>' , '<STR_LIT>' <EOL> % self . locale . english_name ) <EOL> return comment <EOL> def _set_header_comment ( self , string ) : <EOL> self . _header_comment = string <EOL> header_comment = property ( _get_header_comment , _set_header_comment , doc = """<STR_LIT>""" ) <EOL> def _get_mime_headers ( self ) : <EOL> headers = [ ] <EOL> headers . append ( ( '<STR_LIT>' , <EOL> '<STR_LIT>' % ( self . project , self . version ) ) ) <EOL> headers . append ( ( '<STR_LIT>' , self . msgid_bugs_address ) ) <EOL> headers . append ( ( '<STR_LIT>' , <EOL> format_datetime ( self . creation_date , '<STR_LIT>' , <EOL> locale = '<STR_LIT>' ) ) ) <EOL> if isinstance ( self . revision_date , ( datetime , time_ ) + number_types ) : <EOL> headers . append ( ( '<STR_LIT>' , <EOL> format_datetime ( self . revision_date , <EOL> '<STR_LIT>' , locale = '<STR_LIT>' ) ) ) <EOL> else : <EOL> headers . append ( ( '<STR_LIT>' , self . revision_date ) ) <EOL> headers . append ( ( '<STR_LIT>' , self . last_translator ) ) <EOL> if ( self . locale is not None ) and ( '<STR_LIT>' in self . language_team ) : <EOL> headers . append ( ( '<STR_LIT>' , <EOL> self . language_team . replace ( '<STR_LIT>' , <EOL> str ( self . locale ) ) ) ) <EOL> else : <EOL> headers . append ( ( '<STR_LIT>' , self . language_team ) ) <EOL> if self . locale is not None : <EOL> headers . append ( ( '<STR_LIT>' , self . plural_forms ) ) <EOL> headers . append ( ( '<STR_LIT>' , '<STR_LIT:1.0>' ) ) <EOL> headers . append ( ( '<STR_LIT:Content-Type>' , <EOL> '<STR_LIT>' % self . charset ) ) <EOL> headers . append ( ( '<STR_LIT>' , '<STR_LIT>' ) ) <EOL> headers . append ( ( '<STR_LIT>' , '<STR_LIT>' % VERSION ) ) <EOL> return headers <EOL> def _set_mime_headers ( self , headers ) : <EOL> for name , value in headers : <EOL> name = name . lower ( ) <EOL> if name == '<STR_LIT>' : <EOL> parts = value . split ( '<STR_LIT:U+0020>' ) <EOL> self . project = u'<STR_LIT:U+0020>' . join ( parts [ : - <NUM_LIT:1> ] ) <EOL> self . version = parts [ - <NUM_LIT:1> ] <EOL> elif name == '<STR_LIT>' : <EOL> self . msgid_bugs_address = value <EOL> elif name == '<STR_LIT>' : <EOL> self . last_translator = value <EOL> elif name == '<STR_LIT>' : <EOL> self . language_team = value <EOL> elif name == '<STR_LIT>' : <EOL> mimetype , params = parse_header ( value ) <EOL> if '<STR_LIT>' in params : <EOL> self . charset = params [ '<STR_LIT>' ] . lower ( ) <EOL> elif name == '<STR_LIT>' : <EOL> _ , params = parse_header ( '<STR_LIT>' + value ) <EOL> self . _num_plurals = int ( params . get ( '<STR_LIT>' , <NUM_LIT:2> ) ) <EOL> self . _plural_expr = params . get ( '<STR_LIT>' , '<STR_LIT>' ) <EOL> elif name == '<STR_LIT>' : <EOL> self . creation_date = _parse_datetime_header ( value ) <EOL> elif name == '<STR_LIT>' : <EOL> if '<STR_LIT>' not in value : <EOL> self . revision_date = _parse_datetime_header ( value ) <EOL> mime_headers = property ( _get_mime_headers , _set_mime_headers , doc = """<STR_LIT>""" ) <EOL> @ property <EOL> def num_plurals ( self ) : <EOL> """<STR_LIT>""" <EOL> if self . _num_plurals is None : <EOL> num = <NUM_LIT:2> <EOL> if self . locale : <EOL> num = get_plural ( self . locale ) [ <NUM_LIT:0> ] <EOL> self . _num_plurals = num <EOL> return self . _num_plurals <EOL> @ property <EOL> def plural_expr ( self ) : <EOL> """<STR_LIT>""" <EOL> if self . _plural_expr is None : <EOL> expr = '<STR_LIT>' <EOL> if self . locale : <EOL> expr = get_plural ( self . locale ) [ <NUM_LIT:1> ] <EOL> self . _plural_expr = expr <EOL> return self . _plural_expr <EOL> @ property <EOL> def plural_forms ( self ) : <EOL> """<STR_LIT>""" <EOL> return '<STR_LIT>' % ( self . num_plurals , self . plural_expr ) <EOL> def __contains__ ( self , id ) : <EOL> """<STR_LIT>""" <EOL> return self . _key_for ( id ) in self . _messages <EOL> def __len__ ( self ) : <EOL> """<STR_LIT>""" <EOL> return len ( self . _messages ) <EOL> def __iter__ ( self ) : <EOL> """<STR_LIT>""" <EOL> buf = [ ] <EOL> for name , value in self . mime_headers : <EOL> buf . append ( '<STR_LIT>' % ( name , value ) ) <EOL> flags = set ( ) <EOL> if self . fuzzy : <EOL> flags |= set ( [ '<STR_LIT>' ] ) <EOL> yield Message ( u'<STR_LIT>' , '<STR_LIT:\n>' . join ( buf ) , flags = flags ) <EOL> for key in self . _messages : <EOL> yield self . _messages [ key ] <EOL> def __repr__ ( self ) : <EOL> locale = '<STR_LIT>' <EOL> if self . locale : <EOL> locale = '<STR_LIT>' % self . locale <EOL> return '<STR_LIT>' % ( type ( self ) . __name__ , self . domain , locale ) <EOL> def __delitem__ ( self , id ) : <EOL> """<STR_LIT>""" <EOL> self . delete ( id ) <EOL> def __getitem__ ( self , id ) : <EOL> """<STR_LIT>""" <EOL> return self . get ( id ) <EOL> def __setitem__ ( self , id , message ) : <EOL> """<STR_LIT>""" <EOL> assert isinstance ( message , Message ) , '<STR_LIT>' <EOL> key = self . _key_for ( id , message . context ) <EOL> current = self . _messages . get ( key ) <EOL> if current : <EOL> if message . pluralizable and not current . pluralizable : <EOL> current . id = message . id <EOL> current . string = message . string <EOL> current . locations = list ( distinct ( current . locations + <EOL> message . locations ) ) <EOL> current . auto_comments = list ( distinct ( current . auto_comments + <EOL> message . auto_comments ) ) <EOL> current . user_comments = list ( distinct ( current . user_comments + <EOL> message . user_comments ) ) <EOL> current . flags |= message . flags <EOL> message = current <EOL> elif id == '<STR_LIT>' : <EOL> self . mime_headers = _parse_header ( message . string ) . items ( ) <EOL> self . header_comment = '<STR_LIT:\n>' . join ( [ ( '<STR_LIT>' % c ) . rstrip ( ) for c <EOL> in message . user_comments ] ) <EOL> self . fuzzy = message . fuzzy <EOL> else : <EOL> if isinstance ( id , ( list , tuple ) ) : <EOL> assert isinstance ( message . string , ( list , tuple ) ) , '<STR_LIT>' % type ( message . string ) <EOL> self . _messages [ key ] = message <EOL> def add ( self , id , string = None , locations = ( ) , flags = ( ) , auto_comments = ( ) , <EOL> user_comments = ( ) , previous_id = ( ) , lineno = None , context = None ) : <EOL> """<STR_LIT>""" <EOL> message = Message ( id , string , list ( locations ) , flags , auto_comments , <EOL> user_comments , previous_id , lineno = lineno , <EOL> context = context ) <EOL> self [ id ] = message <EOL> return message <EOL> def check ( self ) : <EOL> """<STR_LIT>""" <EOL> for message in self . _messages . values ( ) : <EOL> errors = message . check ( catalog = self ) <EOL> if errors : <EOL> yield message , errors <EOL> def get ( self , id , context = None ) : <EOL> """<STR_LIT>""" <EOL> return self . _messages . get ( self . _key_for ( id , context ) ) <EOL> def delete ( self , id , context = None ) : <EOL> """<STR_LIT>""" <EOL> key = self . _key_for ( id , context ) <EOL> if key in self . _messages : <EOL> del self . _messages [ key ] <EOL> def update ( self , template , no_fuzzy_matching = False ) : <EOL> """<STR_LIT>""" <EOL> messages = self . _messages <EOL> remaining = messages . copy ( ) <EOL> self . _messages = odict ( ) <EOL> fuzzy_candidates = [ ] <EOL> if not no_fuzzy_matching : <EOL> fuzzy_candidates = dict ( [ <EOL> ( self . _key_for ( msgid ) , messages [ msgid ] . context ) <EOL> for msgid in messages if msgid and messages [ msgid ] . string <EOL> ] ) <EOL> fuzzy_matches = set ( ) <EOL> def _merge ( message , oldkey , newkey ) : <EOL> message = message . clone ( ) <EOL> fuzzy = False <EOL> if oldkey != newkey : <EOL> fuzzy = True <EOL> fuzzy_matches . add ( oldkey ) <EOL> oldmsg = messages . get ( oldkey ) <EOL> if isinstance ( oldmsg . id , string_types ) : <EOL> message . previous_id = [ oldmsg . id ] <EOL> else : <EOL> message . previous_id = list ( oldmsg . id ) <EOL> else : <EOL> oldmsg = remaining . pop ( oldkey , None ) <EOL> message . string = oldmsg . string <EOL> if isinstance ( message . id , ( list , tuple ) ) : <EOL> if not isinstance ( message . string , ( list , tuple ) ) : <EOL> fuzzy = True <EOL> message . string = tuple ( <EOL> [ message . string ] + ( [ u'<STR_LIT>' ] * ( len ( message . id ) - <NUM_LIT:1> ) ) <EOL> ) <EOL> elif len ( message . string ) != self . num_plurals : <EOL> fuzzy = True <EOL> message . string = tuple ( message . string [ : len ( oldmsg . string ) ] ) <EOL> elif isinstance ( message . string , ( list , tuple ) ) : <EOL> fuzzy = True <EOL> message . string = message . string [ <NUM_LIT:0> ] <EOL> message . flags |= oldmsg . flags <EOL> if fuzzy : <EOL> message . flags |= set ( [ u'<STR_LIT>' ] ) <EOL> self [ message . id ] = message <EOL> for message in template : <EOL> if message . id : <EOL> key = self . _key_for ( message . id , message . context ) <EOL> if key in messages : <EOL> _merge ( message , key , key ) <EOL> else : <EOL> if no_fuzzy_matching is False : <EOL> if isinstance ( key , tuple ) : <EOL> matchkey = key [ <NUM_LIT:0> ] <EOL> else : <EOL> matchkey = key <EOL> matches = get_close_matches ( matchkey . lower ( ) . strip ( ) , <EOL> fuzzy_candidates . keys ( ) , <NUM_LIT:1> ) <EOL> if matches : <EOL> newkey = matches [ <NUM_LIT:0> ] <EOL> newctxt = fuzzy_candidates [ newkey ] <EOL> if newctxt is not None : <EOL> newkey = newkey , newctxt <EOL> _merge ( message , newkey , key ) <EOL> continue <EOL> self [ message . id ] = message <EOL> for msgid in remaining : <EOL> if no_fuzzy_matching or msgid not in fuzzy_matches : <EOL> self . obsolete [ msgid ] = remaining [ msgid ] <EOL> self . creation_date = template . creation_date <EOL> def _key_for ( self , id , context = None ) : <EOL> """<STR_LIT>""" <EOL> key = id <EOL> if isinstance ( key , ( list , tuple ) ) : <EOL> key = id [ <NUM_LIT:0> ] <EOL> if context is not None : <EOL> key = ( key , context ) <EOL> return key </s>
