mirror of
https://github.com/django/django.git
synced 2025-07-03 17:29:12 +00:00
newforms-admin: Merged from trunk up to [7852].
git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@7853 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
058a190a79
commit
8c8513281e
1
AUTHORS
1
AUTHORS
@ -359,6 +359,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Swaroop C H <http://www.swaroopch.info>
|
Swaroop C H <http://www.swaroopch.info>
|
||||||
Aaron Swartz <http://www.aaronsw.com/>
|
Aaron Swartz <http://www.aaronsw.com/>
|
||||||
Ville Säävuori <http://www.unessa.net/>
|
Ville Säävuori <http://www.unessa.net/>
|
||||||
|
Christian Tanzer <tanzer@swing.co.at>
|
||||||
Tyler Tarabula <tyler.tarabula@gmail.com>
|
Tyler Tarabula <tyler.tarabula@gmail.com>
|
||||||
Tyson Tate <tyson@fallingbullets.com>
|
Tyson Tate <tyson@fallingbullets.com>
|
||||||
Frank Tegtmeyer <fte@fte.to>
|
Frank Tegtmeyer <fte@fte.to>
|
||||||
|
@ -1,64 +1,11 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
import optparse
|
if __name__ == "__main__":
|
||||||
import os
|
import sys
|
||||||
import sys
|
name = sys.argv[0]
|
||||||
|
args = ' '.join(sys.argv[1:])
|
||||||
try:
|
print >> sys.stderr, "%s has been moved into django-admin.py" % name
|
||||||
set
|
print >> sys.stderr, 'Please run "django-admin.py compilemessages %s" instead.'% args
|
||||||
except NameError:
|
print >> sys.stderr
|
||||||
from sets import Set as set # For Python 2.3
|
|
||||||
|
|
||||||
|
|
||||||
def compile_messages(locale=None):
|
|
||||||
basedirs = (os.path.join('conf', 'locale'), 'locale')
|
|
||||||
if os.environ.get('DJANGO_SETTINGS_MODULE'):
|
|
||||||
from django.conf import settings
|
|
||||||
basedirs += settings.LOCALE_PATHS
|
|
||||||
|
|
||||||
# Gather existing directories.
|
|
||||||
basedirs = set(map(os.path.abspath, filter(os.path.isdir, basedirs)))
|
|
||||||
|
|
||||||
if not basedirs:
|
|
||||||
print "This script should be run from the Django SVN tree or your project or app tree, or with the settings module specified."
|
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
for basedir in basedirs:
|
|
||||||
if locale:
|
|
||||||
basedir = os.path.join(basedir, locale, 'LC_MESSAGES')
|
|
||||||
compile_messages_in_dir(basedir)
|
|
||||||
|
|
||||||
def compile_messages_in_dir(basedir):
|
|
||||||
for dirpath, dirnames, filenames in os.walk(basedir):
|
|
||||||
for f in filenames:
|
|
||||||
if f.endswith('.po'):
|
|
||||||
sys.stderr.write('processing file %s in %s\n' % (f, dirpath))
|
|
||||||
pf = os.path.splitext(os.path.join(dirpath, f))[0]
|
|
||||||
# Store the names of the .mo and .po files in an environment
|
|
||||||
# variable, rather than doing a string replacement into the
|
|
||||||
# command, so that we can take advantage of shell quoting, to
|
|
||||||
# quote any malicious characters/escaping.
|
|
||||||
# See http://cyberelk.net/tim/articles/cmdline/ar01s02.html
|
|
||||||
os.environ['djangocompilemo'] = pf + '.mo'
|
|
||||||
os.environ['djangocompilepo'] = pf + '.po'
|
|
||||||
if sys.platform == 'win32': # Different shell-variable syntax
|
|
||||||
cmd = 'msgfmt --check-format -o "%djangocompilemo%" "%djangocompilepo%"'
|
|
||||||
else:
|
|
||||||
cmd = 'msgfmt --check-format -o "$djangocompilemo" "$djangocompilepo"'
|
|
||||||
os.system(cmd)
|
|
||||||
|
|
||||||
def main():
|
|
||||||
parser = optparse.OptionParser()
|
|
||||||
parser.add_option('-l', '--locale', dest='locale',
|
|
||||||
help="The locale to process. Default is to process all.")
|
|
||||||
parser.add_option('--settings',
|
|
||||||
help='Python path to settings module, e.g. "myproject.settings". If provided, all LOCALE_PATHS will be processed. If this isn\'t provided, the DJANGO_SETTINGS_MODULE environment variable will be checked as well.')
|
|
||||||
options, args = parser.parse_args()
|
|
||||||
if len(args):
|
|
||||||
parser.error("This program takes no arguments")
|
|
||||||
if options.settings:
|
|
||||||
os.environ['DJANGO_SETTINGS_MODULE'] = options.settings
|
|
||||||
compile_messages(options.locale)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
|
@ -7,14 +7,7 @@ Can be run as a cronjob to clean out old data from the database (only expired
|
|||||||
sessions at the moment).
|
sessions at the moment).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import datetime
|
from django.core import management
|
||||||
from django.db import transaction
|
|
||||||
from django.contrib.sessions.models import Session
|
|
||||||
|
|
||||||
def clean_up():
|
|
||||||
"""Clean up expired sessions."""
|
|
||||||
Session.objects.filter(expire_date__lt=datetime.datetime.now()).delete()
|
|
||||||
transaction.commit_unless_managed()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
clean_up()
|
management.call_command('cleanup')
|
||||||
|
@ -1,159 +1,11 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
# Need to ensure that the i18n framework is enabled
|
|
||||||
from django.conf import settings
|
|
||||||
settings.configure(USE_I18N = True)
|
|
||||||
|
|
||||||
from django.utils.translation import templatize
|
|
||||||
import re
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import getopt
|
|
||||||
from itertools import dropwhile
|
|
||||||
|
|
||||||
pythonize_re = re.compile(r'\n\s*//')
|
|
||||||
|
|
||||||
def make_messages():
|
|
||||||
localedir = None
|
|
||||||
|
|
||||||
if os.path.isdir(os.path.join('conf', 'locale')):
|
|
||||||
localedir = os.path.abspath(os.path.join('conf', 'locale'))
|
|
||||||
elif os.path.isdir('locale'):
|
|
||||||
localedir = os.path.abspath('locale')
|
|
||||||
else:
|
|
||||||
print "This script should be run from the django svn tree or your project or app tree."
|
|
||||||
print "If you did indeed run it from the svn checkout or your project or application,"
|
|
||||||
print "maybe you are just missing the conf/locale (in the django tree) or locale (for project"
|
|
||||||
print "and application) directory?"
|
|
||||||
print "make-messages.py doesn't create it automatically, you have to create it by hand if"
|
|
||||||
print "you want to enable i18n for your project or application."
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
(opts, args) = getopt.getopt(sys.argv[1:], 'l:d:va')
|
|
||||||
|
|
||||||
lang = None
|
|
||||||
domain = 'django'
|
|
||||||
verbose = False
|
|
||||||
all = False
|
|
||||||
|
|
||||||
for o, v in opts:
|
|
||||||
if o == '-l':
|
|
||||||
lang = v
|
|
||||||
elif o == '-d':
|
|
||||||
domain = v
|
|
||||||
elif o == '-v':
|
|
||||||
verbose = True
|
|
||||||
elif o == '-a':
|
|
||||||
all = True
|
|
||||||
|
|
||||||
if domain not in ('django', 'djangojs'):
|
|
||||||
print "currently make-messages.py only supports domains 'django' and 'djangojs'"
|
|
||||||
sys.exit(1)
|
|
||||||
if (lang is None and not all) or domain is None:
|
|
||||||
print "usage: make-messages.py -l <language>"
|
|
||||||
print " or: make-messages.py -a"
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
languages = []
|
|
||||||
|
|
||||||
if lang is not None:
|
|
||||||
languages.append(lang)
|
|
||||||
elif all:
|
|
||||||
languages = [el for el in os.listdir(localedir) if not el.startswith('.')]
|
|
||||||
|
|
||||||
for lang in languages:
|
|
||||||
|
|
||||||
print "processing language", lang
|
|
||||||
basedir = os.path.join(localedir, lang, 'LC_MESSAGES')
|
|
||||||
if not os.path.isdir(basedir):
|
|
||||||
os.makedirs(basedir)
|
|
||||||
|
|
||||||
pofile = os.path.join(basedir, '%s.po' % domain)
|
|
||||||
potfile = os.path.join(basedir, '%s.pot' % domain)
|
|
||||||
|
|
||||||
if os.path.exists(potfile):
|
|
||||||
os.unlink(potfile)
|
|
||||||
|
|
||||||
all_files = []
|
|
||||||
for (dirpath, dirnames, filenames) in os.walk("."):
|
|
||||||
all_files.extend([(dirpath, f) for f in filenames])
|
|
||||||
all_files.sort()
|
|
||||||
for dirpath, file in all_files:
|
|
||||||
if domain == 'djangojs' and file.endswith('.js'):
|
|
||||||
if verbose: sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
|
|
||||||
src = open(os.path.join(dirpath, file), "rb").read()
|
|
||||||
src = pythonize_re.sub('\n#', src)
|
|
||||||
open(os.path.join(dirpath, '%s.py' % file), "wb").write(src)
|
|
||||||
thefile = '%s.py' % file
|
|
||||||
cmd = 'xgettext -d %s -L Perl --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % (domain, os.path.join(dirpath, thefile))
|
|
||||||
(stdin, stdout, stderr) = os.popen3(cmd, 't')
|
|
||||||
msgs = stdout.read()
|
|
||||||
errors = stderr.read()
|
|
||||||
if errors:
|
|
||||||
print "errors happened while running xgettext on %s" % file
|
|
||||||
print errors
|
|
||||||
sys.exit(8)
|
|
||||||
old = '#: '+os.path.join(dirpath, thefile)[2:]
|
|
||||||
new = '#: '+os.path.join(dirpath, file)[2:]
|
|
||||||
msgs = msgs.replace(old, new)
|
|
||||||
if os.path.exists(potfile):
|
|
||||||
# Strip the header
|
|
||||||
msgs = '\n'.join(dropwhile(len, msgs.split('\n')))
|
|
||||||
else:
|
|
||||||
msgs = msgs.replace('charset=CHARSET', 'charset=UTF-8')
|
|
||||||
if msgs:
|
|
||||||
open(potfile, 'ab').write(msgs)
|
|
||||||
os.unlink(os.path.join(dirpath, thefile))
|
|
||||||
elif domain == 'django' and (file.endswith('.py') or file.endswith('.html')):
|
|
||||||
thefile = file
|
|
||||||
if file.endswith('.html'):
|
|
||||||
src = open(os.path.join(dirpath, file), "rb").read()
|
|
||||||
thefile = '%s.py' % file
|
|
||||||
open(os.path.join(dirpath, thefile), "wb").write(templatize(src))
|
|
||||||
if verbose:
|
|
||||||
sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
|
|
||||||
cmd = 'xgettext -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --keyword=ugettext_noop --keyword=ugettext_lazy --keyword=ungettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % (
|
|
||||||
domain, os.path.join(dirpath, thefile))
|
|
||||||
(stdin, stdout, stderr) = os.popen3(cmd, 't')
|
|
||||||
msgs = stdout.read()
|
|
||||||
errors = stderr.read()
|
|
||||||
if errors:
|
|
||||||
print "errors happened while running xgettext on %s" % file
|
|
||||||
print errors
|
|
||||||
sys.exit(8)
|
|
||||||
if thefile != file:
|
|
||||||
old = '#: '+os.path.join(dirpath, thefile)[2:]
|
|
||||||
new = '#: '+os.path.join(dirpath, file)[2:]
|
|
||||||
msgs = msgs.replace(old, new)
|
|
||||||
if os.path.exists(potfile):
|
|
||||||
# Strip the header
|
|
||||||
msgs = '\n'.join(dropwhile(len, msgs.split('\n')))
|
|
||||||
else:
|
|
||||||
msgs = msgs.replace('charset=CHARSET', 'charset=UTF-8')
|
|
||||||
if msgs:
|
|
||||||
open(potfile, 'ab').write(msgs)
|
|
||||||
if thefile != file:
|
|
||||||
os.unlink(os.path.join(dirpath, thefile))
|
|
||||||
|
|
||||||
if os.path.exists(potfile):
|
|
||||||
(stdin, stdout, stderr) = os.popen3('msguniq --to-code=utf-8 "%s"' % potfile, 'b')
|
|
||||||
msgs = stdout.read()
|
|
||||||
errors = stderr.read()
|
|
||||||
if errors:
|
|
||||||
print "errors happened while running msguniq"
|
|
||||||
print errors
|
|
||||||
sys.exit(8)
|
|
||||||
open(potfile, 'w').write(msgs)
|
|
||||||
if os.path.exists(pofile):
|
|
||||||
(stdin, stdout, stderr) = os.popen3('msgmerge -q "%s" "%s"' % (pofile, potfile), 'b')
|
|
||||||
msgs = stdout.read()
|
|
||||||
errors = stderr.read()
|
|
||||||
if errors:
|
|
||||||
print "errors happened while running msgmerge"
|
|
||||||
print errors
|
|
||||||
sys.exit(8)
|
|
||||||
open(pofile, 'wb').write(msgs)
|
|
||||||
os.unlink(potfile)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
make_messages()
|
import sys
|
||||||
|
name = sys.argv[0]
|
||||||
|
args = ' '.join(sys.argv[1:])
|
||||||
|
print >> sys.stderr, "%s has been moved into django-admin.py" % name
|
||||||
|
print >> sys.stderr, 'Please run "django-admin.py makemessages %s" instead.'% args
|
||||||
|
print >> sys.stderr
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
@ -71,6 +71,13 @@ class LazySettings(object):
|
|||||||
setattr(holder, name, value)
|
setattr(holder, name, value)
|
||||||
self._target = holder
|
self._target = holder
|
||||||
|
|
||||||
|
def configured(self):
|
||||||
|
"""
|
||||||
|
Returns True if the settings have already been configured.
|
||||||
|
"""
|
||||||
|
return bool(self._target)
|
||||||
|
configured = property(configured)
|
||||||
|
|
||||||
class Settings(object):
|
class Settings(object):
|
||||||
def __init__(self, settings_module):
|
def __init__(self, settings_module):
|
||||||
# update this dict from global settings (but only for ALL_CAPS settings)
|
# update this dict from global settings (but only for ALL_CAPS settings)
|
||||||
|
@ -38,14 +38,11 @@ def debug(request):
|
|||||||
return context_extras
|
return context_extras
|
||||||
|
|
||||||
def i18n(request):
|
def i18n(request):
|
||||||
|
from django.utils import translation
|
||||||
|
|
||||||
context_extras = {}
|
context_extras = {}
|
||||||
context_extras['LANGUAGES'] = settings.LANGUAGES
|
context_extras['LANGUAGES'] = settings.LANGUAGES
|
||||||
if hasattr(request, 'LANGUAGE_CODE'):
|
context_extras['LANGUAGE_CODE'] = translation.get_language()
|
||||||
context_extras['LANGUAGE_CODE'] = request.LANGUAGE_CODE
|
|
||||||
else:
|
|
||||||
context_extras['LANGUAGE_CODE'] = settings.LANGUAGE_CODE
|
|
||||||
|
|
||||||
from django.utils import translation
|
|
||||||
context_extras['LANGUAGE_BIDI'] = translation.get_language_bidi()
|
context_extras['LANGUAGE_BIDI'] = translation.get_language_bidi()
|
||||||
|
|
||||||
return context_extras
|
return context_extras
|
||||||
|
@ -6,6 +6,11 @@ import django
|
|||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.core.management.color import color_style
|
from django.core.management.color import color_style
|
||||||
|
|
||||||
|
try:
|
||||||
|
set
|
||||||
|
except NameError:
|
||||||
|
from sets import Set as set # For Python 2.3
|
||||||
|
|
||||||
class CommandError(Exception):
|
class CommandError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
11
django/core/management/commands/cleanup.py
Normal file
11
django/core/management/commands/cleanup.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import datetime
|
||||||
|
from django.core.management.base import NoArgsCommand
|
||||||
|
|
||||||
|
class Command(NoArgsCommand):
|
||||||
|
help = "Can be run as a cronjob or directly to clean out old data from the database (only expired sessions at the moment)."
|
||||||
|
|
||||||
|
def handle_noargs(self, **options):
|
||||||
|
from django.db import transaction
|
||||||
|
from django.contrib.sessions.models import Session
|
||||||
|
Session.objects.filter(expire_date__lt=datetime.datetime.now()).delete()
|
||||||
|
transaction.commit_unless_managed()
|
58
django/core/management/commands/compilemessages.py
Normal file
58
django/core/management/commands/compilemessages.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from optparse import make_option
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.core.management.color import no_style
|
||||||
|
|
||||||
|
try:
|
||||||
|
set
|
||||||
|
except NameError:
|
||||||
|
from sets import Set as set # For Python 2.3
|
||||||
|
|
||||||
|
def compile_messages(locale=None):
|
||||||
|
basedirs = (os.path.join('conf', 'locale'), 'locale')
|
||||||
|
if os.environ.get('DJANGO_SETTINGS_MODULE'):
|
||||||
|
from django.conf import settings
|
||||||
|
basedirs += settings.LOCALE_PATHS
|
||||||
|
|
||||||
|
# Gather existing directories.
|
||||||
|
basedirs = set(map(os.path.abspath, filter(os.path.isdir, basedirs)))
|
||||||
|
|
||||||
|
if not basedirs:
|
||||||
|
raise CommandError("This script should be run from the Django SVN tree or your project or app tree, or with the settings module specified.")
|
||||||
|
|
||||||
|
for basedir in basedirs:
|
||||||
|
if locale:
|
||||||
|
basedir = os.path.join(basedir, locale, 'LC_MESSAGES')
|
||||||
|
for dirpath, dirnames, filenames in os.walk(basedir):
|
||||||
|
for f in filenames:
|
||||||
|
if f.endswith('.po'):
|
||||||
|
sys.stderr.write('processing file %s in %s\n' % (f, dirpath))
|
||||||
|
pf = os.path.splitext(os.path.join(dirpath, f))[0]
|
||||||
|
# Store the names of the .mo and .po files in an environment
|
||||||
|
# variable, rather than doing a string replacement into the
|
||||||
|
# command, so that we can take advantage of shell quoting, to
|
||||||
|
# quote any malicious characters/escaping.
|
||||||
|
# See http://cyberelk.net/tim/articles/cmdline/ar01s02.html
|
||||||
|
os.environ['djangocompilemo'] = pf + '.mo'
|
||||||
|
os.environ['djangocompilepo'] = pf + '.po'
|
||||||
|
if sys.platform == 'win32': # Different shell-variable syntax
|
||||||
|
cmd = 'msgfmt --check-format -o "%djangocompilemo%" "%djangocompilepo%"'
|
||||||
|
else:
|
||||||
|
cmd = 'msgfmt --check-format -o "$djangocompilemo" "$djangocompilepo"'
|
||||||
|
os.system(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
option_list = BaseCommand.option_list + (
|
||||||
|
make_option('--locale', '-l', dest='locale',
|
||||||
|
help='The locale to process. Default is to process all.'),
|
||||||
|
)
|
||||||
|
help = 'Compiles .po files to .mo files for use with builtin gettext support.'
|
||||||
|
|
||||||
|
requires_model_validation = False
|
||||||
|
can_import_settings = False
|
||||||
|
|
||||||
|
def handle(self, **options):
|
||||||
|
locale = options.get('locale')
|
||||||
|
compile_messages(locale)
|
162
django/core/management/commands/makemessages.py
Normal file
162
django/core/management/commands/makemessages.py
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
import re
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from itertools import dropwhile
|
||||||
|
from optparse import make_option
|
||||||
|
from django.core.management.base import CommandError, BaseCommand
|
||||||
|
|
||||||
|
pythonize_re = re.compile(r'\n\s*//')
|
||||||
|
|
||||||
|
def make_messages(locale=None, domain='django', verbosity='1', all=False):
|
||||||
|
"""
|
||||||
|
Uses the locale directory from the Django SVN tree or an application/
|
||||||
|
project to process all
|
||||||
|
"""
|
||||||
|
# Need to ensure that the i18n framework is enabled
|
||||||
|
from django.conf import settings
|
||||||
|
if settings.configured:
|
||||||
|
settings.USE_I18N = True
|
||||||
|
else:
|
||||||
|
settings.configure(USE_I18N = True)
|
||||||
|
|
||||||
|
from django.utils.translation import templatize
|
||||||
|
|
||||||
|
if os.path.isdir(os.path.join('conf', 'locale')):
|
||||||
|
localedir = os.path.abspath(os.path.join('conf', 'locale'))
|
||||||
|
elif os.path.isdir('locale'):
|
||||||
|
localedir = os.path.abspath('locale')
|
||||||
|
else:
|
||||||
|
raise CommandError("This script should be run from the Django SVN tree or your project or app tree. If you did indeed run it from the SVN 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.")
|
||||||
|
|
||||||
|
if domain not in ('django', 'djangojs'):
|
||||||
|
raise CommandError("currently makemessages only supports domains 'django' and 'djangojs'")
|
||||||
|
|
||||||
|
if (locale is None and not all) or domain is None:
|
||||||
|
# backwards compatible error message
|
||||||
|
if not sys.argv[0].endswith("make-messages.py"):
|
||||||
|
message = "Type '%s help %s' for usage.\n" % (os.path.basename(sys.argv[0]), sys.argv[1])
|
||||||
|
else:
|
||||||
|
message = "usage: make-messages.py -l <language>\n or: make-messages.py -a\n"
|
||||||
|
raise CommandError(message)
|
||||||
|
|
||||||
|
languages = []
|
||||||
|
if locale is not None:
|
||||||
|
languages.append(locale)
|
||||||
|
elif all:
|
||||||
|
languages = [el for el in os.listdir(localedir) if not el.startswith('.')]
|
||||||
|
|
||||||
|
for locale in languages:
|
||||||
|
if verbosity > 0:
|
||||||
|
print "processing language", locale
|
||||||
|
basedir = os.path.join(localedir, locale, 'LC_MESSAGES')
|
||||||
|
if not os.path.isdir(basedir):
|
||||||
|
os.makedirs(basedir)
|
||||||
|
|
||||||
|
pofile = os.path.join(basedir, '%s.po' % domain)
|
||||||
|
potfile = os.path.join(basedir, '%s.pot' % domain)
|
||||||
|
|
||||||
|
if os.path.exists(potfile):
|
||||||
|
os.unlink(potfile)
|
||||||
|
|
||||||
|
all_files = []
|
||||||
|
for (dirpath, dirnames, filenames) in os.walk("."):
|
||||||
|
all_files.extend([(dirpath, f) for f in filenames])
|
||||||
|
all_files.sort()
|
||||||
|
for dirpath, file in all_files:
|
||||||
|
if domain == 'djangojs' and file.endswith('.js'):
|
||||||
|
if verbosity > 1:
|
||||||
|
sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
|
||||||
|
src = open(os.path.join(dirpath, file), "rb").read()
|
||||||
|
src = pythonize_re.sub('\n#', src)
|
||||||
|
open(os.path.join(dirpath, '%s.py' % file), "wb").write(src)
|
||||||
|
thefile = '%s.py' % file
|
||||||
|
cmd = 'xgettext -d %s -L Perl --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % (domain, os.path.join(dirpath, thefile))
|
||||||
|
(stdin, stdout, stderr) = os.popen3(cmd, 't')
|
||||||
|
msgs = stdout.read()
|
||||||
|
errors = stderr.read()
|
||||||
|
if errors:
|
||||||
|
raise CommandError("errors happened while running xgettext on %s\n%s" % (file, errors))
|
||||||
|
old = '#: '+os.path.join(dirpath, thefile)[2:]
|
||||||
|
new = '#: '+os.path.join(dirpath, file)[2:]
|
||||||
|
msgs = msgs.replace(old, new)
|
||||||
|
if os.path.exists(potfile):
|
||||||
|
# Strip the header
|
||||||
|
msgs = '\n'.join(dropwhile(len, msgs.split('\n')))
|
||||||
|
else:
|
||||||
|
msgs = msgs.replace('charset=CHARSET', 'charset=UTF-8')
|
||||||
|
if msgs:
|
||||||
|
open(potfile, 'ab').write(msgs)
|
||||||
|
os.unlink(os.path.join(dirpath, thefile))
|
||||||
|
elif domain == 'django' and (file.endswith('.py') or file.endswith('.html')):
|
||||||
|
thefile = file
|
||||||
|
if file.endswith('.html'):
|
||||||
|
src = open(os.path.join(dirpath, file), "rb").read()
|
||||||
|
thefile = '%s.py' % file
|
||||||
|
open(os.path.join(dirpath, thefile), "wb").write(templatize(src))
|
||||||
|
if verbosity > 1:
|
||||||
|
sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
|
||||||
|
cmd = 'xgettext -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --keyword=ugettext_noop --keyword=ugettext_lazy --keyword=ungettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % (
|
||||||
|
domain, os.path.join(dirpath, thefile))
|
||||||
|
(stdin, stdout, stderr) = os.popen3(cmd, 't')
|
||||||
|
msgs = stdout.read()
|
||||||
|
errors = stderr.read()
|
||||||
|
if errors:
|
||||||
|
raise CommandError("errors happened while running xgettext on %s\n%s" % (file, errors))
|
||||||
|
if thefile != file:
|
||||||
|
old = '#: '+os.path.join(dirpath, thefile)[2:]
|
||||||
|
new = '#: '+os.path.join(dirpath, file)[2:]
|
||||||
|
msgs = msgs.replace(old, new)
|
||||||
|
if os.path.exists(potfile):
|
||||||
|
# Strip the header
|
||||||
|
msgs = '\n'.join(dropwhile(len, msgs.split('\n')))
|
||||||
|
else:
|
||||||
|
msgs = msgs.replace('charset=CHARSET', 'charset=UTF-8')
|
||||||
|
if msgs:
|
||||||
|
open(potfile, 'ab').write(msgs)
|
||||||
|
if thefile != file:
|
||||||
|
os.unlink(os.path.join(dirpath, thefile))
|
||||||
|
|
||||||
|
if os.path.exists(potfile):
|
||||||
|
(stdin, stdout, stderr) = os.popen3('msguniq --to-code=utf-8 "%s"' % potfile, 'b')
|
||||||
|
msgs = stdout.read()
|
||||||
|
errors = stderr.read()
|
||||||
|
if errors:
|
||||||
|
raise CommandError("errors happened while running msguniq\n%s" % errors)
|
||||||
|
open(potfile, 'w').write(msgs)
|
||||||
|
if os.path.exists(pofile):
|
||||||
|
(stdin, stdout, stderr) = os.popen3('msgmerge -q "%s" "%s"' % (pofile, potfile), 'b')
|
||||||
|
msgs = stdout.read()
|
||||||
|
errors = stderr.read()
|
||||||
|
if errors:
|
||||||
|
raise CommandError("errors happened while running msgmerge\n%s" % errors)
|
||||||
|
open(pofile, 'wb').write(msgs)
|
||||||
|
os.unlink(potfile)
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
option_list = BaseCommand.option_list + (
|
||||||
|
make_option('--locale', '-l', default=None, dest='locale',
|
||||||
|
help='Creates or updates the message files only 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('--verbosity', '-v', action='store', dest='verbosity',
|
||||||
|
default='1', type='choice', choices=['0', '1', '2'],
|
||||||
|
help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
|
||||||
|
make_option('--all', '-a', action='store_true', dest='all',
|
||||||
|
default=False, help='Reexamines all source code and templates for new translation strings and updates all message files for all available languages.'),
|
||||||
|
)
|
||||||
|
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 project and application) directory."
|
||||||
|
|
||||||
|
requires_model_validation = False
|
||||||
|
can_import_settings = False
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
if len(args) != 0:
|
||||||
|
raise CommandError("Command doesn't accept any arguments")
|
||||||
|
|
||||||
|
locale = options.get('locale')
|
||||||
|
domain = options.get('domain')
|
||||||
|
verbosity = int(options.get('verbosity'))
|
||||||
|
process_all = options.get('all')
|
||||||
|
|
||||||
|
make_messages(locale, domain, verbosity, process_all)
|
@ -177,7 +177,7 @@ def isValidImage(field_data, all_data):
|
|||||||
from PIL import Image
|
from PIL import Image
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
try:
|
try:
|
||||||
content = field_data['content']
|
content = field_data.read()
|
||||||
except TypeError:
|
except TypeError:
|
||||||
raise ValidationError, _("No file was submitted. Check the encoding type on the form.")
|
raise ValidationError, _("No file was submitted. Check the encoding type on the form.")
|
||||||
try:
|
try:
|
||||||
@ -469,7 +469,7 @@ class HasAllowableSize(object):
|
|||||||
|
|
||||||
def __call__(self, field_data, all_data):
|
def __call__(self, field_data, all_data):
|
||||||
try:
|
try:
|
||||||
content = field_data['content']
|
content = field_data.read()
|
||||||
except TypeError:
|
except TypeError:
|
||||||
raise ValidationError, ugettext_lazy("No file was submitted. Check the encoding type on the form.")
|
raise ValidationError, ugettext_lazy("No file was submitted. Check the encoding type on the form.")
|
||||||
if self.min_size is not None and len(content) < self.min_size:
|
if self.min_size is not None and len(content) < self.min_size:
|
||||||
|
@ -161,16 +161,6 @@ class BaseDatabaseOperations(object):
|
|||||||
"""
|
"""
|
||||||
return cursor.lastrowid
|
return cursor.lastrowid
|
||||||
|
|
||||||
def limit_offset_sql(self, limit, offset=None):
|
|
||||||
"""
|
|
||||||
Returns a LIMIT/OFFSET SQL clause, given a limit and optional offset.
|
|
||||||
"""
|
|
||||||
# 'LIMIT 40 OFFSET 20'
|
|
||||||
sql = "LIMIT %s" % limit
|
|
||||||
if offset and offset != 0:
|
|
||||||
sql += " OFFSET %s" % offset
|
|
||||||
return sql
|
|
||||||
|
|
||||||
def lookup_cast(self, lookup_type):
|
def lookup_cast(self, lookup_type):
|
||||||
"""
|
"""
|
||||||
Returns the string to use in a query when performing lookups
|
Returns the string to use in a query when performing lookups
|
||||||
|
@ -89,13 +89,6 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|||||||
def fulltext_search_sql(self, field_name):
|
def fulltext_search_sql(self, field_name):
|
||||||
return 'MATCH (%s) AGAINST (%%s IN BOOLEAN MODE)' % field_name
|
return 'MATCH (%s) AGAINST (%%s IN BOOLEAN MODE)' % field_name
|
||||||
|
|
||||||
def limit_offset_sql(self, limit, offset=None):
|
|
||||||
# 'LIMIT 20,40'
|
|
||||||
sql = "LIMIT "
|
|
||||||
if offset and offset != 0:
|
|
||||||
sql += "%s," % offset
|
|
||||||
return sql + str(limit)
|
|
||||||
|
|
||||||
def no_limit_value(self):
|
def no_limit_value(self):
|
||||||
# 2**64 - 1, as recommended by the MySQL documentation
|
# 2**64 - 1, as recommended by the MySQL documentation
|
||||||
return 18446744073709551615L
|
return 18446744073709551615L
|
||||||
|
@ -93,13 +93,6 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|||||||
def fulltext_search_sql(self, field_name):
|
def fulltext_search_sql(self, field_name):
|
||||||
return 'MATCH (%s) AGAINST (%%s IN BOOLEAN MODE)' % field_name
|
return 'MATCH (%s) AGAINST (%%s IN BOOLEAN MODE)' % field_name
|
||||||
|
|
||||||
def limit_offset_sql(self, limit, offset=None):
|
|
||||||
# 'LIMIT 20,40'
|
|
||||||
sql = "LIMIT "
|
|
||||||
if offset and offset != 0:
|
|
||||||
sql += "%s," % offset
|
|
||||||
return sql + str(limit)
|
|
||||||
|
|
||||||
def no_limit_value(self):
|
def no_limit_value(self):
|
||||||
# 2**64 - 1, as recommended by the MySQL documentation
|
# 2**64 - 1, as recommended by the MySQL documentation
|
||||||
return 18446744073709551615L
|
return 18446744073709551615L
|
||||||
|
@ -87,11 +87,6 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|||||||
cursor.execute('SELECT %s_sq.currval FROM dual' % sq_name)
|
cursor.execute('SELECT %s_sq.currval FROM dual' % sq_name)
|
||||||
return cursor.fetchone()[0]
|
return cursor.fetchone()[0]
|
||||||
|
|
||||||
def limit_offset_sql(self, limit, offset=None):
|
|
||||||
# Limits and offset are too complicated to be handled here.
|
|
||||||
# Instead, they are handled in django/db/backends/oracle/query.py.
|
|
||||||
return ""
|
|
||||||
|
|
||||||
def lookup_cast(self, lookup_type):
|
def lookup_cast(self, lookup_type):
|
||||||
if lookup_type in ('iexact', 'icontains', 'istartswith', 'iendswith'):
|
if lookup_type in ('iexact', 'icontains', 'istartswith', 'iendswith'):
|
||||||
return "UPPER(%s)"
|
return "UPPER(%s)"
|
||||||
@ -146,11 +141,11 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|||||||
# Since we've just deleted all the rows, running our sequence
|
# Since we've just deleted all the rows, running our sequence
|
||||||
# ALTER code will reset the sequence to 0.
|
# ALTER code will reset the sequence to 0.
|
||||||
for sequence_info in sequences:
|
for sequence_info in sequences:
|
||||||
table_name = sequence_info['table']
|
sequence_name = get_sequence_name(sequence_info['table'])
|
||||||
seq_name = get_sequence_name(table_name)
|
table_name = self.quote_name(sequence_info['table'])
|
||||||
column_name = self.quote_name(sequence_info['column'] or 'id')
|
column_name = self.quote_name(sequence_info['column'] or 'id')
|
||||||
query = _get_sequence_reset_sql() % {'sequence': seq_name,
|
query = _get_sequence_reset_sql() % {'sequence': sequence_name,
|
||||||
'table': self.quote_name(table_name),
|
'table': table_name,
|
||||||
'column': column_name}
|
'column': column_name}
|
||||||
sql.append(query)
|
sql.append(query)
|
||||||
return sql
|
return sql
|
||||||
@ -162,19 +157,22 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|||||||
output = []
|
output = []
|
||||||
query = _get_sequence_reset_sql()
|
query = _get_sequence_reset_sql()
|
||||||
for model in model_list:
|
for model in model_list:
|
||||||
for f in model._meta.fields:
|
for f in model._meta.local_fields:
|
||||||
if isinstance(f, models.AutoField):
|
if isinstance(f, models.AutoField):
|
||||||
|
table_name = self.quote_name(model._meta.db_table)
|
||||||
sequence_name = get_sequence_name(model._meta.db_table)
|
sequence_name = get_sequence_name(model._meta.db_table)
|
||||||
column_name = self.quote_name(f.db_column or f.name)
|
column_name = self.quote_name(f.column)
|
||||||
output.append(query % {'sequence': sequence_name,
|
output.append(query % {'sequence': sequence_name,
|
||||||
'table': model._meta.db_table,
|
'table': table_name,
|
||||||
'column': column_name})
|
'column': column_name})
|
||||||
break # Only one AutoField is allowed per model, so don't bother continuing.
|
break # Only one AutoField is allowed per model, so don't bother continuing.
|
||||||
for f in model._meta.many_to_many:
|
for f in model._meta.many_to_many:
|
||||||
|
table_name = self.quote_name(f.m2m_db_table())
|
||||||
sequence_name = get_sequence_name(f.m2m_db_table())
|
sequence_name = get_sequence_name(f.m2m_db_table())
|
||||||
|
column_name = self.quote_name('id')
|
||||||
output.append(query % {'sequence': sequence_name,
|
output.append(query % {'sequence': sequence_name,
|
||||||
'table': f.m2m_db_table(),
|
'table': table_name,
|
||||||
'column': self.quote_name('id')})
|
'column': column_name})
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def start_transaction_sql(self):
|
def start_transaction_sql(self):
|
||||||
|
@ -31,19 +31,15 @@ except NameError:
|
|||||||
class ModelBase(type):
|
class ModelBase(type):
|
||||||
"Metaclass for all models"
|
"Metaclass for all models"
|
||||||
def __new__(cls, name, bases, attrs):
|
def __new__(cls, name, bases, attrs):
|
||||||
# If this isn't a subclass of Model, don't do anything special.
|
super_new = super(ModelBase, cls).__new__
|
||||||
try:
|
parents = [b for b in bases if isinstance(b, ModelBase)]
|
||||||
parents = [b for b in bases if issubclass(b, Model)]
|
|
||||||
except NameError:
|
|
||||||
# 'Model' isn't defined yet, meaning we're looking at Django's own
|
|
||||||
# Model class, defined below.
|
|
||||||
parents = []
|
|
||||||
if not parents:
|
if not parents:
|
||||||
return super(ModelBase, cls).__new__(cls, name, bases, attrs)
|
# If this isn't a subclass of Model, don't do anything special.
|
||||||
|
return super_new(cls, name, bases, attrs)
|
||||||
|
|
||||||
# Create the class.
|
# Create the class.
|
||||||
module = attrs.pop('__module__')
|
module = attrs.pop('__module__')
|
||||||
new_class = type.__new__(cls, name, bases, {'__module__': module})
|
new_class = super_new(cls, name, bases, {'__module__': module})
|
||||||
attr_meta = attrs.pop('Meta', None)
|
attr_meta = attrs.pop('Meta', None)
|
||||||
abstract = getattr(attr_meta, 'abstract', False)
|
abstract = getattr(attr_meta, 'abstract', False)
|
||||||
if not attr_meta:
|
if not attr_meta:
|
||||||
|
@ -1104,19 +1104,7 @@ class Query(object):
|
|||||||
# that's harmless.
|
# that's harmless.
|
||||||
self.promote_alias(table)
|
self.promote_alias(table)
|
||||||
|
|
||||||
# To save memory and copying time, convert the value from the Python
|
self.where.add((alias, col, field, lookup_type, value), connector)
|
||||||
# object to the actual value used in the SQL query.
|
|
||||||
if field:
|
|
||||||
params = field.get_db_prep_lookup(lookup_type, value)
|
|
||||||
else:
|
|
||||||
params = Field().get_db_prep_lookup(lookup_type, value)
|
|
||||||
if isinstance(value, datetime.datetime):
|
|
||||||
annotation = datetime.datetime
|
|
||||||
else:
|
|
||||||
annotation = bool(value)
|
|
||||||
|
|
||||||
self.where.add((alias, col, field.db_type(), lookup_type, annotation,
|
|
||||||
params), connector)
|
|
||||||
|
|
||||||
if negate:
|
if negate:
|
||||||
for alias in join_list:
|
for alias in join_list:
|
||||||
@ -1126,8 +1114,8 @@ class Query(object):
|
|||||||
for alias in join_list:
|
for alias in join_list:
|
||||||
if self.alias_map[alias][JOIN_TYPE] == self.LOUTER:
|
if self.alias_map[alias][JOIN_TYPE] == self.LOUTER:
|
||||||
j_col = self.alias_map[alias][RHS_JOIN_COL]
|
j_col = self.alias_map[alias][RHS_JOIN_COL]
|
||||||
entry = Node([(alias, j_col, None, 'isnull', True,
|
entry = self.where_class()
|
||||||
[True])])
|
entry.add((alias, j_col, None, 'isnull', True), AND)
|
||||||
entry.negate()
|
entry.negate()
|
||||||
self.where.add(entry, AND)
|
self.where.add(entry, AND)
|
||||||
break
|
break
|
||||||
@ -1135,7 +1123,8 @@ class Query(object):
|
|||||||
# Leaky abstraction artifact: We have to specifically
|
# Leaky abstraction artifact: We have to specifically
|
||||||
# exclude the "foo__in=[]" case from this handling, because
|
# exclude the "foo__in=[]" case from this handling, because
|
||||||
# it's short-circuited in the Where class.
|
# it's short-circuited in the Where class.
|
||||||
entry = Node([(alias, col, None, 'isnull', True, [True])])
|
entry = self.where_class()
|
||||||
|
entry.add((alias, col, None, 'isnull', True), AND)
|
||||||
entry.negate()
|
entry.negate()
|
||||||
self.where.add(entry, AND)
|
self.where.add(entry, AND)
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ class DeleteQuery(Query):
|
|||||||
for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE):
|
for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE):
|
||||||
where = self.where_class()
|
where = self.where_class()
|
||||||
where.add((None, related.field.m2m_reverse_name(),
|
where.add((None, related.field.m2m_reverse_name(),
|
||||||
related.field.db_type(), 'in', True,
|
related.field, 'in',
|
||||||
pk_list[offset : offset+GET_ITERATOR_CHUNK_SIZE]),
|
pk_list[offset : offset+GET_ITERATOR_CHUNK_SIZE]),
|
||||||
AND)
|
AND)
|
||||||
self.do_query(related.field.m2m_db_table(), where)
|
self.do_query(related.field.m2m_db_table(), where)
|
||||||
@ -59,11 +59,11 @@ class DeleteQuery(Query):
|
|||||||
if isinstance(f, generic.GenericRelation):
|
if isinstance(f, generic.GenericRelation):
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
field = f.rel.to._meta.get_field(f.content_type_field_name)
|
field = f.rel.to._meta.get_field(f.content_type_field_name)
|
||||||
w1.add((None, field.column, field.db_type(), 'exact', True,
|
w1.add((None, field.column, field, 'exact',
|
||||||
[ContentType.objects.get_for_model(cls).id]), AND)
|
ContentType.objects.get_for_model(cls).id), AND)
|
||||||
for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE):
|
for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE):
|
||||||
where = self.where_class()
|
where = self.where_class()
|
||||||
where.add((None, f.m2m_column_name(), f.db_type(), 'in', True,
|
where.add((None, f.m2m_column_name(), f, 'in',
|
||||||
pk_list[offset : offset + GET_ITERATOR_CHUNK_SIZE]),
|
pk_list[offset : offset + GET_ITERATOR_CHUNK_SIZE]),
|
||||||
AND)
|
AND)
|
||||||
if w1:
|
if w1:
|
||||||
@ -81,7 +81,7 @@ class DeleteQuery(Query):
|
|||||||
for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE):
|
for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE):
|
||||||
where = self.where_class()
|
where = self.where_class()
|
||||||
field = self.model._meta.pk
|
field = self.model._meta.pk
|
||||||
where.add((None, field.column, field.db_type(), 'in', True,
|
where.add((None, field.column, field, 'in',
|
||||||
pk_list[offset : offset + GET_ITERATOR_CHUNK_SIZE]), AND)
|
pk_list[offset : offset + GET_ITERATOR_CHUNK_SIZE]), AND)
|
||||||
self.do_query(self.model._meta.db_table, where)
|
self.do_query(self.model._meta.db_table, where)
|
||||||
|
|
||||||
@ -204,7 +204,7 @@ class UpdateQuery(Query):
|
|||||||
for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE):
|
for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE):
|
||||||
self.where = self.where_class()
|
self.where = self.where_class()
|
||||||
f = self.model._meta.pk
|
f = self.model._meta.pk
|
||||||
self.where.add((None, f.column, f.db_type(), 'in', True,
|
self.where.add((None, f.column, f, 'in',
|
||||||
pk_list[offset : offset + GET_ITERATOR_CHUNK_SIZE]),
|
pk_list[offset : offset + GET_ITERATOR_CHUNK_SIZE]),
|
||||||
AND)
|
AND)
|
||||||
self.values = [(related_field.column, None, '%s')]
|
self.values = [(related_field.column, None, '%s')]
|
||||||
|
@ -27,7 +27,36 @@ class WhereNode(tree.Node):
|
|||||||
"""
|
"""
|
||||||
default = AND
|
default = AND
|
||||||
|
|
||||||
def as_sql(self, node=None, qn=None):
|
def add(self, data, connector):
|
||||||
|
"""
|
||||||
|
Add a node to the where-tree. If the data is a list or tuple, it is
|
||||||
|
expected to be of the form (alias, col_name, field_obj, lookup_type,
|
||||||
|
value), which is then slightly munged before being stored (to avoid
|
||||||
|
storing any reference to field objects). Otherwise, the 'data' is
|
||||||
|
stored unchanged and can be anything with an 'as_sql()' method.
|
||||||
|
"""
|
||||||
|
if not isinstance(data, (list, tuple)):
|
||||||
|
super(WhereNode, self).add(data, connector)
|
||||||
|
return
|
||||||
|
|
||||||
|
alias, col, field, lookup_type, value = data
|
||||||
|
if field:
|
||||||
|
params = field.get_db_prep_lookup(lookup_type, value)
|
||||||
|
db_type = field.db_type()
|
||||||
|
else:
|
||||||
|
# This is possible when we add a comparison to NULL sometimes (we
|
||||||
|
# don't really need to waste time looking up the associated field
|
||||||
|
# object).
|
||||||
|
params = Field().get_db_prep_lookup(lookup_type, value)
|
||||||
|
db_type = None
|
||||||
|
if isinstance(value, datetime.datetime):
|
||||||
|
annotation = datetime.datetime
|
||||||
|
else:
|
||||||
|
annotation = bool(value)
|
||||||
|
super(WhereNode, self).add((alias, col, db_type, lookup_type,
|
||||||
|
annotation, params), connector)
|
||||||
|
|
||||||
|
def as_sql(self, qn=None):
|
||||||
"""
|
"""
|
||||||
Returns the SQL version of the where clause and the value to be
|
Returns the SQL version of the where clause and the value to be
|
||||||
substituted in. Returns None, None if this node is empty.
|
substituted in. Returns None, None if this node is empty.
|
||||||
@ -36,60 +65,56 @@ class WhereNode(tree.Node):
|
|||||||
(generally not needed except by the internal implementation for
|
(generally not needed except by the internal implementation for
|
||||||
recursion).
|
recursion).
|
||||||
"""
|
"""
|
||||||
if node is None:
|
|
||||||
node = self
|
|
||||||
if not qn:
|
if not qn:
|
||||||
qn = connection.ops.quote_name
|
qn = connection.ops.quote_name
|
||||||
if not node.children:
|
if not self.children:
|
||||||
return None, []
|
return None, []
|
||||||
result = []
|
result = []
|
||||||
result_params = []
|
result_params = []
|
||||||
empty = True
|
empty = True
|
||||||
for child in node.children:
|
for child in self.children:
|
||||||
try:
|
try:
|
||||||
if hasattr(child, 'as_sql'):
|
if hasattr(child, 'as_sql'):
|
||||||
sql, params = child.as_sql(qn=qn)
|
sql, params = child.as_sql(qn=qn)
|
||||||
format = '(%s)'
|
|
||||||
elif isinstance(child, tree.Node):
|
|
||||||
sql, params = self.as_sql(child, qn)
|
|
||||||
if child.negated:
|
|
||||||
format = 'NOT (%s)'
|
|
||||||
elif len(child.children) == 1:
|
|
||||||
format = '%s'
|
|
||||||
else:
|
|
||||||
format = '(%s)'
|
|
||||||
else:
|
else:
|
||||||
|
# A leaf node in the tree.
|
||||||
sql, params = self.make_atom(child, qn)
|
sql, params = self.make_atom(child, qn)
|
||||||
format = '%s'
|
|
||||||
except EmptyResultSet:
|
except EmptyResultSet:
|
||||||
if node.connector == AND and not node.negated:
|
if self.connector == AND and not self.negated:
|
||||||
# We can bail out early in this particular case (only).
|
# We can bail out early in this particular case (only).
|
||||||
raise
|
raise
|
||||||
elif node.negated:
|
elif self.negated:
|
||||||
empty = False
|
empty = False
|
||||||
continue
|
continue
|
||||||
except FullResultSet:
|
except FullResultSet:
|
||||||
if self.connector == OR:
|
if self.connector == OR:
|
||||||
if node.negated:
|
if self.negated:
|
||||||
empty = True
|
empty = True
|
||||||
break
|
break
|
||||||
# We match everything. No need for any constraints.
|
# We match everything. No need for any constraints.
|
||||||
return '', []
|
return '', []
|
||||||
if node.negated:
|
if self.negated:
|
||||||
empty = True
|
empty = True
|
||||||
continue
|
continue
|
||||||
empty = False
|
empty = False
|
||||||
if sql:
|
if sql:
|
||||||
result.append(format % sql)
|
result.append(sql)
|
||||||
result_params.extend(params)
|
result_params.extend(params)
|
||||||
if empty:
|
if empty:
|
||||||
raise EmptyResultSet
|
raise EmptyResultSet
|
||||||
conn = ' %s ' % node.connector
|
|
||||||
return conn.join(result), result_params
|
conn = ' %s ' % self.connector
|
||||||
|
sql_string = conn.join(result)
|
||||||
|
if sql_string:
|
||||||
|
if self.negated:
|
||||||
|
sql_string = 'NOT (%s)' % sql_string
|
||||||
|
elif len(self.children) != 1:
|
||||||
|
sql_string = '(%s)' % sql_string
|
||||||
|
return sql_string, result_params
|
||||||
|
|
||||||
def make_atom(self, child, qn):
|
def make_atom(self, child, qn):
|
||||||
"""
|
"""
|
||||||
Turn a tuple (table_alias, field_name, db_type, lookup_type,
|
Turn a tuple (table_alias, column_name, db_type, lookup_type,
|
||||||
value_annot, params) into valid SQL.
|
value_annot, params) into valid SQL.
|
||||||
|
|
||||||
Returns the string for the SQL fragment and the parameters to use for
|
Returns the string for the SQL fragment and the parameters to use for
|
||||||
|
@ -57,8 +57,8 @@ class DeclarativeFieldsMetaclass(type):
|
|||||||
"""
|
"""
|
||||||
def __new__(cls, name, bases, attrs):
|
def __new__(cls, name, bases, attrs):
|
||||||
attrs['base_fields'] = get_declared_fields(bases, attrs)
|
attrs['base_fields'] = get_declared_fields(bases, attrs)
|
||||||
|
new_class = super(DeclarativeFieldsMetaclass,
|
||||||
new_class = type.__new__(cls, name, bases, attrs)
|
cls).__new__(cls, name, bases, attrs)
|
||||||
if 'media' not in attrs:
|
if 'media' not in attrs:
|
||||||
new_class.media = media_property(new_class)
|
new_class.media = media_property(new_class)
|
||||||
return new_class
|
return new_class
|
||||||
|
@ -215,18 +215,19 @@ class ModelFormOptions(object):
|
|||||||
|
|
||||||
|
|
||||||
class ModelFormMetaclass(type):
|
class ModelFormMetaclass(type):
|
||||||
def __new__(cls, name, bases, attrs,
|
def __new__(cls, name, bases, attrs):
|
||||||
formfield_callback=lambda f: f.formfield()):
|
formfield_callback = attrs.pop('formfield_callback',
|
||||||
|
lambda f: f.formfield())
|
||||||
try:
|
try:
|
||||||
parents = [b for b in bases if issubclass(b, ModelForm)]
|
parents = [b for b in bases if issubclass(b, ModelForm)]
|
||||||
except NameError:
|
except NameError:
|
||||||
# We are defining ModelForm itself.
|
# We are defining ModelForm itself.
|
||||||
parents = None
|
parents = None
|
||||||
if not parents:
|
new_class = super(ModelFormMetaclass, cls).__new__(cls, name, bases,
|
||||||
return super(ModelFormMetaclass, cls).__new__(cls, name, bases,
|
|
||||||
attrs)
|
attrs)
|
||||||
|
if not parents:
|
||||||
|
return new_class
|
||||||
|
|
||||||
new_class = type.__new__(cls, name, bases, attrs)
|
|
||||||
if 'media' not in attrs:
|
if 'media' not in attrs:
|
||||||
new_class.media = media_property(new_class)
|
new_class.media = media_property(new_class)
|
||||||
declared_fields = get_declared_fields(bases, attrs, False)
|
declared_fields = get_declared_fields(bases, attrs, False)
|
||||||
|
@ -29,6 +29,22 @@ class Node(object):
|
|||||||
self.subtree_parents = []
|
self.subtree_parents = []
|
||||||
self.negated = negated
|
self.negated = negated
|
||||||
|
|
||||||
|
# We need this because of django.db.models.query_utils.Q. Q. __init__() is
|
||||||
|
# problematic, but it is a natural Node subclass in all other respects.
|
||||||
|
def _new_instance(cls, children=None, connector=None, negated=False):
|
||||||
|
"""
|
||||||
|
This is called to create a new instance of this class when we need new
|
||||||
|
Nodes (or subclasses) in the internal code in this class. Normally, it
|
||||||
|
just shadows __init__(). However, subclasses with an __init__ signature
|
||||||
|
that is not an extension of Node.__init__ might need to implement this
|
||||||
|
method to allow a Node to create a new instance of them (if they have
|
||||||
|
any extra setting up to do).
|
||||||
|
"""
|
||||||
|
obj = Node(children, connector, negated)
|
||||||
|
obj.__class__ = cls
|
||||||
|
return obj
|
||||||
|
_new_instance = classmethod(_new_instance)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
if self.negated:
|
if self.negated:
|
||||||
return '(NOT (%s: %s))' % (self.connector, ', '.join([str(c) for c
|
return '(NOT (%s: %s))' % (self.connector, ', '.join([str(c) for c
|
||||||
@ -82,7 +98,8 @@ class Node(object):
|
|||||||
else:
|
else:
|
||||||
self.children.append(node)
|
self.children.append(node)
|
||||||
else:
|
else:
|
||||||
obj = Node(self.children, self.connector, self.negated)
|
obj = self._new_instance(self.children, self.connector,
|
||||||
|
self.negated)
|
||||||
self.connector = conn_type
|
self.connector = conn_type
|
||||||
self.children = [obj, node]
|
self.children = [obj, node]
|
||||||
|
|
||||||
@ -96,7 +113,8 @@ class Node(object):
|
|||||||
Interpreting the meaning of this negate is up to client code. This
|
Interpreting the meaning of this negate is up to client code. This
|
||||||
method is useful for implementing "not" arrangements.
|
method is useful for implementing "not" arrangements.
|
||||||
"""
|
"""
|
||||||
self.children = [Node(self.children, self.connector, not self.negated)]
|
self.children = [self._new_instance(self.children, self.connector,
|
||||||
|
not self.negated)]
|
||||||
self.connector = self.default
|
self.connector = self.default
|
||||||
|
|
||||||
def start_subtree(self, conn_type):
|
def start_subtree(self, conn_type):
|
||||||
@ -108,12 +126,13 @@ class Node(object):
|
|||||||
if len(self.children) == 1:
|
if len(self.children) == 1:
|
||||||
self.connector = conn_type
|
self.connector = conn_type
|
||||||
elif self.connector != conn_type:
|
elif self.connector != conn_type:
|
||||||
self.children = [Node(self.children, self.connector, self.negated)]
|
self.children = [self._new_instance(self.children, self.connector,
|
||||||
|
self.negated)]
|
||||||
self.connector = conn_type
|
self.connector = conn_type
|
||||||
self.negated = False
|
self.negated = False
|
||||||
|
|
||||||
self.subtree_parents.append(Node(self.children, self.connector,
|
self.subtree_parents.append(self.__class__(self.children,
|
||||||
self.negated))
|
self.connector, self.negated))
|
||||||
self.connector = self.default
|
self.connector = self.default
|
||||||
self.negated = False
|
self.negated = False
|
||||||
self.children = []
|
self.children = []
|
||||||
@ -126,7 +145,7 @@ class Node(object):
|
|||||||
the current instances state to be the parent.
|
the current instances state to be the parent.
|
||||||
"""
|
"""
|
||||||
obj = self.subtree_parents.pop()
|
obj = self.subtree_parents.pop()
|
||||||
node = Node(self.children, self.connector)
|
node = self.__class__(self.children, self.connector)
|
||||||
self.connector = obj.connector
|
self.connector = obj.connector
|
||||||
self.negated = obj.negated
|
self.negated = obj.negated
|
||||||
self.children = obj.children
|
self.children = obj.children
|
||||||
|
@ -392,7 +392,7 @@ translated, here's what to do:
|
|||||||
* Create translations using the methods described in the
|
* Create translations using the methods described in the
|
||||||
`i18n documentation`_.
|
`i18n documentation`_.
|
||||||
* Create a diff of the ``.po`` file against the current Subversion trunk.
|
* Create a diff of the ``.po`` file against the current Subversion trunk.
|
||||||
* Make sure that `` bin/compile-messages.py -l <lang>`` runs without
|
* Make sure that `` django-admin.py compilemessages -l <lang>`` runs without
|
||||||
producing any warnings.
|
producing any warnings.
|
||||||
* Attach the patch to a ticket in Django's ticket system.
|
* Attach the patch to a ticket in Django's ticket system.
|
||||||
|
|
||||||
|
@ -85,6 +85,32 @@ your admin's index page. See `Tutorial 2`_ for more information.
|
|||||||
|
|
||||||
.. _Tutorial 2: ../tutorial02/
|
.. _Tutorial 2: ../tutorial02/
|
||||||
|
|
||||||
|
cleanup
|
||||||
|
-------
|
||||||
|
|
||||||
|
**New in Django development version**
|
||||||
|
|
||||||
|
Can be run as a cronjob or directly to clean out old data from the database
|
||||||
|
(only expired sessions at the moment).
|
||||||
|
|
||||||
|
compilemessages
|
||||||
|
---------------
|
||||||
|
|
||||||
|
**New in Django development version**
|
||||||
|
|
||||||
|
Compiles .po files created with ``makemessages`` to .mo files for use with
|
||||||
|
the builtin gettext support. See the `i18n documentation`_ for details.
|
||||||
|
|
||||||
|
--locale
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
Use the ``--locale`` or ``-l`` option to specify the locale to process.
|
||||||
|
If not provided all locales are processed.
|
||||||
|
|
||||||
|
Example usage::
|
||||||
|
|
||||||
|
django-admin.py compilemessages --locale=br_PT
|
||||||
|
|
||||||
createcachetable <tablename>
|
createcachetable <tablename>
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
@ -362,6 +388,62 @@ Example usage::
|
|||||||
|
|
||||||
django-admin.py loaddata --verbosity=2
|
django-admin.py loaddata --verbosity=2
|
||||||
|
|
||||||
|
makemessages
|
||||||
|
------------
|
||||||
|
|
||||||
|
**New in Django development version**
|
||||||
|
|
||||||
|
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 project and application)
|
||||||
|
directory. After making changes to the messages files you need to compile them
|
||||||
|
with ``compilemessages`` for use with the builtin gettext support. See the
|
||||||
|
`i18n documentation`_ for details.
|
||||||
|
|
||||||
|
.. _i18n documentation: ../i18n/#how-to-create-language-files
|
||||||
|
|
||||||
|
--all
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
Use the ``--all`` or ``-a`` option to update the message files for all
|
||||||
|
available languages.
|
||||||
|
|
||||||
|
Example usage::
|
||||||
|
|
||||||
|
django-admin.py makemessages --all
|
||||||
|
|
||||||
|
--locale
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
Use the ``--locale`` or ``-l`` option to specify the locale to process.
|
||||||
|
|
||||||
|
Example usage::
|
||||||
|
|
||||||
|
django-admin.py makemessages --locale=br_PT
|
||||||
|
|
||||||
|
--domain
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
Use the ``--domain`` or ``-d`` option to change the domain of the messages files.
|
||||||
|
Currently supported:
|
||||||
|
|
||||||
|
* ``django`` for all ``*.py`` and ``*.html`` files (default)
|
||||||
|
* ``djangojs`` for ``*.js`` files
|
||||||
|
|
||||||
|
--verbosity
|
||||||
|
~~~~~~~~~~~
|
||||||
|
|
||||||
|
Use ``--verbosity`` or ``-v`` to specify the amount of notification and debug
|
||||||
|
information that ``django-admin.py`` should print to the console.
|
||||||
|
|
||||||
|
* ``0`` means no output.
|
||||||
|
* ``1`` means normal output (default).
|
||||||
|
* ``2`` means verbose output.
|
||||||
|
|
||||||
|
Example usage::
|
||||||
|
|
||||||
|
django-admin.py makemessages --verbosity=2
|
||||||
|
|
||||||
reset <appname appname ...>
|
reset <appname appname ...>
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
|
@ -122,8 +122,8 @@ Translation works on variables. Again, here's an identical example::
|
|||||||
|
|
||||||
(The caveat with using variables or computed values, as in the previous two
|
(The caveat with using variables or computed values, as in the previous two
|
||||||
examples, is that Django's translation-string-detecting utility,
|
examples, is that Django's translation-string-detecting utility,
|
||||||
``make-messages.py``, won't be able to find these strings. More on
|
``django-admin.py makemessages``, won't be able to find these strings. More on
|
||||||
``make-messages`` later.)
|
``makemessages`` later.)
|
||||||
|
|
||||||
The strings you pass to ``_()`` or ``ugettext()`` can take placeholders,
|
The strings you pass to ``_()`` or ``ugettext()`` can take placeholders,
|
||||||
specified with Python's standard named-string interpolation syntax. Example::
|
specified with Python's standard named-string interpolation syntax. Example::
|
||||||
@ -266,10 +266,11 @@ Internally, all block and inline translations use the appropriate
|
|||||||
Each ``RequestContext`` has access to three translation-specific variables:
|
Each ``RequestContext`` has access to three translation-specific variables:
|
||||||
|
|
||||||
* ``LANGUAGES`` is a list of tuples in which the first element is the
|
* ``LANGUAGES`` is a list of tuples in which the first element is the
|
||||||
language code and the second is the language name (in that language).
|
language code and the second is the language name (translated into the
|
||||||
|
currently active locale).
|
||||||
* ``LANGUAGE_CODE`` is the current user's preferred language, as a string.
|
* ``LANGUAGE_CODE`` is the current user's preferred language, as a string.
|
||||||
Example: ``en-us``. (See "How language preference is discovered", below.)
|
Example: ``en-us``. (See "How language preference is discovered", below.)
|
||||||
* ``LANGUAGE_BIDI`` is the current language's direction. If True, it's a
|
* ``LANGUAGE_BIDI`` is the current locale's direction. If True, it's a
|
||||||
right-to-left language, e.g: Hebrew, Arabic. If False it's a
|
right-to-left language, e.g: Hebrew, Arabic. If False it's a
|
||||||
left-to-right language, e.g: English, French, German etc.
|
left-to-right language, e.g: English, French, German etc.
|
||||||
|
|
||||||
@ -392,12 +393,17 @@ file is a plain-text file, representing a single language, that contains all
|
|||||||
available translation strings and how they should be represented in the given
|
available translation strings and how they should be represented in the given
|
||||||
language. Message files have a ``.po`` file extension.
|
language. Message files have a ``.po`` file extension.
|
||||||
|
|
||||||
Django comes with a tool, ``bin/make-messages.py``, that automates the creation
|
Django comes with a tool, ``django-admin.py makemessages``, that automates the
|
||||||
and upkeep of these files.
|
creation and upkeep of these files.
|
||||||
|
|
||||||
|
.. admonition:: A note to Django veterans
|
||||||
|
|
||||||
|
The old tool ``bin/make-messages.py`` has been moved to the command
|
||||||
|
``django-admin.py makemessages`` to provide consistency throughout Django.
|
||||||
|
|
||||||
To create or update a message file, run this command::
|
To create or update a message file, run this command::
|
||||||
|
|
||||||
bin/make-messages.py -l de
|
django-admin.py makemessages -l de
|
||||||
|
|
||||||
...where ``de`` is the language code for the message file you want to create.
|
...where ``de`` is the language code for the message file you want to create.
|
||||||
The language code, in this case, is in locale format. For example, it's
|
The language code, in this case, is in locale format. For example, it's
|
||||||
@ -422,11 +428,11 @@ do the same, but the location of the locale directory is ``locale/LANG/LC_MESSAG
|
|||||||
|
|
||||||
.. admonition:: No gettext?
|
.. admonition:: No gettext?
|
||||||
|
|
||||||
If you don't have the ``gettext`` utilities installed, ``make-messages.py``
|
If you don't have the ``gettext`` utilities installed,
|
||||||
will create empty files. If that's the case, either install the ``gettext``
|
``django-admin.py makemessages`` will create empty files. If that's the
|
||||||
utilities or just copy the English message file
|
case, either install the ``gettext`` utilities or just copy the English
|
||||||
(``conf/locale/en/LC_MESSAGES/django.po``) and use it as a starting point;
|
message file (``conf/locale/en/LC_MESSAGES/django.po``) and use it as a
|
||||||
it's just an empty translation file.
|
starting point; it's just an empty translation file.
|
||||||
|
|
||||||
The format of ``.po`` files is straightforward. Each ``.po`` file contains a
|
The format of ``.po`` files is straightforward. Each ``.po`` file contains a
|
||||||
small bit of metadata, such as the translation maintainer's contact
|
small bit of metadata, such as the translation maintainer's contact
|
||||||
@ -439,8 +445,8 @@ For example, if your Django app contained a translation string for the text
|
|||||||
|
|
||||||
_("Welcome to my site.")
|
_("Welcome to my site.")
|
||||||
|
|
||||||
...then ``make-messages.py`` will have created a ``.po`` file containing the
|
...then ``django-admin.py makemessages`` will have created a ``.po`` file
|
||||||
following snippet -- a message::
|
containing the following snippet -- a message::
|
||||||
|
|
||||||
#: path/to/python/module.py:23
|
#: path/to/python/module.py:23
|
||||||
msgid "Welcome to my site."
|
msgid "Welcome to my site."
|
||||||
@ -475,24 +481,30 @@ otherwise, they'll be tacked together without whitespace!
|
|||||||
To reexamine all source code and templates for new translation strings and
|
To reexamine all source code and templates for new translation strings and
|
||||||
update all message files for **all** languages, run this::
|
update all message files for **all** languages, run this::
|
||||||
|
|
||||||
make-messages.py -a
|
django-admin.py makemessages -a
|
||||||
|
|
||||||
Compiling message files
|
Compiling message files
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
After you create your message file -- and each time you make changes to it --
|
After you create your message file -- and each time you make changes to it --
|
||||||
you'll need to compile it into a more efficient form, for use by ``gettext``.
|
you'll need to compile it into a more efficient form, for use by ``gettext``.
|
||||||
Do this with the ``bin/compile-messages.py`` utility.
|
Do this with the ``django-admin.py compilemessages`` utility.
|
||||||
|
|
||||||
This tool runs over all available ``.po`` files and creates ``.mo`` files,
|
This tool runs over all available ``.po`` files and creates ``.mo`` files,
|
||||||
which are binary files optimized for use by ``gettext``. In the same directory
|
which are binary files optimized for use by ``gettext``. In the same directory
|
||||||
from which you ran ``make-messages.py``, run ``compile-messages.py`` like
|
from which you ran ``django-admin.py makemessages``, run
|
||||||
this::
|
``django-admin.py compilemessages`` like this::
|
||||||
|
|
||||||
bin/compile-messages.py
|
django-admin.py compilemessages
|
||||||
|
|
||||||
That's it. Your translations are ready for use.
|
That's it. Your translations are ready for use.
|
||||||
|
|
||||||
|
.. admonition:: A note to Django veterans
|
||||||
|
|
||||||
|
The old tool ``bin/compile-messages.py`` has been moved to the command
|
||||||
|
``django-admin.py compilemessages`` to provide consistency throughout
|
||||||
|
Django.
|
||||||
|
|
||||||
.. admonition:: A note to translators
|
.. admonition:: A note to translators
|
||||||
|
|
||||||
If you've created a translation in a language Django doesn't yet support,
|
If you've created a translation in a language Django doesn't yet support,
|
||||||
@ -597,9 +609,9 @@ Notes:
|
|||||||
('en', ugettext('English')),
|
('en', ugettext('English')),
|
||||||
)
|
)
|
||||||
|
|
||||||
With this arrangement, ``make-messages.py`` will still find and mark
|
With this arrangement, ``django-admin.py makemessages`` will still find
|
||||||
these strings for translation, but the translation won't happen at
|
and mark these strings for translation, but the translation won't happen
|
||||||
runtime -- so you'll have to remember to wrap the languages in the *real*
|
at runtime -- so you'll have to remember to wrap the languages in the *real*
|
||||||
``ugettext()`` in any code that uses ``LANGUAGES`` at runtime.
|
``ugettext()`` in any code that uses ``LANGUAGES`` at runtime.
|
||||||
|
|
||||||
* The ``LocaleMiddleware`` can only select languages for which there is a
|
* The ``LocaleMiddleware`` can only select languages for which there is a
|
||||||
@ -676,15 +688,16 @@ All message file repositories are structured the same way. They are:
|
|||||||
searched in that order for ``<language>/LC_MESSAGES/django.(po|mo)``
|
searched in that order for ``<language>/LC_MESSAGES/django.(po|mo)``
|
||||||
* ``$PYTHONPATH/django/conf/locale/<language>/LC_MESSAGES/django.(po|mo)``
|
* ``$PYTHONPATH/django/conf/locale/<language>/LC_MESSAGES/django.(po|mo)``
|
||||||
|
|
||||||
To create message files, you use the same ``make-messages.py`` tool as with the
|
To create message files, you use the same ``django-admin.py makemessages``
|
||||||
Django message files. You only need to be in the right place -- in the directory
|
tool as with the Django message files. You only need to be in the right place
|
||||||
where either the ``conf/locale`` (in case of the source tree) or the ``locale/``
|
-- in the directory where either the ``conf/locale`` (in case of the source
|
||||||
(in case of app messages or project messages) directory are located. And you
|
tree) or the ``locale/`` (in case of app messages or project messages)
|
||||||
use the same ``compile-messages.py`` to produce the binary ``django.mo`` files
|
directory are located. And you use the same ``django-admin.py compilemessages``
|
||||||
that are used by ``gettext``.
|
to produce the binary ``django.mo`` files that are used by ``gettext``.
|
||||||
|
|
||||||
You can also run ``compile-message.py --settings=path.to.settings`` to make
|
You can also run ``django-admin.py compilemessages --settings=path.to.settings``
|
||||||
the compiler process all the directories in your ``LOCALE_PATHS`` setting.
|
to make the compiler process all the directories in your ``LOCALE_PATHS``
|
||||||
|
setting.
|
||||||
|
|
||||||
Application message files are a bit complicated to discover -- they need the
|
Application message files are a bit complicated to discover -- they need the
|
||||||
``LocaleMiddleware``. If you don't use the middleware, only the Django message
|
``LocaleMiddleware``. If you don't use the middleware, only the Django message
|
||||||
@ -694,15 +707,15 @@ 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
|
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.
|
be used in other projects, you might want to use app-specific translations.
|
||||||
But using app-specific translations and project translations could produce
|
But using app-specific translations and project translations could produce
|
||||||
weird problems with ``make-messages``: ``make-messages`` will traverse all
|
weird problems with ``makemessages``: ``makemessages`` will traverse all
|
||||||
directories below the current path and so might put message IDs into the
|
directories below the current path and so might put message IDs into the
|
||||||
project message file that are already in application message files.
|
project message file that are already in application message files.
|
||||||
|
|
||||||
The easiest way out is to store applications that are not part of the project
|
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,
|
(and so carry their own translations) outside the project tree. That way,
|
||||||
``make-messages`` on the project level will only translate strings that are
|
``django-admin.py makemessages`` on the project level will only translate
|
||||||
connected to your explicit project and not strings that are distributed
|
strings that are connected to your explicit project and not strings that are
|
||||||
independently.
|
distributed independently.
|
||||||
|
|
||||||
The ``set_language`` redirect view
|
The ``set_language`` redirect view
|
||||||
==================================
|
==================================
|
||||||
@ -857,14 +870,14 @@ Creating JavaScript translation catalogs
|
|||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
|
||||||
You create and update the translation catalogs the same way as the other
|
You create and update the translation catalogs the same way as the other
|
||||||
Django translation catalogs -- with the make-messages.py tool. The only
|
Django translation catalogs -- with the django-admin.py makemessages tool. The
|
||||||
difference is you need to provide a ``-d djangojs`` parameter, like this::
|
only difference is you need to provide a ``-d djangojs`` parameter, like this::
|
||||||
|
|
||||||
make-messages.py -d djangojs -l de
|
django-admin.py makemessages -d djangojs -l de
|
||||||
|
|
||||||
This would create or update the translation catalog for JavaScript for German.
|
This would create or update the translation catalog for JavaScript for German.
|
||||||
After updating translation catalogs, just run ``compile-messages.py`` the same
|
After updating translation catalogs, just run ``django-admin.py compilemessages``
|
||||||
way as you do with normal Django translation catalogs.
|
the same way as you do with normal Django translation catalogs.
|
||||||
|
|
||||||
Specialties of Django translation
|
Specialties of Django translation
|
||||||
==================================
|
==================================
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
.TH "compile-messages.py" "1" "August 2007" "Django Project" ""
|
|
||||||
.SH "NAME"
|
|
||||||
compile-messages.py \- Internationalization utility for the Django
|
|
||||||
web framework
|
|
||||||
.SH "SYNOPSIS"
|
|
||||||
.B compile-messages.py \fR[-l <locale>]
|
|
||||||
|
|
||||||
.SH "DESCRIPTION"
|
|
||||||
A Django-customised wrapper around gettext's \fBmsgfmt\fR command. Generates
|
|
||||||
binary message catalogs (.mo files) from textual translation descriptions (.po
|
|
||||||
files).
|
|
||||||
.sp
|
|
||||||
The script should be invoked after running
|
|
||||||
.BI make-messages.py,
|
|
||||||
in the same directory from which
|
|
||||||
.BI make-messages.py
|
|
||||||
was invoked.
|
|
||||||
|
|
||||||
.SH "OPTIONS"
|
|
||||||
.TP
|
|
||||||
.I \-l <locale>
|
|
||||||
Compile the message catalogs for a specific locale. If this option is omitted,
|
|
||||||
all message catalogs are (re-)compiled.
|
|
||||||
|
|
||||||
.SH "SEE ALSO"
|
|
||||||
The man page for
|
|
||||||
.BI msgfmt
|
|
||||||
from the GNU gettext utilities, and the internationalization documentation
|
|
||||||
for Django:
|
|
||||||
.sp
|
|
||||||
.I http://www.djangoproject.com/documentation/i18n/
|
|
||||||
|
|
||||||
.SH "AUTHORS/CREDITS"
|
|
||||||
Originally developed at World Online in Lawrence, Kansas, USA. Refer to the
|
|
||||||
AUTHORS file in the Django distribution for contributors.
|
|
||||||
|
|
||||||
.SH "LICENSE"
|
|
||||||
New BSD license. For the full license text refer to the LICENSE file in the
|
|
||||||
Django distribution.
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
.TH "django-admin.py" "1" "June 2007" "Django Project" ""
|
.TH "django-admin.py" "1" "March 2008" "Django Project" ""
|
||||||
.SH "NAME"
|
.SH "NAME"
|
||||||
django\-admin.py \- Utility script for the Django web framework
|
django\-admin.py \- Utility script for the Django web framework
|
||||||
.SH "SYNOPSIS"
|
.SH "SYNOPSIS"
|
||||||
@ -21,6 +21,12 @@ script found at the top level of each Django project directory.
|
|||||||
.BI "adminindex [" "appname ..." "]"
|
.BI "adminindex [" "appname ..." "]"
|
||||||
Prints the admin\-index template snippet for the given app name(s).
|
Prints the admin\-index template snippet for the given app name(s).
|
||||||
.TP
|
.TP
|
||||||
|
.BI cleanup
|
||||||
|
Cleans out old data from the database (only expired sessions at the moment).
|
||||||
|
.TP
|
||||||
|
.BI "compilemessages [" "\-\-locale=LOCALE" "]"
|
||||||
|
Compiles .po files to .mo files for use with builtin gettext support.
|
||||||
|
.TP
|
||||||
.BI "createcachetable [" "tablename" "]"
|
.BI "createcachetable [" "tablename" "]"
|
||||||
Creates the table needed to use the SQL cache backend
|
Creates the table needed to use the SQL cache backend
|
||||||
.TP
|
.TP
|
||||||
@ -43,6 +49,11 @@ Executes
|
|||||||
.B sqlall
|
.B sqlall
|
||||||
for the given app(s) in the current database.
|
for the given app(s) in the current database.
|
||||||
.TP
|
.TP
|
||||||
|
.BI "makemessages [" "\-\-locale=LOCALE" "] [" "\-\-domain=DOMAIN" "] [" "\-\-all" "]"
|
||||||
|
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 project and application) directory.
|
||||||
|
.TP
|
||||||
.BI "reset [" "appname ..." "]"
|
.BI "reset [" "appname ..." "]"
|
||||||
Executes
|
Executes
|
||||||
.B sqlreset
|
.B sqlreset
|
||||||
@ -136,7 +147,15 @@ Verbosity level: 0=minimal output, 1=normal output, 2=all output.
|
|||||||
.TP
|
.TP
|
||||||
.I \-\-adminmedia=ADMIN_MEDIA_PATH
|
.I \-\-adminmedia=ADMIN_MEDIA_PATH
|
||||||
Specifies the directory from which to serve admin media when using the development server.
|
Specifies the directory from which to serve admin media when using the development server.
|
||||||
|
.TP
|
||||||
|
.I \-l, \-\-locale=LOCALE
|
||||||
|
The locale to process when using makemessages or compilemessages.
|
||||||
|
.TP
|
||||||
|
.I \-d, \-\-domain=DOMAIN
|
||||||
|
The domain of the message files (default: "django") when using makemessages.
|
||||||
|
.TP
|
||||||
|
.I \-a, \-\-all
|
||||||
|
Process all available locales when using makemessages.
|
||||||
.SH "ENVIRONMENT"
|
.SH "ENVIRONMENT"
|
||||||
.TP
|
.TP
|
||||||
.I DJANGO_SETTINGS_MODULE
|
.I DJANGO_SETTINGS_MODULE
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
.TH "make-messages.py" "1" "August 2007" "Django Project" ""
|
|
||||||
.SH "NAME"
|
|
||||||
make-messages.py \- Internationalization utility for the Django
|
|
||||||
web framework
|
|
||||||
.SH "SYNOPSIS"
|
|
||||||
.B make-messages.py\fR [\-a] [\-v] [\-l <locale>] [\-d <domain>]
|
|
||||||
|
|
||||||
.SH "DESCRIPTION"
|
|
||||||
This script creates or updates one or more message files for a Django app,
|
|
||||||
a Django project or the Django framework itself. It should be run from one
|
|
||||||
of three places: the root directory of a Django app; the root directory
|
|
||||||
of a Django project; or the root django directory (the one in your PYTHONPATH,
|
|
||||||
not the root of a Subversion checkout).
|
|
||||||
.sp
|
|
||||||
The script will run over the source tree of an application, project or Django
|
|
||||||
itself (depending on where it is invoked), pulling out all strings marked for
|
|
||||||
translation and creating or updating a standard PO-format message file for the
|
|
||||||
specified language. Refer to Django's internationalization documentation for
|
|
||||||
details of where this file is created.
|
|
||||||
.sp
|
|
||||||
The \fI\-a\fR and \fI\-l\fR options are used to control whether message
|
|
||||||
catalogs are created for all locales, or just a single one.
|
|
||||||
|
|
||||||
.SH "OPTIONS"
|
|
||||||
.TP
|
|
||||||
.I \-a
|
|
||||||
Run make-messages for all locales specified in the Django settings file. Cannot
|
|
||||||
be used in conjuntion with \fI\-l\fR.
|
|
||||||
.TP
|
|
||||||
.I \-d <domain>
|
|
||||||
Specifies the translation domain to use. Valid domains are \fIdjango\fR or
|
|
||||||
\fIdjangojs\fR, depending on whether you wish to generate translation strings
|
|
||||||
for the Python or JavaScript components of your app, your project or the
|
|
||||||
framework itself. The default domain is \fIdjango\fR.
|
|
||||||
.TP
|
|
||||||
.I \-l <locale>
|
|
||||||
Extract messages for a particular locale.
|
|
||||||
.TP
|
|
||||||
.I \-v
|
|
||||||
Run verbosely.
|
|
||||||
|
|
||||||
.SH "ENVIRONMENT"
|
|
||||||
.TP
|
|
||||||
.I DJANGO_SETTINGS_MODULE
|
|
||||||
This environment variable defines the settings module to be read.
|
|
||||||
It should be in Python-import form, e.g. "myproject.settings".
|
|
||||||
|
|
||||||
.SH "SEE ALSO"
|
|
||||||
The Django internationalization documentation:
|
|
||||||
.sp
|
|
||||||
.I http://www.djangoproject.com/documentation/i18n/
|
|
||||||
.sp
|
|
||||||
The PO file format is documented in the GNU gettext documentation.
|
|
||||||
|
|
||||||
.SH "AUTHORS/CREDITS"
|
|
||||||
Originally developed at World Online in Lawrence, Kansas, USA. Refer to the
|
|
||||||
AUTHORS file in the Django distribution for contributors.
|
|
||||||
|
|
||||||
.SH "LICENSE"
|
|
||||||
New BSD license. For the full license text refer to the LICENSE file in the
|
|
||||||
Django distribution.
|
|
||||||
|
|
@ -1348,7 +1348,7 @@ An ``UploadedFile`` object has two attributes:
|
|||||||
The string representation of an ``UploadedFile`` is the same as the filename
|
The string representation of an ``UploadedFile`` is the same as the filename
|
||||||
attribute.
|
attribute.
|
||||||
|
|
||||||
When you use a ``FileField`` on a form, you must also remember to
|
When you use a ``FileField`` in a form, you must also remember to
|
||||||
`bind the file data to the form`_.
|
`bind the file data to the form`_.
|
||||||
|
|
||||||
.. _`bind the file data to the form`: `Binding uploaded files to a form`_
|
.. _`bind the file data to the form`: `Binding uploaded files to a form`_
|
||||||
@ -1415,7 +1415,7 @@ These control the range of values permitted in the field.
|
|||||||
|
|
||||||
Using an ImageField requires that the `Python Imaging Library`_ is installed.
|
Using an ImageField requires that the `Python Imaging Library`_ is installed.
|
||||||
|
|
||||||
When you use a ``FileField`` on a form, you must also remember to
|
When you use an ``ImageField`` in a form, you must also remember to
|
||||||
`bind the file data to the form`_.
|
`bind the file data to the form`_.
|
||||||
|
|
||||||
.. _Python Imaging Library: http://www.pythonware.com/products/pil/
|
.. _Python Imaging Library: http://www.pythonware.com/products/pil/
|
||||||
@ -1820,15 +1820,21 @@ reuse certain sets of widget attributes over and over again. Rather than
|
|||||||
repeat these attribute definitions every time you need them, Django allows
|
repeat these attribute definitions every time you need them, Django allows
|
||||||
you to capture those definitions as a custom widget.
|
you to capture those definitions as a custom widget.
|
||||||
|
|
||||||
For example, if you find that you are including a lot of comment fields on forms,
|
For example, if you find that you are including a lot of comment fields on
|
||||||
you could capture the idea of a ``TextInput`` with a specific ``size`` attribute
|
forms, you could capture the idea of a ``TextInput`` with a specific
|
||||||
as a custom extension to the ``TextInput`` widget::
|
default ``size`` attribute as a custom extension to the ``TextInput`` widget::
|
||||||
|
|
||||||
class CommentWidget(forms.TextInput):
|
class CommentWidget(forms.TextInput):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
kwargs.setdefault('attrs',{}).update({'size': '40'})
|
attrs = kwargs.setdefault('attrs',{})
|
||||||
|
if 'size' not in attrs:
|
||||||
|
attrs['size'] = 40
|
||||||
super(CommentWidget, self).__init__(*args, **kwargs)
|
super(CommentWidget, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
We allow the ``size`` attribute to be overridden by the user, but, by default,
|
||||||
|
this widget will behave as if ``attrs={'size': 40}`` was always passed into the
|
||||||
|
constructor.
|
||||||
|
|
||||||
Then you can use this widget in your forms::
|
Then you can use this widget in your forms::
|
||||||
|
|
||||||
class CommentForm(forms.Form):
|
class CommentForm(forms.Form):
|
||||||
|
@ -349,7 +349,7 @@ table. Django updates this row each time the session data changes. If the user
|
|||||||
logs out manually, Django deletes the row. But if the user does *not* log out,
|
logs out manually, Django deletes the row. But if the user does *not* log out,
|
||||||
the row never gets deleted.
|
the row never gets deleted.
|
||||||
|
|
||||||
Django provides a sample clean-up script in ``django/bin/daily_cleanup.py``.
|
Django provides a sample clean-up script in ``django-admin.py cleanup``.
|
||||||
That script deletes any session in the session table whose ``expire_date`` is
|
That script deletes any session in the session table whose ``expire_date`` is
|
||||||
in the past -- but your application may have different requirements.
|
in the past -- but your application may have different requirements.
|
||||||
|
|
||||||
|
@ -682,10 +682,10 @@ settings file::
|
|||||||
('en', gettext('English')),
|
('en', gettext('English')),
|
||||||
)
|
)
|
||||||
|
|
||||||
With this arrangement, ``make-messages.py`` will still find and mark these
|
With this arrangement, ``django-admin.py makemessages`` will still find and
|
||||||
strings for translation, but the translation won't happen at runtime -- so
|
mark these strings for translation, but the translation won't happen at
|
||||||
you'll have to remember to wrap the languages in the *real* ``gettext()`` in
|
runtime -- so you'll have to remember to wrap the languages in the *real*
|
||||||
any code that uses ``LANGUAGES`` at runtime.
|
``gettext()`` in any code that uses ``LANGUAGES`` at runtime.
|
||||||
|
|
||||||
LOCALE_PATHS
|
LOCALE_PATHS
|
||||||
------------
|
------------
|
||||||
|
@ -42,13 +42,13 @@ _django_completion()
|
|||||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||||
|
|
||||||
# Standalone options
|
# Standalone options
|
||||||
opts="--help --settings --pythonpath --noinput --noreload --format --indent --verbosity --adminmedia --version"
|
opts="--help --settings --pythonpath --noinput --noreload --format --indent --verbosity --adminmedia --version --locale --domain"
|
||||||
# Actions
|
# Actions
|
||||||
actions="adminindex createcachetable createsuperuser dbshell diffsettings \
|
actions="adminindex createcachetable createsuperuser compilemessages \
|
||||||
dumpdata flush inspectdb loaddata reset runfcgi runserver \
|
dbshell diffsettings dumpdata flush inspectdb loaddata \
|
||||||
shell sql sqlall sqlclear sqlcustom sqlflush sqlindexes \
|
makemessages reset runfcgi runserver shell sql sqlall sqlclear \
|
||||||
sqlreset sqlsequencereset startapp startproject \
|
sqlcustom sqlflush sqlindexes sqlreset sqlsequencereset startapp \
|
||||||
syncdb test validate"
|
startproject syncdb test validate"
|
||||||
# Action's options
|
# Action's options
|
||||||
action_shell_opts="--plain"
|
action_shell_opts="--plain"
|
||||||
action_runfcgi_opts="host port socket method maxspare minspare maxchildren daemonize pidfile workdir"
|
action_runfcgi_opts="host port socket method maxspare minspare maxchildren daemonize pidfile workdir"
|
||||||
@ -118,8 +118,9 @@ _django_completion()
|
|||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
|
|
||||||
createcachetable|dbshell|diffsettings| \
|
createcachetable|cleanup|compilemessages|dbshell| \
|
||||||
inspectdb|runserver|startapp|startproject|syncdb| \
|
diffsettings|inspectdb|makemessages| \
|
||||||
|
runserver|startapp|startproject|syncdb| \
|
||||||
validate)
|
validate)
|
||||||
COMPREPLY=()
|
COMPREPLY=()
|
||||||
return 0
|
return 0
|
||||||
|
@ -39,7 +39,7 @@ Second Revision of First Revision
|
|||||||
(2, 1)
|
(2, 1)
|
||||||
|
|
||||||
Queryset to match most recent revision:
|
Queryset to match most recent revision:
|
||||||
>>> qs = RevisionableModel.objects.extra(where=["%(table)s.id IN (SELECT MAX(rev.id) FROM %(table)s AS rev GROUP BY rev.base_id)" % {'table': RevisionableModel._meta.db_table,}],)
|
>>> qs = RevisionableModel.objects.extra(where=["%(table)s.id IN (SELECT MAX(rev.id) FROM %(table)s rev GROUP BY rev.base_id)" % {'table': RevisionableModel._meta.db_table,}],)
|
||||||
>>> qs
|
>>> qs
|
||||||
[<RevisionableModel: Second Revision (2, 1)>]
|
[<RevisionableModel: Second Revision (2, 1)>]
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user