1 | diff --git a/django/template/defaultfilters.py b/django/template/defaultfilters.py
|
---|
2 | index 865f5fe..19a73ad 100644
|
---|
3 | --- a/django/template/defaultfilters.py
|
---|
4 | +++ b/django/template/defaultfilters.py
|
---|
5 | @@ -16,7 +16,7 @@ from django.utils.html import (conditional_escape, escapejs, fix_ampersands,
|
---|
6 | escape, urlize as _urlize, linebreaks, strip_tags, avoid_wrapping,
|
---|
7 | remove_tags)
|
---|
8 | from django.utils.http import urlquote
|
---|
9 | -from django.utils.text import Truncator, wrap, phone2numeric
|
---|
10 | +from django.utils.text import Truncator, wrap, phone2numeric, word_capital
|
---|
11 | from django.utils.safestring import mark_safe, SafeData, mark_for_escaping
|
---|
12 | from django.utils import six
|
---|
13 | from django.utils.timesince import timesince, timeuntil
|
---|
14 | @@ -266,6 +266,15 @@ def title(value):
|
---|
15 |
|
---|
16 | @register.filter(is_safe=True)
|
---|
17 | @stringfilter
|
---|
18 | +def wordcap(value):
|
---|
19 | + """
|
---|
20 | + Capitalizes the first character of each word.
|
---|
21 | + """
|
---|
22 | + return word_capital(value)
|
---|
23 | +
|
---|
24 | +
|
---|
25 | +@register.filter(is_safe=True)
|
---|
26 | +@stringfilter
|
---|
27 | def truncatechars(value, arg):
|
---|
28 | """
|
---|
29 | Truncates a string after a certain number of characters.
|
---|
30 | diff --git a/django/utils/text.py b/django/utils/text.py
|
---|
31 | index f52050c..8a63ed7 100644
|
---|
32 | --- a/django/utils/text.py
|
---|
33 | +++ b/django/utils/text.py
|
---|
34 | @@ -29,6 +29,18 @@ re_newlines = re.compile(r'\r\n|\r') # Used in normalize_newlines
|
---|
35 | re_camel_case = re.compile(r'(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))')
|
---|
36 |
|
---|
37 |
|
---|
38 | +def word_capital(text):
|
---|
39 | + """
|
---|
40 | + Capitalizes the first character of each word, it converts a string into
|
---|
41 | + titlecase by making words start with an uppercase character and keep the
|
---|
42 | + remaining characters.
|
---|
43 | + """
|
---|
44 | + if text and len(text) > 0:
|
---|
45 | + return ' '.join([s[0].upper() + s[1:] for s in text.split(' ') if len(s) > 0])
|
---|
46 | + else:
|
---|
47 | + return text
|
---|
48 | +
|
---|
49 | +
|
---|
50 | def wrap(text, width):
|
---|
51 | """
|
---|
52 | A word-wrap function that preserves existing line breaks and most spaces in
|
---|
53 | diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt
|
---|
54 | index e5c6efc..b92383a 100644
|
---|
55 | --- a/docs/ref/templates/builtins.txt
|
---|
56 | +++ b/docs/ref/templates/builtins.txt
|
---|
57 | @@ -1214,6 +1214,21 @@ For example::
|
---|
58 |
|
---|
59 | If ``value`` is ``"django"``, the output will be ``"Django"``.
|
---|
60 |
|
---|
61 | +.. templatefilter:: wordcap
|
---|
62 | +
|
---|
63 | +wordcap
|
---|
64 | +^^^^^^^
|
---|
65 | +
|
---|
66 | +Capitalizes the first character of each word, it converts a string into
|
---|
67 | +titlecase by making words start with an uppercase character and keep the
|
---|
68 | +remaining characters.
|
---|
69 | +
|
---|
70 | +For example::
|
---|
71 | +
|
---|
72 | + {{ value|wordcap }}
|
---|
73 | +
|
---|
74 | +If ``value`` is ``"joel SMS content"``, the output will be ``"Joel SMS Content"``.
|
---|
75 | +
|
---|
76 | .. templatefilter:: center
|
---|
77 |
|
---|
78 | center
|
---|
79 | diff --git a/tests/defaultfilters/tests.py b/tests/defaultfilters/tests.py
|
---|
80 | index 2dc6d9c..af0de04 100644
|
---|
81 | --- a/tests/defaultfilters/tests.py
|
---|
82 | +++ b/tests/defaultfilters/tests.py
|
---|
83 | @@ -14,7 +14,7 @@ from django.template.defaultfilters import (
|
---|
84 | phone2numeric_filter, pluralize, removetags, rjust, slice_filter, slugify,
|
---|
85 | stringformat, striptags, time, timesince_filter, timeuntil_filter, title,
|
---|
86 | truncatewords, truncatewords_html, unordered_list, upper, urlencode,
|
---|
87 | - urlize, urlizetrunc, wordcount, wordwrap, yesno,
|
---|
88 | + urlize, urlizetrunc, wordcount, wordwrap, yesno, wordcap,
|
---|
89 | )
|
---|
90 | from django.test import TestCase
|
---|
91 | from django.test.utils import TransRealMixin
|
---|
92 | @@ -111,6 +111,9 @@ class DefaultFiltersTests(TestCase):
|
---|
93 | def test_capfirst(self):
|
---|
94 | self.assertEqual(capfirst('hello world'), 'Hello world')
|
---|
95 |
|
---|
96 | + def test_wordcap(self):
|
---|
97 | + self.assertEqual(wordcap('send SMS'), 'Send SMS')
|
---|
98 | +
|
---|
99 | def test_escapejs(self):
|
---|
100 | self.assertEqual(escapejs_filter('"double quotes" and \'single quotes\''),
|
---|
101 | '\\u0022double quotes\\u0022 and \\u0027single quotes\\u0027')
|
---|
102 | diff --git a/tests/template_tests/tests.py b/tests/template_tests/tests.py
|
---|
103 | index 0afb3a8..8df0599 100644
|
---|
104 | --- a/tests/template_tests/tests.py
|
---|
105 | +++ b/tests/template_tests/tests.py
|
---|
106 | @@ -1503,6 +1503,9 @@ class TemplateTests(TransRealMixin, TestCase):
|
---|
107 | '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'),
|
---|
108 | '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; '),
|
---|
109 |
|
---|
110 | + # test wordcap with the {% trans %} tag
|
---|
111 | + 'i18n39': ("{% load i18n %}{% trans 'Page not found'|wordcap %}", {'LANGUAGE_CODE': 'de'}, 'Seite Nicht Gefunden'),
|
---|
112 | +
|
---|
113 | ### HANDLING OF TEMPLATE_STRING_IF_INVALID ###################################
|
---|
114 |
|
---|
115 | 'invalidstr01': ('{{ var|default:"Foo" }}', {}, ('Foo', 'INVALID')),
|
---|