Index: django/contrib/admin/templatetags/admin_modify.py
===================================================================
--- django/contrib/admin/templatetags/admin_modify.py	(revision 2524)
+++ django/contrib/admin/templatetags/admin_modify.py	(working copy)
@@ -200,7 +200,7 @@
 filter_interface_script_maybe = register.simple_tag(filter_interface_script_maybe)
 
 def do_one_arg_tag(node_factory, parser,token):
-    tokens = token.contents.split()
+    tokens = token.split_contents()
     if len(tokens) != 2:
         raise template.TemplateSyntaxError("%s takes 1 argument" % tokens[0])
     return node_factory(tokens[1])
Index: django/contrib/admin/templatetags/adminapplist.py
===================================================================
--- django/contrib/admin/templatetags/adminapplist.py	(revision 2524)
+++ django/contrib/admin/templatetags/adminapplist.py	(working copy)
@@ -49,7 +49,7 @@
     """
     {% get_admin_app_list as app_list %}
     """
-    tokens = token.contents.split()
+    tokens = token.split_contents()
     if len(tokens) < 3:
         raise template.TemplateSyntaxError, "'%s' tag requires two arguments" % tokens[0]
     if tokens[1] != 'as':
Index: django/contrib/admin/templatetags/log.py
===================================================================
--- django/contrib/admin/templatetags/log.py	(revision 2524)
+++ django/contrib/admin/templatetags/log.py	(working copy)
@@ -38,7 +38,7 @@
         self.tag_name = tag_name
 
     def __call__(self, parser, token):
-        tokens = token.contents.split()
+        tokens = token.split_contents()
         if len(tokens) < 4:
             raise template.TemplateSyntaxError, "'%s' statements require two arguments" % self.tag_name
         if not tokens[1].isdigit():
Index: django/contrib/comments/templatetags/comments.py
===================================================================
--- django/contrib/comments/templatetags/comments.py	(revision 2524)
+++ django/contrib/comments/templatetags/comments.py	(working copy)
@@ -147,7 +147,7 @@
         self.free = free
 
     def __call__(self, parser, token):
-        tokens = token.contents.split()
+        tokens = token.split_contents()
         if len(tokens) < 4:
             raise template.TemplateSyntaxError, "%r tag requires at least 3 arguments" % tokens[0]
         if tokens[1] != 'for':
@@ -225,7 +225,7 @@
         self.free = free
 
     def __call__(self, parser, token):
-        tokens = token.contents.split()
+        tokens = token.split_contents()
         # Now tokens is a list like this:
         # ['get_comment_list', 'for', 'lcom.eventtimes', 'event.id', 'as', 'comment_list']
         if len(tokens) != 6:
@@ -280,7 +280,7 @@
         self.free = free
 
     def __call__(self, parser, token):
-        tokens = token.contents.split()
+        tokens = token.split_contents()
         # Now tokens is a list like this:
         # ['get_comment_list', 'for', 'lcom.eventtimes', 'event.id', 'as', 'comment_list']
         if not len(tokens) in (6, 7):
Index: django/core/template/__init__.py
===================================================================
--- django/core/template/__init__.py	(revision 2524)
+++ django/core/template/__init__.py	(working copy)
@@ -84,6 +84,10 @@
 tag_re = re.compile('(%s.*?%s|%s.*?%s)' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END),
                                           re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END)))
 
+# split a token up seperating by spaces (allowing for quoted bits)
+split_token_re = re.compile(r'(?:\'[^\']+\'|"[^"]+"|[^ ]+)(?= )*')
+check_for_quotes = re.compile(r'[\'"]')
+
 # global dictionary of libraries that have been loaded using get_library
 libraries = {}
 # global list of libraries to load by default for a new parser
@@ -220,6 +224,13 @@
             self.contents[:].replace('\n', '')
             )
 
+    def split_contents(self):
+        if check_for_quotes.search(self.contents):
+            return split_token_re.findall(self.contents)
+        else:
+            return self.contents.split()
+
+
 class Lexer(object):
     def __init__(self, template_string, origin):
         self.template_string = template_string
@@ -291,7 +302,7 @@
                     self.prepend_token(token)
                     return nodelist
                 try:
-                    command = token.contents.split()[0]
+                    command = token.split_contents()[0]
                 except IndexError:
                     self.empty_block_tag(token)
                 # execute callback function for this tag and append resulting node
@@ -784,7 +795,7 @@
 
 def generic_tag_compiler(params, defaults, name, node_class, parser, token):
     "Returns a template.Node subclass."
-    bits = token.contents.split()[1:]
+    bits = token.split_contents()[1:]
     bmax = len(params)
     def_len = defaults and len(defaults) or 0
     bmin = bmax - def_len
Index: django/core/template/defaulttags.py
===================================================================
--- django/core/template/defaulttags.py	(revision 2524)
+++ django/core/template/defaulttags.py	(working copy)
@@ -328,7 +328,7 @@
     # a global variable, which would make cycle names have to be unique across
     # *all* templates.
 
-    args = token.contents.split()
+    args = token.split_contents()
     if len(args) < 2:
         raise TemplateSyntaxError("'Cycle' statement requires at least two arguments")
 
@@ -410,7 +410,7 @@
 
     but obviously much cleaner!
     """
-    bits = token.contents.split()[1:]
+    bits = token.split_contents()[1:]
     if len(bits) < 1:
         raise TemplateSyntaxError, "'firstof' statement requires at least one argument"
     return FirstOfNode(bits)
@@ -450,7 +450,7 @@
         ==========================  ================================================
 
     """
-    bits = token.contents.split()
+    bits = token.split_contents()
     if len(bits) == 5 and bits[4] != 'reversed':
         raise TemplateSyntaxError, "'for' statements with five words should end in 'reversed': %s" % token.contents
     if len(bits) not in (4, 5):
@@ -481,7 +481,7 @@
             ...
         {% endifnotequal %}
     """
-    bits = token.contents.split()
+    bits = token.split_contents()
     if len(bits) != 3:
         raise TemplateSyntaxError, "%r takes two arguments" % bits[0]
     end_tag = 'end' + bits[0]
@@ -550,7 +550,7 @@
             {% endif %}
         {% endif %}
     """
-    bits = token.contents.split()
+    bits = token.split_contents()
     del bits[0]
     if not bits:
         raise TemplateSyntaxError, "'if' statement requires at least one argument"
@@ -591,7 +591,7 @@
         <a href="{{ date|date:"M/d"|lower }}/">{{ date|date:"j" }}</a>
         {% endfor %}
     """
-    bits = token.contents.split()
+    bits = token.split_contents()
     if len(bits) != 1:
         raise TemplateSyntaxError, "'ifchanged' tag takes no arguments"
     nodelist = parser.parse(('endifchanged',))
@@ -615,7 +615,7 @@
 
         {% ssi /home/html/ljworld.com/includes/right_generic.html parsed %}
     """
-    bits = token.contents.split()
+    bits = token.split_contents()
     parsed = False
     if len(bits) not in (2, 3):
         raise TemplateSyntaxError, "'ssi' tag takes one argument: the path to the file to be included"
@@ -636,7 +636,7 @@
 
         {% load news.photos %}
     """
-    bits = token.contents.split()
+    bits = token.split_contents()
     for taglib in bits[1:]:
         # add the library to the parser
         try:
@@ -779,7 +779,7 @@
         ``closevariable``   ``}}``
         ==================  =======
     """
-    bits = token.contents.split()
+    bits = token.split_contents()
     if len(bits) != 2:
         raise TemplateSyntaxError, "'templatetag' statement takes one argument"
     tag = bits[1]
@@ -803,7 +803,7 @@
     the above example will be 88 pixels wide (because 175/200 = .875; .875 *
     100 = 87.5 which is rounded up to 88).
     """
-    bits = token.contents.split()
+    bits = token.split_contents()
     if len(bits) != 4:
         raise TemplateSyntaxError("widthratio takes three arguments")
     tag, this_value_expr, max_value_expr, max_width = bits
Index: django/core/template/loader_tags.py
===================================================================
--- django/core/template/loader_tags.py	(revision 2524)
+++ django/core/template/loader_tags.py	(working copy)
@@ -112,7 +112,7 @@
     """
     Define a block that can be overridden by child templates.
     """
-    bits = token.contents.split()
+    bits = token.split_contents()
     if len(bits) != 2:
         raise TemplateSyntaxError, "'%s' tag takes only one argument" % bits[0]
     block_name = bits[1]
@@ -137,7 +137,7 @@
     or ``{% extends variable %}`` uses the value of ``variable`` as the name
     of the parent template to extend.
     """
-    bits = token.contents.split()
+    bits = token.split_contents()
     if len(bits) != 2:
         raise TemplateSyntaxError, "'%s' takes one argument" % bits[0]
     parent_name, parent_name_expr = None, None
@@ -158,7 +158,7 @@
 
         {% include "foo/some_include" %}
     """
-    bits = token.contents.split()
+    bits = token.split_contents()
     if len(bits) != 2:
         raise TemplateSyntaxError, "%r tag takes one argument: the name of the template to be included" % bits[0]
     path = bits[1]
Index: django/templatetags/i18n.py
===================================================================
--- django/templatetags/i18n.py	(revision 2524)
+++ django/templatetags/i18n.py	(working copy)
@@ -83,7 +83,7 @@
     your setting file (or the default settings) and
     put it into the named variable.
     """
-    args = token.contents.split()
+    args = token.split_contents()
     if len(args) != 3 or args[1] != 'as':
         raise TemplateSyntaxError, "'get_available_languages' requires 'as variable' (got %r)" % args
     return GetAvailableLanguagesNode(args[2])
@@ -100,7 +100,7 @@
     put it's value into the ``language`` context
     variable.
     """
-    args = token.contents.split()
+    args = token.split_contents()
     if len(args) != 3 or args[1] != 'as':
         raise TemplateSyntaxError, "'get_available_languages' requires 'as variable' (got %r)" % args
     return GetCurrentLanguageNode(args[2])
Index: tests/othertests/templates.py
===================================================================
--- tests/othertests/templates.py	(revision 2524)
+++ tests/othertests/templates.py	(working copy)
@@ -8,9 +8,9 @@
 from django.utils.translation import activate, deactivate, install
 import traceback
 
-#################################
-# Custom template tag for tests #
-#################################
+##################################
+# Custom template tags for tests #
+##################################
 
 register = template.Library()
 
@@ -22,10 +22,25 @@
         return " ".join(self.contents)
 
 def do_echo(parser, token):
-    return EchoNode(token.contents.split()[1:])
+    return EchoNode(token.split_contents()[1:])
 
 register.tag("echo", do_echo)
 
+
+class TokenBitsNode(template.Node):
+    def __init__(self, token):
+        self.token = token
+
+    def render(self, context):
+        bits = self.token.split_contents()[1:]
+        return str(bits)
+
+def do_token_bits(parser, token):
+    return TokenBitsNode(token)
+
+register.tag("tokenbits", do_token_bits)
+
+
 template.libraries['django.templatetags.testtags'] = register
 
 #####################################
@@ -134,6 +149,11 @@
 
     # Default argument testing
     'basic-syntax32' : (r'{{ var|yesno:"yup,nup,mup" }} {{ var|yesno }}', {"var": True}, 'yup yes'),
+    
+    # Smart token content splitting
+    'basic-syntax33': (r'{% load testtags %}{% tokenbits one two three %}', {}, "['one', 'two', 'three']"),
+    'basic-syntax34': (r'{% load testtags %}{% tokenbits one "two three" %}', {}, "['one', '\"two three\"']"),
+    'basic-syntax35': (r"{% load testtags %}{% tokenbits 'one two' three %}", {}, "[\"'one two'\", 'three']"),
 
     ### IF TAG ################################################################
     'if-tag01': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": True}, "yes"),
