Source

fat_po_editor / fat_po_editor / diffutil.py

Full commit
# -*- coding: utf-8 -*-

from polib import POEntry

from fat_po_editor.util import isiterable
from fat_po_editor import _
from fat_po_editor.util import StringBuilder

MAXLEN = 80

class Diff(object):
    """This class implements storage of diff data between two po-files.

    It:
    
    - knows which phrases were added, removed or changed.
    - can display them in various formats.

    Entries of diff should be in :class:`~polib.POEntry` format.

    :internal:
    """

    def __init__(self):
        self.entries_add = []
        self.entries_rm = []
        self.entries_modified = []

        self.operation_to_storage_map = {
            'add': self.entries_add,
            'rm': self.entries_rm,
            'modify': self.entries_modified
        }
        self.operation_types = self.operation_to_storage_map.keys()
    
    def entry_append(self, operation_type, entry):
        """
        ``operation_type``
            one of ['add', 'rm', 'modify']
        """
        assert operation_type in self.operation_types
        if operation_type == 'modify':
            assert isiterable(entry)
            entry = list(entry)
            assert len(entry) == 2
        else:
            assert isinstance(entry, POEntry)
        storage = self.operation_to_storage_map[operation_type]
        storage.append(entry)

    def get_entries(self, operation_type):
        assert operation_type in self.operation_types
        return self.operation_to_storage_map[operation_type]

    def __unicode__(self):
        """Gives a nice text representation of what happened."""
        def esc_chunk(s, maxlen):
            """Escapes chunk's ``\\n`` symbols etc. and returns a chunk
            of that.
            """
            from polib import escape
            
            def chunk(s, maxlen):
                if len(s) > maxlen - 3:
                    return u"".join([s[:maxlen - 3], '...'])
                return s

            return chunk(escape(s), maxlen)
        
        rv = StringBuilder()
        
        list_prefix = u"    * "
        if len(self.operation_to_storage_map['add']):
            rv += _(u"Added phrases:\n")
            for item in self.operation_to_storage_map['add']:
                rv += u"%s%s\n" % (list_prefix,
                                   esc_chunk(item.msgid,
                                             MAXLEN - len(list_prefix)))
        if len(self.operation_to_storage_map['rm']):
            rv += _(u"Removed phrases:\n")
            for item in self.operation_to_storage_map['rm']:
                rv += u"%s%s\n" % (list_prefix,
                                   esc_chunk(item.msgid,
                                             MAXLEN - len(list_prefix)))
        if len(self.operation_to_storage_map['modify']):
            rv += _(u"Modified translation of phrases:\n")
            for item in self.operation_to_storage_map['modify']:
                rv += u"%s%s\n" % (list_prefix,
                                   esc_chunk(item[0].msgid,
                                             MAXLEN - len(list_prefix)))
        return unicode(rv)
    
    def full_represent(self):
        """Full represent should guaranty that it represent all the information
        needed to fully describe Diff. Used to make sure that two Diff's are
        equal.
        """
        def prefix_lines(prefix, text):
            return u"\n".join(u"".join([prefix, line])
                              for line in text.splitlines())
        
        rv = StringBuilder()
        for item in self.operation_to_storage_map['add']:
            rv += prefix_lines('+ ', unicode(item))
            rv += u'\n'
        for item in self.operation_to_storage_map['rm']:
            rv += prefix_lines('- ', unicode(item))
            rv += u'\n'
        for item in self.operation_to_storage_map['modify']:
            rv += prefix_lines('+ ', unicode(item[0]))
            rv += u'\n'
            rv += prefix_lines('- ', unicode(item[1]))
            rv += u'\n'
        return unicode(rv)

    def __eq__(self, other):
        if not isinstance(other, Diff):
            return False
        return self.full_represent() == other.full_represent()

def compare_two_pofiles(pofile1, pofile2):
    """Returns :class:`~Diff` object that represents difference between two po
    files.

    ``pofile1``, ``pofile2``
        :class:`~polib.POFile` instances.
    """
    
    pass