def encode_truncate(text, limit, encoding='utf8', return_encoded=True):
    """
    Given a string, return a truncated version of the string such that
    the UTF8 encoding of the string is smaller than the given limit.

    This function correctly truncates even in the presence of Unicode code
    points that encode to multi-byte encodings which must not be truncated
    in the middle.

    :param text: The (Unicode) string to truncate.
    :type text: str
    :param limit: The number of bytes to limit the UTF8 encoding to.
    :type limit: int
    :param encoding: Truncate the string in this encoding (default is ``utf-8``).
    :type encoding: str
    :param return_encoded: If ``True``, return the string encoded into bytes
        according to the specified encoding, else return the string as a string.
    :type return_encoded: bool

    :returns: The truncated string.
    :rtype: str or bytes
    """
    assert(text is None or type(text) == str)
    assert(type(limit) == int)
    assert(limit >= 0)

    if text is None:
        return

    # encode the given string in the specified encoding
    s = text.encode(encoding)

    # when the resulting byte string is longer than the given limit ..
    if len(s) > limit:
        # .. truncate, and
        s = s[:limit]

        # decode back, ignoring errors that result from truncation
        # in the middle of multi-byte encodings
        text = s.decode(encoding, 'ignore')

        if return_encoded:
            s = text.encode(encoding)

    if return_encoded:
        return s
    else:
        return text