Index: django/templatetags/__init__.py
===================================================================
--- django/templatetags/__init__.py	(revision 6589)
+++ django/templatetags/__init__.py	(working copy)
@@ -1,7 +1,4 @@
 from django.conf import settings
 
-for a in settings.INSTALLED_APPS:
-    try:
-        __path__.extend(__import__(a + '.templatetags', {}, {}, ['']).__path__)
-    except ImportError:
-        pass
+# Make django.template.* tag libraries available from django.templatetags.* for consistent loading
+__path__.extend(__import__('django.template', {}, {}, ['']).__path__)
Index: django/contrib/admin/views/doc.py
===================================================================
--- django/contrib/admin/views/doc.py	(revision 6589)
+++ django/contrib/admin/views/doc.py	(working copy)
@@ -1,4 +1,4 @@
-from django import template, templatetags
+from django import template
 from django.template import RequestContext
 from django.conf import settings
 from django.contrib.admin.views.decorators import staff_member_required
@@ -40,7 +40,7 @@
     load_all_installed_template_libraries()
 
     tags = []
-    for module_name, library in template.libraries.items():
+    for library_name, (library, app_name, module_name) in template.libraries.items():
         for tag_name, tag_func in library.tags.items():
             title, body, metadata = utils.parse_docstring(tag_func.__doc__)
             if title:
@@ -49,10 +49,10 @@
                 body = utils.parse_rst(body, 'tag', _('tag:') + tag_name)
             for key in metadata:
                 metadata[key] = utils.parse_rst(metadata[key], 'tag', _('tag:') + tag_name)
-            if library in template.builtins:
+            if library in zip(*template.builtins)[0]:
                 tag_library = None
             else:
-                tag_library = module_name.split('.')[-1]
+                tag_library = module_name, library_name
             tags.append({
                 'name': tag_name,
                 'title': title,
@@ -71,7 +71,7 @@
     load_all_installed_template_libraries()
 
     filters = []
-    for module_name, library in template.libraries.items():
+    for library_name, (library, app_name, module_name) in template.libraries.items():
         for filter_name, filter_func in library.filters.items():
             title, body, metadata = utils.parse_docstring(filter_func.__doc__)
             if title:
@@ -80,10 +80,10 @@
                 body = utils.parse_rst(body, 'filter', _('filter:') + filter_name)
             for key in metadata:
                 metadata[key] = utils.parse_rst(metadata[key], 'filter', _('filter:') + filter_name)
-            if library in template.builtins:
+            if library in zip(*template.builtins)[0]:
                 tag_library = None
             else:
-                tag_library = module_name.split('.')[-1]
+                tag_library = module_name, library_name
             filters.append({
                 'name': filter_name,
                 'title': title,
@@ -267,11 +267,20 @@
 
 def load_all_installed_template_libraries():
     # Load/register all template tag libraries from installed apps.
-    for e in templatetags.__path__:
-        libraries = [os.path.splitext(p)[0] for p in os.listdir(e) if p.endswith('.py') and p[0].isalpha()]
+    for a in settings.INSTALLED_APPS:
+        try:
+            path = __import__(a + '.templatetags', {}, {}, ['']).__path__[0]
+        except ImportError:
+            continue
+        libraries = []
+
+        for dirpath, dirnames, filenames in os.walk(path):
+            libraries.extend([os.path.splitext(p)[0] for p in filenames if p.endswith('.py') and p[0].isalpha()])
+            libraries.extend([p for p in dirnames if '.' not in p and os.path.exists(os.path.join(p, '__init__.py')) and p[0].isalpha()])
+
         for library_name in libraries:
             try:
-                lib = template.get_library("django.templatetags.%s" % library_name.split('.')[-1])
+                lib = template.get_library("%s.%s" % (a, library_name))
             except template.InvalidTemplateLibrary:
                 pass
 
Index: django/contrib/admin/templates/admin_doc/template_tag_index.html
===================================================================
--- django/contrib/admin/templates/admin_doc/template_tag_index.html	(revision 6589)
+++ django/contrib/admin/templates/admin_doc/template_tag_index.html	(working copy)
@@ -12,8 +12,8 @@
 {% regroup tags|dictsort:"library" by library as tag_libraries %}
 {% for library in tag_libraries %}
 <div class="module">
-    <h2>{% if library.grouper %}{{ library.grouper }}{% else %}Built-in tags{% endif %}</h2>
-    {% if library.grouper %}<p class="small quiet">To use these tags, put <code>{% templatetag openblock %} load {{ library.grouper }} {% templatetag closeblock %}</code> in your template before using the tag.</p><hr>{% endif %}
+    <h2>{% if library.grouper %}{{ library.grouper.0 }} ({{ library.grouper.1 }}){% else %}Built-in tags{% endif %}</h2>
+    {% if library.grouper %}<p class="small quiet">To use these tags, put <code>{% templatetag openblock %} load {{ library.grouper.0 }} {% templatetag closeblock %}</code> in your template before using the tag.</p><hr>{% endif %}
     {% for tag in library.list|dictsort:"name" %}
     <h3 id="{{ tag.name }}">{{ tag.name }}</h3>
     <h4>{{ tag.title }}</h4>
@@ -33,7 +33,7 @@
 {% regroup tags|dictsort:"library" by library as tag_libraries %}
 {% for library in tag_libraries %}
 <div class="module">
-    <h2>{% if library.grouper %}{{ library.grouper }}{% else %}Built-in tags{% endif %}</h2>
+    <h2>{% if library.grouper %}{{ library.grouper.0 }}{% else %}Built-in tags{% endif %}</h2>
     <ul>
     {% for tag in library.list|dictsort:"name" %}
         <li><a href="#{{ tag.name }}">{{ tag.name }}</a></li>
Index: django/contrib/admin/templates/admin_doc/template_filter_index.html
===================================================================
--- django/contrib/admin/templates/admin_doc/template_filter_index.html	(revision 6589)
+++ django/contrib/admin/templates/admin_doc/template_filter_index.html	(working copy)
@@ -12,8 +12,8 @@
 {% regroup filters|dictsort:"library" by library as filter_libraries %}
 {% for library in filter_libraries %}
 <div class="module">
-    <h2>{% if library.grouper %}{{ library.grouper }}{% else %}Built-in filters{% endif %}</h2>
-    {% if library.grouper %}<p class="small quiet">To use these filters, put <code>{% templatetag openblock %} load {{ library.grouper }} {% templatetag closeblock %}</code> in your template before using the filter.</p><hr>{% endif %}
+    <h2>{% if library.grouper %}{{ library.grouper.0 }} ({{ library.grouper.1 }}){% else %}Built-in filters{% endif %}</h2>
+    {% if library.grouper %}<p class="small quiet">To use these filters, put <code>{% templatetag openblock %} load {{ library.grouper.0 }} {% templatetag closeblock %}</code> in your template before using the filter.</p><hr>{% endif %}
     {% for filter in library.list|dictsort:"name" %}
     <h3 id="{{ filter.name }}">{{ filter.name }}</h3>
     <p>{{ filter.title }}</p>
@@ -33,7 +33,7 @@
 {% regroup filters|dictsort:"library" by library as filter_libraries %}
 {% for library in filter_libraries %}
 <div class="module">
-    <h2>{% if library.grouper %}{{ library.grouper }}{% else %}Built-in filters{% endif %}</h2>
+    <h2>{% if library.grouper %}{{ library.grouper.0 }}{% else %}Built-in filters{% endif %}</h2>
     <ul>
     {% for filter in library.list|dictsort:"name" %}
         <li><a href="#{{ filter.name }}">{{ filter.name }}</a></li>
Index: django/contrib/markup/tests.py
===================================================================
--- django/contrib/markup/tests.py	(revision 6589)
+++ django/contrib/markup/tests.py	(working copy)
@@ -4,7 +4,7 @@
 import re
 import unittest
 
-add_to_builtins('django.contrib.markup.templatetags.markup')
+add_to_builtins('django.contrib.markup', 'markup')
 
 class Templates(unittest.TestCase):
     def test_textile(self):
Index: django/template/__init__.py
===================================================================
--- django/template/__init__.py	(revision 6589)
+++ django/template/__init__.py	(working copy)
@@ -253,8 +253,9 @@
         self.tokens = tokens
         self.tags = {}
         self.filters = {}
-        for lib in builtins:
-            self.add_library(lib)
+        for lib, app, ref in builtins:
+            self.add_library(lib, ref)
+            self.add_library(lib, app + '.' + ref)
 
     def parse(self, parse_until=None):
         if parse_until is None: parse_until = []
@@ -344,9 +345,13 @@
     def delete_first_token(self):
         del self.tokens[0]
 
-    def add_library(self, lib):
+    def add_library(self, lib, ref):
+        def with_ref(d):
+            return dict([(ref + '.' + k, v) for (k, v) in d.items()])
         self.tags.update(lib.tags)
+        self.tags.update(with_ref(lib.tags))
         self.filters.update(lib.filters)
+        self.filters.update(with_ref(lib.filters))
 
     def compile_filter(self, token):
         "Convenient wrapper for FilterExpression"
@@ -495,7 +500,7 @@
 ^"(?P<constant>%(str)s)"|
 ^(?P<var>[%(var_chars)s]+)|
  (?:%(filter_sep)s
-     (?P<filter_name>\w+)
+     (?P<filter_name>[\w\.]+)
          (?:%(arg_sep)s
              (?:
               %(i18n_open)s"(?P<i18n_arg>%(str)s)"%(i18n_close)s|
@@ -969,22 +974,49 @@
             return func
         return dec
 
-def get_library(module_name):
-    lib = libraries.get(module_name, None)
-    if not lib:
+def get_library(library_name):
+    return get_library_details(library_name)[0]
+
+def get_library_details(library_name):
+    library_details = libraries.get(library_name)
+    if not library_details:
+        mod = None
+        class ModFound(Exception): pass
+        tried = []
+        apps = ['django'] + settings.INSTALLED_APPS
         try:
-            mod = __import__(module_name, {}, {}, [''])
-        except ImportError, e:
-            raise InvalidTemplateLibrary, "Could not load template library from %s, %s" % (module_name, e)
-        try:
-            lib = mod.register
-            libraries[module_name] = lib
-        except AttributeError:
-            raise InvalidTemplateLibrary, "Template library %s does not have a variable named 'register'" % module_name
-    return lib
+            # For library_name of the form <app.path>.<library.path>
+            for app_name in apps:
+                if library_name.startswith(app_name + '.'):
+                    module_name = library_name[len(app_name) + 1:]
+                    try:
+                        mod = __import__(app_name + '.templatetags.' + module_name, {}, {}, [''])
+                    except ImportError, e:
+                        tried.append((module_name, app_name))
+                    else:
+                        raise ModFound, (mod, app_name, module_name)
+            # For library_name of the form <library.path>
+            for app_name in apps:
+                try:
+                    mod = __import__(app_name + '.templatetags.' + library_name, {}, {}, [''])
+                except ImportError, e:
+                    tried.append((library_name, app_name))
+                else:
+                    raise ModFound, (mod, app_name, library_name)
+        except ModFound, e:
+            mod, app_name, module_name = e.args
+            try:
+                lib = mod.register
+                library_details = libraries[app_name + '.' + module_name] = (lib, app_name, module_name)
+            except AttributeError:
+                raise InvalidTemplateLibrary, "Template library %s does not have a variable named 'register'" % library_name
+        else:
+            tried_s = ", ".join(["'%s' from app '%s'" % t for t in tried])
+            raise InvalidTemplateLibrary, "Could not load template library %s; tried %s" % (library_name, tried_s)
+    return library_details
 
-def add_to_builtins(module_name):
-    builtins.append(get_library(module_name))
+def add_to_builtins(app_name, library_name):
+    builtins.append((get_library(app_name + '.' + library_name), app_name, library_name))
 
-add_to_builtins('django.template.defaulttags')
-add_to_builtins('django.template.defaultfilters')
+add_to_builtins('django', 'defaulttags')
+add_to_builtins('django', 'defaultfilters')
Index: django/template/defaulttags.py
===================================================================
--- django/template/defaulttags.py	(revision 6589)
+++ django/template/defaulttags.py	(working copy)
@@ -2,7 +2,7 @@
 
 from django.template import Node, NodeList, Template, Context, Variable
 from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, SINGLE_BRACE_START, SINGLE_BRACE_END, COMMENT_TAG_START, COMMENT_TAG_END
-from django.template import get_library, Library, InvalidTemplateLibrary
+from django.template import get_library_details, Library, InvalidTemplateLibrary
 from django.conf import settings
 from django.utils.encoding import smart_str, smart_unicode
 from django.utils.itercompat import groupby
@@ -801,8 +801,8 @@
     for taglib in bits[1:]:
         # add the library to the parser
         try:
-            lib = get_library("django.templatetags.%s" % taglib)
-            parser.add_library(lib)
+            lib, app_name, ref = get_library_details(taglib)
+            parser.add_library(lib, taglib)
         except InvalidTemplateLibrary, e:
             raise TemplateSyntaxError, "'%s' is not a valid tag library: %s" % (taglib, e)
     return LoadNode()
Index: django/template/loader.py
===================================================================
--- django/template/loader.py	(revision 6589)
+++ django/template/loader.py	(working copy)
@@ -115,4 +115,4 @@
     # If we get here, none of the templates could be loaded
     raise TemplateDoesNotExist, ', '.join(template_name_list)
 
-add_to_builtins('django.template.loader_tags')
+add_to_builtins('django', 'loader_tags')
Index: tests/regressiontests/humanize/tests.py
===================================================================
--- tests/regressiontests/humanize/tests.py	(revision 6589)
+++ tests/regressiontests/humanize/tests.py	(working copy)
@@ -4,7 +4,7 @@
 from django.utils.dateformat import DateFormat
 from django.utils.translation import ugettext as _
 
-add_to_builtins('django.contrib.humanize.templatetags.humanize')
+add_to_builtins('django.contrib.humanize', 'humanize')
 
 class HumanizeTests(unittest.TestCase):
 
Index: tests/regressiontests/templates/tests.py
===================================================================
--- tests/regressiontests/templates/tests.py	(revision 6589)
+++ tests/regressiontests/templates/tests.py	(working copy)
@@ -41,7 +41,7 @@
 
 register.tag("echo", do_echo)
 
-template.libraries['django.templatetags.testtags'] = register
+template.libraries['testtags'] = (register, 'django', 'testtags')
 
 #####################################
 # Helper objects for template tests #
@@ -819,6 +819,20 @@
             'cache08' : ('{% load cache %}{% cache %}{% endcache %}', {}, template.TemplateSyntaxError),
             'cache09' : ('{% load cache %}{% cache 1 %}{% endcache %}', {}, template.TemplateSyntaxError),
             'cache10' : ('{% load cache %}{% cache foo bar %}{% endcache %}', {}, template.TemplateSyntaxError),
+
+            ### TAG LIBRARY NAMESPACING ###############################################
+            'library-namespacing01': ("{% load defaulttags %}", {}, ""),
+            'library-namespacing02': ("{% load django.defaulttags %}", {}, ""),
+
+            ### TAG NAMESPACING #######################################################
+            'tag-namespacing01': ('{% defaulttags.templatetag openbrace %}', {}, '{'),
+            'tag-namespacing02': ('{% django.defaulttags.templatetag openbrace %}', {}, '{'),
+
+            'tag-namespacing03': ('{% defaulttags.with a as b %}{{ b }}{% endwith %}', {'a': 'a'}, 'a'),
+            'tag-namespacing04': ('{% django.defaulttags.with a as b %}{{ b }}{% endwith %}', {'a': 'a'}, 'a'),
+
+            'tag-namespacing05': ('{{ a|defaultfilters.upper }}', {'a': 'a'}, 'A'),
+            'tag-namespacing06': ('{{ a|django.defaultfilters.upper }}', {'a': 'a'}, 'A'),
         }
 
         # Register our custom template loader.
Index: docs/templates.txt
===================================================================
--- docs/templates.txt	(revision 6589)
+++ docs/templates.txt	(working copy)
@@ -363,6 +363,29 @@
 
 This is a feature for the sake of maintainability and sanity.
 
+Custom libraries and name conflicts
+-----------------------------------
+
+If two or more libraries in different apps share the same name, then you will
+have to load them by giving the app name and the library name, separated by
+a dot (``.``)::
+
+    {% load someapp.taglibrary %}
+    {% load otherapp.taglibrary %}
+
+In a similar fashion, if two different libraries offer tags or filters with
+the same name, you can prefix the use of the tag or filter with the library
+name to make it clear which tag or filter you wish to use::
+
+    {% i18n.trans "this is a test" %}
+
+If there is a conflict in both the library names and the tag or filter names,
+the tag or filter prefix must be the name you loaded the library with:
+
+    {% load someapp.taglibrary otherapp.taglibrary %}
+    {% someapp.taglibrary.sometag "This is the tag in someapp" %}
+    {% otherapp.taglibrary.sometag "A completely different tag in otherapp" %}
+
 Built-in tag and filter reference
 =================================
 
