diff --git a/django/core/management/commands/makemessages.py b/django/core/management/commands/makemessages.py
--- a/django/core/management/commands/makemessages.py
+++ b/django/core/management/commands/makemessages.py
@@ -11,7 +11,8 @@
 from django.utils.text import get_text_list
 from django.utils.jslex import prepare_js_for_gettext
 
-plural_forms_re = re.compile(r'^(?P<value>"Plural-Forms.+?\\n")\s*$', re.MULTILINE | re.DOTALL)
+plural_forms_re = re.compile(
+    r'^(?P<value>"Plural-Forms.+?\\n")\s*$', re.MULTILINE | re.DOTALL)
 
 def handle_extensions(extensions=('html',), ignored=('py',)):
     """
@@ -41,7 +42,8 @@
     """
     Friendly wrapper around Popen for Windows
     """
-    p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE, close_fds=os.name != 'nt', universal_newlines=True)
+    p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE,
+              close_fds=os.name != 'nt', universal_newlines=True)
     return p.communicate()
 
 def walk(root, topdown=True, onerror=None, followlinks=False):
@@ -95,12 +97,14 @@
     else:
         domains = ('django',)
     for domain in domains:
-        django_po = os.path.join(django_dir, 'conf', 'locale', locale, 'LC_MESSAGES', '%s.po' % domain)
+        django_po = os.path.join(django_dir, 'conf', 'locale', locale,
+                                 'LC_MESSAGES', '%s.po' % domain)
         if os.path.exists(django_po):
             m = plural_forms_re.search(open(django_po, 'rU').read())
             if m:
                 if verbosity > 1:
-                    sys.stderr.write("copying plural forms: %s\n" % m.group('value'))
+                    sys.stderr.write(
+                        "copying plural forms: %s\n" % m.group('value'))
                 lines = []
                 seen = False
                 for line in msgs.split('\n'):
@@ -133,7 +137,7 @@
         f.close()
 
 def process_file(file, dirpath, potfile, domain, verbosity, extensions, wrap,
-        location):
+        location, keep_pot):
     """
     Extract translatable literals from :param file: for :param domain:
     creating or updating the :param potfile: POT file.
@@ -196,7 +200,7 @@
     if errors:
         if is_templatized:
             os.unlink(work_file)
-        if os.path.exists(potfile):
+        if not keep_pot and os.path.exists(potfile):
             os.unlink(potfile)
         raise CommandError(
             "errors happened while running xgettext on %s\n%s" %
@@ -207,7 +211,7 @@
         os.unlink(work_file)
 
 def write_po_file(pofile, potfile, domain, locale, verbosity,
-        copy_pforms, wrap, location, no_obsolete):
+        copy_pforms, wrap, location, no_obsolete, keep_pot):
     """
     Creates of updates the :param pofile: PO file for :param domain: and :param
     locale:.  Uses contents of the existing :param potfile:.
@@ -217,7 +221,8 @@
     msgs, errors = _popen('msguniq %s %s --to-code=utf-8 "%s"' %
                             (wrap, location, potfile))
     if errors:
-        os.unlink(potfile)
+        if not keep_pot:
+            os.unlink(potfile)
         raise CommandError("errors happened while running msguniq\n%s" % errors)
     if os.path.exists(pofile):
         f = open(potfile, 'w')
@@ -228,7 +233,8 @@
         msgs, errors = _popen('msgmerge %s %s -q "%s" "%s"' %
                                 (wrap, location, pofile, potfile))
         if errors:
-            os.unlink(potfile)
+            if not keep_pot:
+                os.unlink(potfile)
             raise CommandError(
                 "errors happened while running msgmerge\n%s" % errors)
     elif copy_pforms:
@@ -240,7 +246,8 @@
         f.write(msgs)
     finally:
         f.close()
-    os.unlink(potfile)
+    if not keep_pot:
+        os.unlink(potfile)
     if no_obsolete:
         msgs, errors = _popen('msgattrib %s %s -o "%s" --no-obsolete "%s"' %
                                 (wrap, location, pofile, pofile))
@@ -250,7 +257,7 @@
 
 def make_messages(locale=None, domain='django', verbosity=1, all=False,
         extensions=None, symlinks=False, ignore_patterns=None, no_wrap=False,
-        no_location=False, no_obsolete=False):
+        no_location=False, no_obsolete=False, keep_pot=False):
     """
     Uses the ``locale/`` directory from the Django SVN tree or an
     application/project to process all files with translatable literals for
@@ -284,10 +291,12 @@
                 "if you want to enable i18n for your project or application.")
 
     if domain not in ('django', 'djangojs'):
-        raise CommandError("currently makemessages only supports domains 'django' and 'djangojs'")
+        raise CommandError("currently makemessages only supports domains "
+                           "'django' and 'djangojs'")
 
     if (locale is None and not all) or domain is None:
-        message = "Type '%s help %s' for usage information." % (os.path.basename(sys.argv[0]), sys.argv[1])
+        message = "Type '%s help %s' for usage information." % (
+                  os.path.basename(sys.argv[0]), sys.argv[1])
         raise CommandError(message)
 
     # We require gettext version 0.15 or newer.
@@ -326,42 +335,56 @@
         for dirpath, file in find_files(".", ignore_patterns, verbosity,
                 symlinks=symlinks):
             process_file(file, dirpath, potfile, domain, verbosity, extensions,
-                    wrap, location)
+                    wrap, location, keep_pot)
 
         if os.path.exists(potfile):
             write_po_file(pofile, potfile, domain, locale, verbosity,
-                    not invoked_for_django, wrap, location, no_obsolete)
+                    not invoked_for_django, wrap, location, no_obsolete,
+                    keep_pot)
 
 
 class Command(NoArgsCommand):
     option_list = NoArgsCommand.option_list + (
         make_option('--locale', '-l', default=None, dest='locale',
-            help='Creates or updates the message files for the given locale (e.g. pt_BR).'),
+            help='Creates or updates the message files for the given locale '
+                 '(e.g. pt_BR).'),
         make_option('--domain', '-d', default='django', dest='domain',
             help='The domain of the message files (default: "django").'),
         make_option('--all', '-a', action='store_true', dest='all',
-            default=False, help='Updates the message files for all existing locales.'),
-        make_option('--extension', '-e', dest='extensions',
-            help='The file extension(s) to examine (default: "html,txt", or "js" if the domain is "djangojs"). Separate multiple extensions with commas, or use -e multiple times.',
-            action='append'),
+            default=False, help='Updates the message files for all existing '
+                                'locales.'),
+        make_option('--extension', '-e', dest='extensions', action='append',
+            help='The file extension(s) to examine (default: "html,txt", or '
+                 '"js" if the domain is "djangojs"). Separate multiple '
+                 'extensions with commas, or use -e multiple times.'),
         make_option('--symlinks', '-s', action='store_true', dest='symlinks',
-            default=False, help='Follows symlinks to directories when examining source code and templates for translation strings.'),
+            default=False, help='Follows symlinks to directories when '
+                                'examining source code and templates for '
+                                'translation strings.'),
         make_option('--ignore', '-i', action='append', dest='ignore_patterns',
-            default=[], metavar='PATTERN', help='Ignore files or directories matching this glob-style pattern. Use multiple times to ignore more.'),
-        make_option('--no-default-ignore', action='store_false', dest='use_default_ignore_patterns',
-            default=True, help="Don't ignore the common glob-style patterns 'CVS', '.*' and '*~'."),
+            default=[], metavar='PATTERN',
+            help='Ignore files or directories matching this glob-style '
+                 'pattern. Use multiple times to ignore more.'),
+        make_option('--no-default-ignore', action='store_false',
+            default=True, dest='use_default_ignore_patterns',
+            help="Don't ignore the common glob-style patterns 'CVS', '.*' and "
+                 "'*~'."),
         make_option('--no-wrap', action='store_true', dest='no_wrap',
-            default=False, help="Don't break long message lines into several lines"),
+            default=False, help="Don't break long message lines into several "
+                                "lines"),
         make_option('--no-location', action='store_true', dest='no_location',
             default=False, help="Don't write '#: filename:line' lines"),
         make_option('--no-obsolete', action='store_true', dest='no_obsolete',
             default=False, help="Remove obsolete message strings"),
+        make_option('--keep-pot', action='store_true', dest='keep_pot',
+            default=False, help="Keep .pot file after making messages. Useful "
+                                "when debugging."),
     )
     help = ( "Runs over the entire source tree of the current directory and "
-"pulls out all strings marked for translation. It creates (or updates) a message "
-"file in the conf/locale (in the django tree) or locale (for projects and "
-"applications) directory.\n\nYou must run this command with one of either the "
-"--locale or --all options.")
+"pulls out all strings marked for translation. It creates (or updates) a "
+"message file in the conf/locale (in the django tree) or locale (for projects "
+"and applications) directory.\n\nYou must run this command with one of either "
+"the --locale or --all options.")
 
     requires_model_validation = False
     can_import_settings = False
@@ -380,6 +403,7 @@
         no_wrap = options.get('no_wrap')
         no_location = options.get('no_location')
         no_obsolete = options.get('no_obsolete')
+        keep_pot = options.get('keep_pot')
         if domain == 'djangojs':
             extensions = handle_extensions(extensions or ['js'])
         else:
@@ -389,4 +413,6 @@
             sys.stdout.write('examining files with the extensions: %s\n'
                              % get_text_list(list(extensions), 'and'))
 
-        make_messages(locale, domain, verbosity, process_all, extensions, symlinks, ignore_patterns, no_wrap, no_location, no_obsolete)
+        make_messages(locale, domain, verbosity, process_all, extensions,
+            symlinks, ignore_patterns, no_wrap, no_location, no_obsolete,
+            keep_pot)
diff --git a/docs/ref/django-admin.txt b/docs/ref/django-admin.txt
--- a/docs/ref/django-admin.txt
+++ b/docs/ref/django-admin.txt
@@ -483,6 +483,14 @@
 comment lines in language files. Note that using this option makes it harder
 for technically skilled translators to understand each message's context.
 
+.. django-admin-option:: --keep-pot
+
+.. versionadded:: 1.4
+
+Use the ``--keep-pot`` option to prevent django from deleting the temporary
+.pot file it generates before creating the .po file. This is useful for
+debugging errors which may prevent the final language files from being created.
+
 reset <appname appname ...>
 ---------------------------
 
diff --git a/tests/regressiontests/i18n/commands/extraction.py b/tests/regressiontests/i18n/commands/extraction.py
--- a/tests/regressiontests/i18n/commands/extraction.py
+++ b/tests/regressiontests/i18n/commands/extraction.py
@@ -263,3 +263,36 @@
         with open(self.PO_FILE, 'r') as fp:
             po_contents = fp.read()
             self.assertTrue('#: templates/test.html:55' in po_contents)
+
+
+class KeepPotFileExtractorTests(ExtractorTests):
+
+    def setUp(self):
+        self.POT_FILE = self.PO_FILE + 't'
+        super(KeepPotFileExtractorTests, self).setUp()
+
+    def tearDown(self):
+        super(KeepPotFileExtractorTests, self).tearDown()
+        os.chdir(self.test_dir)
+        try:
+            os.unlink(self.POT_FILE)
+        except OSError:
+            pass
+        os.chdir(self._cwd)
+
+    def test_keep_pot_disabled_by_default(self):
+        os.chdir(self.test_dir)
+        management.call_command('makemessages', locale=LOCALE, verbosity=0)
+        self.assertFalse(os.path.exists(self.POT_FILE))
+
+    def test_keep_pot_explicitly_disabled(self):
+        os.chdir(self.test_dir)
+        management.call_command('makemessages', locale=LOCALE, verbosity=0,
+            keep_pot=False)
+        self.assertFalse(os.path.exists(self.POT_FILE))
+
+    def test_keep_pot_enabled(self):
+        os.chdir(self.test_dir)
+        management.call_command('makemessages', locale=LOCALE, verbosity=0,
+            keep_pot=True)
+        self.assertTrue(os.path.exists(self.POT_FILE))
diff --git a/tests/regressiontests/i18n/tests.py b/tests/regressiontests/i18n/tests.py
--- a/tests/regressiontests/i18n/tests.py
+++ b/tests/regressiontests/i18n/tests.py
@@ -29,7 +29,7 @@
     from .commands.extraction import (ExtractorTests, BasicExtractorTests,
         JavascriptExtractorTests, IgnoredExtractorTests, SymlinkExtractorTests,
         CopyPluralFormsExtractorTests, NoWrapExtractorTests,
-        NoLocationExtractorTests)
+        NoLocationExtractorTests, KeepPotFileExtractorTests)
 if can_run_compilation_tests:
     from .commands.compilation import (PoFileTests, PoFileContentsTests,
         PercentRenderingTests)
