<s> from __future__ import absolute_import <EOL> import codecs <EOL> import copy <EOL> import logging <EOL> import os <EOL> from l20n . format . parser import L20nParser <EOL> from l20n . format . serializer import Serializer <EOL> from l20n . format import ast <EOL> from pontoon . sync import SyncError <EOL> from pontoon . sync . formats . base import ParsedResource <EOL> from pontoon . sync . vcs . models import VCSTranslation <EOL> log = logging . getLogger ( __name__ ) <EOL> class L20NEntity ( VCSTranslation ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , key , source_string , source_string_plural , strings , comments = None , order = None ) : <EOL> super ( L20NEntity , self ) . __init__ ( <EOL> key = key , <EOL> source_string = source_string , <EOL> source_string_plural = source_string_plural , <EOL> strings = strings , <EOL> comments = comments or [ ] , <EOL> fuzzy = False , <EOL> order = order , <EOL> ) <EOL> def __repr__ ( self ) : <EOL> return '<STR_LIT>' . format ( key = self . key . encode ( '<STR_LIT:utf-8>' ) ) <EOL> class L20NResource ( ParsedResource ) : <EOL> def __init__ ( self , path , locale , source_resource = None ) : <EOL> self . path = path <EOL> self . locale = locale <EOL> self . entities = { } <EOL> self . source_resource = source_resource <EOL> if source_resource : <EOL> for key , entity in source_resource . entities . items ( ) : <EOL> self . entities [ key ] = L20NEntity ( <EOL> entity . key , <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> { } , <EOL> copy . copy ( entity . comments ) , <EOL> entity . order <EOL> ) <EOL> with codecs . open ( path , '<STR_LIT:r>' , '<STR_LIT:utf-8>' ) as resource : <EOL> self . structure = L20nParser ( ) . parse ( resource . read ( ) ) <EOL> order = <NUM_LIT:0> <EOL> comments = [ ] <EOL> for obj in self . structure . body : <EOL> if obj . type == '<STR_LIT>' : <EOL> if obj . value and obj . value . type == '<STR_LIT>' : <EOL> self . entities [ obj . id . name ] = L20NEntity ( <EOL> obj . id . name , <EOL> obj . value . source , <EOL> '<STR_LIT>' , <EOL> { None : obj . value . source } , <EOL> comments , <EOL> order <EOL> ) <EOL> order += <NUM_LIT:1> <EOL> elif obj . value and obj . value . type == '<STR_LIT>' : <EOL> strings = { <EOL> self . locale . get_plural_index ( item . id . name ) : <EOL> item . value . source for item in obj . value . items <EOL> } <EOL> self . entities [ obj . id . name ] = L20NEntity ( <EOL> obj . id . name , <EOL> strings . get ( <NUM_LIT:0> , '<STR_LIT>' ) , <EOL> strings . get ( <NUM_LIT:1> , '<STR_LIT>' ) , <EOL> strings , <EOL> comments , <EOL> order <EOL> ) <EOL> order += <NUM_LIT:1> <EOL> for attr in obj . attrs : <EOL> key = '<STR_LIT:.>' . join ( [ obj . id . name , attr . id . name ] ) <EOL> self . entities [ key ] = L20NEntity ( <EOL> key , <EOL> attr . value . source , <EOL> '<STR_LIT>' , <EOL> { None : attr . value . source } , <EOL> order = order <EOL> ) <EOL> order += <NUM_LIT:1> <EOL> comments = [ ] <EOL> elif obj . type == '<STR_LIT>' : <EOL> comments . append ( obj . body ) <EOL> else : <EOL> comments = [ ] <EOL> @ property <EOL> def translations ( self ) : <EOL> return sorted ( self . entities . values ( ) , key = lambda e : e . order ) <EOL> def save ( self , locale ) : <EOL> """<STR_LIT>""" <EOL> if not self . source_resource : <EOL> raise SyncError ( '<STR_LIT>' <EOL> . format ( self . path ) ) <EOL> with codecs . open ( self . source_resource . path , '<STR_LIT:r>' , '<STR_LIT:utf-8>' ) as resource : <EOL> new_structure = L20nParser ( ) . parse ( resource . read ( ) ) <EOL> def attr_key ( entity , attr ) : <EOL> """<STR_LIT>""" <EOL> return '<STR_LIT:.>' . join ( [ entity . id . name , attr . id . name ] ) <EOL> to_remove = [ ] <EOL> for res_entity in new_structure . body : <EOL> if res_entity . type == '<STR_LIT>' : <EOL> entity_id = res_entity . id . name <EOL> translations = self . entities [ entity_id ] . strings <EOL> comments = self . entities [ entity_id ] . comments <EOL> if not translations : <EOL> entity_idx = new_structure . body . index ( res_entity ) <EOL> for comment_entity in new_structure . body [ entity_idx - len ( comments ) : entity_idx ] : <EOL> to_remove . append ( ( new_structure . body , comment_entity ) ) <EOL> has_attributes = any ( [ <EOL> bool ( self . entities [ attr_key ( res_entity , a ) ] . strings ) <EOL> for a in res_entity . attrs <EOL> ] ) <EOL> if has_attributes : <EOL> res_entity . value = None <EOL> else : <EOL> to_remove . append ( ( new_structure . body , res_entity ) ) <EOL> continue <EOL> if res_entity . value and res_entity . value . type == '<STR_LIT>' : <EOL> res_entity . value . content [ <NUM_LIT:0> ] = translations [ None ] <EOL> elif res_entity . value and res_entity . value . type == '<STR_LIT>' : <EOL> res_entity . value . items = [ <EOL> ast . HashItem ( <EOL> ast . Identifier ( locale . get_relative_cldr_plural ( plural_relative_id ) ) , <EOL> ast . String ( [ value ] , value ) , <EOL> False <EOL> ) for plural_relative_id , value in translations . items ( ) ] <EOL> for attr in res_entity . attrs : <EOL> key = attr_key ( res_entity , attr ) <EOL> attr_translations = self . entities [ key ] . strings <EOL> if not attr_translations : <EOL> to_remove . append ( ( res_entity . attrs , attr ) ) <EOL> continue <EOL> attr . value . content [ <NUM_LIT:0> ] = attr_translations [ None ] <EOL> for parent , entity in to_remove : <EOL> parent . remove ( entity ) <EOL> try : <EOL> os . makedirs ( os . path . dirname ( self . path ) ) <EOL> except OSError : <EOL> pass <EOL> with codecs . open ( self . path , '<STR_LIT>' , '<STR_LIT:utf-8>' ) as f : <EOL> f . write ( Serializer ( ) . serialize ( new_structure ) ) <EOL> log . debug ( "<STR_LIT>" , self . path ) <EOL> def parse ( path , source_path = None , locale = None ) : <EOL> if source_path is not None : <EOL> source_resource = L20NResource ( source_path , locale ) <EOL> else : <EOL> source_resource = None <EOL> return L20NResource ( path , locale , source_resource ) </s>
