diff --git a/django/template/defaultfilters.py b/django/template/defaultfilters.py index 865f5fe..19a73ad 100644 --- a/django/template/defaultfilters.py +++ b/django/template/defaultfilters.py @@ -16,7 +16,7 @@ from django.utils.html import (conditional_escape, escapejs, fix_ampersands, escape, urlize as _urlize, linebreaks, strip_tags, avoid_wrapping, remove_tags) from django.utils.http import urlquote -from django.utils.text import Truncator, wrap, phone2numeric +from django.utils.text import Truncator, wrap, phone2numeric, word_capital from django.utils.safestring import mark_safe, SafeData, mark_for_escaping from django.utils import six from django.utils.timesince import timesince, timeuntil @@ -266,6 +266,15 @@ def title(value): @register.filter(is_safe=True) @stringfilter +def wordcap(value): + """ + Capitalizes the first character of each word. + """ + return word_capital(value) + + +@register.filter(is_safe=True) +@stringfilter def truncatechars(value, arg): """ Truncates a string after a certain number of characters. diff --git a/django/utils/text.py b/django/utils/text.py index f52050c..8a63ed7 100644 --- a/django/utils/text.py +++ b/django/utils/text.py @@ -29,6 +29,18 @@ re_newlines = re.compile(r'\r\n|\r') # Used in normalize_newlines re_camel_case = re.compile(r'(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))') +def word_capital(text): + """ + Capitalizes the first character of each word, it converts a string into + titlecase by making words start with an uppercase character and keep the + remaining characters. + """ + if text and len(text) > 0: + return ' '.join([s[0].upper() + s[1:] for s in text.split(' ') if len(s) > 0]) + else: + return text + + def wrap(text, width): """ A word-wrap function that preserves existing line breaks and most spaces in diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt index e5c6efc..b92383a 100644 --- a/docs/ref/templates/builtins.txt +++ b/docs/ref/templates/builtins.txt @@ -1214,6 +1214,21 @@ For example:: If ``value`` is ``"django"``, the output will be ``"Django"``. +.. templatefilter:: wordcap + +wordcap +^^^^^^^ + +Capitalizes the first character of each word, it converts a string into +titlecase by making words start with an uppercase character and keep the +remaining characters. + +For example:: + + {{ value|wordcap }} + +If ``value`` is ``"joel SMS content"``, the output will be ``"Joel SMS Content"``. + .. templatefilter:: center center diff --git a/tests/defaultfilters/tests.py b/tests/defaultfilters/tests.py index 2dc6d9c..af0de04 100644 --- a/tests/defaultfilters/tests.py +++ b/tests/defaultfilters/tests.py @@ -14,7 +14,7 @@ from django.template.defaultfilters import ( phone2numeric_filter, pluralize, removetags, rjust, slice_filter, slugify, stringformat, striptags, time, timesince_filter, timeuntil_filter, title, truncatewords, truncatewords_html, unordered_list, upper, urlencode, - urlize, urlizetrunc, wordcount, wordwrap, yesno, + urlize, urlizetrunc, wordcount, wordwrap, yesno, wordcap, ) from django.test import TestCase from django.test.utils import TransRealMixin @@ -111,6 +111,9 @@ class DefaultFiltersTests(TestCase): def test_capfirst(self): self.assertEqual(capfirst('hello world'), 'Hello world') + def test_wordcap(self): + self.assertEqual(wordcap('send SMS'), 'Send SMS') + def test_escapejs(self): self.assertEqual(escapejs_filter('"double quotes" and \'single quotes\''), '\\u0022double quotes\\u0022 and \\u0027single quotes\\u0027') diff --git a/tests/template_tests/tests.py b/tests/template_tests/tests.py index 0afb3a8..8df0599 100644 --- a/tests/template_tests/tests.py +++ b/tests/template_tests/tests.py @@ -1503,6 +1503,9 @@ class TemplateTests(TransRealMixin, TestCase): 'i18n38': ('{% load i18n custom %}{% get_language_info for "de"|noop:"x y" as l %}{{ l.code }}: {{ l.name }}/{{ l.name_local }} bidi={{ l.bidi }}', {}, 'de: German/Deutsch bidi=False'), 'i18n38_2': ('{% load i18n custom %}{% get_language_info_list for langcodes|noop:"x y" as langs %}{% for l in langs %}{{ l.code }}: {{ l.name }}/{{ l.name_local }} bidi={{ l.bidi }}; {% endfor %}', {'langcodes': ['it', 'no']}, 'it: Italian/italiano bidi=False; no: Norwegian/norsk bidi=False; '), + # test wordcap with the {% trans %} tag + 'i18n39': ("{% load i18n %}{% trans 'Page not found'|wordcap %}", {'LANGUAGE_CODE': 'de'}, 'Seite Nicht Gefunden'), + ### HANDLING OF TEMPLATE_STRING_IF_INVALID ################################### 'invalidstr01': ('{{ var|default:"Foo" }}', {}, ('Foo', 'INVALID')),