Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Revert "Patch by Claude for #16084."

This reverts commit 2babab0.
  • Loading branch information...
commit ce27fb198dcce5dad47de83fc81119d3bb6567ce 1 parent 5b99d5a
Ramiro Morales ramiro authored
139 django/core/management/commands/makemessages.py
View
@@ -19,28 +19,25 @@
@total_ordering
class TranslatableFile(object):
- def __init__(self, dirpath, file_name, locale_dir):
+ def __init__(self, dirpath, file_name):
self.file = file_name
self.dirpath = dirpath
- self.locale_dir = locale_dir
def __repr__(self):
return "<TranslatableFile: %s>" % os.sep.join([self.dirpath, self.file])
def __eq__(self, other):
- return self.path == other.path
+ return self.dirpath == other.dirpath and self.file == other.file
def __lt__(self, other):
- return self.path < other.path
+ if self.dirpath == other.dirpath:
+ return self.file < other.file
+ return self.dirpath < other.dirpath
- @property
- def path(self):
- return os.path.join(self.dirpath, self.file)
-
- def process(self, command, domain):
+ def process(self, command, potfile, domain, keep_pot=False):
"""
- Extract translatable literals from self.file for :param domain:,
- creating or updating the POT file.
+ Extract translatable literals from self.file for :param domain:
+ creating or updating the :param potfile: POT file.
Uses the xgettext GNU gettext utility.
"""
@@ -94,6 +91,8 @@ def process(self, command, domain):
if status != STATUS_OK:
if is_templatized:
os.unlink(work_file)
+ if not keep_pot and os.path.exists(potfile):
+ os.unlink(potfile)
raise CommandError(
"errors happened while running xgettext on %s\n%s" %
(self.file, errors))
@@ -101,14 +100,11 @@ def process(self, command, domain):
# Print warnings
command.stdout.write(errors)
if msgs:
- # Write/append messages to pot file
- potfile = os.path.join(self.locale_dir, '%s.pot' % str(domain))
if is_templatized:
old = '#: ' + work_file[2:]
new = '#: ' + orig_file[2:]
msgs = msgs.replace(old, new)
write_pot_file(potfile, msgs)
-
if is_templatized:
os.unlink(work_file)
@@ -236,21 +232,21 @@ def handle_noargs(self, *args, **options):
settings.configure(USE_I18N = True)
self.invoked_for_django = False
- self.locale_paths = []
- self.default_locale_path = None
if os.path.isdir(os.path.join('conf', 'locale')):
- self.locale_paths = [os.path.abspath(os.path.join('conf', 'locale'))]
- self.default_locale_path = self.locale_paths[0]
+ localedir = os.path.abspath(os.path.join('conf', 'locale'))
self.invoked_for_django = True
# Ignoring all contrib apps
self.ignore_patterns += ['contrib/*']
+ elif os.path.isdir('locale'):
+ localedir = os.path.abspath('locale')
else:
- self.locale_paths.extend(list(settings.LOCALE_PATHS))
- # Allow to run makemessages inside an app dir
- if os.path.isdir('locale'):
- self.locale_paths.append(os.path.abspath('locale'))
- if self.locale_paths:
- self.default_locale_path = self.locale_paths[0]
+ raise CommandError("This script should be run from the Django Git "
+ "tree or your project or app tree. If you did indeed run it "
+ "from the Git checkout or your project or application, "
+ "maybe you are just missing the conf/locale (in the django "
+ "tree) or locale (for project and application) directory? It "
+ "is not created automatically, you have to create it by hand "
+ "if you want to enable i18n for your project or application.")
# We require gettext version 0.15 or newer.
output, errors, status = _popen('xgettext --version')
@@ -265,25 +261,24 @@ def handle_noargs(self, *args, **options):
"gettext 0.15 or newer. You are using version %s, please "
"upgrade your gettext toolset." % match.group())
- try:
- potfiles = self.build_potfiles()
+ potfile = self.build_pot_file(localedir)
- # Build po files for each selected locale
- locales = []
- if locale is not None:
- locales = locale.split(',') if not isinstance(locale, list) else locale
- elif process_all:
- locale_dirs = filter(os.path.isdir, glob.glob('%s/*' % self.default_locale_path))
- locales = [os.path.basename(l) for l in locale_dirs]
+ # Build po files for each selected locale
+ locales = []
+ if locale is not None:
+ locales += locale.split(',') if not isinstance(locale, list) else locale
+ elif process_all:
+ locale_dirs = filter(os.path.isdir, glob.glob('%s/*' % localedir))
+ locales = [os.path.basename(l) for l in locale_dirs]
+ try:
for locale in locales:
if self.verbosity > 0:
self.stdout.write("processing locale %s\n" % locale)
- for potfile in potfiles:
- self.write_po_file(potfile, locale)
+ self.write_po_file(potfile, locale)
finally:
- if not self.keep_pot:
- self.remove_potfiles()
+ if not self.keep_pot and os.path.exists(potfile):
+ os.unlink(potfile)
def build_pot_file(self, localedir):
file_list = self.find_files(".")
@@ -297,41 +292,9 @@ def build_pot_file(self, localedir):
f.process(self, potfile, self.domain, self.keep_pot)
return potfile
- def build_potfiles(self):
- """Build pot files and apply msguniq to them"""
- file_list = self.find_files(".")
- self.remove_potfiles()
- for f in file_list:
- f.process(self, self.domain)
-
- potfiles = []
- for path in self.locale_paths:
- potfile = os.path.join(path, '%s.pot' % str(self.domain))
- if not os.path.exists(potfile):
- continue
- msgs, errors, status = _popen('msguniq %s %s --to-code=utf-8 "%s"' %
- (self.wrap, self.location, potfile))
- if errors:
- if status != STATUS_OK:
- raise CommandError(
- "errors happened while running msguniq\n%s" % errors)
- elif self.verbosity > 0:
- self.stdout.write(errors)
- with open(potfile, 'w') as fp:
- fp.write(msgs)
- potfiles.append(potfile)
- return potfiles
-
- def remove_potfiles(self):
- for path in self.locale_paths:
- pot_path = os.path.join(path, '%s.pot' % str(self.domain))
- if os.path.exists(pot_path):
- os.unlink(pot_path)
-
def find_files(self, root):
"""
- Helper function to get all files in the given root. Also check that there
- is a matching locale dir for each file.
+ Helper method to get all files in the given root.
"""
def is_ignored(path, ignore_patterns):
@@ -352,26 +315,12 @@ def is_ignored(path, ignore_patterns):
dirnames.remove(dirname)
if self.verbosity > 1:
self.stdout.write('ignoring directory %s\n' % dirname)
- elif dirname == 'locale':
- dirnames.remove(dirname)
- self.locale_paths.insert(0, os.path.join(os.path.abspath(dirpath), dirname))
for filename in filenames:
- file_path = os.path.normpath(os.path.join(dirpath, filename))
- if is_ignored(file_path, self.ignore_patterns):
+ if is_ignored(os.path.normpath(os.path.join(dirpath, filename)), self.ignore_patterns):
if self.verbosity > 1:
self.stdout.write('ignoring file %s in %s\n' % (filename, dirpath))
else:
- locale_dir = None
- for path in self.locale_paths:
- if os.path.abspath(dirpath).startswith(os.path.dirname(path)):
- locale_dir = path
- break
- if not locale_dir:
- locale_dir = self.default_locale_path
- if not locale_dir:
- raise CommandError(
- "Unable to find a locale path to store translations for file %s" % file_path)
- all_files.append(TranslatableFile(dirpath, filename, locale_dir))
+ all_files.append(TranslatableFile(dirpath, filename))
return sorted(all_files)
def write_po_file(self, potfile, locale):
@@ -379,8 +328,16 @@ def write_po_file(self, potfile, locale):
Creates or updates the PO file for self.domain and :param locale:.
Uses contents of the existing :param potfile:.
- Uses msgmerge, and msgattrib GNU gettext utilities.
+ Uses mguniq, msgmerge, and msgattrib GNU gettext utilities.
"""
+ msgs, errors, status = _popen('msguniq %s %s --to-code=utf-8 "%s"' %
+ (self.wrap, self.location, potfile))
+ if errors:
+ if status != STATUS_OK:
+ raise CommandError(
+ "errors happened while running msguniq\n%s" % errors)
+ elif self.verbosity > 0:
+ self.stdout.write(errors)
basedir = os.path.join(os.path.dirname(potfile), locale, 'LC_MESSAGES')
if not os.path.isdir(basedir):
@@ -388,6 +345,8 @@ def write_po_file(self, potfile, locale):
pofile = os.path.join(basedir, '%s.po' % str(self.domain))
if os.path.exists(pofile):
+ with open(potfile, 'w') as fp:
+ fp.write(msgs)
msgs, errors, status = _popen('msgmerge %s %s -q "%s" "%s"' %
(self.wrap, self.location, pofile, potfile))
if errors:
@@ -396,10 +355,8 @@ def write_po_file(self, potfile, locale):
"errors happened while running msgmerge\n%s" % errors)
elif self.verbosity > 0:
self.stdout.write(errors)
- else:
- msgs = open(potfile, 'r').read()
- if not self.invoked_for_django:
- msgs = self.copy_plural_forms(msgs, locale)
+ elif not self.invoked_for_django:
+ msgs = self.copy_plural_forms(msgs, locale)
msgs = msgs.replace(
"#. #-#-#-#-# %s.pot (PACKAGE VERSION) #-#-#-#-#\n" % self.domain, "")
with open(pofile, 'w') as fp:
3  docs/man/django-admin.1
View
@@ -193,8 +193,7 @@ Ignore files or directories matching this glob-style pattern. Use multiple
times to ignore more (makemessages command).
.TP
.I \-\-no\-default\-ignore
-Don't ignore the common private glob-style patterns 'CVS', '.*', '*~' and '*.pyc'
-(makemessages command).
+Don't ignore the common private glob-style patterns 'CVS', '.*' and '*~' (makemessages command).
.TP
.I \-\-no\-wrap
Don't break long message lines into several lines (makemessages command).
4 docs/ref/django-admin.txt
View
@@ -472,7 +472,7 @@ Example usage::
Use the ``--ignore`` or ``-i`` option to ignore files or directories matching
the given :mod:`glob`-style pattern. Use multiple times to ignore more.
-These patterns are used by default: ``'CVS'``, ``'.*'``, ``'*~'``, ``'*.pyc'``
+These patterns are used by default: ``'CVS'``, ``'.*'``, ``'*~'``
Example usage::
@@ -499,7 +499,7 @@ for technically skilled translators to understand each message's context.
.. versionadded:: 1.6
Use the ``--keep-pot`` option to prevent django from deleting the temporary
-.pot files it generates before creating the .po file. This is useful for
+.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.
runfcgi [options]
17 docs/topics/i18n/translation.txt
View
@@ -1543,9 +1543,24 @@ All message file repositories are structured the same way. They are:
* ``$PYTHONPATH/django/conf/locale/<language>/LC_MESSAGES/django.(po|mo)``
To create message files, you use the :djadmin:`django-admin.py makemessages <makemessages>`
-tool. And you use :djadmin:`django-admin.py compilemessages <compilemessages>`
+tool. You only need to be in the same directory where the ``locale/`` directory
+is located. And you use :djadmin:`django-admin.py compilemessages <compilemessages>`
to produce the binary ``.mo`` files that are used by ``gettext``.
You can also run :djadmin:`django-admin.py compilemessages
--settings=path.to.settings <compilemessages>` to make the compiler process all
the directories in your :setting:`LOCALE_PATHS` setting.
+
+Finally, you should give some thought to the structure of your translation
+files. If your applications need to be delivered to other users and will be used
+in other projects, you might want to use app-specific translations. But using
+app-specific translations and project-specific translations could produce weird
+problems with :djadmin:`makemessages`: it will traverse all directories below
+the current path and so might put message IDs into a unified, common message
+file for the current project that are already in application message files.
+
+The easiest way out is to store applications that are not part of the project
+(and so carry their own translations) outside the project tree. That way,
+:djadmin:`django-admin.py makemessages <makemessages>`, when ran on a project
+level will only extract strings that are connected to your explicit project and
+not strings that are distributed independently.
44 tests/regressiontests/i18n/commands/extraction.py
View
@@ -5,13 +5,10 @@
import re
import shutil
-from django.conf import settings
from django.core import management
from django.test import SimpleTestCase
-from django.test.utils import override_settings
from django.utils.encoding import force_text
from django.utils._os import upath
-from django.utils import six
from django.utils.six import StringIO
@@ -355,44 +352,3 @@ def test_comma_separated_locales(self):
management.call_command('makemessages', locale='pt,de,ch', verbosity=0)
self.assertTrue(os.path.exists(self.PO_FILE_PT))
self.assertTrue(os.path.exists(self.PO_FILE_DE))
-
-
-class CustomLayoutExtractionTests(ExtractorTests):
- def setUp(self):
- self._cwd = os.getcwd()
- self.test_dir = os.path.join(os.path.dirname(upath(__file__)), 'project_dir')
-
- def test_no_locale_raises(self):
- os.chdir(self.test_dir)
- with six.assertRaisesRegex(self, management.CommandError,
- "Unable to find a locale path to store translations for file"):
- management.call_command('makemessages', locale=LOCALE, verbosity=0)
-
- @override_settings(
- LOCALE_PATHS=(os.path.join(os.path.dirname(upath(__file__)), 'project_dir/project_locale'),)
- )
- def test_project_locale_paths(self):
- """
- Test that:
- * translations for app containing locale folder are stored in that folder
- * translations outside of that app are in LOCALE_PATHS[0]
- """
- os.chdir(self.test_dir)
- self.addCleanup(shutil.rmtree, os.path.join(settings.LOCALE_PATHS[0], LOCALE))
- self.addCleanup(shutil.rmtree, os.path.join(self.test_dir, 'app_with_locale/locale', LOCALE))
-
- management.call_command('makemessages', locale=LOCALE, verbosity=0)
- project_de_locale = os.path.join(
- self.test_dir, 'project_locale/de/LC_MESSAGES/django.po',)
- app_de_locale = os.path.join(
- self.test_dir, 'app_with_locale/locale/de/LC_MESSAGES/django.po',)
- self.assertTrue(os.path.exists(project_de_locale))
- self.assertTrue(os.path.exists(app_de_locale))
-
- with open(project_de_locale, 'r') as fp:
- po_contents = force_text(fp.read())
- self.assertMsgId('This app has no locale directory', po_contents)
- self.assertMsgId('This is a project-level string', po_contents)
- with open(app_de_locale, 'r') as fp:
- po_contents = force_text(fp.read())
- self.assertMsgId('This app has a locale directory', po_contents)
3  tests/regressiontests/i18n/commands/project_dir/__init__.py
View
@@ -1,3 +0,0 @@
-from django.utils.translation import ugettext as _
-
-string = _("This is a project-level string")
4 tests/regressiontests/i18n/commands/project_dir/app_no_locale/models.py
View
@@ -1,4 +0,0 @@
-from django.utils.translation import ugettext as _
-
-string = _("This app has no locale directory")
-
4 tests/regressiontests/i18n/commands/project_dir/app_with_locale/models.py
View
@@ -1,4 +0,0 @@
-from django.utils.translation import ugettext as _
-
-string = _("This app has a locale directory")
-
2  tests/regressiontests/i18n/tests.py
View
@@ -33,7 +33,7 @@
JavascriptExtractorTests, IgnoredExtractorTests, SymlinkExtractorTests,
CopyPluralFormsExtractorTests, NoWrapExtractorTests,
NoLocationExtractorTests, KeepPotFileExtractorTests,
- MultipleLocaleExtractionTests, CustomLayoutExtractionTests)
+ MultipleLocaleExtractionTests)
if can_run_compilation_tests:
from .commands.compilation import (PoFileTests, PoFileContentsTests,
PercentRenderingTests, MultipleLocaleCompilationTests)
Please sign in to comment.
Something went wrong with that request. Please try again.