1. Konstantine Rybnikov
  2. fat_po_editor


fat_po_editor / fat_po_editor / diff_util.py

# -*- 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


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

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

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


    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 append_entry(self, operation_type, entry):
        :param `operation_type`:
            one of ['add', 'rm', 'modify']
        :param entry:
            :class:`~polib.POEntry` instance for add and rm operations,
            [:class:`~polib.POEntry`, :class:`~polib.POEntry`] for modify
            operation (describes old and new elements)
        assert operation_type in self.operation_types
        if operation_type == 'modify':
            assert isiterable(entry)
            entry = list(entry)
            assert len(entry) == 2
            assert isinstance(entry, POEntry)
        storage = self.operation_to_storage_map[operation_type]

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

    def __repr__(self):
        rv = StringBuilder(unicode(super(PODiff, self).__repr__()))
        rv += u' (%(add_num)s add, %(rm_num)s rm, %(modify_num)s modify)' \
            % dict(add_num=len(self.operation_to_storage_map['add']),
        return unicode(rv)

    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,
                                             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,
                                             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,
                                             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 PODiff. Used to make sure that two PODiff's are
        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[1]))
            rv += u'\n'
            rv += prefix_lines('- ', unicode(item[0]))
            rv += u'\n'
        return unicode(rv)

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

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

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

    rv = PODiff()
    pofile1_msgid_to_poentry_map = dict(map(lambda entry: (entry.msgid, entry), pofile1))
    pofile2_msgid_to_poentry_map = dict(map(lambda entry: (entry.msgid, entry), pofile2))
    for item in pofile2:
        if item.msgid not in pofile1_msgid_to_poentry_map:
            rv.append_entry('add', item)
            old_item = pofile1_msgid_to_poentry_map[item.msgid]
            if unicode(item) != unicode(old_item):
                rv.append_entry('modify', [old_item, item])
    for item in pofile1:
        if item.msgid not in pofile2_msgid_to_poentry_map:
            rv.append_entry('rm', item)

    return rv