Ticket #5025: updated-truncatechars-5075.diff

File updated-truncatechars-5075.diff, 4.9 KB (added by floguy, 13 years ago)

Updated truncatechars patch

  • django/utils/text.py

     
    11import re
     2import unicodedata
    23from django.utils.encoding import force_unicode
    34from django.utils.functional import allow_lazy
    45from django.utils.translation import ugettext_lazy, ugettext as _
     
    3637    return u''.join(_generator())
    3738wrap = allow_lazy(wrap, unicode)
    3839
     40def truncate_chars(s, num, end_text='...'):
     41    """Truncates a string after a certain number of characters. Takes an
     42    optional argument of what should be used to notify that the string has been
     43    truncated, defaulting to ellipsis (...)"""
     44    s = force_unicode(s)
     45    length = int(num)
     46   
     47    normalized = unicodedata.normalize('NFC', s)
     48   
     49    # If the text is short enough, we can bail out right now
     50    if len(normalized) <= length:
     51        return normalized
     52   
     53    translated_end_text = _(end_text)
     54    len_end_text = len(translated_end_text)
     55   
     56    end_index = max(length-len_end_text, 0)
     57    while unicodedata.combining(normalized[end_index]) and end_index < len(normalized):
     58        end_index += 1
     59   
     60    return u'%s%s' % (normalized[:end_index], translated_end_text)
     61truncate_chars = allow_lazy(truncate_chars, unicode)
     62
    3963def truncate_words(s, num, end_text='...'):
    4064    """Truncates a string after a certain number of words. Takes an optional
    4165    argument of what should be used to notify that the string has been
  • django/template/defaultfilters.py

     
    251251title.is_safe = True
    252252title = stringfilter(title)
    253253
     254def truncatechars(value, arg):
     255    """
     256    Truncates a string after a certain number of characters.
     257   
     258    Argument: Number of characters to truncate after.
     259    """
     260    from django.utils.text import truncate_chars
     261    try:
     262        length = int(arg)
     263    except ValueError: # Invalid literal for int().
     264        return value # Fail silently.
     265    return truncate_chars(value, length)
     266truncatechars.is_safe = True
     267truncatechars = stringfilter(truncatechars)
     268
    254269def truncatewords(value, arg):
    255270    """
    256271    Truncates a string after a certain number of words.
  • tests/regressiontests/utils/text.py

     
     1# -*- coding: utf-8 -*-
    12import unittest
    23
    34from django.utils import text
     
    45
    56class TestUtilsText(unittest.TestCase):
    67
     8    def test_truncate_chars(self):
     9        self.assertEqual(u'The quick brown fox jumped over the lazy dog.',
     10            text.truncate_chars(u'The quick brown fox jumped over the lazy dog.', 100))
     11        self.assertEqual(u'The quick brown fox ...',
     12            text.truncate_chars('The quick brown fox jumped over the lazy dog.', 23))
     13        self.assertEqual(u'The quick brown fox ....',
     14            text.truncate_chars('The quick brown fox jumped over the lazy dog.', 24, '....'))
     15       
     16        # Ensure that we normalize our unicode data first
     17        nfc = u'o\xfco\xfco\xfco\xfc'
     18        nfd = u'ou\u0308ou\u0308ou\u0308ou\u0308'
     19        self.assertEqual(u'oüoüoüoü', text.truncate_chars(nfc, 8))
     20        self.assertEqual(u'oüoüoüoü', text.truncate_chars(nfd, 8))
     21        self.assertEqual(u'oü...', text.truncate_chars(nfc, 5))
     22        self.assertEqual(u'oü...', text.truncate_chars(nfd, 5))
     23       
     24        # We shouldn't split combining characters up
     25        self.assertEqual(u'__B\u030A...',
     26            text.truncate_chars(u'__B\u030A____', 6))
     27       
     28        # Make a best effort to shorten to the desired length, but requesting
     29        # a length shorter than the ellipsis shouldn't break
     30        self.assertEqual(u'...', text.truncate_chars(u'asdf', 1))
     31
    732    def test_truncate_words(self):
    833        self.assertEqual(u'The quick brown fox jumped over the lazy dog.',
    934            text.truncate_words(u'The quick brown fox jumped over the lazy dog.', 10))
  • docs/ref/templates/builtins.txt

     
    19891989
    19901990If ``value`` is ``"my first post"``, the output will be ``"My First Post"``.
    19911991
     1992.. templatefilter:: truncatechars
     1993
     1994truncatechars
     1995~~~~~~~~~~~~~
     1996
     1997Truncates a string after a certain number of characters.
     1998
     1999**Argument:** Number of characters to truncate after
     2000
     2001For example::
     2002
     2003    {{ value|truncatechars:11 }}
     2004
     2005If ``value`` is ``"Joel is a slug"``, the output will be ``"Joel is ..."``.
     2006
    19922007.. templatefilter:: truncatewords
    19932008
    19942009truncatewords
Back to Top