diff options
| author | Derek Anderson <public@kered.org> | 2006-10-26 19:09:51 +0000 |
|---|---|---|
| committer | Derek Anderson <public@kered.org> | 2006-10-26 19:09:51 +0000 |
| commit | 42851d90dadbf62f5d342ce5c4f496ba1eeba987 (patch) | |
| tree | a5d0e5c178afb2d7dbb7bf5ab37db9ced42f4b52 | |
| parent | 450889c9a6f7da3c2fce77a0ccf4c4cea9e29710 (diff) | |
committing to schema-evolution
merge from HEAD
git-svn-id: http://code.djangoproject.com/svn/django/branches/schema-evolution@3937 bcc190cf-cafb-0310-a4f2-bffc1f526a37
314 files changed, 16288 insertions, 5759 deletions
@@ -16,12 +16,23 @@ before Simon departed and currently oversees things with Adrian. Wilson Miner <http://www.wilsonminer.com/>, who designed Django's admin interface, pretty error pages, official Web site (djangoproject.com) and has -made many other contributions. +made many other contributions. He makes us look good. + +Malcolm Tredinnick <http://www.pointy-stick.com/blog/>, who has made +significant contributions to all levels of the framework, from its database +layer to template system and documentation. Georg "Hugo" Bauer <http://hugo.muensterland.org/>, who added internationalization support, manages i18n contributions and has made a ton of excellent tweaks, feature additions and bug fixes. +Luke Plant <http://lukeplant.me.uk/>, who has contributed many excellent +improvements, including database-level improvements, the CSRF middleware and +unit tests. + +Russell Keith-Magee <freakboy@iinet.net.au>, who has contributed many excellent +improvements, including refactoring of the Django ORM code and unit tests. + Robert Wittams <http://robert.wittams.com/>, who majorly refactored the Django admin application to allow for easier reuse and has made a ton of excellent tweaks, feature additions and bug fixes. @@ -31,8 +42,10 @@ And here is an inevitably incomplete list of MUCH-APPRECIATED CONTRIBUTORS -- people who have submitted patches, reported bugs, added translations, helped answer newbie questions, and generally made Django that much better: + adurdin@gmail.com akaihola Andreas + ant9000@netwise.it David Ascher <http://ascher.ca/> Arthur <avandorp@gmail.com> Jiri Barton @@ -49,18 +62,30 @@ answer newbie questions, and generally made Django that much better: Amit Chakradeo <http://amit.chakradeo.net/> ChaosKCW Ian Clelland <clelland@gmail.com> + crankycoder@gmail.com Matt Croydon <http://www.postneo.com/> + dackze+django@gmail.com Jonathan Daugherty (cygnus) <http://www.cprogrammer.org/> Jason Davies (Esaj) <http://www.jasondavies.com/> Alex Dedul deric@monowerks.com dne@mayonnaise.net + Maximillian Dornseif <md@hudora.de> + dummy@habmalnefrage.de Jeremy Dunck <http://dunck.us/> + Andy Dustman <farcepest@gmail.com> Clint Ecker + Enrico <rico.bl@gmail.com> + favo@exoweb.net gandalf@owca.info Baishampayan Ghose + martin.glueck@gmail.com + Simon Greenhill <dev@simon.net.nz> Espen Grindhaug <http://grindhaug.org/> Brant Harris + Hawkeye + heckj@mac.com + Joel Heenan <joelh-django@planetjoel.com> hipertracker@gmail.com Ian Holsman <http://feh.holsman.net/> Kieran Holland <http://www.kieranholland.com> @@ -70,34 +95,39 @@ answer newbie questions, and generally made Django that much better: Michael Josephson <http://www.sdjournal.com/> jpellerin@gmail.com junzhang.jn@gmail.com - Russell Keith-Magee <freakboy@iinet.net.au> Garth Kidd <http://www.deadlybloodyserious.com/> kilian <kilian.cavalotti@lip6.fr> Sune Kirkeby <http://ibofobi.dk/> Cameron Knight (ckknight) + Meir Kriheli <http://mksoft.co.il/> Bruce Kroeze <http://coderseye.com/> Joseph Kocherhans konrad@gwu.edu lakin.wecker@gmail.com Stuart Langridge <http://www.kryogenix.org/> Eugene Lazutkin <http://lazutkin.com/blog/> + Jeong-Min Lee Christopher Lenz <http://www.cmlenz.net/> + lerouxb@gmail.com limodou + mattmcc Martin Maney <http://www.chipy.org/Martin_Maney> Manuzhai Petar Marić mark@junklight.com mattycakes@gmail.com Jason McBrayer <http://www.carcosa.net/jason/> + mccutchen@gmail.com michael.mcewan@gmail.com - mir@noris.de mmarshall Eric Moritz <http://eric.themoritzfamily.com/> Robin Munn <http://www.geekforgod.com/> NebojÅ¡a DorÄ‘ević + Fraser Nevett <mail@nevett.org> Sam Newman <http://www.magpiebrain.com/> Neal Norwitz <nnorwitz@google.com> oggie rob <oz.robharvey@gmail.com> + Jay Parlar <parlar@gmail.com> pgross@thoughtworks.com phaedo <http://phaedo.cx/> phil@produxion.net @@ -106,25 +136,35 @@ answer newbie questions, and generally made Django that much better: plisk Daniel Poelzleithner <http://poelzi.org/> J. Rademaker + Michael Radziej <mir@noris.de> + ramiro Brian Ray <http://brianray.chipy.org/> rhettg@gmail.com Oliver Rutherfurd <http://rutherfurd.net/> Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/> David Schein + serbaut@gmail.com + Pete Shinners <pete@shinners.org> + SmileyChris <smileychris@gmail.com> sopel + Thomas Steinacher <tom@eggdrop.ch> Radek Å varz <http://www.svarz.cz/translate/> Swaroop C H <http://www.swaroopch.info> Aaron Swartz <http://www.aaronsw.com/> + Tyson Tate <tyson@fallingbullets.com> Tom Tobin Tom Insam Joe Topjian <http://joe.terrarum.net/geek/code/python/django/> - Malcolm Tredinnick + Karen Tracey <graybark@bellsouth.net> Amit Upadhyay Geert Vanderkelen Milton Waddams + Dan Watson <http://theidioteque.net/> Rachel Willmer <http://www.willmer.com/kb/> + Gary Wilson <gary.wilson@gmail.com> wojtek ye7cakf02@sneakemail.com + ymasuda@ethercube.com Cheng Zhang A big THANK YOU goes to: @@ -1,7 +1,22 @@ Thanks for downloading Django. -To install it, make sure you have Python 2.3 or greater installed. Then run this command: +To install it, make sure you have Python 2.3 or greater installed. Then run +this command from the command prompt: -python setup.py install + python setup.py install + +Note this requires a working Internet connection if you don't already have the +Python utility "setuptools" installed. + +AS AN ALTERNATIVE, you can just copy the entire "django" directory to Python's +site-packages directory, which is located wherever your Python installation +lives. Some places you might check are: + + /usr/lib/python2.4/site-packages (Unix, Python 2.4) + /usr/lib/python2.3/site-packages (Unix, Python 2.3) + C:\\PYTHON\site-packages (Windows) + +This second solution does not require a working Internet connection; it +bypasses "setuptools" entirely. For more detailed instructions, see docs/install.txt. diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000000..b5fbb3cb90 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,8 @@ +include AUTHORS +include INSTALL +include LICENSE +recursive-include django/conf/locale * +recursive-include django/contrib/admin/templates +recursive-include django/contrib/admin/media +recursive-include django/contrib/comments/templates +recursive-include django/contrib/sitemaps/templates @@ -25,10 +25,10 @@ http://code.djangoproject.com/newticket To get more help: * Join the #django channel on irc.freenode.net. Lots of helpful people - hang out there. Read the archives at http://loglibrary.com/179 . + hang out there. Read the archives at http://simon.bofh.ms/logger/django/ . * Join the django-users mailing list, or read the archives, at - http://groups-beta.google.com/group/django-users. + http://groups.google.com/group/django-users. To contribute to Django: diff --git a/django/__init__.py b/django/__init__.py index 00c6f82478..5d5461c867 100644 --- a/django/__init__.py +++ b/django/__init__.py @@ -1 +1 @@ -VERSION = (0, 95, 'post-magic-removal') +VERSION = (0, 96, 'pre') diff --git a/django/bin/compile-messages.py b/django/bin/compile-messages.py index e33fdd780b..0137ec8dd4 100755 --- a/django/bin/compile-messages.py +++ b/django/bin/compile-messages.py @@ -2,7 +2,6 @@ import os import sys -import getopt def compile_messages(): basedir = None @@ -12,15 +11,25 @@ def compile_messages(): elif os.path.isdir('locale'): basedir = os.path.abspath('locale') else: - print "this script should be run from the django svn tree or your project or app tree" + print "This script should be run from the Django SVN tree or your project or app tree." sys.exit(1) - for (dirpath, dirnames, filenames) in os.walk(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] - cmd = 'msgfmt -o "%s.mo" "%s.po"' % (pf, pf) + # 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 -o "%djangocompilemo%" "%djangocompilepo%"' + else: + cmd = 'msgfmt -o "$djangocompilemo" "$djangocompilepo"' os.system(cmd) if __name__ == "__main__": diff --git a/django/bin/daily_cleanup.py b/django/bin/daily_cleanup.py index 6eb5c17feb..667e0f16c6 100644 --- a/django/bin/daily_cleanup.py +++ b/django/bin/daily_cleanup.py @@ -1,16 +1,17 @@ -"Daily cleanup file" +""" +Daily cleanup job. -from django.db import backend, connection, transaction +Can be run as a cronjob to clean out old data from the database (only expired +sessions at the moment). +""" -DOCUMENTATION_DIRECTORY = '/home/html/documentation/' +from django.db import backend, connection, transaction def clean_up(): # Clean up old database records cursor = connection.cursor() cursor.execute("DELETE FROM %s WHERE %s < NOW()" % \ - (backend.quote_name('core_sessions'), backend.quote_name('expire_date'))) - cursor.execute("DELETE FROM %s WHERE %s < NOW() - INTERVAL '1 week'" % \ - (backend.quote_name('registration_challenges'), backend.quote_name('request_date'))) + (backend.quote_name('django_session'), backend.quote_name('expire_date'))) transaction.commit_unless_managed() if __name__ == "__main__": diff --git a/django/bin/make-messages.py b/django/bin/make-messages.py index 75b0bc0ca0..557cb5eeec 100755 --- a/django/bin/make-messages.py +++ b/django/bin/make-messages.py @@ -1,5 +1,9 @@ #!/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 diff --git a/django/conf/__init__.py b/django/conf/__init__.py index a6a09d772f..1a04bbfb02 100644 --- a/django/conf/__init__.py +++ b/django/conf/__init__.py @@ -7,7 +7,6 @@ a list of all possible variables. """ import os -import sys from django.conf import global_settings ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE" diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py index 497a0d16aa..69c775cdec 100644 --- a/django/conf/global_settings.py +++ b/django/conf/global_settings.py @@ -46,6 +46,7 @@ LANGUAGES = ( ('en', gettext_noop('English')), ('es', gettext_noop('Spanish')), ('es_AR', gettext_noop('Argentinean Spanish')), + ('fi', gettext_noop('Finnish')), ('fr', gettext_noop('French')), ('gl', gettext_noop('Galician')), ('hu', gettext_noop('Hungarian')), @@ -55,6 +56,7 @@ LANGUAGES = ( ('ja', gettext_noop('Japanese')), ('nl', gettext_noop('Dutch')), ('no', gettext_noop('Norwegian')), + ('pl', gettext_noop('Polish')), ('pt-br', gettext_noop('Brazilian')), ('ro', gettext_noop('Romanian')), ('ru', gettext_noop('Russian')), @@ -62,6 +64,8 @@ LANGUAGES = ( ('sl', gettext_noop('Slovenian')), ('sr', gettext_noop('Serbian')), ('sv', gettext_noop('Swedish')), + ('ta', gettext_noop('Tamil')), + ('tr', gettext_noop('Turkish')), ('uk', gettext_noop('Ukrainian')), ('zh-cn', gettext_noop('Simplified Chinese')), ('zh-tw', gettext_noop('Traditional Chinese')), @@ -220,10 +224,6 @@ YEAR_MONTH_FORMAT = 'F Y' # http://www.djangoproject.com/documentation/templates/#now MONTH_DAY_FORMAT = 'F j' -# Whether to enable Psyco, which optimizes Python code. Requires Psyco. -# http://psyco.sourceforge.net/ -ENABLE_PSYCO = False - # Do you want to manage transactions manually? # Hint: you really don't! TRANSACTIONS_MANAGED = False @@ -251,6 +251,7 @@ MIDDLEWARE_CLASSES = ( SESSION_COOKIE_NAME = 'sessionid' # Cookie name. This can be whatever you want. SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2 # Age of cookie, in seconds (default: 2 weeks). SESSION_COOKIE_DOMAIN = None # A string like ".lawrence.com", or None for standard domain cookie. +SESSION_COOKIE_SECURE = False # Whether the session cookie should be secure (https:// only). SESSION_SAVE_EVERY_REQUEST = False # Whether to save the session data on every request. SESSION_EXPIRE_AT_BROWSER_CLOSE = False # Whether sessions expire when a user closes his browser. @@ -269,6 +270,10 @@ CACHE_MIDDLEWARE_KEY_PREFIX = '' COMMENTS_ALLOW_PROFANITIES = False +# The profanities that will trigger a validation error in the +# 'hasNoProfanities' validator. All of these should be in lowercase. +PROFANITIES_LIST = ('asshat', 'asshead', 'asshole', 'cunt', 'fuck', 'gook', 'nigger', 'shit') + # The group ID that designates which users are banned. # Set to None if you're not using it. COMMENTS_BANNED_USERS_GROUP = None @@ -294,3 +299,14 @@ BANNED_IPS = () ################## AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend',) + +########### +# TESTING # +########### + +# The name of the method to use to invoke the test suite +TEST_RUNNER = 'django.test.simple.run_tests' + +# The name of the database to use for testing purposes. +# If None, a name of 'test_' + DATABASE_NAME will be assumed +TEST_DATABASE_NAME = None diff --git a/django/conf/locale/cs/LC_MESSAGES/django.mo b/django/conf/locale/cs/LC_MESSAGES/django.mo Binary files differindex 8984023810..c2f04edb81 100644 --- a/django/conf/locale/cs/LC_MESSAGES/django.mo +++ b/django/conf/locale/cs/LC_MESSAGES/django.mo diff --git a/django/conf/locale/cs/LC_MESSAGES/django.po b/django/conf/locale/cs/LC_MESSAGES/django.po index cdbb124c94..0dcc31394c 100644 --- a/django/conf/locale/cs/LC_MESSAGES/django.po +++ b/django/conf/locale/cs/LC_MESSAGES/django.po @@ -8,15 +8,14 @@ msgstr "" "Project-Id-Version: Django Czech translation\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2006-05-16 10:11+0200\n" -"PO-Revision-Date: 2006-05-20 22:44+0100\n" -"Last-Translator: Radek Å varz <translate@svarz.cz>\n" +"PO-Revision-Date: 2006-10-07 13:10+0100\n" +"Last-Translator: \n" "Language-Team: Czech\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "X-Poedit-Country: CZECH REPUBLIC\n" -"X-Poedit-Bookmarks: -1,-1,-1,-1,-1,-1,-1,-1,-1,139\n" #: contrib/comments/models.py:67 #: contrib/comments/models.py:166 @@ -80,7 +79,7 @@ msgid "is public" msgstr "je veÅ™ejné" #: contrib/comments/models.py:85 -#: contrib/admin/views/doc.py:289 +#: contrib/admin/views/doc.py:304 msgid "IP address" msgstr "IP adresa" @@ -214,11 +213,11 @@ msgstr "Neplatné ID komentáře" msgid "No voting for yourself" msgstr "Nelze hlasovat pro sebe" -#: contrib/comments/views/comments.py:28 +#: contrib/comments/views/comments.py:27 msgid "This rating is required because you've entered at least one other rating." msgstr "Toto hodnocenà je povinné, protože jste zadal(a) alespoň jedno jiné hodnocenÃ." -#: contrib/comments/views/comments.py:112 +#: contrib/comments/views/comments.py:111 #, python-format msgid "" "This comment was posted by a user who has posted fewer than %(count)s comment:\n" @@ -241,7 +240,7 @@ msgstr[2] "" "\n" "%(text)s" -#: contrib/comments/views/comments.py:117 +#: contrib/comments/views/comments.py:116 #, python-format msgid "" "This comment was posted by a sketchy user:\n" @@ -252,22 +251,22 @@ msgstr "" "\n" "%(text)s" -#: contrib/comments/views/comments.py:189 +#: contrib/comments/views/comments.py:188 #: contrib/comments/views/comments.py:280 msgid "Only POSTs are allowed" msgstr "Je povolená pouze metoda POST" -#: contrib/comments/views/comments.py:193 +#: contrib/comments/views/comments.py:192 #: contrib/comments/views/comments.py:284 msgid "One or more of the required fields wasn't submitted" msgstr "Jedno nebo vÃce povinných polà nebylo vyplnÄ›né" -#: contrib/comments/views/comments.py:197 +#: contrib/comments/views/comments.py:196 #: contrib/comments/views/comments.py:286 msgid "Somebody tampered with the comment form (security violation)" msgstr "NÄ›kdo falÅ¡oval formulář komentáře (bezpeÄnostnà naruÅ¡enÃ)" -#: contrib/comments/views/comments.py:207 +#: contrib/comments/views/comments.py:206 #: contrib/comments/views/comments.py:292 msgid "The comment form had an invalid 'target' parameter -- the object ID was invalid" msgstr "Formulář komentáře mÄ›l neplatný parametr 'target' -- ID objektu nebylo platné" @@ -284,18 +283,9 @@ msgid "Username:" msgstr "Uživatelské jméno:" #: contrib/comments/templates/comments/form.html:6 -#: contrib/admin/templates/admin/login.html:20 -msgid "Password:" -msgstr "Heslo:" - -#: contrib/comments/templates/comments/form.html:6 -msgid "Forgotten your password?" -msgstr "Zapomenuté heslo?" - -#: contrib/comments/templates/comments/form.html:8 #: contrib/admin/templates/admin/object_history.html:3 #: contrib/admin/templates/admin/change_list.html:5 -#: contrib/admin/templates/admin/base.html:23 +#: contrib/admin/templates/admin/base.html:25 #: contrib/admin/templates/admin/delete_confirmation.html:3 #: contrib/admin/templates/admin/change_form.html:10 #: contrib/admin/templates/registration/password_change_done.html:3 @@ -313,6 +303,15 @@ msgstr "Zapomenuté heslo?" msgid "Log out" msgstr "Odhlásit se" +#: contrib/comments/templates/comments/form.html:8 +#: contrib/admin/templates/admin/login.html:20 +msgid "Password:" +msgstr "Heslo:" + +#: contrib/comments/templates/comments/form.html:8 +msgid "Forgotten your password?" +msgstr "Zapomenuté heslo?" + #: contrib/comments/templates/comments/form.html:12 msgid "Ratings" msgstr "HodnocenÃ" @@ -331,13 +330,13 @@ msgstr "Volitelné" msgid "Post a photo" msgstr "ZaÅ™adit fotografii" -#: contrib/comments/templates/comments/form.html:27 +#: contrib/comments/templates/comments/form.html:28 #: contrib/comments/templates/comments/freeform.html:5 msgid "Comment:" msgstr "Komentář:" -#: contrib/comments/templates/comments/form.html:32 -#: contrib/comments/templates/comments/freeform.html:9 +#: contrib/comments/templates/comments/form.html:35 +#: contrib/comments/templates/comments/freeform.html:10 msgid "Preview comment" msgstr "Náhled komentáře" @@ -357,6 +356,7 @@ msgstr "" #: contrib/admin/filterspecs.py:70 #: contrib/admin/filterspecs.py:88 #: contrib/admin/filterspecs.py:143 +#: contrib/admin/filterspecs.py:169 msgid "All" msgstr "VÅ¡e" @@ -420,217 +420,292 @@ msgstr "log záznam" msgid "log entries" msgstr "log záznamy" -#: contrib/admin/templatetags/admin_list.py:228 +#: contrib/admin/templatetags/admin_list.py:230 msgid "All dates" msgstr "VÅ¡echna data" -#: contrib/admin/views/decorators.py:9 -#: contrib/auth/forms.py:36 -#: contrib/auth/forms.py:41 +#: contrib/admin/views/decorators.py:10 +#: contrib/auth/forms.py:59 msgid "Please enter a correct username and password. Note that both fields are case-sensitive." msgstr "ProsÃme, vložte správné uživatelské jméno a heslo. Poznámka - u obou položek se rozliÅ¡uje velikost pÃsmen." -#: contrib/admin/views/decorators.py:23 +#: contrib/admin/views/decorators.py:24 #: contrib/admin/templates/admin/login.html:25 msgid "Log in" msgstr "PÅ™ihlášenÃ" -#: contrib/admin/views/decorators.py:61 +#: contrib/admin/views/decorators.py:62 msgid "Please log in again, because your session has expired. Don't worry: Your submission has been saved." msgstr "ProsÃme, znovu se pÅ™ihlaÅ¡te, VaÅ¡e sezenà vyprÅ¡elo. NemusÃte se obávat, VaÅ¡e podánà je uloženo." -#: contrib/admin/views/decorators.py:68 +#: contrib/admin/views/decorators.py:69 msgid "Looks like your browser isn't configured to accept cookies. Please enable cookies, reload this page, and try again." msgstr "Vypadá to, že Váš prohlÞeÄ nenà nastaven, aby akceptoval cookies. ProsÃme, zapnÄ›te cookies, obnovte tuto stránku a zkuste znovu." -#: contrib/admin/views/decorators.py:82 +#: contrib/admin/views/decorators.py:83 msgid "Usernames cannot contain the '@' character." msgstr "Uživatelská jména nemohou obsahovat znak '@'." -#: contrib/admin/views/decorators.py:84 +#: contrib/admin/views/decorators.py:85 #, python-format msgid "Your e-mail address is not your username. Try '%s' instead." msgstr "VaÅ¡e e-mailová adresa nenà VaÅ¡e uživatelské jméno. Zkuste mÃsto toho '%s'." -#: contrib/admin/views/main.py:226 +#: contrib/admin/views/main.py:223 msgid "Site administration" msgstr "Django správa" -#: contrib/admin/views/main.py:260 +#: contrib/admin/views/main.py:257 +#: contrib/admin/views/auth.py:17 #, python-format msgid "The %(name)s \"%(obj)s\" was added successfully." msgstr "Záznam %(name)s \"%(obj)s\" byl úspěšnÄ› pÅ™idán." -#: contrib/admin/views/main.py:264 -#: contrib/admin/views/main.py:348 +#: contrib/admin/views/main.py:261 +#: contrib/admin/views/main.py:347 +#: contrib/admin/views/auth.py:22 msgid "You may edit it again below." msgstr "Můžete to opÄ›t upravit nÞe." -#: contrib/admin/views/main.py:272 -#: contrib/admin/views/main.py:357 +#: contrib/admin/views/main.py:271 +#: contrib/admin/views/main.py:356 #, python-format msgid "You may add another %s below." msgstr "Můžete pÅ™idat dalšà %s nÞe." -#: contrib/admin/views/main.py:290 +#: contrib/admin/views/main.py:289 #, python-format msgid "Add %s" msgstr "%s: pÅ™idat" -#: contrib/admin/views/main.py:336 +#: contrib/admin/views/main.py:335 #, python-format msgid "Added %s." msgstr "Záznam %s byl pÅ™idán." -#: contrib/admin/views/main.py:336 -#: contrib/admin/views/main.py:338 -#: contrib/admin/views/main.py:340 +#: contrib/admin/views/main.py:335 +#: contrib/admin/views/main.py:337 +#: contrib/admin/views/main.py:339 msgid "and" msgstr "a" -#: contrib/admin/views/main.py:338 +#: contrib/admin/views/main.py:337 #, python-format msgid "Changed %s." msgstr "%s: zmÄ›nÄ›no" -#: contrib/admin/views/main.py:340 +#: contrib/admin/views/main.py:339 #, python-format msgid "Deleted %s." msgstr "Záznam %s byl smazán." -#: contrib/admin/views/main.py:343 +#: contrib/admin/views/main.py:342 msgid "No fields changed." msgstr "Nebyly zmÄ›nÄ›ny žádné pole." -#: contrib/admin/views/main.py:346 +#: contrib/admin/views/main.py:345 #, python-format msgid "The %(name)s \"%(obj)s\" was changed successfully." msgstr "%(name)s \"%(obj)s\" byl úspěšnÄ› zmÄ›nÄ›n." -#: contrib/admin/views/main.py:354 +#: contrib/admin/views/main.py:353 #, python-format msgid "The %(name)s \"%(obj)s\" was added successfully. You may edit it again below." msgstr "The %(name)s \"%(obj)s\" byl úspěšnÄ› pÅ™idán. Můžete to opÄ›t upravit nÞe." -#: contrib/admin/views/main.py:392 +#: contrib/admin/views/main.py:391 #, python-format msgid "Change %s" msgstr "%s: zmÄ›nit" -#: contrib/admin/views/main.py:470 +#: contrib/admin/views/main.py:473 #, python-format msgid "One or more %(fieldname)s in %(name)s: %(obj)s" msgstr "Jedno nebo vÃce %(fieldname)s z %(name)s: %(obj)s" -#: contrib/admin/views/main.py:475 +#: contrib/admin/views/main.py:478 #, python-format msgid "One or more %(fieldname)s in %(name)s:" msgstr "Jedno nebo vÃce %(fieldname)s z %(name)s:" -#: contrib/admin/views/main.py:508 +#: contrib/admin/views/main.py:511 #, python-format msgid "The %(name)s \"%(obj)s\" was deleted successfully." msgstr "Záznam %(name)s \"%(obj)s\" byl úspěšnÄ› smazán." -#: contrib/admin/views/main.py:511 +#: contrib/admin/views/main.py:514 msgid "Are you sure?" msgstr "Jste si jist(á)?" -#: contrib/admin/views/main.py:533 +#: contrib/admin/views/main.py:536 #, python-format msgid "Change history: %s" msgstr "Historie zmÄ›n: %s" -#: contrib/admin/views/main.py:565 +#: contrib/admin/views/main.py:570 #, python-format msgid "Select %s" msgstr "Vybrat %s" -#: contrib/admin/views/main.py:565 +#: contrib/admin/views/main.py:570 #, python-format msgid "Select %s to change" msgstr "Vyberte %s pro zmÄ›nu" -#: contrib/admin/views/doc.py:277 -#: contrib/admin/views/doc.py:286 -#: contrib/admin/views/doc.py:288 -#: contrib/admin/views/doc.py:294 -#: contrib/admin/views/doc.py:295 -#: contrib/admin/views/doc.py:297 +#: contrib/admin/views/main.py:758 +msgid "Database error" +msgstr "Databázová chyba" + +#: contrib/admin/views/doc.py:46 +#: contrib/admin/views/doc.py:48 +#: contrib/admin/views/doc.py:50 +msgid "tag:" +msgstr "tag:" + +#: contrib/admin/views/doc.py:77 +#: contrib/admin/views/doc.py:79 +#: contrib/admin/views/doc.py:81 +msgid "filter:" +msgstr "filtr:" + +#: contrib/admin/views/doc.py:135 +#: contrib/admin/views/doc.py:137 +#: contrib/admin/views/doc.py:139 +msgid "view:" +msgstr "pohled (view):" + +#: contrib/admin/views/doc.py:164 +#, python-format +msgid "App %r not found" +msgstr "Aplikace %r nenalezena" + +#: contrib/admin/views/doc.py:171 +#, python-format +msgid "Model %r not found in app %r" +msgstr "Model %r v aplikaci %r nenalezen" + +#: contrib/admin/views/doc.py:183 +#, python-format +msgid "the related `%s.%s` object" +msgstr "souvisejÃcà objekt `%s.%s`" + +#: contrib/admin/views/doc.py:183 +#: contrib/admin/views/doc.py:205 +#: contrib/admin/views/doc.py:219 +#: contrib/admin/views/doc.py:224 +msgid "model:" +msgstr "model:" + +#: contrib/admin/views/doc.py:214 +#, python-format +msgid "related `%s.%s` objects" +msgstr "souvisejÃcà objekty `%s.%s`" + +#: contrib/admin/views/doc.py:219 +#, python-format +msgid "all %s" +msgstr "%s: vÅ¡e" + +#: contrib/admin/views/doc.py:224 +#, python-format +msgid "number of %s" +msgstr "%s: poÄet" + +#: contrib/admin/views/doc.py:229 +#, python-format +msgid "Fields on %s objects" +msgstr "Pole na objektech %s" + +#: contrib/admin/views/doc.py:291 +#: contrib/admin/views/doc.py:301 +#: contrib/admin/views/doc.py:303 +#: contrib/admin/views/doc.py:309 +#: contrib/admin/views/doc.py:310 +#: contrib/admin/views/doc.py:312 msgid "Integer" msgstr "Celé ÄÃslo" -#: contrib/admin/views/doc.py:278 +#: contrib/admin/views/doc.py:292 msgid "Boolean (Either True or False)" msgstr "Boolean (buÄ Ano (True), nebo Ne (False))" -#: contrib/admin/views/doc.py:279 -#: contrib/admin/views/doc.py:296 +#: contrib/admin/views/doc.py:293 +#: contrib/admin/views/doc.py:311 #, python-format msgid "String (up to %(maxlength)s)" msgstr "Text (maximálnÄ› %(maxlength)s znaků)" -#: contrib/admin/views/doc.py:280 +#: contrib/admin/views/doc.py:294 msgid "Comma-separated integers" msgstr "Celá ÄÃsla oddÄ›lená Äárkou" -#: contrib/admin/views/doc.py:281 +#: contrib/admin/views/doc.py:295 msgid "Date (without time)" msgstr "Datum (bez Äasu)" -#: contrib/admin/views/doc.py:282 +#: contrib/admin/views/doc.py:296 msgid "Date (with time)" msgstr "Datum (s Äasem)" -#: contrib/admin/views/doc.py:283 +#: contrib/admin/views/doc.py:297 msgid "E-mail address" msgstr "E-mailová adresa" -#: contrib/admin/views/doc.py:284 -#: contrib/admin/views/doc.py:287 +#: contrib/admin/views/doc.py:298 +#: contrib/admin/views/doc.py:299 +#: contrib/admin/views/doc.py:302 msgid "File path" msgstr "Cesta k souboru" -#: contrib/admin/views/doc.py:285 +#: contrib/admin/views/doc.py:300 msgid "Decimal number" msgstr "Desetiné ÄÃslo" -#: contrib/admin/views/doc.py:291 +#: contrib/admin/views/doc.py:306 msgid "Boolean (Either True, False or None)" msgstr "Boolean (buÄ Ano (True), Ne (False), nebo Nic (None))" -#: contrib/admin/views/doc.py:292 +#: contrib/admin/views/doc.py:307 msgid "Relation to parent model" msgstr "V relaci k rodiÄovskému modelu" -#: contrib/admin/views/doc.py:293 +#: contrib/admin/views/doc.py:308 msgid "Phone number" msgstr "Telefonnà ÄÃslo" -#: contrib/admin/views/doc.py:298 +#: contrib/admin/views/doc.py:313 msgid "Text" msgstr "Text" -#: contrib/admin/views/doc.py:299 +#: contrib/admin/views/doc.py:314 msgid "Time" msgstr "ÄŒas" -#: contrib/admin/views/doc.py:300 +#: contrib/admin/views/doc.py:315 #: contrib/flatpages/models.py:7 msgid "URL" msgstr "URL" -#: contrib/admin/views/doc.py:301 +#: contrib/admin/views/doc.py:316 msgid "U.S. state (two uppercase letters)" msgstr "Stát US (2 velké znaky)" -#: contrib/admin/views/doc.py:302 +#: contrib/admin/views/doc.py:317 msgid "XML text" msgstr "text XML" +#: contrib/admin/views/doc.py:343 +#, python-format +msgid "%s does not appear to be a urlpattern object" +msgstr "%s pravdÄ›podobnÄ› nenà objekt urlpattern" + +#: contrib/admin/views/auth.py:28 +msgid "Add user" +msgstr "PÅ™idat uživatele" + #: contrib/admin/templates/admin/object_history.html:3 #: contrib/admin/templates/admin/change_list.html:5 -#: contrib/admin/templates/admin/base.html:23 +#: contrib/admin/templates/admin/base.html:25 #: contrib/admin/templates/admin/delete_confirmation.html:3 #: contrib/admin/templates/admin/change_form.html:10 #: contrib/admin/templates/registration/password_change_done.html:3 @@ -641,7 +716,7 @@ msgstr "Dokumentace" #: contrib/admin/templates/admin/object_history.html:3 #: contrib/admin/templates/admin/change_list.html:5 -#: contrib/admin/templates/admin/base.html:23 +#: contrib/admin/templates/admin/base.html:25 #: contrib/admin/templates/admin/delete_confirmation.html:3 #: contrib/admin/templates/admin/change_form.html:10 #: contrib/admin/templates/registration/password_change_done.html:3 @@ -662,9 +737,10 @@ msgstr "ZmÄ›nit heslo" #: contrib/admin/templates/admin/object_history.html:5 #: contrib/admin/templates/admin/500.html:4 #: contrib/admin/templates/admin/change_list.html:6 -#: contrib/admin/templates/admin/base.html:28 +#: contrib/admin/templates/admin/base.html:30 #: contrib/admin/templates/admin/delete_confirmation.html:6 #: contrib/admin/templates/admin/change_form.html:13 +#: contrib/admin/templates/admin/invalid_setup.html:4 #: contrib/admin/templates/registration/password_change_done.html:4 #: contrib/admin/templates/registration/password_reset_form.html:4 #: contrib/admin/templates/registration/logged_out.html:4 @@ -737,6 +813,11 @@ msgstr "Je nám lÃto, ale vyžádaná stránka nebyla nalezena." msgid "Models available in the %(name)s application." msgstr "Dostupné modely v aplikaci %(name)s." +#: contrib/admin/templates/admin/index.html:18 +#, python-format +msgid "%(name)s" +msgstr "%(name)s" + #: contrib/admin/templates/admin/index.html:28 #: contrib/admin/templates/admin/change_form.html:15 msgid "Add" @@ -771,7 +852,7 @@ msgstr "%(name)s: pÅ™idat" msgid "Have you <a href=\"/password_reset/\">forgotten your password</a>?" msgstr "<a href=\"/password_reset/\">ZapomnÄ›l(a) jste své heslo?</a>" -#: contrib/admin/templates/admin/base.html:23 +#: contrib/admin/templates/admin/base.html:25 msgid "Welcome," msgstr "VÃtejte," @@ -782,13 +863,13 @@ msgstr "Smazat" #: contrib/admin/templates/admin/delete_confirmation.html:14 #, python-format -msgid "Deleting the %(object_name)s '%(object)s' would result in deleting related objects, but your account doesn't have permission to delete the following types of objects:" -msgstr "Mazánà %(object_name)s '%(object)s' by vyústilo ve vymazánà souvisejÃcÃch objektů, ale Váš úÄet nemá oprávnÄ›nà pro mazánà následujÃcÃch typů objektů:" +msgid "Deleting the %(object_name)s '%(escaped_object)s' would result in deleting related objects, but your account doesn't have permission to delete the following types of objects:" +msgstr "Mazánà %(object_name)s '%(escaped_object)s' by vyústilo ve vymazánà souvisejÃcÃch objektů, ale Váš úÄet nemá oprávnÄ›nà pro mazánà následujÃcÃch typů objektů:" #: contrib/admin/templates/admin/delete_confirmation.html:21 #, python-format -msgid "Are you sure you want to delete the %(object_name)s \"%(object)s\"? All of the following related items will be deleted:" -msgstr "Jste si jist(á), že chcete smazat %(object_name)s \"%(object)s\"? VÅ¡echny následujÃcà souvisejÃcà položky budou smazány:" +msgid "Are you sure you want to delete the %(object_name)s \"%(escaped_object)s\"? All of the following related items will be deleted:" +msgstr "Jste si jist(á), že chcete smazat %(object_name)s \"%(escaped_object)s\"? VÅ¡echny následujÃcà souvisejÃcà položky budou smazány:" #: contrib/admin/templates/admin/delete_confirmation.html:26 msgid "Yes, I'm sure" @@ -796,13 +877,34 @@ msgstr "Ano, jsem si jist" #: contrib/admin/templates/admin/filter.html:2 #, python-format -msgid " By %(title)s " -msgstr "Od %(title)s" +msgid " By %(filter_title)s " +msgstr " Dle %(filter_title)s " #: contrib/admin/templates/admin/search_form.html:8 msgid "Go" msgstr "Provést" +#: contrib/admin/templates/admin/search_form.html:10 +#, python-format +msgid "1 result" +msgid_plural "%(counter)s results" +msgstr[0] "1 výsledek" +msgstr[1] "%(counter)s výsledky" +msgstr[2] "%(counter)s výsledků" + +#: contrib/admin/templates/admin/search_form.html:10 +#, python-format +msgid "%(full_result_count)s total" +msgstr "celkem %(full_result_count)s" + +#: contrib/admin/templates/admin/pagination.html:10 +msgid "Show all" +msgstr "Zobrazit vÅ¡echny" + +#: contrib/admin/templates/admin/filters.html:4 +msgid "Filter" +msgstr "Filtr" + #: contrib/admin/templates/admin/change_form.html:21 msgid "View on site" msgstr "Pohled na stránku" @@ -838,6 +940,30 @@ msgstr "Uložit a pokraÄovat v úpravách" msgid "Save" msgstr "Uložit" +#: contrib/admin/templates/admin/invalid_setup.html:8 +msgid "Something's wrong with your database installation. Make sure the appropriate database tables have been created, and make sure the database is readable by the appropriate user." +msgstr "NÄ›co nenà v pořádku s Vašà instalacà databáze. UjistÄ›te se, že byly vytvoÅ™eny odpovÃdajÃcà tabulky databáze a že databáze je pÅ™Ãstupná pro Ätenà daným databázovým uživatelem." + +#: contrib/admin/templates/admin/auth/user/add_form.html:6 +msgid "First, enter a username and password. Then, you'll be able to edit more user options." +msgstr "NejdÅ™Ãve vložte uživatelské jméno a heslo. Poté budete moci upravovat vÃce uživatelských možnostÃ." + +#: contrib/admin/templates/admin/auth/user/add_form.html:12 +msgid "Username" +msgstr "Uživatelské jméno" + +#: contrib/admin/templates/admin/auth/user/add_form.html:18 +msgid "Password" +msgstr "Heslo" + +#: contrib/admin/templates/admin/auth/user/add_form.html:23 +msgid "Password (again)" +msgstr "Heslo (znova)" + +#: contrib/admin/templates/admin/auth/user/add_form.html:24 +msgid "Enter the same password as above, for verification." +msgstr "Pro ověřenà vložte stejné heslo znovu." + #: contrib/admin/templates/registration/password_change_done.html:4 #: contrib/admin/templates/registration/password_change_form.html:4 #: contrib/admin/templates/registration/password_change_form.html:6 @@ -1031,11 +1157,11 @@ msgstr "pÅ™esmÄ›rovat na" msgid "This can be either an absolute path (as above) or a full URL starting with 'http://'." msgstr "Toto může být buÄ absolutnà cesta (jako nahoÅ™e) nebo plné URL zaÄÃnajÃcà na 'http://'." -#: contrib/redirects/models.py:12 +#: contrib/redirects/models.py:13 msgid "redirect" msgstr "pÅ™esmÄ›rovat" -#: contrib/redirects/models.py:13 +#: contrib/redirects/models.py:14 msgid "redirects" msgstr "pÅ™esmÄ›rovánÃ" @@ -1060,8 +1186,8 @@ msgid "template name" msgstr "jméno Å¡ablony" #: contrib/flatpages/models.py:13 -msgid "Example: 'flatpages/contact_page'. If this isn't provided, the system will use 'flatpages/default'." -msgstr "NapÅ™Ãklad: 'flatfiles/kontaktni_stranka'. Pokud toto nenà zadáno, systém použije 'flatfiles/default'." +msgid "Example: 'flatpages/contact_page.html'. If this isn't provided, the system will use 'flatpages/default.html'." +msgstr "NapÅ™Ãklad: 'flatpages/kontaktni_stranka.html'. Pokud toto nenà zadáno, systém použije 'flatpages/default.html'." #: contrib/flatpages/models.py:14 msgid "registration required" @@ -1079,150 +1205,170 @@ msgstr "statická stránka" msgid "flat pages" msgstr "statické stránky" -#: contrib/auth/models.py:13 -#: contrib/auth/models.py:26 +#: contrib/auth/views.py:39 +msgid "Logged out" +msgstr "Odhlášeno" + +#: contrib/auth/models.py:38 +#: contrib/auth/models.py:57 msgid "name" msgstr "jméno" -#: contrib/auth/models.py:15 +#: contrib/auth/models.py:40 msgid "codename" msgstr "codename" -#: contrib/auth/models.py:17 +#: contrib/auth/models.py:42 msgid "permission" msgstr "oprávnÄ›nÃ" -#: contrib/auth/models.py:18 -#: contrib/auth/models.py:27 +#: contrib/auth/models.py:43 +#: contrib/auth/models.py:58 msgid "permissions" msgstr "oprávnÄ›nÃ" -#: contrib/auth/models.py:29 +#: contrib/auth/models.py:60 msgid "group" msgstr "skupina" -#: contrib/auth/models.py:30 -#: contrib/auth/models.py:65 +#: contrib/auth/models.py:61 +#: contrib/auth/models.py:100 msgid "groups" msgstr "skupiny" -#: contrib/auth/models.py:55 +#: contrib/auth/models.py:90 msgid "username" msgstr "uživatelské jméno" -#: contrib/auth/models.py:56 +#: contrib/auth/models.py:90 +msgid "Required. 30 characters or fewer. Alphanumeric characters only (letters, digits and underscores)." +msgstr "Požadováno. 30 znaků nebo ménÄ›. Pouze alfanumerické znaky (znaky, ÄÃsla a podtržÃtka)." + +#: contrib/auth/models.py:91 msgid "first name" msgstr "kÅ™estnà jméno" -#: contrib/auth/models.py:57 +#: contrib/auth/models.py:92 msgid "last name" msgstr "pÅ™ÃjmenÃ" -#: contrib/auth/models.py:58 +#: contrib/auth/models.py:93 msgid "e-mail address" msgstr "e-mailová adresa" -#: contrib/auth/models.py:59 +#: contrib/auth/models.py:94 msgid "password" msgstr "heslo" -#: contrib/auth/models.py:59 +#: contrib/auth/models.py:94 msgid "Use '[algo]$[salt]$[hexdigest]'" msgstr "Použijte '[algo]$[salt]$[hexdigest]'" -#: contrib/auth/models.py:60 +#: contrib/auth/models.py:95 msgid "staff status" msgstr "administrativnà pÅ™Ãstup " -#: contrib/auth/models.py:60 +#: contrib/auth/models.py:95 msgid "Designates whether the user can log into this admin site." msgstr "Rozhodne, zda se může uživatel pÅ™ihlásit do správy webu." -#: contrib/auth/models.py:61 +#: contrib/auth/models.py:96 msgid "active" msgstr "aktivnÃ" -#: contrib/auth/models.py:62 +#: contrib/auth/models.py:96 +msgid "Designates whether this user can log into the Django admin. Unselect this instead of deleting accounts." +msgstr "Rozhodne, zda se může uživatel pÅ™ihlásit do správy webu. Nastavte toto mÃsto mazánà úÄtů." + +#: contrib/auth/models.py:97 msgid "superuser status" msgstr "stav superuživatel" -#: contrib/auth/models.py:63 +#: contrib/auth/models.py:97 +msgid "Designates that this user has all permissions without explicitly assigning them." +msgstr "StanovÃ, že tento uživatel má veÅ¡kerá oprávnÄ›nà bez jejich explicitnÃho pÅ™iÅ™azenÃ." + +#: contrib/auth/models.py:98 msgid "last login" msgstr "poslednà pÅ™ihlášenÃ" -#: contrib/auth/models.py:64 +#: contrib/auth/models.py:99 msgid "date joined" msgstr "datum zaregistrovánÃ" -#: contrib/auth/models.py:66 +#: contrib/auth/models.py:101 msgid "In addition to the permissions manually assigned, this user will also get all permissions granted to each group he/she is in." msgstr "KromÄ› manuálnÄ› pÅ™idÄ›lených oprávnÄ›nà uživatel dostane vÅ¡echna oprávnÄ›nà pro každou skupinu, ve které je." -#: contrib/auth/models.py:67 +#: contrib/auth/models.py:102 msgid "user permissions" msgstr "uživatelskà oprávnÄ›nÃ" -#: contrib/auth/models.py:70 +#: contrib/auth/models.py:105 msgid "user" msgstr "uživatel" -#: contrib/auth/models.py:71 +#: contrib/auth/models.py:106 msgid "users" msgstr "uživatelé" -#: contrib/auth/models.py:76 +#: contrib/auth/models.py:111 msgid "Personal info" msgstr "Osobnà informace" -#: contrib/auth/models.py:77 +#: contrib/auth/models.py:112 msgid "Permissions" msgstr "OprávnÄ›nÃ" -#: contrib/auth/models.py:78 +#: contrib/auth/models.py:113 msgid "Important dates" msgstr "Důležitá data" -#: contrib/auth/models.py:79 +#: contrib/auth/models.py:114 msgid "Groups" msgstr "Skupiny" -#: contrib/auth/models.py:219 +#: contrib/auth/models.py:256 msgid "message" msgstr "zpráva" -#: contrib/auth/forms.py:30 +#: contrib/auth/forms.py:52 msgid "Your Web browser doesn't appear to have cookies enabled. Cookies are required for logging in." msgstr "Váš prohlÞeÄ pravdÄ›podobnÄ› nemá zapnuté cookies. Cookies jsou potÅ™eba pro zalogovánÃ." -#: contrib/contenttypes/models.py:25 +#: contrib/auth/forms.py:61 +msgid "This account is inactive." +msgstr "Tento úÄet nenà aktivnÃ." + +#: contrib/contenttypes/models.py:20 msgid "python model class name" msgstr "jméno modelu Pythonu" -#: contrib/contenttypes/models.py:28 +#: contrib/contenttypes/models.py:23 msgid "content type" msgstr "typ obsahu" -#: contrib/contenttypes/models.py:29 +#: contrib/contenttypes/models.py:24 msgid "content types" msgstr "typy obsahu" -#: contrib/sessions/models.py:35 +#: contrib/sessions/models.py:51 msgid "session key" msgstr "klÃÄ sezenÃ" -#: contrib/sessions/models.py:36 +#: contrib/sessions/models.py:52 msgid "session data" msgstr "data sezenÃ" -#: contrib/sessions/models.py:37 +#: contrib/sessions/models.py:53 msgid "expire date" msgstr "datum expirace" -#: contrib/sessions/models.py:41 +#: contrib/sessions/models.py:57 msgid "session" msgstr "sezenÃ" -#: contrib/sessions/models.py:42 +#: contrib/sessions/models.py:58 msgid "sessions" msgstr "sezenÃ" @@ -1242,18 +1388,6 @@ msgstr "web" msgid "sites" msgstr "weby" -#: utils/translation.py:360 -msgid "DATE_FORMAT" -msgstr "j.n.Y" - -#: utils/translation.py:361 -msgid "DATETIME_FORMAT" -msgstr "j.n.Y, H:i" - -#: utils/translation.py:362 -msgid "TIME_FORMAT" -msgstr "H:i" - #: utils/dates.py:6 msgid "Monday" msgstr "PondÄ›lÃ" @@ -1453,203 +1587,263 @@ msgstr[0] "minuta" msgstr[1] "minuty" msgstr[2] "minut" -#: conf/global_settings.py:37 +#: utils/translation/trans_real.py:362 +msgid "DATE_FORMAT" +msgstr "j.n.Y" + +#: utils/translation/trans_real.py:363 +msgid "DATETIME_FORMAT" +msgstr "j.n.Y, H:i" + +#: utils/translation/trans_real.py:364 +msgid "TIME_FORMAT" +msgstr "H:i" + +#: utils/translation/trans_real.py:380 +msgid "YEAR_MONTH_FORMAT" +msgstr "F Y" + +#: utils/translation/trans_real.py:381 +msgid "MONTH_DAY_FORMAT" +msgstr "j. F" + +#: conf/global_settings.py:39 +msgid "Arabic" +msgstr "Arabic" + +#: conf/global_settings.py:40 msgid "Bengali" msgstr "Bengálsky" -#: conf/global_settings.py:38 +#: conf/global_settings.py:41 msgid "Czech" msgstr "ÄŒesky" -#: conf/global_settings.py:39 +#: conf/global_settings.py:42 msgid "Welsh" msgstr "WelÅ¡sky" -#: conf/global_settings.py:40 +#: conf/global_settings.py:43 msgid "Danish" msgstr "Dánsky" -#: conf/global_settings.py:41 +#: conf/global_settings.py:44 msgid "German" msgstr "NÄ›mecky" -#: conf/global_settings.py:42 +#: conf/global_settings.py:45 msgid "Greek" msgstr "Řecky" -#: conf/global_settings.py:43 +#: conf/global_settings.py:46 msgid "English" msgstr "Anglicky" -#: conf/global_settings.py:44 +#: conf/global_settings.py:47 msgid "Spanish" msgstr "Å panÄ›lsky" -#: conf/global_settings.py:45 +#: conf/global_settings.py:48 +msgid "Argentinean Spanish" +msgstr "Argentinean Spanish" + +#: conf/global_settings.py:49 +msgid "Finnish" +msgstr "Finsky" + +#: conf/global_settings.py:50 msgid "French" msgstr "Francouzsky" -#: conf/global_settings.py:46 +#: conf/global_settings.py:51 msgid "Galician" msgstr "Galicijsky" -#: conf/global_settings.py:47 +#: conf/global_settings.py:52 msgid "Hungarian" msgstr "MaÄarsky" -#: conf/global_settings.py:48 +#: conf/global_settings.py:53 msgid "Hebrew" msgstr "Hebrejsky" -#: conf/global_settings.py:49 +#: conf/global_settings.py:54 msgid "Icelandic" msgstr "IslandÅ¡tina" -#: conf/global_settings.py:50 +#: conf/global_settings.py:55 msgid "Italian" msgstr "Italsky" -#: conf/global_settings.py:51 +#: conf/global_settings.py:56 msgid "Japanese" msgstr "JaponÅ¡tina" -#: conf/global_settings.py:52 +#: conf/global_settings.py:57 msgid "Dutch" msgstr "HolandÅ¡tina" -#: conf/global_settings.py:53 +#: conf/global_settings.py:58 msgid "Norwegian" msgstr "Norsky" -#: conf/global_settings.py:54 +#: conf/global_settings.py:59 msgid "Brazilian" msgstr "Brazilsky" -#: conf/global_settings.py:55 +#: conf/global_settings.py:60 msgid "Romanian" msgstr "Rumunsky" -#: conf/global_settings.py:56 +#: conf/global_settings.py:61 msgid "Russian" msgstr "Rusky" -#: conf/global_settings.py:57 +#: conf/global_settings.py:62 msgid "Slovak" msgstr "Slovensky" -#: conf/global_settings.py:58 +#: conf/global_settings.py:63 msgid "Slovenian" msgstr "Slovinsky" -#: conf/global_settings.py:59 +#: conf/global_settings.py:64 msgid "Serbian" msgstr "Srbsky" -#: conf/global_settings.py:60 +#: conf/global_settings.py:65 msgid "Swedish" msgstr "Å védsky" -#: conf/global_settings.py:61 +#: conf/global_settings.py:66 +msgid "Tamil" +msgstr "Tamil" + +#: conf/global_settings.py:67 +msgid "Turkish" +msgstr "Turecky" + +#: conf/global_settings.py:68 msgid "Ukrainian" msgstr "Ukrajinsky" -#: conf/global_settings.py:62 +#: conf/global_settings.py:69 msgid "Simplified Chinese" msgstr "Jednoduchá ÄÃnÅ¡tina" -#: conf/global_settings.py:63 +#: conf/global_settings.py:70 msgid "Traditional Chinese" msgstr "TradiÄnà ÄÃnÅ¡tina" -#: core/validators.py:60 +#: core/validators.py:63 msgid "This value must contain only letters, numbers and underscores." msgstr "Tato hodnota musà obsahovat pouze znaky, ÄÃsla nebo podtržÃtka." -#: core/validators.py:64 +#: core/validators.py:67 msgid "This value must contain only letters, numbers, underscores, dashes or slashes." msgstr "Tato hodnota musà obsahovat pouze znaky, ÄÃsla, podtržÃtka, pomlÄky nebo lomÃtka." -#: core/validators.py:72 +#: core/validators.py:71 +msgid "This value must contain only letters, numbers, underscores or hyphens." +msgstr "Tato hodnota musà obsahovat pouze znaky, ÄÃsla, podtržÃtka nebo Äárky." + +#: core/validators.py:75 msgid "Uppercase letters are not allowed here." msgstr "Velká pÃsmena zde nejsou povolená." -#: core/validators.py:76 +#: core/validators.py:79 msgid "Lowercase letters are not allowed here." msgstr "Malá pÃsmena zde nejsou povolená." -#: core/validators.py:83 +#: core/validators.py:86 msgid "Enter only digits separated by commas." msgstr "Vložte pouze cifry oddÄ›lené Äárkami." -#: core/validators.py:95 +#: core/validators.py:98 msgid "Enter valid e-mail addresses separated by commas." msgstr "Vložte platné e-mailové adresy oddÄ›lené Äárkami." -#: core/validators.py:99 +#: core/validators.py:102 msgid "Please enter a valid IP address." msgstr "ProsÃme, zadejte platnou IP adresu." -#: core/validators.py:103 +#: core/validators.py:106 msgid "Empty values are not allowed here." msgstr "Zde nejsou povolené prázdné hodnoty." -#: core/validators.py:107 +#: core/validators.py:110 msgid "Non-numeric characters aren't allowed here." msgstr "Znaky, které nejsou ÄÃsla, nejsou zde povoleny." -#: core/validators.py:111 +#: core/validators.py:114 msgid "This value can't be comprised solely of digits." msgstr "Tato hodnota nemůže být složená pouze z cifer." -#: core/validators.py:116 +#: core/validators.py:119 msgid "Enter a whole number." msgstr "Vložte celé ÄÃslo." -#: core/validators.py:120 +#: core/validators.py:123 msgid "Only alphabetical characters are allowed here." msgstr "Zde jsou povoleny pouze alfanumerické znaky." -#: core/validators.py:124 +#: core/validators.py:138 +msgid "Year must be 1900 or later." +msgstr "Rok musà být 1900 a vyššÃ." + +#: core/validators.py:142 +#, python-format +msgid "Invalid date: %s." +msgstr "Neplatné datum: %s." + +#: core/validators.py:146 +#: db/models/fields/__init__.py:415 msgid "Enter a valid date in YYYY-MM-DD format." msgstr "Vložte platné datum ve formátu RRRR-MM-DD." -#: core/validators.py:128 +#: core/validators.py:151 msgid "Enter a valid time in HH:MM format." msgstr "Vložte platný Äas ve formátu HH:MM." -#: core/validators.py:132 -#: db/models/fields/__init__.py:468 +#: core/validators.py:155 +#: db/models/fields/__init__.py:477 msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format." msgstr "Vložte platné datum a Äas ve formátu RRRR-MM-DD HH:MM." -#: core/validators.py:136 +#: core/validators.py:160 msgid "Enter a valid e-mail address." msgstr "Vložte platnou e-mailovou adresu." -#: core/validators.py:148 +#: core/validators.py:172 +#: core/validators.py:401 +#: forms/__init__.py:661 +msgid "No file was submitted. Check the encoding type on the form." +msgstr "Soubor nebyl odeslán. Zkontrolujte encoding type formuláře." + +#: core/validators.py:176 msgid "Upload a valid image. The file you uploaded was either not an image or a corrupted image." msgstr "Nahrajte na server platný obrázek. Soubor, který jste nahrál(a) nebyl obrázek, nebo byl poruÅ¡en." -#: core/validators.py:155 +#: core/validators.py:183 #, python-format msgid "The URL %s does not point to a valid image." msgstr "URL %s neukazuje na platný obrázek." -#: core/validators.py:159 +#: core/validators.py:187 #, python-format msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid." msgstr "Telefonnà ÄÃsla musà být ve formátu XXX-XXX-XXXX. \"%s\" nenà platné." -#: core/validators.py:167 +#: core/validators.py:195 #, python-format msgid "The URL %s does not point to a valid QuickTime video." msgstr "URL %s neodkazuje na platné video ve formátu QuickTime." -#: core/validators.py:171 +#: core/validators.py:199 msgid "A valid URL is required." msgstr "Je vyžadováno platné URL." -#: core/validators.py:185 +#: core/validators.py:213 #, python-format msgid "" "Valid HTML is required. Specific errors are:\n" @@ -1658,27 +1852,27 @@ msgstr "" "Je vyžadováno platné HTML. Konkrétnà chyby jsou:\n" "%s" -#: core/validators.py:192 +#: core/validators.py:220 #, python-format msgid "Badly formed XML: %s" msgstr "Å patnÄ› formované XML: %s" -#: core/validators.py:202 +#: core/validators.py:230 #, python-format msgid "Invalid URL: %s" msgstr "Neplatné URL: %s" -#: core/validators.py:206 -#: core/validators.py:208 +#: core/validators.py:234 +#: core/validators.py:236 #, python-format msgid "The URL %s is a broken link." msgstr "Odkaz na URL %s je rozbitý." -#: core/validators.py:214 +#: core/validators.py:242 msgid "Enter a valid U.S. state abbreviation." msgstr "Vložte platnou zkraku U.S. státu." -#: core/validators.py:229 +#: core/validators.py:256 #, python-format msgid "Watch your mouth! The word %s is not allowed here." msgid_plural "Watch your mouth! The words %s are not allowed here." @@ -1686,44 +1880,44 @@ msgstr[0] "Mluvte sluÅ¡nÄ›! Slovo %s zde nenà pÅ™Ãpustné." msgstr[1] "Mluvte sluÅ¡nÄ›! Slova %s zde nejsou pÅ™Ãpustná." msgstr[2] "Mluvte sluÅ¡nÄ›! Slova %s zde nejsou pÅ™Ãpustná." -#: core/validators.py:236 +#: core/validators.py:263 #, python-format msgid "This field must match the '%s' field." msgstr "Toto pole se musà shodovat s polem '%s'." -#: core/validators.py:255 +#: core/validators.py:282 msgid "Please enter something for at least one field." msgstr "ProsÃme, vložte nÄ›co alespoň pro jedno pole." -#: core/validators.py:264 -#: core/validators.py:275 +#: core/validators.py:291 +#: core/validators.py:302 msgid "Please enter both fields or leave them both empty." msgstr "ProsÃme, vložte obÄ› pole, nebo je nechte obÄ› prázdná." -#: core/validators.py:282 +#: core/validators.py:309 #, python-format msgid "This field must be given if %(field)s is %(value)s" msgstr "Toto pole musà být vyplnÄ›no, když %(field)s má %(value)s" -#: core/validators.py:294 +#: core/validators.py:321 #, python-format msgid "This field must be given if %(field)s is not %(value)s" msgstr "Toto pole musà být vyplnÄ›no, když %(field)s nemá %(value)s" -#: core/validators.py:313 +#: core/validators.py:340 msgid "Duplicate values are not allowed." msgstr "Duplikátnà hodnoty nejsou povolené." -#: core/validators.py:336 +#: core/validators.py:363 #, python-format msgid "This value must be a power of %s." msgstr "Tato hodnota musà být mocninou %s." -#: core/validators.py:347 +#: core/validators.py:374 msgid "Please enter a valid decimal number." msgstr "ProsÃme, vložte platné ÄÃslo." -#: core/validators.py:349 +#: core/validators.py:378 #, python-format msgid "Please enter a valid decimal number with at most %s total digit." msgid_plural "Please enter a valid decimal number with at most %s total digits." @@ -1731,7 +1925,15 @@ msgstr[0] "ProsÃme, vložte platné ÄÃslo s nejvÃce %s cifrou celkem." msgstr[1] "ProsÃme, vložte platné ÄÃslo s nejvÃce %s ciframi celkem." msgstr[2] "ProsÃme, vložte platné ÄÃslo s nejvÃce %s ciframi celkem." -#: core/validators.py:352 +#: core/validators.py:381 +#, python-format +msgid "Please enter a valid decimal number with a whole part of at most %s digit." +msgid_plural "Please enter a valid decimal number with a whole part of at most %s digits." +msgstr[0] "ProsÃme, vložte platné ÄÃslo s nejvÃce %s cifrou." +msgstr[1] "ProsÃme, vložte platné ÄÃslo s nejvÃce %s ciframi." +msgstr[2] "ProsÃme, vložte platné ÄÃslo s nejvÃce %s ciframi." + +#: core/validators.py:384 #, python-format msgid "Please enter a valid decimal number with at most %s decimal place." msgid_plural "Please enter a valid decimal number with at most %s decimal places." @@ -1739,64 +1941,79 @@ msgstr[0] "ProsÃme, vložte platné ÄÃslo s nejvÃce %s cifrou za desetinnou msgstr[1] "ProsÃme, vložte platné ÄÃslo s nejvÃce %s ciframi za desetinnou Äárkou celkem." msgstr[2] "ProsÃme, vložte platné ÄÃslo s nejvÃce %s ciframi za desetinnou Äárkou celkem." -#: core/validators.py:362 +#: core/validators.py:394 #, python-format msgid "Make sure your uploaded file is at least %s bytes big." msgstr "UjistÄ›te se, že posÃlaný soubor je velký nejménÄ› %s bytů." -#: core/validators.py:363 +#: core/validators.py:395 #, python-format msgid "Make sure your uploaded file is at most %s bytes big." msgstr "UjistÄ›te se, že posÃlaný soubor je velký nejvÃce %s bytů." -#: core/validators.py:376 +#: core/validators.py:412 msgid "The format for this field is wrong." msgstr "Formát pro toto pole je Å¡patný." -#: core/validators.py:391 +#: core/validators.py:427 msgid "This field is invalid." msgstr "Toto pole nenà platné." -#: core/validators.py:426 +#: core/validators.py:463 #, python-format msgid "Could not retrieve anything from %s." msgstr "Nemohl jsem zÃskat nic z %s." -#: core/validators.py:429 +#: core/validators.py:466 #, python-format msgid "The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'." msgstr "URL %(url)s vrátilo neplatnou hlaviÄku Content-Type '%(contenttype)s'." -#: core/validators.py:462 +#: core/validators.py:499 #, python-format msgid "Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with \"%(start)s\".)" msgstr "ProsÃme, zavÅ™ete nezavÅ™enou znaÄku %(tag)s z řádky %(line)s. (Řádka zaÄÃná s \"%(start)s\".)" -#: core/validators.py:466 +#: core/validators.py:503 #, python-format msgid "Some text starting on line %(line)s is not allowed in that context. (Line starts with \"%(start)s\".)" msgstr "NÄ›jaký text zaÄÃnajÃcà na řádce %(line)s nenà povolen v tomto kontextu. (Řádka zaÄÃná s \"%(start)s\".)" -#: core/validators.py:471 +#: core/validators.py:508 #, python-format msgid "\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%(start)s\".)" msgstr "\"%(attr)s\" na řádce %(line)s je neplatný atribut. (Řádka zaÄÃná s \"%(start)s\".)" -#: core/validators.py:476 +#: core/validators.py:513 #, python-format msgid "\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%(start)s\".)" msgstr "\"<%(tag)s>\" na řádce %(line)s je neplatná znaÄka. (Řádka zaÄÃná s \"%(start)s\".)" -#: core/validators.py:480 +#: core/validators.py:517 #, python-format msgid "A tag on line %(line)s is missing one or more required attributes. (Line starts with \"%(start)s\".)" msgstr "ZnaÄce na řádce %(line)s scházà jeden nebo vÃce požadovaných atributů. (Řádka zaÄÃná s \"%(start)s\".)" -#: core/validators.py:485 +#: core/validators.py:522 #, python-format msgid "The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line starts with \"%(start)s\".)" msgstr "Atribut \"%(attr)s\" na řádce %(line)s má neplatnou hodnotu. (Řádka zaÄÃna s \"%(start)s\".)" +#: views/generic/create_update.py:43 +#, python-format +msgid "The %(verbose_name)s was created successfully." +msgstr "Záznam %(verbose_name)s byl úspěšnÄ› vytvoÅ™en." + +#: views/generic/create_update.py:117 +#, python-format +msgid "The %(verbose_name)s was updated successfully." +msgstr "Záznam %(verbose_name)s byl úspěšnÄ› zmÄ›nen." + +#: views/generic/create_update.py:184 +#, python-format +msgid "The %(verbose_name)s was deleted." +msgstr "Záznam %(verbose_name)s byl smazán." + #: db/models/manipulators.py:302 #, python-format msgid "%(object)s with this %(type)s already exists for the given %(field)s." @@ -1809,42 +2026,42 @@ msgstr "%(optname)s s tÃmto %(fieldname)s již existuje." #: db/models/fields/__init__.py:114 #: db/models/fields/__init__.py:265 -#: db/models/fields/__init__.py:542 -#: db/models/fields/__init__.py:553 +#: db/models/fields/__init__.py:551 +#: db/models/fields/__init__.py:562 #: forms/__init__.py:346 msgid "This field is required." msgstr "Toto pole je povinné." -#: db/models/fields/__init__.py:337 +#: db/models/fields/__init__.py:340 msgid "This value must be an integer." msgstr "Tato hodnota musà být celé ÄÃslo." -#: db/models/fields/__init__.py:369 +#: db/models/fields/__init__.py:372 msgid "This value must be either True or False." msgstr "Tato hodnota musà být buÄ Ano (True), nebo Ne (False)." -#: db/models/fields/__init__.py:385 +#: db/models/fields/__init__.py:388 msgid "This field cannot be null." msgstr "Toto pole nemůže být prázdné (null)." -#: db/models/fields/__init__.py:562 +#: db/models/fields/__init__.py:571 msgid "Enter a valid filename." msgstr "Vložte platný název souboru." -#: db/models/fields/related.py:43 +#: db/models/fields/related.py:51 #, python-format msgid "Please enter a valid %s." msgstr "ProsÃme, zadejte %s správnÄ›." -#: db/models/fields/related.py:579 +#: db/models/fields/related.py:618 msgid "Separate multiple IDs with commas." msgstr "OddÄ›lte vÃce identifikátorů Äárkami." -#: db/models/fields/related.py:581 +#: db/models/fields/related.py:620 msgid "Hold down \"Control\", or \"Command\" on a Mac, to select more than one." msgstr "Podržte \"Control\", nebo \"Command\" na Macu pro vybránà vÃce jak jedné položky." -#: db/models/fields/related.py:625 +#: db/models/fields/related.py:664 #, python-format msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid." msgid_plural "Please enter valid %(self)s IDs. The values %(value)r are invalid." @@ -1852,7 +2069,7 @@ msgstr[0] "ProsÃme, vložte platná %(self)s ID. Hodnota %(value)r nenà platnà msgstr[1] "ProsÃme, vložte platná %(self)s ID. Hodnoty %(value)r nejsou platné." msgstr[2] "ProsÃme, vložte platná %(self)s ID. Hodnoty %(value)r nejsou platné." -#: forms/__init__.py:380 +#: forms/__init__.py:381 #, python-format msgid "Ensure your text is less than %s character." msgid_plural "Ensure your text is less than %s characters." @@ -1860,59 +2077,34 @@ msgstr[0] "UjistÄ›te se, že Váš text má ménÄ› než %s znak." msgstr[1] "UjistÄ›te se, že Váš text má ménÄ› než %s znaky." msgstr[2] "UjistÄ›te se, že Váš text má ménÄ› než %s znaků." -#: forms/__init__.py:385 +#: forms/__init__.py:386 msgid "Line breaks are not allowed here." msgstr "Zalomenà řádky zde nenjsou povolená." -#: forms/__init__.py:480 -#: forms/__init__.py:551 -#: forms/__init__.py:589 +#: forms/__init__.py:487 +#: forms/__init__.py:560 +#: forms/__init__.py:599 #, python-format msgid "Select a valid choice; '%(data)s' is not in %(choices)s." msgstr "Vyberte platnou volbu. '%(data)s' nenà mezi %(choices)s." -#: forms/__init__.py:645 +#: forms/__init__.py:663 msgid "The submitted file is empty." msgstr "Odevzdaný soubor je prázdný." -#: forms/__init__.py:699 +#: forms/__init__.py:719 msgid "Enter a whole number between -32,768 and 32,767." msgstr "Vložte celé ÄÃslo mezi -32,768 a 32,767." -#: forms/__init__.py:708 +#: forms/__init__.py:729 msgid "Enter a positive number." msgstr "Vložte celé kladné ÄÃslo." -#: forms/__init__.py:717 +#: forms/__init__.py:739 msgid "Enter a whole number between 0 and 32,767." msgstr "Vložte celé ÄÃslo mezi 0 a 32,767." -#: template/defaultfilters.py:379 +#: template/defaultfilters.py:401 msgid "yes,no,maybe" msgstr "ano, ne, možná" -#~ msgid "Comment" -#~ msgstr "Komentář" -#~ msgid "Comments" -#~ msgstr "Komentáře" -#~ msgid "String (up to 50)" -#~ msgstr "Text (max. 50 znaků)" -#~ msgid "label" -#~ msgstr "nadpis" -#~ msgid "package" -#~ msgstr "balÃk" -#~ msgid "packages" -#~ msgstr "balÃky" -#~ msgid "Error in Template" -#~ msgstr "Chyba v Å¡ablonÄ›" -#~ msgid "" -#~ "\n" -#~ "In template %(name)s, error at line %(line)s:\n" -#~ msgstr "" -#~ "\n" -#~ "V Å¡ablonÄ› %(name)s, chyba na řádce %(line)s:\n" - -#, fuzzy -#~ msgid "count" -#~ msgstr "poÄet" - diff --git a/django/conf/locale/da/LC_MESSAGES/django.mo b/django/conf/locale/da/LC_MESSAGES/django.mo Binary files differindex 668f02cbef..9f86e56407 100644 --- a/django/conf/locale/da/LC_MESSAGES/django.mo +++ b/django/conf/locale/da/LC_MESSAGES/django.mo diff --git a/django/conf/locale/da/LC_MESSAGES/django.po b/django/conf/locale/da/LC_MESSAGES/django.po index 9bf20cf833..7688907694 100644 --- a/django/conf/locale/da/LC_MESSAGES/django.po +++ b/django/conf/locale/da/LC_MESSAGES/django.po @@ -1,104 +1,100 @@ -# SOME DESCRIPTIVE TITLE. +# translation of django.po to Dansk +# Rune Rønde Laursen <runerl@skjoldhoej.dk>, 2006. # Copyright (C) 2005 and beyond # This file is distributed under the same license as the PACKAGE package. # Morten Bagai <m@bagai.com>, Nov 2005. -# -# +# Rune Rønde Laursen <runerl@skjoldhoej.dk>, Sept 2006. msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" +"Project-Id-Version: django\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2006-05-16 10:12+0200\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Morten Bagai <m@bagai.com>\n" -"Language-Team: Danish\n" +"PO-Revision-Date: 2006-09-24 10:34+0200\n" +"Last-Translator: Rune Rønde Laursen <runerl@skjoldhoej.dk>\n" +"Language-Team: Dansk <dansk@klid.dk>\n" "MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" +"Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" #: contrib/comments/models.py:67 contrib/comments/models.py:166 -#, fuzzy msgid "object ID" -msgstr "objekt id" +msgstr "objekt ID" #: contrib/comments/models.py:68 msgid "headline" -msgstr "" +msgstr "overskrift" #: contrib/comments/models.py:69 contrib/comments/models.py:90 #: contrib/comments/models.py:167 -#, fuzzy msgid "comment" -msgstr "indhold" +msgstr "kommentar" #: contrib/comments/models.py:70 msgid "rating #1" -msgstr "" +msgstr "rangering # 1" #: contrib/comments/models.py:71 msgid "rating #2" -msgstr "" +msgstr "rangering # 2" #: contrib/comments/models.py:72 msgid "rating #3" -msgstr "" +msgstr "rangering # 3" #: contrib/comments/models.py:73 msgid "rating #4" -msgstr "" +msgstr "rangering # 4" #: contrib/comments/models.py:74 msgid "rating #5" -msgstr "" +msgstr "rangering # 5" #: contrib/comments/models.py:75 msgid "rating #6" -msgstr "" +msgstr "rangering # 6" #: contrib/comments/models.py:76 msgid "rating #7" -msgstr "" +msgstr "rangering # 7" #: contrib/comments/models.py:77 msgid "rating #8" -msgstr "" +msgstr "rangering # 8" #: contrib/comments/models.py:82 msgid "is valid rating" -msgstr "" +msgstr "er gyldig rangering" #: contrib/comments/models.py:83 contrib/comments/models.py:169 msgid "date/time submitted" -msgstr "" +msgstr "dato/tidspunkt oprettet" #: contrib/comments/models.py:84 contrib/comments/models.py:170 msgid "is public" -msgstr "" +msgstr "er offentlig" #: contrib/comments/models.py:85 contrib/admin/views/doc.py:289 -#, fuzzy msgid "IP address" -msgstr "e-mail adresse" +msgstr "IP-adresse" #: contrib/comments/models.py:86 msgid "is removed" -msgstr "" +msgstr "er fjernet" #: contrib/comments/models.py:86 msgid "" "Check this box if the comment is inappropriate. A \"This comment has been " "removed\" message will be displayed instead." -msgstr "" +msgstr "Afkryds denne boks hvis kommentaren er upassende. Beskeden \"Denne kommentar er blevet fjernet\" vil blive vist istedet." #: contrib/comments/models.py:91 -#, fuzzy msgid "comments" -msgstr "indhold" +msgstr "kommentarer" #: contrib/comments/models.py:131 contrib/comments/models.py:207 -#, fuzzy msgid "Content object" -msgstr "indholdstype" +msgstr "Indholdsobjekt" #: contrib/comments/models.py:159 #, python-format @@ -109,52 +105,52 @@ msgid "" "\n" "http://%(domain)s%(url)s" msgstr "" +"Indsendt af %(user)s den %(date)s\n" +"\n" +"%(comment)s\n" +"\n" +"http://%(domain)s%(url)s" #: contrib/comments/models.py:168 -#, fuzzy msgid "person's name" -msgstr "fornavn" +msgstr "personens navn" #: contrib/comments/models.py:171 -#, fuzzy msgid "ip address" -msgstr "e-mail adresse" +msgstr "IP-adresse" #: contrib/comments/models.py:173 msgid "approved by staff" -msgstr "" +msgstr "godkendt af personale" #: contrib/comments/models.py:176 -#, fuzzy msgid "free comment" -msgstr "tillad kommentarer" +msgstr "fri kommentar" #: contrib/comments/models.py:177 -#, fuzzy msgid "free comments" -msgstr "tillad kommentarer" +msgstr "frie kommentarer" #: contrib/comments/models.py:233 msgid "score" -msgstr "" +msgstr "score" #: contrib/comments/models.py:234 -#, fuzzy msgid "score date" -msgstr "udløbsdato" +msgstr "scoringsdato" #: contrib/comments/models.py:237 msgid "karma score" -msgstr "" +msgstr "karma score" #: contrib/comments/models.py:238 msgid "karma scores" -msgstr "" +msgstr "karma score" #: contrib/comments/models.py:242 #, python-format msgid "%(score)d rating by %(user)s" -msgstr "" +msgstr "%(score)d rangering efter %(user)s" #: contrib/comments/models.py:258 #, python-format @@ -163,62 +159,59 @@ msgid "" "\n" "%(text)s" msgstr "" +"Denne kommentar blev markeret af %(user)s:\n" +"\n" +"%(text)s" #: contrib/comments/models.py:265 -#, fuzzy msgid "flag date" -msgstr "flad side" +msgstr "mærkedato" #: contrib/comments/models.py:268 -#, fuzzy msgid "user flag" -msgstr "Bruger" +msgstr "bruger-mærke" #: contrib/comments/models.py:269 -#, fuzzy msgid "user flags" -msgstr "Brugere" +msgstr "bruger-mærker" #: contrib/comments/models.py:273 #, python-format msgid "Flag by %r" -msgstr "" +msgstr "Mærket af %r" #: contrib/comments/models.py:278 -#, fuzzy msgid "deletion date" -msgstr "sessionsdata" +msgstr "sletningsdato" #: contrib/comments/models.py:280 msgid "moderator deletion" -msgstr "" +msgstr "moderator-sletning" #: contrib/comments/models.py:281 msgid "moderator deletions" -msgstr "" +msgstr "moderator-sletninger" #: contrib/comments/models.py:285 #, python-format msgid "Moderator deletion by %r" -msgstr "" +msgstr "Moderator-sletning af %r" #: contrib/comments/views/karma.py:19 msgid "Anonymous users cannot vote" -msgstr "" +msgstr "Anonyme brugere kan ikke stemme" #: contrib/comments/views/karma.py:23 -#, fuzzy msgid "Invalid comment ID" -msgstr "tillad kommentarer" +msgstr "Ugyldigt kommentar-ID" #: contrib/comments/views/karma.py:25 msgid "No voting for yourself" -msgstr "" +msgstr "Du kan ikke selv stemme" #: contrib/comments/views/comments.py:28 -msgid "" -"This rating is required because you've entered at least one other rating." -msgstr "" +msgid "This rating is required because you've entered at least one other rating." +msgstr "Denne rangering er pÃ¥krævet fordi du har indtastet mindst en anden rangering." #: contrib/comments/views/comments.py:112 #, python-format @@ -233,7 +226,13 @@ msgid_plural "" "\n" "%(text)s" msgstr[0] "" +"Denne kommentar blev indsendt af en bruger som har indsendt færre end %(count)s kommentar:\n" +"\n" +"%(text)s" msgstr[1] "" +"Denne kommentar blev indsendt af en bruger som har indsendt færre end %(count)s kommentarer:\n" +"\n" +"%(text)s" #: contrib/comments/views/comments.py:117 #, python-format @@ -242,33 +241,36 @@ msgid "" "\n" "%(text)s" msgstr "" +"Denne kommentar blev indsendt af en overfladisk bruger:\n" +"\n" +"%(text)s" #: contrib/comments/views/comments.py:189 #: contrib/comments/views/comments.py:280 msgid "Only POSTs are allowed" -msgstr "" +msgstr "Kun POST er tilladt" #: contrib/comments/views/comments.py:193 #: contrib/comments/views/comments.py:284 msgid "One or more of the required fields wasn't submitted" -msgstr "" +msgstr "En eller flere af de pÃ¥krævede felter blev ikke indsendt" #: contrib/comments/views/comments.py:197 #: contrib/comments/views/comments.py:286 msgid "Somebody tampered with the comment form (security violation)" -msgstr "" +msgstr "Nogen har misbrugt kommentarformularen (sikkerhedsovertrædelse)" #: contrib/comments/views/comments.py:207 #: contrib/comments/views/comments.py:292 msgid "" "The comment form had an invalid 'target' parameter -- the object ID was " "invalid" -msgstr "" +msgstr "Kommentarformularen havde en ugyldigt 'target'-parameter -- objekt-ID'var ugyldigt" #: contrib/comments/views/comments.py:257 #: contrib/comments/views/comments.py:321 msgid "The comment form didn't provide either 'preview' or 'post'" -msgstr "" +msgstr "Kommentarformularen tilbød ikke hverken 'forhÃ¥ndsvis' eller 'indsend'" #: contrib/comments/templates/comments/form.html:6 #: contrib/comments/templates/comments/form.html:8 @@ -282,9 +284,8 @@ msgid "Password:" msgstr "Adgangskode:" #: contrib/comments/templates/comments/form.html:6 -#, fuzzy msgid "Forgotten your password?" -msgstr "Ændre adgangskode" +msgstr "Har du glemt dit kodeord?" #: contrib/comments/templates/comments/form.html:8 #: contrib/admin/templates/admin/object_history.html:3 @@ -309,38 +310,35 @@ msgstr "Log ud" #: contrib/comments/templates/comments/form.html:12 msgid "Ratings" -msgstr "" +msgstr "Rangeringer" #: contrib/comments/templates/comments/form.html:12 #: contrib/comments/templates/comments/form.html:23 msgid "Required" -msgstr "" +msgstr "PÃ¥krævet" #: contrib/comments/templates/comments/form.html:12 #: contrib/comments/templates/comments/form.html:23 msgid "Optional" -msgstr "" +msgstr "Valgfri" #: contrib/comments/templates/comments/form.html:23 msgid "Post a photo" -msgstr "" +msgstr "Indsend et foto" #: contrib/comments/templates/comments/form.html:27 #: contrib/comments/templates/comments/freeform.html:5 -#, fuzzy msgid "Comment:" -msgstr "tillad kommentarer" +msgstr "Kommentar:" #: contrib/comments/templates/comments/form.html:32 #: contrib/comments/templates/comments/freeform.html:9 -#, fuzzy msgid "Preview comment" -msgstr "tillad kommentarer" +msgstr "ForhÃ¥ndsvis kommentar" #: contrib/comments/templates/comments/freeform.html:4 -#, fuzzy msgid "Your name:" -msgstr "brugernavn" +msgstr "Dit navn:" #: contrib/admin/filterspecs.py:40 #, python-format @@ -348,45 +346,45 @@ msgid "" "<h3>By %s:</h3>\n" "<ul>\n" msgstr "" +"<h3>Af %s:</h3>\n" +"<ul>\n" #: contrib/admin/filterspecs.py:70 contrib/admin/filterspecs.py:88 #: contrib/admin/filterspecs.py:143 msgid "All" -msgstr "" +msgstr "Alle" #: contrib/admin/filterspecs.py:109 msgid "Any date" -msgstr "" +msgstr "NÃ¥r som helst" #: contrib/admin/filterspecs.py:110 -#, fuzzy msgid "Today" -msgstr "Mandag" +msgstr "Idag" #: contrib/admin/filterspecs.py:113 msgid "Past 7 days" -msgstr "" +msgstr "De sidste 7 dage" #: contrib/admin/filterspecs.py:115 msgid "This month" -msgstr "" +msgstr "Denne mÃ¥ned" #: contrib/admin/filterspecs.py:117 msgid "This year" -msgstr "" +msgstr "Dette Ã¥r" #: contrib/admin/filterspecs.py:143 msgid "Yes" -msgstr "" +msgstr "Ja" #: contrib/admin/filterspecs.py:143 -#, fuzzy msgid "No" -msgstr "Nov." +msgstr "Nej" #: contrib/admin/filterspecs.py:150 msgid "Unknown" -msgstr "" +msgstr "Ukendt" #: contrib/admin/models.py:16 msgid "action time" @@ -394,7 +392,7 @@ msgstr "handlingstid" #: contrib/admin/models.py:19 msgid "object id" -msgstr "objekt id" +msgstr "objekt-ID" #: contrib/admin/models.py:20 msgid "object repr" @@ -418,14 +416,14 @@ msgstr "logmeddelelser" #: contrib/admin/templatetags/admin_list.py:228 msgid "All dates" -msgstr "" +msgstr "Alle datoer" #: contrib/admin/views/decorators.py:9 contrib/auth/forms.py:36 #: contrib/auth/forms.py:41 msgid "" "Please enter a correct username and password. Note that both fields are case-" "sensitive." -msgstr "" +msgstr "Indtast venligst et korrekt brugernavn og kodeord. Læg mærke til at begge felter er versalfølsomme." #: contrib/admin/views/decorators.py:23 #: contrib/admin/templates/admin/login.html:25 @@ -436,196 +434,189 @@ msgstr "Log ind" msgid "" "Please log in again, because your session has expired. Don't worry: Your " "submission has been saved." -msgstr "" +msgstr "Log venligst ind igen, da din session er udløbet. Der er ingen grund til bekymring, informationen du indsendte er blevet gemt." #: contrib/admin/views/decorators.py:68 msgid "" "Looks like your browser isn't configured to accept cookies. Please enable " "cookies, reload this page, and try again." -msgstr "" +msgstr "Det ser ud til din browser ikke er indstillet til at acceptere cookier. SlÃ¥ venligst cookier til, genindlæs denne side og prøv igen." #: contrib/admin/views/decorators.py:82 msgid "Usernames cannot contain the '@' character." -msgstr "" +msgstr "Brugernavne kan ikke indeholde tegnet '@'." #: contrib/admin/views/decorators.py:84 #, python-format msgid "Your e-mail address is not your username. Try '%s' instead." -msgstr "" +msgstr "Din e-mail-adresse er ikke dit brugernavn. Prøv '%s' i stedet." #: contrib/admin/views/main.py:226 -#, fuzzy msgid "Site administration" -msgstr "Django administration" +msgstr "Website-administration" #: contrib/admin/views/main.py:260 #, python-format msgid "The %(name)s \"%(obj)s\" was added successfully." -msgstr "" +msgstr "%(name)s \"%(obj)s\" blev tilføjet i databasen." #: contrib/admin/views/main.py:264 contrib/admin/views/main.py:348 msgid "You may edit it again below." -msgstr "" +msgstr "Du kan redigere det igen herunder." #: contrib/admin/views/main.py:272 contrib/admin/views/main.py:357 #, python-format msgid "You may add another %s below." -msgstr "" +msgstr "Du kan tilføje endnu en %s herunder." #: contrib/admin/views/main.py:290 -#, fuzzy, python-format +#, python-format msgid "Add %s" -msgstr "Tilføj" +msgstr "Tilføj %s" #: contrib/admin/views/main.py:336 #, python-format msgid "Added %s." -msgstr "" +msgstr "Tilføjede %s." #: contrib/admin/views/main.py:336 contrib/admin/views/main.py:338 #: contrib/admin/views/main.py:340 msgid "and" -msgstr "" +msgstr "og" #: contrib/admin/views/main.py:338 -#, fuzzy, python-format +#, python-format msgid "Changed %s." -msgstr "Ændre" +msgstr "Ændrede %s." #: contrib/admin/views/main.py:340 #, python-format msgid "Deleted %s." -msgstr "" +msgstr "Slettede %s." #: contrib/admin/views/main.py:343 msgid "No fields changed." -msgstr "" +msgstr "Ingen filer ændret." #: contrib/admin/views/main.py:346 #, python-format msgid "The %(name)s \"%(obj)s\" was changed successfully." -msgstr "" +msgstr "%(name)s \"%(obj)s\" blev ændret." #: contrib/admin/views/main.py:354 #, python-format -msgid "" -"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below." -msgstr "" +msgid "The %(name)s \"%(obj)s\" was added successfully. You may edit it again below." +msgstr "%(name)s \"%(obj)s\" blev tilføjet. Du kan redigere det igen herunder." #: contrib/admin/views/main.py:392 -#, fuzzy, python-format +#, python-format msgid "Change %s" -msgstr "Ændre" +msgstr "Ændr %s" #: contrib/admin/views/main.py:470 #, python-format msgid "One or more %(fieldname)s in %(name)s: %(obj)s" -msgstr "" +msgstr "Et eller flere %(fieldname)s i %(name)s: %(obj)s" #: contrib/admin/views/main.py:475 #, python-format msgid "One or more %(fieldname)s in %(name)s:" -msgstr "" +msgstr "Et eller flere %(fieldname)s i %(name)s:" #: contrib/admin/views/main.py:508 #, python-format msgid "The %(name)s \"%(obj)s\" was deleted successfully." -msgstr "" +msgstr "%(name)s \"%(obj)s\" blev slettet." #: contrib/admin/views/main.py:511 msgid "Are you sure?" -msgstr "" +msgstr "Er du sikker?" #: contrib/admin/views/main.py:533 -#, fuzzy, python-format +#, python-format msgid "Change history: %s" -msgstr "Ændre adgangskode" +msgstr "Ændringshistorik: %s" #: contrib/admin/views/main.py:565 #, python-format msgid "Select %s" -msgstr "" +msgstr "Vælg %s" #: contrib/admin/views/main.py:565 #, python-format msgid "Select %s to change" -msgstr "" +msgstr "Vælg %s for at ændre" #: contrib/admin/views/doc.py:277 contrib/admin/views/doc.py:286 #: contrib/admin/views/doc.py:288 contrib/admin/views/doc.py:294 #: contrib/admin/views/doc.py:295 contrib/admin/views/doc.py:297 msgid "Integer" -msgstr "" +msgstr "Heltal" #: contrib/admin/views/doc.py:278 msgid "Boolean (Either True or False)" -msgstr "" +msgstr "Boolsk (enten \"true\" eller \"false\")" #: contrib/admin/views/doc.py:279 contrib/admin/views/doc.py:296 #, python-format msgid "String (up to %(maxlength)s)" -msgstr "" +msgstr "Tekst (op til %(maxlength)s)" #: contrib/admin/views/doc.py:280 msgid "Comma-separated integers" -msgstr "" +msgstr "Kommaadskilte heltal" #: contrib/admin/views/doc.py:281 -#, fuzzy msgid "Date (without time)" -msgstr "handlingstid" +msgstr "Dato (uden tid)" #: contrib/admin/views/doc.py:282 -#, fuzzy msgid "Date (with time)" -msgstr "Dato/tid" +msgstr "Dato (med tid)" #: contrib/admin/views/doc.py:283 -#, fuzzy msgid "E-mail address" -msgstr "E-mail adresse:" +msgstr "E-mail-adresse" #: contrib/admin/views/doc.py:284 contrib/admin/views/doc.py:287 msgid "File path" -msgstr "" +msgstr "Filsti" #: contrib/admin/views/doc.py:285 -#, fuzzy msgid "Decimal number" -msgstr "December" +msgstr "Decimaltal" #: contrib/admin/views/doc.py:291 msgid "Boolean (Either True, False or None)" -msgstr "" +msgstr "Boolsk (enten \"true\", \"false\", eller \"none\")" #: contrib/admin/views/doc.py:292 msgid "Relation to parent model" -msgstr "" +msgstr "Relation-til-forælder-model" #: contrib/admin/views/doc.py:293 -#, fuzzy msgid "Phone number" -msgstr "Indtast et heltal." +msgstr "Telefonnummer" #: contrib/admin/views/doc.py:298 msgid "Text" -msgstr "" +msgstr "Tekst" #: contrib/admin/views/doc.py:299 msgid "Time" -msgstr "" +msgstr "Tid" #: contrib/admin/views/doc.py:300 contrib/flatpages/models.py:7 msgid "URL" -msgstr "Internetadresse" +msgstr "URL" #: contrib/admin/views/doc.py:301 msgid "U.S. state (two uppercase letters)" -msgstr "" +msgstr "Stat (i USA, to store bogstaver)" #: contrib/admin/views/doc.py:302 msgid "XML text" -msgstr "" +msgstr "XML tekst" #: contrib/admin/templates/admin/object_history.html:3 #: contrib/admin/templates/admin/change_list.html:5 @@ -636,7 +627,7 @@ msgstr "" #: contrib/admin/templates/registration/password_change_form.html:3 #: contrib/admin/templates/admin_doc/bookmarklets.html:3 msgid "Documentation" -msgstr "" +msgstr "Dokumentation" #: contrib/admin/templates/admin/object_history.html:3 #: contrib/admin/templates/admin/change_list.html:5 @@ -704,7 +695,7 @@ msgstr "" #: contrib/admin/templates/admin/base_site.html:4 msgid "Django site admin" -msgstr "Django site administration" +msgstr "Django website-administration" #: contrib/admin/templates/admin/base_site.html:7 msgid "Django administration" @@ -726,9 +717,7 @@ msgstr "Serverfejl <em>(500)</em>" msgid "" "There's been an error. It's been reported to the site administrators via e-" "mail and should be fixed shortly. Thanks for your patience." -msgstr "" -"Der opstod en fejl. Fejlen er rapporteret til site-administratoren via e-" -"mail, og vil blive rettet hurtigst muligt. Tak for din tÃ¥lmodighed." +msgstr "Der opstod en fejl. Fejlen er rapporteret til website-administratoren via e-mail, og vil blive rettet hurtigst muligt. Tak for din tÃ¥lmodighed." #: contrib/admin/templates/admin/404.html:4 #: contrib/admin/templates/admin/404.html:8 @@ -737,12 +726,12 @@ msgstr "Siden blev ikke fundet" #: contrib/admin/templates/admin/404.html:10 msgid "We're sorry, but the requested page could not be found." -msgstr "Vi Beklager, men den ønskede side kunne ikke findes" +msgstr "Vi beklager, men den ønskede side kunne ikke findes" #: contrib/admin/templates/admin/index.html:17 #, python-format msgid "Models available in the %(name)s application." -msgstr "" +msgstr "Modeller til rÃ¥dighed i %(name)s applikationen." #: contrib/admin/templates/admin/index.html:28 #: contrib/admin/templates/admin/change_form.html:15 @@ -751,11 +740,11 @@ msgstr "Tilføj" #: contrib/admin/templates/admin/index.html:34 msgid "Change" -msgstr "Ændre" +msgstr "Ændr" #: contrib/admin/templates/admin/index.html:44 msgid "You don't have permission to edit anything." -msgstr "Du har ikke rettigehed til at foretage ændringer" +msgstr "Du har ikke rettigheder til at foretage ændringer." #: contrib/admin/templates/admin/index.html:52 msgid "Recent Actions" @@ -772,7 +761,7 @@ msgstr "Ingen tilgængelige" #: contrib/admin/templates/admin/change_list.html:11 #, python-format msgid "Add %(name)s" -msgstr "" +msgstr "Tilføj %(name)s" #: contrib/admin/templates/admin/login.html:22 msgid "Have you <a href=\"/password_reset/\">forgotten your password</a>?" @@ -780,12 +769,12 @@ msgstr "Har du <a href=\"/password_reset/\">glemt din adgangskode</a>?" #: contrib/admin/templates/admin/base.html:23 msgid "Welcome," -msgstr "Velkommen" +msgstr "Velkommen," #: contrib/admin/templates/admin/delete_confirmation.html:9 #: contrib/admin/templates/admin/submit_line.html:3 msgid "Delete" -msgstr "" +msgstr "Slet" #: contrib/admin/templates/admin/delete_confirmation.html:14 #, python-format @@ -795,16 +784,14 @@ msgid "" "types of objects:" msgstr "" "Hvis du sletter %(object_name)s '%(object)s' vil du ogsÃ¥ slette relaterede " -"objekter, men du har ikke rettigheder til at slette flg. typer objekter:" +"objekter, men du har ikke rettigheder til at slette følgende objekttyper:" #: contrib/admin/templates/admin/delete_confirmation.html:21 #, python-format msgid "" "Are you sure you want to delete the %(object_name)s \"%(object)s\"? All of " "the following related items will be deleted:" -msgstr "" -"Er du sikker pÃ¥ at du vil slette %(object_name) \"%(object)s\"? Alle de " -"følgende relaterede objekter vil blive slettet:" +msgstr "Er du sikker pÃ¥ du vil slette %(object_name)s \"%(object)s\"? Alle følgende relaterede objekter vil blive slettet:" #: contrib/admin/templates/admin/delete_confirmation.html:26 msgid "Yes, I'm sure" @@ -813,62 +800,61 @@ msgstr "Ja, jeg er sikker" #: contrib/admin/templates/admin/filter.html:2 #, python-format msgid " By %(title)s " -msgstr "" +msgstr " Efter %(title)s " #: contrib/admin/templates/admin/search_form.html:8 msgid "Go" -msgstr "" +msgstr "Kør" #: contrib/admin/templates/admin/change_form.html:21 msgid "View on site" -msgstr "" +msgstr "Se pÃ¥ website" #: contrib/admin/templates/admin/change_form.html:30 msgid "Please correct the error below." msgid_plural "Please correct the errors below." -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Ret venligst fejlen herunder." +msgstr[1] "Ret venligst fejlene herunder." #: contrib/admin/templates/admin/change_form.html:48 msgid "Ordering" -msgstr "" +msgstr "Rækkefølge" #: contrib/admin/templates/admin/change_form.html:51 msgid "Order:" -msgstr "" +msgstr "Rækkefølge:" #: contrib/admin/templates/admin/submit_line.html:4 msgid "Save as new" -msgstr "" +msgstr "Gem som ny" #: contrib/admin/templates/admin/submit_line.html:5 msgid "Save and add another" -msgstr "" +msgstr "Gem og tilføj endnu en" #: contrib/admin/templates/admin/submit_line.html:6 msgid "Save and continue editing" -msgstr "" +msgstr "Gem og fortsæt med at redigere" #: contrib/admin/templates/admin/submit_line.html:7 -#, fuzzy msgid "Save" -msgstr "aktiv" +msgstr "Gem" #: contrib/admin/templates/registration/password_change_done.html:4 #: contrib/admin/templates/registration/password_change_form.html:4 #: contrib/admin/templates/registration/password_change_form.html:6 #: contrib/admin/templates/registration/password_change_form.html:10 msgid "Password change" -msgstr "Ændre passord" +msgstr "Ændr adgangskode" #: contrib/admin/templates/registration/password_change_done.html:6 #: contrib/admin/templates/registration/password_change_done.html:10 msgid "Password change successful" -msgstr "Adgangskoden er ændret" +msgstr "Adgangskoden blev ændret" #: contrib/admin/templates/registration/password_change_done.html:12 msgid "Your password was changed." -msgstr "Din adgangskode er ændret" +msgstr "Din adgangskode blev ændret." #: contrib/admin/templates/registration/password_reset_form.html:4 #: contrib/admin/templates/registration/password_reset_form.html:6 @@ -881,13 +867,11 @@ msgstr "Nulstil adgangskode" msgid "" "Forgotten your password? Enter your e-mail address below, and we'll reset " "your password and e-mail the new one to you." -msgstr "" -"Har din adgangskode? Indtast din email-adresse nedenfor, sÃ¥ sender vi dig en " -"ny kode via e-mail" +msgstr "Har du glemt din adgangskode? Indtast din e-mail-adresse herunder, sÃ¥ sender vi dig en ny adgangskode." #: contrib/admin/templates/registration/password_reset_form.html:16 msgid "E-mail address:" -msgstr "E-mail adresse:" +msgstr "E-mail-adresse:" #: contrib/admin/templates/registration/password_reset_form.html:16 msgid "Reset my password" @@ -895,7 +879,7 @@ msgstr "Nulstil min adgangskode" #: contrib/admin/templates/registration/logged_out.html:8 msgid "Thanks for spending some quality time with the Web site today." -msgstr "Tak for den tid du brugte pÃ¥ sitet idag" +msgstr "Tak for den kvalitetstid du brugte pÃ¥ websitet idag." #: contrib/admin/templates/registration/logged_out.html:10 msgid "Log in again" @@ -910,18 +894,16 @@ msgstr "Adgangskoden blev nulstillet" msgid "" "We've e-mailed a new password to the e-mail address you submitted. You " "should be receiving it shortly." -msgstr "" -"Vi har e-mailet en ny adgangskode til dig. Du skulle modtage den om ganske " -"kort tid." +msgstr "Vi har sendt en ny adgangskode til din e-mail-adresse. Du skulle modtage den om ganske kort tid." #: contrib/admin/templates/registration/password_change_form.html:12 msgid "" "Please enter your old password, for security's sake, and then enter your new " "password twice so we can verify you typed it in correctly." msgstr "" -"Indtast venligst din gamle adgangskode af sikkerhedsgrunde, og indtast sÃ¥ " -"dit nye password to gange, sÃ¥ vi kan være sikre pÃ¥, at det er indtastet " -"korrekt" +"Indtast venligst din gamle adgangskode, for en sikkerheds skyld og indtast sÃ¥ " +"din nye adgangskode to gange, sÃ¥ vi kan være sikre pÃ¥, at den er indtastet " +"korrekt." #: contrib/admin/templates/registration/password_change_form.html:17 msgid "Old password:" @@ -937,17 +919,16 @@ msgstr "Bekræft ny adgangskode:" #: contrib/admin/templates/registration/password_change_form.html:23 msgid "Change my password" -msgstr "Ændre adgangskode" +msgstr "Ændr min adgangskode" #: contrib/admin/templates/registration/password_reset_email.html:2 msgid "You're receiving this e-mail because you requested a password reset" -msgstr "" -"Du modtager denne e-mail, fordi du har bedt om at fÃ¥ nulstillet dit password" +msgstr "Du modtager denne e-mail, fordi du har bedt om at fÃ¥ nulstillet din adgangskode" #: contrib/admin/templates/registration/password_reset_email.html:3 #, python-format msgid "for your user account at %(site_name)s" -msgstr "for din konto hos %(site_name)s" +msgstr "til din brugerkonto ved %(site_name)s" #: contrib/admin/templates/registration/password_reset_email.html:5 #, python-format @@ -956,15 +937,15 @@ msgstr "Din nye adgangskode er: %(new_password)s" #: contrib/admin/templates/registration/password_reset_email.html:7 msgid "Feel free to change this password by going to this page:" -msgstr "Du kan ændre din adgangskode ved at gÃ¥ til denne side" +msgstr "Du kan ændre din adgangskode ved at gÃ¥ til denne side:" #: contrib/admin/templates/registration/password_reset_email.html:11 msgid "Your username, in case you've forgotten:" -msgstr "I det tilfælde, at du har glemt dit brugernavn er det:" +msgstr "I det tilfælde at du har glemt dit brugernavn er det:" #: contrib/admin/templates/registration/password_reset_email.html:13 msgid "Thanks for using our site!" -msgstr "Tak, fordi du brugte vores site!" +msgstr "Tak fordi du brugte vores website!" #: contrib/admin/templates/registration/password_reset_email.html:15 #, python-format @@ -973,11 +954,11 @@ msgstr "Med venlig hilsen %(site_name)s" #: contrib/admin/templates/admin_doc/bookmarklets.html:3 msgid "Bookmarklets" -msgstr "" +msgstr "Bookmarklets" #: contrib/admin/templates/admin_doc/bookmarklets.html:5 msgid "Documentation bookmarklets" -msgstr "" +msgstr "Documentation bookmarklets" #: contrib/admin/templates/admin_doc/bookmarklets.html:9 msgid "" @@ -989,60 +970,64 @@ msgid "" "as \"internal\" (talk to your system administrator if you aren't sure if\n" "your computer is \"internal\").</p>\n" msgstr "" +"\n" +"<p class=\"help\">For at installere bookmarklets, træk linket til din bogmærkelinje\n, eller højreklik pÃ¥ linket og tilføj det til dine bogmærker. Du kan nu\n" +"markere bookmarkletten fra enhver side pÃ¥ websitet. Bid mærke i at nogle af disse \n" +"bookmarkletter kræver at du ser pÃ¥ websitet fra en computer der opfattes \n" +"som \"intern\" (tal med din systemadministrator, hvis du ikke er sikker pÃ¥ om\n" +"din computer er \"intern\").</p>\n" #: contrib/admin/templates/admin_doc/bookmarklets.html:19 msgid "Documentation for this page" -msgstr "" +msgstr "Dokumentation for denne side" #: contrib/admin/templates/admin_doc/bookmarklets.html:20 msgid "" "Jumps you from any page to the documentation for the view that generates " "that page." -msgstr "" +msgstr "Bringer dig fra en hvilken som helst side til dokumentationen for det view der genererer den pÃ¥gældende side." #: contrib/admin/templates/admin_doc/bookmarklets.html:22 -#, fuzzy msgid "Show object ID" -msgstr "objekt id" +msgstr "Vis objekt-ID" #: contrib/admin/templates/admin_doc/bookmarklets.html:23 msgid "" "Shows the content-type and unique ID for pages that represent a single " "object." -msgstr "" +msgstr "Viser indholdstypen og unikt ID for sider der repræsenterer et enkelt objekt." #: contrib/admin/templates/admin_doc/bookmarklets.html:25 msgid "Edit this object (current window)" -msgstr "" +msgstr "Redigér dette objekt (i det aktuelle vindue)" #: contrib/admin/templates/admin_doc/bookmarklets.html:26 msgid "Jumps to the admin page for pages that represent a single object." -msgstr "" +msgstr "Springer til administrationssiden for sider der repræsenterer et enkelt objekt." #: contrib/admin/templates/admin_doc/bookmarklets.html:28 msgid "Edit this object (new window)" -msgstr "" +msgstr "Redigér dette objekt (i nyt vindue)" #: contrib/admin/templates/admin_doc/bookmarklets.html:29 msgid "As above, but opens the admin page in a new window." -msgstr "" +msgstr "Som ovenfor, men Ã¥bner administrationssiden i et nyt vindue." #: contrib/admin/templates/widget/date_time.html:3 msgid "Date:" -msgstr "" +msgstr "Dato:" #: contrib/admin/templates/widget/date_time.html:4 msgid "Time:" -msgstr "" +msgstr "Tid:" #: contrib/admin/templates/widget/file.html:2 msgid "Currently:" -msgstr "" +msgstr "Nuværende:" #: contrib/admin/templates/widget/file.html:3 -#, fuzzy msgid "Change:" -msgstr "Ændre" +msgstr "Ændr:" #: contrib/redirects/models.py:7 msgid "redirect from" @@ -1054,7 +1039,7 @@ msgid "" "events/search/'." msgstr "" "Dette skal være en absolut sti uden domænenavnet. For eksempel: '/nyheder/" -"find/" +"søg/" #: contrib/redirects/models.py:9 msgid "redirect to" @@ -1065,7 +1050,7 @@ msgid "" "This can be either an absolute path (as above) or a full URL starting with " "'http://'." msgstr "" -"Dette kan enten være en absolut sti (som over), eller en komplet URL " +"Dette kan enten være en absolut sti (som ovenfor), eller en komplet URL " "startende med 'http://'" #: contrib/redirects/models.py:12 @@ -1077,11 +1062,8 @@ msgid "redirects" msgstr "omaddresseringer" #: contrib/flatpages/models.py:8 -msgid "" -"Example: '/about/contact/'. Make sure to have leading and trailing slashes." -msgstr "" -"Eksempel: '/om/kontakt/'. Vær sikker pÃ¥ at du har en skrÃ¥streg foran og og " -"bagefter." +msgid "Example: '/about/contact/'. Make sure to have leading and trailing slashes." +msgstr "Eksempel: '/om/kontakt/'. Vær sikker pÃ¥ at du har en skrÃ¥streg foran og bagved." #: contrib/flatpages/models.py:9 msgid "title" @@ -1100,22 +1082,19 @@ msgid "template name" msgstr "skabelonnavn" #: contrib/flatpages/models.py:13 -#, fuzzy msgid "" "Example: 'flatpages/contact_page'. If this isn't provided, the system will " "use 'flatpages/default'." -msgstr "" -"Eksempel: 'fladesider/kontakt_side'. Vist denne ikke denne er gitt, vill " -"'flatfiles/default' bli brukt." +msgstr "Eksempel: 'fladesider/kontakt_side'. Hvis dette ikke tilbydes, bruger systemet 'fladesider/default'." #: contrib/flatpages/models.py:14 msgid "registration required" -msgstr "registrering kreves" +msgstr "registrering pÃ¥krævet" #: contrib/flatpages/models.py:14 msgid "If this is checked, only logged-in users will be able to view the page." msgstr "" -"Hvis denne box er krydset af, vil kun brugere, der er logget ind, kunne se " +"Hvis denne boks er markeret, vil kun brugere der er logget ind, kunne se " "siden." #: contrib/flatpages/models.py:18 @@ -1135,24 +1114,20 @@ msgid "codename" msgstr "kodenavn" #: contrib/auth/models.py:17 -#, fuzzy msgid "permission" -msgstr "Rettighed" +msgstr "rettighed" #: contrib/auth/models.py:18 contrib/auth/models.py:27 -#, fuzzy msgid "permissions" -msgstr "Rettigheder" +msgstr "rettigheder" #: contrib/auth/models.py:29 -#, fuzzy msgid "group" -msgstr "Gruppe" +msgstr "gruppe" #: contrib/auth/models.py:30 contrib/auth/models.py:65 -#, fuzzy msgid "groups" -msgstr "Grupper" +msgstr "grupper" #: contrib/auth/models.py:55 msgid "username" @@ -1168,7 +1143,7 @@ msgstr "efternavn" #: contrib/auth/models.py:58 msgid "e-mail address" -msgstr "e-mail adresse" +msgstr "e-mail-adresse" #: contrib/auth/models.py:59 msgid "password" @@ -1176,7 +1151,7 @@ msgstr "adgangskode" #: contrib/auth/models.py:59 msgid "Use '[algo]$[salt]$[hexdigest]'" -msgstr "" +msgstr "Brug '[algo]$[salt]$[hexdigest]'" #: contrib/auth/models.py:60 msgid "staff status" @@ -1184,7 +1159,7 @@ msgstr "administrationsstatus" #: contrib/auth/models.py:60 msgid "Designates whether the user can log into this admin site." -msgstr "Bestemmer om brugeren kan logge ind pÃ¥ dette administrationssite" +msgstr "Bestemmer om brugeren kan logge ind pÃ¥ dette administrationswebsite." #: contrib/auth/models.py:61 msgid "active" @@ -1192,7 +1167,7 @@ msgstr "aktiv" #: contrib/auth/models.py:62 msgid "superuser status" -msgstr "superbruger" +msgstr "superbrugerstatus" #: contrib/auth/models.py:63 msgid "last login" @@ -1207,23 +1182,20 @@ msgid "" "In addition to the permissions manually assigned, this user will also get " "all permissions granted to each group he/she is in." msgstr "" -"I tillæg til de rettighder, som manuelt er tildelt brugeren, vil denne ogsÃ¥ " -"fÃ¥ alle rettigheder tildelt hver gruppe han/hun er medlem af" +"Udover de rettigheder, der manuelt er tildelt brugeren, vil denne ogsÃ¥ " +"fÃ¥ alle rettigheder der er tildelt hver gruppe, brugeren er medlem af." #: contrib/auth/models.py:67 -#, fuzzy msgid "user permissions" -msgstr "Rettigheder" +msgstr "brugerrettigheder" #: contrib/auth/models.py:70 -#, fuzzy msgid "user" -msgstr "Bruger" +msgstr "bruger" #: contrib/auth/models.py:71 -#, fuzzy msgid "users" -msgstr "Brugere" +msgstr "brugere" #: contrib/auth/models.py:76 msgid "Personal info" @@ -1242,20 +1214,18 @@ msgid "Groups" msgstr "Grupper" #: contrib/auth/models.py:219 -#, fuzzy msgid "message" -msgstr "Meddelelse" +msgstr "meddelelse" #: contrib/auth/forms.py:30 msgid "" "Your Web browser doesn't appear to have cookies enabled. Cookies are " "required for logging in." -msgstr "" +msgstr "Din browser ser ud til ikke at have cookier aktiveret. Cookier er pÃ¥krævet for at kunne logge ind." #: contrib/contenttypes/models.py:25 -#, fuzzy msgid "python model class name" -msgstr "python modulnavn" +msgstr "python model klassenavn" #: contrib/contenttypes/models.py:28 msgid "content type" @@ -1295,11 +1265,11 @@ msgstr "vist navn" #: contrib/sites/models.py:15 msgid "site" -msgstr "side" +msgstr "website" #: contrib/sites/models.py:16 msgid "sites" -msgstr "sider" +msgstr "websites" #: utils/translation.py:360 msgid "DATE_FORMAT" @@ -1391,52 +1361,51 @@ msgstr "December" #: utils/dates.py:19 msgid "jan" -msgstr "" +msgstr "jan" #: utils/dates.py:19 msgid "feb" -msgstr "" +msgstr "feb" #: utils/dates.py:19 msgid "mar" -msgstr "" +msgstr "mar" #: utils/dates.py:19 msgid "apr" -msgstr "" +msgstr "apr" #: utils/dates.py:19 -#, fuzzy msgid "may" -msgstr "Maj" +msgstr "maj" #: utils/dates.py:19 msgid "jun" -msgstr "" +msgstr "jun" #: utils/dates.py:20 msgid "jul" -msgstr "" +msgstr "jul" #: utils/dates.py:20 msgid "aug" -msgstr "" +msgstr "aug" #: utils/dates.py:20 msgid "sep" -msgstr "" +msgstr "sept" #: utils/dates.py:20 msgid "oct" -msgstr "" +msgstr "okt" #: utils/dates.py:20 msgid "nov" -msgstr "" +msgstr "nov" #: utils/dates.py:20 msgid "dec" -msgstr "" +msgstr "dec" #: utils/dates.py:27 msgid "Jan." @@ -1469,44 +1438,42 @@ msgstr "Dec." #: utils/timesince.py:12 msgid "year" msgid_plural "years" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Ã¥r" +msgstr[1] "Ã¥r" #: utils/timesince.py:13 msgid "month" msgid_plural "months" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "mÃ¥ned" +msgstr[1] "mÃ¥neder" #: utils/timesince.py:14 msgid "week" msgid_plural "weeks" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "uge" +msgstr[1] "uger" #: utils/timesince.py:15 -#, fuzzy msgid "day" msgid_plural "days" -msgstr[0] "Maj" -msgstr[1] "Maj" +msgstr[0] "dag" +msgstr[1] "dage" #: utils/timesince.py:16 msgid "hour" msgid_plural "hours" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "time" +msgstr[1] "timer" #: utils/timesince.py:17 -#, fuzzy msgid "minute" msgid_plural "minutes" -msgstr[0] "side" -msgstr[1] "side" +msgstr[0] "minut" +msgstr[1] "minutter" #: conf/global_settings.py:37 msgid "Bengali" -msgstr "" +msgstr "Bengalsk" #: conf/global_settings.py:38 msgid "Czech" @@ -1517,9 +1484,8 @@ msgid "Welsh" msgstr "Walisisk" #: conf/global_settings.py:40 -#, fuzzy msgid "Danish" -msgstr "Spansk" +msgstr "Dansk" #: conf/global_settings.py:41 msgid "German" @@ -1527,7 +1493,7 @@ msgstr "Tysk" #: conf/global_settings.py:42 msgid "Greek" -msgstr "" +msgstr "Græsk" #: conf/global_settings.py:43 msgid "English" @@ -1547,11 +1513,11 @@ msgstr "Galicisk" #: conf/global_settings.py:47 msgid "Hungarian" -msgstr "" +msgstr "Ungarsk" #: conf/global_settings.py:48 msgid "Hebrew" -msgstr "" +msgstr "Hebræisk" #: conf/global_settings.py:49 msgid "Icelandic" @@ -1563,11 +1529,11 @@ msgstr "Italiensk" #: conf/global_settings.py:51 msgid "Japanese" -msgstr "" +msgstr "Japansk" #: conf/global_settings.py:52 msgid "Dutch" -msgstr "" +msgstr "Hollandsk" #: conf/global_settings.py:53 msgid "Norwegian" @@ -1590,9 +1556,8 @@ msgid "Slovak" msgstr "Slovakisk" #: conf/global_settings.py:58 -#, fuzzy msgid "Slovenian" -msgstr "Slovakisk" +msgstr "Slovensk" #: conf/global_settings.py:59 msgid "Serbian" @@ -1603,9 +1568,8 @@ msgid "Swedish" msgstr "Svensk" #: conf/global_settings.py:61 -#, fuzzy msgid "Ukrainian" -msgstr "Brasiliansk" +msgstr "Ukrainsk" #: conf/global_settings.py:62 msgid "Simplified Chinese" @@ -1620,20 +1584,18 @@ msgid "This value must contain only letters, numbers and underscores." msgstr "Dette felt mÃ¥ kun indeholde bogstaver, tal og understreger." #: core/validators.py:64 -#, fuzzy msgid "" "This value must contain only letters, numbers, underscores, dashes or " "slashes." -msgstr "" -"Dette felt mÃ¥ kun indeholde bogstaver, tal, understreger og skrÃ¥streger." +msgstr "Dette felt mÃ¥ kun indeholde bogstaver, tal, understreger, streger eller skrÃ¥streger." #: core/validators.py:72 msgid "Uppercase letters are not allowed here." -msgstr "Store bogstaver er ikke tilladt her" +msgstr "Store bogstaver er ikke tilladt her." #: core/validators.py:76 msgid "Lowercase letters are not allowed here." -msgstr "SmÃ¥ bogstaver er ikke tilladt her" +msgstr "SmÃ¥ bogstaver er ikke tilladt her." #: core/validators.py:83 msgid "Enter only digits separated by commas." @@ -1641,11 +1603,11 @@ msgstr "Indtast kun tal adskilt af kommaer." #: core/validators.py:95 msgid "Enter valid e-mail addresses separated by commas." -msgstr "Indtast gyldige email-adresser adskilt af kommaer" +msgstr "Indtast gyldige e-mail-adresser adskilt af kommaer." #: core/validators.py:99 msgid "Please enter a valid IP address." -msgstr "Venlist indtast en gyldig email-adresse." +msgstr "Indtast venligst en gyldig IP-adresse." #: core/validators.py:103 msgid "Empty values are not allowed here." @@ -1653,11 +1615,11 @@ msgstr "Dette felt kan ikke være tomt." #: core/validators.py:107 msgid "Non-numeric characters aren't allowed here." -msgstr "Der mÃ¥ kun være tal her" +msgstr "Der mÃ¥ kun være tal i dette felt." #: core/validators.py:111 msgid "This value can't be comprised solely of digits." -msgstr "Denne værdi kan ikke kun bestÃ¥ af tal." +msgstr "Denne værdi kan ikke udelukkende bestÃ¥ af tal." #: core/validators.py:116 msgid "Enter a whole number." @@ -1681,26 +1643,25 @@ msgstr "Indtast dato og tid i Ã…Ã…Ã…Ã…-MM-DD TT:MM format." #: core/validators.py:136 msgid "Enter a valid e-mail address." -msgstr "Indtast en gyldig email-adresse." +msgstr "Indtast en gyldig e-mail-adresse." #: core/validators.py:148 msgid "" "Upload a valid image. The file you uploaded was either not an image or a " "corrupted image." msgstr "" -"Upload en billed-fil. Filen du uploadede var enten ikke et billede eller en " -"ødelagt billed-fil" +"Indsend en billedfil. Filen du indsendte var enten ikke et billede eller en " +"ødelagt billedfil." #: core/validators.py:155 #, python-format msgid "The URL %s does not point to a valid image." -msgstr "URLen %s viser ikke til en gyldig billed-fil" +msgstr "URLen %s viser ikke til en gyldig billedfil." #: core/validators.py:159 #, python-format msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid." -msgstr "" -"Telefonnumre skal være i XXX-XXX-XXXX formatet. \"%s\" er ikke godkjent." +msgstr "Telefonnumre skal være i formatet XXXXXXXX. \"%s\" er ikke godkendt." #: core/validators.py:167 #, python-format @@ -1709,7 +1670,7 @@ msgstr "URLen %s viser ikke til en gyldig QuickTime-film." #: core/validators.py:171 msgid "A valid URL is required." -msgstr "En gyldig URL er pÃ¥krævet" +msgstr "En gyldig URL er pÃ¥krævet." #: core/validators.py:185 #, python-format @@ -1733,11 +1694,11 @@ msgstr "Ugyldig URL: %s" #: core/validators.py:206 core/validators.py:208 #, python-format msgid "The URL %s is a broken link." -msgstr "Denne URL %s linker ikke til en gyldig side eller fil" +msgstr "Denne URL %s linker ikke til en gyldig side eller fil." #: core/validators.py:214 msgid "Enter a valid U.S. state abbreviation." -msgstr "Indtast en gyldig amerikansk statsforkortelse" +msgstr "Indtast en gyldig amerikansk statsforkortelse." #: core/validators.py:229 #, python-format @@ -1753,25 +1714,25 @@ msgstr "Dette felt skal matche '%s' feltet." #: core/validators.py:255 msgid "Please enter something for at least one field." -msgstr "Indtast venligst noget i mindst et felt" +msgstr "Indtast venligst noget, i mindst ét felt" #: core/validators.py:264 core/validators.py:275 msgid "Please enter both fields or leave them both empty." -msgstr "Udfyld begge felter, eller lad dem begge være blanke" +msgstr "Udfyld begge felter, eller lad dem begge være tomme." #: core/validators.py:282 #, python-format msgid "This field must be given if %(field)s is %(value)s" -msgstr "Dette felt skal udfyldes, hvis %(field)s er lig %(value)s" +msgstr "Dette felt skal udfyldes, hvis %(field)s er lig %(value)s." #: core/validators.py:294 #, python-format msgid "This field must be given if %(field)s is not %(value)s" -msgstr "Dette felt skal udfyldes, hvis %(field)s ikke er lig %(value)s" +msgstr "Dette felt skal udfyldes, hvis %(field)s ikke er lig %(value)s." #: core/validators.py:313 msgid "Duplicate values are not allowed." -msgstr "Duplikate værdier er ikke tilladt her" +msgstr "Identiske værdier er ikke tilladt her." #: core/validators.py:336 #, python-format @@ -1783,34 +1744,32 @@ msgid "Please enter a valid decimal number." msgstr "Indtast venligst et gyldigt decimaltal." #: core/validators.py:349 -#, fuzzy, python-format +#, python-format msgid "Please enter a valid decimal number with at most %s total digit." -msgid_plural "" -"Please enter a valid decimal number with at most %s total digits." -msgstr[0] "Indtast en gyldig decimal med max %s tal ialt" -msgstr[1] "Indtast en gyldig decimal med max %s tal ialt" +msgid_plural "Please enter a valid decimal number with at most %s total digits." +msgstr[0] "Indtast et gyldigt decimaltal med maksimalt %s ciffer i alt." +msgstr[1] "Indtast et gyldigt decimaltal med maksimalt %s cifre i alt." #: core/validators.py:352 #, python-format msgid "Please enter a valid decimal number with at most %s decimal place." -msgid_plural "" -"Please enter a valid decimal number with at most %s decimal places." -msgstr[0] "Indtast en gyldig decimal med max %s tal efter kommaet" -msgstr[1] "Indtast en gyldig decimal med max %s tal efter kommaet" +msgid_plural "Please enter a valid decimal number with at most %s decimal places." +msgstr[0] "Indtast en gyldig decimal med maksimalt %s tal efter kommaet" +msgstr[1] "Indtast en gyldig decimal med maksimalt %s tal efter kommaet" #: core/validators.py:362 #, python-format msgid "Make sure your uploaded file is at least %s bytes big." -msgstr "Tjek at den uploadede fil er mindst % bytes." +msgstr "Tjek at den indsendte fil er mindst %s bytes." #: core/validators.py:363 #, python-format msgid "Make sure your uploaded file is at most %s bytes big." -msgstr "Tjek at den uploadede file er max %s bytes." +msgstr "Tjek at den indsendte fil er maksimalt %s bytes." #: core/validators.py:376 msgid "The format for this field is wrong." -msgstr "Formatet i dette feltet er feil." +msgstr "Formatet i dette felt er forkert." #: core/validators.py:391 msgid "This field is invalid." @@ -1823,18 +1782,15 @@ msgstr "Kunne ikke finde noget i %s." #: core/validators.py:429 #, python-format -msgid "" -"The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'." -msgstr "" -"URLen %(url)s returnerede ikke en godkendt Content-Type '%(contenttype)s'." +msgid "The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'." +msgstr "URLen %(url)s returnerede ikke en godkendt Content-Type header '%(contenttype)s'." #: core/validators.py:462 #, python-format msgid "" "Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with " "\"%(start)s\".)" -msgstr "" -"Luk venligst %(tag)s pÃ¥ linje %(line)s. (Linjen starer med \"%(start)s\".)" +msgstr "Luk venligst %(tag)s pÃ¥ linje %(line)s. (Linjen starter med \"%(start)s\".)" #: core/validators.py:466 #, python-format @@ -1860,8 +1816,8 @@ msgid "" "\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%" "(start)s\".)" msgstr "" -"\"<%(tag)s>\" pÃ¥ linje %(line)s er ikke et gyldigt tag. (Linjen starter med " -"\"%(start)s\".)" +"\"<%(tag)s>\" pÃ¥ linje %(line)s er et ugyldigt tag. (Linjen starter med \"%" +"(start)s\".)" #: core/validators.py:480 #, python-format @@ -1869,7 +1825,7 @@ msgid "" "A tag on line %(line)s is missing one or more required attributes. (Line " "starts with \"%(start)s\".)" msgstr "" -"Et tag pÃ¥ linje %(line)s mangler en obligatorisk attribut. (Linjen starter " +"Et tag pÃ¥ linje %(line)s mangler en pÃ¥krævet attribut. (Linjen starter " "med \"%(start)s\".)" #: core/validators.py:485 @@ -1878,120 +1834,94 @@ msgid "" "The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line " "starts with \"%(start)s\".)" msgstr "" -"\"%(attr)s\" attributten pÃ¥ linje $(line)s har en ugyldig værdi. (Linjen " +"\"%(attr)s\" attributten pÃ¥ linje %(line)s har en ugyldig værdi. (Linjen " "starter med \"%(start)s\".)" #: db/models/manipulators.py:302 #, python-format msgid "%(object)s with this %(type)s already exists for the given %(field)s." -msgstr "" +msgstr "%(object)s med denne %(type)s eksisterer allerede for den givne %(field)s." #: db/models/fields/__init__.py:40 #, python-format msgid "%(optname)s with this %(fieldname)s already exists." -msgstr "" +msgstr "%(optname)s med dette %(fieldname)s eksisterer allerede." #: db/models/fields/__init__.py:114 db/models/fields/__init__.py:265 #: db/models/fields/__init__.py:542 db/models/fields/__init__.py:553 #: forms/__init__.py:346 -#, fuzzy msgid "This field is required." -msgstr "Dette felt er ugyldigt." +msgstr "Dette felt er pÃ¥krævet." #: db/models/fields/__init__.py:337 -#, fuzzy msgid "This value must be an integer." -msgstr "Denne værdi skal være en potens af %s." +msgstr "Denne værdi skal et heltal." #: db/models/fields/__init__.py:369 -#, fuzzy msgid "This value must be either True or False." -msgstr "Denne værdi skal være en potens af %s." +msgstr "Denne værdi skal være enten true eller false." #: db/models/fields/__init__.py:385 -#, fuzzy msgid "This field cannot be null." -msgstr "Dette felt er ugyldigt." +msgstr "Dette felt kan ikke være null." #: db/models/fields/__init__.py:562 -#, fuzzy msgid "Enter a valid filename." -msgstr "Indtast en gyldig email-adresse." +msgstr "Indtast et gyldigt filnavn." #: db/models/fields/related.py:43 -#, fuzzy, python-format +#, python-format msgid "Please enter a valid %s." -msgstr "Venlist indtast en gyldig email-adresse." +msgstr "Indtast venligst en gyldig %s." #: db/models/fields/related.py:579 -#, fuzzy msgid "Separate multiple IDs with commas." -msgstr "Adskil id'er med kommaer." +msgstr "Adskil flere ID'er med kommaer." #: db/models/fields/related.py:581 -#, fuzzy -msgid "" -"Hold down \"Control\", or \"Command\" on a Mac, to select more than one." -msgstr "" -"Hold \"Kontrol\", eller \"Æbletasten\" pÃ¥ Mac, nede for at vælge mere end en." +msgid "Hold down \"Control\", or \"Command\" on a Mac, to select more than one." +msgstr "Hold \"Kontrol\", eller \"Æbletasten\" pÃ¥ Mac nede, for at vælge mere end en." #: db/models/fields/related.py:625 #, python-format msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid." -msgid_plural "" -"Please enter valid %(self)s IDs. The values %(value)r are invalid." -msgstr[0] "" -msgstr[1] "" +msgid_plural "Please enter valid %(self)s IDs. The values %(value)r are invalid." +msgstr[0] "Indtast venligst et gyldigt %(self)s-ID. Værdien %(value)r er ugyldig." +msgstr[1] "Indtast venligst gyldige %(self)s-ID'er. Værdierne %(value)r er ugyldige." #: forms/__init__.py:380 #, python-format msgid "Ensure your text is less than %s character." msgid_plural "Ensure your text is less than %s characters." -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Sørg for din tekst er kortere end %s tegn." +msgstr[1] "Sørg for din tekst er kortere end %s tegn." #: forms/__init__.py:385 -#, fuzzy msgid "Line breaks are not allowed here." -msgstr "SmÃ¥ bogstaver er ikke tilladt her" +msgstr "Linjebrud er ikke tilladt her." #: forms/__init__.py:480 forms/__init__.py:551 forms/__init__.py:589 #, python-format msgid "Select a valid choice; '%(data)s' is not in %(choices)s." -msgstr "" +msgstr "Markér et gyldigt valg; '%(data)s' er ikke i %(choices)s." #: forms/__init__.py:645 msgid "The submitted file is empty." -msgstr "" +msgstr "Den indsendte fil er tom." #: forms/__init__.py:699 -#, fuzzy msgid "Enter a whole number between -32,768 and 32,767." -msgstr "Indtast et heltal." +msgstr "Indtast et heltal mellem -32,768 og 32,767." #: forms/__init__.py:708 -#, fuzzy msgid "Enter a positive number." -msgstr "Indtast et heltal." +msgstr "Indtast et positivt tal." #: forms/__init__.py:717 -#, fuzzy msgid "Enter a whole number between 0 and 32,767." -msgstr "Indtast et heltal." +msgstr "Indtast et heltal mellem 0 og 32,767." #: template/defaultfilters.py:379 msgid "yes,no,maybe" -msgstr "" - -#, fuzzy -#~ msgid "Comments" -#~ msgstr "tillad kommentarer" - -#~ msgid "label" -#~ msgstr "mærkat" - -#~ msgid "package" -#~ msgstr "pakke" +msgstr "ja,nej,mÃ¥ske" -#~ msgid "packages" -#~ msgstr "pakker" diff --git a/django/conf/locale/de/LC_MESSAGES/django.mo b/django/conf/locale/de/LC_MESSAGES/django.mo Binary files differindex a4f4af172e..aef68099d3 100644 --- a/django/conf/locale/de/LC_MESSAGES/django.mo +++ b/django/conf/locale/de/LC_MESSAGES/django.mo diff --git a/django/conf/locale/de/LC_MESSAGES/django.po b/django/conf/locale/de/LC_MESSAGES/django.po index 99212a4f53..614ea69247 100644 --- a/django/conf/locale/de/LC_MESSAGES/django.po +++ b/django/conf/locale/de/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Django 1.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2006-05-16 10:11+0200\n" +"POT-Creation-Date: 2006-09-25 16:04+0200\n" "PO-Revision-Date: 2005-10-08 00:03+0200\n" "Last-Translator: Georg Bauer <gb@bofh.ms>\n" "MIME-Version: 1.0\n" @@ -71,7 +71,7 @@ msgstr "Datum/Zeit Erstellung" msgid "is public" msgstr "ist öffentlich" -#: contrib/comments/models.py:85 contrib/admin/views/doc.py:289 +#: contrib/comments/models.py:85 contrib/admin/views/doc.py:304 msgid "IP address" msgstr "IP-Adresse" @@ -208,14 +208,14 @@ msgstr "Ungültige Kommentar-ID" msgid "No voting for yourself" msgstr "Keine Abstimmung bei Dir selber" -#: contrib/comments/views/comments.py:28 +#: contrib/comments/views/comments.py:27 msgid "" "This rating is required because you've entered at least one other rating." msgstr "" "Die Abstimmung ist zwangsweise, weil Du an mindestens einer anderen " "Abstimmung teilnimmst." -#: contrib/comments/views/comments.py:112 +#: contrib/comments/views/comments.py:111 #, python-format msgid "" "This comment was posted by a user who has posted fewer than %(count)s " @@ -238,7 +238,7 @@ msgstr[1] "" "\n" "%(text)s" -#: contrib/comments/views/comments.py:117 +#: contrib/comments/views/comments.py:116 #, python-format msgid "" "This comment was posted by a sketchy user:\n" @@ -249,23 +249,23 @@ msgstr "" "\n" "%(text)s" -#: contrib/comments/views/comments.py:189 +#: contrib/comments/views/comments.py:188 #: contrib/comments/views/comments.py:280 msgid "Only POSTs are allowed" msgstr "Nur POST ist erlaubt" -#: contrib/comments/views/comments.py:193 +#: contrib/comments/views/comments.py:192 #: contrib/comments/views/comments.py:284 msgid "One or more of the required fields wasn't submitted" msgstr "Eines oder mehrere der erforderlichen Felder fehlt" -#: contrib/comments/views/comments.py:197 +#: contrib/comments/views/comments.py:196 #: contrib/comments/views/comments.py:286 msgid "Somebody tampered with the comment form (security violation)" msgstr "" "Jemand hat mit dem Kommentarformular herumgespielt (Sicherheitsverletzung)" -#: contrib/comments/views/comments.py:207 +#: contrib/comments/views/comments.py:206 #: contrib/comments/views/comments.py:292 msgid "" "The comment form had an invalid 'target' parameter -- the object ID was " @@ -287,18 +287,9 @@ msgid "Username:" msgstr "Benutzername:" #: contrib/comments/templates/comments/form.html:6 -#: contrib/admin/templates/admin/login.html:20 -msgid "Password:" -msgstr "Passwort:" - -#: contrib/comments/templates/comments/form.html:6 -msgid "Forgotten your password?" -msgstr "Kennwort vergessen?" - -#: contrib/comments/templates/comments/form.html:8 #: contrib/admin/templates/admin/object_history.html:3 #: contrib/admin/templates/admin/change_list.html:5 -#: contrib/admin/templates/admin/base.html:23 +#: contrib/admin/templates/admin/base.html:25 #: contrib/admin/templates/admin/delete_confirmation.html:3 #: contrib/admin/templates/admin/change_form.html:10 #: contrib/admin/templates/registration/password_change_done.html:3 @@ -316,6 +307,15 @@ msgstr "Kennwort vergessen?" msgid "Log out" msgstr "Abmelden" +#: contrib/comments/templates/comments/form.html:8 +#: contrib/admin/templates/admin/login.html:20 +msgid "Password:" +msgstr "Passwort:" + +#: contrib/comments/templates/comments/form.html:8 +msgid "Forgotten your password?" +msgstr "Kennwort vergessen?" + #: contrib/comments/templates/comments/form.html:12 msgid "Ratings" msgstr "Bewertungen" @@ -334,13 +334,13 @@ msgstr "Optional" msgid "Post a photo" msgstr "Ein Bild veröffentlichen" -#: contrib/comments/templates/comments/form.html:27 +#: contrib/comments/templates/comments/form.html:28 #: contrib/comments/templates/comments/freeform.html:5 msgid "Comment:" msgstr "Kommentar:" -#: contrib/comments/templates/comments/form.html:32 -#: contrib/comments/templates/comments/freeform.html:9 +#: contrib/comments/templates/comments/form.html:35 +#: contrib/comments/templates/comments/freeform.html:10 msgid "Preview comment" msgstr "Kommentarvorschau" @@ -358,7 +358,7 @@ msgstr "" "<ul>\n" #: contrib/admin/filterspecs.py:70 contrib/admin/filterspecs.py:88 -#: contrib/admin/filterspecs.py:143 +#: contrib/admin/filterspecs.py:143 contrib/admin/filterspecs.py:169 msgid "All" msgstr "Alle" @@ -422,12 +422,11 @@ msgstr "Logeintrag" msgid "log entries" msgstr "Logeinträge" -#: contrib/admin/templatetags/admin_list.py:228 +#: contrib/admin/templatetags/admin_list.py:230 msgid "All dates" msgstr "Alle Tage" -#: contrib/admin/views/decorators.py:9 contrib/auth/forms.py:36 -#: contrib/auth/forms.py:41 +#: contrib/admin/views/decorators.py:10 contrib/auth/forms.py:59 msgid "" "Please enter a correct username and password. Note that both fields are case-" "sensitive." @@ -435,12 +434,12 @@ msgstr "" "Bitte einen Benutzernamen und ein Kennwort eingeben. Beide Felder " "berücksichtigen die Groß-/Kleinschreibung." -#: contrib/admin/views/decorators.py:23 +#: contrib/admin/views/decorators.py:24 #: contrib/admin/templates/admin/login.html:25 msgid "Log in" msgstr "Anmelden" -#: contrib/admin/views/decorators.py:61 +#: contrib/admin/views/decorators.py:62 msgid "" "Please log in again, because your session has expired. Don't worry: Your " "submission has been saved." @@ -448,7 +447,7 @@ msgstr "" "Bitte neu anmelden, da die Session ausgelaufen ist. Keine Angst: die " "Beiträge wurden gesichert." -#: contrib/admin/views/decorators.py:68 +#: contrib/admin/views/decorators.py:69 msgid "" "Looks like your browser isn't configured to accept cookies. Please enable " "cookies, reload this page, and try again." @@ -456,70 +455,71 @@ msgstr "" "Es sieht danach aus, das der Browser keine Cookies akzeptiert. Bitte im " "Browser Cookies aktivieren und diese Seite neu laden." -#: contrib/admin/views/decorators.py:82 +#: contrib/admin/views/decorators.py:83 msgid "Usernames cannot contain the '@' character." msgstr "Benutzernamen können das Zeichen '@' nicht enthalten." -#: contrib/admin/views/decorators.py:84 +#: contrib/admin/views/decorators.py:85 #, python-format msgid "Your e-mail address is not your username. Try '%s' instead." msgstr "" "Die eMail-Adresse ist nicht der Benutzername. Bitte '%s' stattdessen " "versuchen." -#: contrib/admin/views/main.py:226 +#: contrib/admin/views/main.py:223 msgid "Site administration" msgstr "Website Verwaltung" -#: contrib/admin/views/main.py:260 +#: contrib/admin/views/main.py:257 contrib/admin/views/auth.py:17 #, python-format msgid "The %(name)s \"%(obj)s\" was added successfully." msgstr "%(name)s \"%(obj)s\" wurde erfolgreich hinzugefügt." -#: contrib/admin/views/main.py:264 contrib/admin/views/main.py:348 +#: contrib/admin/views/main.py:261 contrib/admin/views/main.py:347 +#: contrib/admin/views/auth.py:22 msgid "You may edit it again below." msgstr "Das Element kann jetzt weiter geändert werden." -#: contrib/admin/views/main.py:272 contrib/admin/views/main.py:357 +#: contrib/admin/views/main.py:271 contrib/admin/views/main.py:356 #, python-format msgid "You may add another %s below." msgstr "Jetzt kann ein weiteres Element vom Typ %s angelegt werden." -#: contrib/admin/views/main.py:290 +#: contrib/admin/views/main.py:289 #, python-format msgid "Add %s" msgstr "%s zufügen" -#: contrib/admin/views/main.py:336 +#: contrib/admin/views/main.py:335 #, python-format msgid "Added %s." msgstr "%s hinzugefügt." -#: contrib/admin/views/main.py:336 contrib/admin/views/main.py:338 -#: contrib/admin/views/main.py:340 +#: contrib/admin/views/main.py:335 contrib/admin/views/main.py:337 +#: contrib/admin/views/main.py:339 msgid "and" msgstr "und" -#: contrib/admin/views/main.py:338 +#: contrib/admin/views/main.py:337 #, python-format msgid "Changed %s." msgstr "%s geändert" -#: contrib/admin/views/main.py:340 +#: contrib/admin/views/main.py:339 #, python-format msgid "Deleted %s." msgstr "%s gelöscht." -#: contrib/admin/views/main.py:343 +#: contrib/admin/views/main.py:342 msgid "No fields changed." msgstr "Keine Felder geändert." -#: contrib/admin/views/main.py:346 +#: contrib/admin/views/main.py:345 #, python-format msgid "The %(name)s \"%(obj)s\" was changed successfully." msgstr "%(name)s \"%(obj)s\" wurde erfolgreich geändert." -#: contrib/admin/views/main.py:354 +#: contrib/admin/views/main.py:353 #, python-format msgid "" "The %(name)s \"%(obj)s\" was added successfully. You may edit it again below." @@ -527,119 +527,188 @@ msgstr "" "%(name)s \"%(obj)s\" wurde erfolgreich zugefügt. Das Element kann jetzt " "geändert werden." -#: contrib/admin/views/main.py:392 +#: contrib/admin/views/main.py:391 #, python-format msgid "Change %s" msgstr "%s ändern" -#: contrib/admin/views/main.py:470 +#: contrib/admin/views/main.py:473 #, python-format msgid "One or more %(fieldname)s in %(name)s: %(obj)s" msgstr "Ein oder mehrere %(fieldname)s in %(name)s: %(obj)s" -#: contrib/admin/views/main.py:475 +#: contrib/admin/views/main.py:478 #, python-format msgid "One or more %(fieldname)s in %(name)s:" msgstr "Ein oder mehrere %(fieldname)s in %(name)s:" -#: contrib/admin/views/main.py:508 +#: contrib/admin/views/main.py:511 #, python-format msgid "The %(name)s \"%(obj)s\" was deleted successfully." msgstr "%(name)s \"%(obj)s\" wurde erfolgreich gelöscht." -#: contrib/admin/views/main.py:511 +#: contrib/admin/views/main.py:514 msgid "Are you sure?" msgstr "Sicher? Ganz sicher?" -#: contrib/admin/views/main.py:533 +#: contrib/admin/views/main.py:536 #, python-format msgid "Change history: %s" msgstr "Änderungsgeschichte: %s" -#: contrib/admin/views/main.py:565 +#: contrib/admin/views/main.py:570 #, python-format msgid "Select %s" msgstr "%s auswählen" -#: contrib/admin/views/main.py:565 +#: contrib/admin/views/main.py:570 #, python-format msgid "Select %s to change" msgstr "%s zur Änderung auswählen" -#: contrib/admin/views/doc.py:277 contrib/admin/views/doc.py:286 -#: contrib/admin/views/doc.py:288 contrib/admin/views/doc.py:294 -#: contrib/admin/views/doc.py:295 contrib/admin/views/doc.py:297 +#: contrib/admin/views/main.py:758 +msgid "Database error" +msgstr "Datenbankfehler" + +#: contrib/admin/views/doc.py:46 contrib/admin/views/doc.py:48 +#: contrib/admin/views/doc.py:50 +msgid "tag:" +msgstr "Schlagwort:" + +#: contrib/admin/views/doc.py:77 contrib/admin/views/doc.py:79 +#: contrib/admin/views/doc.py:81 +msgid "filter:" +msgstr "Filter:" + +#: contrib/admin/views/doc.py:135 contrib/admin/views/doc.py:137 +#: contrib/admin/views/doc.py:139 +msgid "view:" +msgstr "Ansicht:" + +#: contrib/admin/views/doc.py:164 +#, python-format +msgid "App %r not found" +msgstr "Anwendung %r nicht gefunden" + +#: contrib/admin/views/doc.py:171 +#, python-format +msgid "Model %r not found in app %r" +msgstr "Modell %r wurde nicht in Anwendung %r gefunden" + +#: contrib/admin/views/doc.py:183 +#, python-format +msgid "the related `%s.%s` object" +msgstr "Das verknüpfte `%s.%s` Objekt" + +#: contrib/admin/views/doc.py:183 contrib/admin/views/doc.py:205 +#: contrib/admin/views/doc.py:219 contrib/admin/views/doc.py:224 +msgid "model:" +msgstr "Modell:" + +#: contrib/admin/views/doc.py:214 +#, python-format +msgid "related `%s.%s` objects" +msgstr "verknüpftes `%s.%s` Objekt" + +#: contrib/admin/views/doc.py:219 +#, python-format +msgid "all %s" +msgstr "Alle %s" + +#: contrib/admin/views/doc.py:224 +#, python-format +msgid "number of %s" +msgstr "Anzahl von %s" + +#: contrib/admin/views/doc.py:229 +#, python-format +msgid "Fields on %s objects" +msgstr "Felder am %s Objekt" + +#: contrib/admin/views/doc.py:291 contrib/admin/views/doc.py:301 +#: contrib/admin/views/doc.py:303 contrib/admin/views/doc.py:309 +#: contrib/admin/views/doc.py:310 contrib/admin/views/doc.py:312 msgid "Integer" msgstr "Ganzzahl" -#: contrib/admin/views/doc.py:278 +#: contrib/admin/views/doc.py:292 msgid "Boolean (Either True or False)" msgstr "Wahrheitswert (Wahr oder Falsch)" -#: contrib/admin/views/doc.py:279 contrib/admin/views/doc.py:296 +#: contrib/admin/views/doc.py:293 contrib/admin/views/doc.py:311 #, python-format msgid "String (up to %(maxlength)s)" msgstr "Zeichenkette (bis zu %(maxlength)s Zeichen)" -#: contrib/admin/views/doc.py:280 +#: contrib/admin/views/doc.py:294 msgid "Comma-separated integers" msgstr "Kommaseparierte Liste von Zahlen" -#: contrib/admin/views/doc.py:281 +#: contrib/admin/views/doc.py:295 msgid "Date (without time)" msgstr "Datum (ohne Zeit)" -#: contrib/admin/views/doc.py:282 +#: contrib/admin/views/doc.py:296 msgid "Date (with time)" msgstr "Datum (mit Zeit)" -#: contrib/admin/views/doc.py:283 +#: contrib/admin/views/doc.py:297 msgid "E-mail address" msgstr "E-mail-Adresse" -#: contrib/admin/views/doc.py:284 contrib/admin/views/doc.py:287 +#: contrib/admin/views/doc.py:298 contrib/admin/views/doc.py:299 +#: contrib/admin/views/doc.py:302 msgid "File path" msgstr "Dateipfad" -#: contrib/admin/views/doc.py:285 +#: contrib/admin/views/doc.py:300 msgid "Decimal number" msgstr "Dezimalzahl" -#: contrib/admin/views/doc.py:291 +#: contrib/admin/views/doc.py:306 msgid "Boolean (Either True, False or None)" msgstr "Wahrheitswert (Wahr, Falsch oder Nichts)" -#: contrib/admin/views/doc.py:292 +#: contrib/admin/views/doc.py:307 msgid "Relation to parent model" msgstr "Beziehung zum Übermodell" -#: contrib/admin/views/doc.py:293 +#: contrib/admin/views/doc.py:308 msgid "Phone number" msgstr "Telefonnummer" -#: contrib/admin/views/doc.py:298 +#: contrib/admin/views/doc.py:313 msgid "Text" msgstr "Text" -#: contrib/admin/views/doc.py:299 +#: contrib/admin/views/doc.py:314 msgid "Time" msgstr "Zeit" -#: contrib/admin/views/doc.py:300 contrib/flatpages/models.py:7 +#: contrib/admin/views/doc.py:315 contrib/flatpages/models.py:7 msgid "URL" msgstr "URL" -#: contrib/admin/views/doc.py:301 +#: contrib/admin/views/doc.py:316 msgid "U.S. state (two uppercase letters)" msgstr "U.S. Bundesstaat (zwei Grossbuchstaben)" -#: contrib/admin/views/doc.py:302 +#: contrib/admin/views/doc.py:317 msgid "XML text" msgstr "XML Text" +#: contrib/admin/views/doc.py:343 +#, python-format +msgid "%s does not appear to be a urlpattern object" +msgstr "%s ist scheinbar kein urlpattern Objekt" + +#: contrib/admin/views/auth.py:28 +msgid "Add user" +msgstr "Benutzer zufügen" + #: contrib/admin/templates/admin/object_history.html:3 #: contrib/admin/templates/admin/change_list.html:5 -#: contrib/admin/templates/admin/base.html:23 +#: contrib/admin/templates/admin/base.html:25 #: contrib/admin/templates/admin/delete_confirmation.html:3 #: contrib/admin/templates/admin/change_form.html:10 #: contrib/admin/templates/registration/password_change_done.html:3 @@ -650,7 +719,7 @@ msgstr "Dokumentation" #: contrib/admin/templates/admin/object_history.html:3 #: contrib/admin/templates/admin/change_list.html:5 -#: contrib/admin/templates/admin/base.html:23 +#: contrib/admin/templates/admin/base.html:25 #: contrib/admin/templates/admin/delete_confirmation.html:3 #: contrib/admin/templates/admin/change_form.html:10 #: contrib/admin/templates/registration/password_change_done.html:3 @@ -671,9 +740,10 @@ msgstr "Passwort ändern" #: contrib/admin/templates/admin/object_history.html:5 #: contrib/admin/templates/admin/500.html:4 #: contrib/admin/templates/admin/change_list.html:6 -#: contrib/admin/templates/admin/base.html:28 +#: contrib/admin/templates/admin/base.html:30 #: contrib/admin/templates/admin/delete_confirmation.html:6 #: contrib/admin/templates/admin/change_form.html:13 +#: contrib/admin/templates/admin/invalid_setup.html:4 #: contrib/admin/templates/registration/password_change_done.html:4 #: contrib/admin/templates/registration/password_reset_form.html:4 #: contrib/admin/templates/registration/logged_out.html:4 @@ -754,7 +824,12 @@ msgstr "" #: contrib/admin/templates/admin/index.html:17 #, python-format msgid "Models available in the %(name)s application." -msgstr "" +msgstr "Modelle, die in der Anwendung %(name)s vorhanden sind." + +#: contrib/admin/templates/admin/index.html:18 +#, python-format +msgid "%(name)s" +msgstr "%(name)s" #: contrib/admin/templates/admin/index.html:28 #: contrib/admin/templates/admin/change_form.html:15 @@ -790,7 +865,7 @@ msgstr "%(name)s zufügen" msgid "Have you <a href=\"/password_reset/\">forgotten your password</a>?" msgstr "Haben Sie <a href=\"/password_reset/\">ihr Passwort vergessen</a>?" -#: contrib/admin/templates/admin/base.html:23 +#: contrib/admin/templates/admin/base.html:25 msgid "Welcome," msgstr "Willkommen," @@ -802,22 +877,22 @@ msgstr "Löschen" #: contrib/admin/templates/admin/delete_confirmation.html:14 #, python-format msgid "" -"Deleting the %(object_name)s '%(object)s' would result in deleting related " -"objects, but your account doesn't have permission to delete the following " -"types of objects:" +"Deleting the %(object_name)s '%(escaped_object)s' would result in deleting " +"related objects, but your account doesn't have permission to delete the " +"following types of objects:" msgstr "" -"Die Löschung des %(object_name)s '%(object)s' hätte die Löschung von " +"Die Löschung des %(object_name)s '%(escaped_object)s' hätte die Löschung von " "abhängigen Daten zur Folge, aber Sie haben nicht die nötigen Rechte um die " "folgenden abhängigen Daten zu löschen:" #: contrib/admin/templates/admin/delete_confirmation.html:21 #, python-format msgid "" -"Are you sure you want to delete the %(object_name)s \"%(object)s\"? All of " -"the following related items will be deleted:" +"Are you sure you want to delete the %(object_name)s \"%(escaped_object)s\"? " +"All of the following related items will be deleted:" msgstr "" -"Sind Sie sicher, das Sie %(object_name)s \"%(object)s\" löschen wollen? Es " -"werden zusätzlich die folgenden abhängigen Daten mit gelöscht:" +"Sind Sie sicher, das Sie %(object_name)s \"%(escaped_object)s\" löschen " +"wollen? Es werden zusätzlich die folgenden abhängigen Daten mit gelöscht:" #: contrib/admin/templates/admin/delete_confirmation.html:26 msgid "Yes, I'm sure" @@ -825,13 +900,33 @@ msgstr "Ja, ich bin sicher" #: contrib/admin/templates/admin/filter.html:2 #, python-format -msgid " By %(title)s " -msgstr " Nach %(title)s " +msgid " By %(filter_title)s " +msgstr " Nach %(filter_title)s " #: contrib/admin/templates/admin/search_form.html:8 msgid "Go" msgstr "Los" +#: contrib/admin/templates/admin/search_form.html:10 +#, python-format +msgid "1 result" +msgid_plural "%(counter)s results" +msgstr[0] "" +msgstr[1] "" + +#: contrib/admin/templates/admin/search_form.html:10 +#, python-format +msgid "%(full_result_count)s total" +msgstr "%(full_result_count)s gesamt" + +#: contrib/admin/templates/admin/pagination.html:10 +msgid "Show all" +msgstr "Zeige alle" + +#: contrib/admin/templates/admin/filters.html:4 +msgid "Filter" +msgstr "Filter" + #: contrib/admin/templates/admin/change_form.html:21 msgid "View on site" msgstr "Im Web Anzeigen" @@ -866,6 +961,40 @@ msgstr "Sichern und weiter bearbeiten" msgid "Save" msgstr "Sichern" +#: contrib/admin/templates/admin/invalid_setup.html:8 +msgid "" +"Something's wrong with your database installation. Make sure the appropriate " +"database tables have been created, and make sure the database is readable by " +"the appropriate user." +msgstr "" +"Irgendetwas ist falsch mit der Datenbankkonfiguration. Bitte sicherstellen, " +"das die richtigen Datenbanktabellen angelegt wurden und bitte sicherstellen, " +"das die Datenbank vom verwendeten Datenbankbenutzer auch lesbar ist." + +#: contrib/admin/templates/admin/auth/user/add_form.html:6 +msgid "" +"First, enter a username and password. Then, you'll be able to edit more user " +"options." +msgstr "" +"Zuerst einen Benutzer und ein Passwort eingeben. Danach können weitere " +"Optionen für den Benutzer geändert werden." + +#: contrib/admin/templates/admin/auth/user/add_form.html:12 +msgid "Username" +msgstr "Benutzername" + +#: contrib/admin/templates/admin/auth/user/add_form.html:18 +msgid "Password" +msgstr "Passwort" + +#: contrib/admin/templates/admin/auth/user/add_form.html:23 +msgid "Password (again)" +msgstr "Kennwort (wiederholen)" + +#: contrib/admin/templates/admin/auth/user/add_form.html:24 +msgid "Enter the same password as above, for verification." +msgstr "Bitte das gleiche Passwort zur Prüfung nochmal eingeben." + #: contrib/admin/templates/registration/password_change_done.html:4 #: contrib/admin/templates/registration/password_change_form.html:4 #: contrib/admin/templates/registration/password_change_form.html:6 @@ -1093,11 +1222,11 @@ msgstr "" "Hier muss entweder ein absoluter Pfad oder eine komplette URL mit http:// am " "Anfang stehen." -#: contrib/redirects/models.py:12 +#: contrib/redirects/models.py:13 msgid "redirect" msgstr "Umleitung" -#: contrib/redirects/models.py:13 +#: contrib/redirects/models.py:14 msgid "redirects" msgstr "Umleitungen" @@ -1125,11 +1254,11 @@ msgstr "Name der Vorlage" #: contrib/flatpages/models.py:13 msgid "" -"Example: 'flatpages/contact_page'. If this isn't provided, the system will " -"use 'flatpages/default'." +"Example: 'flatpages/contact_page.html'. If this isn't provided, the system " +"will use 'flatpages/default.html'." msgstr "" -"Beispiel: 'flatpages/contact_page'. Wenn dieses Feld nicht gefüllt ist, wird " -"'flatpages/default' als Standard gewählt." +"Beispiel: 'flatpages/contact_page.html'. Wenn dieses Feld nicht gefüllt ist, " +"wird 'flatpages/default.html' als Standard gewählt." #: contrib/flatpages/models.py:14 msgid "registration required" @@ -1148,80 +1277,108 @@ msgstr "Webseite" msgid "flat pages" msgstr "Webseiten" -#: contrib/auth/models.py:13 contrib/auth/models.py:26 +#: contrib/auth/views.py:39 +msgid "Logged out" +msgstr "Abgemeldet" + +#: contrib/auth/models.py:38 contrib/auth/models.py:57 msgid "name" msgstr "Name" -#: contrib/auth/models.py:15 +#: contrib/auth/models.py:40 msgid "codename" msgstr "Codename" -#: contrib/auth/models.py:17 +#: contrib/auth/models.py:42 msgid "permission" msgstr "Berechtigung" -#: contrib/auth/models.py:18 contrib/auth/models.py:27 +#: contrib/auth/models.py:43 contrib/auth/models.py:58 msgid "permissions" msgstr "Berechtigungen" -#: contrib/auth/models.py:29 +#: contrib/auth/models.py:60 msgid "group" msgstr "Gruppe" -#: contrib/auth/models.py:30 contrib/auth/models.py:65 +#: contrib/auth/models.py:61 contrib/auth/models.py:100 msgid "groups" msgstr "Gruppen" -#: contrib/auth/models.py:55 +#: contrib/auth/models.py:90 msgid "username" msgstr "Benutzername" -#: contrib/auth/models.py:56 +#: contrib/auth/models.py:90 +msgid "" +"Required. 30 characters or fewer. Alphanumeric characters only (letters, " +"digits and underscores)." +msgstr "" +"Erforderlich. 30 Zeichen oder weniger. Alphanumerische Zeichen (Buchstaben, " +"Ziffern und Unterstriche sind erlaubt)." + +#: contrib/auth/models.py:91 msgid "first name" msgstr "Vorname" -#: contrib/auth/models.py:57 +#: contrib/auth/models.py:92 msgid "last name" msgstr "Nachname" -#: contrib/auth/models.py:58 +#: contrib/auth/models.py:93 msgid "e-mail address" msgstr "eMail-Adresse" -#: contrib/auth/models.py:59 +#: contrib/auth/models.py:94 msgid "password" msgstr "Kennwort" -#: contrib/auth/models.py:59 +#: contrib/auth/models.py:94 msgid "Use '[algo]$[salt]$[hexdigest]'" msgstr "Im Format '[algo]$[salt]$[hexdigest]'" -#: contrib/auth/models.py:60 +#: contrib/auth/models.py:95 msgid "staff status" msgstr "Administrator" -#: contrib/auth/models.py:60 +#: contrib/auth/models.py:95 msgid "Designates whether the user can log into this admin site." msgstr "" "Gibt an, ob der Benutzer sich an der Administrationsseite anmelden kann." -#: contrib/auth/models.py:61 +#: contrib/auth/models.py:96 msgid "active" msgstr "Aktiv" -#: contrib/auth/models.py:62 +#: contrib/auth/models.py:96 +msgid "" +"Designates whether this user can log into the Django admin. Unselect this " +"instead of deleting accounts." +msgstr "" +"Gibt an, ob der Benutzer sich an der Administrationsseite anmelden kann. " +"Anstelle Benutzer zu löschen, kann das hier auch einfach abgeschaltet werden." + +#: contrib/auth/models.py:97 msgid "superuser status" msgstr "Hauptadmin." -#: contrib/auth/models.py:63 +#: contrib/auth/models.py:97 +msgid "" +"Designates that this user has all permissions without explicitly assigning " +"them." +msgstr "" +"Bestimmt, das dieser Benutzer alle Berechtigungen hat, ohne diese einzeln " +"zuweisen zu müssen." + +#: contrib/auth/models.py:98 msgid "last login" msgstr "letzte Anmeldung" -#: contrib/auth/models.py:64 +#: contrib/auth/models.py:99 msgid "date joined" msgstr "Mitglied seit" -#: contrib/auth/models.py:66 +#: contrib/auth/models.py:101 msgid "" "In addition to the permissions manually assigned, this user will also get " "all permissions granted to each group he/she is in." @@ -1229,39 +1386,39 @@ msgstr "" "Zusätzlich zu den manuell angelegten Rechten erhält dieser Benutzer auch " "alle Rechte, die seine zugewiesenen Gruppen haben." -#: contrib/auth/models.py:67 +#: contrib/auth/models.py:102 msgid "user permissions" msgstr "Berechtigungen" -#: contrib/auth/models.py:70 +#: contrib/auth/models.py:105 msgid "user" msgstr "Benutzer" -#: contrib/auth/models.py:71 +#: contrib/auth/models.py:106 msgid "users" msgstr "Benutzer" -#: contrib/auth/models.py:76 +#: contrib/auth/models.py:111 msgid "Personal info" msgstr "Persönliche Infos" -#: contrib/auth/models.py:77 +#: contrib/auth/models.py:112 msgid "Permissions" msgstr "Berechtigungen" -#: contrib/auth/models.py:78 +#: contrib/auth/models.py:113 msgid "Important dates" msgstr "Wichtige Daten" -#: contrib/auth/models.py:79 +#: contrib/auth/models.py:114 msgid "Groups" msgstr "Gruppen" -#: contrib/auth/models.py:219 +#: contrib/auth/models.py:256 msgid "message" msgstr "Mitteilung" -#: contrib/auth/forms.py:30 +#: contrib/auth/forms.py:52 msgid "" "Your Web browser doesn't appear to have cookies enabled. Cookies are " "required for logging in." @@ -1269,35 +1426,55 @@ msgstr "" "Der Webbrowser scheint keine Cookies aktiviert zu haben. Cookies sind für " "die Anmeldung zwingend notwendig." -#: contrib/contenttypes/models.py:25 +#: contrib/auth/forms.py:61 +msgid "This account is inactive." +msgstr "Dieser Benutzer ist inaktiv." + +#: contrib/auth/forms.py:84 +msgid "" +"That e-mail address doesn't have an associated user acount. Are you sure " +"you've registered?" +msgstr "" +"Die Email-Adresse hat keinen Benutzer zugeordnet. Sicher, das die Adresse " +"hier angemeldet ist?" + +#: contrib/auth/forms.py:116 +msgid "The two 'new password' fields didn't match." +msgstr "Die zwei Passwörter sind nicht gleich." + +#: contrib/auth/forms.py:123 +msgid "Your old password was entered incorrectly. Please enter it again." +msgstr "Das alte Passwort war falsch. Bitte neu eingeben." + +#: contrib/contenttypes/models.py:20 msgid "python model class name" msgstr "Python Model-Klassenname" -#: contrib/contenttypes/models.py:28 +#: contrib/contenttypes/models.py:23 msgid "content type" msgstr "Inhaltstyp" -#: contrib/contenttypes/models.py:29 +#: contrib/contenttypes/models.py:24 msgid "content types" msgstr "Inhaltstypen" -#: contrib/sessions/models.py:35 +#: contrib/sessions/models.py:51 msgid "session key" msgstr "Sitzungs-ID" -#: contrib/sessions/models.py:36 +#: contrib/sessions/models.py:52 msgid "session data" msgstr "Sitzungsdaten" -#: contrib/sessions/models.py:37 +#: contrib/sessions/models.py:53 msgid "expire date" msgstr "Verfallsdatum" -#: contrib/sessions/models.py:41 +#: contrib/sessions/models.py:57 msgid "session" msgstr "Sitzung" -#: contrib/sessions/models.py:42 +#: contrib/sessions/models.py:58 msgid "sessions" msgstr "Sitzungen" @@ -1317,18 +1494,6 @@ msgstr "Website" msgid "sites" msgstr "Websites" -#: utils/translation.py:360 -msgid "DATE_FORMAT" -msgstr "j. N Y" - -#: utils/translation.py:361 -msgid "DATETIME_FORMAT" -msgstr "j. N Y, H:i" - -#: utils/translation.py:362 -msgid "TIME_FORMAT" -msgstr "H:i" - #: utils/dates.py:6 msgid "Monday" msgstr "Montag" @@ -1517,119 +1682,159 @@ msgid_plural "minutes" msgstr[0] "Minute" msgstr[1] "Minuten" -#: conf/global_settings.py:37 +#: utils/translation/trans_real.py:362 +msgid "DATE_FORMAT" +msgstr "j. N Y" + +#: utils/translation/trans_real.py:363 +msgid "DATETIME_FORMAT" +msgstr "j. N Y, H:i" + +#: utils/translation/trans_real.py:364 +msgid "TIME_FORMAT" +msgstr "H:i" + +#: utils/translation/trans_real.py:380 +msgid "YEAR_MONTH_FORMAT" +msgstr "F Y" + +#: utils/translation/trans_real.py:381 +msgid "MONTH_DAY_FORMAT" +msgstr "j. F" + +#: conf/global_settings.py:39 +msgid "Arabic" +msgstr "Arabisch" + +#: conf/global_settings.py:40 msgid "Bengali" msgstr "Bengali" -#: conf/global_settings.py:38 +#: conf/global_settings.py:41 msgid "Czech" msgstr "Tschechisch" -#: conf/global_settings.py:39 +#: conf/global_settings.py:42 msgid "Welsh" msgstr "Walisisch" -#: conf/global_settings.py:40 +#: conf/global_settings.py:43 msgid "Danish" msgstr "Dänisch" -#: conf/global_settings.py:41 +#: conf/global_settings.py:44 msgid "German" msgstr "Deutsch" -#: conf/global_settings.py:42 +#: conf/global_settings.py:45 msgid "Greek" msgstr "Griechisch" -#: conf/global_settings.py:43 +#: conf/global_settings.py:46 msgid "English" msgstr "Englisch" -#: conf/global_settings.py:44 +#: conf/global_settings.py:47 msgid "Spanish" msgstr "Spanisch" -#: conf/global_settings.py:45 +#: conf/global_settings.py:48 +msgid "Argentinean Spanish" +msgstr "Argentinisches Spanisch" + +#: conf/global_settings.py:49 +msgid "Finnish" +msgstr "Finnisch" + +#: conf/global_settings.py:50 msgid "French" msgstr "Französisch" -#: conf/global_settings.py:46 +#: conf/global_settings.py:51 msgid "Galician" msgstr "Galicisch" -#: conf/global_settings.py:47 +#: conf/global_settings.py:52 msgid "Hungarian" -msgstr "" +msgstr "Ungarisch" -#: conf/global_settings.py:48 +#: conf/global_settings.py:53 msgid "Hebrew" msgstr "Hebräisch" -#: conf/global_settings.py:49 +#: conf/global_settings.py:54 msgid "Icelandic" msgstr "Isländisch" -#: conf/global_settings.py:50 +#: conf/global_settings.py:55 msgid "Italian" msgstr "Italienisch" -#: conf/global_settings.py:51 +#: conf/global_settings.py:56 msgid "Japanese" msgstr "Japanisch" -#: conf/global_settings.py:52 +#: conf/global_settings.py:57 msgid "Dutch" msgstr "Holländisch" -#: conf/global_settings.py:53 +#: conf/global_settings.py:58 msgid "Norwegian" msgstr "Norwegisch" -#: conf/global_settings.py:54 +#: conf/global_settings.py:59 msgid "Brazilian" msgstr "Brasilianisch" -#: conf/global_settings.py:55 +#: conf/global_settings.py:60 msgid "Romanian" msgstr "Rumänisch" -#: conf/global_settings.py:56 +#: conf/global_settings.py:61 msgid "Russian" msgstr "Russisch" -#: conf/global_settings.py:57 +#: conf/global_settings.py:62 msgid "Slovak" msgstr "Slowakisch" -#: conf/global_settings.py:58 +#: conf/global_settings.py:63 msgid "Slovenian" msgstr "Slowenisch" -#: conf/global_settings.py:59 +#: conf/global_settings.py:64 msgid "Serbian" msgstr "Serbisch" -#: conf/global_settings.py:60 +#: conf/global_settings.py:65 msgid "Swedish" msgstr "Schwedisch" -#: conf/global_settings.py:61 +#: conf/global_settings.py:66 +msgid "Tamil" +msgstr "Tamilisch" + +#: conf/global_settings.py:67 +msgid "Turkish" +msgstr "Türkisch" + +#: conf/global_settings.py:68 msgid "Ukrainian" msgstr "Ukrainisch" -#: conf/global_settings.py:62 +#: conf/global_settings.py:69 msgid "Simplified Chinese" msgstr "Vereinfachtes Chinesisch" -#: conf/global_settings.py:63 +#: conf/global_settings.py:70 msgid "Traditional Chinese" msgstr "Traditionelles Chinesisch" -#: core/validators.py:60 +#: core/validators.py:63 msgid "This value must contain only letters, numbers and underscores." msgstr "Dieser Wert darf nur Buchstaben, Ziffern und Unterstriche enthalten." -#: core/validators.py:64 +#: core/validators.py:67 msgid "" "This value must contain only letters, numbers, underscores, dashes or " "slashes." @@ -1637,65 +1842,85 @@ msgstr "" "Dieser Wert darf nur Buchstaben, Ziffern, Unterstriche und Schrägstriche " "enthalten." -#: core/validators.py:72 +#: core/validators.py:71 +msgid "This value must contain only letters, numbers, underscores or hyphens." +msgstr "" +"Dieser Wert darf nur Buchstaben, Ziffern, Unterstriche und Bindestriche " +"enthalten." + +#: core/validators.py:75 msgid "Uppercase letters are not allowed here." msgstr "Großbuchstaben sind hier nicht erlaubt." -#: core/validators.py:76 +#: core/validators.py:79 msgid "Lowercase letters are not allowed here." msgstr "Kleinbuchstaben sind hier nicht erlaubt." -#: core/validators.py:83 +#: core/validators.py:86 msgid "Enter only digits separated by commas." msgstr "Hier sind nur durch Komma getrennte Ziffern erlaubt." -#: core/validators.py:95 +#: core/validators.py:98 msgid "Enter valid e-mail addresses separated by commas." msgstr "Bitte mit Komma getrennte, gültige eMail-Adressen eingeben." -#: core/validators.py:99 +#: core/validators.py:102 msgid "Please enter a valid IP address." msgstr "Bitte eine gültige IP-Adresse eingeben." -#: core/validators.py:103 +#: core/validators.py:106 msgid "Empty values are not allowed here." msgstr "Dieses Feld darf nicht leer sein." -#: core/validators.py:107 +#: core/validators.py:110 msgid "Non-numeric characters aren't allowed here." msgstr "Nichtnumerische Zeichen sind hier nicht erlaubt." -#: core/validators.py:111 +#: core/validators.py:114 msgid "This value can't be comprised solely of digits." msgstr "Dieser Wert darf nicht nur aus Ziffern bestehen." -#: core/validators.py:116 +#: core/validators.py:119 msgid "Enter a whole number." msgstr "Bitte eine ganze Zahl eingeben." -#: core/validators.py:120 +#: core/validators.py:123 msgid "Only alphabetical characters are allowed here." msgstr "Nur alphabetische Zeichen sind hier erlaubt." -#: core/validators.py:124 +#: core/validators.py:138 +msgid "Year must be 1900 or later." +msgstr "Das Jahr muss 1900 oder später sein." + +#: core/validators.py:142 +#, python-format +msgid "Invalid date: %s." +msgstr "Ungültiges Datum: %s" + +#: core/validators.py:146 db/models/fields/__init__.py:415 msgid "Enter a valid date in YYYY-MM-DD format." msgstr "Bitte ein gültiges Datum im Format JJJJ-MM-TT eingeben." -#: core/validators.py:128 +#: core/validators.py:151 msgid "Enter a valid time in HH:MM format." msgstr "Bitte eine gültige Zeit im Format SS:MM eingeben." -#: core/validators.py:132 db/models/fields/__init__.py:468 +#: core/validators.py:155 db/models/fields/__init__.py:477 msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format." msgstr "" "Bitte eine gültige Datums- und Zeitangabe im Format JJJJ-MM-TT SS:MM " "eingeben." -#: core/validators.py:136 +#: core/validators.py:160 msgid "Enter a valid e-mail address." msgstr "Bitte eine gültige eMail-Adresse eingeben" -#: core/validators.py:148 +#: core/validators.py:172 core/validators.py:401 forms/__init__.py:661 +msgid "No file was submitted. Check the encoding type on the form." +msgstr "" +"Es wurde keine Datei geschickt. Eventuell ist das Formular-Encoding falsch." + +#: core/validators.py:176 msgid "" "Upload a valid image. The file you uploaded was either not an image or a " "corrupted image." @@ -1703,27 +1928,27 @@ msgstr "" "Bitte ein Bild hochladen. Die Datei, die hochgeladen wurde, ist kein Bild " "oder ist defekt." -#: core/validators.py:155 +#: core/validators.py:183 #, python-format msgid "The URL %s does not point to a valid image." msgstr "Die URL %s zeigt nicht auf ein gültiges Bild." -#: core/validators.py:159 +#: core/validators.py:187 #, python-format msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid." msgstr "" "Telefonnummern müssen im Format XXX-XXX-XXXX sein. \"%s\" ist ungültig." -#: core/validators.py:167 +#: core/validators.py:195 #, python-format msgid "The URL %s does not point to a valid QuickTime video." msgstr "Die URL %s zeigt nicht auf ein gültiges QuickTime video." -#: core/validators.py:171 +#: core/validators.py:199 msgid "A valid URL is required." msgstr "Eine gültige URL ist hier verlangt." -#: core/validators.py:185 +#: core/validators.py:213 #, python-format msgid "" "Valid HTML is required. Specific errors are:\n" @@ -1732,71 +1957,71 @@ msgstr "" "Bitte gültiges HTML eingeben. Fehler sind:\n" "%s" -#: core/validators.py:192 +#: core/validators.py:220 #, python-format msgid "Badly formed XML: %s" msgstr "Ungültiges XML: %s" -#: core/validators.py:202 +#: core/validators.py:230 #, python-format msgid "Invalid URL: %s" msgstr "Ungültige URL: %s" -#: core/validators.py:206 core/validators.py:208 +#: core/validators.py:234 core/validators.py:236 #, python-format msgid "The URL %s is a broken link." msgstr "Die URL %s funktioniert nicht." -#: core/validators.py:214 +#: core/validators.py:242 msgid "Enter a valid U.S. state abbreviation." msgstr "Bitte eine gültige Abkürzung für einen US-Staat eingeben." -#: core/validators.py:229 +#: core/validators.py:256 #, python-format msgid "Watch your mouth! The word %s is not allowed here." msgid_plural "Watch your mouth! The words %s are not allowed here." msgstr[0] "Keine Schimpfworte! Das Wort %s ist hier nicht gern gesehen!" msgstr[1] "Keine Schimpfworte! Die Wörter %s sind hier nicht gern gesehen!" -#: core/validators.py:236 +#: core/validators.py:263 #, python-format msgid "This field must match the '%s' field." msgstr "Dieses Feld muss zum Feld '%s' passen." -#: core/validators.py:255 +#: core/validators.py:282 msgid "Please enter something for at least one field." msgstr "Bitte mindestens eines der Felder ausfüllen." -#: core/validators.py:264 core/validators.py:275 +#: core/validators.py:291 core/validators.py:302 msgid "Please enter both fields or leave them both empty." msgstr "Bitte entweder beide Felder ausfüllen, oder beide leer lassen." -#: core/validators.py:282 +#: core/validators.py:309 #, python-format msgid "This field must be given if %(field)s is %(value)s" msgstr "" "Dieses Feld muss gefüllt sein, wenn Feld %(field)s den Wert %(value)s hat." -#: core/validators.py:294 +#: core/validators.py:321 #, python-format msgid "This field must be given if %(field)s is not %(value)s" msgstr "" "Dieses Feld muss gefüllt sein, wenn Feld %(field)s nicht %(value)s ist." -#: core/validators.py:313 +#: core/validators.py:340 msgid "Duplicate values are not allowed." msgstr "Doppelte Werte sind hier nicht erlaubt." -#: core/validators.py:336 +#: core/validators.py:363 #, python-format msgid "This value must be a power of %s." msgstr "Dieser Wert muss eine Potenz von %s sein." -#: core/validators.py:347 +#: core/validators.py:374 msgid "Please enter a valid decimal number." msgstr "Bitte eine gültige Dezimalzahl eingeben." -#: core/validators.py:349 +#: core/validators.py:378 #, python-format msgid "Please enter a valid decimal number with at most %s total digit." msgid_plural "" @@ -1804,7 +2029,16 @@ msgid_plural "" msgstr[0] "Bitte eine gültige Dezimalzahl mit maximal %s Ziffer eingeben." msgstr[1] "Bitte eine gültige Dezimalzahl mit maximal %s Ziffern eingeben." -#: core/validators.py:352 +#: core/validators.py:381 +#, python-format +msgid "" +"Please enter a valid decimal number with a whole part of at most %s digit." +msgid_plural "" +"Please enter a valid decimal number with a whole part of at most %s digits." +msgstr[0] "Bitte eine gültige Dezimalzahl mit maximal %s Ziffer eingeben." +msgstr[1] "Bitte eine gültige Dezimalzahl mit maximal %s Ziffern eingeben." + +#: core/validators.py:384 #, python-format msgid "Please enter a valid decimal number with at most %s decimal place." msgid_plural "" @@ -1814,39 +2048,39 @@ msgstr[0] "" msgstr[1] "" "Bitte eine gültige Dezimalzahl mit maximal %s Dezimalstellen eingeben." -#: core/validators.py:362 +#: core/validators.py:394 #, python-format msgid "Make sure your uploaded file is at least %s bytes big." msgstr "" "Bitte sicherstellen, daß die hochgeladene Datei mindestens %s Bytes gross " "ist." -#: core/validators.py:363 +#: core/validators.py:395 #, python-format msgid "Make sure your uploaded file is at most %s bytes big." msgstr "" "Bitte sicherstellen, daß die hochgeladene Datei maximal %s Bytes gross ist." -#: core/validators.py:376 +#: core/validators.py:412 msgid "The format for this field is wrong." msgstr "Das Format für dieses Feld ist falsch." -#: core/validators.py:391 +#: core/validators.py:427 msgid "This field is invalid." msgstr "Dieses Feld ist ungültig." -#: core/validators.py:426 +#: core/validators.py:463 #, python-format msgid "Could not retrieve anything from %s." msgstr "Konnte nichts von %s empfangen." -#: core/validators.py:429 +#: core/validators.py:466 #, python-format msgid "" "The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'." msgstr "Die URL %(url)s lieferte den falschen Content-Type '%(contenttype)s'." -#: core/validators.py:462 +#: core/validators.py:499 #, python-format msgid "" "Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with " @@ -1855,7 +2089,7 @@ msgstr "" "Bitte das ungeschlossene %(tag)s Tag in Zeile %(line)s schließen. Die Zeile " "beginnt mit \"%(start)s\"." -#: core/validators.py:466 +#: core/validators.py:503 #, python-format msgid "" "Some text starting on line %(line)s is not allowed in that context. (Line " @@ -1864,7 +2098,7 @@ msgstr "" "In Zeile %(line)s ist Text, der nicht in dem Kontext erlaubt ist. Die Zeile " "beginnt mit \"%(start)s\"." -#: core/validators.py:471 +#: core/validators.py:508 #, python-format msgid "" "\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%" @@ -1873,7 +2107,7 @@ msgstr "" "Das Attribute %(attr)s in Zeile %(line)s ist ungültig. Die Zeile beginnt mit " "\"%(start)s\"." -#: core/validators.py:476 +#: core/validators.py:513 #, python-format msgid "" "\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%" @@ -1882,7 +2116,7 @@ msgstr "" "<%(tag)s> in Zeile %(line)s ist ungültig. Die Zeile beginnt mit \"%(start)s" "\"." -#: core/validators.py:480 +#: core/validators.py:517 #, python-format msgid "" "A tag on line %(line)s is missing one or more required attributes. (Line " @@ -1891,7 +2125,7 @@ msgstr "" "Ein Tag in Zeile %(line)s hat eines oder mehrere Pflichtattribute nicht. Die " "Zeile beginnt mit \"%(start)s\"." -#: core/validators.py:485 +#: core/validators.py:522 #, python-format msgid "" "The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line " @@ -1900,6 +2134,21 @@ msgstr "" "Das Attribut %(attr)s in Zeile %(line)s hat einen ungültigen Wert. Die Zeile " "beginnt mit \"%(start)s\"." +#: views/generic/create_update.py:43 +#, python-format +msgid "The %(verbose_name)s was created successfully." +msgstr "%(verbose_name)s wurde erfolgreich angelegt." + +#: views/generic/create_update.py:117 +#, python-format +msgid "The %(verbose_name)s was updated successfully." +msgstr "%(verbose_name)s wurde erfolgreich aktualisiert." + +#: views/generic/create_update.py:184 +#, python-format +msgid "The %(verbose_name)s was deleted." +msgstr "%(verbose_name)s wurde gelöscht" + #: db/models/manipulators.py:302 #, python-format msgid "%(object)s with this %(type)s already exists for the given %(field)s." @@ -1913,44 +2162,44 @@ msgid "%(optname)s with this %(fieldname)s already exists." msgstr "Ein '%(optname)s' mit diesem '%(fieldname)s' existiert bereits." #: db/models/fields/__init__.py:114 db/models/fields/__init__.py:265 -#: db/models/fields/__init__.py:542 db/models/fields/__init__.py:553 +#: db/models/fields/__init__.py:551 db/models/fields/__init__.py:562 #: forms/__init__.py:346 msgid "This field is required." msgstr "Dieses Feld ist zwingend." -#: db/models/fields/__init__.py:337 +#: db/models/fields/__init__.py:340 msgid "This value must be an integer." msgstr "Dieser Wert muss eine Ganzzahl sein." -#: db/models/fields/__init__.py:369 +#: db/models/fields/__init__.py:372 msgid "This value must be either True or False." msgstr "Dieser Wert muss wahr oder falsch sein." -#: db/models/fields/__init__.py:385 +#: db/models/fields/__init__.py:388 msgid "This field cannot be null." msgstr "Dieses Feld darf nicht leer sein." -#: db/models/fields/__init__.py:562 +#: db/models/fields/__init__.py:571 msgid "Enter a valid filename." msgstr "Bitte einen gültigen Dateinamen eingeben" -#: db/models/fields/related.py:43 +#: db/models/fields/related.py:51 #, python-format msgid "Please enter a valid %s." msgstr "Bitte ein gültiges '%s' eingeben." -#: db/models/fields/related.py:579 +#: db/models/fields/related.py:618 msgid "Separate multiple IDs with commas." msgstr "Mehrere IDs können mit Komma getrennt werden." -#: db/models/fields/related.py:581 +#: db/models/fields/related.py:620 msgid "" "Hold down \"Control\", or \"Command\" on a Mac, to select more than one." msgstr "" " Um mehr als eine Selektion zu treffen, \"Strg\", oder auf dem Mac \"Command" "\", beim Klicken gedrückt halten." -#: db/models/fields/related.py:625 +#: db/models/fields/related.py:664 #, python-format msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid." msgid_plural "" @@ -1960,39 +2209,39 @@ msgstr[0] "" msgstr[1] "" "Bitte gültige IDs für %(self)s eingeben. Die Werte %(value)r sind ungültig." -#: forms/__init__.py:380 +#: forms/__init__.py:381 #, python-format msgid "Ensure your text is less than %s character." msgid_plural "Ensure your text is less than %s characters." msgstr[0] "Bitte sicherstellen, das der Text weniger als %s Zeichen hat." msgstr[1] "Bitte sicherstellen, das der Text weniger als %s Zeichen hat." -#: forms/__init__.py:385 +#: forms/__init__.py:386 msgid "Line breaks are not allowed here." msgstr "Zeilenumbrüche sind hier nicht erlaubt." -#: forms/__init__.py:480 forms/__init__.py:551 forms/__init__.py:589 +#: forms/__init__.py:487 forms/__init__.py:560 forms/__init__.py:599 #, python-format msgid "Select a valid choice; '%(data)s' is not in %(choices)s." msgstr "" "Bitte eine gültige Auswahl treffen; '%(data)s' ist nicht in %(choices)s." -#: forms/__init__.py:645 +#: forms/__init__.py:663 msgid "The submitted file is empty." msgstr "Die ausgewählte Datei ist leer." -#: forms/__init__.py:699 +#: forms/__init__.py:719 msgid "Enter a whole number between -32,768 and 32,767." msgstr "Bitte eine ganze Zahl zwischen -32.768 und 32.767 eingeben." -#: forms/__init__.py:708 +#: forms/__init__.py:729 msgid "Enter a positive number." msgstr "Bitte eine ganze, positive Zahl eingeben." -#: forms/__init__.py:717 +#: forms/__init__.py:739 msgid "Enter a whole number between 0 and 32,767." msgstr "Bitte eine ganze Zahl zwischen 0 und 32.767 eingeben." -#: template/defaultfilters.py:379 +#: template/defaultfilters.py:401 msgid "yes,no,maybe" msgstr "Ja,Nein,Vielleicht" diff --git a/django/conf/locale/en/LC_MESSAGES/django.mo b/django/conf/locale/en/LC_MESSAGES/django.mo Binary files differindex 0a4947bfc1..6c4dbe4b4e 100644 --- a/django/conf/locale/en/LC_MESSAGES/django.mo +++ b/django/conf/locale/en/LC_MESSAGES/django.mo diff --git a/django/conf/locale/en/LC_MESSAGES/django.po b/django/conf/locale/en/LC_MESSAGES/django.po index 625c3b04f1..feba39f7cd 100644 --- a/django/conf/locale/en/LC_MESSAGES/django.po +++ b/django/conf/locale/en/LC_MESSAGES/django.po @@ -3,12 +3,11 @@ # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # -#, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2006-05-16 10:10+0200\n" +"POT-Creation-Date: 2006-09-25 15:43+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -73,7 +72,7 @@ msgstr "" msgid "is public" msgstr "" -#: contrib/comments/models.py:85 contrib/admin/views/doc.py:289 +#: contrib/comments/models.py:85 contrib/admin/views/doc.py:304 msgid "IP address" msgstr "" @@ -200,12 +199,12 @@ msgstr "" msgid "No voting for yourself" msgstr "" -#: contrib/comments/views/comments.py:28 +#: contrib/comments/views/comments.py:27 msgid "" "This rating is required because you've entered at least one other rating." msgstr "" -#: contrib/comments/views/comments.py:112 +#: contrib/comments/views/comments.py:111 #, python-format msgid "" "This comment was posted by a user who has posted fewer than %(count)s " @@ -220,7 +219,7 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: contrib/comments/views/comments.py:117 +#: contrib/comments/views/comments.py:116 #, python-format msgid "" "This comment was posted by a sketchy user:\n" @@ -228,22 +227,22 @@ msgid "" "%(text)s" msgstr "" -#: contrib/comments/views/comments.py:189 +#: contrib/comments/views/comments.py:188 #: contrib/comments/views/comments.py:280 msgid "Only POSTs are allowed" msgstr "" -#: contrib/comments/views/comments.py:193 +#: contrib/comments/views/comments.py:192 #: contrib/comments/views/comments.py:284 msgid "One or more of the required fields wasn't submitted" msgstr "" -#: contrib/comments/views/comments.py:197 +#: contrib/comments/views/comments.py:196 #: contrib/comments/views/comments.py:286 msgid "Somebody tampered with the comment form (security violation)" msgstr "" -#: contrib/comments/views/comments.py:207 +#: contrib/comments/views/comments.py:206 #: contrib/comments/views/comments.py:292 msgid "" "The comment form had an invalid 'target' parameter -- the object ID was " @@ -262,18 +261,9 @@ msgid "Username:" msgstr "" #: contrib/comments/templates/comments/form.html:6 -#: contrib/admin/templates/admin/login.html:20 -msgid "Password:" -msgstr "" - -#: contrib/comments/templates/comments/form.html:6 -msgid "Forgotten your password?" -msgstr "" - -#: contrib/comments/templates/comments/form.html:8 #: contrib/admin/templates/admin/object_history.html:3 #: contrib/admin/templates/admin/change_list.html:5 -#: contrib/admin/templates/admin/base.html:23 +#: contrib/admin/templates/admin/base.html:25 #: contrib/admin/templates/admin/delete_confirmation.html:3 #: contrib/admin/templates/admin/change_form.html:10 #: contrib/admin/templates/registration/password_change_done.html:3 @@ -291,6 +281,15 @@ msgstr "" msgid "Log out" msgstr "" +#: contrib/comments/templates/comments/form.html:8 +#: contrib/admin/templates/admin/login.html:20 +msgid "Password:" +msgstr "" + +#: contrib/comments/templates/comments/form.html:8 +msgid "Forgotten your password?" +msgstr "" + #: contrib/comments/templates/comments/form.html:12 msgid "Ratings" msgstr "" @@ -309,13 +308,13 @@ msgstr "" msgid "Post a photo" msgstr "" -#: contrib/comments/templates/comments/form.html:27 +#: contrib/comments/templates/comments/form.html:28 #: contrib/comments/templates/comments/freeform.html:5 msgid "Comment:" msgstr "" -#: contrib/comments/templates/comments/form.html:32 -#: contrib/comments/templates/comments/freeform.html:9 +#: contrib/comments/templates/comments/form.html:35 +#: contrib/comments/templates/comments/freeform.html:10 msgid "Preview comment" msgstr "" @@ -331,7 +330,7 @@ msgid "" msgstr "" #: contrib/admin/filterspecs.py:70 contrib/admin/filterspecs.py:88 -#: contrib/admin/filterspecs.py:143 +#: contrib/admin/filterspecs.py:143 contrib/admin/filterspecs.py:169 msgid "All" msgstr "" @@ -395,214 +394,283 @@ msgstr "" msgid "log entries" msgstr "" -#: contrib/admin/templatetags/admin_list.py:228 +#: contrib/admin/templatetags/admin_list.py:230 msgid "All dates" msgstr "" -#: contrib/admin/views/decorators.py:9 contrib/auth/forms.py:36 -#: contrib/auth/forms.py:41 +#: contrib/admin/views/decorators.py:10 contrib/auth/forms.py:59 msgid "" "Please enter a correct username and password. Note that both fields are case-" "sensitive." msgstr "" -#: contrib/admin/views/decorators.py:23 +#: contrib/admin/views/decorators.py:24 #: contrib/admin/templates/admin/login.html:25 msgid "Log in" msgstr "" -#: contrib/admin/views/decorators.py:61 +#: contrib/admin/views/decorators.py:62 msgid "" "Please log in again, because your session has expired. Don't worry: Your " "submission has been saved." msgstr "" -#: contrib/admin/views/decorators.py:68 +#: contrib/admin/views/decorators.py:69 msgid "" "Looks like your browser isn't configured to accept cookies. Please enable " "cookies, reload this page, and try again." msgstr "" -#: contrib/admin/views/decorators.py:82 +#: contrib/admin/views/decorators.py:83 msgid "Usernames cannot contain the '@' character." msgstr "" -#: contrib/admin/views/decorators.py:84 +#: contrib/admin/views/decorators.py:85 #, python-format msgid "Your e-mail address is not your username. Try '%s' instead." msgstr "" -#: contrib/admin/views/main.py:226 +#: contrib/admin/views/main.py:223 msgid "Site administration" msgstr "" -#: contrib/admin/views/main.py:260 +#: contrib/admin/views/main.py:257 contrib/admin/views/auth.py:17 #, python-format msgid "The %(name)s \"%(obj)s\" was added successfully." msgstr "" -#: contrib/admin/views/main.py:264 contrib/admin/views/main.py:348 +#: contrib/admin/views/main.py:261 contrib/admin/views/main.py:347 +#: contrib/admin/views/auth.py:22 msgid "You may edit it again below." msgstr "" -#: contrib/admin/views/main.py:272 contrib/admin/views/main.py:357 +#: contrib/admin/views/main.py:271 contrib/admin/views/main.py:356 #, python-format msgid "You may add another %s below." msgstr "" -#: contrib/admin/views/main.py:290 +#: contrib/admin/views/main.py:289 #, python-format msgid "Add %s" msgstr "" -#: contrib/admin/views/main.py:336 +#: contrib/admin/views/main.py:335 #, python-format msgid "Added %s." msgstr "" -#: contrib/admin/views/main.py:336 contrib/admin/views/main.py:338 -#: contrib/admin/views/main.py:340 +#: contrib/admin/views/main.py:335 contrib/admin/views/main.py:337 +#: contrib/admin/views/main.py:339 msgid "and" msgstr "" -#: contrib/admin/views/main.py:338 +#: contrib/admin/views/main.py:337 #, python-format msgid "Changed %s." msgstr "" -#: contrib/admin/views/main.py:340 +#: contrib/admin/views/main.py:339 #, python-format msgid "Deleted %s." msgstr "" -#: contrib/admin/views/main.py:343 +#: contrib/admin/views/main.py:342 msgid "No fields changed." msgstr "" -#: contrib/admin/views/main.py:346 +#: contrib/admin/views/main.py:345 #, python-format msgid "The %(name)s \"%(obj)s\" was changed successfully." msgstr "" -#: contrib/admin/views/main.py:354 +#: contrib/admin/views/main.py:353 #, python-format msgid "" "The %(name)s \"%(obj)s\" was added successfully. You may edit it again below." msgstr "" -#: contrib/admin/views/main.py:392 +#: contrib/admin/views/main.py:391 #, python-format msgid "Change %s" msgstr "" -#: contrib/admin/views/main.py:470 +#: contrib/admin/views/main.py:473 #, python-format msgid "One or more %(fieldname)s in %(name)s: %(obj)s" msgstr "" -#: contrib/admin/views/main.py:475 +#: contrib/admin/views/main.py:478 #, python-format msgid "One or more %(fieldname)s in %(name)s:" msgstr "" -#: contrib/admin/views/main.py:508 +#: contrib/admin/views/main.py:511 #, python-format msgid "The %(name)s \"%(obj)s\" was deleted successfully." msgstr "" -#: contrib/admin/views/main.py:511 +#: contrib/admin/views/main.py:514 msgid "Are you sure?" msgstr "" -#: contrib/admin/views/main.py:533 +#: contrib/admin/views/main.py:536 #, python-format msgid "Change history: %s" msgstr "" -#: contrib/admin/views/main.py:565 +#: contrib/admin/views/main.py:570 #, python-format msgid "Select %s" msgstr "" -#: contrib/admin/views/main.py:565 +#: contrib/admin/views/main.py:570 #, python-format msgid "Select %s to change" msgstr "" -#: contrib/admin/views/doc.py:277 contrib/admin/views/doc.py:286 -#: contrib/admin/views/doc.py:288 contrib/admin/views/doc.py:294 -#: contrib/admin/views/doc.py:295 contrib/admin/views/doc.py:297 +#: contrib/admin/views/main.py:758 +msgid "Database error" +msgstr "" + +#: contrib/admin/views/doc.py:46 contrib/admin/views/doc.py:48 +#: contrib/admin/views/doc.py:50 +msgid "tag:" +msgstr "" + +#: contrib/admin/views/doc.py:77 contrib/admin/views/doc.py:79 +#: contrib/admin/views/doc.py:81 +msgid "filter:" +msgstr "" + +#: contrib/admin/views/doc.py:135 contrib/admin/views/doc.py:137 +#: contrib/admin/views/doc.py:139 +msgid "view:" +msgstr "" + +#: contrib/admin/views/doc.py:164 +#, python-format +msgid "App %r not found" +msgstr "" + +#: contrib/admin/views/doc.py:171 +#, python-format +msgid "Model %r not found in app %r" +msgstr "" + +#: contrib/admin/views/doc.py:183 +#, python-format +msgid "the related `%s.%s` object" +msgstr "" + +#: contrib/admin/views/doc.py:183 contrib/admin/views/doc.py:205 +#: contrib/admin/views/doc.py:219 contrib/admin/views/doc.py:224 +msgid "model:" +msgstr "" + +#: contrib/admin/views/doc.py:214 +#, python-format +msgid "related `%s.%s` objects" +msgstr "" + +#: contrib/admin/views/doc.py:219 +#, python-format +msgid "all %s" +msgstr "" + +#: contrib/admin/views/doc.py:224 +#, python-format +msgid "number of %s" +msgstr "" + +#: contrib/admin/views/doc.py:229 +#, python-format +msgid "Fields on %s objects" +msgstr "" + +#: contrib/admin/views/doc.py:291 contrib/admin/views/doc.py:301 +#: contrib/admin/views/doc.py:303 contrib/admin/views/doc.py:309 +#: contrib/admin/views/doc.py:310 contrib/admin/views/doc.py:312 msgid "Integer" msgstr "" -#: contrib/admin/views/doc.py:278 +#: contrib/admin/views/doc.py:292 msgid "Boolean (Either True or False)" msgstr "" -#: contrib/admin/views/doc.py:279 contrib/admin/views/doc.py:296 +#: contrib/admin/views/doc.py:293 contrib/admin/views/doc.py:311 #, python-format msgid "String (up to %(maxlength)s)" msgstr "" -#: contrib/admin/views/doc.py:280 +#: contrib/admin/views/doc.py:294 msgid "Comma-separated integers" msgstr "" -#: contrib/admin/views/doc.py:281 +#: contrib/admin/views/doc.py:295 msgid "Date (without time)" msgstr "" -#: contrib/admin/views/doc.py:282 +#: contrib/admin/views/doc.py:296 msgid "Date (with time)" msgstr "" -#: contrib/admin/views/doc.py:283 +#: contrib/admin/views/doc.py:297 msgid "E-mail address" msgstr "" -#: contrib/admin/views/doc.py:284 contrib/admin/views/doc.py:287 +#: contrib/admin/views/doc.py:298 contrib/admin/views/doc.py:299 +#: contrib/admin/views/doc.py:302 msgid "File path" msgstr "" -#: contrib/admin/views/doc.py:285 +#: contrib/admin/views/doc.py:300 msgid "Decimal number" msgstr "" -#: contrib/admin/views/doc.py:291 +#: contrib/admin/views/doc.py:306 msgid "Boolean (Either True, False or None)" msgstr "" -#: contrib/admin/views/doc.py:292 +#: contrib/admin/views/doc.py:307 msgid "Relation to parent model" msgstr "" -#: contrib/admin/views/doc.py:293 +#: contrib/admin/views/doc.py:308 msgid "Phone number" msgstr "" -#: contrib/admin/views/doc.py:298 +#: contrib/admin/views/doc.py:313 msgid "Text" msgstr "" -#: contrib/admin/views/doc.py:299 +#: contrib/admin/views/doc.py:314 msgid "Time" msgstr "" -#: contrib/admin/views/doc.py:300 contrib/flatpages/models.py:7 +#: contrib/admin/views/doc.py:315 contrib/flatpages/models.py:7 msgid "URL" msgstr "" -#: contrib/admin/views/doc.py:301 +#: contrib/admin/views/doc.py:316 msgid "U.S. state (two uppercase letters)" msgstr "" -#: contrib/admin/views/doc.py:302 +#: contrib/admin/views/doc.py:317 msgid "XML text" msgstr "" +#: contrib/admin/views/doc.py:343 +#, python-format +msgid "%s does not appear to be a urlpattern object" +msgstr "" + +#: contrib/admin/views/auth.py:28 +msgid "Add user" +msgstr "" + #: contrib/admin/templates/admin/object_history.html:3 #: contrib/admin/templates/admin/change_list.html:5 -#: contrib/admin/templates/admin/base.html:23 +#: contrib/admin/templates/admin/base.html:25 #: contrib/admin/templates/admin/delete_confirmation.html:3 #: contrib/admin/templates/admin/change_form.html:10 #: contrib/admin/templates/registration/password_change_done.html:3 @@ -613,7 +681,7 @@ msgstr "" #: contrib/admin/templates/admin/object_history.html:3 #: contrib/admin/templates/admin/change_list.html:5 -#: contrib/admin/templates/admin/base.html:23 +#: contrib/admin/templates/admin/base.html:25 #: contrib/admin/templates/admin/delete_confirmation.html:3 #: contrib/admin/templates/admin/change_form.html:10 #: contrib/admin/templates/registration/password_change_done.html:3 @@ -634,9 +702,10 @@ msgstr "" #: contrib/admin/templates/admin/object_history.html:5 #: contrib/admin/templates/admin/500.html:4 #: contrib/admin/templates/admin/change_list.html:6 -#: contrib/admin/templates/admin/base.html:28 +#: contrib/admin/templates/admin/base.html:30 #: contrib/admin/templates/admin/delete_confirmation.html:6 #: contrib/admin/templates/admin/change_form.html:13 +#: contrib/admin/templates/admin/invalid_setup.html:4 #: contrib/admin/templates/registration/password_change_done.html:4 #: contrib/admin/templates/registration/password_reset_form.html:4 #: contrib/admin/templates/registration/logged_out.html:4 @@ -713,6 +782,11 @@ msgstr "" msgid "Models available in the %(name)s application." msgstr "" +#: contrib/admin/templates/admin/index.html:18 +#, python-format +msgid "%(name)s" +msgstr "" + #: contrib/admin/templates/admin/index.html:28 #: contrib/admin/templates/admin/change_form.html:15 msgid "Add" @@ -747,7 +821,7 @@ msgstr "" msgid "Have you <a href=\"/password_reset/\">forgotten your password</a>?" msgstr "" -#: contrib/admin/templates/admin/base.html:23 +#: contrib/admin/templates/admin/base.html:25 msgid "Welcome," msgstr "" @@ -759,16 +833,16 @@ msgstr "" #: contrib/admin/templates/admin/delete_confirmation.html:14 #, python-format msgid "" -"Deleting the %(object_name)s '%(object)s' would result in deleting related " -"objects, but your account doesn't have permission to delete the following " -"types of objects:" +"Deleting the %(object_name)s '%(escaped_object)s' would result in deleting " +"related objects, but your account doesn't have permission to delete the " +"following types of objects:" msgstr "" #: contrib/admin/templates/admin/delete_confirmation.html:21 #, python-format msgid "" -"Are you sure you want to delete the %(object_name)s \"%(object)s\"? All of " -"the following related items will be deleted:" +"Are you sure you want to delete the %(object_name)s \"%(escaped_object)s\"? " +"All of the following related items will be deleted:" msgstr "" #: contrib/admin/templates/admin/delete_confirmation.html:26 @@ -777,13 +851,33 @@ msgstr "" #: contrib/admin/templates/admin/filter.html:2 #, python-format -msgid " By %(title)s " +msgid " By %(filter_title)s " msgstr "" #: contrib/admin/templates/admin/search_form.html:8 msgid "Go" msgstr "" +#: contrib/admin/templates/admin/search_form.html:10 +#, python-format +msgid "1 result" +msgid_plural "%(counter)s results" +msgstr[0] "" +msgstr[1] "" + +#: contrib/admin/templates/admin/search_form.html:10 +#, python-format +msgid "%(full_result_count)s total" +msgstr "" + +#: contrib/admin/templates/admin/pagination.html:10 +msgid "Show all" +msgstr "" + +#: contrib/admin/templates/admin/filters.html:4 +msgid "Filter" +msgstr "" + #: contrib/admin/templates/admin/change_form.html:21 msgid "View on site" msgstr "" @@ -818,6 +912,35 @@ msgstr "" msgid "Save" msgstr "" +#: contrib/admin/templates/admin/invalid_setup.html:8 +msgid "" +"Something's wrong with your database installation. Make sure the appropriate " +"database tables have been created, and make sure the database is readable by " +"the appropriate user." +msgstr "" + +#: contrib/admin/templates/admin/auth/user/add_form.html:6 +msgid "" +"First, enter a username and password. Then, you'll be able to edit more user " +"options." +msgstr "" + +#: contrib/admin/templates/admin/auth/user/add_form.html:12 +msgid "Username" +msgstr "" + +#: contrib/admin/templates/admin/auth/user/add_form.html:18 +msgid "Password" +msgstr "" + +#: contrib/admin/templates/admin/auth/user/add_form.html:23 +msgid "Password (again)" +msgstr "" + +#: contrib/admin/templates/admin/auth/user/add_form.html:24 +msgid "Enter the same password as above, for verification." +msgstr "" + #: contrib/admin/templates/registration/password_change_done.html:4 #: contrib/admin/templates/registration/password_change_form.html:4 #: contrib/admin/templates/registration/password_change_form.html:6 @@ -1018,11 +1141,11 @@ msgid "" "'http://'." msgstr "" -#: contrib/redirects/models.py:12 +#: contrib/redirects/models.py:13 msgid "redirect" msgstr "" -#: contrib/redirects/models.py:13 +#: contrib/redirects/models.py:14 msgid "redirects" msgstr "" @@ -1049,8 +1172,8 @@ msgstr "" #: contrib/flatpages/models.py:13 msgid "" -"Example: 'flatpages/contact_page'. If this isn't provided, the system will " -"use 'flatpages/default'." +"Example: 'flatpages/contact_page.html'. If this isn't provided, the system " +"will use 'flatpages/default.html'." msgstr "" #: contrib/flatpages/models.py:14 @@ -1069,151 +1192,177 @@ msgstr "" msgid "flat pages" msgstr "" -#: contrib/auth/models.py:13 contrib/auth/models.py:26 +#: contrib/auth/views.py:39 +msgid "Logged out" +msgstr "" + +#: contrib/auth/models.py:38 contrib/auth/models.py:57 msgid "name" msgstr "" -#: contrib/auth/models.py:15 +#: contrib/auth/models.py:40 msgid "codename" msgstr "" -#: contrib/auth/models.py:17 +#: contrib/auth/models.py:42 msgid "permission" msgstr "" -#: contrib/auth/models.py:18 contrib/auth/models.py:27 +#: contrib/auth/models.py:43 contrib/auth/models.py:58 msgid "permissions" msgstr "" -#: contrib/auth/models.py:29 +#: contrib/auth/models.py:60 msgid "group" msgstr "" -#: contrib/auth/models.py:30 contrib/auth/models.py:65 +#: contrib/auth/models.py:61 contrib/auth/models.py:100 msgid "groups" msgstr "" -#: contrib/auth/models.py:55 +#: contrib/auth/models.py:90 msgid "username" msgstr "" -#: contrib/auth/models.py:56 +#: contrib/auth/models.py:90 +msgid "" +"Required. 30 characters or fewer. Alphanumeric characters only (letters, " +"digits and underscores)." +msgstr "" + +#: contrib/auth/models.py:91 msgid "first name" msgstr "" -#: contrib/auth/models.py:57 +#: contrib/auth/models.py:92 msgid "last name" msgstr "" -#: contrib/auth/models.py:58 +#: contrib/auth/models.py:93 msgid "e-mail address" msgstr "" -#: contrib/auth/models.py:59 +#: contrib/auth/models.py:94 msgid "password" msgstr "" -#: contrib/auth/models.py:59 +#: contrib/auth/models.py:94 msgid "Use '[algo]$[salt]$[hexdigest]'" msgstr "" -#: contrib/auth/models.py:60 +#: contrib/auth/models.py:95 msgid "staff status" msgstr "" -#: contrib/auth/models.py:60 +#: contrib/auth/models.py:95 msgid "Designates whether the user can log into this admin site." msgstr "" -#: contrib/auth/models.py:61 +#: contrib/auth/models.py:96 msgid "active" msgstr "" -#: contrib/auth/models.py:62 +#: contrib/auth/models.py:96 +msgid "" +"Designates whether this user can log into the Django admin. Unselect this " +"instead of deleting accounts." +msgstr "" + +#: contrib/auth/models.py:97 msgid "superuser status" msgstr "" -#: contrib/auth/models.py:63 +#: contrib/auth/models.py:97 +msgid "" +"Designates that this user has all permissions without explicitly assigning " +"them." +msgstr "" + +#: contrib/auth/models.py:98 msgid "last login" msgstr "" -#: contrib/auth/models.py:64 +#: contrib/auth/models.py:99 msgid "date joined" msgstr "" -#: contrib/auth/models.py:66 +#: contrib/auth/models.py:101 msgid "" "In addition to the permissions manually assigned, this user will also get " "all permissions granted to each group he/she is in." msgstr "" -#: contrib/auth/models.py:67 +#: contrib/auth/models.py:102 msgid "user permissions" msgstr "" -#: contrib/auth/models.py:70 +#: contrib/auth/models.py:105 msgid "user" msgstr "" -#: contrib/auth/models.py:71 +#: contrib/auth/models.py:106 msgid "users" msgstr "" -#: contrib/auth/models.py:76 +#: contrib/auth/models.py:111 msgid "Personal info" msgstr "" -#: contrib/auth/models.py:77 +#: contrib/auth/models.py:112 msgid "Permissions" msgstr "" -#: contrib/auth/models.py:78 +#: contrib/auth/models.py:113 msgid "Important dates" msgstr "" -#: contrib/auth/models.py:79 +#: contrib/auth/models.py:114 msgid "Groups" msgstr "" -#: contrib/auth/models.py:219 +#: contrib/auth/models.py:256 msgid "message" msgstr "" -#: contrib/auth/forms.py:30 +#: contrib/auth/forms.py:52 msgid "" "Your Web browser doesn't appear to have cookies enabled. Cookies are " "required for logging in." msgstr "" -#: contrib/contenttypes/models.py:25 +#: contrib/auth/forms.py:61 +msgid "This account is inactive." +msgstr "" + +#: contrib/contenttypes/models.py:20 msgid "python model class name" msgstr "" -#: contrib/contenttypes/models.py:28 +#: contrib/contenttypes/models.py:23 msgid "content type" msgstr "" -#: contrib/contenttypes/models.py:29 +#: contrib/contenttypes/models.py:24 msgid "content types" msgstr "" -#: contrib/sessions/models.py:35 +#: contrib/sessions/models.py:51 msgid "session key" msgstr "" -#: contrib/sessions/models.py:36 +#: contrib/sessions/models.py:52 msgid "session data" msgstr "" -#: contrib/sessions/models.py:37 +#: contrib/sessions/models.py:53 msgid "expire date" msgstr "" -#: contrib/sessions/models.py:41 +#: contrib/sessions/models.py:57 msgid "session" msgstr "" -#: contrib/sessions/models.py:42 +#: contrib/sessions/models.py:58 msgid "sessions" msgstr "" @@ -1233,18 +1382,6 @@ msgstr "" msgid "sites" msgstr "" -#: utils/translation.py:360 -msgid "DATE_FORMAT" -msgstr "N j, Y" - -#: utils/translation.py:361 -msgid "DATETIME_FORMAT" -msgstr "N j, Y, P" - -#: utils/translation.py:362 -msgid "TIME_FORMAT" -msgstr "P" - #: utils/dates.py:6 msgid "Monday" msgstr "" @@ -1433,275 +1570,332 @@ msgid_plural "minutes" msgstr[0] "" msgstr[1] "" -#: conf/global_settings.py:37 +#: utils/translation/trans_real.py:362 +msgid "DATE_FORMAT" +msgstr "N j, Y" + +#: utils/translation/trans_real.py:363 +msgid "DATETIME_FORMAT" +msgstr "N j, Y, P" + +#: utils/translation/trans_real.py:364 +msgid "TIME_FORMAT" +msgstr "P" + +#: utils/translation/trans_real.py:380 +msgid "YEAR_MONTH_FORMAT" +msgstr "F Y" + +#: utils/translation/trans_real.py:381 +msgid "MONTH_DAY_FORMAT" +msgstr "F j" + +#: conf/global_settings.py:39 +msgid "Arabic" +msgstr "" + +#: conf/global_settings.py:40 msgid "Bengali" msgstr "" -#: conf/global_settings.py:38 +#: conf/global_settings.py:41 msgid "Czech" msgstr "" -#: conf/global_settings.py:39 +#: conf/global_settings.py:42 msgid "Welsh" msgstr "" -#: conf/global_settings.py:40 +#: conf/global_settings.py:43 msgid "Danish" msgstr "" -#: conf/global_settings.py:41 +#: conf/global_settings.py:44 msgid "German" msgstr "" -#: conf/global_settings.py:42 +#: conf/global_settings.py:45 msgid "Greek" msgstr "" -#: conf/global_settings.py:43 +#: conf/global_settings.py:46 msgid "English" msgstr "" -#: conf/global_settings.py:44 +#: conf/global_settings.py:47 msgid "Spanish" msgstr "" -#: conf/global_settings.py:45 +#: conf/global_settings.py:48 +msgid "Argentinean Spanish" +msgstr "" + +#: conf/global_settings.py:49 +msgid "Finnish" +msgstr "" + +#: conf/global_settings.py:50 msgid "French" msgstr "" -#: conf/global_settings.py:46 +#: conf/global_settings.py:51 msgid "Galician" msgstr "" -#: conf/global_settings.py:47 +#: conf/global_settings.py:52 msgid "Hungarian" msgstr "" -#: conf/global_settings.py:48 +#: conf/global_settings.py:53 msgid "Hebrew" msgstr "" -#: conf/global_settings.py:49 +#: conf/global_settings.py:54 msgid "Icelandic" msgstr "" -#: conf/global_settings.py:50 +#: conf/global_settings.py:55 msgid "Italian" msgstr "" -#: conf/global_settings.py:51 +#: conf/global_settings.py:56 msgid "Japanese" msgstr "" -#: conf/global_settings.py:52 +#: conf/global_settings.py:57 msgid "Dutch" msgstr "" -#: conf/global_settings.py:53 +#: conf/global_settings.py:58 msgid "Norwegian" msgstr "" -#: conf/global_settings.py:54 +#: conf/global_settings.py:59 msgid "Brazilian" msgstr "" -#: conf/global_settings.py:55 +#: conf/global_settings.py:60 msgid "Romanian" msgstr "" -#: conf/global_settings.py:56 +#: conf/global_settings.py:61 msgid "Russian" msgstr "" -#: conf/global_settings.py:57 +#: conf/global_settings.py:62 msgid "Slovak" msgstr "" -#: conf/global_settings.py:58 +#: conf/global_settings.py:63 msgid "Slovenian" msgstr "" -#: conf/global_settings.py:59 +#: conf/global_settings.py:64 msgid "Serbian" msgstr "" -#: conf/global_settings.py:60 +#: conf/global_settings.py:65 msgid "Swedish" msgstr "" -#: conf/global_settings.py:61 +#: conf/global_settings.py:66 +msgid "Tamil" +msgstr "" + +#: conf/global_settings.py:67 +msgid "Turkish" +msgstr "" + +#: conf/global_settings.py:68 msgid "Ukrainian" msgstr "" -#: conf/global_settings.py:62 +#: conf/global_settings.py:69 msgid "Simplified Chinese" msgstr "" -#: conf/global_settings.py:63 +#: conf/global_settings.py:70 msgid "Traditional Chinese" msgstr "" -#: core/validators.py:60 +#: core/validators.py:63 msgid "This value must contain only letters, numbers and underscores." msgstr "" -#: core/validators.py:64 +#: core/validators.py:67 msgid "" "This value must contain only letters, numbers, underscores, dashes or " "slashes." msgstr "" -#: core/validators.py:72 +#: core/validators.py:71 +msgid "This value must contain only letters, numbers, underscores or hyphens." +msgstr "" + +#: core/validators.py:75 msgid "Uppercase letters are not allowed here." msgstr "" -#: core/validators.py:76 +#: core/validators.py:79 msgid "Lowercase letters are not allowed here." msgstr "" -#: core/validators.py:83 +#: core/validators.py:86 msgid "Enter only digits separated by commas." msgstr "" -#: core/validators.py:95 +#: core/validators.py:98 msgid "Enter valid e-mail addresses separated by commas." msgstr "" -#: core/validators.py:99 +#: core/validators.py:102 msgid "Please enter a valid IP address." msgstr "" -#: core/validators.py:103 +#: core/validators.py:106 msgid "Empty values are not allowed here." msgstr "" -#: core/validators.py:107 +#: core/validators.py:110 msgid "Non-numeric characters aren't allowed here." msgstr "" -#: core/validators.py:111 +#: core/validators.py:114 msgid "This value can't be comprised solely of digits." msgstr "" -#: core/validators.py:116 +#: core/validators.py:119 msgid "Enter a whole number." msgstr "" -#: core/validators.py:120 +#: core/validators.py:123 msgid "Only alphabetical characters are allowed here." msgstr "" -#: core/validators.py:124 +#: core/validators.py:138 +msgid "Year must be 1900 or later." +msgstr "" + +#: core/validators.py:142 +#, python-format +msgid "Invalid date: %s." +msgstr "" + +#: core/validators.py:146 db/models/fields/__init__.py:415 msgid "Enter a valid date in YYYY-MM-DD format." msgstr "" -#: core/validators.py:128 +#: core/validators.py:151 msgid "Enter a valid time in HH:MM format." msgstr "" -#: core/validators.py:132 db/models/fields/__init__.py:468 +#: core/validators.py:155 db/models/fields/__init__.py:477 msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format." msgstr "" -#: core/validators.py:136 +#: core/validators.py:160 msgid "Enter a valid e-mail address." msgstr "" -#: core/validators.py:148 +#: core/validators.py:172 core/validators.py:401 forms/__init__.py:661 +msgid "No file was submitted. Check the encoding type on the form." +msgstr "" + +#: core/validators.py:176 msgid "" "Upload a valid image. The file you uploaded was either not an image or a " "corrupted image." msgstr "" -#: core/validators.py:155 +#: core/validators.py:183 #, python-format msgid "The URL %s does not point to a valid image." msgstr "" -#: core/validators.py:159 +#: core/validators.py:187 #, python-format msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid." msgstr "" -#: core/validators.py:167 +#: core/validators.py:195 #, python-format msgid "The URL %s does not point to a valid QuickTime video." msgstr "" -#: core/validators.py:171 +#: core/validators.py:199 msgid "A valid URL is required." msgstr "" -#: core/validators.py:185 +#: core/validators.py:213 #, python-format msgid "" "Valid HTML is required. Specific errors are:\n" "%s" msgstr "" -#: core/validators.py:192 +#: core/validators.py:220 #, python-format msgid "Badly formed XML: %s" msgstr "" -#: core/validators.py:202 +#: core/validators.py:230 #, python-format msgid "Invalid URL: %s" msgstr "" -#: core/validators.py:206 core/validators.py:208 +#: core/validators.py:234 core/validators.py:236 #, python-format msgid "The URL %s is a broken link." msgstr "" -#: core/validators.py:214 +#: core/validators.py:242 msgid "Enter a valid U.S. state abbreviation." msgstr "" -#: core/validators.py:229 +#: core/validators.py:256 #, python-format msgid "Watch your mouth! The word %s is not allowed here." msgid_plural "Watch your mouth! The words %s are not allowed here." msgstr[0] "" msgstr[1] "" -#: core/validators.py:236 +#: core/validators.py:263 #, python-format msgid "This field must match the '%s' field." msgstr "" -#: core/validators.py:255 +#: core/validators.py:282 msgid "Please enter something for at least one field." msgstr "" -#: core/validators.py:264 core/validators.py:275 +#: core/validators.py:291 core/validators.py:302 msgid "Please enter both fields or leave them both empty." msgstr "" -#: core/validators.py:282 +#: core/validators.py:309 #, python-format msgid "This field must be given if %(field)s is %(value)s" msgstr "" -#: core/validators.py:294 +#: core/validators.py:321 #, python-format msgid "This field must be given if %(field)s is not %(value)s" msgstr "" -#: core/validators.py:313 +#: core/validators.py:340 msgid "Duplicate values are not allowed." msgstr "" -#: core/validators.py:336 +#: core/validators.py:363 #, python-format msgid "This value must be a power of %s." msgstr "" -#: core/validators.py:347 +#: core/validators.py:374 msgid "Please enter a valid decimal number." msgstr "" -#: core/validators.py:349 +#: core/validators.py:378 #, python-format msgid "Please enter a valid decimal number with at most %s total digit." msgid_plural "" @@ -1709,7 +1903,16 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: core/validators.py:352 +#: core/validators.py:381 +#, python-format +msgid "" +"Please enter a valid decimal number with a whole part of at most %s digit." +msgid_plural "" +"Please enter a valid decimal number with a whole part of at most %s digits." +msgstr[0] "" +msgstr[1] "" + +#: core/validators.py:384 #, python-format msgid "Please enter a valid decimal number with at most %s decimal place." msgid_plural "" @@ -1717,77 +1920,92 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: core/validators.py:362 +#: core/validators.py:394 #, python-format msgid "Make sure your uploaded file is at least %s bytes big." msgstr "" -#: core/validators.py:363 +#: core/validators.py:395 #, python-format msgid "Make sure your uploaded file is at most %s bytes big." msgstr "" -#: core/validators.py:376 +#: core/validators.py:412 msgid "The format for this field is wrong." msgstr "" -#: core/validators.py:391 +#: core/validators.py:427 msgid "This field is invalid." msgstr "" -#: core/validators.py:426 +#: core/validators.py:463 #, python-format msgid "Could not retrieve anything from %s." msgstr "" -#: core/validators.py:429 +#: core/validators.py:466 #, python-format msgid "" "The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'." msgstr "" -#: core/validators.py:462 +#: core/validators.py:499 #, python-format msgid "" "Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with " "\"%(start)s\".)" msgstr "" -#: core/validators.py:466 +#: core/validators.py:503 #, python-format msgid "" "Some text starting on line %(line)s is not allowed in that context. (Line " "starts with \"%(start)s\".)" msgstr "" -#: core/validators.py:471 +#: core/validators.py:508 #, python-format msgid "" "\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%" "(start)s\".)" msgstr "" -#: core/validators.py:476 +#: core/validators.py:513 #, python-format msgid "" "\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%" "(start)s\".)" msgstr "" -#: core/validators.py:480 +#: core/validators.py:517 #, python-format msgid "" "A tag on line %(line)s is missing one or more required attributes. (Line " "starts with \"%(start)s\".)" msgstr "" -#: core/validators.py:485 +#: core/validators.py:522 #, python-format msgid "" "The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line " "starts with \"%(start)s\".)" msgstr "" +#: views/generic/create_update.py:43 +#, python-format +msgid "The %(verbose_name)s was created successfully." +msgstr "" + +#: views/generic/create_update.py:117 +#, python-format +msgid "The %(verbose_name)s was updated successfully." +msgstr "" + +#: views/generic/create_update.py:184 +#, python-format +msgid "The %(verbose_name)s was deleted." +msgstr "" + #: db/models/manipulators.py:302 #, python-format msgid "%(object)s with this %(type)s already exists for the given %(field)s." @@ -1799,42 +2017,42 @@ msgid "%(optname)s with this %(fieldname)s already exists." msgstr "" #: db/models/fields/__init__.py:114 db/models/fields/__init__.py:265 -#: db/models/fields/__init__.py:542 db/models/fields/__init__.py:553 +#: db/models/fields/__init__.py:551 db/models/fields/__init__.py:562 #: forms/__init__.py:346 msgid "This field is required." msgstr "" -#: db/models/fields/__init__.py:337 +#: db/models/fields/__init__.py:340 msgid "This value must be an integer." msgstr "" -#: db/models/fields/__init__.py:369 +#: db/models/fields/__init__.py:372 msgid "This value must be either True or False." msgstr "" -#: db/models/fields/__init__.py:385 +#: db/models/fields/__init__.py:388 msgid "This field cannot be null." msgstr "" -#: db/models/fields/__init__.py:562 +#: db/models/fields/__init__.py:571 msgid "Enter a valid filename." msgstr "" -#: db/models/fields/related.py:43 +#: db/models/fields/related.py:51 #, python-format msgid "Please enter a valid %s." msgstr "" -#: db/models/fields/related.py:579 +#: db/models/fields/related.py:618 msgid "Separate multiple IDs with commas." msgstr "" -#: db/models/fields/related.py:581 +#: db/models/fields/related.py:620 msgid "" "Hold down \"Control\", or \"Command\" on a Mac, to select more than one." msgstr "" -#: db/models/fields/related.py:625 +#: db/models/fields/related.py:664 #, python-format msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid." msgid_plural "" @@ -1842,38 +2060,38 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: forms/__init__.py:380 +#: forms/__init__.py:381 #, python-format msgid "Ensure your text is less than %s character." msgid_plural "Ensure your text is less than %s characters." msgstr[0] "" msgstr[1] "" -#: forms/__init__.py:385 +#: forms/__init__.py:386 msgid "Line breaks are not allowed here." msgstr "" -#: forms/__init__.py:480 forms/__init__.py:551 forms/__init__.py:589 +#: forms/__init__.py:487 forms/__init__.py:560 forms/__init__.py:599 #, python-format msgid "Select a valid choice; '%(data)s' is not in %(choices)s." msgstr "" -#: forms/__init__.py:645 +#: forms/__init__.py:663 msgid "The submitted file is empty." msgstr "" -#: forms/__init__.py:699 +#: forms/__init__.py:719 msgid "Enter a whole number between -32,768 and 32,767." msgstr "" -#: forms/__init__.py:708 +#: forms/__init__.py:729 msgid "Enter a positive number." msgstr "" -#: forms/__init__.py:717 +#: forms/__init__.py:739 msgid "Enter a whole number between 0 and 32,767." msgstr "" -#: template/defaultfilters.py:379 +#: template/defaultfilters.py:401 msgid "yes,no,maybe" msgstr "" diff --git a/django/conf/locale/es_AR/LC_MESSAGES/django.mo b/django/conf/locale/es_AR/LC_MESSAGES/django.mo Binary files differindex f550fca3db..dd96bf99ce 100644 --- a/django/conf/locale/es_AR/LC_MESSAGES/django.mo +++ b/django/conf/locale/es_AR/LC_MESSAGES/django.mo diff --git a/django/conf/locale/es_AR/LC_MESSAGES/django.po b/django/conf/locale/es_AR/LC_MESSAGES/django.po index 8af7c42e5e..e5169e9c4a 100644 --- a/django/conf/locale/es_AR/LC_MESSAGES/django.po +++ b/django/conf/locale/es_AR/LC_MESSAGES/django.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: django\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2006-06-19 11:19-0300\n" -"PO-Revision-Date: 2006-05-16 10:05-0300\n" +"POT-Creation-Date: 2006-08-18 18:57-0300\n" +"PO-Revision-Date: 2006-08-21 18:06-0300\n" "Last-Translator: Ramiro Morales <rm0@gmx.net>\n" "Language-Team: Spanish <es@li.org>\n" "MIME-Version: 1.0\n" @@ -17,15 +17,15 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: contrib/contenttypes/models.py:25 +#: contrib/contenttypes/models.py:20 msgid "python model class name" msgstr "nombre de la clase python del modelo" -#: contrib/contenttypes/models.py:28 +#: contrib/contenttypes/models.py:23 msgid "content type" msgstr "tipo de contenido" -#: contrib/contenttypes/models.py:29 +#: contrib/contenttypes/models.py:24 msgid "content types" msgstr "tipos de contenido" @@ -33,79 +33,103 @@ msgstr "tipos de contenido" msgid "Logged out" msgstr "Sesión cerrada" -#: contrib/auth/models.py:13 contrib/auth/models.py:26 +#: contrib/auth/models.py:38 contrib/auth/models.py:57 msgid "name" msgstr "nombre" -#: contrib/auth/models.py:15 +#: contrib/auth/models.py:40 msgid "codename" msgstr "nombre en código" -#: contrib/auth/models.py:17 +#: contrib/auth/models.py:42 msgid "permission" msgstr "permiso" -#: contrib/auth/models.py:18 contrib/auth/models.py:27 +#: contrib/auth/models.py:43 contrib/auth/models.py:58 msgid "permissions" msgstr "permisos" -#: contrib/auth/models.py:29 +#: contrib/auth/models.py:60 msgid "group" msgstr "grupo" -#: contrib/auth/models.py:30 contrib/auth/models.py:65 +#: contrib/auth/models.py:61 contrib/auth/models.py:100 msgid "groups" msgstr "grupos" -#: contrib/auth/models.py:55 +#: contrib/auth/models.py:90 msgid "username" msgstr "nombre de usuario" -#: contrib/auth/models.py:56 +#: contrib/auth/models.py:90 +msgid "" +"Required. 30 characters or fewer. Alphanumeric characters only (letters, " +"digits and underscores)." +msgstr "" +"Requerido. Longitud máxima 30 caracteres alfanuméricos (letras, dígitos y " +"guiones bajos)." + +#: contrib/auth/models.py:91 msgid "first name" msgstr "nombre" -#: contrib/auth/models.py:57 +#: contrib/auth/models.py:92 msgid "last name" msgstr "apellido" -#: contrib/auth/models.py:58 +#: contrib/auth/models.py:93 msgid "e-mail address" msgstr "dirección de correo" -#: contrib/auth/models.py:59 +#: contrib/auth/models.py:94 msgid "password" msgstr "contraseña" -#: contrib/auth/models.py:59 +#: contrib/auth/models.py:94 msgid "Use '[algo]$[salt]$[hexdigest]'" msgstr "Use '[algoritmo]$[salt]$[hexdigest]'" -#: contrib/auth/models.py:60 +#: contrib/auth/models.py:95 msgid "staff status" msgstr "es staff" -#: contrib/auth/models.py:60 +#: contrib/auth/models.py:95 msgid "Designates whether the user can log into this admin site." msgstr "Indica si el usuario puede ingresar a este sitio de administración." -#: contrib/auth/models.py:61 +#: contrib/auth/models.py:96 msgid "active" msgstr "activo" -#: contrib/auth/models.py:62 +#: contrib/auth/models.py:96 +msgid "" +"Designates whether this user can log into the Django admin. Unselect this " +"instead of deleting accounts." +msgstr "" +"Indica si el usuario puede ingresar al sitio de administración Django." +"Desactive este campo en lugar de eliminar usuarios." + +#: contrib/auth/models.py:97 msgid "superuser status" msgstr "es superusuario" -#: contrib/auth/models.py:63 +#: contrib/auth/models.py:97 +msgid "" +"Designates that this user has all permissions without explicitly assigning " +"them." +msgstr "" +"Indica que este usuario posee todos los permisos, sin asignarle los mismos " +"explícitamente." + +#: contrib/auth/models.py:98 msgid "last login" msgstr "último registro" -#: contrib/auth/models.py:64 +#: contrib/auth/models.py:99 msgid "date joined" msgstr "fecha de creación" -#: contrib/auth/models.py:66 +#: contrib/auth/models.py:101 msgid "" "In addition to the permissions manually assigned, this user will also get " "all permissions granted to each group he/she is in." @@ -113,39 +137,39 @@ msgstr "" "Además de los permisos asignados manualmente, este usuario también poseerá " "todos los permisos de los grupos a los que pertenezca." -#: contrib/auth/models.py:67 +#: contrib/auth/models.py:102 msgid "user permissions" msgstr "permisos de usuario" -#: contrib/auth/models.py:70 +#: contrib/auth/models.py:105 msgid "user" msgstr "usuario" -#: contrib/auth/models.py:71 +#: contrib/auth/models.py:106 msgid "users" msgstr "usuarios" -#: contrib/auth/models.py:76 +#: contrib/auth/models.py:111 msgid "Personal info" msgstr "Información personal" -#: contrib/auth/models.py:77 +#: contrib/auth/models.py:112 msgid "Permissions" msgstr "Permisos" -#: contrib/auth/models.py:78 +#: contrib/auth/models.py:113 msgid "Important dates" msgstr "Fechas importantes" -#: contrib/auth/models.py:79 +#: contrib/auth/models.py:114 msgid "Groups" msgstr "Grupos" -#: contrib/auth/models.py:219 +#: contrib/auth/models.py:256 msgid "message" msgstr "mensaje" -#: contrib/auth/forms.py:30 +#: contrib/auth/forms.py:52 msgid "" "Your Web browser doesn't appear to have cookies enabled. Cookies are " "required for logging in." @@ -153,8 +177,7 @@ msgstr "" "Su navegador Web aparenta no tener cookies activas. Las cookies son un " "requerimiento para poder ingresar." -#: contrib/auth/forms.py:36 contrib/auth/forms.py:43 -#: contrib/admin/views/decorators.py:9 +#: contrib/auth/forms.py:59 contrib/admin/views/decorators.py:10 msgid "" "Please enter a correct username and password. Note that both fields are case-" "sensitive." @@ -162,7 +185,7 @@ msgstr "" "Por favor ingrese un nombre de usuario y una contraseña correctos. Note que " "ambos campos son sensibles a mayúsculas/minúsculas." -#: contrib/auth/forms.py:45 +#: contrib/auth/forms.py:61 msgid "This account is inactive." msgstr "Esta cuenta está inactiva" @@ -255,7 +278,7 @@ msgstr "fecha/hora de envío" msgid "is public" msgstr "es público" -#: contrib/comments/models.py:85 contrib/admin/views/doc.py:292 +#: contrib/comments/models.py:85 contrib/admin/views/doc.py:304 msgid "IP address" msgstr "Dirección IP" @@ -392,12 +415,12 @@ msgstr "ID de comentario no válido" msgid "No voting for yourself" msgstr "No puedes votarte tú mismo" -#: contrib/comments/views/comments.py:28 +#: contrib/comments/views/comments.py:27 msgid "" "This rating is required because you've entered at least one other rating." msgstr "Se precisa esta puntuación porque ha introducido al menos otra más." -#: contrib/comments/views/comments.py:112 +#: contrib/comments/views/comments.py:111 #, python-format msgid "" "This comment was posted by a user who has posted fewer than %(count)s " @@ -420,7 +443,7 @@ msgstr[1] "" "\n" "%(text)s" -#: contrib/comments/views/comments.py:117 +#: contrib/comments/views/comments.py:116 #, fuzzy, python-format msgid "" "This comment was posted by a sketchy user:\n" @@ -431,24 +454,24 @@ msgstr "" "\n" "%(text)s" -#: contrib/comments/views/comments.py:189 +#: contrib/comments/views/comments.py:188 #: contrib/comments/views/comments.py:280 msgid "Only POSTs are allowed" msgstr "Sólo se admiten POSTs" -#: contrib/comments/views/comments.py:193 +#: contrib/comments/views/comments.py:192 #: contrib/comments/views/comments.py:284 msgid "One or more of the required fields wasn't submitted" msgstr "No se proporcionó uno o más de los siguientes campos requeridos" -#: contrib/comments/views/comments.py:197 +#: contrib/comments/views/comments.py:196 #: contrib/comments/views/comments.py:286 msgid "Somebody tampered with the comment form (security violation)" msgstr "" "Alguien está jugando con el formulario de comentarios (violación de " "seguridad)" -#: contrib/comments/views/comments.py:207 +#: contrib/comments/views/comments.py:206 #: contrib/comments/views/comments.py:292 msgid "" "The comment form had an invalid 'target' parameter -- the object ID was " @@ -467,12 +490,12 @@ msgid "Your name:" msgstr "Su nombre:" #: contrib/comments/templates/comments/freeform.html:5 -#: contrib/comments/templates/comments/form.html:27 +#: contrib/comments/templates/comments/form.html:28 msgid "Comment:" msgstr "Comentario:" -#: contrib/comments/templates/comments/freeform.html:9 -#: contrib/comments/templates/comments/form.html:32 +#: contrib/comments/templates/comments/freeform.html:10 +#: contrib/comments/templates/comments/form.html:35 msgid "Preview comment" msgstr "Previsualizar comentario" @@ -483,19 +506,10 @@ msgid "Username:" msgstr "Usuario:" #: contrib/comments/templates/comments/form.html:6 -#: contrib/admin/templates/admin/login.html:20 -msgid "Password:" -msgstr "Contraseña:" - -#: contrib/comments/templates/comments/form.html:6 -msgid "Forgotten your password?" -msgstr "Olvidó su contraseña?" - -#: contrib/comments/templates/comments/form.html:8 #: contrib/admin/templates/admin/object_history.html:3 #: contrib/admin/templates/admin/change_list.html:5 #: contrib/admin/templates/admin/change_form.html:10 -#: contrib/admin/templates/admin/base.html:24 +#: contrib/admin/templates/admin/base.html:25 #: contrib/admin/templates/admin/delete_confirmation.html:3 #: contrib/admin/templates/registration/password_change_done.html:3 #: contrib/admin/templates/registration/password_change_form.html:3 @@ -512,6 +526,15 @@ msgstr "Olvidó su contraseña?" msgid "Log out" msgstr "Cerrar sesión" +#: contrib/comments/templates/comments/form.html:8 +#: contrib/admin/templates/admin/login.html:20 +msgid "Password:" +msgstr "Contraseña:" + +#: contrib/comments/templates/comments/form.html:8 +msgid "Forgotten your password?" +msgstr "Olvidó su contraseña?" + #: contrib/comments/templates/comments/form.html:12 msgid "Ratings" msgstr "Calificaciones" @@ -530,7 +553,7 @@ msgstr "Opcional" msgid "Post a photo" msgstr "Enviar una foto" -#: contrib/flatpages/models.py:7 contrib/admin/views/doc.py:303 +#: contrib/flatpages/models.py:7 contrib/admin/views/doc.py:315 msgid "URL" msgstr "URL" @@ -559,11 +582,11 @@ msgstr "nombre de plantilla" #: contrib/flatpages/models.py:13 msgid "" -"Example: 'flatpages/contact_page'. If this isn't provided, the system will " -"use 'flatpages/default'." +"Example: 'flatpages/contact_page.html'. If this isn't provided, the system " +"will use 'flatpages/default.html'." msgstr "" -"Ejemplo: 'flatpages/contact_page'. Si no lo proporciona, el sistema usará " -"'flatpages/default'." +"Ejemplo: 'flatpages/contact_page.html'. Si no lo proporciona, el sistema " +"usará 'flatpages/default.html'." #: contrib/flatpages/models.py:14 msgid "registration required" @@ -581,23 +604,23 @@ msgstr "página estática" msgid "flat pages" msgstr "páginas estáticas" -#: contrib/sessions/models.py:35 +#: contrib/sessions/models.py:51 msgid "session key" msgstr "clave de sesión" -#: contrib/sessions/models.py:36 +#: contrib/sessions/models.py:52 msgid "session data" msgstr "datos de sesión" -#: contrib/sessions/models.py:37 +#: contrib/sessions/models.py:53 msgid "expire date" msgstr "fecha de caducidad" -#: contrib/sessions/models.py:41 +#: contrib/sessions/models.py:57 msgid "session" msgstr "sesión" -#: contrib/sessions/models.py:42 +#: contrib/sessions/models.py:58 msgid "sessions" msgstr "sesiones" @@ -695,12 +718,12 @@ msgstr "entradas de registro" msgid "All dates" msgstr "Todas las fechas" -#: contrib/admin/views/decorators.py:23 +#: contrib/admin/views/decorators.py:24 #: contrib/admin/templates/admin/login.html:25 msgid "Log in" msgstr "Identificarse" -#: contrib/admin/views/decorators.py:61 +#: contrib/admin/views/decorators.py:62 msgid "" "Please log in again, because your session has expired. Don't worry: Your " "submission has been saved." @@ -708,7 +731,7 @@ msgstr "" "Por favor, identifíquese de nuevo porque su sesión ha caducado. No se " "preocupe: se ha guardado su envío." -#: contrib/admin/views/decorators.py:68 +#: contrib/admin/views/decorators.py:69 msgid "" "Looks like your browser isn't configured to accept cookies. Please enable " "cookies, reload this page, and try again." @@ -716,187 +739,253 @@ msgstr "" "Parece que su navegador no está configurado para aceptar cookies. Actívelas " "por favor, recargue esta página, e inténtelo de nuevo." -#: contrib/admin/views/decorators.py:82 +#: contrib/admin/views/decorators.py:83 msgid "Usernames cannot contain the '@' character." msgstr "Los nombres de usuario no pueden contener el carácter '@'." -#: contrib/admin/views/decorators.py:84 +#: contrib/admin/views/decorators.py:85 #, python-format msgid "Your e-mail address is not your username. Try '%s' instead." msgstr "" "Su dirección de correo no es su nombre de usuario. Pruebe con '%s' en su " "lugar." -#: contrib/admin/views/main.py:226 +#: contrib/admin/views/main.py:223 msgid "Site administration" msgstr "Sitio administrativo" -#: contrib/admin/views/main.py:260 +#: contrib/admin/views/main.py:257 contrib/admin/views/auth.py:14 #, python-format msgid "The %(name)s \"%(obj)s\" was added successfully." -msgstr "Se añadió con éxito el %(name)s \"%(obj)s\"." +msgstr "Se agregó con éxito el %(name)s \"%(obj)s\"." -#: contrib/admin/views/main.py:264 contrib/admin/views/main.py:348 +#: contrib/admin/views/main.py:261 contrib/admin/views/main.py:347 +#: contrib/admin/views/auth.py:19 msgid "You may edit it again below." -msgstr "Puede editarlo de nuevo abajo." +msgstr "Puede modificarlo nuevamente abajo." -#: contrib/admin/views/main.py:272 contrib/admin/views/main.py:357 +#: contrib/admin/views/main.py:271 contrib/admin/views/main.py:356 #, python-format msgid "You may add another %s below." msgstr "Puede agregar otro %s abajo." -#: contrib/admin/views/main.py:290 +#: contrib/admin/views/main.py:289 #, python-format msgid "Add %s" msgstr "Agregar %s" -#: contrib/admin/views/main.py:336 +#: contrib/admin/views/main.py:335 #, python-format msgid "Added %s." msgstr "Agregado %s." -#: contrib/admin/views/main.py:336 contrib/admin/views/main.py:338 -#: contrib/admin/views/main.py:340 +#: contrib/admin/views/main.py:335 contrib/admin/views/main.py:337 +#: contrib/admin/views/main.py:339 msgid "and" msgstr "y" -#: contrib/admin/views/main.py:338 +#: contrib/admin/views/main.py:337 #, python-format msgid "Changed %s." msgstr "Modifica %s." -#: contrib/admin/views/main.py:340 +#: contrib/admin/views/main.py:339 #, python-format msgid "Deleted %s." msgstr "Elimina %s." -#: contrib/admin/views/main.py:343 +#: contrib/admin/views/main.py:342 msgid "No fields changed." -msgstr "No ha cambiado ningún campo." +msgstr "No ha modificado ningún campo." -#: contrib/admin/views/main.py:346 +#: contrib/admin/views/main.py:345 #, python-format msgid "The %(name)s \"%(obj)s\" was changed successfully." msgstr "Se modificó con éxito el %(name)s \"%(obj)s." -#: contrib/admin/views/main.py:354 +#: contrib/admin/views/main.py:353 #, python-format msgid "" "The %(name)s \"%(obj)s\" was added successfully. You may edit it again below." msgstr "" -"Se agregó con éxito el %(name)s \"%(obj)s. Puede editarlo de nuevo abajo." +"Se agregó con éxito el %(name)s \"%(obj)s. Puede modificarlo nuevamente " +"abajo." -#: contrib/admin/views/main.py:392 +#: contrib/admin/views/main.py:391 #, python-format msgid "Change %s" msgstr "Modificar %s" -#: contrib/admin/views/main.py:470 +#: contrib/admin/views/main.py:473 #, python-format msgid "One or more %(fieldname)s in %(name)s: %(obj)s" msgstr "Uno o más %(fieldname)s en %(name)s: %(obj)s" -#: contrib/admin/views/main.py:475 +#: contrib/admin/views/main.py:478 #, python-format msgid "One or more %(fieldname)s in %(name)s:" msgstr "Uno o más %(fieldname)s en %(name)s:" -#: contrib/admin/views/main.py:508 +#: contrib/admin/views/main.py:511 #, python-format msgid "The %(name)s \"%(obj)s\" was deleted successfully." msgstr "Se eliminó con éxito el %(name)s \"%(obj)s\"." -#: contrib/admin/views/main.py:511 +#: contrib/admin/views/main.py:514 msgid "Are you sure?" msgstr "¿Está seguro?" -#: contrib/admin/views/main.py:533 +#: contrib/admin/views/main.py:536 #, python-format msgid "Change history: %s" msgstr "Historia de modificaciones: %s" -#: contrib/admin/views/main.py:567 +#: contrib/admin/views/main.py:570 #, python-format msgid "Select %s" msgstr "Seleccione %s" -#: contrib/admin/views/main.py:567 +#: contrib/admin/views/main.py:570 #, python-format msgid "Select %s to change" msgstr "Seleccione %s a modificar" -#: contrib/admin/views/main.py:743 +#: contrib/admin/views/main.py:756 msgid "Database error" msgstr "Error de base de datos" -#: contrib/admin/views/doc.py:279 contrib/admin/views/doc.py:289 -#: contrib/admin/views/doc.py:291 contrib/admin/views/doc.py:297 -#: contrib/admin/views/doc.py:298 contrib/admin/views/doc.py:300 +#: contrib/admin/views/doc.py:46 contrib/admin/views/doc.py:48 +#: contrib/admin/views/doc.py:50 +msgid "tag:" +msgstr "etiqueta:" + +#: contrib/admin/views/doc.py:77 contrib/admin/views/doc.py:79 +#: contrib/admin/views/doc.py:81 +msgid "filter:" +msgstr "Filtrar:" + +#: contrib/admin/views/doc.py:135 contrib/admin/views/doc.py:137 +#: contrib/admin/views/doc.py:139 +msgid "view:" +msgstr "ver:" + +#: contrib/admin/views/doc.py:164 +#, python-format +msgid "App %r not found" +msgstr "App %r no encontrada" + +#: contrib/admin/views/doc.py:171 +#, python-format +msgid "Model %r not found in app %r" +msgstr "Modelo %r no encontrado en app %r" + +#: contrib/admin/views/doc.py:183 +#, python-format +msgid "the related `%s.%s` object" +msgstr "El objeto relacionado `%s.%s`" + +#: contrib/admin/views/doc.py:183 contrib/admin/views/doc.py:205 +#: contrib/admin/views/doc.py:219 contrib/admin/views/doc.py:224 +msgid "model:" +msgstr "modelo:" + +#: contrib/admin/views/doc.py:214 +#, python-format +msgid "related `%s.%s` objects" +msgstr "objetos relacionados `%s.%s`" + +#: contrib/admin/views/doc.py:219 +#, python-format +msgid "all %s" +msgstr "todos %s" + +#: contrib/admin/views/doc.py:224 +#, python-format +msgid "number of %s" +msgstr "número de %s" + +#: contrib/admin/views/doc.py:229 +#, python-format +msgid "Fields on %s objects" +msgstr "Capos en %s objetos" + +#: contrib/admin/views/doc.py:291 contrib/admin/views/doc.py:301 +#: contrib/admin/views/doc.py:303 contrib/admin/views/doc.py:309 +#: contrib/admin/views/doc.py:310 contrib/admin/views/doc.py:312 msgid "Integer" msgstr "Entero" -#: contrib/admin/views/doc.py:280 +#: contrib/admin/views/doc.py:292 msgid "Boolean (Either True or False)" msgstr "Booleano (Verdadero o Falso)" -#: contrib/admin/views/doc.py:281 contrib/admin/views/doc.py:299 +#: contrib/admin/views/doc.py:293 contrib/admin/views/doc.py:311 #, python-format msgid "String (up to %(maxlength)s)" msgstr "Cadena (máximo %(maxlength)s)" -#: contrib/admin/views/doc.py:282 +#: contrib/admin/views/doc.py:294 msgid "Comma-separated integers" msgstr "Enteros separados por comas" -#: contrib/admin/views/doc.py:283 +#: contrib/admin/views/doc.py:295 msgid "Date (without time)" msgstr "Fecha (sin hora)" -#: contrib/admin/views/doc.py:284 +#: contrib/admin/views/doc.py:296 msgid "Date (with time)" msgstr "Fecha (con hora)" -#: contrib/admin/views/doc.py:285 +#: contrib/admin/views/doc.py:297 msgid "E-mail address" msgstr "Dirección de correo electrónico" -#: contrib/admin/views/doc.py:286 contrib/admin/views/doc.py:287 -#: contrib/admin/views/doc.py:290 +#: contrib/admin/views/doc.py:298 contrib/admin/views/doc.py:299 +#: contrib/admin/views/doc.py:302 msgid "File path" msgstr "Ruta de archivo" -#: contrib/admin/views/doc.py:288 +#: contrib/admin/views/doc.py:300 msgid "Decimal number" msgstr "Número decimal" -#: contrib/admin/views/doc.py:294 +#: contrib/admin/views/doc.py:306 msgid "Boolean (Either True, False or None)" msgstr "Booleano (Verdadero, Falso o Nulo)" -#: contrib/admin/views/doc.py:295 +#: contrib/admin/views/doc.py:307 msgid "Relation to parent model" msgstr "Relación con el modelo padre" -#: contrib/admin/views/doc.py:296 +#: contrib/admin/views/doc.py:308 msgid "Phone number" msgstr "Número de teléfono" -#: contrib/admin/views/doc.py:301 +#: contrib/admin/views/doc.py:313 msgid "Text" msgstr "Texto" -#: contrib/admin/views/doc.py:302 +#: contrib/admin/views/doc.py:314 msgid "Time" msgstr "Hora" -#: contrib/admin/views/doc.py:304 +#: contrib/admin/views/doc.py:316 msgid "U.S. state (two uppercase letters)" msgstr "Estado de los EEUU (dos letras mayúsculas)" -#: contrib/admin/views/doc.py:305 +#: contrib/admin/views/doc.py:317 msgid "XML text" msgstr "Texto XML" +#: contrib/admin/views/doc.py:339 +#, python-format +msgid "%s does not appear to be a urlpattern object" +msgstr "%s no parece ser un objeto urlpattern" + +#: contrib/admin/views/auth.py:25 +msgid "Add user" +msgstr "Agregar usuario" + #: contrib/admin/templates/widget/file.html:2 msgid "Currently:" msgstr "Actualmente" @@ -916,7 +1005,7 @@ msgstr "Hora:" #: contrib/admin/templates/admin/object_history.html:3 #: contrib/admin/templates/admin/change_list.html:5 #: contrib/admin/templates/admin/change_form.html:10 -#: contrib/admin/templates/admin/base.html:24 +#: contrib/admin/templates/admin/base.html:25 #: contrib/admin/templates/admin/delete_confirmation.html:3 #: contrib/admin/templates/registration/password_change_done.html:3 #: contrib/admin/templates/registration/password_change_form.html:3 @@ -927,7 +1016,7 @@ msgstr "Documentación" #: contrib/admin/templates/admin/object_history.html:3 #: contrib/admin/templates/admin/change_list.html:5 #: contrib/admin/templates/admin/change_form.html:10 -#: contrib/admin/templates/admin/base.html:24 +#: contrib/admin/templates/admin/base.html:25 #: contrib/admin/templates/admin/delete_confirmation.html:3 #: contrib/admin/templates/registration/password_change_done.html:3 #: contrib/admin/templates/registration/password_change_form.html:3 @@ -948,7 +1037,7 @@ msgstr "Cambiar contraseña" #: contrib/admin/templates/admin/change_list.html:6 #: contrib/admin/templates/admin/500.html:4 #: contrib/admin/templates/admin/change_form.html:13 -#: contrib/admin/templates/admin/base.html:29 +#: contrib/admin/templates/admin/base.html:30 #: contrib/admin/templates/admin/delete_confirmation.html:6 #: contrib/admin/templates/admin/invalid_setup.html:4 #: contrib/admin/templates/registration/password_change_done.html:4 @@ -996,8 +1085,8 @@ msgstr "Agregar %(name)s" #: contrib/admin/templates/admin/filter.html:2 #, python-format -msgid " By %(title)s " -msgstr " Por %(title)s " +msgid " By %(filter_title)s " +msgstr " Por %(filter_title)s " #: contrib/admin/templates/admin/500.html:4 msgid "Server error" @@ -1053,6 +1142,11 @@ msgstr "Administración de Django" msgid "Models available in the %(name)s application." msgstr "Modelos disponibles en la aplicación %(name)s." +#: contrib/admin/templates/admin/index.html:18 +#, python-format +msgid "%(name)s" +msgstr "%(name)s" + #: contrib/admin/templates/admin/index.html:28 #: contrib/admin/templates/admin/change_form.html:15 msgid "Add" @@ -1113,7 +1207,7 @@ msgstr "Ordenación" msgid "Order:" msgstr "Orden:" -#: contrib/admin/templates/admin/base.html:24 +#: contrib/admin/templates/admin/base.html:25 msgid "Welcome," msgstr "Bienvenido," @@ -1125,22 +1219,22 @@ msgstr "Eliminar" #: contrib/admin/templates/admin/delete_confirmation.html:14 #, python-format msgid "" -"Deleting the %(object_name)s '%(object)s' would result in deleting related " -"objects, but your account doesn't have permission to delete the following " -"types of objects:" +"Deleting the %(object_name)s '%(escaped_object)s' would result in deleting " +"related objects, but your account doesn't have permission to delete the " +"following types of objects:" msgstr "" -"Eliminar el %(object_name)s '%(object)s' provocaría la eliminación de " -"objetos relacionados, pero su cuenta no tiene permiso para eliminar los " +"Eliminar el %(object_name)s '%(escaped_object)s' provocaría la eliminación " +"de objetos relacionados, pero su cuenta no tiene permiso para eliminar los " "siguientes tipos de objetos:" #: contrib/admin/templates/admin/delete_confirmation.html:21 #, python-format msgid "" -"Are you sure you want to delete the %(object_name)s \"%(object)s\"? All of " -"the following related items will be deleted:" +"Are you sure you want to delete the %(object_name)s \"%(escaped_object)s\"? " +"All of the following related items will be deleted:" msgstr "" -"¿Está seguro de que quiere eliminar los %(object_name)s \"%(object)s\"? Se " -"eliminarán los siguientes objetos relacionados:" +"¿Está seguro de que quiere eliminar los %(object_name)s \"%(escaped_object)s" +"\"? Se eliminarán los siguientes objetos relacionados:" #: contrib/admin/templates/admin/delete_confirmation.html:26 msgid "Yes, I'm sure" @@ -1172,6 +1266,30 @@ msgstr "" "tablas de la misma hayan sido creadas, y asegúrese de que el usuario " "apropiado tenga permisos de escritura en la base de datos." +#: contrib/admin/templates/admin/auth/user/add_form.html:6 +msgid "" +"First, enter a username and password. Then, you'll be able to edit more user " +"options." +msgstr "" +"Primero, ingrese un nombre de usuario y una contraseña. Luego podrá " +"configurar opciones adicionales." + +#: contrib/admin/templates/admin/auth/user/add_form.html:12 +msgid "Username" +msgstr "Nombre de usuario:" + +#: contrib/admin/templates/admin/auth/user/add_form.html:18 +msgid "Password" +msgstr "Contraseña:" + +#: contrib/admin/templates/admin/auth/user/add_form.html:23 +msgid "Password (again)" +msgstr "Contraseña (de nuevo)" + +#: contrib/admin/templates/admin/auth/user/add_form.html:24 +msgid "Enter the same password as above, for verification." +msgstr "Para verificación, ingrese la misma contraseña que ingresó arriba." + #: contrib/admin/templates/registration/password_change_done.html:4 #: contrib/admin/templates/registration/password_change_form.html:4 #: contrib/admin/templates/registration/password_change_form.html:6 @@ -1359,26 +1477,6 @@ msgid "As above, but opens the admin page in a new window." msgstr "" "Como antes, pero abre la página de administración en una nueva ventana." -#: utils/translation.py:363 -msgid "DATE_FORMAT" -msgstr "j N Y" - -#: utils/translation.py:364 -msgid "DATETIME_FORMAT" -msgstr "j N Y P" - -#: utils/translation.py:365 -msgid "TIME_FORMAT" -msgstr "P" - -#: utils/translation.py:381 -msgid "YEAR_MONTH_FORMAT" -msgstr "F Y" - -#: utils/translation.py:382 -msgid "MONTH_DAY_FORMAT" -msgstr "j \\de F" - #: utils/dates.py:6 msgid "Monday" msgstr "Lunes" @@ -1567,115 +1665,143 @@ msgid_plural "minutes" msgstr[0] "minuto" msgstr[1] "minutos" -#: conf/global_settings.py:37 +#: utils/translation/trans_real.py:362 +msgid "DATE_FORMAT" +msgstr "j N Y" + +#: utils/translation/trans_real.py:363 +msgid "DATETIME_FORMAT" +msgstr "j N Y P" + +#: utils/translation/trans_real.py:364 +msgid "TIME_FORMAT" +msgstr "P" + +#: utils/translation/trans_real.py:380 +msgid "YEAR_MONTH_FORMAT" +msgstr "F Y" + +#: utils/translation/trans_real.py:381 +msgid "MONTH_DAY_FORMAT" +msgstr "j \\de F" + +#: conf/global_settings.py:39 +msgid "Arabic" +msgstr "Árabe" + +#: conf/global_settings.py:40 msgid "Bengali" msgstr "Bengalí" -#: conf/global_settings.py:38 +#: conf/global_settings.py:41 msgid "Czech" msgstr "Checo" -#: conf/global_settings.py:39 +#: conf/global_settings.py:42 msgid "Welsh" msgstr "Galés" -#: conf/global_settings.py:40 +#: conf/global_settings.py:43 msgid "Danish" msgstr "Danés" -#: conf/global_settings.py:41 +#: conf/global_settings.py:44 msgid "German" msgstr "Alemán" -#: conf/global_settings.py:42 +#: conf/global_settings.py:45 msgid "Greek" msgstr "Griego" -#: conf/global_settings.py:43 +#: conf/global_settings.py:46 msgid "English" msgstr "Inglés" -#: conf/global_settings.py:44 +#: conf/global_settings.py:47 msgid "Spanish" msgstr "Español" -#: conf/global_settings.py:45 +#: conf/global_settings.py:48 msgid "Argentinean Spanish" msgstr "Español Argentino" -#: conf/global_settings.py:46 +#: conf/global_settings.py:49 msgid "French" msgstr "Francés" -#: conf/global_settings.py:47 +#: conf/global_settings.py:50 msgid "Galician" msgstr "Gallego" -#: conf/global_settings.py:48 +#: conf/global_settings.py:51 msgid "Hungarian" msgstr "Húngaro" -#: conf/global_settings.py:49 +#: conf/global_settings.py:52 msgid "Hebrew" msgstr "Hebreo" -#: conf/global_settings.py:50 +#: conf/global_settings.py:53 msgid "Icelandic" msgstr "Islandés" -#: conf/global_settings.py:51 +#: conf/global_settings.py:54 msgid "Italian" msgstr "Italiano" -#: conf/global_settings.py:52 +#: conf/global_settings.py:55 msgid "Japanese" msgstr "Japonés" -#: conf/global_settings.py:53 +#: conf/global_settings.py:56 msgid "Dutch" msgstr "Holandés" -#: conf/global_settings.py:54 +#: conf/global_settings.py:57 msgid "Norwegian" msgstr "Noruego" -#: conf/global_settings.py:55 +#: conf/global_settings.py:58 msgid "Brazilian" msgstr "Brasileño" -#: conf/global_settings.py:56 +#: conf/global_settings.py:59 msgid "Romanian" msgstr "Rumano" -#: conf/global_settings.py:57 +#: conf/global_settings.py:60 msgid "Russian" msgstr "Ruso" -#: conf/global_settings.py:58 +#: conf/global_settings.py:61 msgid "Slovak" msgstr "Eslovaco" -#: conf/global_settings.py:59 +#: conf/global_settings.py:62 msgid "Slovenian" msgstr "Esloveno" -#: conf/global_settings.py:60 +#: conf/global_settings.py:63 msgid "Serbian" msgstr "Serbio" -#: conf/global_settings.py:61 +#: conf/global_settings.py:64 msgid "Swedish" msgstr "Sueco" -#: conf/global_settings.py:62 +#: conf/global_settings.py:65 +msgid "Tamil" +msgstr "Tamil" + +#: conf/global_settings.py:66 msgid "Ukrainian" msgstr "Ucraniano" -#: conf/global_settings.py:63 +#: conf/global_settings.py:67 msgid "Simplified Chinese" msgstr "Chino simplificado" -#: conf/global_settings.py:64 +#: conf/global_settings.py:68 msgid "Traditional Chinese" msgstr "Chino tradicional" @@ -1691,47 +1817,51 @@ msgid "%(optname)s with this %(fieldname)s already exists." msgstr "Ya existe %(optname)s con este %(fieldname)s." #: db/models/fields/__init__.py:114 db/models/fields/__init__.py:265 -#: db/models/fields/__init__.py:545 db/models/fields/__init__.py:556 +#: db/models/fields/__init__.py:551 db/models/fields/__init__.py:562 #: forms/__init__.py:346 msgid "This field is required." msgstr "Este campo es obligatorio." -#: db/models/fields/__init__.py:337 +#: db/models/fields/__init__.py:340 msgid "This value must be an integer." msgstr "Este valor debe ser un número entero." -#: db/models/fields/__init__.py:369 +#: db/models/fields/__init__.py:372 msgid "This value must be either True or False." msgstr "Este valor debe ser True o False." -#: db/models/fields/__init__.py:385 +#: db/models/fields/__init__.py:388 msgid "This field cannot be null." msgstr "Este campo no puede ser nulo." -#: db/models/fields/__init__.py:471 core/validators.py:135 +#: db/models/fields/__init__.py:415 core/validators.py:127 +msgid "Enter a valid date in YYYY-MM-DD format." +msgstr "Introduzca una fecha válida en formato AAAA-MM-DD." + +#: db/models/fields/__init__.py:477 core/validators.py:135 msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format." msgstr "Introduzca una fecha/hora válida en formato YYYY-MM-DD HH:MM." -#: db/models/fields/__init__.py:565 +#: db/models/fields/__init__.py:571 msgid "Enter a valid filename." msgstr "Introduzca un nombre de achivo válido" -#: db/models/fields/related.py:43 +#: db/models/fields/related.py:51 #, python-format msgid "Please enter a valid %s." msgstr "Por favor, introduzca un %s válido." -#: db/models/fields/related.py:579 +#: db/models/fields/related.py:618 msgid "Separate multiple IDs with commas." msgstr " Separe múltiples IDs con comas." -#: db/models/fields/related.py:581 +#: db/models/fields/related.py:620 msgid "" "Hold down \"Control\", or \"Command\" on a Mac, to select more than one." msgstr "" "Pulse \"Control\", o \"Command\" en un Mac, para seleccionar más de uno." -#: db/models/fields/related.py:625 +#: db/models/fields/related.py:664 #, python-format msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid." msgid_plural "" @@ -1754,29 +1884,29 @@ msgstr[1] "Asegúrese de que su texto tiene menos de %s caracteres." msgid "Line breaks are not allowed here." msgstr "No se permiten saltos de línea." -#: forms/__init__.py:485 forms/__init__.py:558 forms/__init__.py:597 +#: forms/__init__.py:487 forms/__init__.py:560 forms/__init__.py:599 #, python-format msgid "Select a valid choice; '%(data)s' is not in %(choices)s." msgstr "Seleccione una opción válida; '%(data)s' no está en %(choices)s." -#: forms/__init__.py:659 core/validators.py:151 core/validators.py:379 +#: forms/__init__.py:661 core/validators.py:151 core/validators.py:379 msgid "No file was submitted. Check the encoding type on the form." msgstr "" "No se envió un archivo. Verifique el tipo de codificación en el formulario." -#: forms/__init__.py:661 +#: forms/__init__.py:663 msgid "The submitted file is empty." msgstr "El archivo enviado está vacío." -#: forms/__init__.py:717 +#: forms/__init__.py:719 msgid "Enter a whole number between -32,768 and 32,767." msgstr "Introduzca un número entero entre -32,768 y 32,767." -#: forms/__init__.py:727 +#: forms/__init__.py:729 msgid "Enter a positive number." msgstr "Introduzca un número positivo." -#: forms/__init__.py:737 +#: forms/__init__.py:739 msgid "Enter a whole number between 0 and 32,767." msgstr "Introduzca un número entero entre 0 y 32,767." @@ -1832,10 +1962,6 @@ msgstr "Introduzca un número entero." msgid "Only alphabetical characters are allowed here." msgstr "Sólo se admiten caracteres alfabéticos." -#: core/validators.py:127 -msgid "Enter a valid date in YYYY-MM-DD format." -msgstr "Introduzca una fecha válida en formato AAAA-MM-DD." - #: core/validators.py:131 msgid "Enter a valid time in HH:MM format." msgstr "Introduzca una hora válida en formato HH:MM." @@ -2066,18 +2192,28 @@ msgstr "" "El atributo \"%(attr)s\" de la línea %(line)s tiene un valor que no es " "válido. (La línea empieza por \"%(start)s\".)" -#: template/defaultfilters.py:389 +#: template/defaultfilters.py:401 msgid "yes,no,maybe" msgstr "si,no,tal vez" -#, fuzzy +#: views/generic/create_update.py:43 +#, python-format +msgid "The %(verbose_name)s was created successfully." +msgstr "Se creó con éxito el %(verbose_name)." + +#: views/generic/create_update.py:117 +#, python-format +msgid "The %(verbose_name)s was updated successfully." +msgstr "Se actualizó con éxito el %(verbose_name)s." + +#: views/generic/create_update.py:184 +#, python-format +msgid "The %(verbose_name)s was deleted." +msgstr "Se eliminó el %(verbose_name)s." + #~ msgid "%(content_type_name)s" #~ msgstr "tipos de contenido" -#, fuzzy -#~ msgid "%(myname)s" -#~ msgstr "Agregar %(name)s" - #~ msgid "%(result_count)s result" #~ msgid_plural "%(counter)s results" #~ msgstr[0] "un resultado" diff --git a/django/conf/locale/fi/LC_MESSAGES/django.mo b/django/conf/locale/fi/LC_MESSAGES/django.mo Binary files differnew file mode 100644 index 0000000000..1e690716fd --- /dev/null +++ b/django/conf/locale/fi/LC_MESSAGES/django.mo diff --git a/django/conf/locale/fi/LC_MESSAGES/django.po b/django/conf/locale/fi/LC_MESSAGES/django.po new file mode 100644 index 0000000000..9b91982e6b --- /dev/null +++ b/django/conf/locale/fi/LC_MESSAGES/django.po @@ -0,0 +1,2031 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2006-08-05 14:41+0300\n" +"PO-Revision-Date: 2006-08-12 23:41+0300\n" +"Last-Translator: Antti Kaihola <antti.kaihola@ambitone.com>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: db/models/manipulators.py:302 +#, python-format +msgid "%(object)s with this %(type)s already exists for the given %(field)s." +msgstr "" + +#: db/models/fields/related.py:51 +#, python-format +msgid "Please enter a valid %s." +msgstr "Syöttämäsi %s ei kelpaa." + +#: db/models/fields/related.py:618 +msgid "Separate multiple IDs with commas." +msgstr "Erottele tunnisteet pilkuilla." + +#: db/models/fields/related.py:620 +msgid "" +"Hold down \"Control\", or \"Command\" on a Mac, to select more than one." +msgstr "" +" Pidä \"Ctrl\"-näppäin (tai Macin \"Command\") pohjassa valitaksesi useita " +"vaihtoehtoja." + +#: db/models/fields/related.py:664 +#, python-format +msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid." +msgid_plural "" +"Please enter valid %(self)s IDs. The values %(value)r are invalid." +msgstr[0] "Syöttämäsi %(self)s-tunniste %(value)r ei kelpaa." +msgstr[1] "Syöttämäsi %(self)s-tunnisteet %(value)r eivät kelpaa." + +#: db/models/fields/__init__.py:40 +#, python-format +msgid "%(optname)s with this %(fieldname)s already exists." +msgstr "%(optname)s, jolla on tämä %(fieldname)s, on jo olemassa." + +#: db/models/fields/__init__.py:114 db/models/fields/__init__.py:265 +#: db/models/fields/__init__.py:551 db/models/fields/__init__.py:562 +#: forms/__init__.py:346 +msgid "This field is required." +msgstr "Tämä kenttä vaaditaan." + +#: db/models/fields/__init__.py:340 +msgid "This value must be an integer." +msgstr "Tarvitaan kokonaisluku." + +#: db/models/fields/__init__.py:372 +msgid "This value must be either True or False." +msgstr "Tarvitaan tosi (True) tai epätosi (False)." + +#: db/models/fields/__init__.py:388 +msgid "This field cannot be null." +msgstr "Tämän kentän arvo ei voi olla \"null\"." + +#: db/models/fields/__init__.py:415 core/validators.py:127 +msgid "Enter a valid date in YYYY-MM-DD format." +msgstr "Päivämäärän pitää olla muodossa VVVV-KK-PP." + +#: db/models/fields/__init__.py:477 core/validators.py:135 +msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format." +msgstr "Ajankohdan pitää olla muodossa VVVV-KK-PP TT:MM." + +#: db/models/fields/__init__.py:571 +msgid "Enter a valid filename." +msgstr "Tiedostonimi ei kelpaa." + +#: conf/global_settings.py:39 +msgid "Arabic" +msgstr "arabia" + +#: conf/global_settings.py:40 +msgid "Bengali" +msgstr "bengali" + +#: conf/global_settings.py:41 +msgid "Czech" +msgstr "tÅ¡ekki" + +#: conf/global_settings.py:42 +msgid "Welsh" +msgstr "" + +#: conf/global_settings.py:43 +msgid "Danish" +msgstr "tanska" + +#: conf/global_settings.py:44 +msgid "German" +msgstr "saksa" + +#: conf/global_settings.py:45 +msgid "Greek" +msgstr "kreikka" + +#: conf/global_settings.py:46 +msgid "English" +msgstr "englanti" + +#: conf/global_settings.py:47 +msgid "Spanish" +msgstr "espanja" + +#: conf/global_settings.py:48 +msgid "Argentinean Spanish" +msgstr "Argentiinan espanja" + +#: conf/global_settings.py:49 +msgid "French" +msgstr "ranska" + +#: conf/global_settings.py:50 +msgid "Galician" +msgstr "" + +#: conf/global_settings.py:51 +msgid "Hungarian" +msgstr "unkari" + +#: conf/global_settings.py:52 +msgid "Hebrew" +msgstr "heprea" + +#: conf/global_settings.py:53 +msgid "Icelandic" +msgstr "islanti" + +#: conf/global_settings.py:54 +msgid "Italian" +msgstr "italia" + +#: conf/global_settings.py:55 +msgid "Japanese" +msgstr "japani" + +#: conf/global_settings.py:56 +msgid "Dutch" +msgstr "hollanti" + +#: conf/global_settings.py:57 +msgid "Norwegian" +msgstr "norja" + +#: conf/global_settings.py:58 +msgid "Brazilian" +msgstr "" + +#: conf/global_settings.py:59 +msgid "Romanian" +msgstr "romania" + +#: conf/global_settings.py:60 +msgid "Russian" +msgstr "venäjä" + +#: conf/global_settings.py:61 +msgid "Slovak" +msgstr "" + +#: conf/global_settings.py:62 +msgid "Slovenian" +msgstr "" + +#: conf/global_settings.py:63 +msgid "Serbian" +msgstr "" + +#: conf/global_settings.py:64 +msgid "Swedish" +msgstr "ruotsi" + +#: conf/global_settings.py:65 +msgid "Tamil" +msgstr "" + +#: conf/global_settings.py:66 +msgid "Ukrainian" +msgstr "" + +#: conf/global_settings.py:67 +msgid "Simplified Chinese" +msgstr "" + +#: conf/global_settings.py:68 +msgid "Traditional Chinese" +msgstr "" + +#: core/validators.py:63 +msgid "This value must contain only letters, numbers and underscores." +msgstr "Tässä voidaan käyttää vain kirjaimia (a-z), numeroita (0-9) ja alaviivoja (_)." + +#: core/validators.py:67 +msgid "" +"This value must contain only letters, numbers, underscores, dashes or " +"slashes." +msgstr "Tässä voidaan käyttää vain kirjaimia (a-z), numeroita (0-9) sekä ala-, tavu- ja kauttaviivoja (_ - /)." + +#: core/validators.py:75 +msgid "Uppercase letters are not allowed here." +msgstr "Versaalit (ABC) eivät kelpaa tässä." + +#: core/validators.py:79 +msgid "Lowercase letters are not allowed here." +msgstr "Pienet kirjaimet (abc) eivät kelpaa tässä." + +#: core/validators.py:86 +msgid "Enter only digits separated by commas." +msgstr "Vain pilkulla erotetut luvut kelpaavat tässä." + +#: core/validators.py:98 +msgid "Enter valid e-mail addresses separated by commas." +msgstr "Syötä sähköpostiosoitteita pilkuilla erotettuina." + +#: core/validators.py:102 +msgid "Please enter a valid IP address." +msgstr "IP-osoite ei kelpaa." + +#: core/validators.py:106 +msgid "Empty values are not allowed here." +msgstr "Tätä kohtaa ei voi jättää tyhjäksi." + +#: core/validators.py:110 +msgid "Non-numeric characters aren't allowed here." +msgstr "Vain numerot (0-9) kelpaavat tässä." + +#: core/validators.py:114 +msgid "This value can't be comprised solely of digits." +msgstr "Tarvitaan vähintään yksi merkki, joka ei ole numero (0-9)." + +#: core/validators.py:119 +msgid "Enter a whole number." +msgstr "Syötä kokonaisluku." + +#: core/validators.py:123 +msgid "Only alphabetical characters are allowed here." +msgstr "Vain kirjaimet kelpaavat tässä." + +#: core/validators.py:131 +msgid "Enter a valid time in HH:MM format." +msgstr "Ajan täytyy olla muodossa TT:MM." + +#: core/validators.py:139 +msgid "Enter a valid e-mail address." +msgstr "Syötä kelvollinen sähköpostiosoite." + +#: core/validators.py:151 core/validators.py:379 forms/__init__.py:661 +msgid "No file was submitted. Check the encoding type on the form." +msgstr "Tiedostoa ei lähetetty. Tarkista lomakkeen koodaus (encoding)." + +#: core/validators.py:155 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "Kuva ei kelpaa. Lähettämäsi tiedosto ei ole kuva, tai tiedosto on vioittunut." + +#: core/validators.py:162 +#, python-format +msgid "The URL %s does not point to a valid image." +msgstr "Osoittessa %s ei ole kelpaavaa kuvaa." + +#: core/validators.py:166 +#, python-format +msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid." +msgstr "Puhelinnumeron tulee olla muodossa XXX-XXX-XXXX. \"%s\" ei kelpaa." + +#: core/validators.py:174 +#, python-format +msgid "The URL %s does not point to a valid QuickTime video." +msgstr "Osoitteessa %s ei ole kelpaavaa QuickTime-videota." + +#: core/validators.py:178 +msgid "A valid URL is required." +msgstr "URL-osoite ei kelpaa." + +#: core/validators.py:192 +#, python-format +msgid "" +"Valid HTML is required. Specific errors are:\n" +"%s" +msgstr "" +"HTML-koodi ei kelpaa. Virheilmoitus on:\n" +"%s" + +#: core/validators.py:199 +#, python-format +msgid "Badly formed XML: %s" +msgstr "Vääränmuotoinen XML: %s" + +#: core/validators.py:209 +#, python-format +msgid "Invalid URL: %s" +msgstr "URL-osoite %s ei kelpaa." + +#: core/validators.py:213 core/validators.py:215 +#, python-format +msgid "The URL %s is a broken link." +msgstr "Osoite %s on katkennut linkki." + +#: core/validators.py:221 +msgid "Enter a valid U.S. state abbreviation." +msgstr "Syötä USA:n osavaltion lyhenne." + +#: core/validators.py:236 +#, python-format +msgid "Watch your mouth! The word %s is not allowed here." +msgid_plural "Watch your mouth! The words %s are not allowed here." +msgstr[0] "Sanaa \"%s\" ei saa käyttää tässä." +msgstr[1] "Sanoja \"%s\" ei saa käyttää tässä." + +#: core/validators.py:243 +#, python-format +msgid "This field must match the '%s' field." +msgstr "" + +#: core/validators.py:262 +msgid "Please enter something for at least one field." +msgstr "Täytä ainakin yksi kenttä." + +#: core/validators.py:271 core/validators.py:282 +msgid "Please enter both fields or leave them both empty." +msgstr "Täytä tai jätä tyhjäksi kummatkin kentät." + +#: core/validators.py:289 +#, python-format +msgid "This field must be given if %(field)s is %(value)s" +msgstr "Tämä kenttä pitää täyttää, jos %(field)s on %(value)s." + +#: core/validators.py:301 +#, python-format +msgid "This field must be given if %(field)s is not %(value)s" +msgstr "Tämä kenttä pitää täyttää, jos %(field)s ei ole %(value)s." + +#: core/validators.py:320 +msgid "Duplicate values are not allowed." +msgstr "Samaa arvoa ei voi käyttää kahdesti." + +#: core/validators.py:343 +#, python-format +msgid "This value must be a power of %s." +msgstr "Tämän luvun on oltava %s:n potenssi." + +#: core/validators.py:354 +msgid "Please enter a valid decimal number." +msgstr "Desimaaliluku ei kelpaa." + +#: core/validators.py:356 +#, python-format +msgid "Please enter a valid decimal number with at most %s total digit." +msgid_plural "" +"Please enter a valid decimal number with at most %s total digits." +msgstr[0] "Desimaaliluvussa saa tässä olla yhteensä vain %s merkitsevä numero. Huomaa, että desimaalierottimena käytetään pilkun (,) sijasta pistettä (.)." +msgstr[1] "Desimaaliluvussa saa tässä olla yhteensä vain %s merkitsevää numeroa. Huomaa, että desimaalierottimena käytetään pilkun (,) sijasta pistettä (.)." + +#: core/validators.py:359 +#, python-format +msgid "" +"Please enter a valid decimal number with a whole part of at most %s digit." +msgid_plural "" +"Please enter a valid decimal number with a whole part of at most %s digits." +msgstr[0] "Desimaaliluvun kokonaisosassa saa tässä olla vain %s numero. Huomaa, että desimaalierottimena käytetään pilkun (,) sijasta pistettä (.)." +msgstr[1] "Desimaaliluvun kokonaisosassa saa tässä olla vain %s numeroa. Huomaa, että desimaalierottimena käytetään pilkun (,) sijasta pistettä (.)." + +#: core/validators.py:362 +#, python-format +msgid "Please enter a valid decimal number with at most %s decimal place." +msgid_plural "" +"Please enter a valid decimal number with at most %s decimal places." +msgstr[0] "Tässä saa olla vain %s desimaali. Huomaa, että desimaalierottimena käytetään pilkun (,) sijasta pistettä (.)." +msgstr[1] "Tässä saa olla vain %s desimaalia. Huomaa, että desimaalierottimena käytetään pilkun (,) sijasta pistettä (.)." + +#: core/validators.py:372 +#, python-format +msgid "Make sure your uploaded file is at least %s bytes big." +msgstr "Lähetä vähintään %s tavun kokoinen tiedosto." + +#: core/validators.py:373 +#, python-format +msgid "Make sure your uploaded file is at most %s bytes big." +msgstr "Lähetä enintään %s tavun kokoinen tiedosto." + +#: core/validators.py:390 +msgid "The format for this field is wrong." +msgstr "Muoto ei kelpaa." + +#: core/validators.py:405 +msgid "This field is invalid." +msgstr "Tämä arvo ei kelpaa." + +#: core/validators.py:441 +#, python-format +msgid "Could not retrieve anything from %s." +msgstr "" + +#: core/validators.py:444 +#, python-format +msgid "" +"The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'." +msgstr "Osoitteesta %(url)s saatiin virheellinen Content-Type '%(contenttype)s'." + +#: core/validators.py:477 +#, python-format +msgid "" +"Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with " +"\"%(start)s\".)" +msgstr "Rivillä %(line)s oleva tagi %(tag)s pitää sulkea. (Rivi alkaa \"%(start)s\")" + +#: core/validators.py:481 +#, python-format +msgid "" +"Some text starting on line %(line)s is not allowed in that context. (Line " +"starts with \"%(start)s\".)" +msgstr "Rivillä %(line)s on tekstiä, joka ei kelpaa tässä yhteydessä. (Rivi alkaa \"%(start)s\")" + +#: core/validators.py:486 +#, python-format +msgid "" +"\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%" +"(start)s\".)" +msgstr "Rivillä %(line)s attribuutti %(attr)s ei kelpaa. (Rivi alkaa \"%(start)s\")" + +#: core/validators.py:491 +#, python-format +msgid "" +"\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%" +"(start)s\".)" +msgstr "Rivillä %(line)s tagi \"<%(tag)s>\" ei kelpaa. (Rivi alkaa \"%(start)s\")" + +#: core/validators.py:495 +#, python-format +msgid "" +"A tag on line %(line)s is missing one or more required attributes. (Line " +"starts with \"%(start)s\".)" +msgstr "Rivillä %(line)s yhdestä tagista puuttuu yksi tai useampi attribuutti. (Rivi alkaa \"%(start)s\")" + +#: core/validators.py:500 +#, python-format +msgid "" +"The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line " +"starts with \"%(start)s\".)" +msgstr "Rivillä %(line)s attribuutin %(attr)s arvo ei kelpaa. (Rivi alkaa \"%(start)s\")" + +#: contrib/auth/forms.py:52 +msgid "" +"Your Web browser doesn't appear to have cookies enabled. Cookies are " +"required for logging in." +msgstr "Selaimesi ei salli evästeitä. Sisäänkirjautuminen vaatii evästeen." + +#: contrib/auth/forms.py:59 contrib/admin/views/decorators.py:10 +msgid "" +"Please enter a correct username and password. Note that both fields are case-" +"sensitive." +msgstr "Käyttäjätunnus tai salasana ei kelpaa. Huomaa, että isot ja pienet kirjaimet ovat merkitseviä." + +#: contrib/auth/forms.py:61 +msgid "This account is inactive." +msgstr "Tämä käyttäjätili ei ole voimassa." + +#: contrib/auth/models.py:38 contrib/auth/models.py:57 +msgid "name" +msgstr "nimi" + +#: contrib/auth/models.py:40 +msgid "codename" +msgstr "koodinimi" + +#: contrib/auth/models.py:42 +msgid "permission" +msgstr "oikeus" + +#: contrib/auth/models.py:43 contrib/auth/models.py:58 +msgid "permissions" +msgstr "oikeudet" + +#: contrib/auth/models.py:60 +msgid "group" +msgstr "ryhmä" + +#: contrib/auth/models.py:61 contrib/auth/models.py:100 +msgid "groups" +msgstr "ryhmät" + +#: contrib/auth/models.py:90 +msgid "username" +msgstr "tunnus" + +#: contrib/auth/models.py:90 +msgid "" +"Required. 30 characters or fewer. Alphanumeric characters only (letters, " +"digits and underscores)." +msgstr " Vaaditaan. Enintään 30 kirjanta (a-z), numeroa (0-9) tai alaviivaa (_)." + +#: contrib/auth/models.py:91 +msgid "first name" +msgstr "etunimi" + +#: contrib/auth/models.py:92 +msgid "last name" +msgstr "sukunimi" + +#: contrib/auth/models.py:93 +msgid "e-mail address" +msgstr "sähköposti" + +#: contrib/auth/models.py:94 +msgid "password" +msgstr "salasana" + +#: contrib/auth/models.py:94 +msgid "Use '[algo]$[salt]$[hexdigest]'" +msgstr "(Salasanaa ei näytetä selväkielisenä)" + +#: contrib/auth/models.py:95 +msgid "staff status" +msgstr "ylläpitäjä" + +#: contrib/auth/models.py:95 +msgid "Designates whether the user can log into this admin site." +msgstr "Ylläpitäjillä on pääsy tähän sivuston ylläpito-osioon." + +#: contrib/auth/models.py:96 +msgid "active" +msgstr "voimassa" + +#: contrib/auth/models.py:96 +msgid "" +"Designates whether this user can log into the Django admin. Unselect this " +"instead of deleting accounts." +msgstr "Määrää, voiko käyttäjä kirjautua sisään. Tällä voi estää käyttäjätilin käytön poistamatta sitä." + +#: contrib/auth/models.py:97 +msgid "superuser status" +msgstr "pääkäyttäjä" + +#: contrib/auth/models.py:97 +msgid "" +"Designates that this user has all permissions without explicitly assigning " +"them." +msgstr "Antaa käyttäjälle kaikki oikeudet ilman, että niitä täytyy erikseen luetella." + +#: contrib/auth/models.py:98 +msgid "last login" +msgstr "viimeksi kirjautunut" + +#: contrib/auth/models.py:99 +msgid "date joined" +msgstr "liittynyt" + +#: contrib/auth/models.py:101 +msgid "" +"In addition to the permissions manually assigned, this user will also get " +"all permissions granted to each group he/she is in." +msgstr "" +"Tässä valittujen oikeuksien lisäksi käyttäjä saa myös kaikki niiden ryhmien " +"oikeudet, joiden jäsen hän on." + +#: contrib/auth/models.py:102 +msgid "user permissions" +msgstr "käyttäjän oikeudet" + +#: contrib/auth/models.py:105 +msgid "user" +msgstr "käyttäjä" + +#: contrib/auth/models.py:106 +msgid "users" +msgstr "käyttäjät" + +#: contrib/auth/models.py:111 +msgid "Personal info" +msgstr "Henkilökohtaiset tiedot" + +#: contrib/auth/models.py:112 +msgid "Permissions" +msgstr "Oikeudet" + +#: contrib/auth/models.py:113 +msgid "Important dates" +msgstr "Tärkeät päivämäärät" + +#: contrib/auth/models.py:114 +msgid "Groups" +msgstr "Ryhmät" + +#: contrib/auth/models.py:256 +msgid "message" +msgstr "viesti" + +#: contrib/auth/views.py:39 +msgid "Logged out" +msgstr "Kirjautunut ulos" + +#: contrib/admin/models.py:16 +msgid "action time" +msgstr "tapahtumahetki" + +#: contrib/admin/models.py:19 +msgid "object id" +msgstr "kohteen tunniste" + +#: contrib/admin/models.py:20 +msgid "object repr" +msgstr "kohteen tiedot" + +#: contrib/admin/models.py:21 +msgid "action flag" +msgstr "tapahtumatyyppi" + +#: contrib/admin/models.py:22 +msgid "change message" +msgstr "selitys" + +#: contrib/admin/models.py:25 +msgid "log entry" +msgstr "lokimerkintä" + +#: contrib/admin/models.py:26 +msgid "log entries" +msgstr "lokimerkinnät" + +#: contrib/admin/filterspecs.py:40 +#, python-format +msgid "" +"<h3>By %s:</h3>\n" +"<ul>\n" +msgstr "" +"<h3>Yksi %s:</h3>\n" +"<ul>\n" + +#: contrib/admin/filterspecs.py:70 contrib/admin/filterspecs.py:88 +#: contrib/admin/filterspecs.py:143 contrib/admin/filterspecs.py:169 +msgid "All" +msgstr "Kaikki" + +#: contrib/admin/filterspecs.py:109 +msgid "Any date" +msgstr "Mikä tahansa päivä" + +#: contrib/admin/filterspecs.py:110 +msgid "Today" +msgstr "Tänään" + +#: contrib/admin/filterspecs.py:113 +msgid "Past 7 days" +msgstr "Viimeiset 7 päivää" + +#: contrib/admin/filterspecs.py:115 +msgid "This month" +msgstr "Tässä kuussa" + +#: contrib/admin/filterspecs.py:117 +msgid "This year" +msgstr "Tänä vuonna" + +#: contrib/admin/filterspecs.py:143 +msgid "Yes" +msgstr "Kyllä" + +#: contrib/admin/filterspecs.py:143 +msgid "No" +msgstr "Ei" + +#: contrib/admin/filterspecs.py:150 +msgid "Unknown" +msgstr "Tuntematon" + +#: contrib/admin/views/decorators.py:24 +#: contrib/admin/templates/admin/login.html:25 +msgid "Log in" +msgstr "Kirjaudu sisään" + +#: contrib/admin/views/decorators.py:62 +msgid "" +"Please log in again, because your session has expired. Don't worry: Your " +"submission has been saved." +msgstr "Kirjaudu uudelleen sisään, koska istuntosi on mennyt umpeen. Muutoksesi ovat silti tallessa." + +#: contrib/admin/views/decorators.py:69 +msgid "" +"Looks like your browser isn't configured to accept cookies. Please enable " +"cookies, reload this page, and try again." +msgstr "Selaimesi ei salli evästeitä. Muuta asetukset sallimaan evästeet, lataa tämä sivu uudelleen ja yritä toistamiseen." + +#: contrib/admin/views/decorators.py:83 +msgid "Usernames cannot contain the '@' character." +msgstr "Käyttäjätunnuksessa ei saa olla '@'-merkkiä." + +#: contrib/admin/views/decorators.py:85 +#, python-format +msgid "Your e-mail address is not your username. Try '%s' instead." +msgstr "Käyttäjätunnus ei ole sama kuin sähköpostiosoite. Kokeile '%s'." + +#: contrib/admin/views/main.py:223 +msgid "Site administration" +msgstr "Sivuston ylläpito" + +#: contrib/admin/views/main.py:257 contrib/admin/views/auth.py:14 +#, python-format +msgid "The %(name)s \"%(obj)s\" was added successfully." +msgstr "%(name)s \"%(obj)s\" on nyt lisätty." + +#: contrib/admin/views/main.py:261 contrib/admin/views/main.py:345 +#: contrib/admin/views/auth.py:19 +msgid "You may edit it again below." +msgstr "Voit muokata sitä uudelleen alla." + +#: contrib/admin/views/main.py:269 contrib/admin/views/main.py:354 +#, python-format +msgid "You may add another %s below." +msgstr "Uusi %s on lisättävissä alla." + +#: contrib/admin/views/main.py:287 +#, python-format +msgid "Add %s" +msgstr "Uusi %s" + +#: contrib/admin/views/main.py:333 +#, python-format +msgid "Added %s." +msgstr "Lisätty %s." + +#: contrib/admin/views/main.py:333 contrib/admin/views/main.py:335 +#: contrib/admin/views/main.py:337 +msgid "and" +msgstr "ja" + +#: contrib/admin/views/main.py:335 +#, python-format +msgid "Changed %s." +msgstr "Muokattu: %s." + +#: contrib/admin/views/main.py:337 +#, python-format +msgid "Deleted %s." +msgstr "Poistettu %s." + +#: contrib/admin/views/main.py:340 +msgid "No fields changed." +msgstr "Ei muutoksia kenttiin." + +#: contrib/admin/views/main.py:343 +#, python-format +msgid "The %(name)s \"%(obj)s\" was changed successfully." +msgstr "%(name)s \"%(obj)s\" on nyt muutettu." + +#: contrib/admin/views/main.py:351 +#, python-format +msgid "" +"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below." +msgstr "%(name)s \"%(obj)s\" on nyt lisätty. Voit muokata sitä uudelleen alla." + +#: contrib/admin/views/main.py:389 +#, python-format +msgid "Change %s" +msgstr "Muokkaa: %s" + +#: contrib/admin/views/main.py:471 +#, python-format +msgid "One or more %(fieldname)s in %(name)s: %(obj)s" +msgstr "Yksi tai useampi %(fieldname)s kohteessa %(name)s: %(obj)s" + +#: contrib/admin/views/main.py:476 +#, python-format +msgid "One or more %(fieldname)s in %(name)s:" +msgstr "Yksi tai useampi %(fieldname)s kohteessa %(name)s:" + +#: contrib/admin/views/main.py:509 +#, python-format +msgid "The %(name)s \"%(obj)s\" was deleted successfully." +msgstr "%(name)s \"%(obj)s\" on poistettu." + +#: contrib/admin/views/main.py:512 +msgid "Are you sure?" +msgstr "Oletko varma?" + +#: contrib/admin/views/main.py:534 +#, python-format +msgid "Change history: %s" +msgstr "Muokkaushistoria: %s" + +#: contrib/admin/views/main.py:568 +#, python-format +msgid "Select %s" +msgstr "Valitse %s" + +#: contrib/admin/views/main.py:568 +#, python-format +msgid "Select %s to change" +msgstr "Valitse muokattava %s" + +#: contrib/admin/views/main.py:744 +msgid "Database error" +msgstr "Tietokantavirhe" + +#: contrib/admin/views/doc.py:291 contrib/admin/views/doc.py:301 +#: contrib/admin/views/doc.py:303 contrib/admin/views/doc.py:309 +#: contrib/admin/views/doc.py:310 contrib/admin/views/doc.py:312 +msgid "Integer" +msgstr "Kokonaisluku" + +#: contrib/admin/views/doc.py:292 +msgid "Boolean (Either True or False)" +msgstr "Totuusarvo: joko tosi (True) tai epätosi (False)" + +#: contrib/admin/views/doc.py:293 contrib/admin/views/doc.py:311 +#, python-format +msgid "String (up to %(maxlength)s)" +msgstr "Merkkijono (enintään %(maxlength)s merkkiä)" + +#: contrib/admin/views/doc.py:294 +msgid "Comma-separated integers" +msgstr "Pilkulla erotetut kokonaisluvut" + +#: contrib/admin/views/doc.py:295 +msgid "Date (without time)" +msgstr "Päivämäärä" + +#: contrib/admin/views/doc.py:296 +msgid "Date (with time)" +msgstr "Päivämäärä ja kellonaika" + +#: contrib/admin/views/doc.py:297 +msgid "E-mail address" +msgstr "Sähköpostios." + +#: contrib/admin/views/doc.py:298 contrib/admin/views/doc.py:299 +#: contrib/admin/views/doc.py:302 +msgid "File path" +msgstr "Tiedostopolku" + +#: contrib/admin/views/doc.py:300 +msgid "Decimal number" +msgstr "Desimaaliluku" + +#: contrib/admin/views/doc.py:304 contrib/comments/models.py:85 +msgid "IP address" +msgstr "IP-osoite" + +#: contrib/admin/views/doc.py:306 +msgid "Boolean (Either True, False or None)" +msgstr "Totuusarvo: joko tosi (True), epätosi (False) tai ei mikään (None)" + +#: contrib/admin/views/doc.py:307 +msgid "Relation to parent model" +msgstr "Relaatio emomalliin" + +#: contrib/admin/views/doc.py:308 +msgid "Phone number" +msgstr "Puhelinnumero" + +#: contrib/admin/views/doc.py:313 +msgid "Text" +msgstr "Tekstiä" + +#: contrib/admin/views/doc.py:314 +msgid "Time" +msgstr "Kellonaika" + +#: contrib/admin/views/doc.py:315 contrib/flatpages/models.py:7 +msgid "URL" +msgstr "URL-osoite" + +#: contrib/admin/views/doc.py:316 +msgid "U.S. state (two uppercase letters)" +msgstr "USA:n osavaltio (kaksikirjaiminen versaalein)" + +#: contrib/admin/views/doc.py:317 +msgid "XML text" +msgstr "XML-teksti" + +#: contrib/admin/views/auth.py:25 +msgid "Add user" +msgstr "Uusi käyttäjä" + +#: contrib/admin/templatetags/admin_list.py:230 +msgid "All dates" +msgstr "Kaikki päivät" + +#: contrib/admin/templates/admin/pagination.html:10 +msgid "Show all" +msgstr "Näytä kaikki" + +#: contrib/admin/templates/admin/delete_confirmation.html:3 +#: contrib/admin/templates/admin/change_form.html:10 +#: contrib/admin/templates/admin/change_list.html:5 +#: contrib/admin/templates/admin/object_history.html:3 +#: contrib/admin/templates/admin/base.html:24 +#: contrib/admin/templates/admin_doc/bookmarklets.html:3 +#: contrib/admin/templates/registration/password_change_form.html:3 +#: contrib/admin/templates/registration/password_change_done.html:3 +msgid "Documentation" +msgstr "Ohjeita" + +#: contrib/admin/templates/admin/delete_confirmation.html:3 +#: contrib/admin/templates/admin/change_form.html:10 +#: contrib/admin/templates/admin/change_list.html:5 +#: contrib/admin/templates/admin/object_history.html:3 +#: contrib/admin/templates/admin/base.html:24 +#: contrib/admin/templates/admin_doc/template_filter_index.html:5 +#: contrib/admin/templates/admin_doc/bookmarklets.html:4 +#: contrib/admin/templates/admin_doc/template_tag_index.html:5 +#: contrib/admin/templates/admin_doc/index.html:4 +#: contrib/admin/templates/admin_doc/model_detail.html:3 +#: contrib/admin/templates/admin_doc/missing_docutils.html:4 +#: contrib/admin/templates/admin_doc/template_detail.html:4 +#: contrib/admin/templates/admin_doc/view_index.html:5 +#: contrib/admin/templates/admin_doc/model_index.html:5 +#: contrib/admin/templates/admin_doc/view_detail.html:4 +#: contrib/admin/templates/registration/password_change_form.html:3 +#: contrib/admin/templates/registration/password_change_done.html:3 +msgid "Change password" +msgstr "Vaihda salasana" + +#: contrib/admin/templates/admin/delete_confirmation.html:3 +#: contrib/admin/templates/admin/change_form.html:10 +#: contrib/admin/templates/admin/change_list.html:5 +#: contrib/admin/templates/admin/object_history.html:3 +#: contrib/admin/templates/admin/base.html:24 +#: contrib/admin/templates/admin_doc/template_filter_index.html:5 +#: contrib/admin/templates/admin_doc/bookmarklets.html:4 +#: contrib/admin/templates/admin_doc/template_tag_index.html:5 +#: contrib/admin/templates/admin_doc/index.html:4 +#: contrib/admin/templates/admin_doc/model_detail.html:3 +#: contrib/admin/templates/admin_doc/missing_docutils.html:4 +#: contrib/admin/templates/admin_doc/template_detail.html:4 +#: contrib/admin/templates/admin_doc/view_index.html:5 +#: contrib/admin/templates/admin_doc/model_index.html:5 +#: contrib/admin/templates/admin_doc/view_detail.html:4 +#: contrib/admin/templates/registration/password_change_form.html:3 +#: contrib/admin/templates/registration/password_change_done.html:3 +#: contrib/comments/templates/comments/form.html:6 +msgid "Log out" +msgstr "Kirjaudu ulos" + +#: contrib/admin/templates/admin/delete_confirmation.html:6 +#: contrib/admin/templates/admin/change_form.html:13 +#: contrib/admin/templates/admin/change_list.html:6 +#: contrib/admin/templates/admin/object_history.html:5 +#: contrib/admin/templates/admin/500.html:4 +#: contrib/admin/templates/admin/invalid_setup.html:4 +#: contrib/admin/templates/admin/base.html:29 +#: contrib/admin/templates/admin_doc/bookmarklets.html:3 +#: contrib/admin/templates/registration/password_reset_form.html:4 +#: contrib/admin/templates/registration/logged_out.html:4 +#: contrib/admin/templates/registration/password_reset_done.html:4 +#: contrib/admin/templates/registration/password_change_form.html:4 +#: contrib/admin/templates/registration/password_change_done.html:4 +msgid "Home" +msgstr "Etusivu" + +#: contrib/admin/templates/admin/delete_confirmation.html:9 +#: contrib/admin/templates/admin/submit_line.html:3 +msgid "Delete" +msgstr "Poista" + +#: contrib/admin/templates/admin/delete_confirmation.html:14 +#, python-format +msgid "" +"Deleting the %(object_name)s '%(escaped_object)s' would result in deleting " +"related objects, but your account doesn't have permission to delete the " +"following types of objects:" +msgstr "Kohteen '%(escaped_object)s' (%(object_name)s) poisto poistaisi myös siihen liittyviä kohteita, mutta sinulla ei ole oikeutta näiden kohteiden poistamiseen:" + +#: contrib/admin/templates/admin/delete_confirmation.html:21 +#, python-format +msgid "" +"Are you sure you want to delete the %(object_name)s \"%(escaped_object)s\"? " +"All of the following related items will be deleted:" +msgstr "Haluatko varmasti poistaa kohteen \"%(escaped_object)s\" (%(object_name)s)? Myös seuraavat kohteet poistettaisiin samalla:" + +#: contrib/admin/templates/admin/delete_confirmation.html:26 +msgid "Yes, I'm sure" +msgstr "Kyllä, olen varma" + +#: contrib/admin/templates/admin/404.html:4 +#: contrib/admin/templates/admin/404.html:8 +msgid "Page not found" +msgstr "Sivua ei löydy" + +#: contrib/admin/templates/admin/404.html:10 +msgid "We're sorry, but the requested page could not be found." +msgstr "Pahoittelemme, pyydettyä sivua ei voitu löytää." + +#: contrib/admin/templates/admin/change_form.html:15 +#: contrib/admin/templates/admin/index.html:28 +msgid "Add" +msgstr "Lisää uusi" + +#: contrib/admin/templates/admin/change_form.html:20 +#: contrib/admin/templates/admin/object_history.html:5 +msgid "History" +msgstr "Muokkaushistoria" + +#: contrib/admin/templates/admin/change_form.html:21 +msgid "View on site" +msgstr "Näytä lopputulos" + +#: contrib/admin/templates/admin/change_form.html:30 +msgid "Please correct the error below." +msgid_plural "Please correct the errors below." +msgstr[0] "Korjaa virhe." +msgstr[1] "Korjaa virheet." + +#: contrib/admin/templates/admin/change_form.html:48 +msgid "Ordering" +msgstr "Järjestys" + +#: contrib/admin/templates/admin/change_form.html:51 +msgid "Order:" +msgstr "Järjestysnumero:" + +#: contrib/admin/templates/admin/filter.html:2 +#, python-format +msgid " By %(filter_title)s " +msgstr " %(filter_title)s:" + +#: contrib/admin/templates/admin/submit_line.html:4 +msgid "Save as new" +msgstr "Talleta uutena" + +#: contrib/admin/templates/admin/submit_line.html:5 +msgid "Save and add another" +msgstr "Talleta ja lisää seuraava" + +#: contrib/admin/templates/admin/submit_line.html:6 +msgid "Save and continue editing" +msgstr "Talleta välillä ja jatka muokkaamista" + +#: contrib/admin/templates/admin/submit_line.html:7 +msgid "Save" +msgstr "Talleta ja poistu" + +#: contrib/admin/templates/admin/change_list.html:11 +#, python-format +msgid "Add %(name)s" +msgstr "Lisää uusi %(name)s" + +#: contrib/admin/templates/admin/index.html:17 +#, python-format +msgid "Models available in the %(name)s application." +msgstr "Sovelluksen %(name)s mallit." + +#: contrib/admin/templates/admin/index.html:18 +#, python-format +msgid "%(name)s" +msgstr "%(name)s" + +#: contrib/admin/templates/admin/index.html:34 +msgid "Change" +msgstr "Muokkaa" + +#: contrib/admin/templates/admin/index.html:44 +msgid "You don't have permission to edit anything." +msgstr "Sinulla ei ole oikeutta muokata mitään." + +#: contrib/admin/templates/admin/index.html:52 +msgid "Recent Actions" +msgstr "Viimeisimmät muutokset" + +#: contrib/admin/templates/admin/index.html:53 +msgid "My Actions" +msgstr "Sinun tekemäsi muutokset" + +#: contrib/admin/templates/admin/index.html:57 +msgid "None available" +msgstr "Ei yhtään" + +#: contrib/admin/templates/admin/base_site.html:4 +msgid "Django site admin" +msgstr "Django-sivuston ylläpito" + +#: contrib/admin/templates/admin/base_site.html:7 +msgid "Django administration" +msgstr "Djangon ylläpito" + +#: contrib/admin/templates/admin/object_history.html:18 +msgid "Date/time" +msgstr "Pvm/klo" + +#: contrib/admin/templates/admin/object_history.html:19 +msgid "User" +msgstr "Käyttäjä" + +#: contrib/admin/templates/admin/object_history.html:20 +msgid "Action" +msgstr "Toiminto" + +#: contrib/admin/templates/admin/object_history.html:26 +msgid "DATE_WITH_TIME_FULL" +msgstr "N j, Y, P" + +#: contrib/admin/templates/admin/object_history.html:36 +msgid "" +"This object doesn't have a change history. It probably wasn't added via this " +"admin site." +msgstr "Tällä kohteella ei ole muutoshistoriaa. Sitä ei ole lisätty tämän ylläpitosivun avulla." + +#: contrib/admin/templates/admin/500.html:4 +msgid "Server error" +msgstr "Palvelinvirhe" + +#: contrib/admin/templates/admin/500.html:6 +msgid "Server error (500)" +msgstr "Palvelinvirhe (500)" + +#: contrib/admin/templates/admin/500.html:9 +msgid "Server Error <em>(500)</em>" +msgstr "Palvelinvirhe <em>(500)</em>" + +#: contrib/admin/templates/admin/invalid_setup.html:8 +msgid "" +"Something's wrong with your database installation. Make sure the appropriate " +"database tables have been created, and make sure the database is readable by " +"the appropriate user." +msgstr "Tietokanta-asennuksessasi on jotain vialla. Varmistu, että sopivat taulut on luotu ja että oikea käyttäjä voi lukea tietokantaa." + +#: contrib/admin/templates/admin/search_form.html:8 +msgid "Go" +msgstr "Etsi" + +#: contrib/admin/templates/admin/search_form.html:10 +#, python-format +msgid "1 result" +msgid_plural "%(counter)s results" +msgstr[0] "1 hakutulas" +msgstr[1] "%(counter)s hakutulosta" + +#: contrib/admin/templates/admin/search_form.html:10 +#, python-format +msgid "%(full_result_count)s total" +msgstr "yhteensä %(full_result_count)s" + +#: contrib/admin/templates/admin/filters.html:4 +msgid "Filter" +msgstr "Suodatin" + +#: contrib/admin/templates/admin/login.html:17 +#: contrib/comments/templates/comments/form.html:6 +#: contrib/comments/templates/comments/form.html:8 +msgid "Username:" +msgstr "Käyttäjätunnus" + +#: contrib/admin/templates/admin/login.html:20 +#: contrib/comments/templates/comments/form.html:8 +msgid "Password:" +msgstr "Salasana:" + +#: contrib/admin/templates/admin/login.html:22 +msgid "Have you <a href=\"/password_reset/\">forgotten your password</a>?" +msgstr "Oletko <a href=\"/password_reset\">unohtanut salasanasi</a>?" + +#: contrib/admin/templates/admin/base.html:24 +msgid "Welcome," +msgstr "Tervetuloa," + +#: contrib/admin/templates/admin/auth/user/add_form.html:6 +msgid "" +"First, enter a username and password. Then, you'll be able to edit more user " +"options." +msgstr "Syötä ensin käyttäjätunnus ja salasana. Sen jälkeen voit muokata muita käyttäjän tietoja." + +#: contrib/admin/templates/admin/auth/user/add_form.html:12 +msgid "Username" +msgstr "Käyttäjätunnus" + +#: contrib/admin/templates/admin/auth/user/add_form.html:18 +msgid "Password" +msgstr "Salasana:" + +#: contrib/admin/templates/admin/auth/user/add_form.html:23 +msgid "Password (again)" +msgstr "Salasana toistamiseen" + +#: contrib/admin/templates/admin/auth/user/add_form.html:24 +msgid "Enter the same password as above, for verification." +msgstr "Syötä sama salasana tarkistuksen vuoksi toistamiseen." + +#: contrib/admin/templates/admin_doc/bookmarklets.html:3 +msgid "Bookmarklets" +msgstr "Kirjanmerkkiset" + +#: contrib/admin/templates/admin_doc/bookmarklets.html:5 +msgid "Documentation bookmarklets" +msgstr "Ohjeiden kirjanmerkkiset" + +#: contrib/admin/templates/admin_doc/bookmarklets.html:9 +msgid "" +"\n" +"<p class=\"help\">To install bookmarklets, drag the link to your bookmarks\n" +"toolbar, or right-click the link and add it to your bookmarks. Now you can\n" +"select the bookmarklet from any page in the site. Note that some of these\n" +"bookmarklets require you to be viewing the site from a computer designated\n" +"as \"internal\" (talk to your system administrator if you aren't sure if\n" +"your computer is \"internal\").</p>\n" +msgstr "\n<p class=\"help\">Asenna kirjanmerkkinen raahaamalla linkki kirjanmerkkien työkalupalkkiin tai napsauttamalla linkkiä oikeanpuoleisella hiiren painikkeella ja valitsemalla kirjanmerkkeihin lisäämisen. Sen jälkeen voit valita kirjanmerkkisen miltä tahansa sivuston sivulta. Huomaa, että jotkin näistä kirjanmerkkisistä toimivat vain, jos selaat sivustoa \"paikalliseksi\" määritellyltä tietokoneelta (kysy lisätietoja verkkonne ylläpitäjältä).</p>\n" + +#: contrib/admin/templates/admin_doc/bookmarklets.html:19 +msgid "Documentation for this page" +msgstr "Tämän sivun ohjeita" + +#: contrib/admin/templates/admin_doc/bookmarklets.html:20 +msgid "" +"Jumps you from any page to the documentation for the view that generates " +"that page." +msgstr "Vie avoinna olevan sivun luoneen näkymän ohjeisiin." + +#: contrib/admin/templates/admin_doc/bookmarklets.html:22 +msgid "Show object ID" +msgstr "Näytä kohteen tunniste" + +#: contrib/admin/templates/admin_doc/bookmarklets.html:23 +msgid "" +"Shows the content-type and unique ID for pages that represent a single " +"object." +msgstr "Näyttää yksittäistä kohdetta vastaavilla sivuilla kohteen tyypin ja tunnisteen." + +#: contrib/admin/templates/admin_doc/bookmarklets.html:25 +msgid "Edit this object (current window)" +msgstr "Muokkaa tätä kohdetta (tässä ikkunassa)" + +#: contrib/admin/templates/admin_doc/bookmarklets.html:26 +msgid "Jumps to the admin page for pages that represent a single object." +msgstr "Siirtyy yksittäistä kohdetta vastaavalta sivulta kohteen ylläpitosivulle." + +#: contrib/admin/templates/admin_doc/bookmarklets.html:28 +msgid "Edit this object (new window)" +msgstr "Muokkaa tätä kohdetta (uudessa ikkunassa)" + +#: contrib/admin/templates/admin_doc/bookmarklets.html:29 +msgid "As above, but opens the admin page in a new window." +msgstr "Kuten yllä, mutta avaa ylläpitosivun uuteen ikkunaan." + +#: contrib/admin/templates/widget/date_time.html:3 +msgid "Date:" +msgstr "Pvm:" + +#: contrib/admin/templates/widget/date_time.html:4 +msgid "Time:" +msgstr "Klo:" + +#: contrib/admin/templates/widget/file.html:2 +msgid "Currently:" +msgstr "Tällä hetkellä:" + +#: contrib/admin/templates/widget/file.html:3 +msgid "Change:" +msgstr "Muokkaa:" + +#: contrib/admin/templates/registration/password_reset_form.html:4 +#: contrib/admin/templates/registration/password_reset_form.html:6 +#: contrib/admin/templates/registration/password_reset_form.html:10 +#: contrib/admin/templates/registration/password_reset_done.html:4 +msgid "Password reset" +msgstr "Salasanan nollaus" + +#: contrib/admin/templates/registration/password_reset_form.html:12 +msgid "" +"Forgotten your password? Enter your e-mail address below, and we'll reset " +"your password and e-mail the new one to you." +msgstr "" +"Unohditko salasanasi? Syötä alle sähköpostiosoitteesi, niin \n" +"lähetämme sinulle uuden salasanan." + +#: contrib/admin/templates/registration/password_reset_form.html:16 +msgid "E-mail address:" +msgstr "Sähköpostiosoite:" + +#: contrib/admin/templates/registration/password_reset_form.html:16 +msgid "Reset my password" +msgstr "Nollaa salasana" + +#: contrib/admin/templates/registration/password_reset_email.html:2 +msgid "You're receiving this e-mail because you requested a password reset" +msgstr "Sait tämän viestin, koska pyysit uutta salasanaa" + +#: contrib/admin/templates/registration/password_reset_email.html:3 +#, python-format +msgid "for your user account at %(site_name)s" +msgstr "sivuston %(site_name)s käyttäjätilillesi" + +#: contrib/admin/templates/registration/password_reset_email.html:5 +#, python-format +msgid "Your new password is: %(new_password)s" +msgstr "Uusi salasanasi on: %(new_password)s" + +#: contrib/admin/templates/registration/password_reset_email.html:7 +msgid "Feel free to change this password by going to this page:" +msgstr "Voit vaihtaa salasanan sivulla:" + +#: contrib/admin/templates/registration/password_reset_email.html:11 +msgid "Your username, in case you've forgotten:" +msgstr "Käyttäjätunnuksesi siltä varalta, että olet unohtanut sen:" + +#: contrib/admin/templates/registration/password_reset_email.html:13 +msgid "Thanks for using our site!" +msgstr "Kiitos vierailustasi sivuillemme!" + +#: contrib/admin/templates/registration/password_reset_email.html:15 +#, python-format +msgid "The %(site_name)s team" +msgstr "%(site_name)s ylläpitäjät" + +#: contrib/admin/templates/registration/logged_out.html:8 +msgid "Thanks for spending some quality time with the Web site today." +msgstr "Kiitos sivuillamme viettämästäsi ajasta." + +#: contrib/admin/templates/registration/logged_out.html:10 +msgid "Log in again" +msgstr "Kirjaudu uudelleen sisään" + +#: contrib/admin/templates/registration/password_reset_done.html:6 +#: contrib/admin/templates/registration/password_reset_done.html:10 +msgid "Password reset successful" +msgstr "Salasanan nollaus onnistui" + +#: contrib/admin/templates/registration/password_reset_done.html:12 +msgid "" +"We've e-mailed a new password to the e-mail address you submitted. You " +"should be receiving it shortly." +msgstr "" +"Uusi salasanasi on lähetetty antamaasi sähköpostiosoitteeseen.\n" +"Se saapuu tuota pikaa." + +#: contrib/admin/templates/registration/password_change_form.html:4 +#: contrib/admin/templates/registration/password_change_form.html:6 +#: contrib/admin/templates/registration/password_change_form.html:10 +#: contrib/admin/templates/registration/password_change_done.html:4 +msgid "Password change" +msgstr "Salasanan muuttaminen" + +#: contrib/admin/templates/registration/password_change_form.html:12 +msgid "" +"Please enter your old password, for security's sake, and then enter your new " +"password twice so we can verify you typed it in correctly." +msgstr "" +"Syötä vanha salasanasi varmistukseksi, ja syötä sitten uusi salasanasi\n" +"kaksi kertaa, jotta se tulee varmasti oikein." + +#: contrib/admin/templates/registration/password_change_form.html:17 +msgid "Old password:" +msgstr "Vanha salasana:" + +#: contrib/admin/templates/registration/password_change_form.html:19 +msgid "New password:" +msgstr "Uusi salasana:" + +#: contrib/admin/templates/registration/password_change_form.html:21 +msgid "Confirm password:" +msgstr "Varmista uusi salasana:" + +#: contrib/admin/templates/registration/password_change_form.html:23 +msgid "Change my password" +msgstr "Vaihda salasana" + +#: contrib/admin/templates/registration/password_change_done.html:6 +#: contrib/admin/templates/registration/password_change_done.html:10 +msgid "Password change successful" +msgstr "Salasanan muuttaminen onnistui" + +#: contrib/admin/templates/registration/password_change_done.html:12 +msgid "Your password was changed." +msgstr "Salasanasi on muutettu." + +#: contrib/sites/models.py:10 +msgid "domain name" +msgstr "domain-nimi" + +#: contrib/sites/models.py:11 +msgid "display name" +msgstr "näyttönimi" + +#: contrib/sites/models.py:15 +msgid "site" +msgstr "sivusto" + +#: contrib/sites/models.py:16 +msgid "sites" +msgstr "sivustot" + +#: contrib/flatpages/models.py:8 +msgid "" +"Example: '/about/contact/'. Make sure to have leading and trailing slashes." +msgstr "" +"Esimerkki: '/tietoja/yhteystiedot/'. Varmista, että sekä alussa että lopussa " +"on kauttaviiva." + +#: contrib/flatpages/models.py:9 +msgid "title" +msgstr "otsikko" + +#: contrib/flatpages/models.py:10 +msgid "content" +msgstr "sisältö" + +#: contrib/flatpages/models.py:11 +msgid "enable comments" +msgstr "salli kommentit" + +#: contrib/flatpages/models.py:12 +msgid "template name" +msgstr "mallipohjan nimi" + +#: contrib/flatpages/models.py:13 +msgid "" +"Example: 'flatpages/contact_page.html'. If this isn't provided, the system " +"will use 'flatpages/default.html'." +msgstr "Esimerkiksi: 'flatpages/yhteydenotto.html'. Jos tämä jätetään tyhjäksi, käytetään oletuspohjaa 'flatpages/default.html'." + +#: contrib/flatpages/models.py:14 +msgid "registration required" +msgstr "vaaditaan rekisteröityminen" + +#: contrib/flatpages/models.py:14 +msgid "If this is checked, only logged-in users will be able to view the page." +msgstr "Jos tämä kohta on valittu, vain sisäänkirjautuneet käyttäjät näkevät sivun." + +#: contrib/flatpages/models.py:18 +msgid "flat page" +msgstr "tekstisivu" + +#: contrib/flatpages/models.py:19 +msgid "flat pages" +msgstr "tekstisivut" + +#: contrib/redirects/models.py:7 +msgid "redirect from" +msgstr "ohjaa osoitteesta" + +#: contrib/redirects/models.py:8 +msgid "" +"This should be an absolute path, excluding the domain name. Example: '/" +"events/search/'." +msgstr "" +"Tässä on käytettävä absoluuttista polkua ilman verkkotunnusta. Esimerkki: " +"'\\\n" +"events/search/'" + +#: contrib/redirects/models.py:9 +msgid "redirect to" +msgstr "ohjaa osoitteeseen" + +#: contrib/redirects/models.py:10 +msgid "" +"This can be either an absolute path (as above) or a full URL starting with " +"'http://'." +msgstr "" +"Tässä on käytettävä joko absoluuttista polkua (kuten yllä) tai täydellistä " +"'http://'-alkuista URL-osoitetta." + +#: contrib/redirects/models.py:13 +msgid "redirect" +msgstr "edelleenohjaus" + +#: contrib/redirects/models.py:14 +msgid "redirects" +msgstr "edelleenohjaukset" + +#: contrib/comments/models.py:67 contrib/comments/models.py:166 +msgid "object ID" +msgstr "kohteen tunniste" + +#: contrib/comments/models.py:68 +msgid "headline" +msgstr "otsikko" + +#: contrib/comments/models.py:69 contrib/comments/models.py:90 +#: contrib/comments/models.py:167 +msgid "comment" +msgstr "kommentti" + +#: contrib/comments/models.py:70 +msgid "rating #1" +msgstr "1. pisteytys" + +#: contrib/comments/models.py:71 +msgid "rating #2" +msgstr "2. pisteytys" + +#: contrib/comments/models.py:72 +msgid "rating #3" +msgstr "3. pisteytys" + +#: contrib/comments/models.py:73 +msgid "rating #4" +msgstr "4. pisteytys" + +#: contrib/comments/models.py:74 +msgid "rating #5" +msgstr "5. pisteytys" + +#: contrib/comments/models.py:75 +msgid "rating #6" +msgstr "6. pisteytys" + +#: contrib/comments/models.py:76 +msgid "rating #7" +msgstr "7. pisteytys" + +#: contrib/comments/models.py:77 +msgid "rating #8" +msgstr "8. pisteytys" + +#: contrib/comments/models.py:82 +msgid "is valid rating" +msgstr "on sallittu pisteytys" + +#: contrib/comments/models.py:83 contrib/comments/models.py:169 +msgid "date/time submitted" +msgstr "lähetyshetki" + +#: contrib/comments/models.py:84 contrib/comments/models.py:170 +msgid "is public" +msgstr "on julkinen" + +#: contrib/comments/models.py:86 +msgid "is removed" +msgstr "on poistettu" + +#: contrib/comments/models.py:86 +msgid "" +"Check this box if the comment is inappropriate. A \"This comment has been " +"removed\" message will be displayed instead." +msgstr "" +"Rastita jos kommentti on asiaankuulumaton. Kommentin tilalla näytetään\n" +"viesti \"Tämä kommentti on poistettu\"." + +#: contrib/comments/models.py:91 +msgid "comments" +msgstr "kommentit" + +#: contrib/comments/models.py:131 contrib/comments/models.py:207 +msgid "Content object" +msgstr "Kommentoitu kohde" + +#: contrib/comments/models.py:159 +#, python-format +msgid "" +"Posted by %(user)s at %(date)s\n" +"\n" +"%(comment)s\n" +"\n" +"http://%(domain)s%(url)s" +msgstr "" +" Kirjoittanut %(user)s, pvm %(date)s\\n\n" +" \\n\n" +" %(comment)s\\n\n" +" \\n\n" +" http://%(domain)s%(url)s" + +#: contrib/comments/models.py:168 +msgid "person's name" +msgstr "henkilön nimi" + +#: contrib/comments/models.py:171 +msgid "ip address" +msgstr "IP-osoite" + +#: contrib/comments/models.py:173 +msgid "approved by staff" +msgstr "ylläpidon hyväksymä" + +#: contrib/comments/models.py:176 +msgid "free comment" +msgstr "vapaa kommentti" + +#: contrib/comments/models.py:177 +msgid "free comments" +msgstr "vapaat kommentit" + +#: contrib/comments/models.py:233 +msgid "score" +msgstr "pisteet" + +#: contrib/comments/models.py:234 +msgid "score date" +msgstr "pisteytyspäivä" + +#: contrib/comments/models.py:237 +msgid "karma score" +msgstr "karma-pisteytys" + +#: contrib/comments/models.py:238 +msgid "karma scores" +msgstr "karma-pisteytykset" + +#: contrib/comments/models.py:242 +#, python-format +msgid "%(score)d rating by %(user)s" +msgstr "%(score)d pistettä käyttäjältä %(user)s" + +#: contrib/comments/models.py:258 +#, python-format +msgid "" +"This comment was flagged by %(user)s:\n" +"\n" +"%(text)s" +msgstr "" +" %(user)s on merkinnyt tämän kommentin:\\n\n" +" \\n\n" +" %(text)s" + +#: contrib/comments/models.py:265 +msgid "flag date" +msgstr "merkintäpäivä" + +#: contrib/comments/models.py:268 +msgid "user flag" +msgstr "käyttäjän merkki" + +#: contrib/comments/models.py:269 +msgid "user flags" +msgstr "käyttäjien merkit" + +#: contrib/comments/models.py:273 +#, python-format +msgid "Flag by %r" +msgstr "Käyttäjän %r merkki" + +#: contrib/comments/models.py:278 +msgid "deletion date" +msgstr "poistamispäivä" + +#: contrib/comments/models.py:280 +msgid "moderator deletion" +msgstr "valvojan poisto" + +#: contrib/comments/models.py:281 +msgid "moderator deletions" +msgstr "valvojien poistot" + +#: contrib/comments/models.py:285 +#, python-format +msgid "Moderator deletion by %r" +msgstr "Valvojan %r poisto" + +#: contrib/comments/views/karma.py:19 +msgid "Anonymous users cannot vote" +msgstr "Anonyymit käyttäjät eivät voi äänestää" + +#: contrib/comments/views/karma.py:23 +msgid "Invalid comment ID" +msgstr "Kommentin tunniste on virheellinen" + +#: contrib/comments/views/karma.py:25 +msgid "No voting for yourself" +msgstr "Itseään ei voi äänestää" + +#: contrib/comments/views/comments.py:27 +msgid "" +"This rating is required because you've entered at least one other rating." +msgstr "Tämä pisteytys on annettava, koska olet syöttänyt ainakin yhden muunkin pisteytyksen." + +#: contrib/comments/views/comments.py:111 +#, python-format +msgid "" +"This comment was posted by a user who has posted fewer than %(count)s " +"comment:\n" +"\n" +"%(text)s" +msgid_plural "" +"This comment was posted by a user who has posted fewer than %(count)s " +"comments:\n" +"\n" +"%(text)s" +msgstr[0] "" +msgstr[1] "" + +# Mitä "sketchy user" tarkoittaa? +#: contrib/comments/views/comments.py:116 +#, python-format +msgid "" +"This comment was posted by a sketchy user:\n" +"\n" +"%(text)s" +msgstr "" +"Tämä on \"sketchy\"-käyttäjän kirjoittama kommentti:\n" +"\n" +"%(text)s" + +#: contrib/comments/views/comments.py:188 +#: contrib/comments/views/comments.py:280 +msgid "Only POSTs are allowed" +msgstr "Vain POST-kutsut sallittu" + +#: contrib/comments/views/comments.py:192 +#: contrib/comments/views/comments.py:284 +msgid "One or more of the required fields wasn't submitted" +msgstr "Yksi tai useampi vaadittu kenttä on jäänyt täyttämättä" + +#: contrib/comments/views/comments.py:196 +#: contrib/comments/views/comments.py:286 +msgid "Somebody tampered with the comment form (security violation)" +msgstr "Kommenttilomaketta on käpälöity (turvallisuusrike)" + +#: contrib/comments/views/comments.py:206 +#: contrib/comments/views/comments.py:292 +msgid "" +"The comment form had an invalid 'target' parameter -- the object ID was " +"invalid" +msgstr "Kommenttilomakkeen 'target'-parametri ei kelpaa -- kohteen ID oli virheellinen" + +#: contrib/comments/views/comments.py:257 +#: contrib/comments/views/comments.py:321 +msgid "The comment form didn't provide either 'preview' or 'post'" +msgstr "Kommenttilomake ei pyytänyt esikatselua tai lähettämistä" + +#: contrib/comments/templates/comments/form.html:8 +msgid "Forgotten your password?" +msgstr "Unohditko salasanasi?" + +#: contrib/comments/templates/comments/form.html:12 +msgid "Ratings" +msgstr "Pisteytykset" + +#: contrib/comments/templates/comments/form.html:12 +#: contrib/comments/templates/comments/form.html:23 +msgid "Required" +msgstr "Vaaditaan" + +#: contrib/comments/templates/comments/form.html:12 +#: contrib/comments/templates/comments/form.html:23 +msgid "Optional" +msgstr "Vapaavalintainen" + +#: contrib/comments/templates/comments/form.html:23 +msgid "Post a photo" +msgstr "Lähetä valokuva" + +#: contrib/comments/templates/comments/form.html:28 +#: contrib/comments/templates/comments/freeform.html:5 +msgid "Comment:" +msgstr "Kommentti:" + +#: contrib/comments/templates/comments/form.html:35 +#: contrib/comments/templates/comments/freeform.html:10 +msgid "Preview comment" +msgstr "Esikatsele kommenttia" + +#: contrib/comments/templates/comments/freeform.html:4 +msgid "Your name:" +msgstr "Nimesi:" + +#: contrib/sessions/models.py:51 +msgid "session key" +msgstr "istunnon avain" + +#: contrib/sessions/models.py:52 +msgid "session data" +msgstr "istunnon tiedot" + +#: contrib/sessions/models.py:53 +msgid "expire date" +msgstr "vanhenee" + +#: contrib/sessions/models.py:57 +msgid "session" +msgstr "istunto" + +#: contrib/sessions/models.py:58 +msgid "sessions" +msgstr "istunnot" + +#: contrib/contenttypes/models.py:20 +msgid "python model class name" +msgstr "mallin python-luokan nimi" + +#: contrib/contenttypes/models.py:23 +msgid "content type" +msgstr "sisältötyyppi" + +#: contrib/contenttypes/models.py:24 +msgid "content types" +msgstr "sisältötyypit" + +#: forms/__init__.py:381 +#, python-format +msgid "Ensure your text is less than %s character." +msgid_plural "Ensure your text is less than %s characters." +msgstr[0] "Varmista, että tekstin pituus on vähemmän kuin %s merkki." +msgstr[1] "Varmista, että teksti pituus on vähemmän kuin %s merkkiä." + +#: forms/__init__.py:386 +msgid "Line breaks are not allowed here." +msgstr "Rivinvaihtoja ei voi käyttää." + +#: forms/__init__.py:487 forms/__init__.py:560 forms/__init__.py:599 +#, python-format +msgid "Select a valid choice; '%(data)s' is not in %(choices)s." +msgstr "Valinta ei kelpaa; '%(data)s' ei löydy vaihtoehtojen %(choices)s joukosta." + +#: forms/__init__.py:663 +msgid "The submitted file is empty." +msgstr "Lähetetty tiedosto on tyhjä." + +#: forms/__init__.py:719 +msgid "Enter a whole number between -32,768 and 32,767." +msgstr "Syötä kokonaisluku väliltä -32768 ja 32767." + +#: forms/__init__.py:729 +msgid "Enter a positive number." +msgstr "Syötä positiivinen kokonaisluku." + +#: forms/__init__.py:739 +msgid "Enter a whole number between 0 and 32,767." +msgstr "Syötä kokonaisluku väliltä 0 ja 32767." + +#: utils/dates.py:6 +msgid "Monday" +msgstr "maanantai" + +#: utils/dates.py:6 +msgid "Tuesday" +msgstr "tiistai" + +#: utils/dates.py:6 +msgid "Wednesday" +msgstr "keskiviikko" + +#: utils/dates.py:6 +msgid "Thursday" +msgstr "torstai" + +#: utils/dates.py:6 +msgid "Friday" +msgstr "perjantai" + +#: utils/dates.py:7 +msgid "Saturday" +msgstr "lauantai" + +#: utils/dates.py:7 +msgid "Sunday" +msgstr "sunnuntai" + +#: utils/dates.py:14 +msgid "January" +msgstr "tammikuu" + +#: utils/dates.py:14 +msgid "February" +msgstr "helmikuu" + +#: utils/dates.py:14 utils/dates.py:27 +msgid "March" +msgstr "maaliskuu" + +#: utils/dates.py:14 utils/dates.py:27 +msgid "April" +msgstr "huhtikuu" + +#: utils/dates.py:14 utils/dates.py:27 +msgid "May" +msgstr "toukokuu" + +#: utils/dates.py:14 utils/dates.py:27 +msgid "June" +msgstr "kesäkuu" + +#: utils/dates.py:15 utils/dates.py:27 +msgid "July" +msgstr "heinäkuu" + +#: utils/dates.py:15 +msgid "August" +msgstr "elokuu" + +#: utils/dates.py:15 +msgid "September" +msgstr "syyskuu" + +#: utils/dates.py:15 +msgid "October" +msgstr "lokakuu" + +#: utils/dates.py:15 +msgid "November" +msgstr "marraskuu" + +#: utils/dates.py:16 +msgid "December" +msgstr "joulukuu" + +#: utils/dates.py:19 +msgid "jan" +msgstr "tam" + +#: utils/dates.py:19 +msgid "feb" +msgstr "hel" + +#: utils/dates.py:19 +msgid "mar" +msgstr "maa" + +#: utils/dates.py:19 +msgid "apr" +msgstr "huh" + +#: utils/dates.py:19 +msgid "may" +msgstr "tou" + +#: utils/dates.py:19 +msgid "jun" +msgstr "kes" + +#: utils/dates.py:20 +msgid "jul" +msgstr "hei" + +#: utils/dates.py:20 +msgid "aug" +msgstr "elo" + +#: utils/dates.py:20 +msgid "sep" +msgstr "syy" + +#: utils/dates.py:20 +msgid "oct" +msgstr "lok" + +#: utils/dates.py:20 +msgid "nov" +msgstr "mar" + +#: utils/dates.py:20 +msgid "dec" +msgstr "jou" + +#: utils/dates.py:27 +msgid "Jan." +msgstr "tammi" + +#: utils/dates.py:27 +msgid "Feb." +msgstr "helmi" + +#: utils/dates.py:28 +msgid "Aug." +msgstr "elo" + +#: utils/dates.py:28 +msgid "Sept." +msgstr "syys" + +#: utils/dates.py:28 +msgid "Oct." +msgstr "loka" + +#: utils/dates.py:28 +msgid "Nov." +msgstr "marras" + +#: utils/dates.py:28 +msgid "Dec." +msgstr "joulu" + +#: utils/timesince.py:12 +msgid "year" +msgid_plural "years" +msgstr[0] "" +msgstr[1] "" + +#: utils/timesince.py:13 +msgid "month" +msgid_plural "months" +msgstr[0] "" +msgstr[1] "" + +#: utils/timesince.py:14 +msgid "week" +msgid_plural "weeks" +msgstr[0] "" +msgstr[1] "" + +#: utils/timesince.py:15 +msgid "day" +msgid_plural "days" +msgstr[0] "" +msgstr[1] "" + +#: utils/timesince.py:16 +msgid "hour" +msgid_plural "hours" +msgstr[0] "" +msgstr[1] "" + +#: utils/timesince.py:17 +msgid "minute" +msgid_plural "minutes" +msgstr[0] "" +msgstr[1] "" + +#: utils/translation/trans_real.py:362 +msgid "DATE_FORMAT" +msgstr "j.n.Y" + +#: utils/translation/trans_real.py:363 +msgid "DATETIME_FORMAT" +msgstr "j.n.Y G:i" + +#: utils/translation/trans_real.py:364 +msgid "TIME_FORMAT" +msgstr "G:i" + +#: utils/translation/trans_real.py:380 +msgid "YEAR_MONTH_FORMAT" +msgstr "N j, Y" + +#: utils/translation/trans_real.py:381 +#, fuzzy +msgid "MONTH_DAY_FORMAT" +msgstr "N j, Y" + +#: template/defaultfilters.py:401 +msgid "yes,no,maybe" +msgstr "kyllä,ei,ehkä" diff --git a/django/conf/locale/fi/LC_MESSAGES/djangojs.mo b/django/conf/locale/fi/LC_MESSAGES/djangojs.mo Binary files differnew file mode 100644 index 0000000000..34b397e4ba --- /dev/null +++ b/django/conf/locale/fi/LC_MESSAGES/djangojs.mo diff --git a/django/conf/locale/fi/LC_MESSAGES/djangojs.po b/django/conf/locale/fi/LC_MESSAGES/djangojs.po new file mode 100644 index 0000000000..35aa82e893 --- /dev/null +++ b/django/conf/locale/fi/LC_MESSAGES/djangojs.po @@ -0,0 +1,110 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2005-12-09 11:51+0100\n" +"PO-Revision-Date: 2006-08-05 15:27+0300\n" +"Last-Translator: Antti Kaihola <akaihola@ambitone.com>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: contrib/admin/media/js/SelectFilter2.js:33 +#, perl-format +msgid "Available %s" +msgstr "Mahdolliset %s" + +#: contrib/admin/media/js/SelectFilter2.js:41 +msgid "Choose all" +msgstr "Valitse kaikki" + +#: contrib/admin/media/js/SelectFilter2.js:46 +msgid "Add" +msgstr "Lisää uusi" + +#: contrib/admin/media/js/SelectFilter2.js:48 +msgid "Remove" +msgstr "Poista" + +#: contrib/admin/media/js/SelectFilter2.js:53 +#, perl-format +msgid "Chosen %s" +msgstr "Valitut %s" + +#: contrib/admin/media/js/SelectFilter2.js:54 +msgid "Select your choice(s) and click " +msgstr "Valitse vasemmalta ja napsauta " + +#: contrib/admin/media/js/SelectFilter2.js:59 +msgid "Clear all" +msgstr "Tyhjennä kaikki" + +#: contrib/admin/media/js/dateparse.js:26 +#: contrib/admin/media/js/calendar.js:24 +msgid "" +"January February March April May June July August September October November " +"December" +msgstr "" +"Tammikuu Helmikuu Maaliskuu Huhtikuu Toukokuu Kesäkuu Heinäkuu Elokuu " +"Syyskuu Lokakuu Marraskuu Joulukuu" + +#: contrib/admin/media/js/dateparse.js:27 +msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday" +msgstr "Sunnuntai Maanantai Tiistai Keskiviikko Torstai Perjantai Lauantai" + +#: contrib/admin/media/js/calendar.js:25 +msgid "S M T W T F S" +msgstr "S M T K T P L" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45 +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80 +msgid "Now" +msgstr "Nyt" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48 +msgid "Clock" +msgstr "Kello" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77 +msgid "Choose a time" +msgstr "Valitse kellonaika" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81 +msgid "Midnight" +msgstr "24" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82 +msgid "6 a.m." +msgstr "06" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83 +msgid "Noon" +msgstr "12" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87 +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168 +msgid "Cancel" +msgstr "Peruuta" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111 +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162 +msgid "Today" +msgstr "Tänään" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114 +msgid "Calendar" +msgstr "Kalenteri" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160 +msgid "Yesterday" +msgstr "Eilen" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164 +msgid "Tomorrow" +msgstr "Huomenna" diff --git a/django/conf/locale/ja/LC_MESSAGES/django.mo b/django/conf/locale/ja/LC_MESSAGES/django.mo Binary files differindex 34b80e976e..e6725c1140 100644 --- a/django/conf/locale/ja/LC_MESSAGES/django.mo +++ b/django/conf/locale/ja/LC_MESSAGES/django.mo diff --git a/django/conf/locale/ja/LC_MESSAGES/django.po b/django/conf/locale/ja/LC_MESSAGES/django.po index dbc3de5f53..a55af3b45d 100644 --- a/django/conf/locale/ja/LC_MESSAGES/django.po +++ b/django/conf/locale/ja/LC_MESSAGES/django.po @@ -1,14 +1,13 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# Translation of django.po to japanese. +# Copyright (C) 2005,2006 THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# makoto tsuyuki <mtsuyuki@gmail.com>, 2005,2006. # -#, fuzzy msgid "" msgstr "" "Project-Id-Version: Django 1.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2006-05-18 00:21+0900\n" +"POT-Creation-Date: 2006-10-21 20:42+0900\n" "PO-Revision-Date: 2006-05-18 00:28+0900\n" "Last-Translator: makoto tsuyuki <mtsuyuki@gmail.com>\n" "Language-Team: Japanese <django-ja@googlegroups.com>\n" @@ -16,113 +15,135 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: conf/global_settings.py:37 +#: conf/global_settings.py:39 +msgid "Arabic" +msgstr "アラビア語" + +#: conf/global_settings.py:40 msgid "Bengali" msgstr "ベンガル語" -#: conf/global_settings.py:38 +#: conf/global_settings.py:41 msgid "Czech" msgstr "ãƒã‚§ã‚³èªž" -#: conf/global_settings.py:39 +#: conf/global_settings.py:42 msgid "Welsh" msgstr "ウェールズ語" -#: conf/global_settings.py:40 +#: conf/global_settings.py:43 msgid "Danish" msgstr "デンマーク語" -#: conf/global_settings.py:41 +#: conf/global_settings.py:44 msgid "German" msgstr "ドイツ語" -#: conf/global_settings.py:42 +#: conf/global_settings.py:45 msgid "Greek" msgstr "ギリシャ語" -#: conf/global_settings.py:43 +#: conf/global_settings.py:46 msgid "English" msgstr "英語" -#: conf/global_settings.py:44 +#: conf/global_settings.py:47 msgid "Spanish" msgstr "スペイン語" -#: conf/global_settings.py:45 +#: conf/global_settings.py:48 +msgid "Argentinean Spanish" +msgstr "アルゼンãƒãƒ³ã‚¹ãƒšã‚¤ãƒ³èªž" + +#: conf/global_settings.py:49 +msgid "Finnish" +msgstr "フィンランド語" + +#: conf/global_settings.py:50 msgid "French" msgstr "フランス語" -#: conf/global_settings.py:46 +#: conf/global_settings.py:51 msgid "Galician" msgstr "ガリシア語" -#: conf/global_settings.py:47 +#: conf/global_settings.py:52 msgid "Hungarian" msgstr "ãƒãƒ³ã‚¬ãƒªãƒ¼èªž" -#: conf/global_settings.py:48 +#: conf/global_settings.py:53 msgid "Hebrew" msgstr "ヘブライ語" -#: conf/global_settings.py:49 +#: conf/global_settings.py:54 msgid "Icelandic" msgstr "アイスランド語" -#: conf/global_settings.py:50 +#: conf/global_settings.py:55 msgid "Italian" msgstr "イタリア語" -#: conf/global_settings.py:51 +#: conf/global_settings.py:56 msgid "Japanese" msgstr "日本語" -#: conf/global_settings.py:52 +#: conf/global_settings.py:57 msgid "Dutch" msgstr "オランダ語" -#: conf/global_settings.py:53 +#: conf/global_settings.py:58 msgid "Norwegian" msgstr "ノルウェー語" -#: conf/global_settings.py:54 +#: conf/global_settings.py:59 +msgid "Polish" +msgstr "ãƒãƒ¼ãƒ©ãƒ³ãƒ‰èªž" + +#: conf/global_settings.py:60 msgid "Brazilian" msgstr "ブラジル語" -#: conf/global_settings.py:55 +#: conf/global_settings.py:61 msgid "Romanian" msgstr "ルーマニア語" -#: conf/global_settings.py:56 +#: conf/global_settings.py:62 msgid "Russian" msgstr "ãƒã‚·ã‚¢èªž" -#: conf/global_settings.py:57 +#: conf/global_settings.py:63 msgid "Slovak" msgstr "スãƒãƒã‚ア語" -#: conf/global_settings.py:58 -#, fuzzy +#: conf/global_settings.py:64 msgid "Slovenian" msgstr "スãƒãƒ´ã‚§ãƒ‹ã‚¢èªž" -#: conf/global_settings.py:59 +#: conf/global_settings.py:65 msgid "Serbian" msgstr "セルビア語" -#: conf/global_settings.py:60 +#: conf/global_settings.py:66 msgid "Swedish" msgstr "スウェーデン語" -#: conf/global_settings.py:61 -#, fuzzy +#: conf/global_settings.py:67 +msgid "Tamil" +msgstr "タミル語" + +#: conf/global_settings.py:68 +msgid "Turkish" +msgstr "トルコ語" + +#: conf/global_settings.py:69 msgid "Ukrainian" msgstr "ウクライナ語" -#: conf/global_settings.py:62 +#: conf/global_settings.py:70 msgid "Simplified Chinese" msgstr "簡体å—ä¸å›½èªž" -#: conf/global_settings.py:63 +#: conf/global_settings.py:71 msgid "Traditional Chinese" msgstr "ç¹ä½“å—ä¸å›½èªž" @@ -136,7 +157,7 @@ msgstr "" "<ul>\n" #: contrib/admin/filterspecs.py:70 contrib/admin/filterspecs.py:88 -#: contrib/admin/filterspecs.py:143 +#: contrib/admin/filterspecs.py:143 contrib/admin/filterspecs.py:169 msgid "All" msgstr "å…¨ã¦" @@ -210,10 +231,11 @@ msgid "We're sorry, but the requested page could not be found." msgstr "申ã—訳ã‚りã¾ã›ã‚“ãŒã€ãпޢã—ã®ãƒšãƒ¼ã‚¸ã¯è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚" #: contrib/admin/templates/admin/500.html:4 -#: contrib/admin/templates/admin/base.html:28 +#: contrib/admin/templates/admin/base.html:30 #: contrib/admin/templates/admin/change_form.html:13 #: contrib/admin/templates/admin/change_list.html:6 #: contrib/admin/templates/admin/delete_confirmation.html:6 +#: contrib/admin/templates/admin/invalid_setup.html:4 #: contrib/admin/templates/admin/object_history.html:5 #: contrib/admin/templates/admin_doc/bookmarklets.html:3 #: contrib/admin/templates/registration/logged_out.html:4 @@ -244,11 +266,11 @@ msgstr "" "エラーãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚エラーをサイトã®ç®¡ç†è€…ã«ãƒ¡ãƒ¼ãƒ«ã§å ±å‘Šã—ã¾ã—ãŸã®ã§ã€è¿‘ã„" "ã†ã¡ã«ä¿®æ£ã•れるã¯ãšã§ã™ã€‚ã—ã°ã‚‰ããŠå¾…ã¡ãã ã•ã„。" -#: contrib/admin/templates/admin/base.html:23 +#: contrib/admin/templates/admin/base.html:25 msgid "Welcome," msgstr "よã†ã“ã" -#: contrib/admin/templates/admin/base.html:23 +#: contrib/admin/templates/admin/base.html:25 #: contrib/admin/templates/admin/change_form.html:10 #: contrib/admin/templates/admin/change_list.html:5 #: contrib/admin/templates/admin/delete_confirmation.html:3 @@ -259,7 +281,7 @@ msgstr "よã†ã“ã" msgid "Documentation" msgstr "ドã‚ュメント" -#: contrib/admin/templates/admin/base.html:23 +#: contrib/admin/templates/admin/base.html:25 #: contrib/admin/templates/admin/change_form.html:10 #: contrib/admin/templates/admin/change_list.html:5 #: contrib/admin/templates/admin/delete_confirmation.html:3 @@ -279,7 +301,7 @@ msgstr "ドã‚ュメント" msgid "Change password" msgstr "パスワードã®å¤‰æ›´" -#: contrib/admin/templates/admin/base.html:23 +#: contrib/admin/templates/admin/base.html:25 #: contrib/admin/templates/admin/change_form.html:10 #: contrib/admin/templates/admin/change_list.html:5 #: contrib/admin/templates/admin/delete_confirmation.html:3 @@ -296,7 +318,7 @@ msgstr "パスワードã®å¤‰æ›´" #: contrib/admin/templates/admin_doc/view_index.html:5 #: contrib/admin/templates/registration/password_change_done.html:3 #: contrib/admin/templates/registration/password_change_form.html:3 -#: contrib/comments/templates/comments/form.html:8 +#: contrib/comments/templates/comments/form.html:6 msgid "Log out" msgstr "ãƒã‚°ã‚¢ã‚¦ãƒˆ" @@ -306,7 +328,7 @@ msgstr "Django サイト管ç†" #: contrib/admin/templates/admin/base_site.html:7 msgid "Django administration" -msgstr "Django ã®ç®¡ç†" +msgstr "Django 管ç†ã‚µã‚¤ãƒˆ" #: contrib/admin/templates/admin/change_form.html:15 #: contrib/admin/templates/admin/index.html:28 @@ -349,22 +371,22 @@ msgstr "削除" #: contrib/admin/templates/admin/delete_confirmation.html:14 #, python-format msgid "" -"Deleting the %(object_name)s '%(object)s' would result in deleting related " -"objects, but your account doesn't have permission to delete the following " -"types of objects:" +"Deleting the %(object_name)s '%(escaped_object)s' would result in deleting " +"related objects, but your account doesn't have permission to delete the " +"following types of objects:" msgstr "" -"%(object_name)s '%(object)s' ã®å‰Šé™¤æ™‚ã«é–¢é€£ã¥ã‘られãŸã‚ªãƒ–ジェクトも削除ã—よã†" -"ã¨ã—ã¾ã—ãŸãŒã€ã‚ãªãŸã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã«ã¯ä»¥ä¸‹ã®ã‚¿ã‚¤ãƒ—ã®ã‚ªãƒ–ジェクトを削除ã™ã‚‹ãƒ‘ー" -"ミッションãŒã‚りã¾ã›ã‚“:" +"%(object_name)s '%(escaped_object)s' ã®å‰Šé™¤æ™‚ã«é–¢é€£ã¥ã‘られãŸã‚ªãƒ–ジェクトも削" +"除ã—よã†ã¨ã—ã¾ã—ãŸãŒã€ã‚ãªãŸã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã«ã¯ä»¥ä¸‹ã®ã‚¿ã‚¤ãƒ—ã®ã‚ªãƒ–ジェクトを削除" +"ã™ã‚‹ãƒ‘ーミッションãŒã‚りã¾ã›ã‚“:" #: contrib/admin/templates/admin/delete_confirmation.html:21 #, python-format msgid "" -"Are you sure you want to delete the %(object_name)s \"%(object)s\"? All of " -"the following related items will be deleted:" +"Are you sure you want to delete the %(object_name)s \"%(escaped_object)s\"? " +"All of the following related items will be deleted:" msgstr "" -"%(object_name)s \"%(object)s\"を削除ã—ã¾ã™ã‹ï¼Ÿ 関連ã¥ã‘られã¦ã„る以下ã®ã‚ªãƒ–" -"ジェクトも全ã¦å‰Šé™¤ã•れã¾ã™:" +"%(object_name)s \"%(escaped_object)s\"を削除ã—ã¾ã™ã‹ï¼Ÿ 関連ã¥ã‘られã¦ã„る以下" +"ã®ã‚ªãƒ–ジェクトも全ã¦å‰Šé™¤ã•れã¾ã™:" #: contrib/admin/templates/admin/delete_confirmation.html:26 msgid "Yes, I'm sure" @@ -372,14 +394,23 @@ msgstr "ã¯ã„。" #: contrib/admin/templates/admin/filter.html:2 #, python-format -msgid " By %(title)s " -msgstr "%(title)s ã§çµžã‚Šè¾¼ã‚€" +msgid " By %(filter_title)s " +msgstr "%(filter_title)s ã§çµžã‚Šè¾¼ã‚€" + +#: contrib/admin/templates/admin/filters.html:4 +msgid "Filter" +msgstr "フィルタ" #: contrib/admin/templates/admin/index.html:17 #, python-format msgid "Models available in the %(name)s application." msgstr "%(name)s アプリケーションã§åˆ©ç”¨å¯èƒ½ãªãƒ¢ãƒ‡ãƒ«" +#: contrib/admin/templates/admin/index.html:18 +#, python-format +msgid "%(name)s" +msgstr "%(name)s" + #: contrib/admin/templates/admin/index.html:34 msgid "Change" msgstr "変更" @@ -400,6 +431,15 @@ msgstr "æ“作" msgid "None available" msgstr "利用ä¸å¯" +#: contrib/admin/templates/admin/invalid_setup.html:8 +msgid "" +"Something's wrong with your database installation. Make sure the appropriate " +"database tables have been created, and make sure the database is readable by " +"the appropriate user." +msgstr "" +"データベースã®è¨å®šã«å•題ãŒã‚るよã†ã§ã™ã€‚é©åˆ‡ãªãƒ†ãƒ¼ãƒ–ルãŒä½œã‚‰ã‚Œã¦ã„ã‚‹ã“ã¨ã€é©" +"切ãªãƒ¦ãƒ¼ã‚¶ã§ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®ãƒ‡ãƒ¼ã‚¿ã‚’èªã¿è¾¼ã‚ã‚‹ã“ã¨ã‚’確èªã—ã¦ãã ã•ã„。" + #: contrib/admin/templates/admin/login.html:17 #: contrib/comments/templates/comments/form.html:6 #: contrib/comments/templates/comments/form.html:8 @@ -407,7 +447,7 @@ msgid "Username:" msgstr "ユーザå:" #: contrib/admin/templates/admin/login.html:20 -#: contrib/comments/templates/comments/form.html:6 +#: contrib/comments/templates/comments/form.html:8 msgid "Password:" msgstr "パスワード:" @@ -416,7 +456,7 @@ msgid "Have you <a href=\"/password_reset/\">forgotten your password</a>?" msgstr "<a href=\"/password_reset/\">パスワードをãŠå¿˜ã‚Œã§ã™ã‹</a>?" #: contrib/admin/templates/admin/login.html:25 -#: contrib/admin/views/decorators.py:23 +#: contrib/admin/views/decorators.py:24 msgid "Log in" msgstr "ãƒã‚°ã‚¤ãƒ³" @@ -444,10 +484,26 @@ msgstr "" "ã“ã®ã‚ªãƒ–ジェクトã«ã¯å¤‰æ›´å±¥æ´ãŒã‚りã¾ã›ã‚“。ãŠãらãã“ã®ç®¡ç†ã‚µã‚¤ãƒˆã§è¿½åŠ ã—ãŸã‚‚" "ã®ã§ã¯ã‚りã¾ã›ã‚“。" +#: contrib/admin/templates/admin/pagination.html:10 +msgid "Show all" +msgstr "全件表示" + #: contrib/admin/templates/admin/search_form.html:8 msgid "Go" msgstr "検索" +#: contrib/admin/templates/admin/search_form.html:10 +#, python-format +msgid "1 result" +msgid_plural "%(counter)s results" +msgstr[0] "1 ä»¶" +msgstr[1] "%(counter)s ä»¶" + +#: contrib/admin/templates/admin/search_form.html:10 +#, python-format +msgid "%(full_result_count)s total" +msgstr "å…¨ %(full_result_count)s ä»¶" + #: contrib/admin/templates/admin/submit_line.html:4 msgid "Save as new" msgstr "æ–°è¦ä¿å˜" @@ -464,6 +520,30 @@ msgstr "ä¿å˜ã—ã¦ç·¨é›†ã‚’ç¶šã‘ã‚‹" msgid "Save" msgstr "ä¿å˜" +#: contrib/admin/templates/admin/auth/user/add_form.html:6 +msgid "" +"First, enter a username and password. Then, you'll be able to edit more user " +"options." +msgstr "" +"ã¾ãšãƒ¦ãƒ¼ã‚¶åã¨ãƒ‘スワードを登録ã—ã¦ãã ã•ã„。ãã®å¾Œè©³ç´°æƒ…å ±ãŒç·¨é›†å¯èƒ½ã«ãªã‚Šã¾" +"ã™ã€‚" + +#: contrib/admin/templates/admin/auth/user/add_form.html:12 +msgid "Username" +msgstr "ユーザå" + +#: contrib/admin/templates/admin/auth/user/add_form.html:18 +msgid "Password" +msgstr "パスワード" + +#: contrib/admin/templates/admin/auth/user/add_form.html:23 +msgid "Password (again)" +msgstr "パスワード(確èªç”¨)" + +#: contrib/admin/templates/admin/auth/user/add_form.html:24 +msgid "Enter the same password as above, for verification." +msgstr "確èªã®ãŸã‚ã€å†åº¦ãƒ‘スワードを入力ã—ã¦ãã ã•ã„。" + #: contrib/admin/templates/admin_doc/bookmarklets.html:3 msgid "Bookmarklets" msgstr "ブックマークレット" @@ -572,7 +652,7 @@ msgstr "æ–°ã—ã„パスワード:" #: contrib/admin/templates/registration/password_change_form.html:21 msgid "Confirm password:" -msgstr "æ–°ã—ã„パスワード (ã‚‚ã†ä¸€åº¦) :" +msgstr "æ–°ã—ã„パスワード (確èªç”¨) :" #: contrib/admin/templates/registration/password_change_form.html:23 msgid "Change my password" @@ -663,19 +743,32 @@ msgstr "ç¾åœ¨:" msgid "Change:" msgstr "変更:" -#: contrib/admin/templatetags/admin_list.py:228 +#: contrib/admin/templatetags/admin_list.py:230 msgid "All dates" msgstr "ã„ã¤ã§ã‚‚" -#: contrib/admin/views/decorators.py:9 contrib/auth/forms.py:36 -#: contrib/auth/forms.py:41 +#: contrib/admin/views/auth.py:17 contrib/admin/views/main.py:257 +#, python-format +msgid "The %(name)s \"%(obj)s\" was added successfully." +msgstr "%(name)s \"%(obj)s\" ã‚’è¿½åŠ ã—ã¾ã—ãŸã€‚" + +#: contrib/admin/views/auth.py:22 contrib/admin/views/main.py:261 +#: contrib/admin/views/main.py:347 +msgid "You may edit it again below." +msgstr "ç¶šã‘ã¦ç·¨é›†ã§ãã¾ã™ã€‚" + +#: contrib/admin/views/auth.py:28 +msgid "Add user" +msgstr "ãƒ¦ãƒ¼ã‚¶ã‚’è¿½åŠ " + +#: contrib/admin/views/decorators.py:10 contrib/auth/forms.py:59 msgid "" "Please enter a correct username and password. Note that both fields are case-" "sensitive." msgstr "" "æ£ã—ã„ユーザåã¨ãƒ‘スワードを入力ã—ã¦ãã ã•ã„ (大文å—å°æ–‡å—ã¯åŒºåˆ¥ã—ã¾ã™) 。" -#: contrib/admin/views/decorators.py:61 +#: contrib/admin/views/decorators.py:62 msgid "" "Please log in again, because your session has expired. Don't worry: Your " "submission has been saved." @@ -683,7 +776,7 @@ msgstr "" "å†ãƒã‚°ã‚¤ãƒ³ã—ã¦ãã ã•ã„。ãƒã‚°ã‚¤ãƒ³ã‚»ãƒƒã‚·ãƒ§ãƒ³ãŒæœ‰åŠ¹æœŸé–“åˆ‡ã‚Œã—ã¦ã—ã¾ã„ã¾ã—ãŸã€‚å…¥" "力データã¯å¤±ã‚れã¦ãŠã‚Šã¾ã›ã‚“ã®ã§ã”安心ãã ã•ã„。" -#: contrib/admin/views/decorators.py:68 +#: contrib/admin/views/decorators.py:69 msgid "" "Looks like your browser isn't configured to accept cookies. Please enable " "cookies, reload this page, and try again." @@ -691,188 +784,252 @@ msgstr "" "ブラウザãŒã‚¯ãƒƒã‚ーã®ä½¿ç”¨ã‚’許å¯ã—ã¦ã„ãªã„よã†ã§ã™ã€‚クッã‚ーã®ä½¿ç”¨ã‚’許å¯ã—ã¦ã€" "ã‚‚ã†ä¸€åº¦ã“ã®ãƒšãƒ¼ã‚¸ã‚’表示ã—ã¦ãã ã•ã„。" -#: contrib/admin/views/decorators.py:82 +#: contrib/admin/views/decorators.py:83 msgid "Usernames cannot contain the '@' character." msgstr "ユーザåã«ã¯ '@' ã‚’å«ã‚られã¾ã›ã‚“。" -#: contrib/admin/views/decorators.py:84 +#: contrib/admin/views/decorators.py:85 #, python-format msgid "Your e-mail address is not your username. Try '%s' instead." msgstr "メールアドレスã¯ãƒ¦ãƒ¼ã‚¶åã§ã¯ã‚りã¾ã›ã‚“。 '%s' を試ã—ã¦ã¿ã¦ãã ã•ã„。" -#: contrib/admin/views/doc.py:277 contrib/admin/views/doc.py:286 -#: contrib/admin/views/doc.py:288 contrib/admin/views/doc.py:294 -#: contrib/admin/views/doc.py:295 contrib/admin/views/doc.py:297 +#: contrib/admin/views/doc.py:46 contrib/admin/views/doc.py:48 +#: contrib/admin/views/doc.py:50 +msgid "tag:" +msgstr "ã‚¿ã‚°" + +#: contrib/admin/views/doc.py:77 contrib/admin/views/doc.py:79 +#: contrib/admin/views/doc.py:81 +msgid "filter:" +msgstr "フィルタ" + +#: contrib/admin/views/doc.py:135 contrib/admin/views/doc.py:137 +#: contrib/admin/views/doc.py:139 +msgid "view:" +msgstr "ビュー" + +#: contrib/admin/views/doc.py:164 +#, python-format +msgid "App %r not found" +msgstr "アプリケーション %r ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“" + +#: contrib/admin/views/doc.py:171 +#, python-format +msgid "Model %r not found in app %r" +msgstr "モデル %r ㌠%r アプリケーションã«è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“" + +#: contrib/admin/views/doc.py:183 +#, python-format +msgid "the related `%s.%s` object" +msgstr "`%s.%s` (関連オブジェクト)" + +#: contrib/admin/views/doc.py:183 contrib/admin/views/doc.py:205 +#: contrib/admin/views/doc.py:219 contrib/admin/views/doc.py:224 +msgid "model:" +msgstr "モデル :" + +#: contrib/admin/views/doc.py:214 +#, python-format +msgid "related `%s.%s` objects" +msgstr "`%s.%s` (関連オブジェクト)" + +#: contrib/admin/views/doc.py:219 +#, python-format +msgid "all %s" +msgstr "å…¨ã¦ã® %s" + +#: contrib/admin/views/doc.py:224 +#, python-format +msgid "number of %s" +msgstr "%s ã®æ•°" + +#: contrib/admin/views/doc.py:229 +#, python-format +msgid "Fields on %s objects" +msgstr "%s ã®ãƒ•ィールド" + +#: contrib/admin/views/doc.py:291 contrib/admin/views/doc.py:301 +#: contrib/admin/views/doc.py:303 contrib/admin/views/doc.py:309 +#: contrib/admin/views/doc.py:310 contrib/admin/views/doc.py:312 msgid "Integer" msgstr "æ•´æ•°" -#: contrib/admin/views/doc.py:278 +#: contrib/admin/views/doc.py:292 msgid "Boolean (Either True or False)" msgstr "ブール値 (真: True ã¾ãŸã¯å½: False)" -#: contrib/admin/views/doc.py:279 contrib/admin/views/doc.py:296 +#: contrib/admin/views/doc.py:293 contrib/admin/views/doc.py:311 #, python-format msgid "String (up to %(maxlength)s)" msgstr "æ–‡å—列 ( %(maxlength)s å—ã¾ã§ )" -#: contrib/admin/views/doc.py:280 +#: contrib/admin/views/doc.py:294 msgid "Comma-separated integers" msgstr "ã‚«ãƒ³ãƒžåŒºåˆ‡ã‚Šã®æ•´æ•°" -#: contrib/admin/views/doc.py:281 +#: contrib/admin/views/doc.py:295 msgid "Date (without time)" msgstr "日付" -#: contrib/admin/views/doc.py:282 +#: contrib/admin/views/doc.py:296 msgid "Date (with time)" msgstr "日時" -#: contrib/admin/views/doc.py:283 +#: contrib/admin/views/doc.py:297 msgid "E-mail address" msgstr "メールアドレス" -#: contrib/admin/views/doc.py:284 contrib/admin/views/doc.py:287 +#: contrib/admin/views/doc.py:298 contrib/admin/views/doc.py:299 +#: contrib/admin/views/doc.py:302 msgid "File path" msgstr "ファイルã®å ´æ‰€" -#: contrib/admin/views/doc.py:285 +#: contrib/admin/views/doc.py:300 msgid "Decimal number" msgstr "10 進数 (å°æ•°å¯)" -#: contrib/admin/views/doc.py:289 contrib/comments/models.py:85 +#: contrib/admin/views/doc.py:304 contrib/comments/models.py:85 msgid "IP address" msgstr "IP アドレス" -#: contrib/admin/views/doc.py:291 +#: contrib/admin/views/doc.py:306 msgid "Boolean (Either True, False or None)" msgstr "ブール値 (真: True ã€å½: False ã¾ãŸã¯ None)" -#: contrib/admin/views/doc.py:292 +#: contrib/admin/views/doc.py:307 msgid "Relation to parent model" msgstr "親モデルã¸ã®ãƒªãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³" -#: contrib/admin/views/doc.py:293 +#: contrib/admin/views/doc.py:308 msgid "Phone number" msgstr "電話番å·" -#: contrib/admin/views/doc.py:298 +#: contrib/admin/views/doc.py:313 msgid "Text" msgstr "テã‚スト" -#: contrib/admin/views/doc.py:299 +#: contrib/admin/views/doc.py:314 msgid "Time" msgstr "時刻" -#: contrib/admin/views/doc.py:300 contrib/flatpages/models.py:7 +#: contrib/admin/views/doc.py:315 contrib/flatpages/models.py:7 msgid "URL" msgstr "URL" -#: contrib/admin/views/doc.py:301 +#: contrib/admin/views/doc.py:316 msgid "U.S. state (two uppercase letters)" msgstr "アメリカã®å·ž (大文å—二文å—ã§)" -#: contrib/admin/views/doc.py:302 +#: contrib/admin/views/doc.py:317 msgid "XML text" msgstr "XMLテã‚スト" -#: contrib/admin/views/main.py:226 -msgid "Site administration" -msgstr "サイト管ç†" - -#: contrib/admin/views/main.py:260 +#: contrib/admin/views/doc.py:343 #, python-format -msgid "The %(name)s \"%(obj)s\" was added successfully." -msgstr "%(name)s \"%(obj)s\" ã‚’è¿½åŠ ã—ã¾ã—ãŸã€‚" +msgid "%s does not appear to be a urlpattern object" +msgstr "%s ã¯urlpatternオブジェクトã§ã¯ç„¡ã„よã†ã§ã™" -#: contrib/admin/views/main.py:264 contrib/admin/views/main.py:348 -msgid "You may edit it again below." -msgstr "ç¶šã‘ã¦ç·¨é›†ã§ãã¾ã™ã€‚" +#: contrib/admin/views/main.py:223 +msgid "Site administration" +msgstr "サイト管ç†" -#: contrib/admin/views/main.py:272 contrib/admin/views/main.py:357 +#: contrib/admin/views/main.py:271 contrib/admin/views/main.py:356 #, python-format msgid "You may add another %s below." msgstr "ç¶šã‘ã¦åˆ¥ã® %s ã‚’è¿½åŠ ã§ãã¾ã™ã€‚" -#: contrib/admin/views/main.py:290 +#: contrib/admin/views/main.py:289 #, python-format msgid "Add %s" msgstr "%s ã‚’è¿½åŠ " -#: contrib/admin/views/main.py:336 +#: contrib/admin/views/main.py:335 #, python-format msgid "Added %s." msgstr "%s ã‚’è¿½åŠ ã—ã¾ã—ãŸã€‚" -#: contrib/admin/views/main.py:336 contrib/admin/views/main.py:338 -#: contrib/admin/views/main.py:340 +#: contrib/admin/views/main.py:335 contrib/admin/views/main.py:337 +#: contrib/admin/views/main.py:339 msgid "and" msgstr "ã¨" -#: contrib/admin/views/main.py:338 +#: contrib/admin/views/main.py:337 #, python-format msgid "Changed %s." msgstr "%s を変更ã—ã¾ã—ãŸã€‚" -#: contrib/admin/views/main.py:340 +#: contrib/admin/views/main.py:339 #, python-format msgid "Deleted %s." msgstr "%s を削除ã—ã¾ã—ãŸã€‚" -#: contrib/admin/views/main.py:343 +#: contrib/admin/views/main.py:342 msgid "No fields changed." msgstr "変更ã¯ã‚りã¾ã›ã‚“ã§ã—ãŸã€‚" -#: contrib/admin/views/main.py:346 +#: contrib/admin/views/main.py:345 #, python-format msgid "The %(name)s \"%(obj)s\" was changed successfully." msgstr "%(name)s \"%(obj)s\" を変更ã—ã¾ã—ãŸã€‚" -#: contrib/admin/views/main.py:354 +#: contrib/admin/views/main.py:353 #, python-format msgid "" "The %(name)s \"%(obj)s\" was added successfully. You may edit it again below." msgstr "%(name)s \"%(obj)s\" ã‚’è¿½åŠ ã—ã¾ã—ãŸã€‚ç¶šã‘ã¦ç·¨é›†ã§ãã¾ã™ã€‚" -#: contrib/admin/views/main.py:392 +#: contrib/admin/views/main.py:391 #, python-format msgid "Change %s" msgstr "%s を変更" -#: contrib/admin/views/main.py:470 +#: contrib/admin/views/main.py:473 #, python-format msgid "One or more %(fieldname)s in %(name)s: %(obj)s" msgstr "%(name)s ã« %(fieldname)s ãŒä¸€ã¤ä»¥ä¸Šã‚りã¾ã™: %(obj)s" -#: contrib/admin/views/main.py:475 +#: contrib/admin/views/main.py:478 #, python-format msgid "One or more %(fieldname)s in %(name)s:" msgstr "%(name)s ã« %(fieldname)s ãŒä¸€ã¤ä»¥ä¸Šã‚りã¾ã™:" -#: contrib/admin/views/main.py:508 +#: contrib/admin/views/main.py:511 #, python-format msgid "The %(name)s \"%(obj)s\" was deleted successfully." msgstr "%(name)s \"%(obj)s\" を削除ã—ã¾ã—ãŸã€‚" -#: contrib/admin/views/main.py:511 +#: contrib/admin/views/main.py:514 msgid "Are you sure?" msgstr "よã‚ã—ã„ã§ã™ã‹ï¼Ÿ" -#: contrib/admin/views/main.py:533 +#: contrib/admin/views/main.py:536 #, python-format msgid "Change history: %s" msgstr "変更履æ´: %s" -#: contrib/admin/views/main.py:565 +#: contrib/admin/views/main.py:570 #, python-format msgid "Select %s" msgstr "%s ã‚’é¸æŠž" -#: contrib/admin/views/main.py:565 +#: contrib/admin/views/main.py:570 #, python-format msgid "Select %s to change" msgstr "変更ã™ã‚‹ %s ã‚’é¸æŠž" -#: contrib/auth/forms.py:30 +#: contrib/admin/views/main.py:758 +msgid "Database error" +msgstr "データベースエラー" + +#: contrib/auth/forms.py:16 +msgid "The two password fields didn't match." +msgstr "確èªç”¨ãƒ‘スワードãŒä¸€è‡´ã—ã¾ã›ã‚“。" + +#: contrib/auth/forms.py:24 +msgid "A user with that username already exists." +msgstr "åŒã˜ãƒ¦ãƒ¼ã‚¶åãŒæ—¢ã«ç™»éŒ²æ¸ˆã¿ã§ã™ã€‚" + +#: contrib/auth/forms.py:52 msgid "" "Your Web browser doesn't appear to have cookies enabled. Cookies are " "required for logging in." @@ -880,83 +1037,117 @@ msgstr "" "ãŠä½¿ã„ã®ãƒ–ラウザã¯ã‚¯ãƒƒã‚ーを有効ã«ã—ã¦ã„ãªã„よã†ã§ã™ã€‚ãƒã‚°ã‚¤ãƒ³ã«ã¯ã‚¯ãƒƒã‚ーãŒ" "å¿…è¦ã§ã™ã€‚" -#: contrib/auth/models.py:13 contrib/auth/models.py:26 +#: contrib/auth/forms.py:61 +msgid "This account is inactive." +msgstr "アカウントãŒç„¡åйã§ã™ã€‚" + +#: contrib/auth/forms.py:84 +msgid "" +"That e-mail address doesn't have an associated user account. Are you sure " +"you've registered?" +msgstr "メールアドレスã®ä¸€è‡´ã™ã‚‹ãƒ¦ãƒ¼ã‚¶ã¯ã„ã¾ã›ã‚“。本当ã«ç™»éŒ²ã—ã¾ã—ãŸã‹ï¼Ÿ" + +#: contrib/auth/forms.py:116 +msgid "The two 'new password' fields didn't match." +msgstr "æ–°ã—ã„パスワード(確èªç”¨)ãŒä¸€è‡´ã—ã¾ã›ã‚“。" + +#: contrib/auth/forms.py:123 +msgid "Your old password was entered incorrectly. Please enter it again." +msgstr "å…ƒã®ãƒ‘スワードãŒé–“é•ã£ã¦ã„ã¾ã™ã€‚ã‚‚ã†ä¸€åº¦å…¥åŠ›ã—ã¦ãã ã•ã„。" + +#: contrib/auth/models.py:38 contrib/auth/models.py:57 msgid "name" msgstr "åå‰" -#: contrib/auth/models.py:15 +#: contrib/auth/models.py:40 msgid "codename" msgstr "コードå" -#: contrib/auth/models.py:17 -#, fuzzy +#: contrib/auth/models.py:42 msgid "permission" msgstr "パーミッション" -#: contrib/auth/models.py:18 contrib/auth/models.py:27 -#, fuzzy +#: contrib/auth/models.py:43 contrib/auth/models.py:58 msgid "permissions" msgstr "パーミッション" -#: contrib/auth/models.py:29 -#, fuzzy +#: contrib/auth/models.py:60 msgid "group" msgstr "グループ" -#: contrib/auth/models.py:30 contrib/auth/models.py:65 -#, fuzzy +#: contrib/auth/models.py:61 contrib/auth/models.py:100 msgid "groups" msgstr "グループ" -#: contrib/auth/models.py:55 +#: contrib/auth/models.py:90 msgid "username" msgstr "ユーザå" -#: contrib/auth/models.py:56 +#: contrib/auth/models.py:90 +msgid "" +"Required. 30 characters or fewer. Alphanumeric characters only (letters, " +"digits and underscores)." +msgstr "" +"ã“ã®é …ç›®ã¯å¿…é ˆã§ã™ã€‚åŠè§’アルファベットã€åŠè§’æ•°å—ã€åŠè§’アンダーãƒãƒ¼ã§30æ–‡å—以" +"下ã«ã—ã¦ãã ã•ã„。" + +#: contrib/auth/models.py:91 msgid "first name" msgstr "å" -#: contrib/auth/models.py:57 +#: contrib/auth/models.py:92 msgid "last name" msgstr "å§“" -#: contrib/auth/models.py:58 +#: contrib/auth/models.py:93 msgid "e-mail address" msgstr "メールアドレス" -#: contrib/auth/models.py:59 +#: contrib/auth/models.py:94 msgid "password" msgstr "パスワード" -#: contrib/auth/models.py:59 +#: contrib/auth/models.py:94 msgid "Use '[algo]$[salt]$[hexdigest]'" msgstr "'[アルゴリズム]$[ソルト]$[ダイジェスト(hex)]' å½¢å¼ã‚’使ã£ã¦ä¸‹ã•ã„" -#: contrib/auth/models.py:60 +#: contrib/auth/models.py:95 msgid "staff status" msgstr "スタッフ権é™" -#: contrib/auth/models.py:60 +#: contrib/auth/models.py:95 msgid "Designates whether the user can log into this admin site." msgstr "ユーザãŒç®¡ç†ã‚µã‚¤ãƒˆã«ãƒã‚°ã‚¤ãƒ³å¯èƒ½ã‹ã©ã†ã‹ã‚’示ã—ã¾ã™ã€‚" -#: contrib/auth/models.py:61 +#: contrib/auth/models.py:96 msgid "active" msgstr "有効" -#: contrib/auth/models.py:62 +#: contrib/auth/models.py:96 +msgid "" +"Designates whether this user can log into the Django admin. Unselect this " +"instead of deleting accounts." +msgstr "ユーザãŒç®¡ç†ã‚µã‚¤ãƒˆã«ãƒã‚°ã‚¤ãƒ³å¯èƒ½ã‹ã©ã†ã‹ã‚’示ã—ã¾ã™ã€‚" + +#: contrib/auth/models.py:97 msgid "superuser status" msgstr "スーパーユーザ権é™" -#: contrib/auth/models.py:63 +#: contrib/auth/models.py:97 +msgid "" +"Designates that this user has all permissions without explicitly assigning " +"them." +msgstr "å…¨ã¦ã®æ¨©é™ã‚’æŒã£ã¦ã„ã‚‹ã¨ã¿ãªã•れã¾ã™ã€‚" + +#: contrib/auth/models.py:98 msgid "last login" msgstr "最終ãƒã‚°ã‚¤ãƒ³" -#: contrib/auth/models.py:64 +#: contrib/auth/models.py:99 msgid "date joined" msgstr "登録日" -#: contrib/auth/models.py:66 +#: contrib/auth/models.py:101 msgid "" "In addition to the permissions manually assigned, this user will also get " "all permissions granted to each group he/she is in." @@ -964,42 +1155,42 @@ msgstr "" "手動ã§ä»˜ä¸Žã—ãŸãƒ‘ーミッションã«åŠ ãˆã€æ‰€å±žã—ã¦ã„るグループã«ä»˜ä¸Žã•れãŸå…¨ã¦ã®" "パーミッションをç²å¾—ã—ã¾ã™ã€‚" -#: contrib/auth/models.py:67 -#, fuzzy +#: contrib/auth/models.py:102 msgid "user permissions" msgstr "ユーザパーミッション" -#: contrib/auth/models.py:70 -#, fuzzy +#: contrib/auth/models.py:105 msgid "user" msgstr "ユーザ" -#: contrib/auth/models.py:71 -#, fuzzy +#: contrib/auth/models.py:106 msgid "users" msgstr "ユーザ" -#: contrib/auth/models.py:76 +#: contrib/auth/models.py:111 msgid "Personal info" msgstr "å€‹äººæƒ…å ±" -#: contrib/auth/models.py:77 +#: contrib/auth/models.py:112 msgid "Permissions" msgstr "パーミッション" -#: contrib/auth/models.py:78 +#: contrib/auth/models.py:113 msgid "Important dates" msgstr "é‡è¦ãªæ—¥ç¨‹" -#: contrib/auth/models.py:79 +#: contrib/auth/models.py:114 msgid "Groups" msgstr "グループ" -#: contrib/auth/models.py:219 -#, fuzzy +#: contrib/auth/models.py:258 msgid "message" msgstr "メッセージ" +#: contrib/auth/views.py:39 +msgid "Logged out" +msgstr "ãƒã‚°ã‚¢ã‚¦ãƒˆ" + #: contrib/comments/models.py:67 contrib/comments/models.py:166 msgid "object ID" msgstr "オブジェクト ID" @@ -1070,7 +1261,6 @@ msgstr "" "ãŸã€ã¨è¡¨ç¤ºã•れるよã†ã«ãªã‚Šã¾ã™ã€‚" #: contrib/comments/models.py:91 -#, fuzzy msgid "comments" msgstr "コメント" @@ -1106,12 +1296,10 @@ msgid "approved by staff" msgstr "ã‚¹ã‚¿ãƒƒãƒ•ã®æ‰¿èªæ¸ˆã¿" #: contrib/comments/models.py:176 -#, fuzzy msgid "free comment" msgstr "フリーコメント" #: contrib/comments/models.py:177 -#, fuzzy msgid "free comments" msgstr "フリーコメント" @@ -1124,12 +1312,10 @@ msgid "score date" msgstr "スコアã•ã‚ŒãŸæ—¥" #: contrib/comments/models.py:237 -#, fuzzy msgid "karma score" msgstr "カルマスコア" #: contrib/comments/models.py:238 -#, fuzzy msgid "karma scores" msgstr "カルマスコア" @@ -1154,12 +1340,10 @@ msgid "flag date" msgstr "フラグ日" #: contrib/comments/models.py:268 -#, fuzzy msgid "user flag" msgstr "ユーザフラグ" #: contrib/comments/models.py:269 -#, fuzzy msgid "user flags" msgstr "ユーザフラグ" @@ -1173,12 +1357,10 @@ msgid "deletion date" msgstr "削除日" #: contrib/comments/models.py:280 -#, fuzzy msgid "moderator deletion" msgstr "モデレータ削除" #: contrib/comments/models.py:281 -#, fuzzy msgid "moderator deletions" msgstr "モデレータ削除" @@ -1187,13 +1369,11 @@ msgstr "モデレータ削除" msgid "Moderator deletion by %r" msgstr "%r ã«ã‚ˆã‚‹ãƒ¢ãƒ‡ãƒ¬ãƒ¼ã‚¿å‰Šé™¤" -#: contrib/comments/templates/comments/form.html:6 -#, fuzzy +#: contrib/comments/templates/comments/form.html:8 msgid "Forgotten your password?" msgstr "パスワードをãŠå¿˜ã‚Œã§ã™ã‹ï¼Ÿ" #: contrib/comments/templates/comments/form.html:12 -#, fuzzy msgid "Ratings" msgstr "レーティング" @@ -1211,30 +1391,27 @@ msgstr "オプション" msgid "Post a photo" msgstr "写真を登録" -#: contrib/comments/templates/comments/form.html:27 +#: contrib/comments/templates/comments/form.html:28 #: contrib/comments/templates/comments/freeform.html:5 -#, fuzzy msgid "Comment:" msgstr "コメント:" -#: contrib/comments/templates/comments/form.html:32 -#: contrib/comments/templates/comments/freeform.html:9 -#, fuzzy +#: contrib/comments/templates/comments/form.html:35 +#: contrib/comments/templates/comments/freeform.html:10 msgid "Preview comment" msgstr "コメントをプレビュー" #: contrib/comments/templates/comments/freeform.html:4 -#, fuzzy msgid "Your name:" msgstr "ユーザå:" -#: contrib/comments/views/comments.py:28 +#: contrib/comments/views/comments.py:27 msgid "" "This rating is required because you've entered at least one other rating." msgstr "" "ä»–ã®ãƒ¬ãƒ¼ãƒ†ã‚£ãƒ³ã‚°ã‚’入力ã—ãŸå ´åˆã¯ã€ã“ã®ãƒ¬ãƒ¼ãƒ†ã‚£ãƒ³ã‚°ã¯å¿…ãšå…¥åŠ›ã—ã¦ãã ã•ã„。" -#: contrib/comments/views/comments.py:112 +#: contrib/comments/views/comments.py:111 #, python-format msgid "" "This comment was posted by a user who has posted fewer than %(count)s " @@ -1249,7 +1426,7 @@ msgid_plural "" msgstr[0] "ã“ã®ã‚³ãƒ¡ãƒ³ãƒˆã‚’投稿ã—ãŸãƒ¦ãƒ¼ã‚¶ã®ã‚³ãƒ¡ãƒ³ãƒˆæ•°ã¯ %(count)s 未満ã§ã™ã€‚" msgstr[1] "ã“ã®ã‚³ãƒ¡ãƒ³ãƒˆã‚’投稿ã—ãŸãƒ¦ãƒ¼ã‚¶ã®ã‚³ãƒ¡ãƒ³ãƒˆæ•°ã¯ %(count)s 未満ã§ã™ã€‚" -#: contrib/comments/views/comments.py:117 +#: contrib/comments/views/comments.py:116 #, python-format msgid "" "This comment was posted by a sketchy user:\n" @@ -1260,22 +1437,22 @@ msgstr "" "\n" "%(text)s" -#: contrib/comments/views/comments.py:189 +#: contrib/comments/views/comments.py:188 #: contrib/comments/views/comments.py:280 msgid "Only POSTs are allowed" msgstr "POST メソッドã®ã¿æœ‰åйã§ã™ã€‚" -#: contrib/comments/views/comments.py:193 +#: contrib/comments/views/comments.py:192 #: contrib/comments/views/comments.py:284 msgid "One or more of the required fields wasn't submitted" msgstr "å¿…é ˆé …ç›®ãŒã„ãã¤ã‹å…¥åŠ›ã•れã¦ã„ã¾ã›ã‚“。" -#: contrib/comments/views/comments.py:197 +#: contrib/comments/views/comments.py:196 #: contrib/comments/views/comments.py:286 msgid "Somebody tampered with the comment form (security violation)" msgstr "ã れã‹ãŒã‚³ãƒ¡ãƒ³ãƒˆãƒ•ォームを改竄ã—ã¦ã„ã¾ã™ (ã‚»ã‚ュリティ侵害ã§ã™)" -#: contrib/comments/views/comments.py:207 +#: contrib/comments/views/comments.py:206 #: contrib/comments/views/comments.py:292 msgid "" "The comment form had an invalid 'target' parameter -- the object ID was " @@ -1301,16 +1478,15 @@ msgstr "コメント ID ãŒä¸æ£ã§ã™" msgid "No voting for yourself" msgstr "自分ã«ã¯æŠ•票ã§ãã¾ã›ã‚“。" -#: contrib/contenttypes/models.py:25 -#, fuzzy +#: contrib/contenttypes/models.py:20 msgid "python model class name" msgstr "Python モデルクラスå" -#: contrib/contenttypes/models.py:28 +#: contrib/contenttypes/models.py:23 msgid "content type" msgstr "コンテンツタイプ" -#: contrib/contenttypes/models.py:29 +#: contrib/contenttypes/models.py:24 msgid "content types" msgstr "コンテンツタイプ" @@ -1338,11 +1514,11 @@ msgstr "テンプレートå" #: contrib/flatpages/models.py:13 msgid "" -"Example: 'flatpages/contact_page'. If this isn't provided, the system will " -"use 'flatpages/default'." +"Example: 'flatpages/contact_page.html'. If this isn't provided, the system " +"will use 'flatpages/default.html'." msgstr "" -"例: 'flatpages/contact_page'. 指定ã—ãªã‘れã°ã€ãƒ‡ãƒ•ォルトè¨å®šã®'flatpages/" -"default' を使ã„ã¾ã™ã€‚" +"例: 'flatpages/contact_page.html'. 指定ã—ãªã‘れã°ã€ãƒ‡ãƒ•ォルトè¨å®š" +"ã®'flatpages/default.html' を使ã„ã¾ã™ã€‚" #: contrib/flatpages/models.py:14 msgid "registration required" @@ -1380,31 +1556,31 @@ msgid "" "'http://'." msgstr "上記ã®ã‚ˆã†ãªçµ¶å¯¾ãƒ‘スã‹ã€ 'http://' ã§å§‹ã¾ã‚‹å®Œå…¨ãª URL ã«ã—ã¾ã™ã€‚" -#: contrib/redirects/models.py:12 +#: contrib/redirects/models.py:13 msgid "redirect" msgstr "リダイレクト" -#: contrib/redirects/models.py:13 +#: contrib/redirects/models.py:14 msgid "redirects" msgstr "リダイレクト" -#: contrib/sessions/models.py:35 +#: contrib/sessions/models.py:51 msgid "session key" msgstr "セッションã‚ー" -#: contrib/sessions/models.py:36 +#: contrib/sessions/models.py:52 msgid "session data" msgstr "セッションデータ" -#: contrib/sessions/models.py:37 +#: contrib/sessions/models.py:53 msgid "expire date" msgstr "有効期é™" -#: contrib/sessions/models.py:41 +#: contrib/sessions/models.py:57 msgid "session" msgstr "セッション" -#: contrib/sessions/models.py:42 +#: contrib/sessions/models.py:58 msgid "sessions" msgstr "セッション" @@ -1424,74 +1600,92 @@ msgstr "サイト" msgid "sites" msgstr "サイト" -#: core/validators.py:60 +#: core/validators.py:63 msgid "This value must contain only letters, numbers and underscores." msgstr "åŠè§’ã®è‹±æ•°å—ãŠã‚ˆã³ã‚¢ãƒ³ãƒ€ãƒ¼ã‚¹ã‚³ã‚¢ä»¥å¤–ã¯ä½¿ç”¨ã§ãã¾ã›ã‚“。" -#: core/validators.py:64 -#, fuzzy +#: core/validators.py:67 msgid "" "This value must contain only letters, numbers, underscores, dashes or " "slashes." -msgstr "åŠè§’ã®è‹±æ•°å—ã€ã‚¢ãƒ³ãƒ€ãƒ¼ã‚¹ã‚³ã‚¢ã€ãƒ€ãƒƒã‚·ãƒ¥ã€ãƒ©ãƒƒã‚·ãƒ¥ä»¥å¤–ã¯ä½¿ç”¨ã§ãã¾ã›ã‚“。" +msgstr "" +"åŠè§’ã®è‹±æ•°å—ã€ã‚¢ãƒ³ãƒ€ãƒ¼ã‚¹ã‚³ã‚¢ã€ãƒ€ãƒƒã‚·ãƒ¥ã€ã‚¹ãƒ©ãƒƒã‚·ãƒ¥ä»¥å¤–ã¯ä½¿ç”¨ã§ãã¾ã›ã‚“。" + +#: core/validators.py:71 +msgid "This value must contain only letters, numbers, underscores or hyphens." +msgstr "åŠè§’ã®è‹±æ•°å—ã€ã‚¢ãƒ³ãƒ€ãƒ¼ã‚¹ã‚³ã‚¢ã€ãƒã‚¤ãƒ•ン以外ã¯ä½¿ç”¨ã§ãã¾ã›ã‚“。" -#: core/validators.py:72 +#: core/validators.py:75 msgid "Uppercase letters are not allowed here." msgstr "大文å—ã¯ã“ã“ã§ã¯ä½¿ç”¨ã§ãã¾ã›ã‚“。" -#: core/validators.py:76 +#: core/validators.py:79 msgid "Lowercase letters are not allowed here." msgstr "å°æ–‡å—ã¯ã“ã“ã§ã¯ä½¿ç”¨ã§ãã¾ã›ã‚“。" -#: core/validators.py:83 +#: core/validators.py:86 msgid "Enter only digits separated by commas." msgstr "ã‚«ãƒ³ãƒžåŒºåˆ‡ã‚Šã®æ•°å—ã ã‘を入力ã—ã¦ãã ã•ã„。" -#: core/validators.py:95 +#: core/validators.py:98 msgid "Enter valid e-mail addresses separated by commas." msgstr "ã‚«ãƒ³ãƒžåŒºåˆ‡ã‚Šã®æœ‰åйãªãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’入力ã—ã¦ãã ã•ã„。" -#: core/validators.py:99 +#: core/validators.py:102 msgid "Please enter a valid IP address." msgstr "有効㪠IP アドレスを入力ã—ã¦ãã ã•ã„。" -#: core/validators.py:103 +#: core/validators.py:106 msgid "Empty values are not allowed here." msgstr "入力ã¯å¿…é ˆã§ã™ã€‚" -#: core/validators.py:107 +#: core/validators.py:110 msgid "Non-numeric characters aren't allowed here." msgstr "数値以外ã¯ä½¿ç”¨ã§ãã¾ã›ã‚“。" -#: core/validators.py:111 +#: core/validators.py:114 msgid "This value can't be comprised solely of digits." msgstr "数値ã ã‘ã®å€¤ã«ã¯ã§ãã¾ã›ã‚“。" -#: core/validators.py:116 +#: core/validators.py:119 msgid "Enter a whole number." msgstr "整数を入力ã—ã¦ãã ã•ã„。" -#: core/validators.py:120 +#: core/validators.py:123 msgid "Only alphabetical characters are allowed here." msgstr "åŠè§’アルファベット以外使用ã§ãã¾ã›ã‚“。" -#: core/validators.py:124 +#: core/validators.py:138 +msgid "Year must be 1900 or later." +msgstr "1900年以é™ã‚’指定ã—ã¦ãã ã•ã„。" + +#: core/validators.py:142 +#, python-format +msgid "Invalid date: %s." +msgstr "ç„¡åŠ¹ãªæ—¥ä»˜: %s" + +#: core/validators.py:146 db/models/fields/__init__.py:424 msgid "Enter a valid date in YYYY-MM-DD format." msgstr "YYYY-MM-DDå½¢å¼ã§æ—¥ä»˜ã‚’入力ã—ã¦ãã ã•ã„。" -#: core/validators.py:128 +#: core/validators.py:151 msgid "Enter a valid time in HH:MM format." msgstr "HH:MMå½¢å¼ã§æ™‚刻を入力ã—ã¦ãã ã•ã„。" -#: core/validators.py:132 db/models/fields/__init__.py:468 +#: core/validators.py:155 db/models/fields/__init__.py:486 msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format." msgstr "YYYY-MM-DD HH:MMå½¢å¼ã§æ—¥æ™‚を入力ã—ã¦ãã ã•ã„。" -#: core/validators.py:136 +#: core/validators.py:160 msgid "Enter a valid e-mail address." msgstr "有効ãªãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’入力ã—ã¦ãã ã•ã„。" -#: core/validators.py:148 +#: core/validators.py:172 core/validators.py:401 forms/__init__.py:662 +msgid "No file was submitted. Check the encoding type on the form." +msgstr "" +"ファイルãŒå–å¾—ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚formã®encoding typeを確èªã—ã¦ãã ã•ã„。" + +#: core/validators.py:176 msgid "" "Upload a valid image. The file you uploaded was either not an image or a " "corrupted image." @@ -1499,26 +1693,26 @@ msgstr "" "ç”»åƒã‚’アップãƒãƒ¼ãƒ‰ã—ã¦ãã ã•ã„。アップãƒãƒ¼ãƒ‰ã—ãŸç”»åƒã¯ç”»åƒã§ãªã„ã‹ã€ã¾ãŸã¯å£Š" "れã¦ã„ã¾ã™ã€‚" -#: core/validators.py:155 +#: core/validators.py:183 #, python-format msgid "The URL %s does not point to a valid image." msgstr "URL ( %s ) ã¯ç”»åƒã§ã¯ã‚りã¾ã›ã‚“。" -#: core/validators.py:159 +#: core/validators.py:187 #, python-format msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid." msgstr "電話番å·ã¯ XXX-XXX-XXXX å½¢å¼ã§å…¥åŠ›ã—ã¦ãã ã•ã„。\"%s\" ã¯ç„¡åйã§ã™ã€‚" -#: core/validators.py:167 +#: core/validators.py:195 #, python-format msgid "The URL %s does not point to a valid QuickTime video." msgstr "URL ( %s ) 㯠QuickTime ビデオã§ã¯ã‚りã¾ã›ã‚“。" -#: core/validators.py:171 +#: core/validators.py:199 msgid "A valid URL is required." msgstr "æ£ã—ã„ URL を入力ã—ã¦ãã ã•ã„。" -#: core/validators.py:185 +#: core/validators.py:213 #, python-format msgid "" "Valid HTML is required. Specific errors are:\n" @@ -1527,117 +1721,126 @@ msgstr "" "有効㪠HTML を入力ã—ã¦ãã ã•ã„。エラー:\n" "%s" -#: core/validators.py:192 +#: core/validators.py:220 #, python-format msgid "Badly formed XML: %s" msgstr "䏿£ãª XML ã§ã™: %s" -#: core/validators.py:202 +#: core/validators.py:230 #, python-format msgid "Invalid URL: %s" msgstr "無効ãªURL: %s" -#: core/validators.py:206 core/validators.py:208 +#: core/validators.py:234 core/validators.py:236 #, python-format msgid "The URL %s is a broken link." msgstr "URL ( %s ) ã¯ãƒªãƒ³ã‚¯ãŒå£Šã‚Œã¦ã„ã¾ã™ã€‚" -#: core/validators.py:214 +#: core/validators.py:242 msgid "Enter a valid U.S. state abbreviation." msgstr "æ£ã—ã„米州略称を入力ã—ã¦ãã ã•ã„。" -#: core/validators.py:229 +#: core/validators.py:256 #, python-format msgid "Watch your mouth! The word %s is not allowed here." msgid_plural "Watch your mouth! The words %s are not allowed here." msgstr[0] "言葉使ã„ã«æ°—を付ã‘ã¦ï¼ %s ã¨ã„ã†è¨€è‘‰ã¯ä½¿ãˆã¾ã›ã‚“。" msgstr[1] "言葉使ã„ã«æ°—を付ã‘ã¦ï¼ %s ã¨ã„ã†è¨€è‘‰ã¯ä½¿ãˆã¾ã›ã‚“。" -#: core/validators.py:236 +#: core/validators.py:263 #, python-format msgid "This field must match the '%s' field." msgstr "ã“ã®ãƒ•ィールド㯠'%s' フィールドã¨ä¸€è‡´ã›ãã°ãªã‚Šã¾ã›ã‚“。" -#: core/validators.py:255 +#: core/validators.py:282 msgid "Please enter something for at least one field." msgstr "å°‘ãªãã¨ã‚‚一ã¤ã®ãƒ•ィールドã«ä½•ã‹å…¥åŠ›ã—ã¦ãã ã•ã„。" -#: core/validators.py:264 core/validators.py:275 +#: core/validators.py:291 core/validators.py:302 msgid "Please enter both fields or leave them both empty." msgstr "両方ã®ãƒ•ィールドã«å…¥åŠ›ã™ã‚‹ã‹ã€ä¸¡æ–¹ã¨ã‚‚未入力ã«ã—ã¦ãã ã•ã„。" -#: core/validators.py:282 +#: core/validators.py:309 #, python-format msgid "This field must be given if %(field)s is %(value)s" msgstr "" "%(field)s ã‚’ %(value)s ã«ã™ã‚‹ã®ãªã‚‰ã€ã“ã®ãƒ•ィールドã«å¿…ãšå…¥åŠ›ã—ã¦ãã ã•ã„。" -#: core/validators.py:294 +#: core/validators.py:321 #, python-format msgid "This field must be given if %(field)s is not %(value)s" msgstr "" "%(field)s ã‚’ %(value)s ã«ã—ãªã„ã®ãªã‚‰ã€ã“ã®ãƒ•ィールドã«å¿…ãšå…¥åŠ›ã—ã¦ãã ã•ã„。" -#: core/validators.py:313 +#: core/validators.py:340 msgid "Duplicate values are not allowed." msgstr "é‡è¤‡ã™ã‚‹å€¤ã¯èªã‚られã¾ã›ã‚“。" -#: core/validators.py:336 +#: core/validators.py:363 #, python-format msgid "This value must be a power of %s." msgstr "ã“ã®å€¤ã¯ %s ã®ç´¯ä¹—ã§ãªã‘れã°ãªã‚Šã¾ã›ã‚“。" -#: core/validators.py:347 +#: core/validators.py:374 msgid "Please enter a valid decimal number." msgstr "有効㪠10 進数を入力ã—ã¦ãã ã•ã„。" -#: core/validators.py:349 +#: core/validators.py:378 #, python-format msgid "Please enter a valid decimal number with at most %s total digit." msgid_plural "" "Please enter a valid decimal number with at most %s total digits." -msgstr[0] "æœ€å¤§æ¡æ•° %s æ¡ä»¥ä¸‹ã®æœ‰åŠ¹ãª 10 進数を入力ã—ã¦ãã ã•ã„。" -msgstr[1] "æœ€å¤§æ¡æ•° %s æ¡ä»¥ä¸‹ã®æœ‰åŠ¹ãª 10 進数を入力ã—ã¦ãã ã•ã„。" +msgstr[0] "全体㧠%s æ–‡å—ä»¥ä¸‹ã®æ•°å—を入力ã—ã¦ãã ã•ã„。" +msgstr[1] "全体㧠%s æ–‡å—ä»¥ä¸‹ã®æ•°å—を入力ã—ã¦ãã ã•ã„。" -#: core/validators.py:352 +#: core/validators.py:381 +#, python-format +msgid "" +"Please enter a valid decimal number with a whole part of at most %s digit." +msgid_plural "" +"Please enter a valid decimal number with a whole part of at most %s digits." +msgstr[0] "整数部㯠%s æ–‡å—ä»¥ä¸‹ã®æ•°å—を入力ã—ã¦ãã ã•ã„。" +msgstr[1] "整数部㯠%s æ–‡å—ä»¥ä¸‹ã®æ•°å—を入力ã—ã¦ãã ã•ã„。" + +#: core/validators.py:384 #, python-format msgid "Please enter a valid decimal number with at most %s decimal place." msgid_plural "" "Please enter a valid decimal number with at most %s decimal places." -msgstr[0] "å°æ•°ç‚¹ä»¥ä¸‹ãŒ %s æ¡ã¾ã§ã®æœ‰åŠ¹ãª 10 進数を入力ã—ã¦ãã ã•ã„。" -msgstr[1] "å°æ•°ç‚¹ä»¥ä¸‹ãŒ %s æ¡ã¾ã§ã®æœ‰åŠ¹ãª 10 進数を入力ã—ã¦ãã ã•ã„。" +msgstr[0] "å°æ•°éƒ¨ã¯ %s æ–‡å—ä»¥ä¸‹ã®æ•°å—を入力ã—ã¦ãã ã•ã„。" +msgstr[1] "å°æ•°éƒ¨ã¯ %s æ–‡å—ä»¥ä¸‹ã®æ•°å—を入力ã—ã¦ãã ã•ã„。" -#: core/validators.py:362 +#: core/validators.py:394 #, python-format msgid "Make sure your uploaded file is at least %s bytes big." msgstr "アップãƒãƒ¼ãƒ‰ã™ã‚‹ãƒ•ァイルã®å¤§ãã•㯠%s ãƒã‚¤ãƒˆä»¥ä¸Šã«ã—ã¦ãã ã•ã„。" -#: core/validators.py:363 +#: core/validators.py:395 #, python-format msgid "Make sure your uploaded file is at most %s bytes big." msgstr "アップãƒãƒ¼ãƒ‰ã™ã‚‹ãƒ•ァイルã®å¤§ãã•㯠%s 最大ãƒã‚¤ãƒˆã¾ã§ã§ã™ã€‚" -#: core/validators.py:376 +#: core/validators.py:412 msgid "The format for this field is wrong." msgstr "フィールドã®å½¢å¼ãŒæ£ã—ãã‚りã¾ã›ã‚“。" -#: core/validators.py:391 +#: core/validators.py:427 msgid "This field is invalid." msgstr "ã“ã®ãƒ•ィールドã¯ç„¡åйã§ã™ã€‚" -#: core/validators.py:426 +#: core/validators.py:463 #, python-format msgid "Could not retrieve anything from %s." msgstr "%s ã‹ã‚‰ä½•も検索ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚" -#: core/validators.py:429 +#: core/validators.py:466 #, python-format msgid "" "The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'." msgstr "" "URL %(url)s ã¯ç„¡åйãªã‚³ãƒ³ãƒ†ãƒ³ãƒ„タイプヘッダ '%(contenttype)s' ã‚’è¿”ã—ã¾ã—ãŸã€‚" -#: core/validators.py:462 +#: core/validators.py:499 #, python-format msgid "" "Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with " @@ -1646,7 +1849,7 @@ msgstr "" "%(line)s 行目ã‹ã‚‰å§‹ã¾ã‚‹ %(tag)s ã‚¿ã‚°ã‚’é–‰ã˜ã¦ãã ã•ã„ (\"%(start)s\" ã§å§‹ã¾ã‚‹" "行ã§ã™)。" -#: core/validators.py:466 +#: core/validators.py:503 #, python-format msgid "" "Some text starting on line %(line)s is not allowed in that context. (Line " @@ -1655,7 +1858,7 @@ msgstr "" "%(line)s 行目ã‹ã‚‰å§‹ã¾ã‚‹ãƒ†ã‚ストã¯ã“ã®ã‚³ãƒ³ãƒ†ã‚ストã§ã¯ä½¿ãˆã¾ã›ã‚“。 (\"%(start)" "s\" ã§å§‹ã¾ã‚‹è¡Œã§ã™)。" -#: core/validators.py:471 +#: core/validators.py:508 #, python-format msgid "" "\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%" @@ -1664,7 +1867,7 @@ msgstr "" "%(line)s 行目㮠\"%(attr)s\" ã¯ç„¡åйãªã‚¢ãƒˆãƒªãƒ“ュートã§ã™ (\"%(start)s\" ã§å§‹ã¾" "る行ã§ã™)。" -#: core/validators.py:476 +#: core/validators.py:513 #, python-format msgid "" "\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%" @@ -1673,7 +1876,7 @@ msgstr "" "%(line)s 行目㮠\"<%(tag)s>\" ã¯ç„¡åйãªã‚¿ã‚°ã§ã™( \"%(start)s\" ã§å§‹ã¾ã‚‹è¡Œã§" "ã™)。" -#: core/validators.py:480 +#: core/validators.py:517 #, python-format msgid "" "A tag on line %(line)s is missing one or more required attributes. (Line " @@ -1682,7 +1885,7 @@ msgstr "" "%(line)s 行目ã®ã‚¿ã‚°ã¯å¿…é ˆã‚¢ãƒˆãƒªãƒ“ãƒ¥ãƒ¼ãƒˆãŒæœªå…¥åŠ›ã§ã™( \"%(start)s\" ã§å§‹ã¾ã‚‹è¡Œ" "ã§ã™)。" -#: core/validators.py:485 +#: core/validators.py:522 #, python-format msgid "" "The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line " @@ -1691,61 +1894,56 @@ msgstr "" "%(line)s 行目㮠\"%(attr)s\" アトリビュートã®å€¤ãŒæ£ã—ãã‚りã¾ã›ã‚“ (\"%(start)" "s\" ã§å§‹ã¾ã‚‹è¡Œã§ã™) 。" -#: db/models/manipulators.py:302 +#: db/models/manipulators.py:305 #, python-format msgid "%(object)s with this %(type)s already exists for the given %(field)s." msgstr "" "%(field)s ã«å…¥åŠ›ã•れãŸã‚‚ã®ã¯ã€ã“ã® %(type)s ã® %(object)s ã«æ—¢ã«å˜åœ¨ã—ã¾ã™ã€‚" -#: db/models/fields/__init__.py:40 +#: db/models/fields/__init__.py:41 #, python-format msgid "%(optname)s with this %(fieldname)s already exists." msgstr "%(fieldname)s ã« %(optname)s ã¯æ—¢ã«å˜åœ¨ã—ã¾ã™ã€‚" -#: db/models/fields/__init__.py:114 db/models/fields/__init__.py:265 -#: db/models/fields/__init__.py:542 db/models/fields/__init__.py:553 -#: forms/__init__.py:346 +#: db/models/fields/__init__.py:115 db/models/fields/__init__.py:266 +#: db/models/fields/__init__.py:560 db/models/fields/__init__.py:571 +#: forms/__init__.py:347 msgid "This field is required." msgstr "ã“ã®ãƒ•ィールドã¯å¿…é ˆã§ã™ã€‚" -#: db/models/fields/__init__.py:337 -#, fuzzy +#: db/models/fields/__init__.py:349 msgid "This value must be an integer." msgstr "å€¤ã¯æ•´æ•°ã§ãªã‘れã°ãªã‚Šã¾ã›ã‚“。" -#: db/models/fields/__init__.py:369 -#, fuzzy +#: db/models/fields/__init__.py:381 msgid "This value must be either True or False." msgstr "値ã¯çœŸ: True ã¾ãŸã¯å½: False ã§ãªã‘れã°ãªã‚Šã¾ã›ã‚“。" -#: db/models/fields/__init__.py:385 -#, fuzzy +#: db/models/fields/__init__.py:397 msgid "This field cannot be null." msgstr "ã“ã®ãƒ•ィールドã«ã¯ NULL を指定ã§ãã¾ã›ã‚“。" -#: db/models/fields/__init__.py:562 +#: db/models/fields/__init__.py:580 msgid "Enter a valid filename." msgstr "æ£ã—ã„ファイルåを入力ã—ã¦ãã ã•ã„。" -#: db/models/fields/related.py:43 +#: db/models/fields/related.py:51 #, python-format msgid "Please enter a valid %s." msgstr "æ£ã—ã„ %s を入力ã—ã¦ãã ã•ã„。" -#: db/models/fields/related.py:579 -#, fuzzy +#: db/models/fields/related.py:618 msgid "Separate multiple IDs with commas." msgstr "複数㮠ID ã¯ã‚«ãƒ³ãƒžã§åŒºåˆ‡ã£ã¦ãã ã•ã„。" -#: db/models/fields/related.py:581 -#, fuzzy +#: db/models/fields/related.py:620 msgid "" "Hold down \"Control\", or \"Command\" on a Mac, to select more than one." msgstr "" -"è¤‡æ•°é¸æŠžã™ã‚‹ã¨ãã«ã¯ \"Control\"ã‚ーを押ã—ãŸã¾ã¾é¸æŠžã—ã¦ãã ã•ã„。Mac ã§ã¯ " -"\"Command\" ã‚ーを使ã£ã¦ãã ã•ã„。" +"è¤‡æ•°é¸æŠžã™ã‚‹ã¨ãã«ã¯ Control ã‚ーを押ã—ãŸã¾ã¾é¸æŠžã—ã¦ãã ã•ã„。Mac 㯠" +"Command ã‚ーを使ã£ã¦ãã ã•ã„" -#: db/models/fields/related.py:625 +#: db/models/fields/related.py:664 #, python-format msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid." msgid_plural "" @@ -1753,39 +1951,39 @@ msgid_plural "" msgstr[0] "æ£ã—ã„ %(self)s IDを入力ã—ã¦ãã ã•ã„。 %(value)r ã¯ç„¡åйã§ã™ã€‚" msgstr[1] "æ£ã—ã„ %(self)s IDを入力ã—ã¦ãã ã•ã„。 %(value)r ã¯ç„¡åйã§ã™ã€‚" -#: forms/__init__.py:380 +#: forms/__init__.py:382 #, python-format msgid "Ensure your text is less than %s character." msgid_plural "Ensure your text is less than %s characters." msgstr[0] "%s å—以下ã§å…¥åŠ›ã—ã¦ãã ã•ã„。" msgstr[1] "%s å—以下ã§å…¥åŠ›ã—ã¦ãã ã•ã„。" -#: forms/__init__.py:385 +#: forms/__init__.py:387 msgid "Line breaks are not allowed here." msgstr "改行ã¯ã§ãã¾ã›ã‚“。" -#: forms/__init__.py:480 forms/__init__.py:551 forms/__init__.py:589 +#: forms/__init__.py:488 forms/__init__.py:561 forms/__init__.py:600 #, python-format msgid "Select a valid choice; '%(data)s' is not in %(choices)s." msgstr "æ£ã—ãé¸æŠžã—ã¦ãã ã•ã„。; '%(data)s' 㯠%(choices)s ã«ã‚りã¾ã›ã‚“。" -#: forms/__init__.py:645 +#: forms/__init__.py:664 msgid "The submitted file is empty." msgstr "入力ã•れãŸãƒ•ァイルã¯ç©ºã§ã™ã€‚" -#: forms/__init__.py:699 +#: forms/__init__.py:720 msgid "Enter a whole number between -32,768 and 32,767." msgstr "-32,768 ã‹ã‚‰ 32,767 ã¾ã§ã®æ•´æ•°ã‚’入力ã—ã¦ãã ã•ã„。" -#: forms/__init__.py:708 +#: forms/__init__.py:730 msgid "Enter a positive number." msgstr "æ£ã®æ•°ã‚’入力ã—ã¦ãã ã•ã„。" -#: forms/__init__.py:717 +#: forms/__init__.py:740 msgid "Enter a whole number between 0 and 32,767." msgstr "0 ã‹ã‚‰ 32,767 ã¾ã§ã®æ•´æ•°ã‚’入力ã—ã¦ãã ã•ã„。" -#: template/defaultfilters.py:383 +#: template/defaultfilters.py:401 msgid "yes,no,maybe" msgstr "ã¯ã„,ã„ã„ãˆ,ãŸã¶ã‚“" @@ -1866,7 +2064,6 @@ msgid "December" msgstr "12月" #: utils/dates.py:19 -#, fuzzy msgid "jan" msgstr "1月" @@ -1883,7 +2080,6 @@ msgid "apr" msgstr "4月" #: utils/dates.py:19 -#, fuzzy msgid "may" msgstr "5月" @@ -1979,18 +2175,41 @@ msgid_plural "minutes" msgstr[0] "分" msgstr[1] "分" -#: utils/translation.py:363 +#: utils/translation/trans_real.py:362 msgid "DATE_FORMAT" msgstr "Y/m/d" -#: utils/translation.py:364 +#: utils/translation/trans_real.py:363 msgid "DATETIME_FORMAT" msgstr "Y/m/d H:i" -#: utils/translation.py:365 +#: utils/translation/trans_real.py:364 msgid "TIME_FORMAT" msgstr "H:i" +#: utils/translation/trans_real.py:380 +msgid "YEAR_MONTH_FORMAT" +msgstr "Y/m/d" + +#: utils/translation/trans_real.py:381 +msgid "MONTH_DAY_FORMAT" +msgstr "m/d" + +#: views/generic/create_update.py:43 +#, python-format +msgid "The %(verbose_name)s was created successfully." +msgstr "%(verbose_name)s を作æˆã—ã¾ã—ãŸã€‚" + +#: views/generic/create_update.py:117 +#, python-format +msgid "The %(verbose_name)s was updated successfully." +msgstr "%(verbose_name)s ã‚’æ›´æ–°ã—ã¾ã—ãŸã€‚" + +#: views/generic/create_update.py:184 +#, python-format +msgid "The %(verbose_name)s was deleted." +msgstr " %(verbose_name)s を削除ã—ã¾ã—ãŸã€‚" + #~ msgid "String (up to 50)" #~ msgstr "æ–‡å—列 (50 å—ã¾ã§)" diff --git a/django/conf/locale/ja/LC_MESSAGES/djangojs.mo b/django/conf/locale/ja/LC_MESSAGES/djangojs.mo Binary files differindex dee3150d1e..bddecacb10 100644 --- a/django/conf/locale/ja/LC_MESSAGES/djangojs.mo +++ b/django/conf/locale/ja/LC_MESSAGES/djangojs.mo diff --git a/django/conf/locale/ja/LC_MESSAGES/djangojs.po b/django/conf/locale/ja/LC_MESSAGES/djangojs.po index 3d91a17f7d..0ec1cadcf5 100644 --- a/django/conf/locale/ja/LC_MESSAGES/djangojs.po +++ b/django/conf/locale/ja/LC_MESSAGES/djangojs.po @@ -2,13 +2,13 @@ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
-#
+#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Django 1.0\n"
-"Report-Msgid-Bugs-To: Django-users Japan <django-ja@googlegroups.com>\n"
-"POT-Creation-Date: 2006-05-02 23:06+0900\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-10-06 00:30+0900\n"
"PO-Revision-Date: 2006-05-08 13:39+0900\n"
"Last-Translator: makoto tsuyuki <mtsuyuki@gmail.com>\n"
"Language-Team: Japanese <django-ja@googlegroups.com>\n"
@@ -61,50 +61,58 @@ msgstr "é¸æŠžã—ã¦ã‚¯ãƒªãƒƒã‚¯" msgid "Clear all"
msgstr "å…¨ã¦ã‚¯ãƒªã‚¢"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80
+#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
+#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
+msgid "Show"
+msgstr "表示"
+
+#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
+msgid "Hide"
+msgstr "éžè¡¨ç¤º"
+
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:47
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
msgid "Now"
msgstr "ç¾åœ¨"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:51
msgid "Clock"
msgstr "時計"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:78
msgid "Choose a time"
msgstr "æ™‚é–“ã‚’é¸æŠž"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
msgid "Midnight"
msgstr "夜ä¸"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
msgid "6 a.m."
msgstr "åˆå‰ 6 時"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:84
msgid "Noon"
msgstr "æ£åˆ"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
msgid "Cancel"
msgstr "ã‚ャンセル"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:128
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:177
msgid "Today"
msgstr "今日"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:132
msgid "Calendar"
msgstr "カレンダー"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:175
msgid "Yesterday"
msgstr "昨日"
-#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164
+#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
msgid "Tomorrow"
msgstr "明日"
-
diff --git a/django/conf/locale/no/LC_MESSAGES/django.mo b/django/conf/locale/no/LC_MESSAGES/django.mo Binary files differindex 4f55637235..ee2152b5e1 100644 --- a/django/conf/locale/no/LC_MESSAGES/django.mo +++ b/django/conf/locale/no/LC_MESSAGES/django.mo diff --git a/django/conf/locale/no/LC_MESSAGES/django.po b/django/conf/locale/no/LC_MESSAGES/django.po index 9b3099046d..427879a8f3 100644 --- a/django/conf/locale/no/LC_MESSAGES/django.po +++ b/django/conf/locale/no/LC_MESSAGES/django.po @@ -264,7 +264,7 @@ msgstr "Bare POST er tillatt" #: contrib/comments/views/comments.py:193 #: contrib/comments/views/comments.py:284 msgid "One or more of the required fields wasn't submitted" -msgstr "En eller flere av feltene som er krevd ble ikke sendt." +msgstr "En eller flere av feltene som er pÃ¥krevd ble ikke sendt." #: contrib/comments/views/comments.py:197 #: contrib/comments/views/comments.py:286 @@ -371,35 +371,32 @@ msgid "All" msgstr "Alle" #: contrib/admin/filterspecs.py:109 -#, fuzzy msgid "Any date" -msgstr "Alle datoer" +msgstr "NÃ¥r som helst" #: contrib/admin/filterspecs.py:110 -#, fuzzy msgid "Today" -msgstr "Mondag" +msgstr "I dag" #: contrib/admin/filterspecs.py:113 msgid "Past 7 days" -msgstr "" +msgstr "Siste 7 dager" #: contrib/admin/filterspecs.py:115 msgid "This month" -msgstr "" +msgstr "Denne mÃ¥neden" #: contrib/admin/filterspecs.py:117 msgid "This year" -msgstr "" +msgstr "I Ã¥r" #: contrib/admin/filterspecs.py:143 msgid "Yes" -msgstr "" +msgstr "Ja" #: contrib/admin/filterspecs.py:143 -#, fuzzy msgid "No" -msgstr "Nov." +msgstr "Nei" #: contrib/admin/filterspecs.py:150 msgid "Unknown" @@ -443,11 +440,13 @@ msgid "" "Please enter a correct username and password. Note that both fields are case-" "sensitive." msgstr "" +"Vær snill Ã¥ angi korrekt brukernavn og passord. La merke til at smÃ¥ og " +"store bokstaver er betraktet ulik." #: contrib/admin/views/decorators.py:23 #: contrib/admin/templates/admin/login.html:25 msgid "Log in" -msgstr "Log inn" +msgstr "Logg inn" #: contrib/admin/views/decorators.py:61 msgid "" @@ -473,12 +472,11 @@ msgstr "Brukernavnet kan ikke inneholde '@'" #: contrib/admin/views/decorators.py:84 #, python-format msgid "Your e-mail address is not your username. Try '%s' instead." -msgstr "Epost adressen din er ikke brukernavnet ditt, prøv '%s' i stede." +msgstr "E-post adressen din er ikke brukernavnet ditt, prøv '%s' i stede." #: contrib/admin/views/main.py:226 -#, fuzzy msgid "Site administration" -msgstr "Django administrasjon" +msgstr "Nettsted administrasjon" #: contrib/admin/views/main.py:260 #, python-format @@ -502,7 +500,7 @@ msgstr "Ny %s" #: contrib/admin/views/main.py:336 #, python-format msgid "Added %s." -msgstr "La til %s" +msgstr "Lagt til %s" #: contrib/admin/views/main.py:336 contrib/admin/views/main.py:338 #: contrib/admin/views/main.py:340 @@ -559,7 +557,7 @@ msgid "Are you sure?" msgstr "Er du sikker?" #: contrib/admin/views/main.py:533 -#, fuzzy, python-format +#, python-format msgid "Change history: %s" msgstr "Endre historien: %s" @@ -580,7 +578,6 @@ msgid "Integer" msgstr "Heltall" #: contrib/admin/views/doc.py:278 -#, fuzzy msgid "Boolean (Either True or False)" msgstr "Boolean (Enten \"True\" eller \"False\")" @@ -603,7 +600,7 @@ msgstr "Dato/tid" #: contrib/admin/views/doc.py:283 msgid "E-mail address" -msgstr "Epost adresse" +msgstr "E-post adresse" #: contrib/admin/views/doc.py:284 contrib/admin/views/doc.py:287 msgid "File path" @@ -614,13 +611,12 @@ msgid "Decimal number" msgstr "Desimal tall" #: contrib/admin/views/doc.py:291 -#, fuzzy msgid "Boolean (Either True, False or None)" msgstr "Boolean (enten \"True\", \"False\" eller \"None\")" #: contrib/admin/views/doc.py:292 msgid "Relation to parent model" -msgstr "" +msgstr "Relasjon til forelder modell" #: contrib/admin/views/doc.py:293 msgid "Phone number" @@ -636,7 +632,7 @@ msgstr "Tid" #: contrib/admin/views/doc.py:300 contrib/flatpages/models.py:7 msgid "URL" -msgstr "Internettadresse" +msgstr "URL" #: contrib/admin/views/doc.py:301 msgid "U.S. state (two uppercase letters)" @@ -756,12 +752,12 @@ msgstr "Fant ikke siden" #: contrib/admin/templates/admin/404.html:10 msgid "We're sorry, but the requested page could not be found." -msgstr "Beklager, men siden du spør etter finnest ikke." +msgstr "Beklager, men siden du spør etter finnes ikke." #: contrib/admin/templates/admin/index.html:17 #, python-format msgid "Models available in the %(name)s application." -msgstr "" +msgstr "Modeller fra applikasjonen %(name)s." #: contrib/admin/templates/admin/index.html:28 #: contrib/admin/templates/admin/change_form.html:15 @@ -813,7 +809,7 @@ msgid "" "objects, but your account doesn't have permission to delete the following " "types of objects:" msgstr "" -"Vist du sletter %(object_name)s '%(object)s' vill du ogsÃ¥ slette relaterte " +"Hivs du sletter %(object_name)s '%(object)s' vil du ogsÃ¥ slette relaterte " "objekter, men du har ikke tillatelse til Ã¥ slette de følgende objektene:" #: contrib/admin/templates/admin/delete_confirmation.html:21 @@ -836,11 +832,11 @@ msgstr "Av %(title)s " #: contrib/admin/templates/admin/search_form.html:8 msgid "Go" -msgstr "" +msgstr "GÃ¥" #: contrib/admin/templates/admin/change_form.html:21 msgid "View on site" -msgstr "Vis pÃ¥ siden" +msgstr "Vis pÃ¥ nettsted" #: contrib/admin/templates/admin/change_form.html:30 msgid "Please correct the error below." @@ -900,12 +896,12 @@ msgid "" "Forgotten your password? Enter your e-mail address below, and we'll reset " "your password and e-mail the new one to you." msgstr "" -"Har du glemt passordet ditt? Skriv inn epost adressen din under, sÃ¥ sender " -"vi deg et nytt passord via epost." +"Har du glemt passordet ditt? Skriv inn e-post adressen din under, sÃ¥ sender " +"vi deg et nytt passord via e-post." #: contrib/admin/templates/registration/password_reset_form.html:16 msgid "E-mail address:" -msgstr "Epost adresse:" +msgstr "E-post adresse:" #: contrib/admin/templates/registration/password_reset_form.html:16 msgid "Reset my password" @@ -917,7 +913,7 @@ msgstr "Takk for Ã¥ bruke tid pÃ¥ internett siden i dag." #: contrib/admin/templates/registration/logged_out.html:10 msgid "Log in again" -msgstr "Log inn igjen" +msgstr "Logg inn igjen" #: contrib/admin/templates/registration/password_reset_done.html:6 #: contrib/admin/templates/registration/password_reset_done.html:10 @@ -929,7 +925,7 @@ msgid "" "We've e-mailed a new password to the e-mail address you submitted. You " "should be receiving it shortly." msgstr "" -"Vi sender deg et nytt passord til epost adressen du oppgav. Du villmotta det " +"Vi sender deg et nytt passord til e-post adressen du oppgav. Du villmotta det " "snart." #: contrib/admin/templates/registration/password_change_form.html:12 @@ -959,7 +955,7 @@ msgstr "Endre passord" #: contrib/admin/templates/registration/password_reset_email.html:2 msgid "You're receiving this e-mail because you requested a password reset" msgstr "" -"Du har mottatt denne epost-en fordi du ba om Ã¥ tilbakestille passordet ditt" +"Du har mottatt denne e-posten fordi du ba om Ã¥ tilbakestille passordet ditt" #: contrib/admin/templates/registration/password_reset_email.html:3 #, python-format @@ -1036,10 +1032,9 @@ msgid "Edit this object (current window)" msgstr "Endre dette objektet (Ã¥pnes i dette vinduet)" #: contrib/admin/templates/admin_doc/bookmarklets.html:26 -#, fuzzy msgid "Jumps to the admin page for pages that represent a single object." msgstr "" -"Hopp til administrasjonsiden for siden som representerer et enkelt objekt." +"Hopp til administrasjonsiden for sidene som representerer et enkelt objekt." #: contrib/admin/templates/admin_doc/bookmarklets.html:28 msgid "Edit this object (new window)" @@ -1051,21 +1046,19 @@ msgstr "Samme som over, men Ã¥pner administrasjonsiden i et nytt vindu." #: contrib/admin/templates/widget/date_time.html:3 msgid "Date:" -msgstr "" +msgstr "Dato:" #: contrib/admin/templates/widget/date_time.html:4 -#, fuzzy msgid "Time:" -msgstr "Tid" +msgstr "Tid:" #: contrib/admin/templates/widget/file.html:2 msgid "Currently:" -msgstr "" +msgstr "NÃ¥:" #: contrib/admin/templates/widget/file.html:3 -#, fuzzy msgid "Change:" -msgstr "Endre" +msgstr "Endre:" #: contrib/redirects/models.py:7 msgid "redirect from" @@ -1126,7 +1119,7 @@ msgid "" "Example: 'flatpages/contact_page'. If this isn't provided, the system will " "use 'flatpages/default'." msgstr "" -"Eksempel: 'flatfiler/kontakt_side'. Vist denne ikke denne er gitt, vill " +"Eksempel: 'flatfiler/kontakt_side'. Hvis denne ikke denne er gitt, vill " "'flatfiles/default' bli brukt." #: contrib/flatpages/models.py:14 @@ -1136,7 +1129,7 @@ msgstr "registrering kreves" #: contrib/flatpages/models.py:14 msgid "If this is checked, only logged-in users will be able to view the page." msgstr "" -"Vist denne er krysset av er det bare brukere som er logget inn som kan se " +"Hvis denne er krysset av er det bare brukere som er logget inn som kan se " "siden." #: contrib/flatpages/models.py:18 @@ -1156,24 +1149,20 @@ msgid "codename" msgstr "kodenavn" #: contrib/auth/models.py:17 -#, fuzzy msgid "permission" -msgstr "Rettighet" +msgstr "rettighet" #: contrib/auth/models.py:18 contrib/auth/models.py:27 -#, fuzzy msgid "permissions" -msgstr "Rettigheter" +msgstr "rettigheter" #: contrib/auth/models.py:29 -#, fuzzy msgid "group" -msgstr "Gruppe" +msgstr "gruppe" #: contrib/auth/models.py:30 contrib/auth/models.py:65 -#, fuzzy msgid "groups" -msgstr "Grupper" +msgstr "grupper" #: contrib/auth/models.py:55 msgid "username" @@ -1205,7 +1194,7 @@ msgstr "administrasjons status" #: contrib/auth/models.py:60 msgid "Designates whether the user can log into this admin site." -msgstr "Bestemmer om brukeren kan logge inn pÃ¥ denne administrasjons siden." +msgstr "Bestemmer om brukeren kan logge inn pÃ¥ dette administrasjons sted." #: contrib/auth/models.py:61 msgid "active" @@ -1217,7 +1206,7 @@ msgstr "super bruker" #: contrib/auth/models.py:63 msgid "last login" -msgstr "liste logg inn" +msgstr "siste logg inn" #: contrib/auth/models.py:64 msgid "date joined" @@ -1232,19 +1221,16 @@ msgstr "" "tilgang til gruppene han/hun er i." #: contrib/auth/models.py:67 -#, fuzzy msgid "user permissions" msgstr "Rettigheter" #: contrib/auth/models.py:70 -#, fuzzy msgid "user" -msgstr "Bruker" +msgstr "bruker" #: contrib/auth/models.py:71 -#, fuzzy msgid "users" -msgstr "Brukere" +msgstr "brukere" #: contrib/auth/models.py:76 msgid "Personal info" @@ -1263,9 +1249,8 @@ msgid "Groups" msgstr "Grupper" #: contrib/auth/models.py:219 -#, fuzzy msgid "message" -msgstr "Meldinger" +msgstr "Melding" #: contrib/auth/forms.py:30 msgid "" @@ -1274,9 +1259,8 @@ msgid "" msgstr "" #: contrib/contenttypes/models.py:25 -#, fuzzy msgid "python model class name" -msgstr "python modul navn" +msgstr "python modell klasse navn" #: contrib/contenttypes/models.py:28 msgid "content type" @@ -1312,23 +1296,23 @@ msgstr "domene navn" #: contrib/sites/models.py:11 msgid "display name" -msgstr "vist navn" +msgstr "vise navn" #: contrib/sites/models.py:15 msgid "site" -msgstr "side" +msgstr "nettsted" #: contrib/sites/models.py:16 msgid "sites" -msgstr "sider" +msgstr "nettsteder" #: utils/translation.py:360 msgid "DATE_FORMAT" -msgstr "j. M U" +msgstr "j. M Y" #: utils/translation.py:361 msgid "DATETIME_FORMAT" -msgstr "j. M U - h:i" +msgstr "j. M Y - h:i" #: utils/translation.py:362 msgid "TIME_FORMAT" @@ -1336,7 +1320,7 @@ msgstr "h:i" #: utils/dates.py:6 msgid "Monday" -msgstr "Mondag" +msgstr "Mandag" #: utils/dates.py:6 msgid "Tuesday" @@ -1411,54 +1395,52 @@ msgid "December" msgstr "Desember" #: utils/dates.py:19 -#, fuzzy msgid "jan" -msgstr "og" +msgstr "jan" #: utils/dates.py:19 msgid "feb" -msgstr "" +msgstr "feb" #: utils/dates.py:19 msgid "mar" -msgstr "" +msgstr "mar" #: utils/dates.py:19 msgid "apr" -msgstr "" +msgstr "apr" #: utils/dates.py:19 -#, fuzzy msgid "may" -msgstr "Mai" +msgstr "mai" #: utils/dates.py:19 msgid "jun" -msgstr "" +msgstr "jun" #: utils/dates.py:20 msgid "jul" -msgstr "" +msgstr "jul" #: utils/dates.py:20 msgid "aug" -msgstr "" +msgstr "aug" #: utils/dates.py:20 msgid "sep" -msgstr "" +msgstr "sep" #: utils/dates.py:20 msgid "oct" -msgstr "" +msgstr "okt" #: utils/dates.py:20 msgid "nov" -msgstr "" +msgstr "nov" #: utils/dates.py:20 msgid "dec" -msgstr "" +msgstr "des" #: utils/dates.py:27 msgid "Jan." @@ -1466,7 +1448,7 @@ msgstr "Jan." #: utils/dates.py:27 msgid "Feb." -msgstr "Fef." +msgstr "Feb." #: utils/dates.py:28 msgid "Aug." @@ -1491,40 +1473,38 @@ msgstr "Des." #: utils/timesince.py:12 msgid "year" msgid_plural "years" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Ã¥r" +msgstr[1] "Ã¥r" #: utils/timesince.py:13 msgid "month" msgid_plural "months" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "mÃ¥ned" +msgstr[1] "mÃ¥ndeder" #: utils/timesince.py:14 msgid "week" msgid_plural "weeks" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "uke" +msgstr[1] "uker" #: utils/timesince.py:15 -#, fuzzy msgid "day" msgid_plural "days" -msgstr[0] "Mai" -msgstr[1] "Mai" +msgstr[0] "dag" +msgstr[1] "dager" #: utils/timesince.py:16 msgid "hour" msgid_plural "hours" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "time" +msgstr[1] "timer" #: utils/timesince.py:17 -#, fuzzy msgid "minute" msgid_plural "minutes" -msgstr[0] "side" -msgstr[1] "side" +msgstr[0] "minutt" +msgstr[1] "minutter" #: conf/global_settings.py:37 msgid "Bengali" @@ -1548,7 +1528,7 @@ msgstr "Tysk" #: conf/global_settings.py:42 msgid "Greek" -msgstr "" +msgstr "Gresk" #: conf/global_settings.py:43 msgid "English" @@ -1568,11 +1548,11 @@ msgstr "Galisisk" #: conf/global_settings.py:47 msgid "Hungarian" -msgstr "" +msgstr "Ungarsk" #: conf/global_settings.py:48 msgid "Hebrew" -msgstr "" +msgstr "Hebraiske" #: conf/global_settings.py:49 msgid "Icelandic" @@ -1584,11 +1564,11 @@ msgstr "Italiensk" #: conf/global_settings.py:51 msgid "Japanese" -msgstr "" +msgstr "Japansk" #: conf/global_settings.py:52 msgid "Dutch" -msgstr "" +msgstr "Nederlandsk" #: conf/global_settings.py:53 msgid "Norwegian" @@ -1600,7 +1580,7 @@ msgstr "Brasiliansk" #: conf/global_settings.py:55 msgid "Romanian" -msgstr "Romansk" +msgstr "Rumensk" #: conf/global_settings.py:56 msgid "Russian" @@ -1611,9 +1591,8 @@ msgid "Slovak" msgstr "Slovakisk" #: conf/global_settings.py:58 -#, fuzzy msgid "Slovenian" -msgstr "Slovakisk" +msgstr "Slovensk" #: conf/global_settings.py:59 msgid "Serbian" @@ -1624,9 +1603,8 @@ msgid "Swedish" msgstr "Svensk" #: conf/global_settings.py:61 -#, fuzzy msgid "Ukrainian" -msgstr "Brasiliansk" +msgstr "Ukrainsk" #: conf/global_settings.py:62 msgid "Simplified Chinese" @@ -1634,14 +1612,13 @@ msgstr "Simplifisert Kinesisk" #: conf/global_settings.py:63 msgid "Traditional Chinese" -msgstr "" +msgstr "Tradisjonell Kinesisk" #: core/validators.py:60 msgid "This value must contain only letters, numbers and underscores." msgstr "Dette feltet mÃ¥ bare inneholde bokstaver, nummer og understreker." #: core/validators.py:64 -#, fuzzy msgid "" "This value must contain only letters, numbers, underscores, dashes or " "slashes." @@ -1651,7 +1628,7 @@ msgstr "" #: core/validators.py:72 msgid "Uppercase letters are not allowed here." -msgstr "Tor skrift er ikke tillatt her." +msgstr "Stor bokstaver er ikke tillatt her." #: core/validators.py:76 msgid "Lowercase letters are not allowed here." @@ -1687,19 +1664,19 @@ msgstr "Skriv inn et helt nummer." #: core/validators.py:120 msgid "Only alphabetical characters are allowed here." -msgstr "Bare alfabetiske bokstaber er tillatt her." +msgstr "Bare alfabetiske bokstaver er tillatt her." #: core/validators.py:124 msgid "Enter a valid date in YYYY-MM-DD format." -msgstr "Skriv inn en dato i Ã…Ã…Ã…Ã…-MM-DD formatet." +msgstr "Skriv inn en dato i Ã…Ã…Ã…Ã…-MM-DD format." #: core/validators.py:128 msgid "Enter a valid time in HH:MM format." -msgstr "Skriv inn tiden i TT:MM formatet." +msgstr "Skriv inn tiden i TT:MM format." #: core/validators.py:132 db/models/fields/__init__.py:468 msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format." -msgstr "Skriv inn dato og tid i Ã…Ã…Ã…Ã…-MM-DD TT:MM formatet." +msgstr "Skriv inn dato og tid i Ã…Ã…Ã…Ã…-MM-DD TT:MM format." #: core/validators.py:136 msgid "Enter a valid e-mail address." @@ -1722,7 +1699,7 @@ msgstr "Internettadressen %s peker ikke til et godkjent bilde." #, python-format msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid." msgstr "" -"Telefon nummeret mÃ¥ være i XXX-XXX-XXXX formatet. \"%s\" er ikke godkjent." +"Telefon nummeret mÃ¥ være i XXX-XXX-XXXX format. \"%s\" er ikke godkjent." #: core/validators.py:167 #, python-format @@ -1731,7 +1708,7 @@ msgstr "Internettadressen %s peker ikke til en godkjent QuickTime film." #: core/validators.py:171 msgid "A valid URL is required." -msgstr "En godkjent internettadresse er pÃ¥budt." +msgstr "En godkjent internettadresse er pÃ¥krevd." #: core/validators.py:185 #, python-format @@ -1739,7 +1716,7 @@ msgid "" "Valid HTML is required. Specific errors are:\n" "%s" msgstr "" -"Godkjent HTML er pÃ¥budt. Feilene var:\n" +"Godkjent HTML er pÃ¥krevd. Feilene var:\n" "%s" #: core/validators.py:192 @@ -1750,7 +1727,7 @@ msgstr "Ikke godkjent XML: %s" #: core/validators.py:202 #, python-format msgid "Invalid URL: %s" -msgstr "Ikke godkjent internettadresse: %s" +msgstr "Ikke godkjent URL: %s" #: core/validators.py:206 core/validators.py:208 #, python-format @@ -1759,7 +1736,7 @@ msgstr "Internettadresse fører til en side som ikke virker." #: core/validators.py:214 msgid "Enter a valid U.S. state abbreviation." -msgstr "Skriv inn en godkjent amerikansk stats forkortelse." +msgstr "Skriv inn en godkjent amerikansk delstat forkortelse." #: core/validators.py:229 #, python-format @@ -1771,7 +1748,7 @@ msgstr[1] "Pass munnen din! Ordene %s er ikke tillatt her." #: core/validators.py:236 #, python-format msgid "This field must match the '%s' field." -msgstr "Dette felte mÃ¥ være det samme som i '%s' feltet." +msgstr "Dette feltet mÃ¥ være det samme som i '%s' feltet." #: core/validators.py:255 msgid "Please enter something for at least one field." @@ -1784,12 +1761,12 @@ msgstr "Vennligst skriv inn noe i begge felta, eller la dem stÃ¥ blanke." #: core/validators.py:282 #, python-format msgid "This field must be given if %(field)s is %(value)s" -msgstr "Dette feltet mÃ¥ bare brukes vist %(field)s er lik %(value)s" +msgstr "Dette feltet mÃ¥ bare brukes hvis %(field)s er lik %(value)s" #: core/validators.py:294 #, python-format msgid "This field must be given if %(field)s is not %(value)s" -msgstr "Dette feltet mÃ¥ bare brukes vist %(field)s ikke er lik %(value)s" +msgstr "Dette feltet mÃ¥ bare brukes hvis %(field)s ikke er lik %(value)s" #: core/validators.py:313 msgid "Duplicate values are not allowed." @@ -1824,13 +1801,13 @@ msgstr[1] "Skriv inn et desimal tall med maksimum %s tall bak komma. " #, python-format msgid "Make sure your uploaded file is at least %s bytes big." msgstr "" -"Er du sikker pÃ¥ at fila du prøver Ã¥ laste opp er minimum %s bytes stor?" +"Vær sikker pÃ¥ at fila du prøver Ã¥ laste opp er minimum %s bytes stor." #: core/validators.py:363 #, python-format msgid "Make sure your uploaded file is at most %s bytes big." msgstr "" -"Er du sikker pÃ¥ at fila du prøver Ã¥ laste opp er maksimum %s bytes stor?" +"Vær sikker pÃ¥ at fila du prøver Ã¥ laste opp er maksimum %s bytes stor." #: core/validators.py:376 msgid "The format for this field is wrong." @@ -1850,7 +1827,7 @@ msgstr "Klarte ikke Ã¥ motta noe fra %s." msgid "" "The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'." msgstr "" -"Tnternettadressen %(url)s returnerte en ikke godkjent Content-Type '%" +"Internettadressen %(url)s returnerte en ikke godkjent Content-Type '%" "(contenttype)s'." #: core/validators.py:462 @@ -1859,7 +1836,7 @@ msgid "" "Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with " "\"%(start)s\".)" msgstr "" -"Vennligst lukk taggen %(tag)s pÃ¥ linje %(line)s. (Linja starer med \"%(start)" +"Vennligst lukk taggen %(tag)s pÃ¥ linje %(line)s. (Linjen starer med \"%(start)" "s\".)" #: core/validators.py:466 @@ -1868,7 +1845,7 @@ msgid "" "Some text starting on line %(line)s is not allowed in that context. (Line " "starts with \"%(start)s\".)" msgstr "" -"Noe av teksten som starter pÃ¥ linje %(line)s er ikke tillatt. (Linja starter " +"Noe av teksten som starter pÃ¥ linje %(line)s er ikke tillatt. (Linjen starter " "med \"%(start)s\".)" #: core/validators.py:471 @@ -1877,7 +1854,7 @@ msgid "" "\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%" "(start)s\".)" msgstr "" -"\"%(attr)s\" pÃ¥ linje %(line)s er ikke en godkjent tillegg. (Linja starter " +"\"%(attr)s\" pÃ¥ linje %(line)s er ikke en godkjent tillegg. (Linjen starter " "med \"%(start)s\".)" #: core/validators.py:476 @@ -1886,7 +1863,7 @@ msgid "" "\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%" "(start)s\".)" msgstr "" -"\"<%(tag)s>\" pÃ¥ linje %(line)s er ikke en godkjent tag. (linja starter med " +"\"<%(tag)s>\" pÃ¥ linje %(line)s er ikke en godkjent tag. (linjen starter med " "\"%(start)s\".)" #: core/validators.py:480 @@ -1895,7 +1872,7 @@ msgid "" "A tag on line %(line)s is missing one or more required attributes. (Line " "starts with \"%(start)s\".)" msgstr "" -"En tag pÃ¥ linje %(line)s mangler en av de pÃ¥bydte tillegga. (linja starter " +"En tag pÃ¥ linje %(line)s mangler en av de pÃ¥krevde attributtene. (linjen starter " "med \"%(start)s\".)" #: core/validators.py:485 @@ -1904,13 +1881,13 @@ msgid "" "The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line " "starts with \"%(start)s\".)" msgstr "" -"\"%(attr)s\" tillegg pÃ¥ linje $(line)s har en ikke godkjent verdi. (Linja " +"\"%(attr)s\" tillegg pÃ¥ linje $(line)s har en ikke godkjent verdi. (Linjen " "starter med \"%(start)s\".)" #: db/models/manipulators.py:302 -#, fuzzy, python-format +#, python-format msgid "%(object)s with this %(type)s already exists for the given %(field)s." -msgstr "$(optname)s med %(fieldname)s finnes allerede." +msgstr "%(object)s med %(type)s finnes allerede for angitt %(field)s." #: db/models/fields/__init__.py:40 #, python-format @@ -1924,37 +1901,31 @@ msgid "This field is required." msgstr "Dette feltet er pÃ¥krevd." #: db/models/fields/__init__.py:337 -#, fuzzy msgid "This value must be an integer." -msgstr "Denne verdien mÃ¥ være 'power' av %s." +msgstr "Denne verdien mÃ¥ være et heltall." #: db/models/fields/__init__.py:369 -#, fuzzy msgid "This value must be either True or False." -msgstr "Denne verdien mÃ¥ være 'power' av %s." +msgstr "Denne verdien mÃ¥ være enten \"True\" eller \"False\"." #: db/models/fields/__init__.py:385 -#, fuzzy msgid "This field cannot be null." -msgstr "Dette feltet er feil." +msgstr "Dette feltet kan ikke være null/tom." #: db/models/fields/__init__.py:562 -#, fuzzy msgid "Enter a valid filename." -msgstr "Skriv inn en godkjent e-post adresse." +msgstr "Skriv inn et godkjent fil navn." #: db/models/fields/related.py:43 -#, fuzzy, python-format +#, python-format msgid "Please enter a valid %s." -msgstr "Vennligst skriv inn en godkjent IP adresse." +msgstr "Vennligst skriv inn en/et gyldig %s." #: db/models/fields/related.py:579 -#, fuzzy msgid "Separate multiple IDs with commas." msgstr "Separer Id-ene med kommaer." #: db/models/fields/related.py:581 -#, fuzzy msgid "" "Hold down \"Control\", or \"Command\" on a Mac, to select more than one." msgstr "" @@ -1965,14 +1936,14 @@ msgstr "" msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid." msgid_plural "" "Please enter valid %(self)s IDs. The values %(value)r are invalid." -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Skriv inn gyldige %(self)s ID-er. Verdien %(value)r er ikke gyldig." +msgstr[1] "Skriv inn gyldige %(self)s ID-er. Verdiene %(value)r er ikke gyldige." #: forms/__init__.py:380 -#, fuzzy, python-format +#, python-format msgid "Ensure your text is less than %s character." msgid_plural "Ensure your text is less than %s characters." -msgstr[0] "Sjekk at teksten er kortere enn %s bokstaver" +msgstr[0] "Sjekk at teksten er kortere enn %s bokstav" msgstr[1] "Sjekk at teksten er kortere enn %s bokstaver" #: forms/__init__.py:385 @@ -1982,7 +1953,7 @@ msgstr "Det er ikke tillatt med flere linjer her." #: forms/__init__.py:480 forms/__init__.py:551 forms/__init__.py:589 #, python-format msgid "Select a valid choice; '%(data)s' is not in %(choices)s." -msgstr "Velg et av valga; '%(data)s' er ikke i %(choices)s." +msgstr "Velg et gyldig valg; '%(data)s' er ikke i %(choices)s." #: forms/__init__.py:645 msgid "The submitted file is empty." @@ -2002,7 +1973,7 @@ msgstr "Skriv inn et heltall mellom 0 og 32767." #: template/defaultfilters.py:379 msgid "yes,no,maybe" -msgstr "" +msgstr "ja,nei,kanskje" #, fuzzy #~ msgid "Comments" diff --git a/django/conf/locale/no/LC_MESSAGES/djangojs.mo b/django/conf/locale/no/LC_MESSAGES/djangojs.mo Binary files differindex acdc98a7ef..4b23aba4e0 100644 --- a/django/conf/locale/no/LC_MESSAGES/djangojs.mo +++ b/django/conf/locale/no/LC_MESSAGES/djangojs.mo diff --git a/django/conf/locale/no/LC_MESSAGES/djangojs.po b/django/conf/locale/no/LC_MESSAGES/djangojs.po index befc101881..c6087646e0 100644 --- a/django/conf/locale/no/LC_MESSAGES/djangojs.po +++ b/django/conf/locale/no/LC_MESSAGES/djangojs.po @@ -61,6 +61,15 @@ msgstr "Søndag Mandag Tirsdag Onsdag Torsdag Fredag Lørdag" msgid "S M T W T F S" msgstr "S M T O T F L" +#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34 +#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72 +msgid "Show" +msgstr "Vis" + +#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63 +msgid "Hide" +msgstr "Skjul" + #: contrib/admin/media/js/admin/DateTimeShortcuts.js:45 #: contrib/admin/media/js/admin/DateTimeShortcuts.js:80 msgid "Now" @@ -80,7 +89,7 @@ msgstr "24.00" #: contrib/admin/media/js/admin/DateTimeShortcuts.js:82 msgid "6 a.m." -msgstr "18.00" +msgstr "06.00" #: contrib/admin/media/js/admin/DateTimeShortcuts.js:83 msgid "Noon" diff --git a/django/conf/locale/pl/LC_MESSAGES/django.mo b/django/conf/locale/pl/LC_MESSAGES/django.mo Binary files differindex f7fad56339..d132fc114e 100644 --- a/django/conf/locale/pl/LC_MESSAGES/django.mo +++ b/django/conf/locale/pl/LC_MESSAGES/django.mo diff --git a/django/conf/locale/pl/LC_MESSAGES/django.po b/django/conf/locale/pl/LC_MESSAGES/django.po index b6449e22b0..61fc4d0a90 100644 --- a/django/conf/locale/pl/LC_MESSAGES/django.po +++ b/django/conf/locale/pl/LC_MESSAGES/django.po @@ -126,12 +126,10 @@ msgid "approved by staff" msgstr "zaakceptowano" #: contrib/comments/models.py:176 -#, fuzzy msgid "free comment" msgstr "wolny komentarz" #: contrib/comments/models.py:177 -#, fuzzy msgid "free comments" msgstr "wolne komentarze" @@ -144,7 +142,6 @@ msgid "score date" msgstr "data przyznania punktów" #: contrib/comments/models.py:237 -#, fuzzy msgid "karma score" msgstr "ilość punktów" @@ -243,6 +240,9 @@ msgid "" "\n" "%(text)s" msgstr "" +"Ten komentarze zostaÅ‚ dodany przez użytkownika::\n" +"\n" +"%(text)s" #: contrib/comments/views/comments.py:189 #: contrib/comments/views/comments.py:280 @@ -257,19 +257,20 @@ msgstr "Jedno lub wiÄ™cej wymaganych pól nie zostaÅ‚o wypeÅ‚nionych" #: contrib/comments/views/comments.py:197 #: contrib/comments/views/comments.py:286 msgid "Somebody tampered with the comment form (security violation)" -msgstr "" +msgstr "KtoÅ› próbowaÅ‚ obejść zabezpieczenia formularza komentarzy" #: contrib/comments/views/comments.py:207 #: contrib/comments/views/comments.py:292 msgid "" "The comment form had an invalid 'target' parameter -- the object ID was " "invalid" -msgstr "" +msgstr "Formularz komentarza miaÅ‚ niepoprawny parametr 'target' -- ID obiektu byÅ‚o " +"niepoprawne" #: contrib/comments/views/comments.py:257 #: contrib/comments/views/comments.py:321 msgid "The comment form didn't provide either 'preview' or 'post'" -msgstr "" +msgstr "Formularz komentarza nie zapewniÅ‚ obiektów 'preview' ani 'post'" #: contrib/comments/templates/comments/form.html:6 #: contrib/comments/templates/comments/form.html:8 @@ -600,7 +601,7 @@ msgstr "Wartość logiczna (True, False, None - prawda, faÅ‚sz lub nic)" #: contrib/admin/views/doc.py:292 msgid "Relation to parent model" -msgstr "" +msgstr "Relacja do modelu rodzica" #: contrib/admin/views/doc.py:293 msgid "Phone number" @@ -794,6 +795,9 @@ msgid "" "objects, but your account doesn't have permission to delete the following " "types of objects:" msgstr "" +"Skasowanie %(object_name)s '%(object)s' spowoduje kasacjÄ™ zależnych " +"obiektów, lecz twoje uprawnienia nie pozwalajÄ… na usuniÄ™cie nastÄ™pujÄ…cych " +"typów obiektów:" #: contrib/admin/templates/admin/delete_confirmation.html:21 #, python-format @@ -801,6 +805,8 @@ msgid "" "Are you sure you want to delete the %(object_name)s \"%(object)s\"? All of " "the following related items will be deleted:" msgstr "" +"Czy chcesz skasować %(object_name)s \"%(object)s\"? Wszystkie " +"zależne obiekty zostanÄ… skasowane:" #: contrib/admin/templates/admin/delete_confirmation.html:26 msgid "Yes, I'm sure" @@ -820,11 +826,10 @@ msgid "View on site" msgstr "Pokaż na stronie" #: contrib/admin/templates/admin/change_form.html:30 -#, fuzzy msgid "Please correct the error below." msgid_plural "Please correct the errors below." msgstr[0] "ProszÄ™ popraw poniższy błąd" -msgstr[1] "ProszÄ™ popraw poniższy błąd" +msgstr[1] "ProszÄ™ popraw poniższe błędy" #: contrib/admin/templates/admin/change_form.html:48 msgid "Ordering" @@ -965,11 +970,11 @@ msgstr "Zespół %(site_name)s" #: contrib/admin/templates/admin_doc/bookmarklets.html:3 msgid "Bookmarklets" -msgstr "" +msgstr "ZakÅ‚adki" #: contrib/admin/templates/admin_doc/bookmarklets.html:5 msgid "Documentation bookmarklets" -msgstr "" +msgstr "ZakÅ‚adki Dokumentacji" #: contrib/admin/templates/admin_doc/bookmarklets.html:9 msgid "" @@ -1094,6 +1099,8 @@ msgid "" "Example: 'flatpages/contact_page'. If this isn't provided, the system will " "use 'flatpages/default'." msgstr "" +"PrzykÅ‚ad: 'flatpages/contact_page'. Jeżeli nie podane system użyje " +"'flatpages/default'." #: contrib/flatpages/models.py:14 msgid "registration required" @@ -1105,11 +1112,11 @@ msgstr "Jeżeli zaznaczone - tylko zalogowani użytkownicy bÄ™dÄ… mogli zobaczyÄ #: contrib/flatpages/models.py:18 msgid "flat page" -msgstr "" +msgstr "strona statyczna" #: contrib/flatpages/models.py:19 msgid "flat pages" -msgstr "" +msgstr "strony statyczne" #: contrib/auth/models.py:13 contrib/auth/models.py:26 msgid "name" @@ -1117,7 +1124,7 @@ msgstr "nazwa" #: contrib/auth/models.py:15 msgid "codename" -msgstr "" +msgstr "nazwa kodowa" #: contrib/auth/models.py:17 msgid "permission" @@ -1161,11 +1168,11 @@ msgstr "Użyj '[algo]$[salt]$[hexdigest]'" #: contrib/auth/models.py:60 msgid "staff status" -msgstr "stan w zespole" +msgstr "w zespole" #: contrib/auth/models.py:60 msgid "Designates whether the user can log into this admin site." -msgstr "Oznaczy czy użytkownik może zalogować siÄ™ do panelu admina." +msgstr "Oznacza czy użytkownik może zalogować siÄ™ do panelu admina." #: contrib/auth/models.py:61 msgid "active" @@ -1195,15 +1202,14 @@ msgstr "" msgid "user permissions" msgstr "uprawnienia użytkownika" +#kurwa #: contrib/auth/models.py:70 -#, fuzzy msgid "user" -msgstr "Użytkownik" +msgstr "użytkownik" #: contrib/auth/models.py:71 -#, fuzzy msgid "users" -msgstr "Uzytkownicy" +msgstr "użytkownicy" #: contrib/auth/models.py:76 msgid "Personal info" @@ -1222,7 +1228,6 @@ msgid "Groups" msgstr "Grupy" #: contrib/auth/models.py:219 -#, fuzzy msgid "message" msgstr "wiadomość" @@ -1371,7 +1376,6 @@ msgid "December" msgstr "GrudzieÅ„" #: utils/dates.py:19 -#, fuzzy msgid "jan" msgstr "sty" @@ -1472,11 +1476,10 @@ msgstr[0] "dzieÅ„" msgstr[1] "dni" #: utils/timesince.py:16 -#, fuzzy msgid "hour" msgid_plural "hours" msgstr[0] "godzina" -msgstr[1] "godzina" +msgstr[1] "godzin" #: utils/timesince.py:17 msgid "minute" @@ -1569,7 +1572,6 @@ msgid "Slovak" msgstr "SÅ‚owacki" #: conf/global_settings.py:58 -#, fuzzy msgid "Slovenian" msgstr "SÅ‚owacki" @@ -1582,9 +1584,8 @@ msgid "Swedish" msgstr "Szwedzki" #: conf/global_settings.py:61 -#, fuzzy msgid "Ukrainian" -msgstr "Brazylijski" +msgstr "UkraiÅ„ski" #: conf/global_settings.py:62 msgid "Simplified Chinese" @@ -1715,14 +1716,14 @@ msgstr "OdnoÅ›nik %s jest nieprawidÅ‚owy." #: core/validators.py:214 msgid "Enter a valid U.S. state abbreviation." -msgstr "Wpisz poprawny kod stanu U.S." +msgstr "Wpisz poprawny kod stanu U.S.A." #: core/validators.py:229 -#, fuzzy, python-format +#, python-format msgid "Watch your mouth! The word %s is not allowed here." msgid_plural "Watch your mouth! The words %s are not allowed here." msgstr[0] "Nie wolno przeklinać! SÅ‚owo %s jest niedozwolone." -msgstr[1] "Nie wolno przeklinać! SÅ‚owo %s jest niedozwolone." +msgstr[1] "Nie wolno przeklinać! SÅ‚owa %s sÄ… niedozwolone." #: core/validators.py:236 #, python-format @@ -1745,11 +1746,11 @@ msgstr "To pole musi być uzupeÅ‚nione jeÅ›li %(field)s jest %(value)s" #: core/validators.py:294 #, python-format msgid "This field must be given if %(field)s is not %(value)s" -msgstr "" +msgstr "To pole musi być wypeÅ‚nione jeżeli %(field)s nie jest %(value)s" #: core/validators.py:313 msgid "Duplicate values are not allowed." -msgstr "" +msgstr "Duplikaty sÄ… niedozwolone." #: core/validators.py:336 #, python-format @@ -1761,20 +1762,20 @@ msgid "Please enter a valid decimal number." msgstr "ProszÄ™ wpisać poprawnÄ… liczbÄ™ dziesiÄ™tnÄ…." #: core/validators.py:349 -#, fuzzy, python-format +#, python-format msgid "Please enter a valid decimal number with at most %s total digit." msgid_plural "" "Please enter a valid decimal number with at most %s total digits." -msgstr[0] "ProszÄ™ wpisać poprawnÄ… liczbÄ™ dziesiÄ™tnÄ…." -msgstr[1] "ProszÄ™ wpisać poprawnÄ… liczbÄ™ dziesiÄ™tnÄ…." +msgstr[0] "ProszÄ™ wpisać poprawnÄ… liczbÄ™ dziesiÄ™tnÄ… zawierajÄ…cÄ… nie wiÄ™cej niż %s cyfry." +msgstr[1] "ProszÄ™ wpisać poprawnÄ… liczbÄ™ dziesiÄ™tnÄ… zawierajÄ…cÄ… nie wiÄ™cej niż %s cyfr." #: core/validators.py:352 -#, fuzzy, python-format +#, python-format msgid "Please enter a valid decimal number with at most %s decimal place." msgid_plural "" "Please enter a valid decimal number with at most %s decimal places." -msgstr[0] "ProszÄ™ wpisać poprawnÄ… liczbÄ™ dziesiÄ™tnÄ…." -msgstr[1] "ProszÄ™ wpisać poprawnÄ… liczbÄ™ dziesiÄ™tnÄ…." +msgstr[0] "ProszÄ™ wpisać poprawnÄ… liczbÄ™ dziesiÄ™tnÄ… z dokÅ‚adnoÅ›ciÄ… do %s miejsca po przecinku." +msgstr[1] "ProszÄ™ wpisać poprawnÄ… liczbÄ™ dziesiÄ™tnÄ… z dokÅ‚adnoÅ›ciÄ… do %s miejsc po przecinku." #: core/validators.py:362 #, python-format @@ -1797,13 +1798,14 @@ msgstr "To pole jest nieprawidÅ‚owe." #: core/validators.py:426 #, python-format msgid "Could not retrieve anything from %s." -msgstr "Nie można otrzymać nic z %s." +msgstr "Nie można nic pobrać z %s." #: core/validators.py:429 #, python-format msgid "" "The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'." msgstr "" +"URL %(url)s zwróciÅ‚ niepoprawny Content-Type header '%(contenttype)s'." #: core/validators.py:462 @@ -1866,17 +1868,15 @@ msgstr "To pole jest wymagane" #: db/models/fields/__init__.py:337 msgid "This value must be an integer." -msgstr "" +msgstr "Ta wartość musi być liczbÄ… caÅ‚kowitÄ…" #: db/models/fields/__init__.py:369 -#, fuzzy msgid "This value must be either True or False." -msgstr "Wartość logiczna (True, False - prawda lub faÅ‚sz)" +msgstr "Ta wartość musi być logiczna (True, False - prawda lub faÅ‚sz)." #: db/models/fields/__init__.py:385 -#, fuzzy msgid "This field cannot be null." -msgstr "To pole jest nieprawidÅ‚owe." +msgstr "To pole nie może być puste." #: db/models/fields/__init__.py:562 msgid "Enter a valid filename." @@ -1888,12 +1888,10 @@ msgid "Please enter a valid %s." msgstr "ProszÄ™ wpisać poprawne %s." #: db/models/fields/related.py:579 -#, fuzzy msgid "Separate multiple IDs with commas." msgstr "Oddziel kilka pól ID przecinkami." #: db/models/fields/related.py:581 -#, fuzzy msgid "" "Hold down \"Control\", or \"Command\" on a Mac, to select more than one." msgstr "" @@ -1909,11 +1907,11 @@ msgstr[0] "" msgstr[1] "" #: forms/__init__.py:380 -#, fuzzy, python-format +#, python-format msgid "Ensure your text is less than %s character." msgid_plural "Ensure your text is less than %s characters." -msgstr[0] "Upewnij siÄ™, że jest mniej niż %s znaków." -msgstr[1] "Upewnij siÄ™, że jest mniej niż %s znaków." +msgstr[0] "Upewnij siÄ™, że tekst ma mniej niż %s znak." +msgstr[1] "Upewnij siÄ™, że tekst ma mniej niż %s znaków." #: forms/__init__.py:385 msgid "Line breaks are not allowed here." diff --git a/django/conf/locale/ru/LC_MESSAGES/django.mo b/django/conf/locale/ru/LC_MESSAGES/django.mo Binary files differindex 562996eee5..12e240529f 100644 --- a/django/conf/locale/ru/LC_MESSAGES/django.mo +++ b/django/conf/locale/ru/LC_MESSAGES/django.mo diff --git a/django/conf/locale/ru/LC_MESSAGES/django.po b/django/conf/locale/ru/LC_MESSAGES/django.po index 024b2bfc12..f329efe24f 100644 --- a/django/conf/locale/ru/LC_MESSAGES/django.po +++ b/django/conf/locale/ru/LC_MESSAGES/django.po @@ -5,97 +5,102 @@ # msgid "" msgstr "" -"Project-Id-Version: django\n" +"Project-Id-Version: django 0.95\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2006-05-16 10:11+0200\n" -"PO-Revision-Date: 2005-11-26 00:00\n" -"Last-Translator: Dmitry Sorokin <ds@dial.com.ru>\n" -"Language-Team: LANGUAGE <LL@li.org>\n" +"PO-Revision-Date: 2006-09-07 15:28+0300\n" +"Last-Translator: Alexander Yakovlev <AYakovlev@rambler.ru>\n" +"Language-Team: Dialcom Services <greg@dial.com.ru>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Poedit-Language: Russian\n" +"X-Poedit-Country: RUSSIAN FEDERATION\n" +"X-Poedit-SourceCharset: utf-8\n" -#: contrib/comments/models.py:67 contrib/comments/models.py:166 +#: contrib/comments/models.py:67 +#: contrib/comments/models.py:166 msgid "object ID" msgstr "ID объекта" #: contrib/comments/models.py:68 msgid "headline" -msgstr "заголовок" +msgstr "Заголовок" -#: contrib/comments/models.py:69 contrib/comments/models.py:90 +#: contrib/comments/models.py:69 +#: contrib/comments/models.py:90 #: contrib/comments/models.py:167 msgid "comment" -msgstr "комментарий" +msgstr "Комментарий" #: contrib/comments/models.py:70 msgid "rating #1" -msgstr "рейтинг #1" +msgstr "рейтинг â„–1" #: contrib/comments/models.py:71 msgid "rating #2" -msgstr "рейтинг #2" +msgstr "рейтинг â„–2" #: contrib/comments/models.py:72 msgid "rating #3" -msgstr "рейтинг #3" +msgstr "рейтинг â„–3" #: contrib/comments/models.py:73 msgid "rating #4" -msgstr "рейтинг #4" +msgstr "рейтинг â„–4" #: contrib/comments/models.py:74 msgid "rating #5" -msgstr "рейтинг #5" +msgstr "рейтинг â„–5" #: contrib/comments/models.py:75 msgid "rating #6" -msgstr "рейтинг #6" +msgstr "рейтинг â„–6" #: contrib/comments/models.py:76 msgid "rating #7" -msgstr "рейтинг #7" +msgstr "рейтинг â„–7" #: contrib/comments/models.py:77 msgid "rating #8" -msgstr "рейтинг #8" +msgstr "рейтинг â„–8" #: contrib/comments/models.py:82 msgid "is valid rating" -msgstr "доÑтупный рейтинг" +msgstr "ДопуÑтимый рейтинг" -#: contrib/comments/models.py:83 contrib/comments/models.py:169 +#: contrib/comments/models.py:83 +#: contrib/comments/models.py:169 msgid "date/time submitted" -msgstr "дата/Ð²Ñ€ÐµÐ¼Ñ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ" +msgstr "Дата/Ð²Ñ€ÐµÐ¼Ñ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ" -#: contrib/comments/models.py:84 contrib/comments/models.py:170 +#: contrib/comments/models.py:84 +#: contrib/comments/models.py:170 msgid "is public" -msgstr "публичный" +msgstr "Публичный" -#: contrib/comments/models.py:85 contrib/admin/views/doc.py:289 +#: contrib/comments/models.py:85 +#: contrib/admin/views/doc.py:289 msgid "IP address" -msgstr "IP адреÑ" +msgstr "IP-адреÑ" #: contrib/comments/models.py:86 msgid "is removed" -msgstr "удален" +msgstr "Удален" #: contrib/comments/models.py:86 -msgid "" -"Check this box if the comment is inappropriate. A \"This comment has been " -"removed\" message will be displayed instead." -msgstr "" -"Отметте, еÑли комментарий нежелателен. Сообщение \"Ðтот комментарий был " -"удалён\" будет показано взамен." +msgid "Check this box if the comment is inappropriate. A \"This comment has been removed\" message will be displayed instead." +msgstr "Отметьте, еÑли комментарий нежелателен. Сообщение \"Ðтот комментарий был удалён\" будет показано взамен." #: contrib/comments/models.py:91 -#, fuzzy msgid "comments" -msgstr "комментарий" +msgstr "Комментарии" -#: contrib/comments/models.py:131 contrib/comments/models.py:207 +#: contrib/comments/models.py:131 +#: contrib/comments/models.py:207 msgid "Content object" -msgstr "Объект наполнениÑ" +msgstr "Объект Ñодержимого" #: contrib/comments/models.py:159 #, python-format @@ -106,7 +111,7 @@ msgid "" "\n" "http://%(domain)s%(url)s" msgstr "" -"Добавил %(user)s %(date)s\n" +"Добавил %(user)s %(date)s\n" "\n" "%(comment)s\n" "\n" @@ -114,15 +119,15 @@ msgstr "" #: contrib/comments/models.py:168 msgid "person's name" -msgstr "Ð¸Ð¼Ñ Ñ‡ÐµÐ»Ð¾Ð²ÐµÐºÐ°" +msgstr "Ð˜Ð¼Ñ Ñ‡ÐµÐ»Ð¾Ð²ÐµÐºÐ°" #: contrib/comments/models.py:171 msgid "ip address" -msgstr "ip адреÑ:" +msgstr "IP-адреÑ:" #: contrib/comments/models.py:173 msgid "approved by staff" -msgstr "одобрено админиÑтрацией" +msgstr "Одобрено админиÑтрацией" #: contrib/comments/models.py:176 msgid "free comment" @@ -134,24 +139,24 @@ msgstr "Свободные комментарии" #: contrib/comments/models.py:233 msgid "score" -msgstr "Ñчёт" +msgstr "Счёт" #: contrib/comments/models.py:234 msgid "score date" -msgstr "Ñчёт времени" +msgstr "Ð’Ñ€ÐµÐ¼Ñ Ñчёта" #: contrib/comments/models.py:237 msgid "karma score" -msgstr "Карма Ñчёт" +msgstr "КармичеÑкий Ñчёт" #: contrib/comments/models.py:238 msgid "karma scores" -msgstr "Карма Ñчета" +msgstr "КармичеÑкие Ñчета" #: contrib/comments/models.py:242 #, python-format msgid "%(score)d rating by %(user)s" -msgstr "" +msgstr "%(score)d рейтинг Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ %(user)s" #: contrib/comments/models.py:258 #, python-format @@ -160,21 +165,21 @@ msgid "" "\n" "%(text)s" msgstr "" -"Ðтот комментарий был отмечен %(user)s:\n" +"Ðтот комментарий был отмечен пользователем %(user)s:\n" "\n" "%(text)s" #: contrib/comments/models.py:265 msgid "flag date" -msgstr "отметка даты" +msgstr "Дата отметки" #: contrib/comments/models.py:268 msgid "user flag" -msgstr "Признак пользователÑ" +msgstr "Отметка пользователÑ" #: contrib/comments/models.py:269 msgid "user flags" -msgstr "Признаки пользователÑ" +msgstr "Отметки пользователÑ" #: contrib/comments/models.py:273 #, python-format @@ -183,11 +188,11 @@ msgstr "Отмечен %r" #: contrib/comments/models.py:278 msgid "deletion date" -msgstr "дата удалениÑ" +msgstr "Дата удалениÑ" #: contrib/comments/models.py:280 msgid "moderator deletion" -msgstr "Удаленно модератором" +msgstr "Удаление модератором" #: contrib/comments/models.py:281 msgid "moderator deletions" @@ -196,7 +201,7 @@ msgstr "Ð£Ð´Ð°Ð»ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð´ÐµÑ€Ð°Ñ‚Ð¾Ñ€Ð¾Ð¼" #: contrib/comments/models.py:285 #, python-format msgid "Moderator deletion by %r" -msgstr "" +msgstr "Ð£Ð´Ð°Ð»ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð´ÐµÑ€Ð°Ñ‚Ð¾Ñ€Ð° %r" #: contrib/comments/views/karma.py:19 msgid "Anonymous users cannot vote" @@ -211,24 +216,31 @@ msgid "No voting for yourself" msgstr "ÐÐµÐ»ÑŒÐ·Ñ Ð³Ð¾Ð»Ð¾Ñовать за ÑебÑ" #: contrib/comments/views/comments.py:28 -msgid "" -"This rating is required because you've entered at least one other rating." -msgstr "" +msgid "This rating is required because you've entered at least one other rating." +msgstr "Ðтот рейтинг обÑзателен, так как вы уже ввели как минимум еще один рейтинг." #: contrib/comments/views/comments.py:112 #, python-format msgid "" -"This comment was posted by a user who has posted fewer than %(count)s " -"comment:\n" +"This comment was posted by a user who has posted fewer than %(count)s comment:\n" "\n" "%(text)s" msgid_plural "" -"This comment was posted by a user who has posted fewer than %(count)s " -"comments:\n" +"This comment was posted by a user who has posted fewer than %(count)s comments:\n" "\n" "%(text)s" msgstr[0] "" +"Ðтот комментарий Ñделан пользователем, который отправил меньше %(count)s комментариÑ:\n" +"\n" +"%(text)s" msgstr[1] "" +"Ðтот комментарий Ñделан пользователем, который отправил меньше %(count)s комментариев:\n" +"\n" +"%(text)s" +msgstr[2] "" +"Ðтот комментарий Ñделан пользователем, который отправил меньше %(count)s комментариев:\n" +"\n" +"%(text)s" #: contrib/comments/views/comments.py:117 #, python-format @@ -237,14 +249,14 @@ msgid "" "\n" "%(text)s" msgstr "" -"Коментарий был добавлен ндоверенным пользователем:\n" +"Коментарий был добавлен недоверенным пользователем:\n" "\n" "%(text)s" #: contrib/comments/views/comments.py:189 #: contrib/comments/views/comments.py:280 msgid "Only POSTs are allowed" -msgstr "Только POSTÑ‹ разрешены" +msgstr "Разрешены только POSTÑ‹" #: contrib/comments/views/comments.py:193 #: contrib/comments/views/comments.py:284 @@ -254,20 +266,17 @@ msgstr "Одно или больше обÑзательных полей не б #: contrib/comments/views/comments.py:197 #: contrib/comments/views/comments.py:286 msgid "Somebody tampered with the comment form (security violation)" -msgstr "Кто-то вмешиваетÑÑ Ð² форму ÐºÐ¾Ð¼Ð¼ÐµÐ½Ñ‚Ð°Ñ€Ð¸Ñ (нарушение безопаÑноÑти)" +msgstr "Кто-то вмешалÑÑ Ð² форму ÐºÐ¾Ð¼Ð¼ÐµÐ½Ñ‚Ð°Ñ€Ð¸Ñ (нарушение безопаÑноÑти)" #: contrib/comments/views/comments.py:207 #: contrib/comments/views/comments.py:292 -msgid "" -"The comment form had an invalid 'target' parameter -- the object ID was " -"invalid" -msgstr "" -"Форма ÐºÐ¾Ð¼Ð¼ÐµÐ½Ñ‚Ð°Ñ€Ð¸Ñ Ð¸Ð¼ÐµÐµÑ‚ неверный 'target' параметр -- ID объекта неверно" +msgid "The comment form had an invalid 'target' parameter -- the object ID was invalid" +msgstr "Форма ÐºÐ¾Ð¼Ð¼ÐµÐ½Ñ‚Ð°Ñ€Ð¸Ñ Ð¸Ð¼ÐµÐ»Ð° неверный параметр 'target' -- ID объекта неверен" #: contrib/comments/views/comments.py:257 #: contrib/comments/views/comments.py:321 msgid "The comment form didn't provide either 'preview' or 'post'" -msgstr "Форма ÐºÐ¾Ð¼Ð¼ÐµÐ½Ñ‚Ð°Ñ€Ð¸Ñ Ð½Ðµ обеÑпечивает и 'preview' или 'post'" +msgstr "Форма ÐºÐ¾Ð¼Ð¼ÐµÐ½Ñ‚Ð°Ñ€Ð¸Ñ Ð½Ðµ предоÑтавила ни 'предпроÑмотр', ни 'отправить'" #: contrib/comments/templates/comments/form.html:6 #: contrib/comments/templates/comments/form.html:8 @@ -312,7 +321,7 @@ msgstr "Рейтинги" #: contrib/comments/templates/comments/form.html:12 #: contrib/comments/templates/comments/form.html:23 msgid "Required" -msgstr "Ðеобходимое" +msgstr "ОбÑзательное" #: contrib/comments/templates/comments/form.html:12 #: contrib/comments/templates/comments/form.html:23 @@ -331,11 +340,11 @@ msgstr "Комментарий:" #: contrib/comments/templates/comments/form.html:32 #: contrib/comments/templates/comments/freeform.html:9 msgid "Preview comment" -msgstr "ПроÑмотр комментариÑ" +msgstr "ПредпроÑмотр комментариÑ" #: contrib/comments/templates/comments/freeform.html:4 msgid "Your name:" -msgstr "Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ:" +msgstr "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ:" #: contrib/admin/filterspecs.py:40 #, python-format @@ -343,8 +352,11 @@ msgid "" "<h3>By %s:</h3>\n" "<ul>\n" msgstr "" +"<h3>По %s:</h3>\n" +"<ul>\n" -#: contrib/admin/filterspecs.py:70 contrib/admin/filterspecs.py:88 +#: contrib/admin/filterspecs.py:70 +#: contrib/admin/filterspecs.py:88 #: contrib/admin/filterspecs.py:143 msgid "All" msgstr "Ð’Ñе" @@ -383,7 +395,7 @@ msgstr "ÐеизвеÑтно" #: contrib/admin/models.py:16 msgid "action time" -msgstr "Ð²Ñ€ÐµÐ¼Ñ Ð´ÐµÐ¹ÑтвиÑ" +msgstr "Ð’Ñ€ÐµÐ¼Ñ Ð´ÐµÐ¹ÑтвиÑ" #: contrib/admin/models.py:19 msgid "object id" @@ -391,36 +403,33 @@ msgstr "id обьекта" #: contrib/admin/models.py:20 msgid "object repr" -msgstr "предÑтавление обьекта" +msgstr "ПредÑтавление обьекта" #: contrib/admin/models.py:21 msgid "action flag" -msgstr "отметка дейÑтвиÑ" +msgstr "Отметка дейÑтвиÑ" #: contrib/admin/models.py:22 msgid "change message" -msgstr "изменить Ñообщение" +msgstr "Изменить Ñообщение" #: contrib/admin/models.py:25 msgid "log entry" -msgstr "Ð¶ÑƒÑ€Ð½Ð°Ð»ÑŒÐ½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ" +msgstr "Ð–ÑƒÑ€Ð½Ð°Ð»ÑŒÐ½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ" #: contrib/admin/models.py:26 msgid "log entries" -msgstr "журнальные запиÑи" +msgstr "Журнальные запиÑи" #: contrib/admin/templatetags/admin_list.py:228 msgid "All dates" msgstr "Ð’Ñе даты" -#: contrib/admin/views/decorators.py:9 contrib/auth/forms.py:36 +#: contrib/admin/views/decorators.py:9 +#: contrib/auth/forms.py:36 #: contrib/auth/forms.py:41 -msgid "" -"Please enter a correct username and password. Note that both fields are case-" -"sensitive." -msgstr "" -"ПожалуйÑта, вводите верные данные Ð¸Ð¼ÐµÐ½Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸ пароль. Помните, оба " -"Ð¿Ð¾Ð»Ñ Ñ‡ÑƒÐ²Ñтвительны к региÑтру." +msgid "Please enter a correct username and password. Note that both fields are case-sensitive." +msgstr "ПожалуйÑта, введите верные Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸ пароль. Помните, оба Ð¿Ð¾Ð»Ñ Ñ‡ÑƒÐ²Ñтвительны к региÑтру." #: contrib/admin/views/decorators.py:23 #: contrib/admin/templates/admin/login.html:25 @@ -428,20 +437,12 @@ msgid "Log in" msgstr "Вход" #: contrib/admin/views/decorators.py:61 -msgid "" -"Please log in again, because your session has expired. Don't worry: Your " -"submission has been saved." -msgstr "" -"ПожалуйÑта войдите Ñнова, поÑколькук ваша ÑеÑÑÐ¸Ñ ÑƒÑтарела. Ðе беÑпокойтеÑÑŒ:" -"введенные вами данные Ñохранены." +msgid "Please log in again, because your session has expired. Don't worry: Your submission has been saved." +msgstr "ПожалуйÑта, войдите Ñнова, поÑкольку ваша ÑеÑÑÐ¸Ñ ÑƒÑтарела. Ðе беÑпокойтеÑÑŒ: введенные вами данные Ñохранены." #: contrib/admin/views/decorators.py:68 -msgid "" -"Looks like your browser isn't configured to accept cookies. Please enable " -"cookies, reload this page, and try again." -msgstr "" -"Похоже, что ваш броузер не наÑтроен на прием cookies. ПожалуйÑтва включите " -"cookie, перезагрузите Ñтраницу и попытайтеÑÑŒ Ñнова. " +msgid "Looks like your browser isn't configured to accept cookies. Please enable cookies, reload this page, and try again." +msgstr "Похоже, ваш броузер не наÑтроен на прием cookies. ПожалуйÑтва, включите cookie, перезагрузите Ñтраницу и попытайтеÑÑŒ Ñнова." #: contrib/admin/views/decorators.py:82 msgid "Usernames cannot contain the '@' character." @@ -450,7 +451,7 @@ msgstr "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð½Ðµ может включать ÑимР#: contrib/admin/views/decorators.py:84 #, python-format msgid "Your e-mail address is not your username. Try '%s' instead." -msgstr "" +msgstr "Ваш Ð°Ð´Ñ€ÐµÑ Ñлектронной почты не ÑвлÑетÑÑ Ð²Ð°ÑˆÐ¸Ð¼ именем пользователÑ. Попробуйте '%s' взамен." #: contrib/admin/views/main.py:226 msgid "Site administration" @@ -459,13 +460,15 @@ msgstr "ÐдминиÑтрирование Ñайта" #: contrib/admin/views/main.py:260 #, python-format msgid "The %(name)s \"%(obj)s\" was added successfully." -msgstr "%(name)s \"%(obj)s\" были уÑпешно добавлены." +msgstr "%(name)s \"%(obj)s\" был уÑпешно добавлен." -#: contrib/admin/views/main.py:264 contrib/admin/views/main.py:348 +#: contrib/admin/views/main.py:264 +#: contrib/admin/views/main.py:348 msgid "You may edit it again below." -msgstr "Ð’Ñ‹ Ñнова можете редактировать их внизу" +msgstr "Ðиже можно Ñнова редактировать его" -#: contrib/admin/views/main.py:272 contrib/admin/views/main.py:357 +#: contrib/admin/views/main.py:272 +#: contrib/admin/views/main.py:357 #, python-format msgid "You may add another %s below." msgstr "Ð’Ñ‹ можете добавить %s внизу." @@ -478,9 +481,10 @@ msgstr "Добавить %s" #: contrib/admin/views/main.py:336 #, python-format msgid "Added %s." -msgstr "Добавлено %s" +msgstr "Добавлен %s." -#: contrib/admin/views/main.py:336 contrib/admin/views/main.py:338 +#: contrib/admin/views/main.py:336 +#: contrib/admin/views/main.py:338 #: contrib/admin/views/main.py:340 msgid "and" msgstr "и" @@ -488,27 +492,26 @@ msgstr "и" #: contrib/admin/views/main.py:338 #, python-format msgid "Changed %s." -msgstr "Изменено %s." +msgstr "Изменен %s." #: contrib/admin/views/main.py:340 #, python-format msgid "Deleted %s." -msgstr "Удалено %s." +msgstr "Удален %s." #: contrib/admin/views/main.py:343 msgid "No fields changed." -msgstr "" +msgstr "Ðи одно поле не изменено." #: contrib/admin/views/main.py:346 #, python-format msgid "The %(name)s \"%(obj)s\" was changed successfully." -msgstr "" +msgstr "%(name)s \"%(obj)s\" был уÑпешно изменен." #: contrib/admin/views/main.py:354 #, python-format -msgid "" -"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below." -msgstr "" +msgid "The %(name)s \"%(obj)s\" was added successfully. You may edit it again below." +msgstr "%(name)s \"%(obj)s\" был уÑпешно добавлен. Ðиже можно Ñнова редактировать его." #: contrib/admin/views/main.py:392 #, python-format @@ -518,17 +521,17 @@ msgstr "Изменить %s" #: contrib/admin/views/main.py:470 #, python-format msgid "One or more %(fieldname)s in %(name)s: %(obj)s" -msgstr "Одно или более %(fieldname)s в %(name)s: %(obj)s" +msgstr "Один или более %(fieldname)s в %(name)s: %(obj)s" #: contrib/admin/views/main.py:475 #, python-format msgid "One or more %(fieldname)s in %(name)s:" -msgstr "Одно или более %(fieldname)s в %(name)s:" +msgstr "Один или более %(fieldname)s в %(name)s:" #: contrib/admin/views/main.py:508 #, python-format msgid "The %(name)s \"%(obj)s\" was deleted successfully." -msgstr "%(name)s \"%(obj)s\" было уÑпешно удалено." +msgstr "%(name)s \"%(obj)s\" был уÑпешно удален." #: contrib/admin/views/main.py:511 msgid "Are you sure?" @@ -537,7 +540,7 @@ msgstr "Ð’Ñ‹ уверены?" #: contrib/admin/views/main.py:533 #, python-format msgid "Change history: %s" -msgstr "Измени иÑторию: %s" +msgstr "ИÑÑ‚Ð¾Ñ€Ð¸Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ð¹: %s" #: contrib/admin/views/main.py:565 #, python-format @@ -549,9 +552,12 @@ msgstr "Выберите %s" msgid "Select %s to change" msgstr "Выберите %s Ð´Ð»Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ" -#: contrib/admin/views/doc.py:277 contrib/admin/views/doc.py:286 -#: contrib/admin/views/doc.py:288 contrib/admin/views/doc.py:294 -#: contrib/admin/views/doc.py:295 contrib/admin/views/doc.py:297 +#: contrib/admin/views/doc.py:277 +#: contrib/admin/views/doc.py:286 +#: contrib/admin/views/doc.py:288 +#: contrib/admin/views/doc.py:294 +#: contrib/admin/views/doc.py:295 +#: contrib/admin/views/doc.py:297 msgid "Integer" msgstr "Целое" @@ -559,7 +565,8 @@ msgstr "Целое" msgid "Boolean (Either True or False)" msgstr "ЛогичеÑкое (True или False)" -#: contrib/admin/views/doc.py:279 contrib/admin/views/doc.py:296 +#: contrib/admin/views/doc.py:279 +#: contrib/admin/views/doc.py:296 #, python-format msgid "String (up to %(maxlength)s)" msgstr "Строка (до %(maxlength)s Ñимволов)" @@ -578,9 +585,10 @@ msgstr "Дата (Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð¸ÐµÐ¼ времени)" #: contrib/admin/views/doc.py:283 msgid "E-mail address" -msgstr "E-mail адреÑ" +msgstr "ÐÐ´Ñ€ÐµÑ Ñлектронной почты" -#: contrib/admin/views/doc.py:284 contrib/admin/views/doc.py:287 +#: contrib/admin/views/doc.py:284 +#: contrib/admin/views/doc.py:287 msgid "File path" msgstr "Путь к файлу" @@ -594,7 +602,7 @@ msgstr "ЛогичеÑкое (True, False или None)" #: contrib/admin/views/doc.py:292 msgid "Relation to parent model" -msgstr "" +msgstr "СвÑзь Ñ Ñ€Ð¾Ð´Ð¸Ñ‚ÐµÐ»ÑŒÑкой моделью" #: contrib/admin/views/doc.py:293 msgid "Phone number" @@ -608,17 +616,18 @@ msgstr "ТекÑÑ‚" msgid "Time" msgstr "ВремÑ" -#: contrib/admin/views/doc.py:300 contrib/flatpages/models.py:7 +#: contrib/admin/views/doc.py:300 +#: contrib/flatpages/models.py:7 msgid "URL" msgstr "URL" #: contrib/admin/views/doc.py:301 msgid "U.S. state (two uppercase letters)" -msgstr "Штат СШР(два заглавных Ñимвола)" +msgstr "Штат СШР(две заглавные буквы)" #: contrib/admin/views/doc.py:302 msgid "XML text" -msgstr "XML текÑÑ‚" +msgstr "ТекÑÑ‚ XML" #: contrib/admin/templates/admin/object_history.html:3 #: contrib/admin/templates/admin/change_list.html:5 @@ -685,15 +694,11 @@ msgstr "ДейÑтвие" #: contrib/admin/templates/admin/object_history.html:26 msgid "DATE_WITH_TIME_FULL" -msgstr "j. N Y, H:i" +msgstr "j N Y H:i" #: contrib/admin/templates/admin/object_history.html:36 -msgid "" -"This object doesn't have a change history. It probably wasn't added via this " -"admin site." -msgstr "" -"Данный обьект не имеет иÑтории изменениÑ. Возможно он не был добавлен через " -"данный админиÑтративный Ñайт." +msgid "This object doesn't have a change history. It probably wasn't added via this admin site." +msgstr "Данный обьект не имеет иÑтории изменений. Возможно, он был добавлен не через данный админиÑтративный Ñайт." #: contrib/admin/templates/admin/base_site.html:4 msgid "Django site admin" @@ -716,12 +721,8 @@ msgid "Server Error <em>(500)</em>" msgstr "Ошибка Ñервера <em>(500)</em>" #: contrib/admin/templates/admin/500.html:10 -msgid "" -"There's been an error. It's been reported to the site administrators via e-" -"mail and should be fixed shortly. Thanks for your patience." -msgstr "" -"Произошла ошибка. Отчет об ошибке отправлен админиÑтраторам Ñайта по e-mailи " -"она должна быть вÑкоре иÑправлена. Благодарим Ð²Ð°Ñ Ð½Ð° терпение и помощь." +msgid "There's been an error. It's been reported to the site administrators via e-mail and should be fixed shortly. Thanks for your patience." +msgstr "Произошла ошибка. Отчет об ошибке отправлен админиÑтраторам Ñайта по Ñлектронной почте, ошибка должна быть вÑкоре иÑправлена. Благодарим Ð²Ð°Ñ Ð½Ð° терпение и помощь." #: contrib/admin/templates/admin/404.html:4 #: contrib/admin/templates/admin/404.html:8 @@ -735,7 +736,7 @@ msgstr "К Ñожалению, Ð·Ð°Ð¿Ñ€Ð°ÑˆÐ¸Ð²Ð°ÐµÐ¼Ð°Ñ Ð²Ð°Ð¼Ð¸ ÑÑ‚Ñ€Ð°Ð½Ð¸Ñ #: contrib/admin/templates/admin/index.html:17 #, python-format msgid "Models available in the %(name)s application." -msgstr "Модели доÑтупны в %(name)s приложении." +msgstr "Модели доÑтупны в приложении %(name)s." #: contrib/admin/templates/admin/index.html:28 #: contrib/admin/templates/admin/change_form.html:15 @@ -752,11 +753,11 @@ msgstr "ÐедоÑтаточно прав Ð´Ð»Ñ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ." #: contrib/admin/templates/admin/index.html:52 msgid "Recent Actions" -msgstr "ПоÑледние ДейÑтвиÑ" +msgstr "ПоÑледние дейÑтвиÑ" #: contrib/admin/templates/admin/index.html:53 msgid "My Actions" -msgstr "Мои ДейÑтвиÑ" +msgstr "Мои дейÑтвиÑ" #: contrib/admin/templates/admin/index.html:57 msgid "None available" @@ -782,23 +783,13 @@ msgstr "Удалить" #: contrib/admin/templates/admin/delete_confirmation.html:14 #, python-format -msgid "" -"Deleting the %(object_name)s '%(object)s' would result in deleting related " -"objects, but your account doesn't have permission to delete the following " -"types of objects:" -msgstr "" -"Удаление объекта %(object_name)s '%(object)s' приведет к удалению завиÑимых " -"Ñлементов, но предоÑтавленных вам прав недоÑтаточно Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ñледующих " -"типов объектов:" +msgid "Deleting the %(object_name)s '%(object)s' would result in deleting related objects, but your account doesn't have permission to delete the following types of objects:" +msgstr "Удаление объекта %(object_name)s '%(object)s' привело бы к удалению ÑвÑзанных Ñлементов, но предоÑтавленных вам прав недоÑтаточно Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ñледующих типов объектов:" #: contrib/admin/templates/admin/delete_confirmation.html:21 #, python-format -msgid "" -"Are you sure you want to delete the %(object_name)s \"%(object)s\"? All of " -"the following related items will be deleted:" -msgstr "" -"Ð’Ñ‹ уверены, что хотите удалить %(object_name)s \"%(object)s\"? Ð’Ñе " -"Ñледующие объекты также будут удалены:" +msgid "Are you sure you want to delete the %(object_name)s \"%(object)s\"? All of the following related items will be deleted:" +msgstr "Ð’Ñ‹ уверены, что хотите удалить %(object_name)s \"%(object)s\"? Ð’Ñе Ñледующие ÑвÑзанные объекты также будут удалены:" #: contrib/admin/templates/admin/delete_confirmation.html:26 msgid "Yes, I'm sure" @@ -807,12 +798,24 @@ msgstr "Да, Ñ ÑƒÐ²ÐµÑ€ÐµÐ½" #: contrib/admin/templates/admin/filter.html:2 #, python-format msgid " By %(title)s " -msgstr "" +msgstr " По %(title)s " #: contrib/admin/templates/admin/search_form.html:8 msgid "Go" msgstr "Вперёд" +#: contrib/admin/templates/admin/search_form.html:10 +#, python-format +msgid "1 result" +msgid_plural "%(counter)s results" +msgstr[0] "1 результат" +msgstr[1] "%(counter)s результата" +msgstr[2] "%(counter)s результатов" + +#: contrib/admin/templates/admin/search_form.html:10 +msgid "%(full_result_count)s total" +msgstr "%(full_result_count)s вÑего" + #: contrib/admin/templates/admin/change_form.html:21 msgid "View on site" msgstr "Смотреть Ñайт" @@ -820,8 +823,9 @@ msgstr "Смотреть Ñайт" #: contrib/admin/templates/admin/change_form.html:30 msgid "Please correct the error below." msgid_plural "Please correct the errors below." -msgstr[0] "ПожалуйÑта иÑправьте ошибку ниже." -msgstr[1] "ПожалуйÑта иÑправьте ошибки ниже." +msgstr[0] "ПожалуйÑта, иÑправьте ошибку ниже." +msgstr[1] "ПожалуйÑта, иÑправьте ошибки ниже." +msgstr[2] "ПожалуйÑта, иÑправьте ошибки ниже." #: contrib/admin/templates/admin/change_form.html:48 msgid "Ordering" @@ -871,16 +875,12 @@ msgid "Password reset" msgstr "Ð¡Ð±Ñ€Ð¾Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ" #: contrib/admin/templates/registration/password_reset_form.html:12 -msgid "" -"Forgotten your password? Enter your e-mail address below, and we'll reset " -"your password and e-mail the new one to you." -msgstr "" -"Забыли пароль? Введите ваш e-mail Ð°Ð´Ñ€ÐµÑ Ð½Ð¸Ð¶Ðµ и мы очиÑтим ваш Ñтарый пароль, " -"и вышлем вам по e-mail новый." +msgid "Forgotten your password? Enter your e-mail address below, and we'll reset your password and e-mail the new one to you." +msgstr "Забыли пароль? Введите Ñвой Ð°Ð´Ñ€ÐµÑ Ñлектронной почты ниже, мы очиÑтим ваш Ñтарый пароль и вышлем вам по e-mail новый." #: contrib/admin/templates/registration/password_reset_form.html:16 msgid "E-mail address:" -msgstr "E-mail адреÑ:" +msgstr "ÐÐ´Ñ€ÐµÑ Ñлектронной почты:" #: contrib/admin/templates/registration/password_reset_form.html:16 msgid "Reset my password" @@ -900,20 +900,12 @@ msgid "Password reset successful" msgstr "УÑÐ¿ÐµÑˆÐ½Ð°Ñ Ð¾Ñ‡Ð¸Ñтка паролÑ" #: contrib/admin/templates/registration/password_reset_done.html:12 -msgid "" -"We've e-mailed a new password to the e-mail address you submitted. You " -"should be receiving it shortly." -msgstr "" -"Мы отправили новый пароль по указанному вами адреÑу Ñлектронной почты. Ð’Ñ‹ " -"должны его вÑкоре получить." +msgid "We've e-mailed a new password to the e-mail address you submitted. You should be receiving it shortly." +msgstr "Мы отправили новый пароль по указанному вами адреÑу Ñлектронной почты. Ð’Ñкоре вы его получите." #: contrib/admin/templates/registration/password_change_form.html:12 -msgid "" -"Please enter your old password, for security's sake, and then enter your new " -"password twice so we can verify you typed it in correctly." -msgstr "" -"Ð’ целÑÑ… безопаÑноÑти, пожалуйÑта, введите ваш Ñтарый пароль, затем - новый " -"пароль дважды, Ñ Ñ‚ÐµÐ¼, чтобы мы могли убедитьÑÑ Ð² правильноÑти напиÑаниÑ." +msgid "Please enter your old password, for security's sake, and then enter your new password twice so we can verify you typed it in correctly." +msgstr "Ð’ целÑÑ… безопаÑноÑти, пожалуйÑта, введите Ñвой Ñтарый пароль, затем - новый пароль дважды, Ñ Ñ‚ÐµÐ¼, чтобы мы могли убедитьÑÑ Ð² правильноÑти напиÑаниÑ." #: contrib/admin/templates/registration/password_change_form.html:17 msgid "Old password:" @@ -933,12 +925,12 @@ msgstr "Изменение паролÑ" #: contrib/admin/templates/registration/password_reset_email.html:2 msgid "You're receiving this e-mail because you requested a password reset" -msgstr "Ð’Ñ‹ получили Ñто Ñообщение потому что была запрошена очиÑтка паролÑ" +msgstr "Ð’Ñ‹ получили Ñто Ñообщение, потому что была запрошена очиÑтка паролÑ" #: contrib/admin/templates/registration/password_reset_email.html:3 #, python-format msgid "for your user account at %(site_name)s" -msgstr "Ð´Ð»Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ пользовательÑкого аккаунта на %(site_name)s" +msgstr "Ð”Ð»Ñ Ð²Ð°ÑˆÐµÐ¹ учетной запиÑи на %(site_name)s" #: contrib/admin/templates/registration/password_reset_email.html:5 #, python-format @@ -947,7 +939,7 @@ msgstr "Ваш новый пароль: %(new_password)s" #: contrib/admin/templates/registration/password_reset_email.html:7 msgid "Feel free to change this password by going to this page:" -msgstr "Ð’Ñ‹ вÑегда можете изменить Ñтот пароль Ð¿ÐµÑ€ÐµÐ¹Ð´Ñ Ð½Ð° Ñтраницу:" +msgstr "Ð’Ñ‹ вÑегда можете изменить Ñтот пароль, Ð¿ÐµÑ€ÐµÐ¹Ð´Ñ Ð½Ð° Ñтраницу:" #: contrib/admin/templates/registration/password_reset_email.html:11 msgid "Your username, in case you've forgotten:" @@ -968,7 +960,7 @@ msgstr "Закладки" #: contrib/admin/templates/admin_doc/bookmarklets.html:5 msgid "Documentation bookmarklets" -msgstr "Ð”Ð¾ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ Ð¿Ð¾ bookmarklets" +msgstr "Закладки документации" #: contrib/admin/templates/admin_doc/bookmarklets.html:9 msgid "" @@ -980,30 +972,29 @@ msgid "" "as \"internal\" (talk to your system administrator if you aren't sure if\n" "your computer is \"internal\").</p>\n" msgstr "" +"\n" +"<p class=\"help\">Ð”Ð»Ñ ÑƒÑтановки закладок перетащите ÑÑылку к Ñебе на панель\n" +"закладок или щелкните правой кнопкой мыши по ÑÑылке и добавьте ее в закладки. Теперь у Ð²Ð°Ñ ÐµÑть возможноÑть\n" +"выбрать закладку Ñ Ð»ÑŽÐ±Ð¾Ð¹ Ñтраницы Ñайта. Обратите внимание: некоторые из Ñтих\n" +"закладок требуют, чтобы вы проÑматривали Ñайт Ñ ÐºÐ¾Ð¼Ð¿ÑŒÑŽÑ‚ÐµÑ€Ð°, определенного\n" +"как \"внутренний\" (уточните у Ñвоего ÑиÑтемного админиÑтратора, еÑли не уверены, ÑвлÑетÑÑ Ð»Ð¸\n" +"ваш компьютер \"внутренним\").</p>\n" #: contrib/admin/templates/admin_doc/bookmarklets.html:19 msgid "Documentation for this page" msgstr "Ð”Ð¾ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ Ð¿Ð¾ данной Ñтранице" #: contrib/admin/templates/admin_doc/bookmarklets.html:20 -msgid "" -"Jumps you from any page to the documentation for the view that generates " -"that page." -msgstr "" -"Перенаправит Ð²Ð°Ñ Ñ Ð»ÑŽÐ±Ð¾Ð¹ Ñтраницы к проÑмотру документа, который генерирует " -"Ñту Ñтраницу." +msgid "Jumps you from any page to the documentation for the view that generates that page." +msgstr "ПеренаправлÑет Ð²Ð°Ñ Ñ Ð»ÑŽÐ±Ð¾Ð¹ Ñтраницы к документации view, который генерирует Ñту Ñтраницу." #: contrib/admin/templates/admin_doc/bookmarklets.html:22 msgid "Show object ID" msgstr "Показать ID обьекта" #: contrib/admin/templates/admin_doc/bookmarklets.html:23 -msgid "" -"Shows the content-type and unique ID for pages that represent a single " -"object." -msgstr "" -"Показывает тип Ð½Ð°Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð¸ уникальный ID Ð´Ð»Ñ Ñтраниц, которые означают " -"одинокий объект." +msgid "Shows the content-type and unique ID for pages that represent a single object." +msgstr "Показывает тип Ð½Ð°Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð¸ уникальный ID Ð´Ð»Ñ Ñтраниц, предÑтавлÑющих один объект." #: contrib/admin/templates/admin_doc/bookmarklets.html:25 msgid "Edit this object (current window)" @@ -1011,7 +1002,7 @@ msgstr "Редактировать данный обьект (в текущем #: contrib/admin/templates/admin_doc/bookmarklets.html:26 msgid "Jumps to the admin page for pages that represent a single object." -msgstr "Перейти на Ñтраницу админиÑтратор Ð´Ð»Ñ Ñтраниц предÑтавлÑющих один объект." +msgstr "Перейдет на админиÑтративную Ñтраницу Ð´Ð»Ñ Ñтраниц, предÑтавлÑющих один объект." #: contrib/admin/templates/admin_doc/bookmarklets.html:28 msgid "Edit this object (new window)" @@ -1019,7 +1010,7 @@ msgstr "Редактировать данный обьект (в новом ок #: contrib/admin/templates/admin_doc/bookmarklets.html:29 msgid "As above, but opens the admin page in a new window." -msgstr "То же что и выше, но откроет админиÑтративную Ñтраницу в новом окне" +msgstr "То же что и выше, но откроет админиÑтративную Ñтраницу в новом окне." #: contrib/admin/templates/widget/date_time.html:3 msgid "Date:" @@ -1039,67 +1030,55 @@ msgstr "Изменить:" #: contrib/redirects/models.py:7 msgid "redirect from" -msgstr "перенаправить из" +msgstr "Перенаправить из" #: contrib/redirects/models.py:8 -msgid "" -"This should be an absolute path, excluding the domain name. Example: '/" -"events/search/'." -msgstr "" -"Ðто должен быть абÑолютный путь, иÑÐºÐ»ÑŽÑ‡Ð°Ñ Ð´Ð¾Ð¼ÐµÐ½Ð½Ð¾Ðµ имÑ. Пример: '/events/" -"search/'." +msgid "This should be an absolute path, excluding the domain name. Example: '/events/search/'." +msgstr "Ðто должен быть абÑолютный путь без доменного имени. Пример: '/events/search/'." #: contrib/redirects/models.py:9 msgid "redirect to" -msgstr "перенаправить на" +msgstr "Перенаправить на" #: contrib/redirects/models.py:10 -msgid "" -"This can be either an absolute path (as above) or a full URL starting with " -"'http://'." -msgstr "" -"Ðто должен быть, либо абÑолютный путь (как выше) или полный URL начинающийÑÑ " -"Ñ 'http://'." +msgid "This can be either an absolute path (as above) or a full URL starting with 'http://'." +msgstr "Ðто должен быть абÑолютный путь (как выше) или полный URL, начинающийÑÑ Ñ 'http://'." #: contrib/redirects/models.py:12 msgid "redirect" -msgstr "перенаправить" +msgstr "Перенаправление" #: contrib/redirects/models.py:13 msgid "redirects" -msgstr "перенаправлениÑ" +msgstr "ПеренаправлениÑ" #: contrib/flatpages/models.py:8 -msgid "" -"Example: '/about/contact/'. Make sure to have leading and trailing slashes." -msgstr "" -"Пример: '/about/contact/'. Будьте уверенны, что вÑтавили завепршающий ÑлÑш." +msgid "Example: '/about/contact/'. Make sure to have leading and trailing slashes." +msgstr "Пример: '/about/contact/'. Будьте уверенны, что вÑтавили завепршающий ÑлÑш." #: contrib/flatpages/models.py:9 msgid "title" -msgstr "заголовок" +msgstr "Заголовок" #: contrib/flatpages/models.py:10 msgid "content" -msgstr "наполнение" +msgstr "Содержимое" #: contrib/flatpages/models.py:11 msgid "enable comments" -msgstr "активировать комментарии" +msgstr "Ðктивировать комментарии" #: contrib/flatpages/models.py:12 msgid "template name" -msgstr "Ð¸Ð¼Ñ ÑˆÐ°Ð±Ð»Ð¾Ð½Ð°" +msgstr "Ð˜Ð¼Ñ ÑˆÐ°Ð±Ð»Ð¾Ð½Ð°" #: contrib/flatpages/models.py:13 -msgid "" -"Example: 'flatpages/contact_page'. If this isn't provided, the system will " -"use 'flatpages/default'." -msgstr "" +msgid "Example: 'flatpages/contact_page'. If this isn't provided, the system will use 'flatpages/default'." +msgstr "Пример: 'flatpages/contact_page'. ЕÑли Ñтот файл не приÑутÑтвует, ÑиÑтема будет иÑпользовать 'flatpages/default'." #: contrib/flatpages/models.py:14 msgid "registration required" -msgstr "региÑÑ‚Ñ€Ð°Ñ†Ð¸Ñ Ð¾Ð±Ñзательна" +msgstr "РегиÑÑ‚Ñ€Ð°Ñ†Ð¸Ñ Ð¾Ð±Ñзательна" #: contrib/flatpages/models.py:14 msgid "If this is checked, only logged-in users will be able to view the page." @@ -1107,25 +1086,27 @@ msgstr "ЕÑли отмечено, только вошедшие пользовР#: contrib/flatpages/models.py:18 msgid "flat page" -msgstr "проÑÑ‚Ð°Ñ Ñтраница" +msgstr "ПроÑÑ‚Ð°Ñ Ñтраница" #: contrib/flatpages/models.py:19 msgid "flat pages" -msgstr "проÑтые Ñтраницы" +msgstr "ПроÑтые Ñтраницы" -#: contrib/auth/models.py:13 contrib/auth/models.py:26 +#: contrib/auth/models.py:13 +#: contrib/auth/models.py:26 msgid "name" -msgstr "имÑ" +msgstr "ИмÑ" #: contrib/auth/models.py:15 msgid "codename" -msgstr "код" +msgstr "Кодовое название" #: contrib/auth/models.py:17 msgid "permission" -msgstr "Права" +msgstr "Право" -#: contrib/auth/models.py:18 contrib/auth/models.py:27 +#: contrib/auth/models.py:18 +#: contrib/auth/models.py:27 msgid "permissions" msgstr "Права" @@ -1133,37 +1114,38 @@ msgstr "Права" msgid "group" msgstr "Группа" -#: contrib/auth/models.py:30 contrib/auth/models.py:65 +#: contrib/auth/models.py:30 +#: contrib/auth/models.py:65 msgid "groups" msgstr "Группы" #: contrib/auth/models.py:55 msgid "username" -msgstr "Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ" +msgstr "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ" #: contrib/auth/models.py:56 msgid "first name" -msgstr "имÑ" +msgstr "ИмÑ" #: contrib/auth/models.py:57 msgid "last name" -msgstr "фамилиÑ" +msgstr "ФамилиÑ" #: contrib/auth/models.py:58 msgid "e-mail address" -msgstr "e-mail адреÑ" +msgstr "ÐÐ´Ñ€ÐµÑ Ñлектронной почты" #: contrib/auth/models.py:59 msgid "password" -msgstr "пароль" +msgstr "Пароль" #: contrib/auth/models.py:59 msgid "Use '[algo]$[salt]$[hexdigest]'" -msgstr "" +msgstr "ИÑпользуйте '[algo]$[salt]$[hexdigest]'" #: contrib/auth/models.py:60 msgid "staff status" -msgstr "ÑÑ‚Ð°Ñ‚ÑƒÑ Ð¿ÐµÑ€Ñонала" +msgstr "Ð¡Ñ‚Ð°Ñ‚ÑƒÑ Ð¿ÐµÑ€Ñонала" #: contrib/auth/models.py:60 msgid "Designates whether the user can log into this admin site." @@ -1171,31 +1153,27 @@ msgstr "Отметьте, еÑли пользователь может входР#: contrib/auth/models.py:61 msgid "active" -msgstr "активен" +msgstr "Ðктивный" #: contrib/auth/models.py:62 msgid "superuser status" -msgstr "ÑÑ‚Ð°Ñ‚ÑƒÑ Ð°Ð´Ð¼Ð¸Ð½Ð°" +msgstr "Ð¡Ñ‚Ð°Ñ‚ÑƒÑ ÑуперпользователÑ" #: contrib/auth/models.py:63 msgid "last login" -msgstr "поÑледний вход" +msgstr "ПоÑледний вход" #: contrib/auth/models.py:64 msgid "date joined" -msgstr "дата региÑтрации" +msgstr "Дата региÑтрации" #: contrib/auth/models.py:66 -msgid "" -"In addition to the permissions manually assigned, this user will also get " -"all permissions granted to each group he/she is in." -msgstr "" -"К добавлению к перавам выбрнанным вуручную, Ñтот пользователь может получить " -"вÑе права группы, к которой он принадлежит." +msgid "In addition to the permissions manually assigned, this user will also get all permissions granted to each group he/she is in." +msgstr "Ð’ добавление к правам, приÑвоенным вручную, Ñтот пользователь получит вÑе права групп, к которым он принадлежит." #: contrib/auth/models.py:67 msgid "user permissions" -msgstr "Права пользователÑ" +msgstr "права пользователÑ" #: contrib/auth/models.py:70 msgid "user" @@ -1226,10 +1204,8 @@ msgid "message" msgstr "Сообщение" #: contrib/auth/forms.py:30 -msgid "" -"Your Web browser doesn't appear to have cookies enabled. Cookies are " -"required for logging in." -msgstr "" +msgid "Your Web browser doesn't appear to have cookies enabled. Cookies are required for logging in." +msgstr "У вашего браузера не включены cookies. Cookies необходимы Ð´Ð»Ñ Ð²Ñ…Ð¾Ð´Ð°." #: contrib/contenttypes/models.py:25 msgid "python model class name" @@ -1237,59 +1213,59 @@ msgstr "Ð¸Ð¼Ñ ÐºÐ»Ð°ÑÑа python модулÑ" #: contrib/contenttypes/models.py:28 msgid "content type" -msgstr "тип наполнениÑ" +msgstr "Тип Ñодержимого" #: contrib/contenttypes/models.py:29 msgid "content types" -msgstr "типы наполнениÑ" +msgstr "Типы Ñодержимого" #: contrib/sessions/models.py:35 msgid "session key" -msgstr "ключ ÑеÑÑии" +msgstr "Ключ ÑеÑÑии" #: contrib/sessions/models.py:36 msgid "session data" -msgstr "данные ÑеÑÑии" +msgstr "Данные ÑеÑÑии" #: contrib/sessions/models.py:37 msgid "expire date" -msgstr "дата окончаниÑ" +msgstr "Дата окончаниÑ" #: contrib/sessions/models.py:41 msgid "session" -msgstr "ÑеÑÑиÑ" +msgstr "СеÑÑиÑ" #: contrib/sessions/models.py:42 msgid "sessions" -msgstr "ÑеÑÑии" +msgstr "СеÑÑии" #: contrib/sites/models.py:10 msgid "domain name" -msgstr "домен" +msgstr "Доменное имÑ" #: contrib/sites/models.py:11 msgid "display name" -msgstr "выводимое имÑ" +msgstr "Выводимое имÑ" #: contrib/sites/models.py:15 msgid "site" -msgstr "Ñайт" +msgstr "Сайт" #: contrib/sites/models.py:16 msgid "sites" -msgstr "Ñайты" +msgstr "Сайты" #: utils/translation.py:360 msgid "DATE_FORMAT" -msgstr "" +msgstr "d.m.Y" #: utils/translation.py:361 msgid "DATETIME_FORMAT" -msgstr "" +msgstr "d.m.Y H:i" #: utils/translation.py:362 msgid "TIME_FORMAT" -msgstr "" +msgstr "H:i" #: utils/dates.py:6 msgid "Monday" @@ -1327,23 +1303,28 @@ msgstr "Январь" msgid "February" msgstr "Февраль" -#: utils/dates.py:14 utils/dates.py:27 +#: utils/dates.py:14 +#: utils/dates.py:27 msgid "March" msgstr "Март" -#: utils/dates.py:14 utils/dates.py:27 +#: utils/dates.py:14 +#: utils/dates.py:27 msgid "April" msgstr "Ðпрель" -#: utils/dates.py:14 utils/dates.py:27 +#: utils/dates.py:14 +#: utils/dates.py:27 msgid "May" msgstr "Май" -#: utils/dates.py:14 utils/dates.py:27 +#: utils/dates.py:14 +#: utils/dates.py:27 msgid "June" msgstr "Июнь" -#: utils/dates.py:15 utils/dates.py:27 +#: utils/dates.py:15 +#: utils/dates.py:27 msgid "July" msgstr "Июль" @@ -1357,7 +1338,7 @@ msgstr "СентÑбрь" #: utils/dates.py:15 msgid "October" -msgstr "ОÑÑ‚Ñбрь" +msgstr "ОктÑбрь" #: utils/dates.py:15 msgid "November" @@ -1417,143 +1398,149 @@ msgstr "дек" #: utils/dates.py:27 msgid "Jan." -msgstr "Янв." +msgstr "Ñнв." #: utils/dates.py:27 msgid "Feb." -msgstr "Фев." +msgstr "фев." #: utils/dates.py:28 msgid "Aug." -msgstr "Ðвг." +msgstr "авг." #: utils/dates.py:28 msgid "Sept." -msgstr "Сен." +msgstr "Ñен." #: utils/dates.py:28 msgid "Oct." -msgstr "Окт." +msgstr "окт." #: utils/dates.py:28 msgid "Nov." -msgstr "ÐоÑб." +msgstr "ноÑб." #: utils/dates.py:28 msgid "Dec." -msgstr "Дек." +msgstr "дек." #: utils/timesince.py:12 msgid "year" msgid_plural "years" msgstr[0] "год" -msgstr[1] "лет" +msgstr[1] "года" +msgstr[2] "лет" #: utils/timesince.py:13 msgid "month" msgid_plural "months" msgstr[0] "меÑÑц" -msgstr[1] "меÑÑцев" +msgstr[1] "меÑÑца" +msgstr[2] "меÑÑцев" #: utils/timesince.py:14 msgid "week" msgid_plural "weeks" msgstr[0] "неделÑ" -msgstr[1] "недель" +msgstr[1] "недели" +msgstr[2] "недель" #: utils/timesince.py:15 msgid "day" msgid_plural "days" msgstr[0] "день" -msgstr[1] "дней" +msgstr[1] "днÑ" +msgstr[2] "дней" #: utils/timesince.py:16 msgid "hour" msgid_plural "hours" msgstr[0] "чаÑ" -msgstr[1] "чаÑов" +msgstr[1] "чаÑа" +msgstr[2] "чаÑов" #: utils/timesince.py:17 msgid "minute" msgid_plural "minutes" msgstr[0] "минута" -msgstr[1] "минут" +msgstr[1] "минуты" +msgstr[2] "минут" #: conf/global_settings.py:37 msgid "Bengali" -msgstr "" +msgstr "БенгальÑкий" #: conf/global_settings.py:38 msgid "Czech" -msgstr "" +msgstr "ЧешÑкий" #: conf/global_settings.py:39 msgid "Welsh" -msgstr "" +msgstr "УÑльÑкий" #: conf/global_settings.py:40 msgid "Danish" -msgstr "" +msgstr "ДатÑкий" #: conf/global_settings.py:41 msgid "German" -msgstr "" +msgstr "Ðемецкий" #: conf/global_settings.py:42 msgid "Greek" -msgstr "" +msgstr "ГречеÑкий" #: conf/global_settings.py:43 msgid "English" -msgstr "" +msgstr "ÐнглийÑкий" #: conf/global_settings.py:44 msgid "Spanish" -msgstr "" +msgstr "ИÑпанÑкий" #: conf/global_settings.py:45 msgid "French" -msgstr "" +msgstr "ФранцузÑкий" #: conf/global_settings.py:46 msgid "Galician" -msgstr "" +msgstr "ГалльÑкий" #: conf/global_settings.py:47 msgid "Hungarian" -msgstr "" +msgstr "ВенгерÑкий" #: conf/global_settings.py:48 msgid "Hebrew" -msgstr "" +msgstr "Иврит" #: conf/global_settings.py:49 msgid "Icelandic" -msgstr "" +msgstr "ИÑландÑкий" #: conf/global_settings.py:50 msgid "Italian" -msgstr "" +msgstr "ИтальÑнÑкий" #: conf/global_settings.py:51 msgid "Japanese" -msgstr "" +msgstr "ЯпонÑкий" #: conf/global_settings.py:52 msgid "Dutch" -msgstr "" +msgstr "ГолландÑкий" #: conf/global_settings.py:53 msgid "Norwegian" -msgstr "" +msgstr "ÐорвежÑкий" #: conf/global_settings.py:54 msgid "Brazilian" -msgstr "" +msgstr "БразильÑкий" #: conf/global_settings.py:55 msgid "Romanian" -msgstr "" +msgstr "РумынÑкий" #: conf/global_settings.py:56 msgid "Russian" @@ -1561,106 +1548,100 @@ msgstr "РуÑÑкий" #: conf/global_settings.py:57 msgid "Slovak" -msgstr "" +msgstr "Словацкий" #: conf/global_settings.py:58 msgid "Slovenian" -msgstr "" +msgstr "СловенÑкий" #: conf/global_settings.py:59 msgid "Serbian" -msgstr "" +msgstr "СербÑкий" #: conf/global_settings.py:60 msgid "Swedish" -msgstr "" +msgstr "ШведÑкий" #: conf/global_settings.py:61 msgid "Ukrainian" -msgstr "" +msgstr "УкраинÑкий" #: conf/global_settings.py:62 msgid "Simplified Chinese" -msgstr "" +msgstr "Упрощенный китайÑкий" #: conf/global_settings.py:63 msgid "Traditional Chinese" -msgstr "" +msgstr "Традиционный китайÑкий" #: core/validators.py:60 msgid "This value must contain only letters, numbers and underscores." -msgstr "Значение может Ñодержать только буквы, цифры и подчеркиваниÑ." +msgstr "Значение должно ÑоÑтоÑть только из букв, цифр и знаков подчеркиваниÑ." #: core/validators.py:64 -msgid "" -"This value must contain only letters, numbers, underscores, dashes or " -"slashes." -msgstr "Значение может Ñодержать только буквы, цифры, подчеркиваниÑ, дифиÑÑ‹ или " -"тере." +msgid "This value must contain only letters, numbers, underscores, dashes or slashes." +msgstr "Значение должно ÑоÑтоÑть только из букв, цифр, знаков подчеркиваниÑ, тире или наклонной черты вправо." #: core/validators.py:72 msgid "Uppercase letters are not allowed here." -msgstr "Заглавные буквы не разрешены" +msgstr "Заглавные буквы недопуÑтимы." #: core/validators.py:76 msgid "Lowercase letters are not allowed here." -msgstr "Строчные буквы не разрешены" +msgstr "Строчные буквы здеÑÑŒ недопуÑтимы." #: core/validators.py:83 msgid "Enter only digits separated by commas." -msgstr "Вводите только цифры разделённые запÑтыми" +msgstr "Введите цифры, разделённые запÑтыми." #: core/validators.py:95 msgid "Enter valid e-mail addresses separated by commas." -msgstr "Вводите реальные e-mail адреÑа разделённые запÑтыми" +msgstr "Введите правильные адреÑа Ñлектронной почты, разделённые запÑтыми." #: core/validators.py:99 msgid "Please enter a valid IP address." -msgstr "ПожалуйÑта, вводите реальный IP адреÑ" +msgstr "ПожалуйÑта, введите правильный IP-адреÑ." #: core/validators.py:103 msgid "Empty values are not allowed here." -msgstr "ПуÑтое значение не разрешено" +msgstr "ПуÑтое значение здеÑÑŒ недопуÑтимо." #: core/validators.py:107 msgid "Non-numeric characters aren't allowed here." -msgstr "Ðе цифровые Ñимволы не рназрешены" +msgstr "Ðецифровые Ñимволы здеÑÑŒ недопуÑтимы." #: core/validators.py:111 msgid "This value can't be comprised solely of digits." -msgstr "" +msgstr "Ðто значение не может быть ÑоÑтавлено только из цифр." #: core/validators.py:116 msgid "Enter a whole number." -msgstr "Введите номер" +msgstr "Введите целое чиÑло." #: core/validators.py:120 msgid "Only alphabetical characters are allowed here." -msgstr "Только буквы можно иÑпользовать" +msgstr "ЗдеÑÑŒ разрешены только алфавитные Ñимволы." #: core/validators.py:124 msgid "Enter a valid date in YYYY-MM-DD format." -msgstr "Вводите реальную дату в формате YYYY-MM-DD." +msgstr "Вводите правильную дату в формате YYYY-MM-DD." #: core/validators.py:128 msgid "Enter a valid time in HH:MM format." -msgstr "Вводите реальное Ð²Ñ€ÐµÐ¼Ñ Ð² формате HH:MM." +msgstr "Введите правильное Ð²Ñ€ÐµÐ¼Ñ Ð² формате HH:MM." -#: core/validators.py:132 db/models/fields/__init__.py:468 +#: core/validators.py:132 +#: db/models/fields/__init__.py:468 msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format." -msgstr "Вводите реальные дата/Ð²Ñ€ÐµÐ¼Ñ Ð² формате YYYY-MM-DD HH:MM." +msgstr "Введите правильные дату/Ð²Ñ€ÐµÐ¼Ñ Ð² формате YYYY-MM-DD HH:MM." #: core/validators.py:136 msgid "Enter a valid e-mail address." -msgstr "Укажите реальный e-mail адреÑ." +msgstr "Укажите правильный Ð°Ð´Ñ€ÐµÑ Ñлектронной почты." #: core/validators.py:148 -msgid "" -"Upload a valid image. The file you uploaded was either not an image or a " -"corrupted image." -msgstr "" -"Загрузите реальное изображение. Файл, который вы загружали, не был " -"изображением или был поврежден." +msgid "Upload a valid image. The file you uploaded was either not an image or a corrupted image." +msgstr "Загрузите реальное изображение. Файл, который вы загрузили, не ÑвлÑетÑÑ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸ÐµÐ¼ или был поврежден." #: core/validators.py:155 #, python-format @@ -1670,7 +1651,7 @@ msgstr "URL %s не указывает на реальное изображенР#: core/validators.py:159 #, python-format msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid." -msgstr "Телефонный номер должен быть в формате XXX-XXX-XXXX. \"%s\" не верен." +msgstr "Телефонные номера должен быть в формате XXX-XXX-XXXX. \"%s\" неверен." #: core/validators.py:167 #, python-format @@ -1679,7 +1660,7 @@ msgstr "URL %s не указывает на реальное видео QuickTim #: core/validators.py:171 msgid "A valid URL is required." -msgstr "Реальный URL обÑзателен." +msgstr "Правильный URL обÑзателен." #: core/validators.py:185 #, python-format @@ -1687,7 +1668,7 @@ msgid "" "Valid HTML is required. Specific errors are:\n" "%s" msgstr "" -"Реальный HTML обÑзателен. Специфичные ошибки:\n" +"Правильный HTML обÑзателен. Специфичные ошибки:\n" "%s" #: core/validators.py:192 @@ -1700,14 +1681,15 @@ msgstr "Ðеверный формат XML: %s" msgid "Invalid URL: %s" msgstr "Ðеверный URL: %s" -#: core/validators.py:206 core/validators.py:208 +#: core/validators.py:206 +#: core/validators.py:208 #, python-format msgid "The URL %s is a broken link." -msgstr "URL %s ÑÐ»Ð¾Ð¼Ð°Ð½Ð½Ð°Ñ ÑÑылка." +msgstr "URL %s - ÑÐ»Ð¾Ð¼Ð°Ð½Ð½Ð°Ñ ÑÑылка." #: core/validators.py:214 msgid "Enter a valid U.S. state abbreviation." -msgstr "Вводите реальную абревиатуру штатов СШÐ." +msgstr "Введите правильную аббревиатуру штата СШÐ." #: core/validators.py:229 #, python-format @@ -1715,6 +1697,7 @@ msgid "Watch your mouth! The word %s is not allowed here." msgid_plural "Watch your mouth! The words %s are not allowed here." msgstr[0] "Следите за Ñвоими Ñловами! Слово %s здеÑÑŒ запрещено." msgstr[1] "Следите за Ñвоими Ñловами! Слова %s здеÑÑŒ запрещены." +msgstr[2] "Следите за Ñвоими Ñловами! Слова %s здеÑÑŒ запрещены." #: core/validators.py:236 #, python-format @@ -1725,70 +1708,63 @@ msgstr "Ðто поле должно Ñовпадать Ñ Ð¿Ð¾Ð»ÐµÐ¼ '%s'." msgid "Please enter something for at least one field." msgstr "ПожалуйÑта, заполните Ñ…Ð¾Ñ‚Ñ Ð±Ñ‹ одно поле." -#: core/validators.py:264 core/validators.py:275 +#: core/validators.py:264 +#: core/validators.py:275 msgid "Please enter both fields or leave them both empty." -msgstr "ПожалуйÑта, заполните оба Ð¿Ð¾Ð»Ñ Ð»Ð¸Ð±Ð¾ оÑтавьте их пуÑтыми." +msgstr "ПожалуйÑта, заполните оба Ð¿Ð¾Ð»Ñ Ð¸Ð»Ð¸ оÑтавьте их оба пуÑтыми." #: core/validators.py:282 #, python-format msgid "This field must be given if %(field)s is %(value)s" -msgstr "Ðто поле должно быть заполнено еÑли %(field)s равно %(value)s" +msgstr "Ðто поле должно быть заполнено, еÑли %(field)s равно %(value)s" #: core/validators.py:294 #, python-format msgid "This field must be given if %(field)s is not %(value)s" -msgstr "Ðто поле должно быть заполнено еÑли %(field)s не равно %(value)s" +msgstr "Ðто поле должно быть заполнено, еÑли %(field)s не равно %(value)s" #: core/validators.py:313 msgid "Duplicate values are not allowed." -msgstr "Двойные Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð·Ð°Ð¿Ñ€ÐµÑ‰ÐµÐ½Ð½Ñ‹." +msgstr "Двойные Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð·Ð°Ð¿Ñ€ÐµÑ‰ÐµÐ½Ñ‹." #: core/validators.py:336 #, python-format msgid "This value must be a power of %s." -msgstr "" +msgstr "Ðто значение должно быть Ñтепенью %s." #: core/validators.py:347 msgid "Please enter a valid decimal number." -msgstr "ПожалуйÑта, вводите корректное деÑÑтичное чиÑло." +msgstr "ПожалуйÑта, введите корректное деÑÑтичное чиÑло." #: core/validators.py:349 #, python-format msgid "Please enter a valid decimal number with at most %s total digit." -msgid_plural "" -"Please enter a valid decimal number with at most %s total digits." -msgstr[0] "" -"ПожалуйÑта, вводите корректное деÑÑтичное чиÑло Ñ Ð¼Ð°ÐºÑимальным количеÑтвом " -"знаков %s." -msgstr[1] "" -"ПожалуйÑта, вводите корректное деÑÑтичное чиÑло Ñ Ð¼Ð°ÐºÑимальным количеÑтвом " -"знаков %s." +msgid_plural "Please enter a valid decimal number with at most %s total digits." +msgstr[0] "ПожалуйÑта, введите корректное деÑÑтичное чиÑло макÑимально Ñ %s знаком." +msgstr[1] "ПожалуйÑта, введите корректное деÑÑтичное чиÑло макÑимально Ñ %s знаками." +msgstr[2] "ПожалуйÑта, введите корректное деÑÑтичное чиÑло макÑимально Ñ %s знаками." #: core/validators.py:352 #, python-format msgid "Please enter a valid decimal number with at most %s decimal place." -msgid_plural "" -"Please enter a valid decimal number with at most %s decimal places." -msgstr[0] "" -"ПожалуйÑта, вводите корректное деÑÑтичное чиÑло Ñ Ð¼Ð°ÐºÑимальным количеÑтвом " -"знаков поÑле запÑтой %s." -msgstr[1] "" -"ПожалуйÑта, вводите корректное деÑÑтичное чиÑло Ñ Ð¼Ð°ÐºÑимальным количеÑтвом " -"знаков поÑле запÑтой %s." +msgid_plural "Please enter a valid decimal number with at most %s decimal places." +msgstr[0] "ПожалуйÑта, введите корректное деÑÑтичное чиÑло макÑимально Ñ %s знаком поÑле запÑтой." +msgstr[1] "ПожалуйÑта, введите корректное деÑÑтичное чиÑло макÑимально Ñ %s знаками поÑле запÑтой." +msgstr[2] "ПожалуйÑта, введите корректное деÑÑтичное чиÑло макÑимально Ñ %s знаками поÑле запÑтой." #: core/validators.py:362 #, python-format msgid "Make sure your uploaded file is at least %s bytes big." -msgstr "УбедитеÑÑŒ, что загруженный файл по крайней мере не меньше %s байт." +msgstr "УбедитеÑÑŒ, что загруженный файл не меньше %s байт." #: core/validators.py:363 #, python-format msgid "Make sure your uploaded file is at most %s bytes big." -msgstr "УбедитеÑÑŒ, что загруженный файл больше чем %s байт." +msgstr "УбедитеÑÑŒ, что загруженный файл не больше %s байт." #: core/validators.py:376 msgid "The format for this field is wrong." -msgstr "Формат Ñтого Ð¿Ð¾Ð»Ñ Ð½ÐµÐ²ÐµÑ€ÐµÐ½" +msgstr "Формат Ñтого Ð¿Ð¾Ð»Ñ Ð½ÐµÐ²ÐµÑ€ÐµÐ½." #: core/validators.py:391 msgid "This field is invalid." @@ -1797,85 +1773,72 @@ msgstr "Ðто поле неверно." #: core/validators.py:426 #, python-format msgid "Could not retrieve anything from %s." -msgstr "Ðевозможно получить что-либо Ñ %s." +msgstr "Ðевозможно получить ничего Ñ %s." #: core/validators.py:429 #, python-format -msgid "" -"The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'." -msgstr "URL %(url) вернул неверный заголовок Content-Type '%(contenttype)'." +msgid "The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'." +msgstr "URL %(url)s вернул неверный заголовок Content-Type '%(contenttype)s'." #: core/validators.py:462 #, python-format -msgid "" -"Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with " -"\"%(start)s\".)" -msgstr "" +msgid "Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with \"%(start)s\".)" +msgstr "ПожалуйÑта, закройте незакрытый Ñ‚Ñг %(tag)s на Ñтроке %(line)s. (Строка начинаетÑÑ Ñ \"%(start)s\".)" #: core/validators.py:466 #, python-format -msgid "" -"Some text starting on line %(line)s is not allowed in that context. (Line " -"starts with \"%(start)s\".)" -msgstr "" +msgid "Some text starting on line %(line)s is not allowed in that context. (Line starts with \"%(start)s\".)" +msgstr "Что-то из текÑта, начинающегоÑÑ Ð½Ð° Ñтроке %(line)s, недопуÑтимо в том контекÑте. (Строка начинаетÑÑ Ñ \"%(start)s\".)" #: core/validators.py:471 #, python-format -msgid "" -"\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%" -"(start)s\".)" -msgstr "" +msgid "\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%(start)s\".)" +msgstr "\"%(attr)s\" на Ñтроке %(line)s - неправильный атрибут. (Строка начинаетÑÑ Ñ \"%(start)s\".)" #: core/validators.py:476 #, python-format -msgid "" -"\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%" -"(start)s\".)" -msgstr "" +msgid "\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%(start)s\".)" +msgstr "\"<%(tag)s>\" на Ñтроке %(line)s - неправильный тег. (Строка начинаетÑÑ Ñ \"%(start)s\".)" #: core/validators.py:480 #, python-format -msgid "" -"A tag on line %(line)s is missing one or more required attributes. (Line " -"starts with \"%(start)s\".)" -msgstr "" +msgid "A tag on line %(line)s is missing one or more required attributes. (Line starts with \"%(start)s\".)" +msgstr "Ð’ теге на Ñтроке %(line)s не хватает одного или более обÑзательных атрибутов. (Строка начинаетÑÑ Ñ \"%(start)s\".)" #: core/validators.py:485 #, python-format -msgid "" -"The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line " -"starts with \"%(start)s\".)" -msgstr "" +msgid "The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line starts with \"%(start)s\".)" +msgstr "Ðтрибут \"%(attr)s\" на Ñтроке %(line)s имеет недопуÑтимое значение. (Строка начинаетÑÑ Ñ \"%(start)s\".)" #: db/models/manipulators.py:302 #, python-format msgid "%(object)s with this %(type)s already exists for the given %(field)s." -msgstr "" +msgstr "%(object)s Ñ Ñ‚Ð¸Ð¿Ð¾Ð¼ %(type)s уже ÑущеÑтвует Ð´Ð»Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ %(field)s." #: db/models/fields/__init__.py:40 #, python-format msgid "%(optname)s with this %(fieldname)s already exists." -msgstr "" +msgstr "%(optname)s Ñ %(fieldname)s уже ÑущеÑтвует." -#: db/models/fields/__init__.py:114 db/models/fields/__init__.py:265 -#: db/models/fields/__init__.py:542 db/models/fields/__init__.py:553 +#: db/models/fields/__init__.py:114 +#: db/models/fields/__init__.py:265 +#: db/models/fields/__init__.py:542 +#: db/models/fields/__init__.py:553 #: forms/__init__.py:346 msgid "This field is required." msgstr "ОбÑзательное поле." #: db/models/fields/__init__.py:337 msgid "This value must be an integer." -msgstr "" +msgstr "Ðто значение должно быть целым чиÑлом." #: db/models/fields/__init__.py:369 -#, fuzzy msgid "This value must be either True or False." -msgstr "ЛогичеÑкое (True или False)" +msgstr "Значение должно либо True, либо False." #: db/models/fields/__init__.py:385 -#, fuzzy msgid "This field cannot be null." -msgstr "Ðто поле неверно." +msgstr "Ðто поле не может быть нулевым." #: db/models/fields/__init__.py:562 msgid "Enter a valid filename." @@ -1884,52 +1847,50 @@ msgstr "Укажите правильное Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð°." #: db/models/fields/related.py:43 #, python-format msgid "Please enter a valid %s." -msgstr "" +msgstr "ПожалуйÑта, введите правильный %s." #: db/models/fields/related.py:579 -#, fuzzy msgid "Separate multiple IDs with commas." -msgstr "ÐеÑколько значений ID разделÑйте запÑтыми." +msgstr "ÐеÑколько значений ID разделите запÑтыми." #: db/models/fields/related.py:581 -#, fuzzy -msgid "" -"Hold down \"Control\", or \"Command\" on a Mac, to select more than one." -msgstr "" -" Удерживайте \"Control\", или \"Command\" на Макинтош, Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° больше чем " -"одного." +msgid "Hold down \"Control\", or \"Command\" on a Mac, to select more than one." +msgstr "Удерживайте \"Control\" (или \"Command\" на Mac) Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° неÑкольких." #: db/models/fields/related.py:625 #, python-format msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid." -msgid_plural "" -"Please enter valid %(self)s IDs. The values %(value)r are invalid." -msgstr[0] "" -msgstr[1] "" +msgid_plural "Please enter valid %(self)s IDs. The values %(value)r are invalid." +msgstr[0] "ПожалуйÑта, введите корректный ID Ð´Ð»Ñ %(self)s. Значение %(value)r недопуÑтимо." +msgstr[1] "ПожалуйÑта, введите корректные ID Ð´Ð»Ñ %(self)s. Ð—Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ %(value)r недопуÑтимы." +msgstr[2] "ПожалуйÑта, введите корректные ID Ð´Ð»Ñ %(self)s. Ð—Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ %(value)r недопуÑтимы." #: forms/__init__.py:380 #, python-format msgid "Ensure your text is less than %s character." msgid_plural "Ensure your text is less than %s characters." -msgstr[0] "" -msgstr[1] "" +msgstr[0] "УбедитеÑÑŒ, что длина вашего текÑта меньше %s Ñимвола." +msgstr[1] "УбедитеÑÑŒ, что длина вашего текÑта меньше %s Ñимволов." +msgstr[2] "УбедитеÑÑŒ, что длина вашего текÑта меньше %s Ñимволов." #: forms/__init__.py:385 msgid "Line breaks are not allowed here." -msgstr "ПереноÑÑ‹ Ñтрок не допуÑкаютÑÑ Ð·Ð´ÐµÑÑŒ." +msgstr "ПереноÑÑ‹ Ñтрок здеÑÑŒ не допуÑкаютÑÑ." -#: forms/__init__.py:480 forms/__init__.py:551 forms/__init__.py:589 +#: forms/__init__.py:480 +#: forms/__init__.py:551 +#: forms/__init__.py:589 #, python-format msgid "Select a valid choice; '%(data)s' is not in %(choices)s." -msgstr "" +msgstr "Выберите корректный вариант; '%(data)s' нет в %(choices)s." #: forms/__init__.py:645 msgid "The submitted file is empty." -msgstr "Указанный файл - пуÑÑ‚." +msgstr "Указанный файл пуÑÑ‚." #: forms/__init__.py:699 msgid "Enter a whole number between -32,768 and 32,767." -msgstr "" +msgstr "Введите целое чиÑло в диапазоне от -32768 до 32767." #: forms/__init__.py:708 msgid "Enter a positive number." @@ -1943,30 +1904,3 @@ msgstr "Введите целое чиÑло в диапазоне от 0 до 3 msgid "yes,no,maybe" msgstr "да,нет,может быть" -#~ msgid "Comment" -#~ msgstr "Комментарий" - -#~ msgid "Comments" -#~ msgstr "Комментарии" - -#~ msgid "label" -#~ msgstr "метка" - -#~ msgid "package" -#~ msgstr "пакет" - -#~ msgid "packages" -#~ msgstr "пакеты" - -#~ msgid "String (up to 50)" -#~ msgstr "Строка (до 50 Ñимволов)" - -#~ msgid "" -#~ "Example: 'flatfiles/contact_page'. If this isn't provided, the system " -#~ "will use 'flatfiles/default'." -#~ msgstr "" -#~ "Пример: 'flatfiles/contact_page'. ЕÑли не предуÑмотрена, ÑиÑтема будет " -#~ "иÑпользовать 'flatfiles/default'." - -#~ msgid "Server error <em>(500)</em>" -#~ msgstr "Ошибка Ñервера <em>(500)</em>" diff --git a/django/conf/locale/sl/LC_MESSAGES/django.mo b/django/conf/locale/sl/LC_MESSAGES/django.mo Binary files differindex a7d6152411..12253610c4 100644 --- a/django/conf/locale/sl/LC_MESSAGES/django.mo +++ b/django/conf/locale/sl/LC_MESSAGES/django.mo diff --git a/django/conf/locale/sl/LC_MESSAGES/django.po b/django/conf/locale/sl/LC_MESSAGES/django.po index 1d9e2f4028..5a9b6d6b46 100644 --- a/django/conf/locale/sl/LC_MESSAGES/django.po +++ b/django/conf/locale/sl/LC_MESSAGES/django.po @@ -1,21 +1,25 @@ -# SOME DESCRIPTIVE TITLE. +# translation of django.po to Slovenian +# Igor Kolar <ike@email.si), 2006. +# Nena Kojadin <nena@kiberpipa.org), 2006. +# Jure Cuhalev <gandalf@owca.info>, 2006. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# Igor Kolar <ike@email.si), 2006. -# Nena Kojadin <nena@kiberpipa.org), 2006 msgid "" msgstr "" -"Project-Id-Version: Django Slovenian 0.92+svn translation\n" +"Project-Id-Version: django\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2006-05-16 10:13+0200\n" -"PO-Revision-Date: 2006-03-19 17:30+0100\n" +"PO-Revision-Date: 2006-07-29 11:52+0100\n" "Last-Translator: Jure ÄŒuhalev <gandalf@owca.info>\n" -"Language-Team: Slovenian <sl@li.org>\n" +"Language-Team: Slovenian <lugos-slo@lugos.si>\n" "MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" +"Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.2\n" +"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);\n" -#: contrib/comments/models.py:67 contrib/comments/models.py:166 +#: contrib/comments/models.py:67 +#: contrib/comments/models.py:166 msgid "object ID" msgstr "ID objekta" @@ -23,7 +27,8 @@ msgstr "ID objekta" msgid "headline" msgstr "naslov" -#: contrib/comments/models.py:69 contrib/comments/models.py:90 +#: contrib/comments/models.py:69 +#: contrib/comments/models.py:90 #: contrib/comments/models.py:167 msgid "comment" msgstr "komentar" @@ -64,15 +69,18 @@ msgstr "rating #8" msgid "is valid rating" msgstr "je veljavni rating" -#: contrib/comments/models.py:83 contrib/comments/models.py:169 +#: contrib/comments/models.py:83 +#: contrib/comments/models.py:169 msgid "date/time submitted" -msgstr "podatek datum/Äas poslan" +msgstr "datum/Äas vnosa" -#: contrib/comments/models.py:84 contrib/comments/models.py:170 +#: contrib/comments/models.py:84 +#: contrib/comments/models.py:170 msgid "is public" msgstr "je javno" -#: contrib/comments/models.py:85 contrib/admin/views/doc.py:289 +#: contrib/comments/models.py:85 +#: contrib/admin/views/doc.py:289 msgid "IP address" msgstr "IP naslov" @@ -81,21 +89,17 @@ msgid "is removed" msgstr "je odstranjen/-a" #: contrib/comments/models.py:86 -msgid "" -"Check this box if the comment is inappropriate. A \"This comment has been " -"removed\" message will be displayed instead." -msgstr "" -"Odkljukaj, Äe je komntar neprimeren. Namesto komentarja bo vidno obvestilo " -"\"Ta komentar je bil odstranjen\"." +msgid "Check this box if the comment is inappropriate. A \"This comment has been removed\" message will be displayed instead." +msgstr "Odkljukaj, Äe je komntar neprimeren. Namesto komentarja bo vidno obvestilo \"Ta komentar je bil odstranjen\"." #: contrib/comments/models.py:91 -#, fuzzy msgid "comments" -msgstr "komentar" +msgstr "komentarji" -#: contrib/comments/models.py:131 contrib/comments/models.py:207 +#: contrib/comments/models.py:131 +#: contrib/comments/models.py:207 msgid "Content object" -msgstr "Objekt s vsebino" +msgstr "Objekt z vsebino" #: contrib/comments/models.py:159 #, python-format @@ -125,14 +129,12 @@ msgid "approved by staff" msgstr "potrjeno s strani osebja" #: contrib/comments/models.py:176 -#, fuzzy msgid "free comment" -msgstr "Zastonj komentar" +msgstr "anonimen komentar" #: contrib/comments/models.py:177 -#, fuzzy msgid "free comments" -msgstr "Zastonj komentarji" +msgstr "anonimni komentarji" #: contrib/comments/models.py:233 msgid "score" @@ -143,14 +145,12 @@ msgid "score date" msgstr "datum ocene" #: contrib/comments/models.py:237 -#, fuzzy msgid "karma score" -msgstr "Karma" +msgstr "karma toÄke" #: contrib/comments/models.py:238 -#, fuzzy msgid "karma scores" -msgstr "Skrivnosti karme" +msgstr "karma toÄke" #: contrib/comments/models.py:242 #, python-format @@ -173,14 +173,12 @@ msgid "flag date" msgstr "datum oznaÄitve (zastavice)" #: contrib/comments/models.py:268 -#, fuzzy msgid "user flag" -msgstr "UporabniÅ¡ka zastavica" +msgstr "uporabnikova zastavica" #: contrib/comments/models.py:269 -#, fuzzy msgid "user flags" -msgstr "UporabniÅ¡ke zastavice" +msgstr "uporabniÅ¡ke zastavice" #: contrib/comments/models.py:273 #, python-format @@ -192,14 +190,12 @@ msgid "deletion date" msgstr "datum izbrisa" #: contrib/comments/models.py:280 -#, fuzzy msgid "moderator deletion" -msgstr "Izbris s strani moderatorja" +msgstr "izbris s strani moderatorja" #: contrib/comments/models.py:281 -#, fuzzy msgid "moderator deletions" -msgstr "Izbrisi s strani moderatorja" +msgstr "izbrisi s strani moderatorja" #: contrib/comments/models.py:285 #, python-format @@ -219,30 +215,33 @@ msgid "No voting for yourself" msgstr "Ni mogoÄe glasovati zase" #: contrib/comments/views/comments.py:28 -msgid "" -"This rating is required because you've entered at least one other rating." +msgid "This rating is required because you've entered at least one other rating." msgstr "MoraÅ¡ podati tole oceno, ker si podal vsaj Å¡e eno drugo oceno." #: contrib/comments/views/comments.py:112 #, python-format msgid "" -"This comment was posted by a user who has posted fewer than %(count)s " -"comment:\n" +"This comment was posted by a user who has posted fewer than %(count)s comment:\n" "\n" "%(text)s" msgid_plural "" -"This comment was posted by a user who has posted fewer than %(count)s " -"comments:\n" +"This comment was posted by a user who has posted fewer than %(count)s comments:\n" "\n" "%(text)s" msgstr[0] "" -"Ta komentar je poslal uporabnik, ki je do zdaj poslal manj kot %(count)s " -"komentarjev Komentar:\n" +"Ta komentar je poslal uporabnik, ki je do zdaj poslal manj kot %(count)s komentarjev:\n" "\n" "%(text)s" msgstr[1] "" -"Ta komentar je poslal uporabnik, ki je do zdaj poslal manj kot %(count)s " -"komentarjev Komentar:\n" +"Ta komentar je poslal uporabnik, ki je do zdaj poslal manj kot %(count)s komentar:\n" +"\n" +"%(text)s" +msgstr[2] "" +"Ta komentar je poslal uporabnik, ki je do zdaj poslal manj kot %(count)s komentarja:\n" +"\n" +"%(text)s" +msgstr[3] "" +"Ta komentar je poslal uporabnik, ki je do zdaj poslal manj kot %(count)s komentarje:\n" "\n" "%(text)s" @@ -260,12 +259,12 @@ msgstr "" #: contrib/comments/views/comments.py:189 #: contrib/comments/views/comments.py:280 msgid "Only POSTs are allowed" -msgstr "Dovoljena je le metoda HTTP POST" +msgstr "Dovoljena je le metoda POST" #: contrib/comments/views/comments.py:193 #: contrib/comments/views/comments.py:284 msgid "One or more of the required fields wasn't submitted" -msgstr "Eden ali veÄ obveznih polj ni vpisanih" +msgstr "Eno ali veÄ obveznih polj ni vpisanih" #: contrib/comments/views/comments.py:197 #: contrib/comments/views/comments.py:286 @@ -274,17 +273,13 @@ msgstr "Nekdo se je poigraval z obrazcem za komentarje (varnostna krÅ¡itev)" #: contrib/comments/views/comments.py:207 #: contrib/comments/views/comments.py:292 -msgid "" -"The comment form had an invalid 'target' parameter -- the object ID was " -"invalid" -msgstr "" -"Obrazec s komentarji ima neveljavni parameter 'target' -- ID objekta je " -"neveljaven." +msgid "The comment form had an invalid 'target' parameter -- the object ID was invalid" +msgstr "Obrazec s komentarji ima neveljavni parameter 'target' -- ID objekta je neveljaven." #: contrib/comments/views/comments.py:257 #: contrib/comments/views/comments.py:321 msgid "The comment form didn't provide either 'preview' or 'post'" -msgstr "Obrazec s komentarji ne zahteva niti 'preview' niti 'post' akcije." +msgstr "Obrazec s komentarji ni podal niti 'preview' niti 'post' akcije." #: contrib/comments/templates/comments/form.html:6 #: contrib/comments/templates/comments/form.html:8 @@ -363,7 +358,8 @@ msgstr "" "<h3>Avtor: %s</h3>\n" "<ul>\n" -#: contrib/admin/filterspecs.py:70 contrib/admin/filterspecs.py:88 +#: contrib/admin/filterspecs.py:70 +#: contrib/admin/filterspecs.py:88 #: contrib/admin/filterspecs.py:143 msgid "All" msgstr "Vse" @@ -390,7 +386,7 @@ msgstr "Letos" #: contrib/admin/filterspecs.py:143 msgid "Yes" -msgstr "Ja" +msgstr "Da" #: contrib/admin/filterspecs.py:143 msgid "No" @@ -432,46 +428,33 @@ msgstr "vnosi v dnevniku" msgid "All dates" msgstr "Vsi datumi" -#: contrib/admin/views/decorators.py:9 contrib/auth/forms.py:36 +#: contrib/admin/views/decorators.py:9 +#: contrib/auth/forms.py:36 #: contrib/auth/forms.py:41 -msgid "" -"Please enter a correct username and password. Note that both fields are case-" -"sensitive." -msgstr "" -"Prosimo, vnesite veljavno uporabniÅ¡ko ime in geslo. Opomba: obe polji sta " -"obÄutljivi na velikost Ärk" +msgid "Please enter a correct username and password. Note that both fields are case-sensitive." +msgstr "Prosimo, vnesite veljavno uporabniÅ¡ko ime in geslo. Opomba: obe polji sta obÄutljivi na velikost Ärk" #: contrib/admin/views/decorators.py:23 #: contrib/admin/templates/admin/login.html:25 msgid "Log in" -msgstr "Prijate se" +msgstr "Prijavite se" #: contrib/admin/views/decorators.py:61 -msgid "" -"Please log in again, because your session has expired. Don't worry: Your " -"submission has been saved." -msgstr "" -"VaÅ¡a seja je pretekla; prosimo, prijavite se znova. Opomba: Vse vaÅ¡e objave " -"so varno shranjene." +msgid "Please log in again, because your session has expired. Don't worry: Your submission has been saved." +msgstr "VaÅ¡a seja je pretekla; prosimo, prijavite se znova. Ne skrbite, vaÅ¡e objave so varno shranjene." #: contrib/admin/views/decorators.py:68 -msgid "" -"Looks like your browser isn't configured to accept cookies. Please enable " -"cookies, reload this page, and try again." -msgstr "" -"Izgleda, da vaÅ¡ brskalnik nima podpore za piÅ¡kotke. Prosimo, vkljuÄite " -"piÅ¡kotke, znova naložite to stran in poskusite Å¡e enkrat." +msgid "Looks like your browser isn't configured to accept cookies. Please enable cookies, reload this page, and try again." +msgstr "Izgleda, da vaÅ¡ brskalnik nima podpore za piÅ¡kotke. Prosimo, vkljuÄite piÅ¡kotke, znova naložite to stran in poskusite Å¡e enkrat." #: contrib/admin/views/decorators.py:82 msgid "Usernames cannot contain the '@' character." -msgstr "UporabniÅ¡ka imena ne smejo vsebovati znaka '@'" +msgstr "UporabniÅ¡ka imena ne smejo vsebovati znaka '@'." #: contrib/admin/views/decorators.py:84 #, python-format msgid "Your e-mail address is not your username. Try '%s' instead." -msgstr "" -"VaÅ¡ e-mail naslov ne morete uporabljati kot uporabniÅ¡ko ime. Namesto tega " -"uporabite '%s'" +msgstr "VaÅ¡ e-mail naslov ne morete uporabljati kot uporabniÅ¡ko ime. Namesto tega uporabite '%s'." #: contrib/admin/views/main.py:226 msgid "Site administration" @@ -482,11 +465,13 @@ msgstr "Administracija strani" msgid "The %(name)s \"%(obj)s\" was added successfully." msgstr "%(name)s \"%(obj)s\" je bil uspeÅ¡no dodan." -#: contrib/admin/views/main.py:264 contrib/admin/views/main.py:348 +#: contrib/admin/views/main.py:264 +#: contrib/admin/views/main.py:348 msgid "You may edit it again below." msgstr "Vsebino lahko znova uredite spodaj." -#: contrib/admin/views/main.py:272 contrib/admin/views/main.py:357 +#: contrib/admin/views/main.py:272 +#: contrib/admin/views/main.py:357 #, python-format msgid "You may add another %s below." msgstr "Spodaj lahko dodate Å¡e en %s." @@ -501,7 +486,8 @@ msgstr "Dodaj %s" msgid "Added %s." msgstr "Dodal %s." -#: contrib/admin/views/main.py:336 contrib/admin/views/main.py:338 +#: contrib/admin/views/main.py:336 +#: contrib/admin/views/main.py:338 #: contrib/admin/views/main.py:340 msgid "and" msgstr "in" @@ -509,7 +495,7 @@ msgstr "in" #: contrib/admin/views/main.py:338 #, python-format msgid "Changed %s." -msgstr "Spremenil %s" +msgstr "Spremenil %s." #: contrib/admin/views/main.py:340 #, python-format @@ -527,10 +513,8 @@ msgstr "%(name)s \"%(obj)s\" je bilo uspeÅ¡no spremenjeno." #: contrib/admin/views/main.py:354 #, python-format -msgid "" -"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below." -msgstr "" -"%(name)s \"%(obj)s\" je bilo uspeÅ¡no dodano. Znova ga lahko urejate spodaj." +msgid "The %(name)s \"%(obj)s\" was added successfully. You may edit it again below." +msgstr "%(name)s \"%(obj)s\" je bilo uspeÅ¡no dodano. Znova ga lahko urejate spodaj." #: contrib/admin/views/main.py:392 #, python-format @@ -564,24 +548,28 @@ msgstr "Zgodovina sprememb: %s" #: contrib/admin/views/main.py:565 #, python-format msgid "Select %s" -msgstr "Izberi %s" +msgstr "Izberite %s" #: contrib/admin/views/main.py:565 #, python-format msgid "Select %s to change" -msgstr "Izberi %s, ki ga želite spremeniti" +msgstr "Izberite %s, ki ga želite spremeniti" -#: contrib/admin/views/doc.py:277 contrib/admin/views/doc.py:286 -#: contrib/admin/views/doc.py:288 contrib/admin/views/doc.py:294 -#: contrib/admin/views/doc.py:295 contrib/admin/views/doc.py:297 +#: contrib/admin/views/doc.py:277 +#: contrib/admin/views/doc.py:286 +#: contrib/admin/views/doc.py:288 +#: contrib/admin/views/doc.py:294 +#: contrib/admin/views/doc.py:295 +#: contrib/admin/views/doc.py:297 msgid "Integer" -msgstr "Integer (Å¡tevilo)" +msgstr "Å tevilo (integer)" #: contrib/admin/views/doc.py:278 msgid "Boolean (Either True or False)" msgstr "Boolean (ali True ali False)" -#: contrib/admin/views/doc.py:279 contrib/admin/views/doc.py:296 +#: contrib/admin/views/doc.py:279 +#: contrib/admin/views/doc.py:296 #, python-format msgid "String (up to %(maxlength)s)" msgstr "Niz (vse do %(maxlength)s)" @@ -602,7 +590,8 @@ msgstr "Datum (s Äasom)" msgid "E-mail address" msgstr "E-naslov" -#: contrib/admin/views/doc.py:284 contrib/admin/views/doc.py:287 +#: contrib/admin/views/doc.py:284 +#: contrib/admin/views/doc.py:287 msgid "File path" msgstr "Pot do datoteke" @@ -616,7 +605,7 @@ msgstr "Boolean (ali True ali False ali None)" #: contrib/admin/views/doc.py:292 msgid "Relation to parent model" -msgstr "Razmerje z starÅ¡evskim modelom" +msgstr "Razmerje s starÅ¡evskim modelom" #: contrib/admin/views/doc.py:293 msgid "Phone number" @@ -630,7 +619,8 @@ msgstr "Besedilo" msgid "Time" msgstr "ÄŒas" -#: contrib/admin/views/doc.py:300 contrib/flatpages/models.py:7 +#: contrib/admin/views/doc.py:300 +#: contrib/flatpages/models.py:7 msgid "URL" msgstr "URL (spletni naslov)" @@ -707,15 +697,11 @@ msgstr "Dejanje" #: contrib/admin/templates/admin/object_history.html:26 msgid "DATE_WITH_TIME_FULL" -msgstr "N j, Y, P" +msgstr "N j, Y, H:i" #: contrib/admin/templates/admin/object_history.html:36 -msgid "" -"This object doesn't have a change history. It probably wasn't added via this " -"admin site." -msgstr "" -"Ta objekt nima zgodovine. Verjetno ni bil dodan preko te administratorske " -"strani." +msgid "This object doesn't have a change history. It probably wasn't added via this admin site." +msgstr "Ta objekt nima zgodovine. Verjetno ni bil dodan preko te administratorske strani." #: contrib/admin/templates/admin/base_site.html:4 msgid "Django site admin" @@ -738,12 +724,8 @@ msgid "Server Error <em>(500)</em>" msgstr "Napaka strežnika <em>(500)</em>" #: contrib/admin/templates/admin/500.html:10 -msgid "" -"There's been an error. It's been reported to the site administrators via e-" -"mail and should be fixed shortly. Thanks for your patience." -msgstr "" -"PriÅ¡lo je do nepriÄakovane napake. Administratorji strani so že obveÅ¡Äeni " -"prekoe-poÅ¡te in naj bi jo v kratkem odpravili. Hvala za vaÅ¡e potrpljenje." +msgid "There's been an error. It's been reported to the site administrators via e-mail and should be fixed shortly. Thanks for your patience." +msgstr "PriÅ¡lo je do nepriÄakovane napake. Administratorji strani so že obveÅ¡Äeni prekoe-poÅ¡te in naj bi jo v kratkem odpravili. Hvala za vaÅ¡e potrpljenje." #: contrib/admin/templates/admin/404.html:4 #: contrib/admin/templates/admin/404.html:8 @@ -752,12 +734,12 @@ msgstr "Strani ni mogoÄe najti" #: contrib/admin/templates/admin/404.html:10 msgid "We're sorry, but the requested page could not be found." -msgstr "Se opraivÄujemo, a zahtevane strani ni mogoÄe najti." +msgstr "Se opraviÄujemo, a zahtevane strani ni mogoÄe najti." #: contrib/admin/templates/admin/index.html:17 #, python-format msgid "Models available in the %(name)s application." -msgstr "" +msgstr "Modeli na voljo v %(name)s aplikaciji" #: contrib/admin/templates/admin/index.html:28 #: contrib/admin/templates/admin/change_form.html:15 @@ -776,7 +758,7 @@ msgstr "Nimate dovoljenja za urejanje Äesar koli." msgid "Recent Actions" msgstr "Zadnja dejanja" -#: contrib/admin/templates/admin/index.html:53 +#: contrib/admin/tempalates/admin/index.html:53 msgid "My Actions" msgstr "Moja dejanja" @@ -804,22 +786,13 @@ msgstr "IzbriÅ¡i" #: contrib/admin/templates/admin/delete_confirmation.html:14 #, python-format -msgid "" -"Deleting the %(object_name)s '%(object)s' would result in deleting related " -"objects, but your account doesn't have permission to delete the following " -"types of objects:" -msgstr "" -"Izbris %(object_name)s '%(object)s' bi pomenil izbris povezanih objektov, " -"vendarvi nimate dovoljenja za izbris naslednjih tipov objektov:" +msgid "Deleting the %(object_name)s '%(object)s' would result in deleting related objects, but your account doesn't have permission to delete the following types of objects:" +msgstr "Izbris %(object_name)s '%(object)s' bi pomenil izbris povezanih objektov, vendarvi nimate dovoljenja za izbris naslednjih tipov objektov:" #: contrib/admin/templates/admin/delete_confirmation.html:21 #, python-format -msgid "" -"Are you sure you want to delete the %(object_name)s \"%(object)s\"? All of " -"the following related items will be deleted:" -msgstr "" -"Ste prepriÄani, da želite izbrisati %(object_name)s \"%(object)s\"?Vsi " -"naslednji povezani elementi bodo izbrisani:" +msgid "Are you sure you want to delete the %(object_name)s \"%(object)s\"? All of the following related items will be deleted:" +msgstr "Ste prepriÄani, da želite izbrisati %(object_name)s \"%(object)s\"?Vsi naslednji povezani elementi bodo izbrisani:" #: contrib/admin/templates/admin/delete_confirmation.html:26 msgid "Yes, I'm sure" @@ -843,6 +816,8 @@ msgid "Please correct the error below." msgid_plural "Please correct the errors below." msgstr[0] "Prosimo, odpravite sledeÄo napako." msgstr[1] "Prosimo, odpravite sledeÄe napake." +msgstr[2] "Prosimo, odpravite sledeÄi napaki." +msgstr[3] "Prosimo, odpravite sledeÄe napake." #: contrib/admin/templates/admin/change_form.html:48 msgid "Ordering" @@ -892,12 +867,8 @@ msgid "Password reset" msgstr "Obnova gesla" #: contrib/admin/templates/registration/password_reset_form.html:12 -msgid "" -"Forgotten your password? Enter your e-mail address below, and we'll reset " -"your password and e-mail the new one to you." -msgstr "" -"Ste pozabili geslo? Vnesite vaÅ¡ e-naslov spodaj in mi vam bomo poslali novo " -"geslo." +msgid "Forgotten your password? Enter your e-mail address below, and we'll reset your password and e-mail the new one to you." +msgstr "Ste pozabili geslo? Vnesite vaÅ¡ e-naslov spodaj in mi vam bomo poslali novo geslo." #: contrib/admin/templates/registration/password_reset_form.html:16 msgid "E-mail address:" @@ -921,18 +892,12 @@ msgid "Password reset successful" msgstr "Geslo je bilo uspeÅ¡no obnovljeno" #: contrib/admin/templates/registration/password_reset_done.html:12 -msgid "" -"We've e-mailed a new password to the e-mail address you submitted. You " -"should be receiving it shortly." +msgid "We've e-mailed a new password to the e-mail address you submitted. You should be receiving it shortly." msgstr "Po e-poÅ¡ti smo vam poslali novo geslo.Morali bi ga prejeti v kratkem" #: contrib/admin/templates/registration/password_change_form.html:12 -msgid "" -"Please enter your old password, for security's sake, and then enter your new " -"password twice so we can verify you typed it in correctly." -msgstr "" -"Prosim, vnesite vaÅ¡e staro geslo (zaradi varnosti) in nato Å¡e dvakrat novo" -"(da preverimo, da se niste zatipkali)" +msgid "Please enter your old password, for security's sake, and then enter your new password twice so we can verify you typed it in correctly." +msgstr "Prosim, vnesite vaÅ¡e staro geslo (zaradi varnosti) in nato Å¡e dvakrat novo(da preverimo, da se niste zatipkali)" #: contrib/admin/templates/registration/password_change_form.html:17 msgid "Old password:" @@ -1000,34 +965,24 @@ msgid "" "your computer is \"internal\").</p>\n" msgstr "" "\n" -"<p class=\"help\">Za inÅ¡talacijo zaznamkic povleÄite povezavo v orodno " -"vrstico\n" -"z zaznamki, ali kliknite z desno miÅ¡kino tipko na povezavo in jo dodajte med " -"zaznamkeZdaj lahko uporabite zaznamek s katere koli strani. Opomba: nekatere " -"teh stranilahko gledate le z internega raÄunalnika (preverite s sistemskim " -"administratorjem)</p>\n" +"<p class=\"help\">Za inÅ¡talacijo zaznamkic povleÄite povezavo v orodno vrstico\n" +"z zaznamki, ali kliknite z desno miÅ¡kino tipko na povezavo in jo dodajte med zaznamkeZdaj lahko uporabite zaznamek s katere koli strani. Opomba: nekatere teh stranilahko gledate le z internega raÄunalnika (preverite s sistemskim administratorjem)</p>\n" #: contrib/admin/templates/admin_doc/bookmarklets.html:19 msgid "Documentation for this page" msgstr "Dokumentacija za to stran" #: contrib/admin/templates/admin_doc/bookmarklets.html:20 -msgid "" -"Jumps you from any page to the documentation for the view that generates " -"that page." -msgstr "" -"Skok na stran z dokumentacijo za pogled (view), ki generira trenutno stran." +msgid "Jumps you from any page to the documentation for the view that generates that page." +msgstr "Skok na stran z dokumentacijo za pogled (view), ki generira trenutno stran." #: contrib/admin/templates/admin_doc/bookmarklets.html:22 msgid "Show object ID" msgstr "Pokaži ID objekta" #: contrib/admin/templates/admin_doc/bookmarklets.html:23 -msgid "" -"Shows the content-type and unique ID for pages that represent a single " -"object." -msgstr "" -"Pokaže content-type in unikatni ID za strani, ki predstavljajo en objekt." +msgid "Shows the content-type and unique ID for pages that represent a single object." +msgstr "Pokaže content-type in unikatni ID za strani, ki predstavljajo en objekt." #: contrib/admin/templates/admin_doc/bookmarklets.html:25 msgid "Edit this object (current window)" @@ -1035,8 +990,7 @@ msgstr "Uredi trenutni objekt (v trenutnem oknu)" #: contrib/admin/templates/admin_doc/bookmarklets.html:26 msgid "Jumps to the admin page for pages that represent a single object." -msgstr "" -"Skok na administracijsko stran za vse strani, ki predstavljajo en objekt." +msgstr "Skok na administracijsko stran za vse strani, ki predstavljajo en objekt." #: contrib/admin/templates/admin_doc/bookmarklets.html:28 msgid "Edit this object (new window)" @@ -1067,23 +1021,16 @@ msgid "redirect from" msgstr "preusmeritev iz" #: contrib/redirects/models.py:8 -msgid "" -"This should be an absolute path, excluding the domain name. Example: '/" -"events/search/'." -msgstr "" -"To mora biti absolutna pot, izkljuÄujoÄ domeno. Primer: '/events/search'-" +msgid "This should be an absolute path, excluding the domain name. Example: '/events/search/'." +msgstr "To mora biti absolutna pot, izkljuÄujoÄ domeno. Primer: '/events/search'-" #: contrib/redirects/models.py:9 msgid "redirect to" msgstr "preusmeri na" #: contrib/redirects/models.py:10 -msgid "" -"This can be either an absolute path (as above) or a full URL starting with " -"'http://'." -msgstr "" -"To je ali absolutna pot (kot zgoraj) ali popoln URL naslov (zaÄne se z " -"'http://')" +msgid "This can be either an absolute path (as above) or a full URL starting with 'http://'." +msgstr "To je ali absolutna pot (kot zgoraj) ali popoln URL naslov (zaÄne se z 'http://')" #: contrib/redirects/models.py:12 msgid "redirect" @@ -1094,10 +1041,8 @@ msgid "redirects" msgstr "preusmeritve" #: contrib/flatpages/models.py:8 -msgid "" -"Example: '/about/contact/'. Make sure to have leading and trailing slashes." -msgstr "" -"Primer: '/about/contact/'. Mora vsebovati / (poÅ¡evnico) na zaÄetku in koncu." +msgid "Example: '/about/contact/'. Make sure to have leading and trailing slashes." +msgstr "Primer: '/about/contact/'. Mora vsebovati / (poÅ¡evnico) na zaÄetku in koncu." #: contrib/flatpages/models.py:9 msgid "title" @@ -1116,12 +1061,8 @@ msgid "template name" msgstr "ime predloge" #: contrib/flatpages/models.py:13 -msgid "" -"Example: 'flatpages/contact_page'. If this isn't provided, the system will " -"use 'flatpages/default'." -msgstr "" -"Primer: 'flatpages/contact_page'. ÄŒe to polje ni izpolnjeno, bo sistem " -"uporabil 'flatpages/default'." +msgid "Example: 'flatpages/contact_page'. If this isn't provided, the system will use 'flatpages/default'." +msgstr "Primer: 'flatpages/contact_page'. ÄŒe to polje ni izpolnjeno, bo sistem uporabil 'flatpages/default'." #: contrib/flatpages/models.py:14 msgid "registration required" @@ -1129,19 +1070,18 @@ msgstr "obvezna registracija" #: contrib/flatpages/models.py:14 msgid "If this is checked, only logged-in users will be able to view the page." -msgstr "" -"ÄŒe je to polje odkljukano, si lahko to stran ogledajo le registrirani " -"uporabniki." +msgstr "ÄŒe je to polje odkljukano, si lahko to stran ogledajo le registrirani uporabniki." #: contrib/flatpages/models.py:18 msgid "flat page" -msgstr "ploh stran :)" +msgstr "enostavna stran" #: contrib/flatpages/models.py:19 msgid "flat pages" -msgstr "ploh strani :)" +msgstr "enostavne strani" -#: contrib/auth/models.py:13 contrib/auth/models.py:26 +#: contrib/auth/models.py:13 +#: contrib/auth/models.py:26 msgid "name" msgstr "ime" @@ -1150,24 +1090,22 @@ msgid "codename" msgstr "kodno ime" #: contrib/auth/models.py:17 -#, fuzzy msgid "permission" -msgstr "Dovoljenje" +msgstr "dovoljenje" -#: contrib/auth/models.py:18 contrib/auth/models.py:27 -#, fuzzy +#: contrib/auth/models.py:18 +#: contrib/auth/models.py:27 msgid "permissions" -msgstr "Dovoljenja" +msgstr "dovoljenja" #: contrib/auth/models.py:29 -#, fuzzy msgid "group" -msgstr "Skupina" +msgstr "skupina" -#: contrib/auth/models.py:30 contrib/auth/models.py:65 -#, fuzzy +#: contrib/auth/models.py:30 +#: contrib/auth/models.py:65 msgid "groups" -msgstr "Skupine" +msgstr "skupine" #: contrib/auth/models.py:55 msgid "username" @@ -1218,27 +1156,20 @@ msgid "date joined" msgstr "Älan od" #: contrib/auth/models.py:66 -msgid "" -"In addition to the permissions manually assigned, this user will also get " -"all permissions granted to each group he/she is in." -msgstr "" -"Polek roÄno doloÄenih dovoljenj bo ta uporabnik dobil tudi vsa dovoljenja,ki " -"pripadajo vsem skupinah, v katerih je." +msgid "In addition to the permissions manually assigned, this user will also get all permissions granted to each group he/she is in." +msgstr "Polek roÄno doloÄenih dovoljenj bo ta uporabnik dobil tudi vsa dovoljenja,ki pripadajo vsem skupinah, v katerih je." #: contrib/auth/models.py:67 -#, fuzzy msgid "user permissions" -msgstr "Dovoljenja" +msgstr "uporabniÅ¡ka dovoljenja" #: contrib/auth/models.py:70 -#, fuzzy msgid "user" -msgstr "Uporabnik" +msgstr "uporabnik" #: contrib/auth/models.py:71 -#, fuzzy msgid "users" -msgstr "Uporabniki" +msgstr "uporabniki" #: contrib/auth/models.py:76 msgid "Personal info" @@ -1257,22 +1188,16 @@ msgid "Groups" msgstr "Skupine" #: contrib/auth/models.py:219 -#, fuzzy msgid "message" -msgstr "SporoÄilo" +msgstr "sporoÄilo" #: contrib/auth/forms.py:30 -msgid "" -"Your Web browser doesn't appear to have cookies enabled. Cookies are " -"required for logging in." -msgstr "" -"Izgleda, da vaÅ¡ brskalnik nima omogoÄenih piÅ¡kotkov. PiÅ¡kotki so potrebni za " -"prijavo." +msgid "Your Web browser doesn't appear to have cookies enabled. Cookies are required for logging in." +msgstr "Izgleda, da vaÅ¡ brskalnik nima omogoÄenih piÅ¡kotkov. PiÅ¡kotki so potrebni za prijavo." #: contrib/contenttypes/models.py:25 -#, fuzzy msgid "python model class name" -msgstr "python ime modula" +msgstr "python ime razreda modela" #: contrib/contenttypes/models.py:28 msgid "content type" @@ -1366,23 +1291,28 @@ msgstr "januar" msgid "February" msgstr "februar" -#: utils/dates.py:14 utils/dates.py:27 +#: utils/dates.py:14 +#: utils/dates.py:27 msgid "March" msgstr "marec" -#: utils/dates.py:14 utils/dates.py:27 +#: utils/dates.py:14 +#: utils/dates.py:27 msgid "April" msgstr "april" -#: utils/dates.py:14 utils/dates.py:27 +#: utils/dates.py:14 +#: utils/dates.py:27 msgid "May" msgstr "maj" -#: utils/dates.py:14 utils/dates.py:27 +#: utils/dates.py:14 +#: utils/dates.py:27 msgid "June" msgstr "junij" -#: utils/dates.py:15 utils/dates.py:27 +#: utils/dates.py:15 +#: utils/dates.py:27 msgid "July" msgstr "julij" @@ -1407,62 +1337,58 @@ msgid "December" msgstr "december" #: utils/dates.py:19 -#, fuzzy msgid "jan" -msgstr "in" +msgstr "jan" #: utils/dates.py:19 -#, fuzzy msgid "feb" -msgstr "feb." +msgstr "feb" #: utils/dates.py:19 msgid "mar" -msgstr "" +msgstr "mar" #: utils/dates.py:19 msgid "apr" -msgstr "" +msgstr "apr" #: utils/dates.py:19 -#, fuzzy msgid "may" -msgstr "dan" +msgstr "maj" #: utils/dates.py:19 msgid "jun" -msgstr "" +msgstr "jun" #: utils/dates.py:20 msgid "jul" -msgstr "" +msgstr "jul" #: utils/dates.py:20 msgid "aug" -msgstr "" +msgstr "avg" #: utils/dates.py:20 msgid "sep" -msgstr "" +msgstr "sep" #: utils/dates.py:20 msgid "oct" -msgstr "" +msgstr "okt" #: utils/dates.py:20 msgid "nov" -msgstr "" +msgstr "nov" #: utils/dates.py:20 msgid "dec" -msgstr "" +msgstr "dec" #: utils/dates.py:27 msgid "Jan." msgstr "jan." #: utils/dates.py:27 -#, fuzzy msgid "Feb." msgstr "feb." @@ -1489,38 +1415,50 @@ msgstr "dec." #: utils/timesince.py:12 msgid "year" msgid_plural "years" -msgstr[0] "leto" -msgstr[1] "let" +msgstr[0] "let" +msgstr[1] "leto" +msgstr[2] "leti" +msgstr[3] "leta" #: utils/timesince.py:13 msgid "month" msgid_plural "months" -msgstr[0] "mesec" -msgstr[1] "mesecev" +msgstr[0] "mesecev" +msgstr[1] "mesec" +msgstr[2] "meseca" +msgstr[3] "meseci" #: utils/timesince.py:14 msgid "week" msgid_plural "weeks" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "tednov" +msgstr[1] "teden" +msgstr[2] "tedna" +msgstr[3] "tednov" #: utils/timesince.py:15 msgid "day" msgid_plural "days" -msgstr[0] "dan" -msgstr[1] "dni" +msgstr[0] "dni" +msgstr[1] "dan" +msgstr[2] "dneva" +msgstr[3] "dni" #: utils/timesince.py:16 msgid "hour" msgid_plural "hours" -msgstr[0] "ura" -msgstr[1] "ur" +msgstr[0] "ur" +msgstr[1] "ura" +msgstr[2] "uri" +msgstr[3] "ure" #: utils/timesince.py:17 msgid "minute" msgid_plural "minutes" -msgstr[0] "minuta" -msgstr[1] "minut" +msgstr[0] "minut" +msgstr[1] "minuta" +msgstr[2] "minuti" +msgstr[3] "minute" #: conf/global_settings.py:37 msgid "Bengali" @@ -1544,7 +1482,7 @@ msgstr "NemÅ¡ki" #: conf/global_settings.py:42 msgid "Greek" -msgstr "" +msgstr "GrÅ¡ki" #: conf/global_settings.py:43 msgid "English" @@ -1564,11 +1502,11 @@ msgstr "GaliÄanski" #: conf/global_settings.py:47 msgid "Hungarian" -msgstr "" +msgstr "Madžarski" #: conf/global_settings.py:48 msgid "Hebrew" -msgstr "" +msgstr "Hebrejski" #: conf/global_settings.py:49 msgid "Icelandic" @@ -1619,9 +1557,8 @@ msgid "Swedish" msgstr "Å vedski" #: conf/global_settings.py:61 -#, fuzzy msgid "Ukrainian" -msgstr "Brazilski" +msgstr "Ukrajinski" #: conf/global_settings.py:62 msgid "Simplified Chinese" @@ -1636,12 +1573,8 @@ msgid "This value must contain only letters, numbers and underscores." msgstr "To polje lahko vsebuje le Ärke, Å¡tevila in podÄrtaje (_)." #: core/validators.py:64 -#, fuzzy -msgid "" -"This value must contain only letters, numbers, underscores, dashes or " -"slashes." -msgstr "" -"To polje lahko vsebuje le Ärke, Å¡tevila, podÄrtaje (_) in poÅ¡evnice (/)." +msgid "This value must contain only letters, numbers, underscores, dashes or slashes." +msgstr "To polje lahko vsebuje le Ärke, Å¡tevila, podÄrtaje, poÅ¡evnice ali pomiÅ¡ljaje." #: core/validators.py:72 msgid "Uppercase letters are not allowed here." @@ -1691,23 +1624,18 @@ msgstr "Vnesite veljavni datum v zapisu YYYY-MM-DD (leto-mesec-dan)." msgid "Enter a valid time in HH:MM format." msgstr "Vnesite veljavni Äas v zapisu HH:MM (ura:minuta)." -#: core/validators.py:132 db/models/fields/__init__.py:468 +#: core/validators.py:132 +#: db/models/fields/__init__.py:468 msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format." -msgstr "" -"Vnesite veljavni datum/Äas v zapisu YYYY-MM-DD HH:MM (leto-mesec-dan ura:" -"minuta)" +msgstr "Vnesite veljavni datum/Äas v zapisu YYYY-MM-DD HH:MM (leto-mesec-dan ura:minuta)" #: core/validators.py:136 msgid "Enter a valid e-mail address." msgstr "Vnesite veljavni e-naslov." #: core/validators.py:148 -msgid "" -"Upload a valid image. The file you uploaded was either not an image or a " -"corrupted image." -msgstr "" -"Uploadjate veljavno sliko. Trenutna datoteka ni bila niti slika niti " -"okvarjena slika." +msgid "Upload a valid image. The file you uploaded was either not an image or a corrupted image." +msgstr "Uploadjate veljavno sliko. Trenutna datoteka ni bila niti slika niti okvarjena slika." #: core/validators.py:155 #, python-format @@ -1747,7 +1675,8 @@ msgstr "Pokvarjen XML: %s" msgid "Invalid URL: %s" msgstr "Neveljavni URL naslov: %s" -#: core/validators.py:206 core/validators.py:208 +#: core/validators.py:206 +#: core/validators.py:208 #, python-format msgid "The URL %s is a broken link." msgstr "URL povezava %s je polomljena." @@ -1762,6 +1691,8 @@ msgid "Watch your mouth! The word %s is not allowed here." msgid_plural "Watch your mouth! The words %s are not allowed here." msgstr[0] "Pazite na jezik! Beseda %s tu ni dovoljena." msgstr[1] "Pazite na jezik! Besede %s tu niso dovoljene." +msgstr[2] "Pazite na jezik! Besede %s tu niso dovoljene." +msgstr[3] "Pazite na jezik! Besede %s tu niso dovoljene." #: core/validators.py:236 #, python-format @@ -1772,7 +1703,8 @@ msgstr "To polje mora ustrezati polju '%s'." msgid "Please enter something for at least one field." msgstr "Prosim, vnesite nekaj v vsaj eno od polj." -#: core/validators.py:264 core/validators.py:275 +#: core/validators.py:264 +#: core/validators.py:275 msgid "Please enter both fields or leave them both empty." msgstr "Prosimo, izpolnite obe polji ali ju pustite obe prazni." @@ -1802,20 +1734,20 @@ msgstr "Prosim vnesite decimalno Å¡tevilo." #: core/validators.py:349 #, python-format msgid "Please enter a valid decimal number with at most %s total digit." -msgid_plural "" -"Please enter a valid decimal number with at most %s total digits." -msgstr[0] "Prosimo, vnesite veljavno decimalno Å¡tevilo z najveÄ %s Å¡tevkami." -msgstr[1] "Prosimo, vnesite veljavno decimalno Å¡tevilo z najveÄ %s Å¡tevkami." +msgid_plural "Please enter a valid decimal number with at most %s total digits." +msgstr[0] "Prosimo, vnesite veljavno decimalno Å¡tevilo z najveÄ %s Å¡tevko." +msgstr[1] "Prosimo, vnesite veljavno decimalno Å¡tevilo z najveÄ %s Å¡tevkama." +msgstr[2] "Prosimo, vnesite veljavno decimalno Å¡tevilo z najveÄ %s Å¡tevkami." +msgstr[3] "Prosimo, vnesite veljavno decimalno Å¡tevilo z najveÄ %s Å¡tevkami." #: core/validators.py:352 #, python-format msgid "Please enter a valid decimal number with at most %s decimal place." -msgid_plural "" -"Please enter a valid decimal number with at most %s decimal places." -msgstr[0] "" -"Prosimo, vnesite veljavno decimalno Å¡tevilo z najveÄ %s decimalnimi mesti." -msgstr[1] "" -"Prosimo, vnesite veljavno decimalno Å¡tevilo z najveÄ %s decimalnimi mesti." +msgid_plural "Please enter a valid decimal number with at most %s decimal places." +msgstr[0] "Prosimo, vnesite veljavno decimalno Å¡tevilo z najveÄ %s decimalnim mestom." +msgstr[1] "Prosimo, vnesite veljavno decimalno Å¡tevilo z najveÄ %s decimalnimi mesti." +msgstr[2] "Prosimo, vnesite veljavno decimalno Å¡tevilo z najveÄ %s decimalnimi mesti." +msgstr[3] "Prosimo, vnesite veljavno decimalno Å¡tevilo z najveÄ %s decimalnimi mesti." #: core/validators.py:362 #, python-format @@ -1842,94 +1774,68 @@ msgstr "Iz %s nisem mogel izloÄiti niÄesar." #: core/validators.py:429 #, python-format -msgid "" -"The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'." +msgid "The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'." msgstr "URL %(url)s je vrnil neveljavni Content-Type '%(contenttype)s'." #: core/validators.py:462 #, python-format -msgid "" -"Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with " -"\"%(start)s\".)" -msgstr "" -"Prosimo, zaprite nezaprto %(tag)s oznako v vrstici %(line)s. (Vrstica se " -"zaÄne z \"%(start)s\".)" +msgid "Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with \"%(start)s\".)" +msgstr "Prosimo, zaprite nezaprto %(tag)s oznako v vrstici %(line)s. (Vrstica se zaÄne z \"%(start)s\".)" #: core/validators.py:466 #, python-format -msgid "" -"Some text starting on line %(line)s is not allowed in that context. (Line " -"starts with \"%(start)s\".)" -msgstr "" -"Tekst z zaÄetka vrstice %(line)s ni dovoljen v tem kontekstu. (Vrstica se " -"zaÄne z \"%(start)s\".)" +msgid "Some text starting on line %(line)s is not allowed in that context. (Line starts with \"%(start)s\".)" +msgstr "Tekst z zaÄetka vrstice %(line)s ni dovoljen v tem kontekstu. (Vrstica se zaÄne z \"%(start)s\".)" #: core/validators.py:471 -#, fuzzy, python-format -msgid "" -"\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%" -"(start)s\".)" -msgstr "" -"\"<%(tag)s>\" v vrstici %(line)s je neveljavna oznaka. (Vrstica se zaÄne z " -"\"%(start)s\".)" +#, python-format +msgid "\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%(start)s\".)" +msgstr "\"%(attr)s\" v vrstici %(line)s je neveljavna oznaka. (Vrstica se zaÄne z \"%(start)s\".)" #: core/validators.py:476 #, python-format -msgid "" -"\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%" -"(start)s\".)" -msgstr "" -"\"<%(tag)s>\" v vrstici %(line)s je neveljavna oznaka. (Vrstica se zaÄne z " -"\"%(start)s\".)" +msgid "\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%(start)s\".)" +msgstr "\"<%(tag)s>\" v vrstici %(line)s je neveljavna oznaka. (Vrstica se zaÄne z \"%(start)s\".)" #: core/validators.py:480 #, python-format -msgid "" -"A tag on line %(line)s is missing one or more required attributes. (Line " -"starts with \"%(start)s\".)" -msgstr "" -"Oznaki v vrstici %(line)s manjka eden ali veÄ nujnih atributov (Vrstica se " -"zaÄne z \"%(start)s\".)" +msgid "A tag on line %(line)s is missing one or more required attributes. (Line starts with \"%(start)s\".)" +msgstr "Oznaki na vrstici %(line)s manjka eden ali veÄ zahtevanih parametrov. (Vrstica se zaÄne z \"%(start)s\".)" #: core/validators.py:485 #, python-format -msgid "" -"The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line " -"starts with \"%(start)s\".)" -msgstr "" -"Atribut \"%(attr)s\" v vrstici %(line)s vsebuje neveljavno vrednost. " -"(Vrstica se zaÄne z \"%(start)s\".)" +msgid "The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line starts with \"%(start)s\".)" +msgstr "Atribut \"%(attr)s\" v vrstici %(line)s vsebuje neveljavno vrednost. (Vrstica se zaÄne z \"%(start)s\".)" #: db/models/manipulators.py:302 #, python-format msgid "%(object)s with this %(type)s already exists for the given %(field)s." -msgstr "%(object)s s tem %(type)s že obstaja za veljavno (%field)s." +msgstr "%(object)s s tem %(type)s že obstaja za dane %(field)s." #: db/models/fields/__init__.py:40 #, python-format msgid "%(optname)s with this %(fieldname)s already exists." msgstr "%(optname)s s tem %(fieldname)s že obstaja." -#: db/models/fields/__init__.py:114 db/models/fields/__init__.py:265 -#: db/models/fields/__init__.py:542 db/models/fields/__init__.py:553 +#: db/models/fields/__init__.py:114 +#: db/models/fields/__init__.py:265 +#: db/models/fields/__init__.py:542 +#: db/models/fields/__init__.py:553 #: forms/__init__.py:346 msgid "This field is required." msgstr "To polje je obvezno" #: db/models/fields/__init__.py:337 -#, fuzzy msgid "This value must be an integer." -msgstr "Ta vrednost mora biti potenca od %s." +msgstr "Ta vrednost mora biti Å¡tevilo." #: db/models/fields/__init__.py:369 -#, fuzzy msgid "This value must be either True or False." -msgstr "Ta vrednost mora biti potenca od %s." +msgstr "Ta vrednost mora biti \"True\" ali \"False\"." #: db/models/fields/__init__.py:385 -#, fuzzy msgid "This field cannot be null." -msgstr "To polje ni veljavno." +msgstr "To polje ne more biti prazno." #: db/models/fields/__init__.py:562 msgid "Enter a valid filename." @@ -1941,39 +1847,38 @@ msgid "Please enter a valid %s." msgstr "Prosimo, vnesite veljaven %s." #: db/models/fields/related.py:579 -#, fuzzy msgid "Separate multiple IDs with commas." msgstr "VeÄ ID-jev loÄite z vejicami." #: db/models/fields/related.py:581 -#, fuzzy -msgid "" -"Hold down \"Control\", or \"Command\" on a Mac, to select more than one." -msgstr "" -" Stisni \"Control\" (ali \"Command\" na Mac-u), da izbereÅ¡ veÄ kot enega." +msgid "Hold down \"Control\", or \"Command\" on a Mac, to select more than one." +msgstr "Držite \"Control\" (ali \"Command\" na Mac-u), za izbiro veÄ kot enega." #: db/models/fields/related.py:625 #, python-format msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid." -msgid_plural "" -"Please enter valid %(self)s IDs. The values %(value)r are invalid." -msgstr[0] "" -"Prosimo, vnesite veljavni %(self)s ID-je. Vrednost %(value)r ni veljavna." -msgstr[1] "" -"Prosimo, vnesite veljavni %(self)s ID-je. Vrednosti %(value)r niso veljavne." +msgid_plural "Please enter valid %(self)s IDs. The values %(value)r are invalid." +msgstr[0] "Prosimo, vnesite veljavne %(self)s ID-je. Vrednost %(value)r ni veljavna." +msgstr[1] "Prosimo, vnesite veljavni %(self)s ID. Vrednosti %(value)r niso veljavne." +msgstr[2] "Prosimo, vnesite veljavne %(self)s ID-je. Vrednosti %(value)r niso veljavne." +msgstr[3] "Prosimo, vnesite veljavne %(self)s ID-je. Vrednosti %(value)r niso veljavne." #: forms/__init__.py:380 #, python-format msgid "Ensure your text is less than %s character." msgid_plural "Ensure your text is less than %s characters." -msgstr[0] "Poskrbite, da bo tekst krajÅ¡i do %s znakov." -msgstr[1] "Poskrbite, da bo tekst krajÅ¡i od %s znakov." +msgstr[0] "Poskrbite, da bo tekst krajÅ¡i od %s znakov." +msgstr[1] "Poskrbite, da bo tekst krajÅ¡i od %s znaka." +msgstr[2] "Poskrbite, da bo tekst krajÅ¡i od %s znakov." +msgstr[3] "Poskrbite, da bo tekst krajÅ¡i od %s znakov." #: forms/__init__.py:385 msgid "Line breaks are not allowed here." msgstr "Prelomi vrstice tu niso dovoljeni." -#: forms/__init__.py:480 forms/__init__.py:551 forms/__init__.py:589 +#: forms/__init__.py:480 +#: forms/__init__.py:551 +#: forms/__init__.py:589 #, python-format msgid "Select a valid choice; '%(data)s' is not in %(choices)s." msgstr "Izberite veljavno možnost; '%(data)s' ni v %(choices)s." @@ -1998,23 +1903,24 @@ msgstr "Vnesite celo Å¡tevilo med 0 in 32,767." msgid "yes,no,maybe" msgstr "ja,ne,morda" -#~ msgid "Comment" -#~ msgstr "Komentar" +msgid "Comment" +msgstr "Komentar" + +msgid "Comments" +msgstr "Komentarji" -#~ msgid "Comments" -#~ msgstr "Komentarji" +msgid "String (up to 50)" +msgstr "Niz (do 50 znakov)" -#~ msgid "String (up to 50)" -#~ msgstr "Niz (do 50 znakov)" +msgid "label" +msgstr "oznaka" -#~ msgid "label" -#~ msgstr "oznaka" +msgid "package" +msgstr "paket" -#~ msgid "package" -#~ msgstr "paket" +msgid "packages" +msgstr "paketi" -#~ msgid "packages" -#~ msgstr "paketi" +msgid "Slovene" +msgstr "Slovensko" -#~ msgid "Slovene" -#~ msgstr "Slovenski" diff --git a/django/conf/locale/ta/LC_MESSAGES/django.mo b/django/conf/locale/ta/LC_MESSAGES/django.mo Binary files differnew file mode 100644 index 0000000000..c85327d06b --- /dev/null +++ b/django/conf/locale/ta/LC_MESSAGES/django.mo diff --git a/django/conf/locale/ta/LC_MESSAGES/django.po b/django/conf/locale/ta/LC_MESSAGES/django.po new file mode 100644 index 0000000000..7637bb9cdb --- /dev/null +++ b/django/conf/locale/ta/LC_MESSAGES/django.po @@ -0,0 +1,2111 @@ +# translation of django.po to +# translation of django_aa.po to +# translation of django_aa.po to tamil +# Parthan <parthan@au-kbc.org>, 2006. +# R Hariram Aatreya <rha@localhost.localdomain>, 2006. +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2006-05-16 10:14+0200\n" +"PO-Revision-Date: 2006-07-18 16:47+0530\n" +"Last-Translator: R Hariram Aatreya <rha@localhost.localdomain>\n" +"Language-Team: <en@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.9\n" + +#: contrib/comments/models.py:67 contrib/comments/models.py:166 +msgid "object ID" +msgstr "அடையாளமà¯" + +#: contrib/comments/models.py:68 +msgid "headline" +msgstr "தலையஙà¯à®•à®®à¯" + +#: contrib/comments/models.py:69 contrib/comments/models.py:90 +#: contrib/comments/models.py:167 +msgid "comment" +msgstr "கà¯à®±à®¿à®ªà¯à®ªà¯" + +#: contrib/comments/models.py:70 +msgid "rating #1" +msgstr "#1 தரவரிசை" + +#: contrib/comments/models.py:71 +msgid "rating #2" +msgstr "#2 தரவரிசை" + +#: contrib/comments/models.py:72 +msgid "rating #3" +msgstr "#3 தரவரிசை" + +#: contrib/comments/models.py:73 +msgid "rating #4" +msgstr "#4 தரவரிசை" + +#: contrib/comments/models.py:74 +msgid "rating #5" +msgstr "#5 தரவரிசை" + +#: contrib/comments/models.py:75 +msgid "rating #6" +msgstr "#6 தரவரிசை" + +#: contrib/comments/models.py:76 +msgid "rating #7" +msgstr "#7 தரவரிசை" + +#: contrib/comments/models.py:77 +msgid "rating #8" +msgstr "#8 தரவரிசை" + +#: contrib/comments/models.py:82 +msgid "is valid rating" +msgstr "à®…à®™à¯à®•ீகரிகà¯à®•பà¯à®ªà®Ÿà¯à®Ÿ தரவரிசை" + +#: contrib/comments/models.py:83 contrib/comments/models.py:169 +msgid "date/time submitted" +msgstr "தேதிநேரம௠சமரà¯à®ªà¯à®ªà®¿à®•à¯à®•பà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯" + +#: contrib/comments/models.py:84 contrib/comments/models.py:170 +msgid "is public" +msgstr "பொதà¯à®µà®¾à®©à®¤à¯" + +#: contrib/comments/models.py:85 contrib/admin/views/doc.py:289 +msgid "IP address" +msgstr "ip விலாசமà¯" + +#: contrib/comments/models.py:86 +msgid "is removed" +msgstr "நீகà¯à®•படà¯à®Ÿà®¤à¯" + +#: contrib/comments/models.py:86 +msgid "" +"Check this box if the comment is inappropriate. A \"This comment has been " +"removed\" message will be displayed instead." +msgstr "கà¯à®±à®¿à®ªà¯à®ªà¯ செரியாக இலà¯à®²à¯ˆà®¯à¯†à®©à¯à®±à®¾à®²à¯ இநà¯à®¤à¯ பெடà¯à®Ÿà®¿à®¯à®¿à®²à¯ கà¯à®±à®¿à®¯à®¿à®Ÿà®µà¯à®®à¯. இதறà¯à®•௠பதிலாக \"இநà¯à®¤ கà¯à®±à®¿à®ªà¯à®ªà¯ நீகà¯à®•படà¯à®Ÿà®¤à¯\" காணà¯à®ªà®¿à®•à¯à®•படà¯à®®à¯." + +#: contrib/comments/models.py:91 +msgid "comments" +msgstr "கà¯à®±à®¿à®ªà¯à®ªà¯" + +#: contrib/comments/models.py:131 contrib/comments/models.py:207 +msgid "Content object" +msgstr "பொரà¯à®³à¯ அடகà¯à®• object" + +#: contrib/comments/models.py:159 +#, python-format +msgid "" +"Posted by %(user)s at %(date)s\n" +"\n" +"%(comment)s\n" +"\n" +"http://%(domain)s%(url)s" +msgstr "" +"%(user)s ஆல௠%(date)s இல௠அளிகà¯à®•பà¯à®ªà®Ÿà¯à®Ÿà®¤à¯ \n" +"\n" +"%(comment)s\n" +"\n" +"http://%(domain)s%(url)s" + +#: contrib/comments/models.py:168 +msgid "person's name" +msgstr "நபரின௠பெயரà¯" + +#: contrib/comments/models.py:171 +msgid "ip address" +msgstr "ip விலாசமà¯" + +#: contrib/comments/models.py:173 +msgid "approved by staff" +msgstr "பணியாளரà¯à®•ளால௠அனà¯à®®à®¤à®¿à®•à¯à®•பà¯à®ªà®Ÿà¯à®Ÿà®¤à¯" + +#: contrib/comments/models.py:176 +msgid "free comment" +msgstr "சà¯à®¤à®¨à¯à®¤à®°à®®à®¾à®© கà¯à®±à®¿à®ªà¯à®ªà¯" + +#: contrib/comments/models.py:177 +msgid "free comments" +msgstr "சà¯à®¤à®¨à¯à®¤à®°à®®à®¾à®© கà¯à®±à®¿à®ªà¯à®ªà¯" + +#: contrib/comments/models.py:233 +msgid "score" +msgstr "மதிபà¯à®ªà¯€à®Ÿà¯" + +#: contrib/comments/models.py:234 +msgid "score date" +msgstr "மதிபà¯à®ªà¯€à®Ÿà¯ தேதி" + +#: contrib/comments/models.py:237 +msgid "karma score" +msgstr "கரà¯à®®à®¾ மதிபà¯à®ªà¯€à®Ÿà¯" + +#: contrib/comments/models.py:238 +msgid "karma scores" +msgstr "கரà¯à®®à®¾ மதிபà¯à®ªà¯€à®Ÿà¯" + +#: contrib/comments/models.py:242 +#, python-format +msgid "%(score)d rating by %(user)s" +msgstr "%(user)s ஈடà¯à®Ÿà®¯ %(score)d " + +#: contrib/comments/models.py:258 +#, python-format +msgid "" +"This comment was flagged by %(user)s:\n" +"\n" +"%(text)s" +msgstr "" +"இநà¯à®¤ கà¯à®±à®¿à®ªà¯à®ªà¯ %(user)s ஆல௠கà¯à®±à®¿à®•à¯à®•படà¯à®Ÿà®¤à¯:\n" +"\n" +"%(text)s" + +#: contrib/comments/models.py:265 +msgid "flag date" +msgstr "கà¯à®±à®¿à®¯à®¿à®©à¯ தேதி" + +#: contrib/comments/models.py:268 +msgid "user flag" +msgstr "பயனாளர௠கà¯à®±à®¿" + +#: contrib/comments/models.py:269 +msgid "user flags" +msgstr "பயனாளர௠கà¯à®±à®¿à®•ளà¯" + +#: contrib/comments/models.py:273 +#, python-format +msgid "Flag by %r" +msgstr "%r ஆல௠கà¯à®±à®¿à®•à¯à®•பà¯à®ªà®Ÿà¯à®Ÿà®¤à¯" + +#: contrib/comments/models.py:278 +msgid "deletion date" +msgstr "நீகà¯à®•பà¯à®ªà®Ÿà¯à®Ÿ தேதி" + +#: contrib/comments/models.py:280 +msgid "moderator deletion" +msgstr "மடà¯à®Ÿà¯Šà®±à¯à®¤à¯à®¤à®¾à®²à¯ நீகà¯à®•பà¯à®ªà®Ÿà¯à®Ÿà®¤à¯" + +#: contrib/comments/models.py:281 +msgid "moderator deletions" +msgstr "மடà¯à®Ÿà¯Šà®±à¯à®¤à¯à®¤à®¾à®²à¯ நீகà¯à®•பà¯à®ªà®Ÿà¯à®Ÿà®¤à¯" + +#: contrib/comments/models.py:285 +#, python-format +msgid "Moderator deletion by %r" +msgstr "மடà¯à®Ÿà¯Šà®±à¯à®¤à¯à®¤à®¾à®²à¯ நீகà¯à®•பà¯à®ªà®Ÿà¯à®Ÿà®¤à¯ %r" + +#: contrib/comments/views/karma.py:19 +msgid "Anonymous users cannot vote" +msgstr "அடயாளà¯à®®à¯ இலà¯à®²à®¾à®¤ பயனாளறால௠வாகà¯à®•ளிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯" + +#: contrib/comments/views/karma.py:23 +msgid "Invalid comment ID" +msgstr "செலà¯à®²à®¾à®¤ கà¯à®±à®¿à®ªà¯à®ªà¯ ID" + +#: contrib/comments/views/karma.py:25 +msgid "No voting for yourself" +msgstr "உஙà¯à®•ளை நீஙà¯à®•ளே தேரà¯à®µà¯ செயà¯à®¤à¯ கொளà¯à®³ à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯" + +#: contrib/comments/views/comments.py:28 +msgid "This rating is required because you've entered at least one other rating." +msgstr "மறà¯à®±à¯Šà®°à¯ தரவரிசை அளிகà¯à®•à¯à®ªà®Ÿà¯à®Ÿà®¤à®¾à®²à¯ இநà¯à®¤ தரவரிசை தேவைபà¯à®ªà®Ÿà¯à®•ிறதà¯." + +#: contrib/comments/views/comments.py:112 +#, python-format +msgid "" +"This comment was posted by a user who has posted fewer than %(count)s " +"comment:\n" +"\n" +"%(text)s" +"This comment was posted by a user who has posted fewer than %(count)s " +"comments:\n" +"\n" +"%(text)s" +msgstr "" +"%(count)s கà¯à®±à¯ˆà®µà®¾à®• அளிதà¯à®¤ பயனாளரால௠இநà¯à®¤ கà¯à®°à®¿à®ªà¯à®ªà¯ˆ அளà¯à®¤à¯à®¤à®ªà®Ÿà®¤à¯:\n" +"\n" +"%(text)s" +"%(count)s கà¯à®±à¯ˆà®µà®¾à®• அளிதà¯à®¤ பயனாளரால௠இநà¯à®¤ கà¯à®°à®¿à®ªà¯à®ªà¯ˆ அளà¯à®¤à¯à®¤à®ªà®Ÿà®¤à¯:\n" +"\n" +"%(text)s" + +#: contrib/comments/views/comments.py:117 +#, python-format +msgid "" +"This comment was posted by a sketchy user:\n" +"\n" +"%(text)s" +msgstr "" +"à®®à¯à®´à¯à®®à¯ˆà®¯à®¾à®© விவரஙகளை அளிகà¯à®•ாத பயனாளறால௠கொடà¯à®•à¯à®•பà¯à®ªà®Ÿà¯à®Ÿà®¤à¯:\n" +"%(text)s" + +#: contrib/comments/views/comments.py:189 +#: contrib/comments/views/comments.py:280 +msgid "Only POSTs are allowed" +msgstr "POSTகளà¯à®•à¯à®•௠மடà¯à®Ÿà¯à®®à¯ அனà¯à®®à®¤à®¿ உணà¯à®Ÿà¯" + +#: contrib/comments/views/comments.py:193 +#: contrib/comments/views/comments.py:284 +msgid "One or more of the required fields wasn't submitted" +msgstr "ஒனà¯à®±à¯ அலà¯à®²à®¤à¯ ஒனà¯à®±à®¿à®±à¯à®•௠மேறà¯à®ªà¯à®ªà®Ÿà¯à®Ÿ பà¯à®²à®™à¯à®•ள௠சமறà¯à®ªà®¿à®•à¯à®•பà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ" + +#: contrib/comments/views/comments.py:197 +#: contrib/comments/views/comments.py:286 +msgid "Somebody tampered with the comment form (security violation)" +msgstr "எவறோ கà¯à®°à®¿à®ªà¯à®ªà¯à®±à¯ˆà®¯à¯ˆ செதபà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿à®µà®¿à®Ÿà¯à®Ÿà®¾à®±à¯à®•ள௠(பாதà¯à®•ாபà¯à®ªà¯ மீறலà¯)" + +#: contrib/comments/views/comments.py:207 +#: contrib/comments/views/comments.py:292 +msgid "" +"The comment form had an invalid 'target' parameter -- the object ID was " +"invalid" +msgstr "கà¯à®±à®¿à®ªà¯à®ªà¯à®±à¯ˆ படிவதà¯à®¤à®¿à®²à¯ à®®à¯à®±à¯ˆà®¯à®¾à®© இலகà¯à®•௠அளவà¯à®°à¯à®•à¯à®• இலà¯à®²à¯ˆ -- object ID à®®à¯à®±à¯ˆà®¯à®¾à®©à®¤à®¾à®• இலà¯à®²à¯ˆ" + +#: contrib/comments/views/comments.py:257 +#: contrib/comments/views/comments.py:321 +msgid "The comment form didn't provide either 'preview' or 'post'" +msgstr "கà¯à®±à®¿à®ªà¯à®ªà¯ படிவம௠மà¯à®©à¯à®©à¯‹à®Ÿà¯à®Ÿà®®à¯ அலà¯à®²à®¤à¯ பிறà¯à®ªà®Ÿà¯à®Ÿà®¤à¯ˆ வழஙà¯à®•விலà¯à®²à¯ˆ." + +#: contrib/comments/templates/comments/form.html:6 +#: contrib/comments/templates/comments/form.html:8 +#: contrib/admin/templates/admin/login.html:17 +msgid "Username:" +msgstr "பயணர௠பெயரà¯:" + +#: contrib/comments/templates/comments/form.html:6 +#: contrib/admin/templates/admin/login.html:20 +msgid "Password:" +msgstr "கடவà¯à®šà¯à®šà¯†à®¾à®²à¯:" + +#: contrib/comments/templates/comments/form.html:6 +msgid "Forgotten your password?" +msgstr "கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆ மறநà¯à®¤à¯à®µà®¿à®Ÿà¯à®Ÿà¯€à®°à®¾?" + +#: contrib/comments/templates/comments/form.html:8 +#: contrib/admin/templates/admin/object_history.html:3 +#: contrib/admin/templates/admin/change_list.html:5 +#: contrib/admin/templates/admin/base.html:23 +#: contrib/admin/templates/admin/delete_confirmation.html:3 +#: contrib/admin/templates/admin/change_form.html:10 +#: contrib/admin/templates/registration/password_change_done.html:3 +#: contrib/admin/templates/registration/password_change_form.html:3 +#: contrib/admin/templates/admin_doc/bookmarklets.html:4 +#: contrib/admin/templates/admin_doc/view_detail.html:4 +#: contrib/admin/templates/admin_doc/template_tag_index.html:5 +#: contrib/admin/templates/admin_doc/template_detail.html:4 +#: contrib/admin/templates/admin_doc/template_filter_index.html:5 +#: contrib/admin/templates/admin_doc/missing_docutils.html:4 +#: contrib/admin/templates/admin_doc/view_index.html:5 +#: contrib/admin/templates/admin_doc/model_detail.html:3 +#: contrib/admin/templates/admin_doc/index.html:4 +#: contrib/admin/templates/admin_doc/model_index.html:5 +msgid "Log out" +msgstr "வெளியேறà¯" + +#: contrib/comments/templates/comments/form.html:12 +msgid "Ratings" +msgstr "விகிதமà¯" + +#: contrib/comments/templates/comments/form.html:12 +#: contrib/comments/templates/comments/form.html:23 +msgid "Required" +msgstr "தேவைபà¯à®ªà®Ÿà¯à®•ிறத௠" + +#: contrib/comments/templates/comments/form.html:12 +#: contrib/comments/templates/comments/form.html:23 +msgid "Optional" +msgstr "விரà¯à®ªà¯à®ªà®¤à¯à®¤à¯‡à®°à¯à®µà¯" + +#: contrib/comments/templates/comments/form.html:23 +msgid "Post a photo" +msgstr "பà¯à®•ைபà¯à®ªà®Ÿà®¤à¯à®¤à¯ˆ அணà¯à®ªà¯à®ªà¯" + +#: contrib/comments/templates/comments/form.html:27 +#: contrib/comments/templates/comments/freeform.html:5 +msgid "Comment:" +msgstr "விவரமà¯:" + +# translation of django_ab.po to +# translation of django_ab.po to +# translation of django_ab.po to +# translation of django_ab.po to +# translation of django_ab.po to +# translation of django_ab.po to +# translation of django_ab.po to +# translation of django_ab.po to +# translation of django_ab.po to +# translation of django_ab.po to +# translation of django_ab.po to +# translation of django_ab.po to +# translation of django_ab.po to +# translation of django_ab.po to +# translation of django_ab.po to +# translation of django_ab.po to +# translation of django_ab.po to +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# R Hariram Aatreya <rha@localhost.localdomain>, 2006. +#: contrib/comments/templates/comments/form.html:32 +#: contrib/comments/templates/comments/freeform.html:9 +msgid "Preview comment" +msgstr "கà¯à®±à®¿à®ªà¯à®ªà¯ˆ à®®à¯à®©à¯à®©à¯‡à®±à¯à®±à®®à®¿à®Ÿà¯" + +#: contrib/comments/templates/comments/freeform.html:4 +msgid "Your name:" +msgstr "உஙà¯à®•ளà¯à®ªà¯†à®¯à®°à¯:" + +#: contrib/admin/filterspecs.py:40 +#, python-format +msgid "" +"<h3>By %s:</h3>\n" +"<ul>\n" +msgstr "" +"<h3> %s ஆலà¯:</h3>\n" +"<ul>\n" + +#: contrib/admin/filterspecs.py:70 contrib/admin/filterspecs.py:88 +#: contrib/admin/filterspecs.py:143 +msgid "All" +msgstr "அணைதà¯à®¤à¯à®®à¯" + +#: contrib/admin/filterspecs.py:109 +msgid "Any date" +msgstr "எநà¯à®¤ தேதியà¯à®®à¯" + +#: contrib/admin/filterspecs.py:110 +msgid "Today" +msgstr "இணà¯à®±à¯" + +#: contrib/admin/filterspecs.py:113 +msgid "Past 7 days" +msgstr "கடநà¯à®¤ 7 நாடà¯à®•ளிலà¯" + +#: contrib/admin/filterspecs.py:115 +msgid "This month" +msgstr "இநà¯à®¤ மாதமà¯" + +#: contrib/admin/filterspecs.py:117 +msgid "This year" +msgstr "இநà¯à®¤ வரà¯à®Ÿà®®à¯" + +#: contrib/admin/filterspecs.py:143 +msgid "Yes" +msgstr "ஆமà¯" + +#: contrib/admin/filterspecs.py:143 +msgid "No" +msgstr "இலà¯à®²à¯ˆ" + +#: contrib/admin/filterspecs.py:150 +msgid "Unknown" +msgstr "தெரியாத" + +#: contrib/admin/models.py:16 +msgid "action time" +msgstr "செயல௠நேரமà¯" + +#: contrib/admin/models.py:19 +msgid "object id" +msgstr "பொரà¯à®³à¯ அடையாளமà¯" + +#: contrib/admin/models.py:20 +msgid "object repr" +msgstr "பொரà¯à®³à¯ உரà¯à®µà®•ிதà¯à®¤à®®à¯" + +#: contrib/admin/models.py:21 +msgid "action flag" +msgstr "செயரà¯à®•à¯à®±à®¿" + +#: contrib/admin/models.py:22 +msgid "change message" +msgstr "செயà¯à®¤à®¿à®¯à¯ˆ மாறà¯à®±à¯" + +#: contrib/admin/models.py:25 +msgid "log entry" +msgstr "பà¯à®•à¯à®ªà®¤à®¿à®µà¯ உளà¯à®³à¯€à®Ÿà¯" + +#: contrib/admin/models.py:26 +msgid "log entries" +msgstr "பà¯à®•à¯à®ªà®¤à®¿à®µà¯ உளà¯à®³à¯€à®Ÿà¯" + +#: contrib/admin/templatetags/admin_list.py:228 +msgid "All dates" +msgstr "அனைதà¯à®¤à¯ தேதியà¯à®®à¯" + +#: contrib/admin/views/decorators.py:9 contrib/auth/forms.py:36 +#: contrib/auth/forms.py:41 +msgid "" +"Please enter a correct username and password. Note that both fields are case-" +"sensitive." +msgstr "தயவà¯à®šà¯†à®¯à¯à®¤à¯ சரியான பயனரà¯à®ªà®ªà¯†à®¯à®°à¯ மறà¯à®±à¯à®®à¯ கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆ உளà¯à®³à¯à®³à®¿à®Ÿà®µà¯à®®à¯. இரணà¯à®Ÿà¯à®®à¯ எழà¯à®¤à¯à®¤à¯à®µà®•ையை சாரà¯à®¨à¯à®¤à®¤à¯." + +#: contrib/admin/views/decorators.py:23 +#: contrib/admin/templates/admin/login.html:25 +msgid "Log in" +msgstr "உளà¯à®³à¯‡ போ" + +#: contrib/admin/views/decorators.py:61 +msgid "" +"Please log in again, because your session has expired. Don't worry: Your " +"submission has been saved." +msgstr "தயவà¯à®šà¯†à®¯à¯à®¤à¯ மறà¯à®ªà®Ÿà®¿à®¯à¯à®®à¯ பà¯à®•à¯à®ªà®¤à®¿à®µà¯ செயà¯. à®à®©à¯†à®©à¯à®±à®¾à®³à¯ காலம௠மà¯à®Ÿà®¿à®µà®Ÿà¯ˆà®¨à¯à®¤à®µà¯. கவலை படவேணà¯à®Ÿà®¾à®®à¯: உஙà¯à®•ளà¯à®Ÿà¯ˆà®¯ அணà¯à®ªà¯à®ªà¯à®¤à®²à¯ சேமிகà¯à®•பà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯. " + +#: contrib/admin/views/decorators.py:68 +msgid "" +"Looks like your browser isn't configured to accept cookies. Please enable " +"cookies, reload this page, and try again." +msgstr "உஙà¯à®•ளà¯à®Ÿà¯ˆà®¯ உலாவி தறà¯à®•ால நிரலà¯à®•ளை அணà¯à®®à®¤à®¿à®•à¯à®•ாதவாற௠உளà¯à®³à®®à¯ˆà®•à¯à®•ப௠படà¯à®Ÿà®µà®¾à®±à¯ தெரிகிறதà¯. தயவà¯à®šà¯†à®¯à¯à®¤à¯ தறà¯à®•ாலிக நிரலை செயலà¯à®ªà®Ÿ செயà¯à®¤à¯, பகà¯à®•தà¯à®¤à¯ˆ மறà¯à®ªà®Ÿà®¿ உளà¯à®³à¯à®µà®¾à®™à¯à®•வà¯à®®à¯." + +#: contrib/admin/views/decorators.py:82 +msgid "Usernames cannot contain the '@' character." +msgstr "பயனர௠பெயர௠'@' கà¯à®±à®¿à®¯à¯€à®Ÿà¯à®Ÿà¯ˆ கொணà¯à®Ÿà®¿à®°à¯à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯." + +#: contrib/admin/views/decorators.py:84 +#, python-format +msgid "Your e-mail address is not your username. Try '%s' instead." +msgstr "உனà¯à®•ள௠மிணà¯à®…ஞà¯à®šà®³à¯ à®®à¯à®•வரிஉஙà¯à®•ள௠பயனர௠பெயர௠இலà¯à®²à¯ˆ. '%s' யை à®®à¯à®¯à®±à¯à®šà¯à®šà®¿ செயà¯à®¯à®µà¯à®®à¯. " + +#: contrib/admin/views/main.py:226 +msgid "Site administration" +msgstr "இணைய மேளானà¯à®®à¯ˆ" + +#: contrib/admin/views/main.py:260 +#, python-format +msgid "The %(name)s \"%(obj)s\" was added successfully." +msgstr "%(name)s \"%(obj)s\" வெறà¯à®±à®¿à®•ரமாக சேரà¯à®•à¯à®•பà¯à®ªà®Ÿà¯à®Ÿà®¤à¯." + +#: contrib/admin/views/main.py:264 contrib/admin/views/main.py:348 +msgid "You may edit it again below." +msgstr "நீஙà¯à®•ள௠மறà¯à®ªà®Ÿà®¿à®¯à¯à®®à¯ தொகà¯à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à¯à®®à¯. " + +#: contrib/admin/views/main.py:272 contrib/admin/views/main.py:357 +#, python-format +msgid "You may add another %s below." +msgstr "நீஙà¯à®•ள௠மறà¯à®± %s யை கீழே சேரà¯à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à¯à®®à¯." + +#: contrib/admin/views/main.py:290 +#, python-format +msgid "Add %s" +msgstr "%s யை சேரà¯" + +#: contrib/admin/views/main.py:336 +#, python-format +msgid "Added %s." +msgstr "%s சேரà¯à®•à¯à®•பà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯." + +#: contrib/admin/views/main.py:336 contrib/admin/views/main.py:338 +#: contrib/admin/views/main.py:340 +msgid "and" +msgstr "மறà¯à®±à¯à®®à¯" + +#: contrib/admin/views/main.py:338 +#, python-format +msgid "Changed %s." +msgstr "%s மாறà¯à®±à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯." + +#: contrib/admin/views/main.py:340 +#, python-format +msgid "Deleted %s." +msgstr "%s அழிகà¯à®•பà¯à®ªà®Ÿà¯à®Ÿà®¤à¯." + +#: contrib/admin/views/main.py:343 +msgid "No fields changed." +msgstr "எநà¯à®¤ பà¯à®²à®®à¯à®®à¯ மாறவிலà¯à®²à¯ˆ." + +#: contrib/admin/views/main.py:346 +#, python-format +msgid "The %(name)s \"%(obj)s\" was changed successfully." +msgstr " %(name)s \"%(obj)s\" வெறà¯à®±à®¿à®•ரமாக மாறà¯à®±à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯." + +#: contrib/admin/views/main.py:354 +#, python-format +msgid "The %(name)s \"%(obj)s\" was added successfully. You may edit it again below." +msgstr "%(name)s \"%(obj)s\" வெறà¯à®±à®¿à®•ரமாக சேரà¯à®•à¯à®•பà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯. நீஙà¯à®•ள௠கீழே தொகà¯à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à¯à®®à¯." + +#: contrib/admin/views/main.py:392 +#, python-format +msgid "Change %s" +msgstr "%s யை மாறà¯à®±à¯" + +#: contrib/admin/views/main.py:470 +#, python-format +msgid "One or more %(fieldname)s in %(name)s: %(obj)s" +msgstr "%(name)s ல௠உளà¯à®³ %(fieldname)s: %(obj)s" + +#: contrib/admin/views/main.py:475 +#, python-format +msgid "One or more %(fieldname)s in %(name)s:" +msgstr "%(name)s ல௠உளà¯à®³ %(fieldname)s:" + +#: contrib/admin/views/main.py:508 +#, python-format +msgid "The %(name)s \"%(obj)s\" was deleted successfully." +msgstr "%(name)s \"%(obj)s\" வெறà¯à®±à®¿à®•ரமாக அழிகà¯à®•பà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯." + +#: contrib/admin/views/main.py:511 +msgid "Are you sure?" +msgstr "உறà¯à®¤à®¿à®¯à®¾à®• சொகிறீரà¯à®•ளா?" + +#: contrib/admin/views/main.py:533 +#, python-format +msgid "Change history: %s" +msgstr "வரலாறà¯à®±à¯ˆ மாறà¯à®±à¯: %s" + +#: contrib/admin/views/main.py:565 +#, python-format +msgid "Select %s" +msgstr "%s யை தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯" + +#: contrib/admin/views/main.py:565 +#, python-format +msgid "Select %s to change" +msgstr "%s யை மாறà¯à®± தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯" + +#: contrib/admin/views/doc.py:277 contrib/admin/views/doc.py:286 +#: contrib/admin/views/doc.py:288 contrib/admin/views/doc.py:294 +#: contrib/admin/views/doc.py:295 contrib/admin/views/doc.py:297 +msgid "Integer" +msgstr "à®®à¯à®´à¯ எணà¯" + +#: contrib/admin/views/doc.py:278 +msgid "Boolean (Either True or False)" +msgstr "பூலியன௠(சரி அலà¯à®²à®¤à¯ தவறà¯)" + +#: contrib/admin/views/doc.py:279 contrib/admin/views/doc.py:296 +#, python-format +msgid "String (up to %(maxlength)s)" +msgstr "உரை (%(maxlength)s வரைகà¯à®•à¯à®®à¯)" + +#: contrib/admin/views/doc.py:280 +msgid "Comma-separated integers" +msgstr "கமாவாள௠பிரிகà¯à®•பà¯à®ªà®Ÿà¯à®Ÿ à®®à¯à®´à¯ எணà¯" + +#: contrib/admin/views/doc.py:281 +msgid "Date (without time)" +msgstr "தேதி (நேரமிலà¯à®²à®¾à®®à®²à¯)" + +#: contrib/admin/views/doc.py:282 +msgid "Date (with time)" +msgstr "தேதி (நேரமà¯à®Ÿà®©à¯)" + +#: contrib/admin/views/doc.py:283 +msgid "E-mail address" +msgstr "மின௠அஞà¯à®šà®²à¯" + +#: contrib/admin/views/doc.py:284 contrib/admin/views/doc.py:287 +msgid "File path" +msgstr "கோபà¯à®ªà¯à®ªà¯ பாதை" + +#: contrib/admin/views/doc.py:285 +msgid "Decimal number" +msgstr "பà¯à®³à¯à®³à®¿ எணà¯à®•ளà¯" + +#: contrib/admin/views/doc.py:291 +msgid "Boolean (Either True, False or None)" +msgstr "இலகà¯à®•௠மà¯à®±à¯ˆ (சரி, தவற௠அலà¯à®²à®¤à¯ ஒனà¯à®±à¯à®®à¯ இலà¯à®²à¯ˆ)" + +#: contrib/admin/views/doc.py:292 +msgid "Relation to parent model" +msgstr "ஆதி மாதிரிகà¯à®•௠தொடரà¯à®ªà¯à®Ÿà¯ˆà®¯à®¤à¯" + +#: contrib/admin/views/doc.py:293 +msgid "Phone number" +msgstr "தொலைபேசி எணà¯" + +#: contrib/admin/views/doc.py:298 +msgid "Text" +msgstr "உரை" + +#: contrib/admin/views/doc.py:299 +msgid "Time" +msgstr "நேரமà¯" + +#: contrib/admin/views/doc.py:300 contrib/flatpages/models.py:7 +msgid "URL" +msgstr "URL" + +#: contrib/admin/views/doc.py:301 +msgid "U.S. state (two uppercase letters)" +msgstr "U.S. மாநிலம௠(இரணà¯à®Ÿà¯ மேல௠எழà¯à®¤à¯à®¤à¯à®µà®•ை எழà¯à®¤à¯à®¤à¯)" + +#: contrib/admin/views/doc.py:302 +msgid "XML text" +msgstr "XML உரை" + +#: contrib/admin/templates/admin/object_history.html:3 +#: contrib/admin/templates/admin/change_list.html:5 +#: contrib/admin/templates/admin/base.html:23 +#: contrib/admin/templates/admin/delete_confirmation.html:3 +#: contrib/admin/templates/admin/change_form.html:10 +#: contrib/admin/templates/registration/password_change_done.html:3 +#: contrib/admin/templates/registration/password_change_form.html:3 +#: contrib/admin/templates/admin_doc/bookmarklets.html:3 +msgid "Documentation" +msgstr "ஆவணமாகà¯à®•à®®à¯" + +# translation of django_ac.po to +# translation of django_ac.po to tamil +# Ashwin <ashwin@au-kbc.org>, 2006. +# R Hariram Aatreya <rha@localhost.localdomain>, 2006. +#: contrib/admin/templates/admin/object_history.html:3 +#: contrib/admin/templates/admin/change_list.html:5 +#: contrib/admin/templates/admin/base.html:23 +#: contrib/admin/templates/admin/delete_confirmation.html:3 +#: contrib/admin/templates/admin/change_form.html:10 +#: contrib/admin/templates/registration/password_change_done.html:3 +#: contrib/admin/templates/registration/password_change_form.html:3 +#: contrib/admin/templates/admin_doc/bookmarklets.html:4 +#: contrib/admin/templates/admin_doc/view_detail.html:4 +#: contrib/admin/templates/admin_doc/template_tag_index.html:5 +#: contrib/admin/templates/admin_doc/template_detail.html:4 +#: contrib/admin/templates/admin_doc/template_filter_index.html:5 +#: contrib/admin/templates/admin_doc/missing_docutils.html:4 +#: contrib/admin/templates/admin_doc/view_index.html:5 +#: contrib/admin/templates/admin_doc/model_detail.html:3 +#: contrib/admin/templates/admin_doc/index.html:4 +#: contrib/admin/templates/admin_doc/model_index.html:5 +msgid "Change password" +msgstr "கடவà¯à®šà¯à®šà¯†à®¾à®²à¯à®²à¯ˆ மாறà¯à®±à¯ " + +#: contrib/admin/templates/admin/object_history.html:5 +#: contrib/admin/templates/admin/500.html:4 +#: contrib/admin/templates/admin/change_list.html:6 +#: contrib/admin/templates/admin/base.html:28 +#: contrib/admin/templates/admin/delete_confirmation.html:6 +#: contrib/admin/templates/admin/change_form.html:13 +#: contrib/admin/templates/registration/password_change_done.html:4 +#: contrib/admin/templates/registration/password_reset_form.html:4 +#: contrib/admin/templates/registration/logged_out.html:4 +#: contrib/admin/templates/registration/password_reset_done.html:4 +#: contrib/admin/templates/registration/password_change_form.html:4 +#: contrib/admin/templates/admin_doc/bookmarklets.html:3 +msgid "Home" +msgstr "வீடà¯" + +#: contrib/admin/templates/admin/object_history.html:5 +#: contrib/admin/templates/admin/change_form.html:20 +msgid "History" +msgstr "வரலாறà¯" + +#: contrib/admin/templates/admin/object_history.html:18 +msgid "Date/time" +msgstr "தேதி/நேரம௠" + +#: contrib/admin/templates/admin/object_history.html:19 +msgid "User" +msgstr "பயனரà¯" + +#: contrib/admin/templates/admin/object_history.html:20 +msgid "Action" +msgstr "செயலà¯" + +#: contrib/admin/templates/admin/object_history.html:26 +msgid "DATE_WITH_TIME_FULL" +msgstr "தேதியà¯à®®à¯ à®®à¯à®´à¯ நேரமà¯à®®à¯" + +#: contrib/admin/templates/admin/object_history.html:36 +msgid "" +"This object doesn't have a change history. It probably wasn't added via this " +"admin site." +msgstr "" +"இநà¯à®¤ பொரà¯à®³à¯ மாறà¯à®± வரலாறà¯à®±à®¿à®²à¯ இலà¯à®²à¯ˆ" +"ஒர௠வேளை நிரà¯à®µà®¾à®•தà¯à®¤à®³à®¤à¯à®¤à®¿à®©à¯ மூலம௠சேரà¯à®•à¯à®•பà¯à®ªà®Ÿà®¾à®®à®²à®¿à®°à¯à®•à¯à®•லாமà¯" + +#: contrib/admin/templates/admin/base_site.html:4 +msgid "Django site admin" +msgstr "டிஜாஙà¯à®™à¯‹ தள நிரà¯à®µà®¾à®•ி" + +#: contrib/admin/templates/admin/base_site.html:7 +msgid "Django administration" +msgstr "டிஜாஙà¯à®™à¯‹ நிரà¯à®µà®¾à®•ம௠" + +#: contrib/admin/templates/admin/500.html:4 +msgid "Server error" +msgstr "சேவகன௠பிழை" + +#: contrib/admin/templates/admin/500.html:6 +msgid "Server error (500)" +msgstr "சேவையகம௠தவறà¯(500)" + +#: contrib/admin/templates/admin/500.html:9 +msgid "Server Error <em>(500)</em>" +msgstr "சேவையகம௠பிழை<em>(500)</em>" + +#: contrib/admin/templates/admin/500.html:10 +msgid "" +"There's been an error. It's been reported to the site administrators via e-" +"mail and should be fixed shortly. Thanks for your patience." +msgstr "" +"தவற௠à®à®±à¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯" +"வலைதà¯à®¤à®³ நிரà¯à®µà®¾à®•ிகà¯à®•௠மினà¯à®©à®žà¯à®šà®²à¯ அனà¯à®ªà¯à®ªà®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯. விரைவில௠சரி செயà¯à®¯à®ªà¯à®ªà®Ÿà¯à®®à¯. உஙà¯à®•à¯à®³à®¤à¯ பொறà¯à®®à¯ˆà®•à¯à®•௠நனà¯à®±à®¿" + +#: contrib/admin/templates/admin/404.html:4 +#: contrib/admin/templates/admin/404.html:8 +msgid "Page not found" +msgstr "பகà¯à®•தà¯à®¤à¯ˆ காணவிலà¯à®²à¯ˆ" + +#: contrib/admin/templates/admin/404.html:10 +msgid "We're sorry, but the requested page could not be found." +msgstr "" +"நீஙà¯à®•ள௠விரà¯à®®à¯à®ªà®¿à®¯ பகà¯à®•தà¯à®¤à¯ˆ காண இயலவிலà¯à®²à¯ˆ. " +"அதறà¯à®•ாக வரà¯à®¨à¯à®¤à¯à®•ிறோமà¯." + +#: contrib/admin/templates/admin/index.html:17 +#, python-format +msgid "Models available in the %(name)s application." +msgstr "செயலியில௠கிடைகà¯à®•க௠கூடிய %(name)s மாதிரிகளà¯" + +#: contrib/admin/templates/admin/index.html:28 +#: contrib/admin/templates/admin/change_form.html:15 +msgid "Add" +msgstr "சேரà¯" + +#: contrib/admin/templates/admin/index.html:34 +msgid "Change" +msgstr "மாறà¯à®±à¯" + +#: contrib/admin/templates/admin/index.html:44 +msgid "You don't have permission to edit anything." +msgstr "உஙà¯à®•ளà¯à®•à¯à®•௠மாறà¯à®±à¯à®µà®¤à®±à¯à®•௠உரிமையிலà¯à®²à¯ˆ" + +#: contrib/admin/templates/admin/index.html:52 +msgid "Recent Actions" +msgstr "தறà¯à®ªà¯‹à®¤à¯ˆà®¯ செயலà¯à®•ளà¯" + +#: contrib/admin/templates/admin/index.html:53 +msgid "My Actions" +msgstr "எனத௠செயலà¯à®•ளà¯" + +#: contrib/admin/templates/admin/index.html:57 +msgid "None available" +msgstr "எதà¯à®µà¯à®®à¯ கிடைகà¯à®•விலà¯à®²à¯ˆ" + +#: contrib/admin/templates/admin/change_list.html:11 +#, python-format +msgid "Add %(name)s" +msgstr "%(name)s சேரà¯" + +#: contrib/admin/templates/admin/login.html:22 +msgid "Have you <a href=\"/password_reset/\">forgotten your password</a>?" +msgstr "நீஙà¯à®•ள௠தஙà¯à®•ளத௠கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆ <a href=\"/password_reset/\"> மறநà¯à®¤à¯ விடà¯à®Ÿà¯€à®°à¯à®•ளா?" + +#: contrib/admin/templates/admin/base.html:23 +msgid "Welcome," +msgstr "நலà¯à®µà®°à®µà¯," + +#: contrib/admin/templates/admin/delete_confirmation.html:9 +#: contrib/admin/templates/admin/submit_line.html:3 +msgid "Delete" +msgstr "நீகà¯à®•à¯" + +#: contrib/admin/templates/admin/delete_confirmation.html:14 +#, python-format +msgid "" +"Deleting the %(object_name)s '%(object)s' would result in deleting related " +"objects, but your account doesn't have permission to delete the following " +"types of objects:" +msgstr "இநà¯à®¤ '%(object)s' இல௠%(object_name)s நீகà¯à®•à¯à®µà®¤à¯ தொடரà¯à®ªà¯à®Ÿà¯ˆà®¯ மறà¯à®±à®µà®±à¯à®±à¯ˆà®¯à¯à®®à¯ நீகà¯à®•à¯à®®à¯. ஆனால௠அதறà¯à®•௠உஙà¯à®•ளà¯à®•à¯à®•௠உரிமையிலà¯à®²à¯ˆ" + +#: contrib/admin/templates/admin/delete_confirmation.html:21 +#, python-format +msgid "" +"Are you sure you want to delete the %(object_name)s \"%(object)s\"? All of " +"the following related items will be deleted:" +msgstr "" +"நீஙà¯à®•ள௠இநà¯à®¤ \"%(object)s\" %(object_name)s நீகà¯à®•à¯à®µà®¤à®¿à®²à¯ நிசà¯à®šà®¯à®®à®¾?" +"தொடரà¯à®ªà¯à®Ÿà¯ˆà®¯ மறà¯à®±à®µà¯ˆà®¯à¯à®®à¯ நீகà¯à®•பà¯à®ªà®Ÿà¯à®®à¯. " + +#: contrib/admin/templates/admin/delete_confirmation.html:26 +msgid "Yes, I'm sure" +msgstr "ஆம௠எனகà¯à®•௠உறà¯à®¤à®¿ " + +#: contrib/admin/templates/admin/filter.html:2 +#, python-format +msgid " By %(title)s " +msgstr "%(title)s ஆல௠" + +#: contrib/admin/templates/admin/search_form.html:8 +msgid "Go" +msgstr "செலà¯" + +#: contrib/admin/templates/admin/change_form.html:21 +msgid "View on site" +msgstr "தளà¯à®¤à¯à®¤à®¿à®²à¯ பார௠" + +#: contrib/admin/templates/admin/change_form.html:30 +msgid "Please correct the error below." +msgstr "கீழே உளà¯à®³ தவறà¯à®•ளைதà¯à®¤à®¿à®°à¯à®¤à¯à®¤à¯" + +#: contrib/admin/templates/admin/change_form.html:48 +msgid "Ordering" +msgstr "வரிசைபà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®¤à®²à¯" + +#: contrib/admin/templates/admin/change_form.html:51 +msgid "Order:" +msgstr "வரிசைபà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯" + +#: contrib/admin/templates/admin/submit_line.html:4 +msgid "Save as new" +msgstr "பà¯à®¤à®¿à®¯à®¤à®¾à®• சேமி" + +#: contrib/admin/templates/admin/submit_line.html:5 +msgid "Save and add another" +msgstr "சேமிதà¯à®¤à¯ இனà¯à®©à¯à®®à¯Šà®©à¯à®±à¯ˆà®šà¯ சேரà¯" + +#: contrib/admin/templates/admin/submit_line.html:6 +msgid "Save and continue editing" +msgstr "சேமிதà¯à®¤à¯ மாறà¯à®±à®¤à¯à®¤à¯ˆ தொடரà¯à®•" + +#: contrib/admin/templates/admin/submit_line.html:7 +msgid "Save" +msgstr "சேமி" + +#: contrib/admin/templates/registration/password_change_done.html:4 +#: contrib/admin/templates/registration/password_change_form.html:4 +#: contrib/admin/templates/registration/password_change_form.html:6 +#: contrib/admin/templates/registration/password_change_form.html:10 +msgid "Password change" +msgstr "கடவà¯à®šà¯à®šà¯Šà®²à¯ மாறà¯à®±à®®à¯" + +#: contrib/admin/templates/registration/password_change_done.html:6 +#: contrib/admin/templates/registration/password_change_done.html:10 +msgid "Password change successful" +msgstr "கடவà¯à®šà¯à®šà¯Šà®²à¯ மாறà¯à®±à®®à¯ வெறà¯à®±à®¿ " + +#: contrib/admin/templates/registration/password_change_done.html:12 +msgid "Your password was changed." +msgstr "உஙà¯à®•ள௠கடவà¯à®šà¯à®šà¯Šà®²à¯ மாறà¯à®±à®ªà¯ படà¯à®Ÿà¯à®³à¯à®³à®¤à¯" + +#: contrib/admin/templates/registration/password_reset_form.html:4 +#: contrib/admin/templates/registration/password_reset_form.html:6 +#: contrib/admin/templates/registration/password_reset_form.html:10 +#: contrib/admin/templates/registration/password_reset_done.html:4 +msgid "Password reset" +msgstr "கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆ மாறà¯à®±à®¿à®¯à®®à¯ˆ" + +#: contrib/admin/templates/registration/password_reset_form.html:12 +msgid "" +"Forgotten your password? Enter your e-mail address below, and we'll reset " +"your password and e-mail the new one to you." +msgstr "" +"கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆ மறநà¯à®¤à¯ விடà¯à®Ÿà®¾à®²à¯" +"உஙà¯à®•ளத௠மினà¯à®©à®žà¯à®šà®²à¯ à®®à¯à®•வரியை உளà¯à®³à®¿à®Ÿà¯à®•" +"அதன௠பிறக௠உஙà¯à®•ள௠கடவà¯à®šà¯à®šà¯Šà®²à¯ மாறà¯à®±à®¿à®¯à®®à¯ˆà®•à¯à®•பà¯à®ªà®Ÿà¯à®Ÿà¯ " +"உஙà¯à®•ளத௠மினà¯à®©à®žà¯à®šà®²à¯ à®®à¯à®•வரிகà¯à®•௠அனà¯à®ªà¯à®ªà®ªà¯à®ªà®Ÿà¯à®®à¯" + +#: contrib/admin/templates/registration/password_reset_form.html:16 +msgid "E-mail address:" +msgstr "மினà¯à®…ஞà¯à®šà®²à¯ à®®à¯à®•வரி:" + +#: contrib/admin/templates/registration/password_reset_form.html:16 +msgid "Reset my password" +msgstr "எனத௠கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆ மாறà¯à®±à®¿à®¯à®®à¯ˆ" + +#: contrib/admin/templates/registration/logged_out.html:8 +msgid "Thanks for spending some quality time with the Web site today." +msgstr "" +"வலைதà¯à®¤à®³à®¤à¯à®¤à®¿à®²à¯ உஙà¯à®•ளத௠பொனà¯à®©à®¾à®© நேரதà¯à®¤à¯ˆ " +"செலவழிதà¯à®¤à®®à¯ˆà®•à¯à®•௠மிகà¯à®¨à¯à®¤ நனà¯à®±à®¿" + +#: contrib/admin/templates/registration/logged_out.html:10 +msgid "Log in again" +msgstr "மீணà¯à®Ÿà¯à®®à¯ உளà¯à®³à¯‡ பதிவ௠செயà¯à®¯à®µà¯à®®à¯" + +#: contrib/admin/templates/registration/password_reset_done.html:6 +#: contrib/admin/templates/registration/password_reset_done.html:10 +msgid "Password reset successful" +msgstr "கடவà¯à®šà¯à®šà¯Šà®²à¯ மாறà¯à®±à®¿à®¯à®®à¯ˆà®¤à¯à®¤à®²à¯ வெறà¯à®±à®¿" + +#: contrib/admin/templates/registration/password_reset_done.html:12 +msgid "" +"We've e-mailed a new password to the e-mail address you submitted. You " +"should be receiving it shortly." +msgstr "" +"கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆ மறநà¯à®¤à¯ விடà¯à®Ÿà®¾à®²à¯" +"உஙà¯à®•ளத௠மினà¯à®©à®žà¯à®šà®²à¯ à®®à¯à®•வரியை உளà¯à®³à®¿à®Ÿà¯à®•" +"பà¯à®¤à®¿à®¯ கடவà¯à®šà¯à®šà¯Šà®²à¯ " +"உஙà¯à®•ளத௠மினà¯à®©à®žà¯à®šà®²à¯ à®®à¯à®•வரிகà¯à®•௠அனà¯à®ªà¯à®ªà®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯. விரைவில௠அத௠உஙà¯à®•ளà¯à®•à¯à®•௠கிடைகà¯à®•à¯à®®à¯" + +#: contrib/admin/templates/registration/password_change_form.html:12 +msgid "" +"Please enter your old password, for security's sake, and then enter your new " +"password twice so we can verify you typed it in correctly." +msgstr "பாதà¯à®•ாபà¯à®ªà¯ காரணஙà¯à®•ளà¯à®•à¯à®•ாக , à®®à¯à®¤à®²à®¿à®²à¯ உஙà¯à®•ளத௠பழைய கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆ உளà¯à®³à®¿à®Ÿà¯à®•. அதன௠பிறக௠பà¯à®¤à®¿à®¯ கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆ இர௠மà¯à®±à¯ˆ உளà¯à®³à®¿à®Ÿà¯à®•. இத௠உஙà¯à®•ளத௠உளà¯à®³à®¿à®Ÿà¯à®¤à®²à¯ˆ சரிபாரà¯à®•à¯à®• உதவà¯à®®à¯. " + +#: contrib/admin/templates/registration/password_change_form.html:17 +msgid "Old password:" +msgstr "பழைய கடவà¯à®šà¯à®šà¯Šà®²à¯ :" + +#: contrib/admin/templates/registration/password_change_form.html:19 +msgid "New password:" +msgstr "பà¯à®¤à®¿à®¯ கடவà¯à®šà¯à®šà¯Šà®²à¯:" + +#: contrib/admin/templates/registration/password_change_form.html:21 +msgid "Confirm password:" +msgstr "கடவà¯à®šà¯à®šà¯Šà®²à¯ மாறà¯à®±à®¤à¯à®¤à¯ˆ உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯:" + +#: contrib/admin/templates/registration/password_change_form.html:23 +msgid "Change my password" +msgstr "கடவà¯à®šà¯ சொலà¯à®²à¯ˆ மாறà¯à®±à®µà¯à®®à¯" + +#: contrib/admin/templates/registration/password_reset_email.html:2 +msgid "You're receiving this e-mail because you requested a password reset" +msgstr "கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆ மாறà¯à®±à®¿à®¯à®®à¯ˆà®•à¯à®• நீஙà¯à®•ள௠கேடà¯à®Ÿà®¤à®©à®¾à®²à¯ உஙà¯à®•ளà¯à®•à¯à®•௠இநà¯à®¤ மினà¯à®©à®žà¯à®šà®²à¯ அனà¯à®ªà¯à®ªà®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯" + +#: contrib/admin/templates/registration/password_reset_email.html:3 +#, python-format +msgid "for your user account at %(site_name)s" +msgstr "%(site_name)s -இல௠உளà¯à®³ உஙà¯à®•ளத௠பயனாளர௠கணகà¯à®•à¯" + +#: contrib/admin/templates/registration/password_reset_email.html:5 +#, python-format +msgid "Your new password is: %(new_password)s" +msgstr "உஙà¯à®•ளத௠பà¯à®¤à®¿à®¯ கடவà¯à®šà¯à®šà¯Šà®²à¯ : %(new_password)s " + +#: contrib/admin/templates/registration/password_reset_email.html:7 +msgid "Feel free to change this password by going to this page:" +msgstr "கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆ மாறà¯à®±à®¿à®¯à®®à¯ˆà®•à¯à®• நீஙà¯à®•ள௠இநà¯à®¤ பகà¯à®•தà¯à®¤à®¿à®±à¯à®•௠தாராளமாக போகலாமà¯." + +#: contrib/admin/templates/registration/password_reset_email.html:11 +msgid "Your username, in case you've forgotten:" +msgstr "உஙà¯à®•ளத௠பயனாளர௠பெயரà¯, (நீஙà¯à®•ள௠மறநà¯à®¤à®¿à®°à¯à®¨à¯à®¤à®¾à®²à¯ ): " + +#: contrib/admin/templates/registration/password_reset_email.html:13 +msgid "Thanks for using our site!" +msgstr "எஙà¯à®•ளத௠வலைதà¯à®¤à®³à®¤à¯à®¤à¯ˆ பயன௠படà¯à®¤à¯à®¤à®¿à®¯à®¤à®±à¯à®•௠மிகà¯à®¨à¯à®¤ நனà¯à®±à®¿" + +#: contrib/admin/templates/registration/password_reset_email.html:15 +#, python-format +msgid "The %(site_name)s team" +msgstr "இநà¯à®¤ %(site_name)s -இன௠கà¯à®´à¯ " + +#: contrib/admin/templates/admin_doc/bookmarklets.html:3 +msgid "Bookmarklets" +msgstr "பà¯à®¤à¯à®¤à®•கà¯à®•à¯à®±à®¿à®•ளà¯" + +# translation of django_ad.po to +# translation of django_ad.po to +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# aukbc-guest, 2006. +# R Hariram Aatreya <rha@localhost.localdomain>, 2006. +#: contrib/admin/templates/admin_doc/bookmarklets.html:5 +msgid "Documentation bookmarklets" +msgstr "ஆவணமாகà¯à®•க௠கà¯à®±à®¿à®¯à¯€à®Ÿà¯" + +#: contrib/admin/templates/admin_doc/bookmarklets.html:9 +msgid "" +"\n" +"<p class=\"help\">To install bookmarklets, drag the link to your bookmarks\n" +"toolbar, or right-click the link and add it to your bookmarks. Now you can\n" +"select the bookmarklet from any page in the site. Note that some of these\n" +"bookmarklets require you to be viewing the site from a computer designated\n" +"as \"internal\" (talk to your system administrator if you aren't sure if\n" +"your computer is \"internal\").</p>\n" +msgstr "" +"\n" +"<p class=\"help\"> பà¯à®¤à¯à®¤à®• கà¯à®±à®¿à®¯à¯€à®Ÿà¯à®•ளை நிறà¯à®µ இநà¯à®¤ இணைபà¯à®ªà®¿à®©à¯ˆ பà¯à®¤à¯à®¤à®•கà¯à®•à¯à®±à®¿à®¯à¯€à®Ÿà¯à®Ÿà¯à®ªà¯ \n" +"படà¯à®Ÿà¯ˆà®•à¯à®•௠இழà¯à®•à¯à®•வà¯à®®à¯. அலà¯à®²à®¤à¯ வலத௠கிிளிக செயà¯à®¤à¯ பà¯à®¤à¯à®¤à®•கà¯à®•à¯à®±à®¿à®¯à¯€à®Ÿà¯à®•ளில௠சேரà¯à®•à¯à®•வà¯à®®à¯. \n" +" இனி தளதà¯à®¤à®¿à®²à¯ எநà¯à®¤à®ªà¯ பகà¯à®•தà¯à®¤à®¿à®²à¯ இரà¯à®¨à¯à®¤à¯à®®à¯ பà¯à®¤à¯à®¤à®•கà¯à®•à¯à®±à®¿à®¯à¯€à®Ÿà¯à®Ÿà®¿à®©à¯ˆ தேரà¯à®µà¯à®šà¯†à®¯à¯à®¯ à®®à¯à®Ÿà®¿à®¯à¯à®®à¯. \n" +" நீஙà¯à®•ள௠இநà¯à®¤ தளதà¯à®¤à¯ˆ \"internal\" என கà¯à¯à®±à®¿à®•à¯à®•பà¯à®ªà®Ÿà¯à®Ÿ கணிணியில௠இரà¯à®¨à¯à®¤à¯ மடà¯à®Ÿà¯à®®à¯‡ \n" +" à®’à®°à¯à®šà®¿à®² பà¯à®¤à¯à®¤à®•கà¯à®•à¯à®±à®¿à®•ளை செயலà¯à®ªà®Ÿà¯à®¤à¯à®¤à®®à¯à®Ÿà®¿à®¯à¯à®®à¯\n " +" உஙà¯à®•ளà¯à®•à¯à®•à¯, கணிணி \"internal\" என உறà¯à®¤à®¿ செயà¯à®¯ கணிணிமேளாலரை அணà¯à®•வà¯à®®à¯.</p>\n" + +#: contrib/admin/templates/admin_doc/bookmarklets.html:19 +msgid "Documentation for this page" +msgstr "இநà¯à®¤ பகà¯à®•தà¯à®¤à®¿à®±à¯à®•ான ஆவணமà¯" + +#: contrib/admin/templates/admin_doc/bookmarklets.html:20 +msgid "" +"Jumps you from any page to the documentation for the view that generates " +"that page." +msgstr "எநà¯à®¤ ஒர௠பகà¯à®•தà¯à®¤à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯à®®à¯ ஆவணபà¯à®ªà®•à¯à®•தà¯à®¤à¯ˆ பாரà¯à®µà¯ˆà®¯à®¿à®Ÿà¯à®¤à®²à¯, அநà¯à®¤ பகà¯à®•தà¯à®¤à¯ˆ உரà¯à®µà®¾à®•à¯à®•à¯à®•ிறதà¯." + +#: contrib/admin/templates/admin_doc/bookmarklets.html:22 +msgid "Show object ID" +msgstr "object ID-஠காடà¯à®Ÿà¯" + +#: contrib/admin/templates/admin_doc/bookmarklets.html:23 +msgid "" +"Shows the content-type and unique ID for pages that represent a single " +"object." +msgstr "ஒரே object-஠கà¯à®±à®¿à®•à¯à®•à¯à®®à¯ பகà¯à®•à®™à¯à®•ளின௠பொரà¯à®³à®Ÿà®•à¯à®• வகை மறà¯à®±à¯à®®à¯ unique ID-஠காடà¯à®Ÿà¯à®•ிறதà¯." + +#: contrib/admin/templates/admin_doc/bookmarklets.html:25 +msgid "Edit this object (current window)" +msgstr "இதை திரà¯à®¤à¯à®¤à¯à®• (தறà¯à®ªà¯‹à®¤à¯ˆà®¯ சாளரமà¯)" + +#: contrib/admin/templates/admin_doc/bookmarklets.html:26 +msgid "Jumps to the admin page for pages that represent a single object." +msgstr "ஒரே object-஠கà¯à®±à®¿à®•à¯à®•à¯à®®à¯ பகà¯à®•à®™à¯à®•ளைக௠காண மேலாளர௠பகà¯à®•தà¯à®¤à®¿à®±à¯à®•௠செலà¯à®•." + +#: contrib/admin/templates/admin_doc/bookmarklets.html:28 +msgid "Edit this object (new window)" +msgstr "இதை திரà¯à®¤à¯à®¤à¯à®•. (பà¯à®¤à®¿à®¯ சாளரமà¯)" + +#: contrib/admin/templates/admin_doc/bookmarklets.html:29 +msgid "As above, but opens the admin page in a new window." +msgstr "மேளாலர௠பகà¯à®•தà¯à®¤à¯ˆ à®®à¯à®©à¯à®ªà¯ கணà¯à®Ÿà®¤à¯à®ªà¯‹à®²à¯, ஆனால௠பà¯à®¤à®¿à®¯ சாளரதà¯à®¤à®¿à®²à¯ திறகà¯à®•ிறதà¯." + +#: contrib/admin/templates/widget/date_time.html:3 +msgid "Date:" +msgstr "தேதி:" + +#: contrib/admin/templates/widget/date_time.html:4 +msgid "Time:" +msgstr "நேரமà¯:" + +#: contrib/admin/templates/widget/file.html:2 +msgid "Currently:" +msgstr "தறà¯à®ªà¯‹à®¤à¯:" + +#: contrib/admin/templates/widget/file.html:3 +msgid "Change:" +msgstr "மாறà¯à®±à¯:" + +#: contrib/redirects/models.py:7 +msgid "redirect from" +msgstr "லிரà¯à®¨à¯à®¤à¯ திசைமாறà¯à®±à¯" + +#: contrib/redirects/models.py:8 +msgid "" +"This should be an absolute path, excluding the domain name. Example: '/" +"events/search/'." +msgstr "" +"இத௠ஒர௠மà¯à®´à¯à®®à¯ˆà®¯à®¾à®© பாதையாக இரà¯à®•à¯à®•வேணà¯à®Ÿà¯à®®à¯. " +"இணையதà¯à®¤à®³à®ªà¯à®ªà¯†à®¯à®°à®¾à®• இரà¯à®•à¯à®•கà¯à®•ூடாதà¯. உதாரணமà¯:'/" +"events/search/'." + +#: contrib/redirects/models.py:9 +msgid "redirect to" +msgstr "திரà¯à®®à¯à®ª அனà¯à®ªà¯à®ªà¯" + +#: contrib/redirects/models.py:10 +msgid "" +"This can be either an absolute path (as above) or a full URL starting with " +"'http://'." +msgstr "இத௠மà¯à®´à¯à®®à¯ˆà®¯à®¾à®© பாதையாக (மேலே உளà¯à®³à®¤à¯ போல) அலà¯à®²à®¤à¯ \"http\"//\" என தொடஙà¯à®•à¯à®®à¯ வலை à®®à¯à®•வரியாக இரà¯à®•à¯à®•லாமà¯." + +#: contrib/redirects/models.py:12 +msgid "redirect" +msgstr "திரà¯à®®à¯à®ª அனà¯à®ªà¯à®ªà¯" + +#: contrib/redirects/models.py:13 +msgid "redirects" +msgstr "திரà¯à®®à¯à®ª அனà¯à®ªà¯à®ªà¯à®•ிறதà¯. " + +#: contrib/flatpages/models.py:8 +msgid "Example: '/about/contact/'. Make sure to have leading and trailing slashes." +msgstr "உதாரணமà¯: '/about/contact/'. à®®à¯à®©à¯à®©à¯à®®à¯ பினà¯à®©à¯à®®à¯ '/' உளà¯à®³à®¤à¯ˆ உறà¯à®¤à®¿ செயà¯à®•. " + +#: contrib/flatpages/models.py:9 +msgid "title" +msgstr "தலைபà¯à®ªà¯" + +#: contrib/flatpages/models.py:10 +msgid "content" +msgstr "பொரà¯à®³à®Ÿà®•à¯à®•à®®à¯" + +#: contrib/flatpages/models.py:11 +msgid "enable comments" +msgstr "விமரà¯à®šà®©à®™à¯à®•ளை செயலாகà¯à®•à¯" + +#: contrib/flatpages/models.py:12 +msgid "template name" +msgstr "வாரà¯à®ªà¯à®ªà¯à®°à¯ பெயரà¯" + +#: contrib/flatpages/models.py:13 +msgid "" +"Example: 'flatpages/contact_page'. If this isn't provided, the system will " +"use 'flatpages/default'." +msgstr "உதாரணம௠'flatpages/contact_page'. இத௠இலà¯à®²à¯ˆà®¯à¯†à®©à®¿à®²à¯ 'flatpages/default' எனà¯à®ªà®¤à¯‡ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà¯à®®à¯.பà¯à®ªà®Ÿà¯à®®à¯." + +#: contrib/flatpages/models.py:14 +msgid "registration required" +msgstr "à®®à¯à®©à¯à®ªà®¤à®¿à®µà¯ தேவை" + +#: contrib/flatpages/models.py:14 +msgid "If this is checked, only logged-in users will be able to view the page." +msgstr "இத௠தெரிவ௠செயà¯à®¯à®ªà¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®¨à¯à®¤à®¾à®²à¯, உளà¯à®¨à¯à®´à¯ˆà®¨à¯à®¤ பயனரà¯à®•ள௠மடà¯à®Ÿà¯à®®à¯‡ இநà¯à®¤à®ªà¯ பகà¯à®•தà¯à®¤à¯ˆ பாரà¯à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à¯à®®à¯." + +#: contrib/flatpages/models.py:18 +msgid "flat page" +msgstr "எளிய பகà¯à®•à®®à¯" + +#: contrib/flatpages/models.py:19 +msgid "flat pages" +msgstr "எளிய பகà¯à®•à®™à¯à®•ளà¯" + +#: contrib/auth/models.py:13 contrib/auth/models.py:26 +msgid "name" +msgstr "பெயரà¯" + +#: contrib/auth/models.py:15 +msgid "codename" +msgstr "கà¯à®±à®¿à®®à¯à®±à¯ˆ பெயரà¯" + +#: contrib/auth/models.py:17 +msgid "permission" +msgstr "அனà¯à®®à®¤à®¿" + +#: contrib/auth/models.py:18 contrib/auth/models.py:27 +msgid "permissions" +msgstr "அனà¯à®®à®¤à®¿à®•ளà¯" + +#: contrib/auth/models.py:29 +msgid "group" +msgstr "கà¯à®´à¯" + +#: contrib/auth/models.py:30 contrib/auth/models.py:65 +msgid "groups" +msgstr "கà¯à®´à¯à®•à¯à®•ளà¯" + +#: contrib/auth/models.py:55 +msgid "username" +msgstr "பயனர௠பெயரà¯" + +#: contrib/auth/models.py:56 +msgid "first name" +msgstr "à®®à¯à®¤à®²à¯ பெயரà¯" + +#: contrib/auth/models.py:57 +msgid "last name" +msgstr "கடைசி பெயரà¯" + +#: contrib/auth/models.py:58 +msgid "e-mail address" +msgstr "மினà¯à®©à®žà¯à®šà®²à¯ à®®à¯à®•வரி" + +#: contrib/auth/models.py:59 +msgid "password" +msgstr "கடவà¯à®šà¯à®šà¯Šà®²à¯" + +#: contrib/auth/models.py:59 +msgid "Use '[algo]$[salt]$[hexdigest]'" +msgstr "பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯ '[algo]$[salt]$[hexdigest]'" + +#: contrib/auth/models.py:60 +msgid "staff status" +msgstr "பணியாளர௠நிலை" + +#: contrib/auth/models.py:60 +msgid "Designates whether the user can log into this admin site." +msgstr "பயனரà¯, 'மேலாளலரà¯' பகà¯à®•தà¯à®¤à®¿à®²à¯ நà¯à®´à¯ˆà¯à®´à¯ˆà®µà®¤à¯ˆ à®®à¯à®Ÿà®¿à®µà¯ செயà¯à®•ிறத௠" + +#: contrib/auth/models.py:61 +msgid "active" +msgstr "செயலà¯à®ªà®Ÿà¯à®®à¯" + +#: contrib/auth/models.py:62 +msgid "superuser status" +msgstr "மேலாளர௠இரà¯à®ªà¯à®ªà¯ நிலை" + +#: contrib/auth/models.py:63 +msgid "last login" +msgstr "கடைசி உளà¯à®¨à¯à®´à¯ˆà®µà¯" + +#: contrib/auth/models.py:64 +msgid "date joined" +msgstr "சேரà¯à®¨à¯à®¤ தேதி" + +#: contrib/auth/models.py:66 +msgid "" +"In addition to the permissions manually assigned, this user will also get " +"all permissions granted to each group he/she is in." +msgstr "பயனர௠தனத௠அனà¯à®®à®¤à®¿à®•ளோட௠,தான௠உளà¯à®³ கà¯à®´à¯à®µà®¿à®©à®¤à¯ அனà¯à®®à®¤à®¿à®•ளைையà¯à®®à¯ பெறà¯à®µà®¾à®°à¯." + +#: contrib/auth/models.py:67 +msgid "user permissions" +msgstr "பயனர௠அனà¯à®®à®¤à®¿à®•ளà¯" + +#: contrib/auth/models.py:70 +msgid "user" +msgstr "பயனரà¯" + +#: contrib/auth/models.py:71 +msgid "users" +msgstr "பயனரà¯à®•ளà¯" + +#: contrib/auth/models.py:76 +msgid "Personal info" +msgstr "தனிபà¯à®ªà®Ÿà¯à®Ÿ விவரமà¯" + +#: contrib/auth/models.py:77 +msgid "Permissions" +msgstr "அனà¯à®®à®¤à®¿à®•ளà¯" + +#: contrib/auth/models.py:78 +msgid "Important dates" +msgstr "à®®à¯à®•à¯à®•ியமான தேதிகளà¯" + +#: contrib/auth/models.py:79 +msgid "Groups" +msgstr "கà¯à®´à¯à®•à¯à®•ளà¯" + +#: contrib/auth/models.py:219 +msgid "message" +msgstr "செயà¯à®¤à®¿" + +#: contrib/auth/forms.py:30 +msgid "" +"Your Web browser doesn't appear to have cookies enabled. Cookies are " +"required for logging in." +msgstr " உஙà¯à®•ள௠இணைய உலாவியில௠கà¯à®•à¯à®•ிகள௠செயலாகà¯à®•ம௠பெறவிலà¯à®²à¯ˆ. உளà¯à®¨à¯à®´à¯ˆà®µà®¤à®±à¯à®•à¯à®•௠கà¯à®•à¯à®•ிகள௠அவசியமà¯." + +#: contrib/contenttypes/models.py:25 +msgid "python model class name" +msgstr "python model class name" + +#: contrib/contenttypes/models.py:28 +msgid "content type" +msgstr "பொரà¯à®³à®Ÿà®•à¯à®• வகை " + +#: contrib/contenttypes/models.py:29 +msgid "content types" +msgstr "பொரà¯à®³à®Ÿà®•à¯à®• வகைகளà¯" + +#: contrib/sessions/models.py:35 +msgid "session key" +msgstr "அமரà¯à®µà¯ கà¯à®±à®¿à®¯à¯€" + +#: contrib/sessions/models.py:36 +msgid "session data" +msgstr "அமரà¯à®µà¯ தகவலà¯" + +#: contrib/sessions/models.py:37 +msgid "expire date" +msgstr "காலாவதியாகà¯à®®à¯ தேதி" + +#: contrib/sessions/models.py:41 +msgid "session" +msgstr "அமரà¯à®µà¯" + +#: contrib/sessions/models.py:42 +msgid "sessions" +msgstr "அமரà¯à®µà¯à®•ளà¯" + +#: contrib/sites/models.py:10 +msgid "domain name" +msgstr "களப௠பெயரà¯" + +#: contrib/sites/models.py:11 +msgid "display name" +msgstr "காடà¯à®Ÿà¯à®®à¯ பெயரà¯" + +#: contrib/sites/models.py:15 +msgid "site" +msgstr "வலைதà¯à®¤à®³à®®à¯" + +#: contrib/sites/models.py:16 +msgid "sites" +msgstr "வலைதà¯à®¤à®³à®™à¯à®•ளà¯" + +#: utils/translation.py:360 +msgid "DATE_FORMAT" +msgstr "தேதி வடிவமà¯" + +#: utils/translation.py:361 +msgid "DATETIME_FORMAT" +msgstr "தேதிநேர வடிவமà¯" + +# translation of django_ae.po to +# translation of django_ae.po to +# R Hariram Aatreya <rha@localhost.localdomain>, 2006. +#: utils/translation.py:362 +msgid "TIME_FORMAT" +msgstr "நேரதà¯à®¤à®¿à®©à¯ அமைபà¯à®ªà¯à®®à¯" + +#: utils/dates.py:6 +msgid "Monday" +msgstr "திஙà¯à®•ளà¯" + +#: utils/dates.py:6 +msgid "Tuesday" +msgstr "செவà¯à®µà®¾à®¯à¯" + +#: utils/dates.py:6 +msgid "Wednesday" +msgstr "பà¯à®¤à®©à¯" + +#: utils/dates.py:6 +msgid "Thursday" +msgstr "வியாழனà¯" + +#: utils/dates.py:6 +msgid "Friday" +msgstr "வெளà¯à®³à®¿" + +#: utils/dates.py:7 +msgid "Saturday" +msgstr "சனி" + +#: utils/dates.py:7 +msgid "Sunday" +msgstr "ஞாயிறà¯" + +#: utils/dates.py:14 +msgid "January" +msgstr "ஜனவரி" + +#: utils/dates.py:14 +msgid "February" +msgstr "பிபà¯à®°à®µà®°à®¿" + +#: utils/dates.py:14 utils/dates.py:27 +msgid "March" +msgstr "மாரà¯à®šà¯" + +#: utils/dates.py:14 utils/dates.py:27 +msgid "April" +msgstr "à®à®ªà¯à®°à®²à¯" + +#: utils/dates.py:14 utils/dates.py:27 +msgid "May" +msgstr "மே" + +#: utils/dates.py:14 utils/dates.py:27 +msgid "June" +msgstr "ஜூனà¯" + +#: utils/dates.py:15 utils/dates.py:27 +msgid "July" +msgstr "ஜூலை" + +#: utils/dates.py:15 +msgid "August" +msgstr "ஆகஸà¯à®Ÿà¯" + +#: utils/dates.py:15 +msgid "September" +msgstr "செபà¯à®Ÿà®®à¯à®ªà®°à¯" + +#: utils/dates.py:15 +msgid "October" +msgstr "அகà¯à®Ÿà¯‹à®ªà®°à¯" + +#: utils/dates.py:15 +msgid "November" +msgstr "நவமà¯à®ªà®°à¯" + +#: utils/dates.py:16 +msgid "December" +msgstr "டிசமà¯à®ªà®°à¯" + +#: utils/dates.py:19 +msgid "jan" +msgstr "ஜன" + +#: utils/dates.py:19 +msgid "feb" +msgstr "பிபà¯" + +#: utils/dates.py:19 +msgid "mar" +msgstr "மாரà¯" + +#: utils/dates.py:19 +msgid "apr" +msgstr "à®à®ªà¯" + +#: utils/dates.py:19 +msgid "may" +msgstr "மே" + +#: utils/dates.py:19 +msgid "jun" +msgstr "ஜூனà¯" + +#: utils/dates.py:20 +msgid "jul" +msgstr "ஜூலை" + +#: utils/dates.py:20 +msgid "aug" +msgstr "ஆக" + +#: utils/dates.py:20 +msgid "sep" +msgstr "செபà¯" + +#: utils/dates.py:20 +msgid "oct" +msgstr "அகà¯" + +#: utils/dates.py:20 +msgid "nov" +msgstr "நவ" + +#: utils/dates.py:20 +msgid "dec" +msgstr "டிச" + +#: utils/dates.py:27 +msgid "Jan." +msgstr "ஜன." + +#: utils/dates.py:27 +msgid "Feb." +msgstr "பிபà¯." + +#: utils/dates.py:28 +msgid "Aug." +msgstr "ஆக." + +#: utils/dates.py:28 +msgid "Sept." +msgstr "செபà¯." + +#: utils/dates.py:28 +msgid "Oct." +msgstr "அகà¯." + +#: utils/dates.py:28 +msgid "Nov." +msgstr "நவ." + +#: utils/dates.py:28 +msgid "Dec." +msgstr "டிச." + +#: utils/timesince.py:12 +msgid "year" +msgstr "வரà¯à®Ÿà®®à¯" + +#: utils/timesince.py:13 +msgid "month" +msgstr "மாதமà¯" + +#: utils/timesince.py:14 +msgid "week" +msgstr "வாரமà¯" + +#: utils/timesince.py:15 +msgid "day" +msgstr "நாளà¯" + +#: utils/timesince.py:16 +msgid "hour" +msgstr "மணி" + +#: utils/timesince.py:17 +msgid "minute" +msgstr "நிமிடமà¯" + +#: conf/global_settings.py:37 +msgid "Bengali" +msgstr "பெஙà¯à®•ாலி" + +#: conf/global_settings.py:38 +msgid "Czech" +msgstr "செகà¯" + +#: conf/global_settings.py:39 +msgid "Welsh" +msgstr "வெலà¯à®¸à¯" + +#: conf/global_settings.py:40 +msgid "Danish" +msgstr "டேனிஷà¯" + +#: conf/global_settings.py:41 +msgid "German" +msgstr "ஜெரà¯à®®à®©à¯" + +#: conf/global_settings.py:42 +msgid "Greek" +msgstr "கிரேகà¯à®•à®®à¯" + +#: conf/global_settings.py:43 +msgid "English" +msgstr "ஆஙà¯à®•ிலமà¯" + +#: conf/global_settings.py:44 +msgid "Spanish" +msgstr "ஸà¯à®ªà®¾à®©à®¿à®·à¯" + +#: conf/global_settings.py:45 +msgid "French" +msgstr "பà¯à®°à¯†à®©à¯à®šà¯" + +#: conf/global_settings.py:46 +msgid "Galician" +msgstr "கலீஷீயனà¯" + +#: conf/global_settings.py:47 +msgid "Hungarian" +msgstr "ஹஙà¯à®•ேரியனà¯" + +#: conf/global_settings.py:48 +msgid "Hebrew" +msgstr "ஹீபà¯à®°à¯" + +#: conf/global_settings.py:49 +msgid "Icelandic" +msgstr "à®à®¸à¯à®²à®¾à®©à¯à®Ÿà®¿à®•à¯" + +#: conf/global_settings.py:50 +msgid "Italian" +msgstr "இதà¯à®¤à®¾à®²à®¿à®¯à®©à¯" + +#: conf/global_settings.py:51 +msgid "Japanese" +msgstr "ஜபà¯à®ªà®¾à®©à®¿à®¯" + +#: conf/global_settings.py:52 +msgid "Dutch" +msgstr "டசà¯à®šà¯" + +#: conf/global_settings.py:53 +msgid "Norwegian" +msgstr "நாரà¯à®µà¯€à®šà®¿à®¯à®©à¯" + +#: conf/global_settings.py:54 +msgid "Brazilian" +msgstr "பிரேசிலியனà¯" + +#: conf/global_settings.py:55 +msgid "Romanian" +msgstr "ரோமானியனà¯" + +#: conf/global_settings.py:56 +msgid "Russian" +msgstr "à®°à®·à¯à®¯à®©à¯" + +#: conf/global_settings.py:57 +msgid "Slovak" +msgstr "சà¯à®²à¯‹à®µà®¾à®•à¯" + +#: conf/global_settings.py:58 +msgid "Slovenian" +msgstr "ஸà¯à®²à¯‹à®µà¯‡à®©à®¿à®¯à®©à¯" + +#: conf/global_settings.py:59 +msgid "Serbian" +msgstr "செரà¯à®ªà®¿à®¯à®©à¯" + +#: conf/global_settings.py:60 +msgid "Swedish" +msgstr "சà¯à®µà®¿à®Ÿà®¿à®·à¯" + +#: conf/global_settings.py:61 +msgid "Ukrainian" +msgstr "உகà¯à®°à¯‡à®©à®¿à®¯à®©à¯" + +#: conf/global_settings.py:62 +msgid "Simplified Chinese" +msgstr "எளிய சீன மொழி" + +#: conf/global_settings.py:63 +msgid "Traditional Chinese" +msgstr "மரப௠சீன மொழி" + +#: core/validators.py:60 +msgid "This value must contain only letters, numbers and underscores." +msgstr "இநà¯à®¤ மதிபà¯à®ªà¯ எழà¯à®¤à¯à®¤à¯à®•ள௠எணà¯à®•ள௠அனà¯à®Ÿà®°à¯à®¸à¯à®•ோர௠மறà¯à®±à¯à®®à¯ உளà¯à®³à®Ÿà®•à¯à®• வேணà¯à®Ÿà¯à®®à¯ " + +#: core/validators.py:64 +msgid "" +"This value must contain only letters, numbers, underscores, dashes or " +"slashes." +msgstr "இநà¯à®¤ மதிபà¯à®ªà¯ எழà¯à®¤à¯à®¤à¯à®•ள௠எணà¯à®•ள௠அனà¯à®Ÿà®°à¯à®¸à¯à®•ோர௠டஷ௠அலà¯à®²à®¤à¯ சலஷ௠மறà¯à®±à¯à®®à¯ உளà¯à®³à®Ÿà®•à¯à®• வேணà¯à®Ÿà¯à®®à¯" + +#: core/validators.py:72 +msgid "Uppercase letters are not allowed here." +msgstr "பெரிய எழà¯à®¤à¯à®¤à¯à®•ளà¯à®•à¯à®•௠இஙà¯à®•௠அனà¯à®®à®¤à®¿ இலà¯à®²à¯ˆ இலà¯à®²à¯ˆ." + +#: core/validators.py:76 +msgid "Lowercase letters are not allowed here." +msgstr "சிறிய ய எழà¯à®¤à¯à®¤à¯à®•ளà¯à®•à¯à®•௠இஙà¯à®•௠அனà¯à®®à®¤à®¿ இலà¯à®²à¯ˆ" + +# translation of django_af.po to +# translation of django_af.po to +# translation of django_af.po to +# translation of django_af.po to +# translation of django_af.po to +# translation of django_af.po to +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# , 2006. +# R Hariram Aatreya <rha@localhost.localdomain>, 2006. +#: core/validators.py:83 +msgid "Enter only digits separated by commas." +msgstr "காறà¯à®ªà¯à®³à¯à®³à®¿à®•ளால௠தனிமைபà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿à®¯ இலகà¯à®•ஙகள மடà¯à®Ÿà¯à®®à¯ எழà¯à®¤à®µà¯à®®à¯" + +#: core/validators.py:95 +msgid "Enter valid e-mail addresses separated by commas." +msgstr "காறà¯à®ªà¯à®³à¯à®³à®¿à®•ளால௠தனிமைபà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿à®¯ à®®à¯à®±à¯ˆà®¯à®¾à®© e à®®à¯à®•வரிகளà¯à¯ மடà¯à®Ÿà¯à®®à¯ எழà¯à®¤à®µà¯à®®à¯" + +#: core/validators.py:99 +msgid "Please enter a valid IP address." +msgstr "தயவ௠செயà¯à®¤à¯ à®®à¯à®±à¯ˆà®¯à®¾à®© à®.பி à®®à¯à®•வறி மடà¯à®Ÿà¯à®®à¯ எழà¯à®¤à®µà¯à®®à¯" + +#: core/validators.py:103 +msgid "Empty values are not allowed here." +msgstr "காலியான மதிபà¯à®ªà¯à®•à¯à®•ள௠அனà¯à®®à®¤à®¿Â இலà¯à®²à¯ˆ" + +#: core/validators.py:107 +msgid "Non-numeric characters aren't allowed here." +msgstr "எண௠வடிவமிலà¯à®²à®¾à®¤ எழà¯à®¤à¯à®¤à¯à®•à¯à®•ள௠அனà¯à®®à®¤à®¿Â இலà¯à®²à¯ˆ" + +#: core/validators.py:111 +msgid "This value can't be comprised solely of digits." +msgstr "இநà¯à®¤ மதிபà¯à®ªà¯ இலகà¯à®•à®™à¯à®•ள௠மடà¯à®Ÿà¯à®®à¯‡ கொணà¯à®Ÿà®¤à®¾à®• இரà¯à®•à¯à®• கூடாதà¯" + +#: core/validators.py:116 +msgid "Enter a whole number." +msgstr "à®®à¯à®´à¯ எண௠மடà¯à®Ÿà¯à®®à¯‡ எழà¯à®¤à®µà¯à®®à¯" + +#: core/validators.py:120 +msgid "Only alphabetical characters are allowed here." +msgstr "அகர வரிசை எழà¯à®¤à¯à®¤à¯à®•à¯à®•ள௠மடà¯à®Ÿà¯à®®à¯‡ அனà¯à®®à®¤à®¿ உனà¯à®Ÿà¯" + +#: core/validators.py:124 +msgid "Enter a valid date in YYYY-MM-DD format." +msgstr "வவவவ-மாமா-நாநா எனà¯à®± அமைபà¯à®ªà®¿à®²à¯ உளà¯à®³ à®®à¯à®±à¯ˆà®¯à®¾à®© தேதி மடà¯à®Ÿà¯à®®à¯‡ எழà¯à®¤à®µà¯à®®à¯" + +#: core/validators.py:128 +msgid "Enter a valid time in HH:MM format." +msgstr "மம-நிநி எனà¯à®± அமைபà¯à®ªà®¿à®²à¯ உளà¯à®³ à®®à¯à®±à¯ˆà®¯à®¾à®© நேரம௠மடà¯à®Ÿà¯à®®à¯‡ எழà¯à®¤à®µà¯à®®à¯" + +#: core/validators.py:132 db/models/fields/__init__.py:468 +msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format." +msgstr "வவவவ-மாமா-நாநா மம-நிநி எனà¯à®± அமைபà¯à®ªà®¿à®²à¯ உளà¯à®³ à®®à¯à®±à¯ˆà®¯à®¾à®© தேதி/நேரம௠மடà¯à®Ÿà¯à®®à¯‡ எழà¯à®¤à®µà¯à®®à¯" + +#: core/validators.py:136 +msgid "Enter a valid e-mail address." +msgstr "à®®à¯à®±à¯ˆà®¯à®¾à®© e à®®à¯à®•வரிகளà¯à¯ மடà¯à®Ÿà¯à®®à¯ எழà¯à®¤à®µà¯à®®à¯" + +#: core/validators.py:148 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "à®®à¯à®±à¯ˆà®¯à®¾à®© படம௠மடà¯à®Ÿà¯à®®à¯‡ பதிவேறà¯à®±à®®à¯ செயà¯à®¯à®µà¯à®®à¯. நீஙà¯à®•ள௠பதிவேறà¯à®±à®®à¯ செயà¯à®¤ கோபà¯à®ªà¯ படம௠அளà¯à®³à®¾à®¤ அளà¯à®³à®¤à¯ கெடà¯à®Ÿà¯à®ªà¯à®ªà¯‹à®© கோபà¯à®ªà®¾à®•à¯à®®à¯" + +#: core/validators.py:155 +#, python-format +msgid "The URL %s does not point to a valid image." +msgstr "%s எனà¯à®± இணையதள à®®à¯à®•வறி சறியான படதà¯à®¤à¯ˆà®šà¯ சà¯à®Ÿà¯à®Ÿà®µà®¿à®²à¯à®²à¯ˆ" + +#: core/validators.py:159 +#, python-format +msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid." +msgstr "தொலைபேசி எணà¯à®•ள௠XXX-XXX-XXXX எனà¯à®± அமைபà¯à®ªà®¿à®²à¯ இரà¯à®•à¯à®• வேணà¯à®Ÿà¯à®®à¯. \"%s\" எனà¯à®ªà®¤à¯ à®®à¯à®±à¯ˆà®¯à®³à¯à®³" + +#: core/validators.py:167 +#, python-format +msgid "The URL %s does not point to a valid QuickTime video." +msgstr "%s எனà¯à®± இணையதள à®®à¯à®•வறி à®®à¯à®±à¯ˆà®¯à®¾à®© கà¯à®¯à®¿à®•௠டைம௠படகà¯à®•ாடà¯à®šà®¿à®¯à¯ˆà®šà¯ சà¯à®Ÿà¯à®Ÿà®µà®¿à®²à¯à®²à¯ˆ" + +#: core/validators.py:171 +msgid "A valid URL is required." +msgstr "à®®à¯à®±à¯ˆà®¯à®¾à®© இணையதள à®®à¯à®•வறி தேவை" + +#: core/validators.py:185 +#, python-format +msgid "" +"Valid HTML is required. Specific errors are:\n" +"%s" +msgstr "" +"à®®à¯à®±à¯ˆà®¯à®¾à®© இணையதள à®®à¯à®•வறி தேவை. கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà®¤à¯à®¤à®•à¯à®•த௠தவறà¯à®•ளாவன:\n" +"%s" + +#: core/validators.py:192 +#, python-format +msgid "Badly formed XML: %s" +msgstr "à®®à¯à®±à¯ˆà®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà®¾à®¤ XML: %s" + +#: core/validators.py:202 +#, python-format +msgid "Invalid URL: %s" +msgstr "à®®à¯à®±à¯ˆà®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà®¾à®¤ இணையதள à®®à¯à®•வறி: %s" + +#: core/validators.py:206 core/validators.py:208 +#, python-format +msgid "The URL %s is a broken link." +msgstr "%s எனà¯à®± இணையதள à®®à¯à®•வறி உடைநà¯à®¤à¯à®³à¯à®³à®¤à¯" + +#: core/validators.py:214 +msgid "Enter a valid U.S. state abbreviation." +msgstr "à®®à¯à®±à¯ˆà®¯à®¾à®© U.S மாநில பெயர௠சà¯à®°à¯à®•à¯à®•ம௠எழà¯à®¤à®µà¯à®®à¯à®´à¯à®¤à®µà¯à®®à¯" + +#: core/validators.py:229 +#, python-format +msgid "Watch your mouth! The word %s is not allowed here." +msgstr "வாரà¯à®¤à¯à®¤à¯ˆà®•ளை அளனà¯à®¤à¯ பேசà¯à®™à¯à®•ளà¯. %s எனà¯à®± வாரà¯à®¤à¯à®¤à¯ˆ இஙà¯à®•௠அனà¯à®®à®¤à®¿ இலà¯à®²à¯ˆ" + +#: core/validators.py:236 +#, python-format +msgid "This field must match the '%s' field." +msgstr "இநà¯à®¤ பà¯à®²à®®à¯ %s எனà¯à®± பà¯à®²à®¤à¯à®¤à¯à®Ÿà®©à¯ ஒதà¯à®¤à®¿à®±à¯à®•à¯à®• வேணà¯à®Ÿà¯à®®à¯" + +#: core/validators.py:255 +msgid "Please enter something for at least one field." +msgstr "தயவ௠செயà¯à®¤à¯ ஒர௠பà¯à®²à®¤à¯à®¤à®¿à®²à®¾à®µà®¤à¯ à®à®¤à®¾à®µà®¤à¯ எழà¯à®¤à®µà¯à®®à¯" + +#: core/validators.py:264 core/validators.py:275 +msgid "Please enter both fields or leave them both empty." +msgstr "தயவ௠செயà¯à®¤à¯ இரà¯à¯à®ªà¯à®²à®™à¯à®•லையà¯à®®à¯à¯à®®à¯ நிரபà¯à®ªà®µà¯à®®à¯; அலà¯à®²à®¤à¯ இரணà¯à®Ÿà¯ˆà®¯à¯à®®à¯ காலியாக விடவà¯à®®à¯" + +#: core/validators.py:282 +#, python-format +msgid "This field must be given if %(field)s is %(value)s" +msgstr "%(field)s, %(value)s ஆக இரà¯à®¨à¯à®¤à®¾à®²à¯ இனà¯à®¤ பà¯à®²à®®à¯ இரà¯à®•à¯à®• வேணà¯à®Ÿà¯à®®à¯" + +#: core/validators.py:294 +#, python-format +msgid "This field must be given if %(field)s is not %(value)s" +msgstr "%(field)s, %(value)s ஆக இலà¯à®²à¯ˆ எனà¯à®±à®¾à®²à¯ இனà¯à®¤ பà¯à®²à®®à¯ இரà¯à®•à¯à®• வேணà¯à®Ÿà¯à®®à¯" + +#: core/validators.py:313 +msgid "Duplicate values are not allowed." +msgstr "போலியான மதிபà¯à®ªà¯à®•ள௠அனà¯à®®à®¤à®¿ இலà¯à®²à¯ˆ" + +#: core/validators.py:336 +#, python-format +msgid "This value must be a power of %s." +msgstr "இநà¯à®¤ மதிபà¯à®ªà¯ %s இன௠அடà¯à®•à¯à®•ாக இரà¯à®•à¯à®• வேனà¯à®Ÿà¯à®®à¯" + +#: core/validators.py:347 +msgid "Please enter a valid decimal number." +msgstr "தயவà¯à®šà¯†à®¯à¯à®¤à¯ à®®à¯à®±à¯ˆà®¯à®¾à®© பதினà¯à®® எணà¯à®£à¯ˆ நழைகà¯à®•cவà¯à®®à¯" + +#: core/validators.py:349 +#, python-format +msgid "" +"Please enter a valid decimal number with at most %s total digit." +"Please enter a valid decimal number with at most %s total digits." +msgstr "" +"அதிகபடà¯à®šà®®à¯ %s எணà¯à®£à¯ˆ உளà¯à®³ பதினà¯à®® எணà¯à®£à¯ˆ நà¯à®´à¯ˆ." +"அதிகபடà¯à®šà®®à¯ %s எணà¯à®•ள௠உளà¯à®³ பதினà¯à®® எணà¯à®£à¯ˆ நà¯à®´à¯ˆ." + +#: core/validators.py:352 +#, python-format +msgid "" +"Please enter a valid decimal number with at most %s decimal place." +"Please enter a valid decimal number with at most %s decimal places." +msgstr "" +"அதிகபடà¯à®šà®®à¯ %s பà¯à®³à¯à®³à®¿ இடம௠ள௠உளà¯à®³ பதினà¯à®® எணà¯à¯ˆ நà¯à®´à¯ˆ" +"அதிகபடà¯à®šà®®à¯ %s பà¯à®³à¯à®³à®¿ இடஙà¯à®•ள௠உளà¯à®³ பதினà¯à®® எணà¯à¯ˆ நà¯à®´à¯ˆ" + +#: core/validators.py:362 +#, python-format +msgid "Make sure your uploaded file is at least %s bytes big." +msgstr "மேலà¯à®à®±à¯à®±à¯ செயà¯à®¯à®ªà¯à®ªà®Ÿà¯à®Ÿ கோபà¯à®ªà¯ கà¯à®±à¯ˆà®¨à¯à®¤à®ªà®Ÿà¯à®šà®®à¯ %s பைடà¯à®Ÿà¯à®•ள௠உளà¯à®³à®©à®µà®¾ என சரி பாரà¯à®•à¯à®•வà¯à®®à¯" + +#: core/validators.py:363 +#, python-format +msgid "Make sure your uploaded file is at most %s bytes big." +msgstr "மேலà¯à®à®±à¯à®±à¯ செயà¯à®¯à®ªà¯à®ªà®Ÿà¯à®Ÿ கோபà¯à®ªà¯ அதிகபடà¯à®šà®®à¯ %s பைடà¯à®Ÿà¯à®•ள௠உளà¯à®³à®©à®µà®¾ என சரி பாரà¯à®•à¯à®•வà¯à®®à¯." + +#: core/validators.py:376 +msgid "The format for this field is wrong." +msgstr "பà¯à®²à®©à¯à®Ÿà¯ˆà®¯ அமைபà¯à®ªà¯ தவறà¯" + +#: core/validators.py:391 +msgid "This field is invalid." +msgstr "இநà¯à®¤ பà¯à®²à®®à¯ செலà¯à®²à®¾à®¤à¯." + +#: core/validators.py:426 +#, python-format +msgid "Could not retrieve anything from %s." +msgstr "%s இரà¯à®¨à¯à®¤à¯ எதà¯à®µà¯à®®à¯ எடà¯à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ" + +#: core/validators.py:429 +#, python-format +msgid "The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'." +msgstr "வலைமனை %(url)s எனà¯à®ªà®¤à¯ செலà¯à®²à®¾à®¤ உளà¯à®³à®Ÿà®•à¯à®•-வகை தலைபà¯à®ªà®¾à®© '%(contenttype)s' ஠திரà¯à®ªà¯à®ªà®¿ தநà¯à®¤à¯à®³à¯à®³à®¤à¯." + +#: core/validators.py:462 +#, python-format +msgid "" +"Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with " +"\"%(start)s\".)" +msgstr " %(line)s கோட௠லிரà¯à®¨à¯à®¤à¯ மூடாத %(tag)s டாகை மூடà¯. ( வரி,\"%(start)s\"வà¯à®Ÿà®©à¯ தà¯à®µà®™à¯à®•à¯à®•ினà¯à®±à®¤à¯)" + +#: core/validators.py:466 +#, python-format +msgid "" +"Some text starting on line %(line)s is not allowed in that context. (Line " +"starts with \"%(start)s\".)" +msgstr "வரி %(line)s இல௠உளà¯à®³ சில உரைகள௠இரà¯à®ªà¯à®ªà®¤à®±à¯à®•௠அனà¯à®®à®¤à®¿ இலà¯à®²à¯ˆ.( வரி,\"%(start)s\"வà¯à®Ÿà®©à¯ தà¯à®µà®™à¯à®•à¯à®•ினà¯à®±à®¤à¯)" + +#: core/validators.py:471 +#, python-format +msgid "" +"\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%" +"(start)s\".)" +msgstr "வரி %(line)s இல௠உளà¯à®³ \"%(attr)s\" எனà¯à®ªà®¤à¯ தவறான பணà¯à®ªà®¾à®•à¯à®®.( வரி,\"%(start)s\"வà¯à®Ÿà®©à¯ தà¯à®µà®™à¯à®•à¯à®•ினà¯à®±à®¤à¯)" + +#: core/validators.py:476 +#, python-format +msgid "" +"\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%" +"(start)s\".)" +msgstr "வரி %(line)s இல௠உளà¯à®³ \"<%(tag)s>\" எனà¯à®ªà®¤à¯ தவறான ஒடà¯à®Ÿà®¾à®•à¯à®®à¯ .( வரி,\"%(start)s\"வà¯à®Ÿà®©à¯ தà¯à®µà®™à¯à®•à¯à®•ினà¯à®±à®¤à¯)" + +#: core/validators.py:480 +#, python-format +msgid "" +"A tag on line %(line)s is missing one or more required attributes. (Line " +"starts with \"%(start)s\".)" +msgstr "வரி %(line)s இல௠உளà¯à®³ ஒடà¯à®Ÿà¯ இன பணà¯à®ªà¯à®•ள௠தேவைபà¯à®ªà®Ÿà¯à®•ினà¯à®±à®©.(வரி,\"%(start)s\" வà¯à®Ÿà®©à¯ தà¯à®µà®™à¯à®•à¯à®•ினà¯à®±à®¤à¯)" + +#: core/validators.py:485 +#, python-format +msgid "" +"The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line " +"starts with \"%(start)s\".)" +msgstr "வரி %(line)s இல௠உளà¯à®³ \"%(attr)s\" பணà¯à®ªà®¿à®©à¯ மதிபà¯à®ªà¯ தவறானதà¯.(வரி \"%(start)s\" இரà¯à®¨à¯à®¤à¯ ஆரமà¯à®ªà®®à¯)" + +#: db/models/manipulators.py:302 +#, python-format +#, fuzzy +msgid "%(object)s with this %(type)s already exists for the given %(field)s." +msgstr "%(type)s உடன௠உளà¯à®³ %(object)s உளà¯à®³à®¤à¯" + +#: db/models/fields/__init__.py:40 +#, python-format +msgid "%(optname)s with this %(fieldname)s already exists." +msgstr "%(fieldname)s உடன௠உளà¯à®³ %(optname)s உயிரà¯à®Ÿà®© உளà¯à®³à®¤à¯" + +#: db/models/fields/__init__.py:114 db/models/fields/__init__.py:265 +#: db/models/fields/__init__.py:542 db/models/fields/__init__.py:553 +#: forms/__init__.py:346 +msgid "This field is required." +msgstr "இநà¯à®¤ பà¯à®²à®¤à¯à®¤à®¿à®²à¯ மதிபà¯à®ªà¯ தேவை" + +#: db/models/fields/__init__.py:337 +msgid "This value must be an integer." +msgstr "இநà¯à®¤ மதிபà¯à®ªà¯ à®®à¯à®´à¯à®µà¯†à®£à¯à®£à®¾à®• இரà¯à®•à¯à®• வேணà¯à®Ÿà¯à®®" + +#: db/models/fields/__init__.py:369 +msgid "This value must be either True or False." +msgstr "இநà¯à®¤ மதிபà¯à®ªà¯ சரி அலà¯à®²à®¤à¯ தவறாக இரà¯à®•à¯à®• வேணà¯à®Ÿà¯à®®à¯" + +#: db/models/fields/__init__.py:385 +msgid "This field cannot be null." +msgstr "இநà¯à®¤ பà¯à®²à®®à¯ காலியாக இரà¯à®•à¯à®•க௠கூடாதà¯" + +#: db/models/fields/__init__.py:562 +msgid "Enter a valid filename." +msgstr "à®®à¯à®±à¯ˆà®¯à®¾à®© கோபà¯à®ªà¯à®ªà¯ பெயரை எழà¯à®¤à®µà¯à®®à¯" + +#: db/models/fields/related.py:43 +#, python-format +msgid "Please enter a valid %s." +msgstr "தயவ௠செயà¯à®¤à¯ à®®à¯à®±à¯ˆà®¯à®¾à®© %s எழà¯à®¤à®µà¯à®®à¯" + +#: db/models/fields/related.py:579 +msgid "Separate multiple IDs with commas." +msgstr "பனà¯à®®à¯ˆà®¯à®¿à®²à¯à®³à¯à®³ அடையாளஙà¯à®•ளை காறà¯à®ªà¯à®³à¯à®³à®¿à®•ளால௠பிரிகà¯à®•வà¯à®®à¯" + +#: db/models/fields/related.py:581 +msgid "Hold down \"Control\", or \"Command\" on a Mac, to select more than one." +msgstr "Mac இலà¯, ஒனà¯à®±à¯à®•à¯à®•௠மேறà¯à®ªà®Ÿà¯à®Ÿà®µà®±à¯à®±à¯ˆ தேரà¯à®µà¯ செயà¯à®¯ \"Control\" அலà¯à®²à®¤à¯ \"Command\" à® à®…à®´à¯à®¤à¯à®¤à®µà¯à®®à¯" + +#: db/models/fields/related.py:625 +#, python-format +msgid "" +"Please enter valid %(self)s IDs. The value %(value)r is invalid." +"Please enter valid %(self)s IDs. The values %(value)r are invalid." +msgstr "" +"தயவ௠செயà¯à®¤à¯ à®®à¯à®±à¯ˆà®¯à®¾à®© %(self)s அடையாளஙà¯à®•ளை எழà¯à®¤à®µà¯à®®à¯. %(value)r எனà¯à®± மதிபà¯à®ªà¯ à®®à¯à®±à¯ˆà®¯à®¾à®©à®¤à®²à¯à®². " +"தயவ௠செயà¯à®¤à¯ à®®à¯à®±à¯ˆà®¯à®¾à®© %(self)s அடையாளஙà¯à®•ளை எழà¯à®¤à®µà¯à®®à¯. %(value)r எனà¯à®± மதிபà¯à®ªà¯à®•ள௠மà¯à®±à¯ˆà®¯à®¾à®©à®¤à®²à¯à®². " + +#: forms/__init__.py:380 +#, python-format +msgid "Ensure your text is less than %s character." +msgstr "உஙà¯à®•ள௠உரை %s ஠விட கà¯à®±à¯ˆà®µà®¾à®© எழà¯à®¤à¯à®¤à¯à®•à¯à®•ளை உடையதென உறà¯à®¤à®¿ செயà¯à®¤à¯ கொளà¯à®³à¯à®™à¯à®•ளà¯" + +#: forms/__init__.py:385 +msgid "Line breaks are not allowed here." +msgstr "வரி உடைவà¯à®•ள௠அனà¯à®®à®¤à®¿ இலà¯à®²à¯ˆ" + +#: forms/__init__.py:480 forms/__init__.py:551 forms/__init__.py:589 +#, python-format +msgid "Select a valid choice; '%(data)s' is not in %(choices)s." +msgstr "à®®à¯à®±à¯ˆà®¯à®¾à®© விரà¯à®ªà¯à®ªà®¤à¯à®¤à¯ˆ தேரà¯à®µà¯ செயà¯à®¯à®µà¯à®®à¯; '%(data)s எனà¯à®ªà®¤à¯ %(choices)s இல௠இலà¯à®²à¯ˆ" + +#: forms/__init__.py:645 +msgid "The submitted file is empty." +msgstr "சமரà¯à®ªà®¿à®•à¯à®•ப௠படà¯à®Ÿ கோபà¯à®ªà¯ காலியாக உளà¯à®³à®¤à¯" + +#: forms/__init__.py:699 +msgid "Enter a whole number between -32,768 and 32,767." +msgstr "-32,768 மறà¯à®±à¯à®®à¯ 32,767 க௠நடà¯à®µà®¿à®²à¯ ஒர௠மà¯à®´à¯ எணà¯à®£à¯ˆ எழà¯à®¤à®µà¯à®®à¯" + +#: forms/__init__.py:708 +msgid "Enter a positive number." +msgstr "ஒர௠நேரà¯à®•à¯à®•à¯à®±à®¿Â எணà¯à®£à¯ˆ எழà¯à®¤à®µà¯à®®à¯" + +#: forms/__init__.py:717 +msgid "Enter a whole number between 0 and 32,767." +msgstr "0 மறà¯à®±à¯à®®à¯ 32,767 க௠நடà¯à®µà®¿à®²à¯ ஒர௠மà¯à®´à¯ எணà¯à®£à¯ˆ எழà¯à®¤à®µà¯à®®à¯" + +#: template/defaultfilters.py:379 +msgid "yes,no,maybe" +msgstr "ஆமà¯, இலà¯à®²à¯ˆ, இரà¯à®•à¯à®•லாமà¯" + diff --git a/django/conf/locale/tr/LC_MESSAGES/django.mo b/django/conf/locale/tr/LC_MESSAGES/django.mo Binary files differnew file mode 100644 index 0000000000..2415d26ee9 --- /dev/null +++ b/django/conf/locale/tr/LC_MESSAGES/django.mo diff --git a/django/conf/locale/tr/LC_MESSAGES/django.po b/django/conf/locale/tr/LC_MESSAGES/django.po new file mode 100644 index 0000000000..daa299ca66 --- /dev/null +++ b/django/conf/locale/tr/LC_MESSAGES/django.po @@ -0,0 +1,2209 @@ +# translation of django.po to Turkish +# Django 0.95 +# Copyright (C) 2006 Django +# This file is distributed under the same license as the Django package. +# +# Bahadır Kandemir <bahadir@pardus.org.tr>, 2006. +msgid "" +msgstr "" +"Project-Id-Version: django\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2006-10-01 21:09+0300\n" +"PO-Revision-Date: 2006-10-01 21:19+0300\n" +"Last-Translator: Bahadır Kandemir <bahadir@pardus.org.tr>\n" +"Language-Team: Turkish <bahadir@pardus.org.tr>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" + +#: db/models/manipulators.py:305 +#, python-format +msgid "%(object)s with this %(type)s already exists for the given %(field)s." +msgstr "%(type)s ve %(field)s deÄŸerine sahip %(object)s kaydı zaten var." + +#: db/models/manipulators.py:332 +#, python-format +msgid "" +"Please enter a different %s. The one you entered is already being used for %" +"s." +msgstr "Lütfen farklı bir %s girin. GirdiÄŸiniz, %s tarihinde bir kez kullanılmış." + +#: db/models/fields/__init__.py:41 +#, python-format +msgid "%(optname)s with this %(fieldname)s already exists." +msgstr "%(fieldname)s için %(optname)s deÄŸeri zaten seçilmiÅŸ." + +#: db/models/fields/__init__.py:115 db/models/fields/__init__.py:266 +#: db/models/fields/__init__.py:560 db/models/fields/__init__.py:571 +#: forms/__init__.py:347 +msgid "This field is required." +msgstr "Bu alan gerekli." + +#: db/models/fields/__init__.py:349 +msgid "This value must be an integer." +msgstr "Bu deÄŸer tamsayı olmalı." + +#: db/models/fields/__init__.py:381 +msgid "This value must be either True or False." +msgstr "Bu deÄŸer True ya da False olabilir." + +#: db/models/fields/__init__.py:397 +msgid "This field cannot be null." +msgstr "Bu alan boÅŸ bırakılamaz." + +#: db/models/fields/__init__.py:424 core/validators.py:146 +msgid "Enter a valid date in YYYY-MM-DD format." +msgstr "YYYY-AA-GG formatında tarih girin." + +#: db/models/fields/__init__.py:486 core/validators.py:155 +msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format." +msgstr "YYYY-AA-GG SS:DD formatında tarih girin." + +#: db/models/fields/__init__.py:580 +msgid "Enter a valid filename." +msgstr "Geçerli bir dosya adı girin." + +#: db/models/fields/related.py:51 +#, python-format +msgid "Please enter a valid %s." +msgstr "Lütfen geçerli bir %s girin." + +#: db/models/fields/related.py:618 +msgid "Separate multiple IDs with commas." +msgstr "Birden fazla numarayı virgül ile ayırın." + +#: db/models/fields/related.py:620 +msgid "Hold down \"Control\", or \"Command\" on a Mac, to select more than one." +msgstr "" +"\"Ctrl\" ve Mac'de \"Command\" tuÅŸunu basılı tutarak birden fazla seçimde " +"bulunabilirsiniz." + +#: db/models/fields/related.py:664 +#, python-format +msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid." +msgid_plural "Please enter valid %(self)s IDs. The values %(value)r are invalid." +msgstr[0] "Lütfen geçerli bir %(self)s numarası girin. %(value)r deÄŸeri geçersiz." +msgstr[1] "Lütfen geçerli %(self)s numaraları girin. %(value)r deÄŸerleri geçersiz." + +#: conf/global_settings.py:39 +msgid "Arabic" +msgstr "Arapça" + +#: conf/global_settings.py:40 +msgid "Bengali" +msgstr "Bengali Dili" + +#: conf/global_settings.py:41 +msgid "Czech" +msgstr "Çekçe" + +#: conf/global_settings.py:42 +msgid "Welsh" +msgstr "Galce" + +#: conf/global_settings.py:43 +msgid "Danish" +msgstr "Danca" + +#: conf/global_settings.py:44 +msgid "German" +msgstr "Almanca" + +#: conf/global_settings.py:45 +msgid "Greek" +msgstr "Yunanca" + +#: conf/global_settings.py:46 +msgid "English" +msgstr "İngilizce" + +#: conf/global_settings.py:47 +msgid "Spanish" +msgstr "İspanyolca" + +#: conf/global_settings.py:48 +msgid "Argentinean Spanish" +msgstr "Arjantin İspanyolcası" + +#: conf/global_settings.py:49 +msgid "Finnish" +msgstr "Fince" + +#: conf/global_settings.py:50 +msgid "French" +msgstr "Fransızca" + +#: conf/global_settings.py:51 +msgid "Galician" +msgstr "Galler Dili" + +#: conf/global_settings.py:52 +msgid "Hungarian" +msgstr "Macarca" + +#: conf/global_settings.py:53 +msgid "Hebrew" +msgstr "İbranice" + +#: conf/global_settings.py:54 +msgid "Icelandic" +msgstr "İzlanda dili" + +#: conf/global_settings.py:55 +msgid "Italian" +msgstr "İtalyanca" + +#: conf/global_settings.py:56 +msgid "Japanese" +msgstr "Japonca" + +#: conf/global_settings.py:57 +msgid "Dutch" +msgstr "Flamanca" + +#: conf/global_settings.py:58 +msgid "Norwegian" +msgstr "Norveç Dili" + +#: conf/global_settings.py:59 +msgid "Brazilian" +msgstr "Brezilya Dili" + +#: conf/global_settings.py:60 +msgid "Romanian" +msgstr "Romence" + +#: conf/global_settings.py:61 +msgid "Russian" +msgstr "Rusça" + +#: conf/global_settings.py:62 +msgid "Slovak" +msgstr "Slovakça" + +#: conf/global_settings.py:63 +msgid "Slovenian" +msgstr "Slovence" + +#: conf/global_settings.py:64 +msgid "Serbian" +msgstr "Sırpça" + +#: conf/global_settings.py:65 +msgid "Swedish" +msgstr "İsveççe" + +#: conf/global_settings.py:66 +msgid "Tamil" +msgstr "Tamilce" + +#: conf/global_settings.py:67 +msgid "Turkish" +msgstr "Türkçe" + +#: conf/global_settings.py:68 +msgid "Ukrainian" +msgstr "Ukraynaca" + +#: conf/global_settings.py:69 +msgid "Simplified Chinese" +msgstr "BasiteÅŸtirilmiÅŸ Çince" + +#: conf/global_settings.py:70 +msgid "Traditional Chinese" +msgstr "Gelenelsek Çince" + +#: forms/__init__.py:382 +#, python-format +msgid "Ensure your text is less than %s character." +msgid_plural "Ensure your text is less than %s characters." +msgstr[0] "Metnin %s karakterden az olmasına dikkat edin." +msgstr[1] "Metnin %s karakterden az olmasına dikkat edin." + +#: forms/__init__.py:387 +msgid "Line breaks are not allowed here." +msgstr "Burada birden fazla satır olamaz." + +#: forms/__init__.py:488 forms/__init__.py:561 forms/__init__.py:600 +#, python-format +msgid "Select a valid choice; '%(data)s' is not in %(choices)s." +msgstr "Geçerli bir seçimde bulunun; %(choices)s deÄŸerleri içinde '%(data)s' yok." + +#: forms/__init__.py:662 core/validators.py:172 core/validators.py:401 +msgid "No file was submitted. Check the encoding type on the form." +msgstr "Dosya gönderilmedi. Formdaki kodlama türünü kontrol edin." + +#: forms/__init__.py:664 +msgid "The submitted file is empty." +msgstr "Gönderilen dosya boÅŸ." + +#: forms/__init__.py:720 +msgid "Enter a whole number between -32,768 and 32,767." +msgstr "-32,768 ve 32,767 arası bir sayı girin." + +#: forms/__init__.py:730 +msgid "Enter a positive number." +msgstr "Pozitif tamsayı girin." + +#: forms/__init__.py:740 +msgid "Enter a whole number between 0 and 32,767." +msgstr "0 ve 32,767 arası bir sayı girin." + +#: core/validators.py:63 +msgid "This value must contain only letters, numbers and underscores." +msgstr "Bu deÄŸer sadece karakter, rakam ve altçizgiden oluÅŸabilir." + +#: core/validators.py:67 +msgid "" +"This value must contain only letters, numbers, underscores, dashes or " +"slashes." +msgstr "Bu deÄŸer sadece harf, rakam, altçizgi, bölü ve ters bölüden oluÅŸabilir." + +#: core/validators.py:71 +msgid "This value must contain only letters, numbers, underscores or hyphens." +msgstr "Bu deÄŸer sadece harf, rakam, altçizgi veya çizgiden oluÅŸabilir." + +#: core/validators.py:75 +msgid "Uppercase letters are not allowed here." +msgstr "Burada büyük harf kullanılamaz." + +#: core/validators.py:79 +msgid "Lowercase letters are not allowed here." +msgstr "Burada küçük harf kullanılamaz." + +#: core/validators.py:86 +msgid "Enter only digits separated by commas." +msgstr "Sadece virgülle ayrılmış sayılar girin." + +#: core/validators.py:98 +msgid "Enter valid e-mail addresses separated by commas." +msgstr "Virgülle ayrılmış geçerli e-posta adresleri girin." + +#: core/validators.py:102 +msgid "Please enter a valid IP address." +msgstr "Lütfen geçerli bir IP adresi girin." + +#: core/validators.py:106 +msgid "Empty values are not allowed here." +msgstr "Burada boÅŸ deÄŸer kullanılamaz." + +#: core/validators.py:110 +msgid "Non-numeric characters aren't allowed here." +msgstr "Burada numerik olmayan karakterler kullanılamaz." + +#: core/validators.py:114 +msgid "This value can't be comprised solely of digits." +msgstr "Bu alanda sadece rakam kullanılamaz." + +#: core/validators.py:119 +msgid "Enter a whole number." +msgstr "Sayı girin." + +#: core/validators.py:123 +msgid "Only alphabetical characters are allowed here." +msgstr "Burada sadece alfabetik karakterler kullanılabilir." + +#: core/validators.py:138 +msgid "Year must be 1900 or later." +msgstr "Yıl 1900 ya da sonrası olabilir." + +#: core/validators.py:142 +#, python-format +msgid "Invalid date: %s." +msgstr "Geçersiz tarih: %s" + +#: core/validators.py:151 +msgid "Enter a valid time in HH:MM format." +msgstr "SS:DD formatında geçerli bir saat girin." + +#: core/validators.py:160 +msgid "Enter a valid e-mail address." +msgstr "Geçerli bir e-posta adresi girin." + +#: core/validators.py:176 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "" +"Geçerli bir resim girin. GönderdiÄŸiniz dosya resim deÄŸil, ya da bozuk bir " +"dosya." + +#: core/validators.py:183 +#, python-format +msgid "The URL %s does not point to a valid image." +msgstr "%s adresi geçerli bir resme iÅŸaret etmiyor." + +#: core/validators.py:187 +#, python-format +msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid." +msgstr "Telefon numarası XXX-XXX-XXXX formatında olmalı. \"%s\" geçersiz." + +#: core/validators.py:195 +#, python-format +msgid "The URL %s does not point to a valid QuickTime video." +msgstr "%s adresi geçerli bir QuickTime dosyasına iÅŸaret etmiyor." + +#: core/validators.py:199 +msgid "A valid URL is required." +msgstr "Geçerli bir URL gerekli." + +#: core/validators.py:213 +#, python-format +msgid "" +"Valid HTML is required. Specific errors are:\n" +"%s" +msgstr "" +"Metnin geçerli bir HTML kodu olması gerekir. Hatalar:\n" +"%s" + +#: core/validators.py:220 +#, python-format +msgid "Badly formed XML: %s" +msgstr "Geçersiz XML kodu: %s" + +#: core/validators.py:230 +#, python-format +msgid "Invalid URL: %s" +msgstr "Geçersiz adres: %s" + +#: core/validators.py:234 core/validators.py:236 +#, python-format +msgid "The URL %s is a broken link." +msgstr "%s kırık bir link." + +#: core/validators.py:242 +msgid "Enter a valid U.S. state abbreviation." +msgstr "Geçerli bir ÅŸehir kodu girin." + +#: core/validators.py:256 +#, python-format +msgid "Watch your mouth! The word %s is not allowed here." +msgid_plural "Watch your mouth! The words %s are not allowed here." +msgstr[0] "SöylediÄŸinize dikkat edin! %s kelimesi burada kullanılamaz." +msgstr[1] "SöylediÄŸinize dikkat edin! %s kelimeleri burada kullanılamaz." + +#: core/validators.py:263 +#, python-format +msgid "This field must match the '%s' field." +msgstr "Bu alan '%s' ile alanı ile uyuÅŸmalı." + +#: core/validators.py:282 +msgid "Please enter something for at least one field." +msgstr "Lütfen en az bir alana giriÅŸ yapın." + +#: core/validators.py:291 core/validators.py:302 +msgid "Please enter both fields or leave them both empty." +msgstr "Lütfen tüm alanları doldurun ya da hepsini boÅŸ bırakın." + +#: core/validators.py:309 +#, python-format +msgid "This field must be given if %(field)s is %(value)s" +msgstr "Bu alan %(field)s alanı %(value)s deÄŸerine sahipse doldurulmalı." + +#: core/validators.py:321 +#, python-format +msgid "This field must be given if %(field)s is not %(value)s" +msgstr "Bu alan %(field)s alanı %(value)s deÄŸerine sahip deÄŸilse doldurulmalı." + +#: core/validators.py:340 +msgid "Duplicate values are not allowed." +msgstr "Tekrarlanan deÄŸerler kabul edilmez." + +#: core/validators.py:363 +#, python-format +msgid "This value must be a power of %s." +msgstr "Bu deÄŸer %s ya da kuvvetleri olabilir." + +#: core/validators.py:374 +msgid "Please enter a valid decimal number." +msgstr "Lütfen geçerli bir ondalık sayı girin." + +#: core/validators.py:378 +#, python-format +msgid "Please enter a valid decimal number with at most %s total digit." +msgid_plural "Please enter a valid decimal number with at most %s total digits." +msgstr[0] "Lütfen en fazla %s basamaklı bir ondalık sayı girin." +msgstr[1] "Lütfen en fazla %s basamaklı bir ondalık sayı girin." + +#: core/validators.py:381 +#, python-format +msgid "Please enter a valid decimal number with a whole part of at most %s digit." +msgid_plural "Please enter a valid decimal number with a whole part of at most %s digits." +msgstr[0] "Lütfen tamsayı kısmı en fazla %s basamaklı bir ondalık sayı girin." +msgstr[1] "Lütfen tamsayı kısmı en fazla %s basamaklı bir ondalık sayı girin." + +#: core/validators.py:384 +#, python-format +msgid "Please enter a valid decimal number with at most %s decimal place." +msgid_plural "Please enter a valid decimal number with at most %s decimal places." +msgstr[0] "Lütfen ondalıklı kısmı en fazla %s basamaklı bir ondalık sayı girin." +msgstr[1] "Lütfen ondalıklı kısmı en fazla %s basamaklı bir ondalık sayı girin." + +#: core/validators.py:394 +#, python-format +msgid "Make sure your uploaded file is at least %s bytes big." +msgstr "GönderdiÄŸiniz dosyanın en az %s byte uzunlukta olduÄŸundan emin olun." + +#: core/validators.py:395 +#, python-format +msgid "Make sure your uploaded file is at most %s bytes big." +msgstr "GönderdiÄŸiniz dosyanın en fazl %s byte uzunlukta olduÄŸundan emin olun." + +#: core/validators.py:412 +msgid "The format for this field is wrong." +msgstr "Bu alandaki veri formatı hatalı." + +#: core/validators.py:427 +msgid "This field is invalid." +msgstr "Alan geçersiz." + +#: core/validators.py:463 +#, python-format +msgid "Could not retrieve anything from %s." +msgstr "%s içinden hiçbirÅŸey aktarılamıyor." + +#: core/validators.py:466 +#, python-format +msgid "The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'." +msgstr "%(url)s adresi geçersiz içerik türü (%(contenttype)s) gönderdi." + +#: core/validators.py:499 +#, python-format +msgid "" +"Please close the unclosed %(tag)s tag from line %(line)s. (Line starts with " +"\"%(start)s\".)" +msgstr "" +"Lütfen %(line)s. satırdaki kapatılmayan %(tag)s etiketini kapatın. (Satır, " +"\"%(start)s\" ile baÅŸlıyor.)" + +#: core/validators.py:503 +#, python-format +msgid "" +"Some text starting on line %(line)s is not allowed in that context. (Line " +"starts with \"%(start)s\".)" +msgstr "" +"%(line)s. satırda baÅŸlayan bazı kelimeler içerik olarak kabul edilmiyor. " +"(Satır, \"%(start)s\" ile baÅŸlıyor.)" + +#: core/validators.py:508 +#, python-format +msgid "" +"\"%(attr)s\" on line %(line)s is an invalid attribute. (Line starts with \"%" +"(start)s\".)" +msgstr "" +"%(line)s. satırdaki \"%(attr)s\" özelliÄŸi geçersiz. (Satır, \"%(start)s\" " +"ile baÅŸlıyor.)" + +#: core/validators.py:513 +#, python-format +msgid "" +"\"<%(tag)s>\" on line %(line)s is an invalid tag. (Line starts with \"%" +"(start)s\".)" +msgstr "" +"%(line)s. satırdaki \"<%(tag)s>\" etiketi geçersiz. (Satır, \"%(start)s\" " +"ile baÅŸlıyor.)" + +#: core/validators.py:517 +#, python-format +msgid "" +"A tag on line %(line)s is missing one or more required attributes. (Line " +"starts with \"%(start)s\".)" +msgstr "" +"%(line)s. satırdaki bir etiket eksik ya da eklenmesi gereken özellikleri " +"var. (Satır, \"%(start)s\" ile baÅŸlıyor.)" + +#: core/validators.py:522 +#, python-format +msgid "" +"The \"%(attr)s\" attribute on line %(line)s has an invalid value. (Line " +"starts with \"%(start)s\".)" +msgstr "" +"%(line)s. satırdaki \"%(attr)s\" özelliÄŸi geçersiz bir deÄŸere sahip. (Satır, " +"\"%(start)s\" ile baÅŸlıyor.)" + +#: views/generic/create_update.py:43 +#, python-format +msgid "The %(verbose_name)s was created successfully." +msgstr "%(verbose_name)s baÅŸarıyla yaratıldı." + +#: views/generic/create_update.py:117 +#, python-format +msgid "The %(verbose_name)s was updated successfully." +msgstr "%(verbose_name)s baÅŸarıyla güncellendi." + +#: views/generic/create_update.py:184 +#, python-format +msgid "The %(verbose_name)s was deleted." +msgstr "%(verbose_name)s silindi." + +#: utils/dates.py:6 +msgid "Monday" +msgstr "Pazartesi" + +#: utils/dates.py:6 +msgid "Tuesday" +msgstr "Salı" + +#: utils/dates.py:6 +msgid "Wednesday" +msgstr "ÇarÅŸamba" + +#: utils/dates.py:6 +msgid "Thursday" +msgstr "PerÅŸembe" + +#: utils/dates.py:6 +msgid "Friday" +msgstr "Cuma" + +#: utils/dates.py:7 +msgid "Saturday" +msgstr "Cumartesi" + +#: utils/dates.py:7 +msgid "Sunday" +msgstr "Pazar" + +#: utils/dates.py:14 +msgid "January" +msgstr "Ocak" + +#: utils/dates.py:14 +msgid "February" +msgstr "Åžubat" + +#: utils/dates.py:14 utils/dates.py:27 +msgid "March" +msgstr "Mart" + +#: utils/dates.py:14 utils/dates.py:27 +msgid "April" +msgstr "Nisan" + +#: utils/dates.py:14 utils/dates.py:27 +msgid "May" +msgstr "Mayıs" + +#: utils/dates.py:14 utils/dates.py:27 +msgid "June" +msgstr "Haziran" + +#: utils/dates.py:15 utils/dates.py:27 +msgid "July" +msgstr "Temmuz" + +#: utils/dates.py:15 +msgid "August" +msgstr "AÄŸustos" + +#: utils/dates.py:15 +msgid "September" +msgstr "Eylül" + +#: utils/dates.py:15 +msgid "October" +msgstr "Ekim" + +#: utils/dates.py:15 +msgid "November" +msgstr "Kasım" + +#: utils/dates.py:16 +msgid "December" +msgstr "Aralık" + +#: utils/dates.py:19 +msgid "jan" +msgstr "oca" + +#: utils/dates.py:19 +msgid "feb" +msgstr "ÅŸub" + +#: utils/dates.py:19 +msgid "mar" +msgstr "mar" + +#: utils/dates.py:19 +msgid "apr" +msgstr "nis" + +#: utils/dates.py:19 +msgid "may" +msgstr "may" + +#: utils/dates.py:19 +msgid "jun" +msgstr "haz" + +#: utils/dates.py:20 +msgid "jul" +msgstr "tem" + +#: utils/dates.py:20 +msgid "aug" +msgstr "aÄŸu" + +#: utils/dates.py:20 +msgid "sep" +msgstr "eyl" + +#: utils/dates.py:20 +msgid "oct" +msgstr "eki" + +#: utils/dates.py:20 +msgid "nov" +msgstr "kas" + +#: utils/dates.py:20 +msgid "dec" +msgstr "ara" + +#: utils/dates.py:27 +msgid "Jan." +msgstr "Oca." + +#: utils/dates.py:27 +msgid "Feb." +msgstr "Åžub." + +#: utils/dates.py:28 +msgid "Aug." +msgstr "AÄŸu." + +#: utils/dates.py:28 +msgid "Sept." +msgstr "Eyl." + +#: utils/dates.py:28 +msgid "Oct." +msgstr "Eki." + +#: utils/dates.py:28 +msgid "Nov." +msgstr "Kas." + +#: utils/dates.py:28 +msgid "Dec." +msgstr "Ara." + +#: utils/timesince.py:12 +msgid "year" +msgid_plural "years" +msgstr[0] "yıl" +msgstr[1] "yıl" + +#: utils/timesince.py:13 +msgid "month" +msgid_plural "months" +msgstr[0] "ay" +msgstr[1] "ay" + +#: utils/timesince.py:14 +msgid "week" +msgid_plural "weeks" +msgstr[0] "hafta" +msgstr[1] "hafta" + +#: utils/timesince.py:15 +msgid "day" +msgid_plural "days" +msgstr[0] "gün" +msgstr[1] "gün" + +#: utils/timesince.py:16 +msgid "hour" +msgid_plural "hours" +msgstr[0] "saat" +msgstr[1] "saat" + +#: utils/timesince.py:17 +msgid "minute" +msgid_plural "minutes" +msgstr[0] "dakika" +msgstr[1] "dakika" + +#: utils/translation/trans_real.py:362 +msgid "DATE_FORMAT" +msgstr "DATE_FORMAT" + +#: utils/translation/trans_real.py:363 +msgid "DATETIME_FORMAT" +msgstr "DATETIME_FORMAT" + +#: utils/translation/trans_real.py:364 +msgid "TIME_FORMAT" +msgstr "TIME_FORMAT" + +#: utils/translation/trans_real.py:380 +msgid "YEAR_MONTH_FORMAT" +msgstr "YEAR_MONTH_FORMAT" + +#: utils/translation/trans_real.py:381 +msgid "MONTH_DAY_FORMAT" +msgstr "MONTH_DAY_FORMAT" + +#: contrib/contenttypes/models.py:20 +msgid "python model class name" +msgstr "python model sınıfı" + +#: contrib/contenttypes/models.py:23 +msgid "content type" +msgstr "içerik türü" + +#: contrib/contenttypes/models.py:24 +msgid "content types" +msgstr "içerik türleri" + +#: contrib/auth/views.py:39 +msgid "Logged out" +msgstr "Çıkış yapıldı" + +#: contrib/auth/models.py:38 contrib/auth/models.py:57 +msgid "name" +msgstr "isim" + +#: contrib/auth/models.py:40 +msgid "codename" +msgstr "takma ad" + +#: contrib/auth/models.py:42 +msgid "permission" +msgstr "izin" + +#: contrib/auth/models.py:43 contrib/auth/models.py:58 +msgid "permissions" +msgstr "izinler" + +#: contrib/auth/models.py:60 +msgid "group" +msgstr "grup" + +#: contrib/auth/models.py:61 contrib/auth/models.py:100 +msgid "groups" +msgstr "gruplar" + +#: contrib/auth/models.py:90 +msgid "username" +msgstr "kullanıcı adı" + +#: contrib/auth/models.py:90 +msgid "" +"Required. 30 characters or fewer. Alphanumeric characters only (letters, " +"digits and underscores)." +msgstr "" +"Gerekli. 30 karakter ya da da az olmalı. Alfanumerik (harf, rakam ve alt " +"çizgi) karakterler kullanılabilir." + +#: contrib/auth/models.py:91 +msgid "first name" +msgstr "isim" + +#: contrib/auth/models.py:92 +msgid "last name" +msgstr "soyisim" + +#: contrib/auth/models.py:93 +msgid "e-mail address" +msgstr "e-posta adresi" + +#: contrib/auth/models.py:94 +msgid "password" +msgstr "parola" + +#: contrib/auth/models.py:94 +msgid "Use '[algo]$[salt]$[hexdigest]'" +msgstr "'[algo]$[salt]$[hexdigest]' formatında" + +#: contrib/auth/models.py:95 +msgid "staff status" +msgstr "yönetici modu" + +#: contrib/auth/models.py:95 +msgid "Designates whether the user can log into this admin site." +msgstr "Kullanıcının yönetici sayfasına girip giremeyeceÄŸini belirler." + +#: contrib/auth/models.py:96 +msgid "active" +msgstr "aktif" + +#: contrib/auth/models.py:96 +msgid "" +"Designates whether this user can log into the Django admin. Unselect this " +"instead of deleting accounts." +msgstr "" +"Kullanıcının Django yönetim sayfasına girip giremeyeceÄŸini belirler. " +"Kullanıcı hesabı silmek yerine iÅŸareti kaldırın." + +#: contrib/auth/models.py:97 +msgid "superuser status" +msgstr "süper kullanıcı modu" + +#: contrib/auth/models.py:97 +msgid "" +"Designates that this user has all permissions without explicitly assigning " +"them." +msgstr "" +"Kullanıcının tek tek hak atamasına gerek kalmadan tüm haklara sahip olup " +"olamayacağını belirler." + +#: contrib/auth/models.py:98 +msgid "last login" +msgstr "son ziyaret" + +#: contrib/auth/models.py:99 +msgid "date joined" +msgstr "kayıt tarihi" + +#: contrib/auth/models.py:101 +msgid "" +"In addition to the permissions manually assigned, this user will also get " +"all permissions granted to each group he/she is in." +msgstr "" +"Özel olarak atanmış hakların yanı sıra, kullanıcının üyesi olduÄŸu grupların " +"hakları alır." + +#: contrib/auth/models.py:102 +msgid "user permissions" +msgstr "kullanıcı izinleri" + +#: contrib/auth/models.py:105 +msgid "user" +msgstr "kullanıcı" + +#: contrib/auth/models.py:106 +msgid "users" +msgstr "kullanıcılar" + +#: contrib/auth/models.py:111 +msgid "Personal info" +msgstr "KiÅŸisel bilgiler" + +#: contrib/auth/models.py:112 +msgid "Permissions" +msgstr "İzinler" + +#: contrib/auth/models.py:113 +msgid "Important dates" +msgstr "Önemli tarihler" + +#: contrib/auth/models.py:114 +msgid "Groups" +msgstr "Gruplar" + +#: contrib/auth/models.py:258 +msgid "message" +msgstr "mesaj" + +#: contrib/auth/forms.py:16 +msgid "The two password fields didn't match." +msgstr "İki parola alanı uyuÅŸmuyor." + +#: contrib/auth/forms.py:24 +msgid "A user with that username already exists." +msgstr "Bu isimde bir kullanıcı zaten var." + +#: contrib/auth/forms.py:52 +msgid "" +"Your Web browser doesn't appear to have cookies enabled. Cookies are " +"required for logging in." +msgstr "" +"Web tarayıcınızın çerezleri desteklemediÄŸi görülüyor. Çerezler giriÅŸ için " +"gerekli." + +#: contrib/auth/forms.py:59 contrib/admin/views/decorators.py:10 +msgid "" +"Please enter a correct username and password. Note that both fields are case-" +"sensitive." +msgstr "" +"Lütfen geçerli bir kullanıcı adı ve parola girin. Tüm alanlar büyük/küçük " +"harf duyarlıdır." + +#: contrib/auth/forms.py:61 +msgid "This account is inactive." +msgstr "Bu hesap aktif deÄŸil." + +#: contrib/auth/forms.py:84 +msgid "" +"That e-mail address doesn't have an associated user acount. Are you sure " +"you've registered?" +msgstr "Bu e-posta hesabıyla iliÅŸkili kullanıcı bulunmuyor. Kayıtlı olduÄŸunuzdan emin misiniz?" + +#: contrib/auth/forms.py:116 +msgid "The two 'new password' fields didn't match." +msgstr "İki parola alanı uyuÅŸmuyor." + +#: contrib/auth/forms.py:123 +msgid "Your old password was entered incorrectly. Please enter it again." +msgstr "Eski parolanız hatalı. Lütfen tekrar girin." + +#: contrib/redirects/models.py:7 +msgid "redirect from" +msgstr "eski adres" + +#: contrib/redirects/models.py:8 +msgid "" +"This should be an absolute path, excluding the domain name. Example: '/" +"events/search/'." +msgstr "" +"Buraya tam dosya yolu, alan adı kullanılmadan yazılmalı. Örnek: '/events/" +"search/'." + +#: contrib/redirects/models.py:9 +msgid "redirect to" +msgstr "yeni adres" + +#: contrib/redirects/models.py:10 +msgid "" +"This can be either an absolute path (as above) or a full URL starting with " +"'http://'." +msgstr "" +"Buraya tam dosya yolu (yukarıdaki gibi), ya da 'http://' ile baÅŸlayan tam " +"adres yazılmalı." + +#: contrib/redirects/models.py:13 +msgid "redirect" +msgstr "yönlendirme" + +#: contrib/redirects/models.py:14 +msgid "redirects" +msgstr "yönlendirmeler" + +#: contrib/comments/models.py:67 contrib/comments/models.py:166 +msgid "object ID" +msgstr "nesne no" + +#: contrib/comments/models.py:68 +msgid "headline" +msgstr "baÅŸlık" + +#: contrib/comments/models.py:69 contrib/comments/models.py:90 +#: contrib/comments/models.py:167 +msgid "comment" +msgstr "yorum" + +#: contrib/comments/models.py:70 +msgid "rating #1" +msgstr "reyting 1" + +#: contrib/comments/models.py:71 +msgid "rating #2" +msgstr "reyting 2" + +#: contrib/comments/models.py:72 +msgid "rating #3" +msgstr "reyting 3" + +#: contrib/comments/models.py:73 +msgid "rating #4" +msgstr "reyting 4" + +#: contrib/comments/models.py:74 +msgid "rating #5" +msgstr "reyting 5" + +#: contrib/comments/models.py:75 +msgid "rating #6" +msgstr "reyting 6" + +#: contrib/comments/models.py:76 +msgid "rating #7" +msgstr "reyting 7" + +#: contrib/comments/models.py:77 +msgid "rating #8" +msgstr "reyting 8" + +#: contrib/comments/models.py:82 +msgid "is valid rating" +msgstr "geçerli reyting" + +#: contrib/comments/models.py:83 contrib/comments/models.py:169 +msgid "date/time submitted" +msgstr "gönderim tarihi/saati" + +#: contrib/comments/models.py:84 contrib/comments/models.py:170 +msgid "is public" +msgstr "görünürlük" + +#: contrib/comments/models.py:85 contrib/admin/views/doc.py:304 +msgid "IP address" +msgstr "IP adresi" + +#: contrib/comments/models.py:86 +msgid "is removed" +msgstr "silinmiÅŸ" + +#: contrib/comments/models.py:86 +msgid "" +"Check this box if the comment is inappropriate. A \"This comment has been " +"removed\" message will be displayed instead." +msgstr "" +"Yorum uygunsuz ise bu iÅŸareti kaldırın. \"Yorum silindi\" uyarısı " +"görüntülenecek." + +#: contrib/comments/models.py:91 +msgid "comments" +msgstr "yorumlar" + +#: contrib/comments/models.py:131 contrib/comments/models.py:207 +msgid "Content object" +msgstr "İçerik nesnesi" + +#: contrib/comments/models.py:159 +#, python-format +msgid "" +"Posted by %(user)s at %(date)s\n" +"\n" +"%(comment)s\n" +"\n" +"http://%(domain)s%(url)s" +msgstr "" +"%(date)s tarihinde %(user)s göndermiÅŸ:\n" +"\n" +"%(comment)s\n" +"\n" +"http://%(domain)s%(url)s" + +#: contrib/comments/models.py:168 +msgid "person's name" +msgstr "isim" + +#: contrib/comments/models.py:171 +msgid "ip address" +msgstr "ip adresi" + +#: contrib/comments/models.py:173 +msgid "approved by staff" +msgstr "yönetici onayı" + +#: contrib/comments/models.py:176 +msgid "free comment" +msgstr "serbest yorum" + +#: contrib/comments/models.py:177 +msgid "free comments" +msgstr "serbest yorumlar" + +#: contrib/comments/models.py:233 +msgid "score" +msgstr "puan" + +#: contrib/comments/models.py:234 +msgid "score date" +msgstr "puan tarihi" + +#: contrib/comments/models.py:237 +msgid "karma score" +msgstr "karma puanı" + +#: contrib/comments/models.py:238 +msgid "karma scores" +msgstr "karma puanları" + +#: contrib/comments/models.py:242 +#, python-format +msgid "%(score)d rating by %(user)s" +msgstr "%(user)s tarafından %(score)d puan" + +#: contrib/comments/models.py:258 +#, python-format +msgid "" +"This comment was flagged by %(user)s:\n" +"\n" +"%(text)s" +msgstr "" +"Bu yorum %(user)s tarafından iÅŸaretlenmiÅŸ:\n" +"\n" +"%(text)s" + +#: contrib/comments/models.py:265 +msgid "flag date" +msgstr "iÅŸaretleme tarihi" + +#: contrib/comments/models.py:268 +msgid "user flag" +msgstr "kullanıcı iÅŸareti" + +#: contrib/comments/models.py:269 +msgid "user flags" +msgstr "kullanıcı iÅŸaretleri" + +#: contrib/comments/models.py:273 +#, python-format +msgid "Flag by %r" +msgstr "%r tarafından iÅŸaret" + +#: contrib/comments/models.py:278 +msgid "deletion date" +msgstr "silme tarihi" + +#: contrib/comments/models.py:280 +msgid "moderator deletion" +msgstr "yönetici tarafından silinme" + +#: contrib/comments/models.py:281 +msgid "moderator deletions" +msgstr "yönetici tarafından silinme" + +#: contrib/comments/models.py:285 +#, python-format +msgid "Moderator deletion by %r" +msgstr "%s tarafından silme iÅŸlemi" + +#: contrib/comments/views/karma.py:19 +msgid "Anonymous users cannot vote" +msgstr "Kayıtsız kullanıcılar oy veremez" + +#: contrib/comments/views/karma.py:23 +msgid "Invalid comment ID" +msgstr "Geçersiz yorum numarası" + +#: contrib/comments/views/karma.py:25 +msgid "No voting for yourself" +msgstr "Kendinize oy veremezsiniz" + +#: contrib/comments/views/comments.py:27 +msgid "This rating is required because you've entered at least one other rating." +msgstr "Reyting gerekli, çünkü en az bir reyting tanımladınız." + +#: contrib/comments/views/comments.py:111 +#, python-format +msgid "" +"This comment was posted by a user who has posted fewer than %(count)s " +"comment:\n" +"\n" +"%(text)s" +msgid_plural "" +"This comment was posted by a user who has posted fewer than %(count)s " +"comments:\n" +"\n" +"%(text)s" +msgstr[0] "" +"Bu yorum, %(count)s yorumdan daha az gönderide bulunmuÅŸ bir kullanıcıya " +"ait:\n" +"\n" +"%(text)s" +msgstr[1] "" +"Bu yorum, %(count)s yorumdan daha az gönderide bulunmuÅŸ bir kullanıcıya " +"ait:\n" +"\n" +"%(text)s" + +#: contrib/comments/views/comments.py:116 +#, python-format +msgid "" +"This comment was posted by a sketchy user:\n" +"\n" +"%(text)s" +msgstr "" +"Bu yorum kusurlu bir kullanıcı tarafından gönderildi:\n" +"\n" +"%(text)s" + +#: contrib/comments/views/comments.py:188 +#: contrib/comments/views/comments.py:280 +msgid "Only POSTs are allowed" +msgstr "Sadece POST yapılabilir" + +#: contrib/comments/views/comments.py:192 +#: contrib/comments/views/comments.py:284 +msgid "One or more of the required fields wasn't submitted" +msgstr "Bir ya da daha fazla gerekli alan doldurulmadı" + +#: contrib/comments/views/comments.py:196 +#: contrib/comments/views/comments.py:286 +msgid "Somebody tampered with the comment form (security violation)" +msgstr "Birisi yorum gönderme formunu kötüye kullanmaya çalıştı (güvenlik ihlali)" + +#: contrib/comments/views/comments.py:206 +#: contrib/comments/views/comments.py:292 +msgid "" +"The comment form had an invalid 'target' parameter -- the object ID was " +"invalid" +msgstr "Bu yorumun geçersiz bir 'hedef' parametresi var -- nesne narası geçersiz" + +#: contrib/comments/views/comments.py:257 +#: contrib/comments/views/comments.py:321 +msgid "The comment form didn't provide either 'preview' or 'post'" +msgstr "Yorum görüntülememe mi yoksa gönderme amaçlı mı belirsiz" + +#: contrib/comments/templates/comments/form.html:6 +#: contrib/comments/templates/comments/form.html:8 +#: contrib/admin/templates/admin/login.html:17 +msgid "Username:" +msgstr "Kullanıcı:" + +#: contrib/comments/templates/comments/form.html:6 +#: contrib/admin/templates/admin/change_list.html:5 +#: contrib/admin/templates/admin/object_history.html:3 +#: contrib/admin/templates/admin/change_form.html:10 +#: contrib/admin/templates/admin/delete_confirmation.html:3 +#: contrib/admin/templates/admin/base.html:25 +#: contrib/admin/templates/registration/password_change_done.html:3 +#: contrib/admin/templates/registration/password_change_form.html:3 +#: contrib/admin/templates/admin_doc/view_detail.html:4 +#: contrib/admin/templates/admin_doc/bookmarklets.html:4 +#: contrib/admin/templates/admin_doc/template_detail.html:4 +#: contrib/admin/templates/admin_doc/template_tag_index.html:5 +#: contrib/admin/templates/admin_doc/missing_docutils.html:4 +#: contrib/admin/templates/admin_doc/view_index.html:5 +#: contrib/admin/templates/admin_doc/model_detail.html:3 +#: contrib/admin/templates/admin_doc/index.html:4 +#: contrib/admin/templates/admin_doc/model_index.html:5 +#: contrib/admin/templates/admin_doc/template_filter_index.html:5 +msgid "Log out" +msgstr "Çık" + +#: contrib/comments/templates/comments/form.html:8 +#: contrib/admin/templates/admin/login.html:20 +msgid "Password:" +msgstr "Parola:" + +#: contrib/comments/templates/comments/form.html:8 +msgid "Forgotten your password?" +msgstr "Parolanızı mı unuttunuz?" + +#: contrib/comments/templates/comments/form.html:12 +msgid "Ratings" +msgstr "Reytingler" + +#: contrib/comments/templates/comments/form.html:12 +#: contrib/comments/templates/comments/form.html:23 +msgid "Required" +msgstr "Gerekli" + +#: contrib/comments/templates/comments/form.html:12 +#: contrib/comments/templates/comments/form.html:23 +msgid "Optional" +msgstr "Opsiyonel" + +#: contrib/comments/templates/comments/form.html:23 +msgid "Post a photo" +msgstr "Resim gönder" + +#: contrib/comments/templates/comments/form.html:28 +#: contrib/comments/templates/comments/freeform.html:5 +msgid "Comment:" +msgstr "Yorum:" + +#: contrib/comments/templates/comments/form.html:35 +#: contrib/comments/templates/comments/freeform.html:10 +msgid "Preview comment" +msgstr "Yorumu görüntüle" + +#: contrib/comments/templates/comments/freeform.html:4 +msgid "Your name:" +msgstr "İsminiz:" + +#: contrib/flatpages/models.py:7 contrib/admin/views/doc.py:315 +msgid "URL" +msgstr "URL" + +#: contrib/flatpages/models.py:8 +msgid "Example: '/about/contact/'. Make sure to have leading and trailing slashes." +msgstr "" +"Örnek: '/about/contact/'. Başında ve sonunda bölü iÅŸareti olduÄŸundan emin " +"olun." + +#: contrib/flatpages/models.py:9 +msgid "title" +msgstr "baÅŸlık" + +#: contrib/flatpages/models.py:10 +msgid "content" +msgstr "içerik" + +#: contrib/flatpages/models.py:11 +msgid "enable comments" +msgstr "yorumlara izin ver" + +#: contrib/flatpages/models.py:12 +msgid "template name" +msgstr "ÅŸablon adı" + +#: contrib/flatpages/models.py:13 +msgid "" +"Example: 'flatpages/contact_page.html'. If this isn't provided, the system " +"will use 'flatpages/default.html'." +msgstr "" +"Örnek: 'flatpages/contact_page.html'. EÄŸer birÅŸey yazılmazsa, sistem " +"otomatik olarak 'flatpages/default.html' kullanacak." + +#: contrib/flatpages/models.py:14 +msgid "registration required" +msgstr "kayıt gerekli" + +#: contrib/flatpages/models.py:14 +msgid "If this is checked, only logged-in users will be able to view the page." +msgstr "Bu seçili ise, sadece kayıtlı kullanıcılar sayfayı görüntüleyebilir." + +#: contrib/flatpages/models.py:18 +msgid "flat page" +msgstr "düz sayfa" + +#: contrib/flatpages/models.py:19 +msgid "flat pages" +msgstr "düz sayfalar" + +#: contrib/sessions/models.py:51 +msgid "session key" +msgstr "oturum anahtarı" + +#: contrib/sessions/models.py:52 +msgid "session data" +msgstr "oturum bilgisi" + +#: contrib/sessions/models.py:53 +msgid "expire date" +msgstr "bitiÅŸ tarihi" + +#: contrib/sessions/models.py:57 +msgid "session" +msgstr "oturum" + +#: contrib/sessions/models.py:58 +msgid "sessions" +msgstr "oturumlar" + +#: contrib/sites/models.py:10 +msgid "domain name" +msgstr "alan adı" + +#: contrib/sites/models.py:11 +msgid "display name" +msgstr "görülen isim" + +#: contrib/sites/models.py:15 +msgid "site" +msgstr "site" + +#: contrib/sites/models.py:16 +msgid "sites" +msgstr "siteler" + +#: contrib/admin/filterspecs.py:40 +#, python-format +msgid "" +"<h3>By %s:</h3>\n" +"<ul>\n" +msgstr "" +"<h3>%s nesnesine göre:</h3>\n" +"<ul>\n" + +#: contrib/admin/filterspecs.py:70 contrib/admin/filterspecs.py:88 +#: contrib/admin/filterspecs.py:143 contrib/admin/filterspecs.py:169 +msgid "All" +msgstr "Tümü" + +#: contrib/admin/filterspecs.py:109 +msgid "Any date" +msgstr "Herhangi bir tarih" + +#: contrib/admin/filterspecs.py:110 +msgid "Today" +msgstr "Bugün" + +#: contrib/admin/filterspecs.py:113 +msgid "Past 7 days" +msgstr "7 gün içinde" + +#: contrib/admin/filterspecs.py:115 +msgid "This month" +msgstr "Bu ay" + +#: contrib/admin/filterspecs.py:117 +msgid "This year" +msgstr "Bu yıl" + +#: contrib/admin/filterspecs.py:143 +msgid "Yes" +msgstr "Evet" + +#: contrib/admin/filterspecs.py:143 +msgid "No" +msgstr "Hayır" + +#: contrib/admin/filterspecs.py:150 +msgid "Unknown" +msgstr "Bilinmiyor" + +#: contrib/admin/models.py:16 +msgid "action time" +msgstr "iÅŸlem zamanı" + +#: contrib/admin/models.py:19 +msgid "object id" +msgstr "nesne no" + +#: contrib/admin/models.py:20 +msgid "object repr" +msgstr "nesne kodu" + +#: contrib/admin/models.py:21 +msgid "action flag" +msgstr "iÅŸlem adı" + +#: contrib/admin/models.py:22 +msgid "change message" +msgstr "mesajı deÄŸiÅŸtir" + +#: contrib/admin/models.py:25 +msgid "log entry" +msgstr "giriÅŸi kaydet" + +#: contrib/admin/models.py:26 +msgid "log entries" +msgstr "giriÅŸleri kaydet" + +#: contrib/admin/templatetags/admin_list.py:230 +msgid "All dates" +msgstr "Tüm tarihler" + +#: contrib/admin/views/auth.py:17 contrib/admin/views/main.py:257 +#, python-format +msgid "The %(name)s \"%(obj)s\" was added successfully." +msgstr "\"%(obj)s\" isimli %(name)s eklendi." + +#: contrib/admin/views/auth.py:22 contrib/admin/views/main.py:261 +#: contrib/admin/views/main.py:347 +msgid "You may edit it again below." +msgstr "Tekrar düzenleyebilirsiniz." + +#: contrib/admin/views/auth.py:28 +msgid "Add user" +msgstr "Kullanıcı ekle" + +#: contrib/admin/views/main.py:223 +msgid "Site administration" +msgstr "Site yönetimi" + +#: contrib/admin/views/main.py:271 contrib/admin/views/main.py:356 +#, python-format +msgid "You may add another %s below." +msgstr "Yeni bir %s ekleyebilirsiniz." + +#: contrib/admin/views/main.py:289 +#, python-format +msgid "Add %s" +msgstr "%s ekle" + +#: contrib/admin/views/main.py:335 +#, python-format +msgid "Added %s." +msgstr "%s eklendi." + +#: contrib/admin/views/main.py:335 contrib/admin/views/main.py:337 +#: contrib/admin/views/main.py:339 +msgid "and" +msgstr "ve" + +#: contrib/admin/views/main.py:337 +#, python-format +msgid "Changed %s." +msgstr "%s deÄŸiÅŸtirildi." + +#: contrib/admin/views/main.py:339 +#, python-format +msgid "Deleted %s." +msgstr "%s silindi." + +#: contrib/admin/views/main.py:342 +msgid "No fields changed." +msgstr "Hiçbir alan deÄŸiÅŸtirilmedi." + +#: contrib/admin/views/main.py:345 +#, python-format +msgid "The %(name)s \"%(obj)s\" was changed successfully." +msgstr "\"%(obj)s\" isimli %(name)s deÄŸiÅŸtirildi." + +#: contrib/admin/views/main.py:353 +#, python-format +msgid "The %(name)s \"%(obj)s\" was added successfully. You may edit it again below." +msgstr "\"%(obj)s\" isimli %(name)s eklendi. AÅŸağıda tekrar düzenleyebilirsiniz." + +#: contrib/admin/views/main.py:391 +#, python-format +msgid "Change %s" +msgstr "%s deÄŸiÅŸtir" + +#: contrib/admin/views/main.py:473 +#, python-format +msgid "One or more %(fieldname)s in %(name)s: %(obj)s" +msgstr "%(name)s içinde bir ya da daha fazla %(fieldname)s: %(obj)s" + +#: contrib/admin/views/main.py:478 +#, python-format +msgid "One or more %(fieldname)s in %(name)s:" +msgstr "%(name)s içinde bir ya da daha fazla %(fieldname)s:" + +#: contrib/admin/views/main.py:511 +#, python-format +msgid "The %(name)s \"%(obj)s\" was deleted successfully." +msgstr "\"%(obj)s\" isimli %(name)s silindi." + +#: contrib/admin/views/main.py:514 +msgid "Are you sure?" +msgstr "Emin misiniz?" + +#: contrib/admin/views/main.py:536 +#, python-format +msgid "Change history: %s" +msgstr "%s için deÄŸiÅŸiklik geçmiÅŸi:" + +#: contrib/admin/views/main.py:570 +#, python-format +msgid "Select %s" +msgstr "%s seç" + +#: contrib/admin/views/main.py:570 +#, python-format +msgid "Select %s to change" +msgstr "DeÄŸiÅŸtirilecek %s nesnesini seçin" + +#: contrib/admin/views/main.py:758 +msgid "Database error" +msgstr "Veritabanı hatası" + +#: contrib/admin/views/decorators.py:24 +#: contrib/admin/templates/admin/login.html:25 +msgid "Log in" +msgstr "GiriÅŸ yap" + +#: contrib/admin/views/decorators.py:62 +msgid "" +"Please log in again, because your session has expired. Don't worry: Your " +"submission has been saved." +msgstr "" +"Oturumunuzun süresi geçti. Lütfen tekrar giriÅŸ yapın. EndiÅŸe etmeyin, " +"gönderiniz kayıt edildi." + +#: contrib/admin/views/decorators.py:69 +msgid "" +"Looks like your browser isn't configured to accept cookies. Please enable " +"cookies, reload this page, and try again." +msgstr "" +"Görünüşe göre tarayıcınız çerezleri kabul etmiyor. Çerez kullanımını aktif " +"hale getirin ve sayfayı yeniden yükleyin." + +#: contrib/admin/views/decorators.py:83 +msgid "Usernames cannot contain the '@' character." +msgstr "Kullanıcı isminde '@' karakteri bulunamaz." + +#: contrib/admin/views/decorators.py:85 +#, python-format +msgid "Your e-mail address is not your username. Try '%s' instead." +msgstr "E-posta adresiniz kullanıcı adınız deÄŸil. '%s' kullanın." + +#: contrib/admin/views/doc.py:46 contrib/admin/views/doc.py:48 +#: contrib/admin/views/doc.py:50 +msgid "tag:" +msgstr "etiket:" + +#: contrib/admin/views/doc.py:77 contrib/admin/views/doc.py:79 +#: contrib/admin/views/doc.py:81 +msgid "filter:" +msgstr "filtre:" + +#: contrib/admin/views/doc.py:135 contrib/admin/views/doc.py:137 +#: contrib/admin/views/doc.py:139 +msgid "view:" +msgstr "view:" + +#: contrib/admin/views/doc.py:164 +#, python-format +msgid "App %r not found" +msgstr "%r uygulaması bulunamadı" + +#: contrib/admin/views/doc.py:171 +#, python-format +msgid "Model %r not found in app %r" +msgstr "%r modeli %r uygulamasında bulunamadı" + +#: contrib/admin/views/doc.py:183 +#, python-format +msgid "the related `%s.%s` object" +msgstr "ilgili `%s.%s` nesnesi" + +#: contrib/admin/views/doc.py:183 contrib/admin/views/doc.py:205 +#: contrib/admin/views/doc.py:219 contrib/admin/views/doc.py:224 +msgid "model:" +msgstr "model:" + +#: contrib/admin/views/doc.py:214 +#, python-format +msgid "related `%s.%s` objects" +msgstr "ilgili `%s.%s` nesneleri" + +#: contrib/admin/views/doc.py:219 +#, python-format +msgid "all %s" +msgstr "tüm %s" + +#: contrib/admin/views/doc.py:224 +#, python-format +msgid "number of %s" +msgstr "%s sayısı" + +#: contrib/admin/views/doc.py:229 +#, python-format +msgid "Fields on %s objects" +msgstr "%s nesnesindeki alanlar" + +#: contrib/admin/views/doc.py:291 contrib/admin/views/doc.py:301 +#: contrib/admin/views/doc.py:303 contrib/admin/views/doc.py:309 +#: contrib/admin/views/doc.py:310 contrib/admin/views/doc.py:312 +msgid "Integer" +msgstr "Tamsayı" + +#: contrib/admin/views/doc.py:292 +msgid "Boolean (Either True or False)" +msgstr "Mantıksal (True ya da False)" + +#: contrib/admin/views/doc.py:293 contrib/admin/views/doc.py:311 +#, python-format +msgid "String (up to %(maxlength)s)" +msgstr "Karakter disizi (en fazla %(maxlength)s)" + +#: contrib/admin/views/doc.py:294 +msgid "Comma-separated integers" +msgstr "Virgülle ayrılmış tamsayılar" + +#: contrib/admin/views/doc.py:295 +msgid "Date (without time)" +msgstr "Tarih (saat yok)" + +#: contrib/admin/views/doc.py:296 +msgid "Date (with time)" +msgstr "Tarih (saat var)" + +#: contrib/admin/views/doc.py:297 +msgid "E-mail address" +msgstr "E-posta adresi" + +#: contrib/admin/views/doc.py:298 contrib/admin/views/doc.py:299 +#: contrib/admin/views/doc.py:302 +msgid "File path" +msgstr "Dosya yolu" + +#: contrib/admin/views/doc.py:300 +msgid "Decimal number" +msgstr "Ondalık sayı:" + +#: contrib/admin/views/doc.py:306 +msgid "Boolean (Either True, False or None)" +msgstr "Mantıksal (True, False, ya da None)" + +#: contrib/admin/views/doc.py:307 +msgid "Relation to parent model" +msgstr "Ana modelle iliÅŸki" + +#: contrib/admin/views/doc.py:308 +msgid "Phone number" +msgstr "Telefon numarası" + +#: contrib/admin/views/doc.py:313 +msgid "Text" +msgstr "Metin" + +#: contrib/admin/views/doc.py:314 +msgid "Time" +msgstr "Saat" + +#: contrib/admin/views/doc.py:316 +msgid "U.S. state (two uppercase letters)" +msgstr "Åžehir Kodu (iki karakter)" + +#: contrib/admin/views/doc.py:317 +msgid "XML text" +msgstr "XML metni" + +#: contrib/admin/views/doc.py:343 +#, python-format +msgid "%s does not appear to be a urlpattern object" +msgstr "%s geçerli vir adres kalıbı deÄŸil" + +#: contrib/admin/templates/widget/file.html:2 +msgid "Currently:" +msgstr "Åžimdiki:" + +#: contrib/admin/templates/widget/file.html:3 +msgid "Change:" +msgstr "DeÄŸiÅŸtir:" + +#: contrib/admin/templates/widget/date_time.html:3 +msgid "Date:" +msgstr "Tarih:" + +#: contrib/admin/templates/widget/date_time.html:4 +msgid "Time:" +msgstr "Saat:" + +#: contrib/admin/templates/admin/change_list.html:5 +#: contrib/admin/templates/admin/object_history.html:3 +#: contrib/admin/templates/admin/change_form.html:10 +#: contrib/admin/templates/admin/delete_confirmation.html:3 +#: contrib/admin/templates/admin/base.html:25 +#: contrib/admin/templates/registration/password_change_done.html:3 +#: contrib/admin/templates/registration/password_change_form.html:3 +#: contrib/admin/templates/admin_doc/bookmarklets.html:3 +msgid "Documentation" +msgstr "Dökümantasyon" + +#: contrib/admin/templates/admin/change_list.html:5 +#: contrib/admin/templates/admin/object_history.html:3 +#: contrib/admin/templates/admin/change_form.html:10 +#: contrib/admin/templates/admin/delete_confirmation.html:3 +#: contrib/admin/templates/admin/base.html:25 +#: contrib/admin/templates/registration/password_change_done.html:3 +#: contrib/admin/templates/registration/password_change_form.html:3 +#: contrib/admin/templates/admin_doc/view_detail.html:4 +#: contrib/admin/templates/admin_doc/bookmarklets.html:4 +#: contrib/admin/templates/admin_doc/template_detail.html:4 +#: contrib/admin/templates/admin_doc/template_tag_index.html:5 +#: contrib/admin/templates/admin_doc/missing_docutils.html:4 +#: contrib/admin/templates/admin_doc/view_index.html:5 +#: contrib/admin/templates/admin_doc/model_detail.html:3 +#: contrib/admin/templates/admin_doc/index.html:4 +#: contrib/admin/templates/admin_doc/model_index.html:5 +#: contrib/admin/templates/admin_doc/template_filter_index.html:5 +msgid "Change password" +msgstr "Parola deÄŸiÅŸtir" + +#: contrib/admin/templates/admin/change_list.html:6 +#: contrib/admin/templates/admin/object_history.html:5 +#: contrib/admin/templates/admin/500.html:4 +#: contrib/admin/templates/admin/invalid_setup.html:4 +#: contrib/admin/templates/admin/change_form.html:13 +#: contrib/admin/templates/admin/delete_confirmation.html:6 +#: contrib/admin/templates/admin/base.html:30 +#: contrib/admin/templates/registration/password_change_done.html:4 +#: contrib/admin/templates/registration/password_reset_form.html:4 +#: contrib/admin/templates/registration/logged_out.html:4 +#: contrib/admin/templates/registration/password_reset_done.html:4 +#: contrib/admin/templates/registration/password_change_form.html:4 +#: contrib/admin/templates/admin_doc/bookmarklets.html:3 +msgid "Home" +msgstr "Anasayfa" + +#: contrib/admin/templates/admin/change_list.html:11 +#, python-format +msgid "Add %(name)s" +msgstr "%(name)s Ekle" + +#: contrib/admin/templates/admin/filter.html:2 +#, python-format +msgid " By %(filter_title)s " +msgstr " %(filter_title)s nesnesine göre " + +#: contrib/admin/templates/admin/object_history.html:5 +#: contrib/admin/templates/admin/change_form.html:20 +msgid "History" +msgstr "GeçmiÅŸ" + +#: contrib/admin/templates/admin/object_history.html:18 +msgid "Date/time" +msgstr "Tarih/saat" + +#: contrib/admin/templates/admin/object_history.html:19 +msgid "User" +msgstr "Kullanıcı" + +#: contrib/admin/templates/admin/object_history.html:20 +msgid "Action" +msgstr "İşlem" + +#: contrib/admin/templates/admin/object_history.html:26 +msgid "DATE_WITH_TIME_FULL" +msgstr "DATE_WITH_TIME_FULL" + +#: contrib/admin/templates/admin/object_history.html:36 +msgid "" +"This object doesn't have a change history. It probably wasn't added via this " +"admin site." +msgstr "" +"Bu nesnenin iÅŸlem geçmiÅŸi yok. Muhtemelen yönetici sayfası dışında bir " +"yerden eklendi." + +#: contrib/admin/templates/admin/search_form.html:8 +msgid "Go" +msgstr "Git" + +#: contrib/admin/templates/admin/search_form.html:10 +#, python-format +msgid "1 result" +msgid_plural "%(counter)s results" +msgstr[0] "1 sonuç" +msgstr[1] "%(counter)s sonuç" + +#: contrib/admin/templates/admin/search_form.html:10 +#, python-format +msgid "%(full_result_count)s total" +msgstr "toplam %(full_result_count)s" + +#: contrib/admin/templates/admin/pagination.html:10 +msgid "Show all" +msgstr "Tümünü göster" + +#: contrib/admin/templates/admin/base_site.html:4 +msgid "Django site admin" +msgstr "Django site yöneticisi" + +#: contrib/admin/templates/admin/base_site.html:7 +msgid "Django administration" +msgstr "Django yönetimi" + +#: contrib/admin/templates/admin/500.html:4 +msgid "Server error" +msgstr "Sunucu hatası" + +#: contrib/admin/templates/admin/500.html:6 +msgid "Server error (500)" +msgstr "Sunucu hatası (500)" + +#: contrib/admin/templates/admin/500.html:9 +msgid "Server Error <em>(500)</em>" +msgstr "Sunucu Hatası <em>(500)</em>" + +#: contrib/admin/templates/admin/500.html:10 +msgid "" +"There's been an error. It's been reported to the site administrators via e-" +"mail and should be fixed shortly. Thanks for your patience." +msgstr "" +"Bir hata oluÅŸtu. Hata, e-psota ile site yöneticisine bildirildi ve kısa süre " +"içinde çözülecktir. Sabrınız için teÅŸekkürler." + +#: contrib/admin/templates/admin/invalid_setup.html:8 +msgid "" +"Something's wrong with your database installation. Make sure the appropriate " +"database tables have been created, and make sure the database is readable by " +"the appropriate user." +msgstr "" +"Veritabanı kurulumu ile ilgili bir problem var. İlgili veritabanı " +"tablolarının kurulu olduÄŸundan ve veritabanının ilgili kullanıcı tarafından " +"okunabilir olduÄŸundan emin olun." + +#: contrib/admin/templates/admin/index.html:17 +#, python-format +msgid "Models available in the %(name)s application." +msgstr "%(name)s uygulamasındaki modeller." + +#: contrib/admin/templates/admin/index.html:18 +#, python-format +msgid "%(name)s" +msgstr "%(name)s" + +#: contrib/admin/templates/admin/index.html:28 +#: contrib/admin/templates/admin/change_form.html:15 +msgid "Add" +msgstr "Ekle" + +#: contrib/admin/templates/admin/index.html:34 +msgid "Change" +msgstr "DeÄŸiÅŸtir" + +#: contrib/admin/templates/admin/index.html:44 +msgid "You don't have permission to edit anything." +msgstr "İşlem yapmaya yetkiniz yok." + +#: contrib/admin/templates/admin/index.html:52 +msgid "Recent Actions" +msgstr "GeçmiÅŸ İşlemler" + +#: contrib/admin/templates/admin/index.html:53 +msgid "My Actions" +msgstr "İşlemlerim" + +#: contrib/admin/templates/admin/index.html:57 +msgid "None available" +msgstr "Hiç yok" + +#: contrib/admin/templates/admin/404.html:4 +#: contrib/admin/templates/admin/404.html:8 +msgid "Page not found" +msgstr "Sayfa bulunamadı" + +#: contrib/admin/templates/admin/404.html:10 +msgid "We're sorry, but the requested page could not be found." +msgstr "Üzgünüm, aradığınız sayfa bulunamadı." + +#: contrib/admin/templates/admin/filters.html:4 +msgid "Filter" +msgstr "Filtrele" + +#: contrib/admin/templates/admin/change_form.html:21 +msgid "View on site" +msgstr "Sitede görüntüle" + +#: contrib/admin/templates/admin/change_form.html:30 +msgid "Please correct the error below." +msgid_plural "Please correct the errors below." +msgstr[0] "Lütfen aÅŸağıdaki hatayı düzeltin." +msgstr[1] "Lütfen aÅŸağıdaki hataları düzeltin." + +#: contrib/admin/templates/admin/change_form.html:48 +msgid "Ordering" +msgstr "Sıralama:" + +#: contrib/admin/templates/admin/change_form.html:51 +msgid "Order:" +msgstr "Sıra:" + +#: contrib/admin/templates/admin/login.html:22 +msgid "Have you <a href=\"/password_reset/\">forgotten your password</a>?" +msgstr "<a href=\"/password_reset/\">Åžifrenizi mi unuttunuz?</a>" + +#: contrib/admin/templates/admin/delete_confirmation.html:9 +#: contrib/admin/templates/admin/submit_line.html:3 +msgid "Delete" +msgstr "Sil" + +#: contrib/admin/templates/admin/delete_confirmation.html:14 +#, python-format +msgid "" +"Deleting the %(object_name)s '%(escaped_object)s' would result in deleting " +"related objects, but your account doesn't have permission to delete the " +"following types of objects:" +msgstr "" +"'%(escaped_object)s' isimli %(object_name)s nesnesini silmek, baÄŸlantılı " +"nesnelerin silinmesini gerektiriyor, ancak aÅŸağıdaki nesneleri silme " +"yetkiniz yok." + +#: contrib/admin/templates/admin/delete_confirmation.html:21 +#, python-format +msgid "" +"Are you sure you want to delete the %(object_name)s \"%(escaped_object)s\"? " +"All of the following related items will be deleted:" +msgstr "" +"\"%(escaped_object)s\" isimli %(object_name)s nesnesini silmek " +"istediÄŸinizdenemin misiniz? AÅŸağıdaki baÄŸlantılı öğeler silinecek:" + +#: contrib/admin/templates/admin/delete_confirmation.html:26 +msgid "Yes, I'm sure" +msgstr "Evet, eminim" + +#: contrib/admin/templates/admin/base.html:25 +msgid "Welcome," +msgstr "HoÅŸgeldin," + +#: contrib/admin/templates/admin/submit_line.html:4 +msgid "Save as new" +msgstr "Yeni olarak kaydet" + +#: contrib/admin/templates/admin/submit_line.html:5 +msgid "Save and add another" +msgstr "Kaydet ve yeni bir tane ekle" + +#: contrib/admin/templates/admin/submit_line.html:6 +msgid "Save and continue editing" +msgstr "Kaydet ve düzenlemeye devam et" + +#: contrib/admin/templates/admin/submit_line.html:7 +msgid "Save" +msgstr "Kaydet" + +#: contrib/admin/templates/admin/auth/user/add_form.html:6 +msgid "" +"First, enter a username and password. Then, you'll be able to edit more user " +"options." +msgstr "Önce bir kullanıcı adı ve parola girin. Daha sonra daha fazla bilgi girebilirsiniz." + +#: contrib/admin/templates/admin/auth/user/add_form.html:12 +msgid "Username" +msgstr "Kullanıcı" + +#: contrib/admin/templates/admin/auth/user/add_form.html:18 +msgid "Password" +msgstr "Parola" + +#: contrib/admin/templates/admin/auth/user/add_form.html:23 +msgid "Password (again)" +msgstr "Parola (tekrar)" + +#: contrib/admin/templates/admin/auth/user/add_form.html:24 +msgid "Enter the same password as above, for verification." +msgstr "Onaylamak için, yukarıdaki parolanın aynısını girin." + +#: contrib/admin/templates/registration/password_change_done.html:4 +#: contrib/admin/templates/registration/password_change_form.html:4 +#: contrib/admin/templates/registration/password_change_form.html:6 +#: contrib/admin/templates/registration/password_change_form.html:10 +msgid "Password change" +msgstr "Parola deÄŸiÅŸimi" + +#: contrib/admin/templates/registration/password_change_done.html:6 +#: contrib/admin/templates/registration/password_change_done.html:10 +msgid "Password change successful" +msgstr "Parola deÄŸiÅŸimi baÅŸarılı" + +#: contrib/admin/templates/registration/password_change_done.html:12 +msgid "Your password was changed." +msgstr "Parolanız deÄŸiÅŸtirildi." + +#: contrib/admin/templates/registration/password_reset_form.html:4 +#: contrib/admin/templates/registration/password_reset_form.html:6 +#: contrib/admin/templates/registration/password_reset_form.html:10 +#: contrib/admin/templates/registration/password_reset_done.html:4 +msgid "Password reset" +msgstr "Parolayı sıfırla" + +#: contrib/admin/templates/registration/password_reset_form.html:12 +msgid "" +"Forgotten your password? Enter your e-mail address below, and we'll reset " +"your password and e-mail the new one to you." +msgstr "" +"Parolanızı mı unuttunuz? E-posta adresinizi aÅŸağıya girin, parolanızı " +"sıfırlayalım ve e-posta adresinize gönderelim." + +#: contrib/admin/templates/registration/password_reset_form.html:16 +msgid "E-mail address:" +msgstr "E-posta adresi:" + +#: contrib/admin/templates/registration/password_reset_form.html:16 +msgid "Reset my password" +msgstr "Parolamı sıfırla" + +#: contrib/admin/templates/registration/logged_out.html:8 +msgid "Thanks for spending some quality time with the Web site today." +msgstr "Web sitesinde zaman geçirdiÄŸiniz için teÅŸekkür ederiz." + +#: contrib/admin/templates/registration/logged_out.html:10 +msgid "Log in again" +msgstr "Tekrar giriÅŸ yap" + +#: contrib/admin/templates/registration/password_reset_done.html:6 +#: contrib/admin/templates/registration/password_reset_done.html:10 +msgid "Password reset successful" +msgstr "Parola sıfırlandı." + +#: contrib/admin/templates/registration/password_reset_done.html:12 +msgid "" +"We've e-mailed a new password to the e-mail address you submitted. You " +"should be receiving it shortly." +msgstr "" +"Yeni ÅŸifreniz, e-posta adresinize gönderildi, kısa süre içinde size " +"ulaÅŸacaktır." + +#: contrib/admin/templates/registration/password_change_form.html:12 +msgid "" +"Please enter your old password, for security's sake, and then enter your new " +"password twice so we can verify you typed it in correctly." +msgstr "" +"GüvenliÄŸiniz için, lütfen eski parolanızı girin, sonra da yeni ÅŸifrenizi iki " +"kere girin ve böylece doÄŸru yazdığınızdan emin olun." + +#: contrib/admin/templates/registration/password_change_form.html:17 +msgid "Old password:" +msgstr "Eski parola:" + +#: contrib/admin/templates/registration/password_change_form.html:19 +msgid "New password:" +msgstr "Yeni parola:" + +#: contrib/admin/templates/registration/password_change_form.html:21 +msgid "Confirm password:" +msgstr "Parolayı onayla:" + +#: contrib/admin/templates/registration/password_change_form.html:23 +msgid "Change my password" +msgstr "Parolamı deÄŸiÅŸtir" + +#: contrib/admin/templates/registration/password_reset_email.html:2 +msgid "You're receiving this e-mail because you requested a password reset" +msgstr "Bu e-postayı aldınız çünkü " + +#: contrib/admin/templates/registration/password_reset_email.html:3 +#, python-format +msgid "for your user account at %(site_name)s" +msgstr "" +"%(site_name)s adresindeki kullanıcı hesabınız için parola sıfırlama " +"talebinde bulundunuz." + +#: contrib/admin/templates/registration/password_reset_email.html:5 +#, python-format +msgid "Your new password is: %(new_password)s" +msgstr "Yeni parolanız: %(new_password)s" + +#: contrib/admin/templates/registration/password_reset_email.html:7 +msgid "Feel free to change this password by going to this page:" +msgstr "Parolanızı deÄŸiÅŸtirmek için bu adrese gidebilirsiniz:" + +#: contrib/admin/templates/registration/password_reset_email.html:11 +msgid "Your username, in case you've forgotten:" +msgstr "Unutma ihtimaline karşı, kullanıcı adınız:" + +#: contrib/admin/templates/registration/password_reset_email.html:13 +msgid "Thanks for using our site!" +msgstr "TeÅŸekkürler!" + +#: contrib/admin/templates/registration/password_reset_email.html:15 +#, python-format +msgid "The %(site_name)s team" +msgstr "%(site_name)s Ekibi" + +#: contrib/admin/templates/admin_doc/bookmarklets.html:3 +msgid "Bookmarklets" +msgstr "Kısayollar" + +#: contrib/admin/templates/admin_doc/bookmarklets.html:5 +msgid "Documentation bookmarklets" +msgstr "Döküman kısayolları" + +#: contrib/admin/templates/admin_doc/bookmarklets.html:9 +msgid "" +"\n" +"<p class=\"help\">To install bookmarklets, drag the link to your bookmarks\n" +"toolbar, or right-click the link and add it to your bookmarks. Now you can\n" +"select the bookmarklet from any page in the site. Note that some of these\n" +"bookmarklets require you to be viewing the site from a computer designated\n" +"as \"internal\" (talk to your system administrator if you aren't sure if\n" +"your computer is \"internal\").</p>\n" +msgstr "" +"\n" +"<p class=\"help\">Kısayolları kullanabilmek için, baÄŸlantıyı tarayıcınızdaki " +"araç çubuÄŸuna sürükleyin, ya da saÄŸ tıklayıp sık kullanılan adresler " +"listenize ekleyin. Bazı kısayollar, uygulamayı çalıştıran sunucu ile aynı " +"adreste bulunan istemciler tarafından kullanılabilir.</p>\n" + +#: contrib/admin/templates/admin_doc/bookmarklets.html:19 +msgid "Documentation for this page" +msgstr "Bu sayfa için dökümantasyon" + +#: contrib/admin/templates/admin_doc/bookmarklets.html:20 +msgid "" +"Jumps you from any page to the documentation for the view that generates " +"that page." +msgstr "Sizi, bu sayfayı üreten betiÄŸin dökümantasyonuna yönlendirir." + +#: contrib/admin/templates/admin_doc/bookmarklets.html:22 +msgid "Show object ID" +msgstr "Nesne numarasını göster" + +#: contrib/admin/templates/admin_doc/bookmarklets.html:23 +msgid "" +"Shows the content-type and unique ID for pages that represent a single " +"object." +msgstr "Tek bir nesneyi temsil eden sayfaların içerik türünü ve numarasını gösterir." + +#: contrib/admin/templates/admin_doc/bookmarklets.html:25 +msgid "Edit this object (current window)" +msgstr "Nesneyi düzenle (aynı pencerede)" + +#: contrib/admin/templates/admin_doc/bookmarklets.html:26 +msgid "Jumps to the admin page for pages that represent a single object." +msgstr "Tek bir nesneyi temsil eden sayfaların yönetim sayfasını gösterir." + +#: contrib/admin/templates/admin_doc/bookmarklets.html:28 +msgid "Edit this object (new window)" +msgstr "Nesneyi düzenle (yeni pencerede)" + +#: contrib/admin/templates/admin_doc/bookmarklets.html:29 +msgid "As above, but opens the admin page in a new window." +msgstr "Yukarıdaki gibi, ancak yönetim sayfasını yeni bir pencerede açar." + +#: template/defaultfilters.py:401 +msgid "yes,no,maybe" +msgstr "evet,hayır,olabilir" + diff --git a/django/conf/locale/tr/LC_MESSAGES/djangojs.mo b/django/conf/locale/tr/LC_MESSAGES/djangojs.mo Binary files differnew file mode 100644 index 0000000000..1119203925 --- /dev/null +++ b/django/conf/locale/tr/LC_MESSAGES/djangojs.mo diff --git a/django/conf/locale/tr/LC_MESSAGES/djangojs.po b/django/conf/locale/tr/LC_MESSAGES/djangojs.po new file mode 100644 index 0000000000..35928b9c03 --- /dev/null +++ b/django/conf/locale/tr/LC_MESSAGES/djangojs.po @@ -0,0 +1,109 @@ +# Django 0.95 +# Copyright (C) 2006 Django +# This file is distributed under the same license as the Django package. +# Bahadır Kandemir <bahadir@pardus.org.tr>, 2006. +# +msgid "" +msgstr "" +"Project-Id-Version: Django 0.95\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2006-09-30 01:31+0300\n" +"PO-Revision-Date: 2006-09-30 01:31+0300\n" +"Last-Translator: Bahadır Kandemir <bahadir@pardus.org.tr>\n" +"Language-Team: Bahadır Kandemir <bahadir@pardus.org.tr>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: contrib/admin/media/js/SelectFilter2.js:33 +#, perl-format +msgid "Available %s" +msgstr "Mevcut %s" + +#: contrib/admin/media/js/SelectFilter2.js:41 +msgid "Choose all" +msgstr "Hepsini seç" + +#: contrib/admin/media/js/SelectFilter2.js:46 +msgid "Add" +msgstr "Ekle" + +#: contrib/admin/media/js/SelectFilter2.js:48 +msgid "Remove" +msgstr "Kaldır" + +#: contrib/admin/media/js/SelectFilter2.js:53 +#, perl-format +msgid "Chosen %s" +msgstr "Seçilen %s" + +#: contrib/admin/media/js/SelectFilter2.js:54 +msgid "Select your choice(s) and click " +msgstr "Seçiminizi yapın ve tıklayın " + +#: contrib/admin/media/js/SelectFilter2.js:59 +msgid "Clear all" +msgstr "Hepsini temizle" + +#: contrib/admin/media/js/dateparse.js:26 +#: contrib/admin/media/js/calendar.js:24 +msgid "" +"January February March April May June July August September October November " +"December" +msgstr "Ocak Åžubat Mart Nisan Mayıs Haziran Temmuz AÄŸustos Eylül Ekim Kasım " +"Aralık" + +#: contrib/admin/media/js/dateparse.js:27 +msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday" +msgstr "Pazar Pazartesi Salı ÇarÅŸamba PerÅŸembe Cuma Cumartesi" + +#: contrib/admin/media/js/calendar.js:25 +msgid "S M T W T F S" +msgstr "P P S Ç P C C" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45 +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80 +msgid "Now" +msgstr "Åžimdi" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48 +msgid "Clock" +msgstr "Saat" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77 +msgid "Choose a time" +msgstr "Saat seçin" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81 +msgid "Midnight" +msgstr "Geceyarısı" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82 +msgid "6 a.m." +msgstr "Sabah 6" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83 +msgid "Noon" +msgstr "Öğle" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87 +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168 +msgid "Cancel" +msgstr "İptal" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111 +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162 +msgid "Today" +msgstr "Bugün" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114 +msgid "Calendar" +msgstr "Takvim" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160 +msgid "Yesterday" +msgstr "Dün" + +#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164 +msgid "Tomorrow" +msgstr "Yarın" diff --git a/django/conf/locale/zh_CN/LC_MESSAGES/django.mo b/django/conf/locale/zh_CN/LC_MESSAGES/django.mo Binary files differindex 9fc04b9395..0d6bf90c0e 100644 --- a/django/conf/locale/zh_CN/LC_MESSAGES/django.mo +++ b/django/conf/locale/zh_CN/LC_MESSAGES/django.mo diff --git a/django/conf/locale/zh_CN/LC_MESSAGES/django.po b/django/conf/locale/zh_CN/LC_MESSAGES/django.po index 7718514299..2552b677bd 100644 --- a/django/conf/locale/zh_CN/LC_MESSAGES/django.po +++ b/django/conf/locale/zh_CN/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: django v1.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2006-05-16 10:10+0200\n" -"PO-Revision-Date: 2006-05-17 13:47+0800\n" +"PO-Revision-Date: 2006-09-01 22:05+0800\n" "Last-Translator: limodou <limodou@gmail.com>\n" "Language-Team: Simplified Chinese <limodou@gmail.com>\n" "MIME-Version: 1.0\n" @@ -1167,7 +1167,7 @@ msgstr "个人信æ¯" #: contrib/auth/models.py:77 msgid "Permissions" -msgstr "许å¯" +msgstr "æƒé™" #: contrib/auth/models.py:78 msgid "Important dates" diff --git a/django/conf/locale/zh_CN/LC_MESSAGES/djangojs.mo b/django/conf/locale/zh_CN/LC_MESSAGES/djangojs.mo Binary files differindex 983a8a7154..ec7580a862 100644 --- a/django/conf/locale/zh_CN/LC_MESSAGES/djangojs.mo +++ b/django/conf/locale/zh_CN/LC_MESSAGES/djangojs.mo diff --git a/django/conf/locale/zh_CN/LC_MESSAGES/djangojs.po b/django/conf/locale/zh_CN/LC_MESSAGES/djangojs.po index 1e9e7dbeb7..610e61d17a 100644 --- a/django/conf/locale/zh_CN/LC_MESSAGES/djangojs.po +++ b/django/conf/locale/zh_CN/LC_MESSAGES/djangojs.po @@ -3,22 +3,21 @@ # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # -#, fuzzy msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" +"Project-Id-Version: Django 0.95\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2006-03-21 18:43+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME <max@exoweb.net>\n" -"Language-Team: LANGUAGE <LL@li.org>\n" +"PO-Revision-Date: 2006-09-25 08:35+0800\n" +"Last-Translator: limodou <limodou@gmail.com>\n" +"Language-Team: limodou <limodou@gmail.com>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" #: contrib/admin/media/js/SelectFilter2.js:33 msgid "Available %s" -msgstr "å¯è¡Œ %s" +msgstr "å¯ç”¨ %s" #: contrib/admin/media/js/SelectFilter2.js:41 msgid "Choose all" @@ -30,34 +29,32 @@ msgstr "å¢žåŠ " #: contrib/admin/media/js/SelectFilter2.js:48 msgid "Remove" -msgstr "移出" +msgstr "åˆ é™¤" #: contrib/admin/media/js/SelectFilter2.js:53 msgid "Chosen %s" -msgstr "选择 %s" +msgstr "选ä¸çš„ %s" #: contrib/admin/media/js/SelectFilter2.js:54 msgid "Select your choice(s) and click " -msgstr "æŒ‘é€‰ä½ çš„é€‰æ‹©å¹¶ä¸”ç‚¹å‡» " +msgstr "选择并点击 " #: contrib/admin/media/js/SelectFilter2.js:59 msgid "Clear all" -msgstr "清除所有" +msgstr "清除全部" #: contrib/admin/media/js/dateparse.js:32 #: contrib/admin/media/js/calendar.js:24 -msgid "" -"January February March April May June July August September October November " -"December" +msgid "January February March April May June July August September October November December" msgstr "一月 二月 三月 四月 五月 å…æœˆ å…æœˆ 七月 八月 乿œˆ åæœˆ å一月 å二月" #: contrib/admin/media/js/dateparse.js:33 msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday" -msgstr "星期天 星期一 星期二 星期三 星期四 星期五 星期å…" +msgstr "星期日 星期一 星期二 星期三 星期四 星期五 星期å…" #: contrib/admin/media/js/calendar.js:25 msgid "S M T W T F S" -msgstr "æ—¥ 月 ç« æ°´ 木 金 土" +msgstr "æ—¥ 一 二 三 å›› 五 å…" #: contrib/admin/media/js/admin/DateTimeShortcuts.js:45 #: contrib/admin/media/js/admin/DateTimeShortcuts.js:80 @@ -105,3 +102,4 @@ msgstr "昨天" #: contrib/admin/media/js/admin/DateTimeShortcuts.js:164 msgid "Tomorrow" msgstr "明天" + diff --git a/django/conf/project_template/settings.py b/django/conf/project_template/settings.py index 14da715db5..d6f34a28db 100644 --- a/django/conf/project_template/settings.py +++ b/django/conf/project_template/settings.py @@ -27,6 +27,10 @@ LANGUAGE_CODE = 'en-us' SITE_ID = 1 +# If you set this to False, Django will make some optimizations so as not +# to load the internationalization machinery. +USE_I18N = True + # Absolute path to the directory that holds media. # Example: "/home/media/media.lawrence.com/" MEDIA_ROOT = '' @@ -60,8 +64,9 @@ MIDDLEWARE_CLASSES = ( ROOT_URLCONF = '{{ project_name }}.urls' TEMPLATE_DIRS = ( - # Put strings here, like "/home/html/django_templates". + # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". # Always use forward slashes, even on Windows. + # Don't forget to use absolute paths, not relative paths. ) INSTALLED_APPS = ( diff --git a/django/conf/urls/defaults.py b/django/conf/urls/defaults.py index 07611c5147..17fe603d96 100644 --- a/django/conf/urls/defaults.py +++ b/django/conf/urls/defaults.py @@ -10,8 +10,10 @@ include = lambda urlconf_module: [urlconf_module] def patterns(prefix, *tuples): pattern_list = [] for t in tuples: - if type(t[1]) == list: - pattern_list.append(RegexURLResolver(t[0], t[1][0])) + regex, view_or_include = t[:2] + default_kwargs = t[2:] + if type(view_or_include) == list: + pattern_list.append(RegexURLResolver(regex, view_or_include[0], *default_kwargs)) else: - pattern_list.append(RegexURLPattern(t[0], prefix and (prefix + '.' + t[1]) or t[1], *t[2:])) + pattern_list.append(RegexURLPattern(regex, prefix and (prefix + '.' + view_or_include) or view_or_include, *default_kwargs)) return pattern_list diff --git a/django/contrib/admin/filterspecs.py b/django/contrib/admin/filterspecs.py index 25376be12a..8c2b82147e 100644 --- a/django/contrib/admin/filterspecs.py +++ b/django/contrib/admin/filterspecs.py @@ -123,7 +123,7 @@ class DateFieldFilterSpec(FilterSpec): def choices(self, cl): for title, param_dict in self.links: yield {'selected': self.date_params == param_dict, - 'query_string': cl.get_query_string(param_dict, self.field_generic), + 'query_string': cl.get_query_string(param_dict, [self.field_generic]), 'display': title} FilterSpec.register(lambda f: isinstance(f, models.DateField), DateFieldFilterSpec) diff --git a/django/contrib/admin/media/css/changelists.css b/django/contrib/admin/media/css/changelists.css index fbcbe56f06..4834be4685 100644 --- a/django/contrib/admin/media/css/changelists.css +++ b/django/contrib/admin/media/css/changelists.css @@ -42,9 +42,9 @@ /* PAGINATOR */ .paginator { font-size:11px; padding-top:10px; padding-bottom:10px; line-height:22px; margin:0; border-top:1px solid #ddd; } -.paginator a:link, .paginator a:visited { padding:2px 6px; border:solid 1px #ccc; background:white; text-decoration:none; } +.paginator a:link, .paginator a:visited { padding:2px 6px; border:solid 1px #ccc; background:white; text-decoration:none; } .paginator a.showall { padding:0 !important; border:none !important; } .paginator a.showall:hover { color:#036 !important; background:transparent !important; } -.paginator .end { border-width:2px !important; margin-right:6px; } +.paginator .end { border-width:2px !important; margin-right:6px; } .paginator .this-page { padding:2px 6px; font-weight:bold; font-size:13px; vertical-align:top; } .paginator a:hover { color:white; background:#5b80b2; border-color:#036; } diff --git a/django/contrib/admin/media/css/forms.css b/django/contrib/admin/media/css/forms.css index b66f268fec..468e06a8a2 100644 --- a/django/contrib/admin/media/css/forms.css +++ b/django/contrib/admin/media/css/forms.css @@ -7,10 +7,10 @@ form .form-row p { padding-left:0; font-size:11px; } /* FORM LABELS */ -form h4 { margin:0 !important; padding:0 !important; border:none !important; } +form h4 { margin:0 !important; padding:0 !important; border:none !important; } label { font-weight:normal !important; color:#666; font-size:12px; } label.inline { margin-left:20px; } -.required label, label.required { font-weight:bold !important; color:#333 !important; } +.required label, label.required { font-weight:bold !important; color:#333 !important; } /* RADIO BUTTONS */ form ul.radiolist li { list-style-type:none; } diff --git a/django/contrib/admin/media/css/global.css b/django/contrib/admin/media/css/global.css index a87931681c..d50601bde7 100644 --- a/django/contrib/admin/media/css/global.css +++ b/django/contrib/admin/media/css/global.css @@ -1,4 +1,4 @@ -body { margin:0; padding:0; font-size:12px; font-family:"Lucida Grande","Bitstream Vera Sans",Verdana,Arial,sans-serif; color:#333; background:#fff; } +body { margin:0; padding:0; font-size:12px; font-family:"Lucida Grande","DejaVu Sans","Bitstream Vera Sans",Verdana,Arial,sans-serif; color:#333; background:#fff; } /* LINKS */ a:link, a:visited { color: #5b80b2; text-decoration:none; } @@ -31,7 +31,7 @@ fieldset { margin:0; padding:0; } blockquote { font-size:11px; color:#777; margin-left:2px; padding-left:10px; border-left:5px solid #ddd; } code, pre { font-family:"Bitstream Vera Sans Mono", Monaco, "Courier New", Courier, monospace; background:inherit; color:#666; font-size:11px; } pre.literal-block { margin:10px; background:#eee; padding:6px 8px; } -code strong { color:#930; } +code strong { color:#930; } hr { clear:both; color:#eee; background-color:#eee; height:1px; border:none; margin:0; padding:0; font-size:1px; line-height:1px; } /* TEXT STYLES & MODIFIERS */ @@ -81,7 +81,7 @@ table.orderable tbody tr td:first-child { padding-left:14px; background-image:ur table.orderable-initalized .order-cell, body>tr>td.order-cell { display:none; } /* FORM DEFAULTS */ -input, textarea, select { margin:2px 0; padding:2px 3px; vertical-align:middle; font-family:"Lucida Grande", Verdana, Arial, sans-serif; font-weight:normal; font-size:11px; } +input, textarea, select { margin:2px 0; padding:2px 3px; vertical-align:middle; font-family:"Lucida Grande", Verdana, Arial, sans-serif; font-weight:normal; font-size:11px; } textarea { vertical-align:top !important; } input[type=text], input[type=password], textarea, select, .vTextField { border:1px solid #ccc; } @@ -92,7 +92,7 @@ input[type=submit].default, .submit-row input.default { border:2px solid #5b80b2 input[type=submit].default:active { background-image:url(../img/admin/default-bg-reverse.gif); background-position:top; } /* MODULES */ -.module { border:1px solid #ccc; margin-bottom:5px; background:white; } +.module { border:1px solid #ccc; margin-bottom:5px; background:white; } .module p, .module ul, .module h3, .module h4, .module dl, .module pre { padding-left:10px; padding-right:10px; } .module blockquote { margin-left:12px; } .module ul, .module ol { margin-left:1.5em; } diff --git a/django/contrib/admin/media/css/layout.css b/django/contrib/admin/media/css/layout.css index befe4fc1ca..17c52861ee 100644 --- a/django/contrib/admin/media/css/layout.css +++ b/django/contrib/admin/media/css/layout.css @@ -4,7 +4,7 @@ #header { width:100%; } #content-main { float:left; width:100%; } #content-related { float:right; width:18em; position:relative; margin-right:-19em; } -#footer { clear:both; padding:10px; } +#footer { clear:both; padding:10px; } /* COLUMN TYPES */ .colMS { margin-right:20em !important; } @@ -16,14 +16,14 @@ .dashboard #content { width:500px; } /* HEADER */ -#header { background:#417690; color:#ffc; overflow:hidden; } +#header { background:#417690; color:#ffc; overflow:hidden; } #header a:link, #header a:visited { color:white; } #header a:hover { text-decoration:underline; } #branding h1 { padding:0 10px; font-size:18px; margin:8px 0; font-weight:normal; color:#f4f379; } #branding h2 { padding:0 10px; font-size:14px; margin:-8px 0 8px 0; font-weight:normal; color:#ffc; } -#user-tools { position:absolute; top:0; right:0; padding:1.2em 10px; font-size:11px; text-align:right; } +#user-tools { position:absolute; top:0; right:0; padding:1.2em 10px; font-size:11px; text-align:right; } /* SIDEBAR */ #content-related h3 { font-size:12px; color:#666; margin-bottom:3px; } #content-related h4 { font-size:11px; } -#content-related .module h2 { background:#eee url(../img/admin/nav-bg.gif) bottom left repeat-x; color:#666; }
\ No newline at end of file +#content-related .module h2 { background:#eee url(../img/admin/nav-bg.gif) bottom left repeat-x; color:#666; }
\ No newline at end of file diff --git a/django/contrib/admin/media/css/rtl.css b/django/contrib/admin/media/css/rtl.css index c29391cabf..1974e7c2ec 100644 --- a/django/contrib/admin/media/css/rtl.css +++ b/django/contrib/admin/media/css/rtl.css @@ -16,7 +16,7 @@ th { text-align: right; } /* layout styles */ -#user-tools { right:auto; left:0; text-align:left; } +#user-tools { right:auto; left:0; text-align:left; } div.breadcrumbs { text-align:right; } #content-main { float:right;} #content-related { float:left; margin-left:-19em; margin-right:auto;} diff --git a/django/contrib/admin/media/js/admin/CollapsedFieldsets.js b/django/contrib/admin/media/js/admin/CollapsedFieldsets.js index 97f0a68d04..c8426db228 100644 --- a/django/contrib/admin/media/js/admin/CollapsedFieldsets.js +++ b/django/contrib/admin/media/js/admin/CollapsedFieldsets.js @@ -3,83 +3,83 @@ // link when the fieldset is visible. function findForm(node) { - // returns the node of the form containing the given node - if (node.tagName.toLowerCase() != 'form') { - return findForm(node.parentNode); - } - return node; + // returns the node of the form containing the given node + if (node.tagName.toLowerCase() != 'form') { + return findForm(node.parentNode); + } + return node; } var CollapsedFieldsets = { - collapse_re: /\bcollapse\b/, // Class of fieldsets that should be dealt with. - collapsed_re: /\bcollapsed\b/, // Class that fieldsets get when they're hidden. - collapsed_class: 'collapsed', - init: function() { - var fieldsets = document.getElementsByTagName('fieldset'); - var collapsed_seen = false; - for (var i = 0, fs; fs = fieldsets[i]; i++) { - // Collapse this fieldset if it has the correct class, and if it - // doesn't have any errors. (Collapsing shouldn't apply in the case - // of error messages.) - if (fs.className.match(CollapsedFieldsets.collapse_re) && !CollapsedFieldsets.fieldset_has_errors(fs)) { - collapsed_seen = true; - // Give it an additional class, used by CSS to hide it. - fs.className += ' ' + CollapsedFieldsets.collapsed_class; - // (<a id="fieldsetcollapser3" class="collapse-toggle" href="#">Show</a>) - var collapse_link = document.createElement('a'); - collapse_link.className = 'collapse-toggle'; - collapse_link.id = 'fieldsetcollapser' + i; - collapse_link.onclick = new Function('CollapsedFieldsets.show('+i+'); return false;'); - collapse_link.href = '#'; - collapse_link.innerHTML = gettext('Show'); - var h2 = fs.getElementsByTagName('h2')[0]; - h2.appendChild(document.createTextNode(' (')); - h2.appendChild(collapse_link); - h2.appendChild(document.createTextNode(')')); - } - } - if (collapsed_seen) { - // Expand all collapsed fieldsets when form is submitted. - addEvent(findForm(document.getElementsByTagName('fieldset')[0]), 'submit', function() { CollapsedFieldsets.uncollapse_all(); }); - } - }, - fieldset_has_errors: function(fs) { - // Returns true if any fields in the fieldset have validation errors. - var divs = fs.getElementsByTagName('div'); - for (var i=0; i<divs.length; i++) { - if (divs[i].className.match(/\berror\b/)) { - return true; - } - } - return false; - }, - show: function(fieldset_index) { - var fs = document.getElementsByTagName('fieldset')[fieldset_index]; - // Remove the class name that causes the "display: none". - fs.className = fs.className.replace(CollapsedFieldsets.collapsed_re, ''); - // Toggle the "Show" link to a "Hide" link - var collapse_link = document.getElementById('fieldsetcollapser' + fieldset_index); - collapse_link.onclick = new Function('CollapsedFieldsets.hide('+fieldset_index+'); return false;'); - collapse_link.innerHTML = gettext('Hide'); - }, - hide: function(fieldset_index) { - var fs = document.getElementsByTagName('fieldset')[fieldset_index]; - // Add the class name that causes the "display: none". - fs.className += ' ' + CollapsedFieldsets.collapsed_class; - // Toggle the "Hide" link to a "Show" link - var collapse_link = document.getElementById('fieldsetcollapser' + fieldset_index); + collapse_re: /\bcollapse\b/, // Class of fieldsets that should be dealt with. + collapsed_re: /\bcollapsed\b/, // Class that fieldsets get when they're hidden. + collapsed_class: 'collapsed', + init: function() { + var fieldsets = document.getElementsByTagName('fieldset'); + var collapsed_seen = false; + for (var i = 0, fs; fs = fieldsets[i]; i++) { + // Collapse this fieldset if it has the correct class, and if it + // doesn't have any errors. (Collapsing shouldn't apply in the case + // of error messages.) + if (fs.className.match(CollapsedFieldsets.collapse_re) && !CollapsedFieldsets.fieldset_has_errors(fs)) { + collapsed_seen = true; + // Give it an additional class, used by CSS to hide it. + fs.className += ' ' + CollapsedFieldsets.collapsed_class; + // (<a id="fieldsetcollapser3" class="collapse-toggle" href="#">Show</a>) + var collapse_link = document.createElement('a'); + collapse_link.className = 'collapse-toggle'; + collapse_link.id = 'fieldsetcollapser' + i; + collapse_link.onclick = new Function('CollapsedFieldsets.show('+i+'); return false;'); + collapse_link.href = '#'; + collapse_link.innerHTML = gettext('Show'); + var h2 = fs.getElementsByTagName('h2')[0]; + h2.appendChild(document.createTextNode(' (')); + h2.appendChild(collapse_link); + h2.appendChild(document.createTextNode(')')); + } + } + if (collapsed_seen) { + // Expand all collapsed fieldsets when form is submitted. + addEvent(findForm(document.getElementsByTagName('fieldset')[0]), 'submit', function() { CollapsedFieldsets.uncollapse_all(); }); + } + }, + fieldset_has_errors: function(fs) { + // Returns true if any fields in the fieldset have validation errors. + var divs = fs.getElementsByTagName('div'); + for (var i=0; i<divs.length; i++) { + if (divs[i].className.match(/\berror\b/)) { + return true; + } + } + return false; + }, + show: function(fieldset_index) { + var fs = document.getElementsByTagName('fieldset')[fieldset_index]; + // Remove the class name that causes the "display: none". + fs.className = fs.className.replace(CollapsedFieldsets.collapsed_re, ''); + // Toggle the "Show" link to a "Hide" link + var collapse_link = document.getElementById('fieldsetcollapser' + fieldset_index); + collapse_link.onclick = new Function('CollapsedFieldsets.hide('+fieldset_index+'); return false;'); + collapse_link.innerHTML = gettext('Hide'); + }, + hide: function(fieldset_index) { + var fs = document.getElementsByTagName('fieldset')[fieldset_index]; + // Add the class name that causes the "display: none". + fs.className += ' ' + CollapsedFieldsets.collapsed_class; + // Toggle the "Hide" link to a "Show" link + var collapse_link = document.getElementById('fieldsetcollapser' + fieldset_index); collapse_link.onclick = new Function('CollapsedFieldsets.show('+fieldset_index+'); return false;'); - collapse_link.innerHTML = gettext('Show'); - }, + collapse_link.innerHTML = gettext('Show'); + }, - uncollapse_all: function() { - var fieldsets = document.getElementsByTagName('fieldset'); - for (var i=0; i<fieldsets.length; i++) { - if (fieldsets[i].className.match(CollapsedFieldsets.collapsed_re)) { - CollapsedFieldsets.show(i); - } - } - } + uncollapse_all: function() { + var fieldsets = document.getElementsByTagName('fieldset'); + for (var i=0; i<fieldsets.length; i++) { + if (fieldsets[i].className.match(CollapsedFieldsets.collapsed_re)) { + CollapsedFieldsets.show(i); + } + } + } } addEvent(window, 'load', CollapsedFieldsets.init); diff --git a/django/contrib/admin/media/js/admin/DateTimeShortcuts.js b/django/contrib/admin/media/js/admin/DateTimeShortcuts.js index 35199baf84..77c536b865 100644 --- a/django/contrib/admin/media/js/admin/DateTimeShortcuts.js +++ b/django/contrib/admin/media/js/admin/DateTimeShortcuts.js @@ -8,7 +8,9 @@ var DateTimeShortcuts = { clockInputs: [], calendarDivName1: 'calendarbox', // name of calendar <div> that gets toggled calendarDivName2: 'calendarin', // name of <div> that contains calendar + calendarLinkName: 'calendarlink',// name of the link that is used to toggle clockDivName: 'clockbox', // name of clock <div> that gets toggled + clockLinkName: 'clocklink', // name of the link that is used to toggle admin_media_prefix: '', init: function() { // Deduce admin_media_prefix by looking at the <script>s in the @@ -46,6 +48,7 @@ var DateTimeShortcuts = { now_link.appendChild(document.createTextNode(gettext('Now'))); var clock_link = document.createElement('a'); clock_link.setAttribute('href', 'javascript:DateTimeShortcuts.openClock(' + num + ');'); + clock_link.id = DateTimeShortcuts.clockLinkName + num; quickElement('img', clock_link, '', 'src', DateTimeShortcuts.admin_media_prefix + 'img/admin/icon_clock.gif', 'alt', gettext('Clock')); shortcuts_span.appendChild(document.createTextNode('\240')); shortcuts_span.appendChild(now_link); @@ -69,17 +72,6 @@ var DateTimeShortcuts = { var clock_box = document.createElement('div'); clock_box.style.display = 'none'; clock_box.style.position = 'absolute'; - if (getStyle(document.body,'direction')!='rtl') { - clock_box.style.left = findPosX(clock_link) + 17 + 'px'; - } - else { - // since style's width is in em, it'd be tough to calculate - // px value of it. let's use an estimated px for now - // TODO: IE returns wrong value for findPosX when in rtl mode - // (it returns as it was left aligned), needs to be fixed. - clock_box.style.left = findPosX(clock_link) - 110 + 'px'; - } - clock_box.style.top = findPosY(clock_link) - 30 + 'px'; clock_box.className = 'clockbox module'; clock_box.setAttribute('id', DateTimeShortcuts.clockDivName + num); document.body.appendChild(clock_box); @@ -98,7 +90,25 @@ var DateTimeShortcuts = { quickElement('a', cancel_p, gettext('Cancel'), 'href', 'javascript:DateTimeShortcuts.dismissClock(' + num + ');'); }, openClock: function(num) { - document.getElementById(DateTimeShortcuts.clockDivName + num).style.display = 'block'; + var clock_box = document.getElementById(DateTimeShortcuts.clockDivName+num) + var clock_link = document.getElementById(DateTimeShortcuts.clockLinkName+num) + + // Recalculate the clockbox position + // is it left-to-right or right-to-left layout ? + if (getStyle(document.body,'direction')!='rtl') { + clock_box.style.left = findPosX(clock_link) + 17 + 'px'; + } + else { + // since style's width is in em, it'd be tough to calculate + // px value of it. let's use an estimated px for now + // TODO: IE returns wrong value for findPosX when in rtl mode + // (it returns as it was left aligned), needs to be fixed. + clock_box.style.left = findPosX(clock_link) - 110 + 'px'; + } + clock_box.style.top = findPosY(clock_link) - 30 + 'px'; + + // Show the clock box + clock_box.style.display = 'block'; addEvent(window, 'click', function() { DateTimeShortcuts.dismissClock(num); return true; }); }, dismissClock: function(num) { @@ -123,6 +133,7 @@ var DateTimeShortcuts = { today_link.appendChild(document.createTextNode(gettext('Today'))); var cal_link = document.createElement('a'); cal_link.setAttribute('href', 'javascript:DateTimeShortcuts.openCalendar(' + num + ');'); + cal_link.id = DateTimeShortcuts.calendarLinkName + num; quickElement('img', cal_link, '', 'src', DateTimeShortcuts.admin_media_prefix + 'img/admin/icon_calendar.gif', 'alt', gettext('Calendar')); shortcuts_span.appendChild(document.createTextNode('\240')); shortcuts_span.appendChild(today_link); @@ -149,18 +160,6 @@ var DateTimeShortcuts = { var cal_box = document.createElement('div'); cal_box.style.display = 'none'; cal_box.style.position = 'absolute'; - // is it left-to-right or right-to-left layout ? - if (getStyle(document.body,'direction')!='rtl') { - cal_box.style.left = findPosX(cal_link) + 17 + 'px'; - } - else { - // since style's width is in em, it'd be tough to calculate - // px value of it. let's use an estimated px for now - // TODO: IE returns wrong value for findPosX when in rtl mode - // (it returns as it was left aligned), needs to be fixed. - cal_box.style.left = findPosX(cal_link) - 180 + 'px'; - } - cal_box.style.top = findPosY(cal_link) - 75 + 'px'; cal_box.className = 'calendarbox module'; cal_box.setAttribute('id', DateTimeShortcuts.calendarDivName1 + num); document.body.appendChild(cal_box); @@ -172,7 +171,6 @@ var DateTimeShortcuts = { cal_nav_prev.className = 'calendarnav-previous'; var cal_nav_next = quickElement('a', cal_nav, '>', 'href', 'javascript:DateTimeShortcuts.drawNext('+num+');'); cal_nav_next.className = 'calendarnav-next'; - cal_box.appendChild(cal_nav); // main box var cal_main = quickElement('div', cal_box, '', 'id', DateTimeShortcuts.calendarDivName2 + num); @@ -195,7 +193,24 @@ var DateTimeShortcuts = { quickElement('a', cancel_p, gettext('Cancel'), 'href', 'javascript:DateTimeShortcuts.dismissCalendar(' + num + ');'); }, openCalendar: function(num) { - document.getElementById(DateTimeShortcuts.calendarDivName1+num).style.display = 'block'; + var cal_box = document.getElementById(DateTimeShortcuts.calendarDivName1+num) + var cal_link = document.getElementById(DateTimeShortcuts.calendarLinkName+num) + + // Recalculate the clockbox position + // is it left-to-right or right-to-left layout ? + if (getStyle(document.body,'direction')!='rtl') { + cal_box.style.left = findPosX(cal_link) + 17 + 'px'; + } + else { + // since style's width is in em, it'd be tough to calculate + // px value of it. let's use an estimated px for now + // TODO: IE returns wrong value for findPosX when in rtl mode + // (it returns as it was left aligned), needs to be fixed. + cal_box.style.left = findPosX(cal_link) - 180 + 'px'; + } + cal_box.style.top = findPosY(cal_link) - 75 + 'px'; + + cal_box.style.display = 'block'; addEvent(window, 'click', function() { DateTimeShortcuts.dismissCalendar(num); return true; }); }, dismissCalendar: function(num) { diff --git a/django/contrib/admin/media/js/admin/RelatedObjectLookups.js b/django/contrib/admin/media/js/admin/RelatedObjectLookups.js index cf57fc4dfb..db4ed1a9d1 100644 --- a/django/contrib/admin/media/js/admin/RelatedObjectLookups.js +++ b/django/contrib/admin/media/js/admin/RelatedObjectLookups.js @@ -11,7 +11,7 @@ function showRelatedObjectLookupPopup(triggeringLink) { } else { href = triggeringLink.href + '?pop=1'; } - var win = window.open(href, name, 'height=500,width=740,resizable=yes,scrollbars=yes'); + var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes'); win.focus(); return false; } diff --git a/django/contrib/admin/templates/admin/auth/user/add_form.html b/django/contrib/admin/templates/admin/auth/user/add_form.html new file mode 100644 index 0000000000..139fa6a75e --- /dev/null +++ b/django/contrib/admin/templates/admin/auth/user/add_form.html @@ -0,0 +1,28 @@ +{% extends "admin/change_form.html" %} +{% load i18n %} + +{% block after_field_sets %} + +<p>{% trans "First, enter a username and password. Then, you'll be able to edit more user options." %}</p> + +<fieldset class="module aligned"> + +<div class="form-row"> + {{ form.username.html_error_list }} + <label for="id_username" class="required">{% trans 'Username' %}:</label> {{ form.username }} + <p class="help">{{ username_help_text }}</p> +</div> + +<div class="form-row"> + {{ form.password1.html_error_list }} + <label for="id_password1" class="required">{% trans 'Password' %}:</label> {{ form.password1 }} +</div> + +<div class="form-row"> + {{ form.password2.html_error_list }} + <label for="id_password2" class="required">{% trans 'Password (again)' %}:</label> {{ form.password2 }} + <p class="help">{% trans 'Enter the same password as above, for verification.' %}</p> +</div> + +</fieldset> +{% endblock %} diff --git a/django/contrib/admin/templates/admin/base.html b/django/contrib/admin/templates/admin/base.html index 67fe27529c..b63604b268 100644 --- a/django/contrib/admin/templates/admin/base.html +++ b/django/contrib/admin/templates/admin/base.html @@ -6,6 +6,7 @@ {% if LANGUAGE_BIDI %}<link rel="stylesheet" type="text/css" href="{% block stylesheet_rtl %}{% admin_media_prefix %}css/rtl.css{% endblock %}" />{% endif %} {% block extrastyle %}{% endblock %} {% block extrahead %}{% endblock %} +{% block blockbots %}<meta name="robots" content="NONE,NOARCHIVE" />{% endblock %} </head> {% load i18n %} @@ -20,13 +21,13 @@ <div id="branding"> {% block branding %}{% endblock %} </div> - {% if not user.is_anonymous %}{% if user.is_staff %} + {% if user.is_authenticated and user.is_staff %} <div id="user-tools">{% trans 'Welcome,' %} <strong>{% if user.first_name %}{{ user.first_name|escape }}{% else %}{{ user.username }}{% endif %}</strong>. {% block userlinks %}<a href="doc/">{% trans 'Documentation' %}</a> / <a href="password_change/">{% trans 'Change password' %}</a> / <a href="logout/">{% trans 'Log out' %}</a>{% endblock %}</div> - {% endif %}{% endif %} + {% endif %} {% block nav-global %}{% endblock %} </div> <!-- END Header --> - {% block breadcrumbs %}<div class="breadcrumbs"><a href="/">{% trans 'Home' %}</a>{% if title %} › {{ title }}{% endif %}</div>{% endblock %} + {% block breadcrumbs %}<div class="breadcrumbs"><a href="/">{% trans 'Home' %}</a>{% if title %} › {{ title|escape }}{% endif %}</div>{% endblock %} {% endif %} {% if messages %} @@ -36,7 +37,7 @@ <!-- Content --> <div id="content" class="{% block coltype %}colM{% endblock %}"> {% block pretitle %}{% endblock %} - {% block content_title %}{% if title %}<h1>{{ title }}</h1>{% endif %}{% endblock %} + {% block content_title %}{% if title %}<h1>{{ title|escape }}</h1>{% endif %}{% endblock %} {% block content %}{{ content }}{% endblock %} {% block sidebar %}{% endblock %} <br class="clear" /> diff --git a/django/contrib/admin/templates/admin/base_site.html b/django/contrib/admin/templates/admin/base_site.html index b867bd29bd..2bc7310873 100644 --- a/django/contrib/admin/templates/admin/base_site.html +++ b/django/contrib/admin/templates/admin/base_site.html @@ -1,7 +1,7 @@ {% extends "admin/base.html" %} {% load i18n %} -{% block title %}{{ title }} | {% trans 'Django site admin' %}{% endblock %} +{% block title %}{{ title|escape }} | {% trans 'Django site admin' %}{% endblock %} {% block branding %} <h1 id="site-name">{% trans 'Django administration' %}</h1> diff --git a/django/contrib/admin/templates/admin/change_form.html b/django/contrib/admin/templates/admin/change_form.html index fa04969f01..b1fdc5ebdb 100644 --- a/django/contrib/admin/templates/admin/change_form.html +++ b/django/contrib/admin/templates/admin/change_form.html @@ -11,8 +11,8 @@ {% block breadcrumbs %}{% if not is_popup %} <div class="breadcrumbs"> <a href="../../../">{% trans "Home" %}</a> › - <a href="../">{{ opts.verbose_name_plural|capfirst }}</a> › - {% if add %}{% trans "Add" %} {{ opts.verbose_name }}{% else %}{{ original|truncatewords:"18"|escape }}{% endif %} + <a href="../">{{ opts.verbose_name_plural|capfirst|escape }}</a> › + {% if add %}{% trans "Add" %} {{ opts.verbose_name|escape }}{% else %}{{ original|truncatewords:"18"|escape }}{% endif %} </div> {% endif %}{% endblock %} {% block content %}<div id="content-main"> @@ -21,7 +21,7 @@ {% if has_absolute_url %}<li><a href="../../../r/{{ content_type_id }}/{{ object_id }}/" class="viewsitelink">{% trans "View on site" %}</a></li>{% endif%} </ul> {% endif %}{% endif %} -<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="{{ form_url }}" method="post">{% block form_top %}{% endblock %} +<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="{{ form_url }}" method="post" id="{{ opts.module_name }}_form">{% block form_top %}{% endblock %} <div> {% if is_popup %}<input type="hidden" name="_popup" value="1" />{% endif %} {% if opts.admin.save_on_top %}{% submit_row %}{% endif %} diff --git a/django/contrib/admin/templates/admin/change_list.html b/django/contrib/admin/templates/admin/change_list.html index 5b54bfb8cc..bd2304bd52 100644 --- a/django/contrib/admin/templates/admin/change_list.html +++ b/django/contrib/admin/templates/admin/change_list.html @@ -3,12 +3,12 @@ {% block stylesheet %}{% admin_media_prefix %}css/changelists.css{% endblock %} {% block bodyclass %}change-list{% endblock %} {% block userlinks %}<a href="../../doc/">{% trans 'Documentation' %}</a> / <a href="../../password_change/">{% trans 'Change password' %}</a> / <a href="../../logout/">{% trans 'Log out' %}</a>{% endblock %} -{% if not is_popup %}{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans "Home" %}</a> › {{ cl.opts.verbose_name_plural|capfirst }}</div>{% endblock %}{% endif %} +{% if not is_popup %}{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans "Home" %}</a> › {{ cl.opts.verbose_name_plural|capfirst|escape }}</div>{% endblock %}{% endif %} {% block coltype %}flex{% endblock %} {% block content %} <div id="content-main"> {% if has_add_permission %} -<ul class="object-tools"><li><a href="add/{% if is_popup %}?_popup=1{% endif %}" class="addlink">{% blocktrans with cl.opts.verbose_name as name %}Add {{ name }}{% endblocktrans %}</a></li></ul> +<ul class="object-tools"><li><a href="add/{% if is_popup %}?_popup=1{% endif %}" class="addlink">{% blocktrans with cl.opts.verbose_name|escape as name %}Add {{ name }}{% endblocktrans %}</a></li></ul> {% endif %} <div class="module{% if cl.has_filters %} filtered{% endif %}" id="changelist"> {% block search %}{% search_form cl %}{% endblock %} diff --git a/django/contrib/admin/templates/admin/date_hierarchy.html b/django/contrib/admin/templates/admin/date_hierarchy.html index a53d810f93..d2d69616c7 100644 --- a/django/contrib/admin/templates/admin/date_hierarchy.html +++ b/django/contrib/admin/templates/admin/date_hierarchy.html @@ -1,10 +1,10 @@ {% if show %} <div class="xfull"> <ul class="toplinks"> -{% if back %}<li class="date-back"><a href="{{ back.link }}">‹ {{ back.title }}</a></li>{% endif %} +{% if back %}<li class="date-back"><a href="{{ back.link }}">‹ {{ back.title|escape }}</a></li>{% endif %} {% for choice in choices %} -<li> {% if choice.link %}<a href="{{ choice.link }}">{% endif %}{{ choice.title }}{% if choice.link %}</a>{% endif %}</li> +<li> {% if choice.link %}<a href="{{ choice.link }}">{% endif %}{{ choice.title|escape }}{% if choice.link %}</a>{% endif %}</li> {% endfor %} </ul><br class="clear" /> </div> -{% endif %}
\ No newline at end of file +{% endif %} diff --git a/django/contrib/admin/templates/admin/delete_confirmation.html b/django/contrib/admin/templates/admin/delete_confirmation.html index f907c18a16..3921ab69e3 100644 --- a/django/contrib/admin/templates/admin/delete_confirmation.html +++ b/django/contrib/admin/templates/admin/delete_confirmation.html @@ -4,21 +4,21 @@ {% block breadcrumbs %} <div class="breadcrumbs"> <a href="../../../../">{% trans "Home" %}</a> › - <a href="../../">{{ opts.verbose_name_plural|capfirst }}</a> › - <a href="../">{{ object|striptags|truncatewords:"18" }}</a> › + <a href="../../">{{ opts.verbose_name_plural|capfirst|escape }}</a> › + <a href="../">{{ object|escape|truncatewords:"18" }}</a> › {% trans 'Delete' %} </div> {% endblock %} {% block content %} {% if perms_lacking %} - <p>{% blocktrans %}Deleting the {{ object_name }} '{{ object }}' would result in deleting related objects, but your account doesn't have permission to delete the following types of objects:{% endblocktrans %}</p> + <p>{% blocktrans with object|escape as escaped_object %}Deleting the {{ object_name }} '{{ escaped_object }}' would result in deleting related objects, but your account doesn't have permission to delete the following types of objects:{% endblocktrans %}</p> <ul> {% for obj in perms_lacking %} - <li>{{ obj }}</li> + <li>{{ obj|escape }}</li> {% endfor %} </ul> {% else %} - <p>{% blocktrans %}Are you sure you want to delete the {{ object_name }} "{{ object }}"? All of the following related items will be deleted:{% endblocktrans %}</p> + <p>{% blocktrans with object|escape as escaped_object %}Are you sure you want to delete the {{ object_name }} "{{ escaped_object }}"? All of the following related items will be deleted:{% endblocktrans %}</p> <ul>{{ deleted_objects|unordered_list }}</ul> <form action="" method="post"> <div> diff --git a/django/contrib/admin/templates/admin/edit_inline_stacked.html b/django/contrib/admin/templates/admin/edit_inline_stacked.html index 45aa0a4f58..48ecc698d9 100644 --- a/django/contrib/admin/templates/admin/edit_inline_stacked.html +++ b/django/contrib/admin/templates/admin/edit_inline_stacked.html @@ -1,7 +1,7 @@ {% load admin_modify %} <fieldset class="module aligned"> {% for fcw in bound_related_object.form_field_collection_wrappers %} - <h2>{{ bound_related_object.relation.opts.verbose_name|capfirst }} #{{ forloop.counter }}</h2> + <h2>{{ bound_related_object.relation.opts.verbose_name|capfirst|escape }} #{{ forloop.counter }}</h2> {% if bound_related_object.show_url %}{% if fcw.obj.original %} <p><a href="/r/{{ fcw.obj.original.content_type_id }}/{{ fcw.obj.original.id }}/">View on site</a></p> {% endif %}{% endif %} diff --git a/django/contrib/admin/templates/admin/edit_inline_tabular.html b/django/contrib/admin/templates/admin/edit_inline_tabular.html index e9535df02c..3d059c8b3d 100644 --- a/django/contrib/admin/templates/admin/edit_inline_tabular.html +++ b/django/contrib/admin/templates/admin/edit_inline_tabular.html @@ -1,12 +1,13 @@ {% load admin_modify %} <fieldset class="module"> - <h2>{{ bound_related_object.relation.opts.verbose_name_plural|capfirst }}</h2><table> + <h2>{{ bound_related_object.relation.opts.verbose_name_plural|capfirst|escape }}</h2><table> <thead><tr> {% for fw in bound_related_object.field_wrapper_list %} {% if fw.needs_header %} - <th{{ fw.header_class_attribute }}>{{ fw.field.verbose_name|capfirst }}</th> + <th{{ fw.header_class_attribute }}>{{ fw.field.verbose_name|capfirst|escape }}</th> {% endif %} {% endfor %} + </tr></thead> {% for fcw in bound_related_object.form_field_collection_wrappers %} {% if change %}{% if original_row_needed %} {% if fcw.obj.original %} diff --git a/django/contrib/admin/templates/admin/filter.html b/django/contrib/admin/templates/admin/filter.html index 5b0e78b6fc..8b5b521437 100644 --- a/django/contrib/admin/templates/admin/filter.html +++ b/django/contrib/admin/templates/admin/filter.html @@ -1,5 +1,5 @@ {% load i18n %} -<h3>{% blocktrans %} By {{ title }} {% endblocktrans %}</h3> +<h3>{% blocktrans with title|escape as filter_title %} By {{ filter_title }} {% endblocktrans %}</h3> <ul> {% for choice in choices %} <li{% if choice.selected %} class="selected"{% endif %}> diff --git a/django/contrib/admin/templates/admin/index.html b/django/contrib/admin/templates/admin/index.html index f7b121723a..aa63c14fce 100644 --- a/django/contrib/admin/templates/admin/index.html +++ b/django/contrib/admin/templates/admin/index.html @@ -19,9 +19,9 @@ {% for model in app.models %} <tr> {% if model.perms.change %} - <th scope="row"><a href="{{ model.admin_url }}">{{ model.name }}</a></th> + <th scope="row"><a href="{{ model.admin_url }}">{{ model.name|escape }}</a></th> {% else %} - <th scope="row">{{ model.name }}</th> + <th scope="row">{{ model.name|escape }}</th> {% endif %} {% if model.perms.add %} @@ -58,7 +58,7 @@ {% else %} <ul class="actionlist"> {% for entry in admin_log %} - <li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">{% if not entry.is_deletion %}<a href="{{ entry.get_admin_url }}">{% endif %}{{ entry.object_repr|escape }}{% if not entry.is_deletion %}</a>{% endif %}<br /><span class="mini quiet">{{ entry.content_type.name|capfirst }}</span></li> + <li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">{% if not entry.is_deletion %}<a href="{{ entry.get_admin_url }}">{% endif %}{{ entry.object_repr|escape }}{% if not entry.is_deletion %}</a>{% endif %}<br /><span class="mini quiet">{{ entry.content_type.name|capfirst|escape }}</span></li> {% endfor %} </ul> {% endif %} diff --git a/django/contrib/admin/templates/admin/invalid_setup.html b/django/contrib/admin/templates/admin/invalid_setup.html index 1fa0d32358..1d7d61f0d2 100644 --- a/django/contrib/admin/templates/admin/invalid_setup.html +++ b/django/contrib/admin/templates/admin/invalid_setup.html @@ -1,7 +1,7 @@ {% extends "admin/base_site.html" %} {% load i18n %} -{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans 'Home' %}</a> › {{ title }}</div>{% endblock %} +{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans 'Home' %}</a> › {{ title|escape }}</div>{% endblock %} {% block content %} diff --git a/django/contrib/admin/templates/admin/login.html b/django/contrib/admin/templates/admin/login.html index 5f338f703e..0773132cec 100644 --- a/django/contrib/admin/templates/admin/login.html +++ b/django/contrib/admin/templates/admin/login.html @@ -13,17 +13,17 @@ {% endif %} <div id="content-main"> <form action="{{ app_path }}" method="post" id="login-form"> - <div class="form-row"> - <label for="id_username">{% trans 'Username:' %}</label> <input type="text" name="username" id="id_username" /> - </div> - <div class="form-row"> - <label for="id_password">{% trans 'Password:' %}</label> <input type="password" name="password" id="id_password" /> - <input type="hidden" name="this_is_the_login_form" value="1" /> - <input type="hidden" name="post_data" value="{{ post_data }}" /> {% comment %}<span class="help">{% trans 'Have you <a href="/password_reset/">forgotten your password</a>?' %}</span>{% endcomment %} - </div> - <div class="submit-row"> - <label> </label><input type="submit" value="{% trans 'Log in' %}" /> - </div> + <div class="form-row"> + <label for="id_username">{% trans 'Username:' %}</label> <input type="text" name="username" id="id_username" /> + </div> + <div class="form-row"> + <label for="id_password">{% trans 'Password:' %}</label> <input type="password" name="password" id="id_password" /> + <input type="hidden" name="this_is_the_login_form" value="1" /> + <input type="hidden" name="post_data" value="{{ post_data }}" /> {#<span class="help">{% trans 'Have you <a href="/password_reset/">forgotten your password</a>?' %}</span>#} + </div> + <div class="submit-row"> + <label> </label><input type="submit" value="{% trans 'Log in' %}" /> + </div> </form> <script type="text/javascript"> diff --git a/django/contrib/admin/templates/admin/object_history.html b/django/contrib/admin/templates/admin/object_history.html index fc568305ca..14a77b8a31 100644 --- a/django/contrib/admin/templates/admin/object_history.html +++ b/django/contrib/admin/templates/admin/object_history.html @@ -2,7 +2,7 @@ {% load i18n %} {% block userlinks %}<a href="../../../../doc/">{% trans 'Documentation' %}</a> / <a href="../../../../password_change/">{% trans 'Change password' %}</a> / <a href="../../../../logout/">{% trans 'Log out' %}</a>{% endblock %} {% block breadcrumbs %} -<div class="breadcrumbs"><a href="../../../../">{% trans 'Home' %}</a> › <a href="../../">{{ module_name }}</a> › <a href="../">{{ object|truncatewords:"18" }}</a> › {% trans 'History' %}</div> +<div class="breadcrumbs"><a href="../../../../">{% trans 'Home' %}</a> › <a href="../../">{{ module_name|escape }}</a> › <a href="../">{{ object|escape|truncatewords:"18" }}</a> › {% trans 'History' %}</div> {% endblock %} {% block content %} diff --git a/django/contrib/admin/templates/admin/pagination.html b/django/contrib/admin/templates/admin/pagination.html index 7694e4c5b0..e1c09b2932 100644 --- a/django/contrib/admin/templates/admin/pagination.html +++ b/django/contrib/admin/templates/admin/pagination.html @@ -6,6 +6,6 @@ {% paginator_number cl i %} {% endfor %} {% endif %} -{{ cl.result_count }} {% ifequal cl.result_count 1 %}{{ cl.opts.verbose_name }}{% else %}{{ cl.opts.verbose_name_plural }}{% endifequal %} +{{ cl.result_count }} {% ifequal cl.result_count 1 %}{{ cl.opts.verbose_name|escape }}{% else %}{{ cl.opts.verbose_name_plural|escape }}{% endifequal %} {% if show_all_url %} <a href="{{ show_all_url }}" class="showall">{% trans 'Show all' %}</a>{% endif %} </p> diff --git a/django/contrib/admin/templates/admin_doc/index.html b/django/contrib/admin/templates/admin_doc/index.html index 331774d2b3..74f9f20916 100644 --- a/django/contrib/admin/templates/admin_doc/index.html +++ b/django/contrib/admin/templates/admin_doc/index.html @@ -9,17 +9,17 @@ <h1>Documentation</h1>
<div id="content-main">
- <h3><a href="tags/">Tags</a></h3>
- <p>List of all the template tags and their functions.</p>
+ <h3><a href="tags/">Tags</a></h3>
+ <p>List of all the template tags and their functions.</p>
- <h3><a href="filters/">Filters</a></h3>
- <p>Filters are actions which can be applied to variables in a template to alter the output.</p>
+ <h3><a href="filters/">Filters</a></h3>
+ <p>Filters are actions which can be applied to variables in a template to alter the output.</p>
- <h3><a href="models/">Models</a></h3>
- <p>Models are descriptions of all the objects in the system and their associated fields. Each model has a list of fields which can be accessed as template variables.</p>
+ <h3><a href="models/">Models</a></h3>
+ <p>Models are descriptions of all the objects in the system and their associated fields. Each model has a list of fields which can be accessed as template variables.</p>
- <h3><a href="views/">Views</a></h3>
- <p>Each page on the public site is generated by a view. The view defines which template is used to generate the page and which objects are available to that template.</p>
+ <h3><a href="views/">Views</a></h3>
+ <p>Each page on the public site is generated by a view. The view defines which template is used to generate the page and which objects are available to that template.</p>
<h3><a href="bookmarklets/">Bookmarklets</a></h3>
<p>Tools for your browser to quickly access admin functionality.</p>
diff --git a/django/contrib/admin/templates/admin_doc/missing_docutils.html b/django/contrib/admin/templates/admin_doc/missing_docutils.html index d0b571f957..cdeab0cdd8 100644 --- a/django/contrib/admin/templates/admin_doc/missing_docutils.html +++ b/django/contrib/admin/templates/admin_doc/missing_docutils.html @@ -9,9 +9,9 @@ <h1>Documentation</h1> <div id="content-main"> - <h3>The admin documentation system requires Python's <a href="http://docutils.sf.net/">docutils</a> library.</h3> + <h3>The admin documentation system requires Python's <a href="http://docutils.sf.net/">docutils</a> library.</h3> - <p>Please ask your administrators to install <a href="http://docutils.sf.net/">docutils</a>.</p> + <p>Please ask your administrators to install <a href="http://docutils.sf.net/">docutils</a>.</p> </div> {% endblock %} diff --git a/django/contrib/admin/templates/admin_doc/model_detail.html b/django/contrib/admin/templates/admin_doc/model_detail.html index 9ac56864fa..70133e26dd 100644 --- a/django/contrib/admin/templates/admin_doc/model_detail.html +++ b/django/contrib/admin/templates/admin_doc/model_detail.html @@ -9,13 +9,13 @@ </style> {% endblock %} -{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> › <a href="../../">Documentation</a> › <a href="../">Models</a> › {{ name }}</div>{% endblock %} +{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> › <a href="../../">Documentation</a> › <a href="../">Models</a> › {{ name|escape }}</div>{% endblock %} -{% block title %}Model: {{ name }}{% endblock %} +{% block title %}Model: {{ name|escape }}{% endblock %} {% block content %} <div id="content-main"> -<h1>{{ summary }}</h1> +<h1>{{ summary|escape }}</h1> {% if description %} <p>{% filter escape|linebreaksbr %}{% trans description %}{% endfilter %}</p> diff --git a/django/contrib/admin/templates/admin_doc/template_detail.html b/django/contrib/admin/templates/admin_doc/template_detail.html index df67f1856b..280ea912d0 100644 --- a/django/contrib/admin/templates/admin_doc/template_detail.html +++ b/django/contrib/admin/templates/admin_doc/template_detail.html @@ -1,19 +1,19 @@ {% extends "admin/base_site.html" %} {% load i18n %} -{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> › <a href="../../">Documentation</a> › Templates › {{ name }}</div>{% endblock %} +{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> › <a href="../../">Documentation</a> › Templates › {{ name|escape }}</div>{% endblock %} {% block userlinks %}<a href="../../../password_change/">{% trans 'Change password' %}</a> / <a href="../../../logout/">{% trans 'Log out' %}</a>{% endblock %} -{% block title %}Template: {{ name }}{% endblock %} +{% block title %}Template: {{ name|escape }}{% endblock %} {% block content %} -<h1>Template: "{{ name }}"</h1> +<h1>Template: "{{ name|escape }}"</h1> {% regroup templates|dictsort:"site_id" by site as templates_by_site %} {% for group in templates_by_site %} - <h2>Search path for template "{{ name }}" on {{ group.grouper }}:</h2> + <h2>Search path for template "{{ name|escape }}" on {{ group.grouper }}:</h2> <ol> {% for template in group.list|dictsort:"order" %} - <li><code>{{ template.file }}</code>{% if not template.exists %} <em>(does not exist)</em>{% endif %}</li> + <li><code>{{ template.file|escape }}</code>{% if not template.exists %} <em>(does not exist)</em>{% endif %}</li> {% endfor %} </ol> {% endfor %} diff --git a/django/contrib/admin/templates/widget/file.html b/django/contrib/admin/templates/widget/file.html index e4a0756211..e584abf956 100644 --- a/django/contrib/admin/templates/widget/file.html +++ b/django/contrib/admin/templates/widget/file.html @@ -1,4 +1,4 @@ {% load admin_modify i18n %}{% if bound_field.original_value %} -{% trans "Currently:" %} <a href="{{ bound_field.original_url }}" > {{ bound_field.original_value }} </a><br /> +{% trans "Currently:" %} <a href="{{ bound_field.original_url }}" > {{ bound_field.original_value|escape }} </a><br /> {% trans "Change:" %}{% output_all bound_field.form_fields %} {% else %} {% output_all bound_field.form_fields %} {% endif %} diff --git a/django/contrib/admin/templates/widget/foreign.html b/django/contrib/admin/templates/widget/foreign.html index 6b43d044bd..301f5214db 100644 --- a/django/contrib/admin/templates/widget/foreign.html +++ b/django/contrib/admin/templates/widget/foreign.html @@ -15,6 +15,6 @@ {{ bound_field.original_value }} {% endif %} {% if bound_field.raw_id_admin %} - {% if bound_field.existing_display %} <strong>{{ bound_field.existing_display|truncatewords:"14" }}</strong>{% endif %} + {% if bound_field.existing_display %} <strong>{{ bound_field.existing_display|truncatewords:"14"|escape }}</strong>{% endif %} {% endif %} {% endif %} diff --git a/django/contrib/admin/templates/widget/one_to_one.html b/django/contrib/admin/templates/widget/one_to_one.html index a79a12314f..efd0117bf2 100644 --- a/django/contrib/admin/templates/widget/one_to_one.html +++ b/django/contrib/admin/templates/widget/one_to_one.html @@ -1,2 +1,2 @@ {% if add %}{% include "widget/foreign.html" %}{% endif %} -{% if change %}{% if bound_field.existing_display %} <strong>{{ bound_field.existing_display|truncatewords:"14" }}</strong>{% endif %}{% endif %} +{% if change %}{% if bound_field.existing_display %} <strong>{{ bound_field.existing_display|truncatewords:"14"|escape }}</strong>{% endif %}{% endif %} diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py index 3537f46755..832b3562cd 100644 --- a/django/contrib/admin/templatetags/admin_list.py +++ b/django/contrib/admin/templatetags/admin_list.py @@ -1,8 +1,6 @@ -from django import template from django.conf import settings -from django.contrib.admin.views.main import MAX_SHOW_ALL_ALLOWED, ALL_VAR +from django.contrib.admin.views.main import ALL_VAR, EMPTY_CHANGELIST_VALUE from django.contrib.admin.views.main import ORDER_VAR, ORDER_TYPE_VAR, PAGE_VAR, SEARCH_VAR -from django.contrib.admin.views.main import IS_POPUP_VAR, EMPTY_CHANGELIST_VALUE from django.core.exceptions import ObjectDoesNotExist from django.db import models from django.utils import dateformat @@ -119,7 +117,7 @@ def items_for_result(cl, result): if callable(attr): attr = attr() result_repr = str(attr) - except AttributeError, ObjectDoesNotExist: + except (AttributeError, ObjectDoesNotExist): result_repr = EMPTY_CHANGELIST_VALUE else: # Strip HTML tags in the resulting text, except if the @@ -167,11 +165,12 @@ def items_for_result(cl, result): result_repr = ' ' # If list_display_links not defined, add the link tag to the first field if (first and not cl.lookup_opts.admin.list_display_links) or field_name in cl.lookup_opts.admin.list_display_links: + table_tag = {True:'th', False:'td'}[first] first = False url = cl.url_for_result(result) result_id = str(getattr(result, pk)) # str() is needed in case of 23L (long ints) - yield ('<th%s><a href="%s"%s>%s</a></th>' % \ - (row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %r); return false;"' % result_id or ''), result_repr)) + yield ('<%s%s><a href="%s"%s>%s</a></%s>' % \ + (table_tag, row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %r); return false;"' % result_id or ''), result_repr, table_tag)) else: yield ('<td%s>%s</td>' % (row_class, result_repr)) diff --git a/django/contrib/admin/templatetags/admin_modify.py b/django/contrib/admin/templatetags/admin_modify.py index 2d34452f52..d09fa28b10 100644 --- a/django/contrib/admin/templatetags/admin_modify.py +++ b/django/contrib/admin/templatetags/admin_modify.py @@ -1,9 +1,7 @@ from django import template from django.contrib.admin.views.main import AdminBoundField from django.template import loader -from django.utils.html import escape from django.utils.text import capfirst -from django.utils.functional import curry from django.db import models from django.db.models.fields import Field from django.db.models.related import BoundRelatedObject @@ -162,8 +160,10 @@ class EditInlineNode(template.Node): context.push() if relation.field.rel.edit_inline == models.TABULAR: bound_related_object_class = TabularBoundRelatedObject - else: + elif relation.field.rel.edit_inline == models.STACKED: bound_related_object_class = StackedBoundRelatedObject + else: + bound_related_object_class = relation.field.rel.edit_inline original = context.get('original', None) bound_related_object = relation.bind(context['form'], original, bound_related_object_class) context['bound_related_object'] = bound_related_object @@ -198,7 +198,7 @@ def filter_interface_script_maybe(bound_field): if f.rel and isinstance(f.rel, models.ManyToManyRel) and f.rel.filter_interface: return '<script type="text/javascript">addEvent(window, "load", function(e) {' \ ' SelectFilter.init("id_%s", "%s", %s, "%s"); });</script>\n' % ( - f.name, f.verbose_name, f.rel.filter_interface-1, settings.ADMIN_MEDIA_PREFIX) + f.name, f.verbose_name.replace('"', '\\"'), f.rel.filter_interface-1, settings.ADMIN_MEDIA_PREFIX) else: return '' filter_interface_script_maybe = register.simple_tag(filter_interface_script_maybe) diff --git a/django/contrib/admin/urls.py b/django/contrib/admin/urls.py index bd894d8de1..aaf9841e45 100644 --- a/django/contrib/admin/urls.py +++ b/django/contrib/admin/urls.py @@ -21,13 +21,15 @@ urlpatterns = patterns('', ('^doc/tags/$', 'django.contrib.admin.views.doc.template_tag_index'), ('^doc/filters/$', 'django.contrib.admin.views.doc.template_filter_index'), ('^doc/views/$', 'django.contrib.admin.views.doc.view_index'), - ('^doc/views/jump/$', 'django.contrib.admin.views.doc.jump_to_view'), ('^doc/views/(?P<view>[^/]+)/$', 'django.contrib.admin.views.doc.view_detail'), ('^doc/models/$', 'django.contrib.admin.views.doc.model_index'), ('^doc/models/(?P<app_label>[^\.]+)\.(?P<model_name>[^/]+)/$', 'django.contrib.admin.views.doc.model_detail'), # ('^doc/templates/$', 'django.views.admin.doc.template_index'), ('^doc/templates/(?P<template>.*)/$', 'django.contrib.admin.views.doc.template_detail'), + # "Add user" -- a special-case view + ('^auth/user/add/$', 'django.contrib.admin.views.auth.user_add_stage'), + # Add/change/delete/history ('^([^/]+)/([^/]+)/$', 'django.contrib.admin.views.main.change_list'), ('^([^/]+)/([^/]+)/add/$', 'django.contrib.admin.views.main.add_stage'), diff --git a/django/contrib/admin/utils.py b/django/contrib/admin/utils.py index 0242b2f32e..9adf09b6a5 100644 --- a/django/contrib/admin/utils.py +++ b/django/contrib/admin/utils.py @@ -3,7 +3,6 @@ import re from email.Parser import HeaderParser from email.Errors import HeaderParseError -from urlparse import urljoin try: import docutils.core import docutils.nodes diff --git a/django/contrib/admin/views/auth.py b/django/contrib/admin/views/auth.py new file mode 100644 index 0000000000..03876bb4ac --- /dev/null +++ b/django/contrib/admin/views/auth.py @@ -0,0 +1,44 @@ +from django.contrib.admin.views.decorators import staff_member_required +from django.contrib.auth.forms import UserCreationForm +from django.contrib.auth.models import User +from django.core.exceptions import PermissionDenied +from django import forms, template +from django.shortcuts import render_to_response +from django.http import HttpResponseRedirect + +def user_add_stage(request): + if not request.user.has_perm('auth.change_user'): + raise PermissionDenied + manipulator = UserCreationForm() + if request.method == 'POST': + new_data = request.POST.copy() + errors = manipulator.get_validation_errors(new_data) + if not errors: + new_user = manipulator.save(new_data) + msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': 'user', 'obj': new_user} + if request.POST.has_key("_addanother"): + request.user.message_set.create(message=msg) + return HttpResponseRedirect(request.path) + else: + request.user.message_set.create(message=msg + ' ' + _("You may edit it again below.")) + return HttpResponseRedirect('../%s/' % new_user.id) + else: + errors = new_data = {} + form = forms.FormWrapper(manipulator, new_data, errors) + return render_to_response('admin/auth/user/add_form.html', { + 'title': _('Add user'), + 'form': form, + 'is_popup': request.REQUEST.has_key('_popup'), + 'add': True, + 'change': False, + 'has_delete_permission': False, + 'has_change_permission': True, + 'has_file_field': False, + 'has_absolute_url': False, + 'auto_populated_fields': (), + 'bound_field_sets': (), + 'first_form_field_id': 'id_username', + 'opts': User._meta, + 'username_help_text': User._meta.get_field('username').help_text, + }, context_instance=template.RequestContext(request)) +user_add_stage = staff_member_required(user_add_stage) diff --git a/django/contrib/admin/views/decorators.py b/django/contrib/admin/views/decorators.py index 250c585220..9dfe651fe6 100644 --- a/django/contrib/admin/views/decorators.py +++ b/django/contrib/admin/views/decorators.py @@ -46,7 +46,7 @@ def staff_member_required(view_func): member, displaying the login page if necessary. """ def _checklogin(request, *args, **kwargs): - if not request.user.is_anonymous() and request.user.is_staff: + if request.user.is_authenticated() and request.user.is_staff: # The user is valid. Continue to the admin page. if request.POST.has_key('post_data'): # User must have re-authenticated through a different window @@ -87,7 +87,7 @@ def staff_member_required(view_func): # The user data is correct; log in the user in and continue. else: - if user.is_staff: + if user.is_active and user.is_staff: login(request, user) # TODO: set last_login with an event. user.last_login = datetime.datetime.now() diff --git a/django/contrib/admin/views/doc.py b/django/contrib/admin/views/doc.py index 5aa143e1fd..435d76f276 100644 --- a/django/contrib/admin/views/doc.py +++ b/django/contrib/admin/views/doc.py @@ -28,7 +28,7 @@ def bookmarklets(request): # Hack! This couples this view to the URL it lives at. admin_root = request.path[:-len('doc/bookmarklets/')] return render_to_response('admin_doc/bookmarklets.html', { - 'admin_url': "%s://%s%s" % (os.environ.get('HTTPS') == 'on' and 'https' or 'http', get_host(request), admin_root), + 'admin_url': "%s://%s%s" % (request.is_secure() and 'https' or 'http', get_host(request), admin_root), }, context_instance=RequestContext(request)) bookmarklets = staff_member_required(bookmarklets) @@ -43,11 +43,11 @@ def template_tag_index(request): for tag_name, tag_func in library.tags.items(): title, body, metadata = utils.parse_docstring(tag_func.__doc__) if title: - title = utils.parse_rst(title, 'tag', 'tag:' + tag_name) + title = utils.parse_rst(title, 'tag', _('tag:') + tag_name) if body: - body = utils.parse_rst(body, 'tag', 'tag:' + tag_name) + body = utils.parse_rst(body, 'tag', _('tag:') + tag_name) for key in metadata: - metadata[key] = utils.parse_rst(metadata[key], 'tag', 'tag:' + tag_name) + metadata[key] = utils.parse_rst(metadata[key], 'tag', _('tag:') + tag_name) if library in template.builtins: tag_library = None else: @@ -74,11 +74,11 @@ def template_filter_index(request): for filter_name, filter_func in library.filters.items(): title, body, metadata = utils.parse_docstring(filter_func.__doc__) if title: - title = utils.parse_rst(title, 'filter', 'filter:' + filter_name) + title = utils.parse_rst(title, 'filter', _('filter:') + filter_name) if body: - body = utils.parse_rst(body, 'filter', 'filter:' + filter_name) + body = utils.parse_rst(body, 'filter', _('filter:') + filter_name) for key in metadata: - metadata[key] = utils.parse_rst(metadata[key], 'filter', 'filter:' + filter_name) + metadata[key] = utils.parse_rst(metadata[key], 'filter', _('filter:') + filter_name) if library in template.builtins: tag_library = None else: @@ -132,11 +132,11 @@ def view_detail(request, view): raise Http404 title, body, metadata = utils.parse_docstring(view_func.__doc__) if title: - title = utils.parse_rst(title, 'view', 'view:' + view) + title = utils.parse_rst(title, 'view', _('view:') + view) if body: - body = utils.parse_rst(body, 'view', 'view:' + view) + body = utils.parse_rst(body, 'view', _('view:') + view) for key in metadata: - metadata[key] = utils.parse_rst(metadata[key], 'model', 'view:' + view) + metadata[key] = utils.parse_rst(metadata[key], 'model', _('view:') + view) return render_to_response('admin_doc/view_detail.html', { 'name': view, 'summary': title, @@ -161,14 +161,14 @@ def model_detail(request, app_label, model_name): try: app_mod = models.get_app(app_label) except ImproperlyConfigured: - raise Http404, "App %r not found" % app_label + raise Http404, _("App %r not found") % app_label model = None for m in models.get_models(app_mod): if m._meta.object_name.lower() == model_name: model = m break if model is None: - raise Http404, "Model %r not found in app %r" % (model_name, app_label) + raise Http404, _("Model %r not found in app %r") % (model_name, app_label) opts = model._meta @@ -180,7 +180,7 @@ def model_detail(request, app_label, model_name): if isinstance(field, models.ForeignKey): data_type = related_object_name = field.rel.to.__name__ app_label = field.rel.to._meta.app_label - verbose = utils.parse_rst(("the related `%s.%s` object" % (app_label, data_type)), 'model', 'model:' + data_type) + verbose = utils.parse_rst((_("the related `%s.%s` object") % (app_label, data_type)), 'model', _('model:') + data_type) else: data_type = get_readable_field_data_type(field) verbose = field.verbose_name @@ -202,7 +202,7 @@ def model_detail(request, app_label, model_name): continue verbose = func.__doc__ if verbose: - verbose = utils.parse_rst(utils.trim_docstring(verbose), 'model', 'model:' + opts.module_name) + verbose = utils.parse_rst(utils.trim_docstring(verbose), 'model', _('model:') + opts.module_name) fields.append({ 'name': func_name, 'data_type': get_return_data_type(func_name), @@ -211,22 +211,22 @@ def model_detail(request, app_label, model_name): # Gather related objects for rel in opts.get_all_related_objects(): - verbose = "related `%s.%s` objects" % (rel.opts.app_label, rel.opts.object_name) + verbose = _("related `%s.%s` objects") % (rel.opts.app_label, rel.opts.object_name) accessor = rel.get_accessor_name() fields.append({ 'name' : "%s.all" % accessor, 'data_type' : 'List', - 'verbose' : utils.parse_rst("all " + verbose , 'model', 'model:' + opts.module_name), + 'verbose' : utils.parse_rst(_("all %s") % verbose , 'model', _('model:') + opts.module_name), }) fields.append({ 'name' : "%s.count" % accessor, 'data_type' : 'Integer', - 'verbose' : utils.parse_rst("number of " + verbose , 'model', 'model:' + opts.module_name), + 'verbose' : utils.parse_rst(_("number of %s") % verbose , 'model', _('model:') + opts.module_name), }) return render_to_response('admin_doc/model_detail.html', { 'name': '%s.%s' % (opts.app_label, opts.object_name), - 'summary': "Fields on %s objects" % opts.object_name, + 'summary': _("Fields on %s objects") % opts.object_name, 'description': model.__doc__, 'fields': fields, }, context_instance=RequestContext(request)) @@ -328,15 +328,19 @@ def extract_views_from_urlpatterns(urlpatterns, base=''): """ views = [] for p in urlpatterns: - if hasattr(p, 'get_callback'): + if hasattr(p, '_get_callback'): try: - views.append((p.get_callback(), base + p.regex.pattern)) + views.append((p._get_callback(), base + p.regex.pattern)) except ViewDoesNotExist: continue elif hasattr(p, '_get_url_patterns'): - views.extend(extract_views_from_urlpatterns(p.url_patterns, base + p.regex.pattern)) + try: + patterns = p.url_patterns + except ImportError: + continue + views.extend(extract_views_from_urlpatterns(patterns, base + p.regex.pattern)) else: - raise TypeError, "%s does not appear to be a urlpattern object" % p + raise TypeError, _("%s does not appear to be a urlpattern object") % p return views named_group_matcher = re.compile(r'\(\?P(<\w+>).+?\)') diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index a7ee08f1c0..324841a669 100644 --- a/django/contrib/admin/views/main.py +++ b/django/contrib/admin/views/main.py @@ -10,9 +10,6 @@ from django.shortcuts import get_object_or_404, render_to_response from django.db import models from django.db.models.query import handle_legacy_orderlist, QuerySet from django.http import Http404, HttpResponse, HttpResponseRedirect -from django.template import loader -from django.utils import dateformat -from django.utils.dates import MONTHS from django.utils.html import escape from django.utils.text import capfirst, get_text_list import operator @@ -266,6 +263,8 @@ def add_stage(request, app_label, model_name, show_delete=False, form_url='', po post_url_continue += "?_popup=1" return HttpResponseRedirect(post_url_continue % pk_value) if request.POST.has_key("_popup"): + if type(pk_value) is str: # Quote if string, so JavaScript doesn't think it's a variable. + pk_value = '"%s"' % pk_value.replace('"', '\\"') return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, %s, "%s");</script>' % \ (pk_value, str(new_object).replace('"', '\\"'))) elif request.POST.has_key("_addanother"): @@ -455,7 +454,7 @@ def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current if related.opts.admin and has_related_objs: p = '%s.%s' % (related.opts.app_label, related.opts.get_delete_permission()) if not user.has_perm(p): - perms_needed.add(rel_opts_name) + perms_needed.add(related.opts.verbose_name) for related in opts.get_all_related_many_to_many_objects(): if related.opts in opts_seen: continue @@ -714,10 +713,22 @@ class ChangeList(object): qs = qs.order_by((self.order_type == 'desc' and '-' or '') + lookup_order_field) # Apply keyword searches. + def construct_search(field_name): + if field_name.startswith('^'): + return "%s__istartswith" % field_name[1:] + elif field_name.startswith('='): + return "%s__iexact" % field_name[1:] + elif field_name.startswith('@'): + return "%s__search" % field_name[1:] + else: + return "%s__icontains" % field_name + if self.lookup_opts.admin.search_fields and self.query: for bit in self.query.split(): - or_queries = [models.Q(**{'%s__icontains' % field_name: bit}) for field_name in self.lookup_opts.admin.search_fields] + or_queries = [models.Q(**{construct_search(field_name): bit}) for field_name in self.lookup_opts.admin.search_fields] other_qs = QuerySet(self.model) + if qs._select_related: + other_qs = other_qs.select_related() other_qs = other_qs.filter(reduce(operator.or_, or_queries)) qs = qs & other_qs diff --git a/django/contrib/admin/views/template.py b/django/contrib/admin/views/template.py index f73b9e4218..1684870842 100644 --- a/django/contrib/admin/views/template.py +++ b/django/contrib/admin/views/template.py @@ -22,7 +22,7 @@ def template_validator(request): new_data = request.POST.copy() errors = manipulator.get_validation_errors(new_data) if not errors: - request.user.add_message('The template is valid.') + request.user.message_set.create(message='The template is valid.') return render_to_response('admin/template_validator.html', { 'title': 'Template validator', 'form': forms.FormWrapper(manipulator, new_data, errors), @@ -32,7 +32,7 @@ template_validator = staff_member_required(template_validator) class TemplateValidator(forms.Manipulator): def __init__(self, settings_modules): self.settings_modules = settings_modules - site_list = Site.objects.get_in_bulk(settings_modules.keys()).values() + site_list = Site.objects.in_bulk(settings_modules.keys()).values() self.fields = ( forms.SelectField('site', is_required=True, choices=[(s.id, s.name) for s in site_list]), forms.LargeTextField('template', is_required=True, rows=25, validator_list=[self.isValidTemplate]), diff --git a/django/contrib/auth/__init__.py b/django/contrib/auth/__init__.py index 2150893022..a0097a01ed 100644 --- a/django/contrib/auth/__init__.py +++ b/django/contrib/auth/__init__.py @@ -38,7 +38,7 @@ def authenticate(**credentials): if user is None: continue # Annotate the user object with the path of the backend. - user.backend = str(backend.__class__) + user.backend = "%s.%s" % (backend.__module__, backend.__class__.__name__) return user def login(request, user): @@ -56,8 +56,14 @@ def logout(request): """ Remove the authenticated user's ID from the request. """ - del request.session[SESSION_KEY] - del request.session[BACKEND_SESSION_KEY] + try: + del request.session[SESSION_KEY] + except KeyError: + pass + try: + del request.session[BACKEND_SESSION_KEY] + except KeyError: + pass def get_user(request): from django.contrib.auth.models import AnonymousUser diff --git a/django/contrib/auth/backends.py b/django/contrib/auth/backends.py index 3b46b65b0a..4b8efcca46 100644 --- a/django/contrib/auth/backends.py +++ b/django/contrib/auth/backends.py @@ -1,4 +1,4 @@ -from django.contrib.auth.models import User, check_password +from django.contrib.auth.models import User class ModelBackend: """ diff --git a/django/contrib/auth/create_superuser.py b/django/contrib/auth/create_superuser.py index f42d30539e..2e93c35b93 100644 --- a/django/contrib/auth/create_superuser.py +++ b/django/contrib/auth/create_superuser.py @@ -46,6 +46,7 @@ def createsuperuser(username=None, email=None, password=None): if not username.isalnum(): sys.stderr.write("Error: That username is invalid. Use only letters, digits and underscores.\n") username = None + continue try: User.objects.get(username=username) except User.DoesNotExist: diff --git a/django/contrib/auth/decorators.py b/django/contrib/auth/decorators.py index bc8ec39115..37e948f8fe 100644 --- a/django/contrib/auth/decorators.py +++ b/django/contrib/auth/decorators.py @@ -13,14 +13,24 @@ def user_passes_test(test_func, login_url=LOGIN_URL): if test_func(request.user): return view_func(request, *args, **kwargs) return HttpResponseRedirect('%s?%s=%s' % (login_url, REDIRECT_FIELD_NAME, quote(request.get_full_path()))) + _checklogin.__doc__ = view_func.__doc__ + _checklogin.__dict__ = view_func.__dict__ return _checklogin return _dec -login_required = user_passes_test(lambda u: not u.is_anonymous()) +login_required = user_passes_test(lambda u: u.is_authenticated()) login_required.__doc__ = ( """ Decorator for views that checks that the user is logged in, redirecting to the log-in page if necessary. """ ) + +def permission_required(perm, login_url=LOGIN_URL): + """ + Decorator for views that checks whether a user has a particular permission + enabled, redirecting to the log-in page if necessary. + """ + return user_passes_test(lambda u: u.has_perm(perm), login_url=login_url) + diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py index ef81268e2a..24c69cb73e 100644 --- a/django/contrib/auth/forms.py +++ b/django/contrib/auth/forms.py @@ -5,6 +5,28 @@ from django.template import Context, loader from django.core import validators from django import forms +class UserCreationForm(forms.Manipulator): + "A form that creates a user, with no privileges, from the given username and password." + def __init__(self): + self.fields = ( + forms.TextField(field_name='username', length=30, maxlength=30, is_required=True, + validator_list=[validators.isAlphaNumeric, self.isValidUsername]), + forms.PasswordField(field_name='password1', length=30, maxlength=60, is_required=True), + forms.PasswordField(field_name='password2', length=30, maxlength=60, is_required=True, + validator_list=[validators.AlwaysMatchesOtherField('password1', _("The two password fields didn't match."))]), + ) + + def isValidUsername(self, field_data, all_data): + try: + User.objects.get(username=field_data) + except User.DoesNotExist: + return + raise validators.ValidationError, _('A user with that username already exists.') + + def save(self, new_data): + "Creates the user." + return User.objects.create_user(new_data['username'], '', new_data['password1']) + class AuthenticationForm(forms.Manipulator): """ Base class for authenticating users. Extend this to get a form that accepts @@ -59,9 +81,9 @@ class PasswordResetForm(forms.Manipulator): try: self.user_cache = User.objects.get(email__iexact=new_data) except User.DoesNotExist: - raise validators.ValidationError, "That e-mail address doesn't have an associated user acount. Are you sure you've registered?" + raise validators.ValidationError, _("That e-mail address doesn't have an associated user account. Are you sure you've registered?") - def save(self, domain_override=None): + def save(self, domain_override=None, email_template_name='registration/password_reset_email.html'): "Calculates a new password randomly and sends it to the user" from django.core.mail import send_mail new_pass = User.objects.make_random_password() @@ -73,7 +95,7 @@ class PasswordResetForm(forms.Manipulator): domain = current_site.domain else: site_name = domain = domain_override - t = loader.get_template('registration/password_reset_email.html') + t = loader.get_template(email_template_name) c = { 'new_password': new_pass, 'email': self.user_cache.email, @@ -91,14 +113,14 @@ class PasswordChangeForm(forms.Manipulator): forms.PasswordField(field_name="old_password", length=30, maxlength=30, is_required=True, validator_list=[self.isValidOldPassword]), forms.PasswordField(field_name="new_password1", length=30, maxlength=30, is_required=True, - validator_list=[validators.AlwaysMatchesOtherField('new_password2', "The two 'new password' fields didn't match.")]), + validator_list=[validators.AlwaysMatchesOtherField('new_password2', _("The two 'new password' fields didn't match."))]), forms.PasswordField(field_name="new_password2", length=30, maxlength=30, is_required=True), ) def isValidOldPassword(self, new_data, all_data): "Validates that the old_password field is correct." if not self.user.check_password(new_data): - raise validators.ValidationError, "Your old password was entered incorrectly. Please enter it again." + raise validators.ValidationError, _("Your old password was entered incorrectly. Please enter it again.") def save(self, new_data): "Saves the new password." diff --git a/django/contrib/auth/handlers/modpython.py b/django/contrib/auth/handlers/modpython.py index e6719794a1..c7d921313d 100644 --- a/django/contrib/auth/handlers/modpython.py +++ b/django/contrib/auth/handlers/modpython.py @@ -22,6 +22,8 @@ def authenhandler(req, **kwargs): os.environ['DJANGO_SETTINGS_MODULE'] = settings_module from django.contrib.auth.models import User + from django import db + db.reset_queries() # check that the username is valid kwargs = {'username': req.user, 'is_active': True} @@ -30,18 +32,21 @@ def authenhandler(req, **kwargs): if superuser_only: kwargs['is_superuser'] = True try: - user = User.objects.get(**kwargs) - except User.DoesNotExist: - return apache.HTTP_UNAUTHORIZED - - # check the password and any permission given - if user.check_password(req.get_basic_auth_pw()): - if permission_name: - if user.has_perm(permission_name): - return apache.OK + try: + user = User.objects.get(**kwargs) + except User.DoesNotExist: + return apache.HTTP_UNAUTHORIZED + + # check the password and any permission given + if user.check_password(req.get_basic_auth_pw()): + if permission_name: + if user.has_perm(permission_name): + return apache.OK + else: + return apache.HTTP_UNAUTHORIZED else: - return apache.HTTP_UNAUTHORIZED + return apache.OK else: - return apache.OK - else: - return apache.HTTP_UNAUTHORIZED + return apache.HTTP_UNAUTHORIZED + finally: + db.connection.close() diff --git a/django/contrib/auth/management.py b/django/contrib/auth/management.py index 1a07417f1d..3f52681747 100644 --- a/django/contrib/auth/management.py +++ b/django/contrib/auth/management.py @@ -16,7 +16,7 @@ def _get_all_permissions(opts): perms.append((_get_permission_codename(action, opts), 'Can %s %s' % (action, opts.verbose_name))) return perms + list(opts.permissions) -def create_permissions(app, created_models): +def create_permissions(app, created_models, verbosity): from django.contrib.contenttypes.models import ContentType from django.contrib.auth.models import Permission app_models = get_models(app) @@ -27,13 +27,13 @@ def create_permissions(app, created_models): for codename, name in _get_all_permissions(klass._meta): p, created = Permission.objects.get_or_create(codename=codename, content_type__pk=ctype.id, defaults={'name': name, 'content_type': ctype}) - if created: + if created and verbosity >= 2: print "Adding permission '%s'" % p -def create_superuser(app, created_models): +def create_superuser(app, created_models, verbosity, **kwargs): from django.contrib.auth.models import User from django.contrib.auth.create_superuser import createsuperuser as do_create - if User in created_models: + if User in created_models and kwargs.get('interactive', True): msg = "\nYou just installed Django's auth system, which means you don't have " \ "any superusers defined.\nWould you like to create one now? (yes/no): " confirm = raw_input(msg) diff --git a/django/contrib/auth/middleware.py b/django/contrib/auth/middleware.py index a6a60780a7..42dc15a366 100644 --- a/django/contrib/auth/middleware.py +++ b/django/contrib/auth/middleware.py @@ -1,12 +1,9 @@ class LazyUser(object): - def __init__(self): - self._user = None - def __get__(self, request, obj_type=None): - if self._user is None: + if not hasattr(request, '_cached_user'): from django.contrib.auth import get_user - self._user = get_user(request) - return self._user + request._cached_user = get_user(request) + return request._cached_user class AuthenticationMiddleware(object): def process_request(self, request): diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py index cca3c62252..58cc07efa9 100644 --- a/django/contrib/auth/models.py +++ b/django/contrib/auth/models.py @@ -1,4 +1,5 @@ from django.core import validators +from django.core.exceptions import ImproperlyConfigured from django.db import backend, connection, models from django.contrib.contenttypes.models import ContentType from django.utils.translation import gettext_lazy as _ @@ -32,7 +33,7 @@ class Permission(models.Model): Permissions are set globally per type of object, not per specific object instance. It is possible to say "Mary may change news stories," but it's not currently possible to say "Mary may change news stories, but only the ones she created herself" or "Mary may only change news stories that have a certain status or publication date." - Three basic permissions -- add, create and delete -- are automatically created for each Django model. + Three basic permissions -- add, change and delete -- are automatically created for each Django model. """ name = models.CharField(_('name'), maxlength=50) content_type = models.ForeignKey(ContentType) @@ -91,9 +92,9 @@ class User(models.Model): last_name = models.CharField(_('last name'), maxlength=30, blank=True) email = models.EmailField(_('e-mail address'), blank=True) password = models.CharField(_('password'), maxlength=128, help_text=_("Use '[algo]$[salt]$[hexdigest]'")) - is_staff = models.BooleanField(_('staff status'), help_text=_("Designates whether the user can log into this admin site.")) + is_staff = models.BooleanField(_('staff status'), default=False, help_text=_("Designates whether the user can log into this admin site.")) is_active = models.BooleanField(_('active'), default=True, help_text=_("Designates whether this user can log into the Django admin. Unselect this instead of deleting accounts.")) - is_superuser = models.BooleanField(_('superuser status'), help_text=_("Designates that this user has all permissions without explicitly assigning them.")) + is_superuser = models.BooleanField(_('superuser status'), default=False, help_text=_("Designates that this user has all permissions without explicitly assigning them.")) last_login = models.DateTimeField(_('last login'), default=models.LazyDate()) date_joined = models.DateTimeField(_('date joined'), default=models.LazyDate()) groups = models.ManyToManyField(Group, verbose_name=_('groups'), blank=True, @@ -126,6 +127,11 @@ class User(models.Model): "Always returns False. This is a way of comparing User objects to anonymous users." return False + def is_authenticated(self): + """Always return True. This is a way to tell if the user has been authenticated in templates. + """ + return True + def get_full_name(self): "Returns the first_name plus the last_name, with a space in between." full_name = '%s %s' % (self.first_name, self.last_name) @@ -210,6 +216,8 @@ class User(models.Model): def has_module_perms(self, app_label): "Returns True if the user has any permissions in the given app label." + if not self.is_active: + return False if self.is_superuser: return True return bool(len([p for p in self.get_all_permissions() if p[:p.index('.')] == app_label])) @@ -262,6 +270,15 @@ class AnonymousUser(object): def __str__(self): return 'AnonymousUser' + def __eq__(self, other): + return isinstance(other, self.__class__) + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return 1 # instances always return the same hash value + def save(self): raise NotImplementedError @@ -293,3 +310,6 @@ class AnonymousUser(object): def is_anonymous(self): return True + + def is_authenticated(self): + return False diff --git a/django/contrib/auth/views.py b/django/contrib/auth/views.py index 97ecd6a3fd..6882755787 100644 --- a/django/contrib/auth/views.py +++ b/django/contrib/auth/views.py @@ -4,7 +4,7 @@ from django import forms from django.shortcuts import render_to_response from django.template import RequestContext from django.contrib.sites.models import Site -from django.http import HttpResponse, HttpResponseRedirect +from django.http import HttpResponseRedirect from django.contrib.auth.decorators import login_required from django.contrib.auth import LOGIN_URL, REDIRECT_FIELD_NAME @@ -34,9 +34,8 @@ def login(request, template_name='registration/login.html'): def logout(request, next_page=None, template_name='registration/logged_out.html'): "Logs out the user and displays 'You are logged out' message." from django.contrib.auth import logout - try: - logout(request) - except KeyError: + logout(request) + if next_page is None: return render_to_response(template_name, {'title': _('Logged out')}, context_instance=RequestContext(request)) else: # Redirect to this page until the session has been cleared. @@ -50,7 +49,8 @@ def redirect_to_login(next, login_url=LOGIN_URL): "Redirects the user to the login page, passing the given 'next' page" return HttpResponseRedirect('%s?%s=%s' % (login_url, REDIRECT_FIELD_NAME, next)) -def password_reset(request, is_admin_site=False, template_name='registration/password_reset_form.html'): +def password_reset(request, is_admin_site=False, template_name='registration/password_reset_form.html', + email_template_name='registration/password_reset_email.html'): new_data, errors = {}, {} form = PasswordResetForm() if request.POST: @@ -58,9 +58,9 @@ def password_reset(request, is_admin_site=False, template_name='registration/pas errors = form.get_validation_errors(new_data) if not errors: if is_admin_site: - form.save(request.META['HTTP_HOST']) + form.save(domain_override=request.META['HTTP_HOST']) else: - form.save() + form.save(email_template_name=email_template_name) return HttpResponseRedirect('%sdone/' % request.path) return render_to_response(template_name, {'form': forms.FormWrapper(form, new_data, errors)}, context_instance=RequestContext(request)) diff --git a/django/contrib/comments/feeds.py b/django/contrib/comments/feeds.py index cad8c881a1..34cf3d9cef 100644 --- a/django/contrib/comments/feeds.py +++ b/django/contrib/comments/feeds.py @@ -1,7 +1,6 @@ from django.conf import settings from django.contrib.comments.models import Comment, FreeComment from django.contrib.syndication.feeds import Feed -from django.core.exceptions import ObjectDoesNotExist from django.contrib.sites.models import Site class LatestFreeCommentsFeed(Feed): @@ -37,6 +36,6 @@ class LatestCommentsFeed(LatestFreeCommentsFeed): qs = qs.filter(is_removed=False) if settings.COMMENTS_BANNED_USERS_GROUP: where = ['user_id NOT IN (SELECT user_id FROM auth_users_group WHERE group_id = %s)'] - params = [COMMENTS_BANNED_USERS_GROUP] + params = [settings.COMMENTS_BANNED_USERS_GROUP] qs = qs.extra(where=where, params=params) return qs diff --git a/django/contrib/comments/models.py b/django/contrib/comments/models.py index 23b0dfbde6..a8aff1cfb3 100644 --- a/django/contrib/comments/models.py +++ b/django/contrib/comments/models.py @@ -51,7 +51,7 @@ class CommentManager(models.Manager): extra_kwargs.setdefault('select', {}) extra_kwargs['select']['_karma_total_good'] = 'SELECT COUNT(*) FROM comments_karmascore, comments_comment WHERE comments_karmascore.comment_id=comments_comment.id AND score=1' extra_kwargs['select']['_karma_total_bad'] = 'SELECT COUNT(*) FROM comments_karmascore, comments_comment WHERE comments_karmascore.comment_id=comments_comment.id AND score=-1' - return self.filter(**kwargs).extra(**extra_kwargs) + return self.filter(**kwargs).extra(**extra_kwargs) def user_is_moderator(self, user): if user.is_superuser: diff --git a/django/contrib/comments/templates/comments/form.html b/django/contrib/comments/templates/comments/form.html index 4a6b5fc320..c5aa7686a3 100644 --- a/django/contrib/comments/templates/comments/form.html +++ b/django/contrib/comments/templates/comments/form.html @@ -2,10 +2,10 @@ {% if display_form %} <form {% if photos_optional or photos_required %}enctype="multipart/form-data" {% endif %}action="/comments/post/" method="post"> -{% if user.is_anonymous %} -<p><label for="id_username">{% trans "Username:" %}</label> <input type="text" name="username" id="id_username" /><br />{% trans "Password:" %} <input type="password" name="password" id="id_password" /> (<a href="/accounts/password_reset/">{% trans "Forgotten your password?" %}</a>)</p> -{% else %} +{% if user.is_authenticated %} <p>{% trans "Username:" %} <strong>{{ user.username }}</strong> (<a href="/accounts/logout/">{% trans "Log out" %}</a>)</p> +{% else %} +<p><label for="id_username">{% trans "Username:" %}</label> <input type="text" name="username" id="id_username" /><br />{% trans "Password:" %} <input type="password" name="password" id="id_password" /> (<a href="/accounts/password_reset/">{% trans "Forgotten your password?" %}</a>)</p> {% endif %} {% if ratings_optional or ratings_required %} diff --git a/django/contrib/comments/templatetags/comments.py b/django/contrib/comments/templatetags/comments.py index a3893fdf61..c3a2fd40d8 100644 --- a/django/contrib/comments/templatetags/comments.py +++ b/django/contrib/comments/templatetags/comments.py @@ -114,7 +114,7 @@ class CommentListNode(template.Node): comment_list = get_list_function(**kwargs).order_by(self.ordering + 'submit_date').select_related() if not self.free: - if context.has_key('user') and not context['user'].is_anonymous(): + if context.has_key('user') and context['user'].is_authenticated(): user_id = context['user'].id context['user_can_moderate_comments'] = Comment.objects.user_is_moderator(context['user']) else: diff --git a/django/contrib/comments/views/comments.py b/django/contrib/comments/views/comments.py index c32a82f4d8..3640da90fe 100644 --- a/django/contrib/comments/views/comments.py +++ b/django/contrib/comments/views/comments.py @@ -5,7 +5,7 @@ from django.http import Http404 from django.core.exceptions import ObjectDoesNotExist from django.shortcuts import render_to_response from django.template import RequestContext -from django.contrib.comments.models import Comment, FreeComment, PHOTOS_REQUIRED, PHOTOS_OPTIONAL, RATINGS_REQUIRED, RATINGS_OPTIONAL, IS_PUBLIC +from django.contrib.comments.models import Comment, FreeComment, RATINGS_REQUIRED, RATINGS_OPTIONAL, IS_PUBLIC from django.contrib.contenttypes.models import ContentType from django.contrib.auth.forms import AuthenticationForm from django.http import HttpResponseRedirect @@ -63,7 +63,7 @@ class PublicCommentManipulator(AuthenticationForm): validator_list=get_validator_list(8), ), ]) - if not user.is_anonymous(): + if user.is_authenticated(): self["username"].is_required = False self["username"].validator_list = [] self["password"].is_required = False @@ -109,7 +109,7 @@ class PublicCommentManipulator(AuthenticationForm): # send the comment to the managers. if self.user_cache.comment_set.count() <= settings.COMMENTS_FIRST_FEW: message = ngettext('This comment was posted by a user who has posted fewer than %(count)s comment:\n\n%(text)s', - 'This comment was posted by a user who has posted fewer than %(count)s comments:\n\n%(text)s') % \ + 'This comment was posted by a user who has posted fewer than %(count)s comments:\n\n%(text)s', settings.COMMENTS_FIRST_FEW) % \ {'count': settings.COMMENTS_FIRST_FEW, 'text': c.get_as_text()} mail_managers("Comment posted by rookie user", message) if settings.COMMENTS_SKETCHY_USERS_GROUP and settings.COMMENTS_SKETCHY_USERS_GROUP in [g.id for g in self.user_cache.get_group_list()]: @@ -217,7 +217,7 @@ def post_comment(request): errors = manipulator.get_validation_errors(new_data) # If user gave correct username/password and wasn't already logged in, log them in # so they don't have to enter a username/password again. - if manipulator.get_user() and new_data.has_key('password') and manipulator.get_user().check_password(new_data['password']): + if manipulator.get_user() and not manipulator.get_user().is_authenticated() and new_data.has_key('password') and manipulator.get_user().check_password(new_data['password']): from django.contrib.auth import login login(request, manipulator.get_user()) if errors or request.POST.has_key('preview'): diff --git a/django/contrib/comments/views/karma.py b/django/contrib/comments/views/karma.py index becb02e128..8c18523feb 100644 --- a/django/contrib/comments/views/karma.py +++ b/django/contrib/comments/views/karma.py @@ -15,7 +15,7 @@ def vote(request, comment_id, vote): rating = {'up': 1, 'down': -1}.get(vote, False) if not rating: raise Http404, "Invalid vote" - if request.user.is_anonymous(): + if not request.user.is_authenticated(): raise Http404, _("Anonymous users cannot vote") try: comment = Comment.objects.get(pk=comment_id) diff --git a/django/contrib/contenttypes/management.py b/django/contrib/contenttypes/management.py index a9174584bc..de3a685477 100644 --- a/django/contrib/contenttypes/management.py +++ b/django/contrib/contenttypes/management.py @@ -5,7 +5,7 @@ Creates content types for all installed models. from django.dispatch import dispatcher from django.db.models import get_models, signals -def create_contenttypes(app, created_models): +def create_contenttypes(app, created_models, verbosity): from django.contrib.contenttypes.models import ContentType app_models = get_models(app) if not app_models: @@ -19,6 +19,7 @@ def create_contenttypes(app, created_models): ct = ContentType(name=str(opts.verbose_name), app_label=opts.app_label, model=opts.object_name.lower()) ct.save() - print "Adding content type '%s | %s'" % (ct.app_label, ct.model) + if verbosity >= 2: + print "Adding content type '%s | %s'" % (ct.app_label, ct.model) dispatcher.connect(create_contenttypes, signal=signals.post_syncdb) diff --git a/django/contrib/flatpages/README.TXT b/django/contrib/flatpages/README.TXT index e46aa1f9bf..d3071377f5 100644 --- a/django/contrib/flatpages/README.TXT +++ b/django/contrib/flatpages/README.TXT @@ -2,7 +2,7 @@ This is an optional add-on app, flatpages. For full documentation, see either of these: - * The file django/docs/flatpages.txt in the Django distribution + * The file docs/flatpages.txt in the Django distribution * http://www.djangoproject.com/documentation/flatpages/ on the Web -Both have identical content.
\ No newline at end of file +Both have identical content. diff --git a/django/contrib/flatpages/views.py b/django/contrib/flatpages/views.py index 1441f6f3a3..f386a52101 100644 --- a/django/contrib/flatpages/views.py +++ b/django/contrib/flatpages/views.py @@ -3,6 +3,7 @@ from django.template import loader, RequestContext from django.shortcuts import get_object_or_404 from django.http import HttpResponse from django.conf import settings +from django.core.xheaders import populate_xheaders DEFAULT_TEMPLATE = 'flatpages/default.html' @@ -22,7 +23,7 @@ def flatpage(request, url): f = get_object_or_404(FlatPage, url__exact=url, sites__id__exact=settings.SITE_ID) # If registration is required for accessing this page, and the user isn't # logged in, redirect to the login page. - if f.registration_required and request.user.is_anonymous(): + if f.registration_required and not request.user.is_authenticated(): from django.contrib.auth.views import redirect_to_login return redirect_to_login(request.path) if f.template_name: @@ -32,4 +33,6 @@ def flatpage(request, url): c = RequestContext(request, { 'flatpage': f, }) - return HttpResponse(t.render(c)) + response = HttpResponse(t.render(c)) + populate_xheaders(request, response, FlatPage, f.id) + return response diff --git a/django/contrib/sessions/middleware.py b/django/contrib/sessions/middleware.py index dde4f1a6c0..2337ad8a61 100644 --- a/django/contrib/sessions/middleware.py +++ b/django/contrib/sessions/middleware.py @@ -88,5 +88,6 @@ class SessionMiddleware(object): new_session = Session.objects.save(session_key, request.session._session, datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE)) response.set_cookie(settings.SESSION_COOKIE_NAME, session_key, - max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN) + max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN, + secure=settings.SESSION_COOKIE_SECURE or None) return response diff --git a/django/contrib/sessions/models.py b/django/contrib/sessions/models.py index 8e2d011e3f..f684cd381e 100644 --- a/django/contrib/sessions/models.py +++ b/django/contrib/sessions/models.py @@ -32,11 +32,21 @@ class SessionManager(models.Manager): return s class Session(models.Model): - """Django provides full support for anonymous sessions. The session framework lets you store and retrieve arbitrary data on a per-site-visitor basis. It stores data on the server side and abstracts the sending and receiving of cookies. Cookies contain a session ID -- not the data itself. + """ + Django provides full support for anonymous sessions. The session + framework lets you store and retrieve arbitrary data on a + per-site-visitor basis. It stores data on the server side and + abstracts the sending and receiving of cookies. Cookies contain a + session ID -- not the data itself. - The Django sessions framework is entirely cookie-based. It does not fall back to putting session IDs in URLs. This is an intentional design decision. Not only does that behavior make URLs ugly, it makes your site vulnerable to session-ID theft via the "Referer" header. + The Django sessions framework is entirely cookie-based. It does + not fall back to putting session IDs in URLs. This is an intentional + design decision. Not only does that behavior make URLs ugly, it makes + your site vulnerable to session-ID theft via the "Referer" header. - For complete documentation on using Sessions in your code, consult the sessions documentation that is shipped with Django (also available on the Django website). + For complete documentation on using Sessions in your code, consult + the sessions documentation that is shipped with Django (also available + on the Django website). """ session_key = models.CharField(_('session key'), maxlength=40, primary_key=True) session_data = models.TextField(_('session data')) diff --git a/django/contrib/sitemaps/__init__.py b/django/contrib/sitemaps/__init__.py new file mode 100644 index 0000000000..2c76e13c22 --- /dev/null +++ b/django/contrib/sitemaps/__init__.py @@ -0,0 +1,90 @@ +from django.core import urlresolvers +import urllib + +PING_URL = "http://www.google.com/webmasters/sitemaps/ping" + +class SitemapNotFound(Exception): + pass + +def ping_google(sitemap_url=None, ping_url=PING_URL): + """ + Alerts Google that the sitemap for the current site has been updated. + If sitemap_url is provided, it should be an absolute path to the sitemap + for this site -- e.g., '/sitemap.xml'. If sitemap_url is not provided, this + function will attempt to deduce it by using urlresolvers.reverse(). + """ + if sitemap_url is None: + try: + # First, try to get the "index" sitemap URL. + sitemap_url = urlresolvers.reverse('django.contrib.sitemaps.views.index') + except urlresolvers.NoReverseMatch: + try: + # Next, try for the "global" sitemap URL. + sitemap_url = urlresolvers.reverse('django.contrib.sitemaps.views.sitemap') + except urlresolvers.NoReverseMatch: + pass + + if sitemap_url is None: + raise SitemapNotFound("You didn't provide a sitemap_url, and the sitemap URL couldn't be auto-detected.") + + from django.contrib.sites.models import Site + current_site = Site.objects.get_current() + url = "%s%s" % (current_site.domain, sitemap) + params = urllib.urlencode({'sitemap':url}) + urllib.urlopen("%s?%s" % (ping_url, params)) + +class Sitemap: + def __get(self, name, obj, default=None): + try: + attr = getattr(self, name) + except AttributeError: + return default + if callable(attr): + return attr(obj) + return attr + + def items(self): + return [] + + def location(self, obj): + return obj.get_absolute_url() + + def get_urls(self): + from django.contrib.sites.models import Site + current_site = Site.objects.get_current() + urls = [] + for item in self.items(): + loc = "http://%s%s" % (current_site.domain, self.__get('location', item)) + url_info = { + 'location': loc, + 'lastmod': self.__get('lastmod', item, None), + 'changefreq': self.__get('changefreq', item, None), + 'priority': self.__get('priority', item, None) + } + urls.append(url_info) + return urls + +class FlatPageSitemap(Sitemap): + def items(self): + from django.contrib.sites.models import Site + current_site = Site.objects.get_current() + return current_site.flatpage_set.all() + +class GenericSitemap(Sitemap): + priority = None + changefreq = None + + def __init__(self, info_dict, priority=None, changefreq=None): + self.queryset = info_dict['queryset'] + self.date_field = info_dict.get('date_field', None) + self.priority = priority + self.changefreq = changefreq + + def items(self): + # Make sure to return a clone; we don't want premature evaluation. + return self.queryset.filter() + + def lastmod(self, item): + if self.date_field is not None: + return getattr(item, self.date_field) + return None diff --git a/django/contrib/sitemaps/templates/sitemap.xml b/django/contrib/sitemaps/templates/sitemap.xml new file mode 100644 index 0000000000..ad24c045d4 --- /dev/null +++ b/django/contrib/sitemaps/templates/sitemap.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<urlset xmlns="http://www.google.com/schemas/sitemap/0.84"> +{% spaceless %} +{% for url in urlset %} + <url> + <loc>{{ url.location|escape }}</loc> + {% if url.lastmod %}<lastmod>{{ url.lastmod|date:"Y-m-d" }}</lastmod>{% endif %} + {% if url.changefreq %}<changefreq>{{ url.changefreq }}</changefreq>{% endif %} + {% if url.priority %}<priority>{{ url.priority }}</priority>{% endif %} + </url> +{% endfor %} +{% endspaceless %} +</urlset> diff --git a/django/contrib/sitemaps/templates/sitemap_index.xml b/django/contrib/sitemaps/templates/sitemap_index.xml new file mode 100644 index 0000000000..c89b192ecc --- /dev/null +++ b/django/contrib/sitemaps/templates/sitemap_index.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<sitemapindex xmlns="http://www.google.com/schemas/sitemap/0.84"> +{% for location in sitemaps %}<sitemap><loc>{{ location|escape }}</loc></sitemap>{% endfor %} +</sitemapindex> diff --git a/django/contrib/sitemaps/views.py b/django/contrib/sitemaps/views.py new file mode 100644 index 0000000000..576e3d0bb8 --- /dev/null +++ b/django/contrib/sitemaps/views.py @@ -0,0 +1,30 @@ +from django.http import HttpResponse, Http404 +from django.template import loader +from django.contrib.sites.models import Site +from django.core import urlresolvers + +def index(request, sitemaps): + current_site = Site.objects.get_current() + sites = [] + protocol = request.is_secure() and 'https' or 'http' + for section in sitemaps.keys(): + sitemap_url = urlresolvers.reverse('django.contrib.sitemaps.views.sitemap', kwargs={'section': section}) + sites.append('%s://%s%s' % (protocol, current_site.domain, sitemap_url)) + xml = loader.render_to_string('sitemap_index.xml', {'sitemaps': sites}) + return HttpResponse(xml, mimetype='application/xml') + +def sitemap(request, sitemaps, section=None): + maps, urls = [], [] + if section is not None: + if not sitemaps.has_key(section): + raise Http404("No sitemap available for section: %r" % section) + maps.append(sitemaps[section]) + else: + maps = sitemaps.values() + for site in maps: + if callable(site): + urls.extend(site().get_urls()) + else: + urls.extend(site.get_urls()) + xml = loader.render_to_string('sitemap.xml', {'urlset': urls}) + return HttpResponse(xml, mimetype='application/xml') diff --git a/django/contrib/sites/management.py b/django/contrib/sites/management.py index 0e1a50227a..6831cab96d 100644 --- a/django/contrib/sites/management.py +++ b/django/contrib/sites/management.py @@ -7,9 +7,10 @@ from django.db.models import signals from django.contrib.sites.models import Site from django.contrib.sites import models as site_app -def create_default_site(app, created_models): +def create_default_site(app, created_models, verbosity): if Site in created_models: - print "Creating example.com Site object" + if verbosity >= 2: + print "Creating example.com Site object" s = Site(domain="example.com", name="example.com") s.save() diff --git a/django/contrib/syndication/feeds.py b/django/contrib/syndication/feeds.py index e648c6c746..119615a0b9 100644 --- a/django/contrib/syndication/feeds.py +++ b/django/contrib/syndication/feeds.py @@ -73,7 +73,7 @@ class Feed(object): link = link, description = self.__get_dynamic_attr('description', obj), language = settings.LANGUAGE_CODE.decode(), - feed_url = add_domain(current_site, self.feed_url), + feed_url = add_domain(current_site, self.__get_dynamic_attr('feed_url', obj)), author_name = self.__get_dynamic_attr('author_name', obj), author_link = self.__get_dynamic_attr('author_link', obj), author_email = self.__get_dynamic_attr('author_email', obj), diff --git a/django/core/cache/backends/db.py b/django/core/cache/backends/db.py index 1b54addded..4a0d44a44e 100644 --- a/django/core/cache/backends/db.py +++ b/django/core/cache/backends/db.py @@ -1,7 +1,7 @@ "Database cache backend." from django.core.cache.backends.base import BaseCache -from django.db import connection, transaction +from django.db import connection, transaction, DatabaseError import base64, time from datetime import datetime try: diff --git a/django/core/cache/backends/locmem.py b/django/core/cache/backends/locmem.py index 5bd6da5857..0e21b80ed8 100644 --- a/django/core/cache/backends/locmem.py +++ b/django/core/cache/backends/locmem.py @@ -3,10 +3,6 @@ from django.core.cache.backends.simple import CacheClass as SimpleCacheClass from django.utils.synch import RWLock import copy, time -try: - import cPickle as pickle -except ImportError: - import pickle class CacheClass(SimpleCacheClass): def __init__(self, host, params): diff --git a/django/core/cache/backends/memcached.py b/django/core/cache/backends/memcached.py index 86ae096d2c..180f95da73 100644 --- a/django/core/cache/backends/memcached.py +++ b/django/core/cache/backends/memcached.py @@ -20,7 +20,7 @@ class CacheClass(BaseCache): return val def set(self, key, value, timeout=0): - self._cache.set(key, value, timeout) + self._cache.set(key, value, timeout or self.default_timeout) def delete(self, key): self._cache.delete(key) diff --git a/django/core/context_processors.py b/django/core/context_processors.py index 2ae9a6d972..f4b288dfc4 100644 --- a/django/core/context_processors.py +++ b/django/core/context_processors.py @@ -51,15 +51,19 @@ def request(request): class PermLookupDict(object): def __init__(self, user, module_name): self.user, self.module_name = user, module_name + def __repr__(self): - return str(self.user.get_permission_list()) + return str(self.user.get_all_permissions()) + def __getitem__(self, perm_name): return self.user.has_perm("%s.%s" % (self.module_name, perm_name)) + def __nonzero__(self): return self.user.has_module_perms(self.module_name) class PermWrapper(object): def __init__(self, user): self.user = user + def __getitem__(self, module_name): return PermLookupDict(self.user, module_name) diff --git a/django/core/handlers/base.py b/django/core/handlers/base.py index c25ff2b14e..213c528952 100644 --- a/django/core/handlers/base.py +++ b/django/core/handlers/base.py @@ -48,7 +48,7 @@ class BaseHandler(object): if hasattr(mw_instance, 'process_exception'): self._exception_middleware.insert(0, mw_instance.process_exception) - def get_response(self, path, request): + def get_response(self, request): "Returns an HttpResponse object for the given HttpRequest" from django.core import exceptions, urlresolvers from django.core.mail import mail_admins @@ -62,7 +62,7 @@ class BaseHandler(object): resolver = urlresolvers.RegexURLResolver(r'^/', settings.ROOT_URLCONF) try: - callback, callback_args, callback_kwargs = resolver.resolve(path) + callback, callback_args, callback_kwargs = resolver.resolve(request.path) # Apply view middleware for middleware_method in self._view_middleware: @@ -89,7 +89,8 @@ class BaseHandler(object): return response except http.Http404, e: if settings.DEBUG: - return self.get_technical_error_response(request, is404=True, exception=e) + from django.views import debug + return debug.technical_404_response(request, e) else: callback, param_dict = resolver.resolve404() return callback(request, **param_dict) @@ -99,40 +100,23 @@ class BaseHandler(object): pass # See http://code.djangoproject.com/ticket/1023 except: # Handle everything else, including SuspiciousOperation, etc. if settings.DEBUG: - return self.get_technical_error_response(request) + from django.views import debug + return debug.technical_500_response(request, *sys.exc_info()) else: # Get the exception info now, in case another exception is thrown later. exc_info = sys.exc_info() receivers = dispatcher.send(signal=signals.got_request_exception) # When DEBUG is False, send an error message to the admins. - subject = 'Error (%s IP): %s' % ((request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS and 'internal' or 'EXTERNAL'), getattr(request, 'path', '')) + subject = 'Error (%s IP): %s' % ((request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS and 'internal' or 'EXTERNAL'), request.path) try: request_repr = repr(request) except: request_repr = "Request repr() unavailable" message = "%s\n\n%s" % (self._get_traceback(exc_info), request_repr) mail_admins(subject, message, fail_silently=True) - return self.get_friendly_error_response(request, resolver) - - def get_friendly_error_response(self, request, resolver): - """ - Returns an HttpResponse that displays a PUBLIC error message for a - fundamental error. - """ - from django.core import urlresolvers - callback, param_dict = resolver.resolve500() - return callback(request, **param_dict) - - def get_technical_error_response(self, request, is404=False, exception=None): - """ - Returns an HttpResponse that displays a TECHNICAL error message for a - fundamental error. - """ - from django.views import debug - if is404: - return debug.technical_404_response(request, exception) - else: - return debug.technical_500_response(request, *sys.exc_info()) + # Return an HttpResponse that displays a friendly error message. + callback, param_dict = resolver.resolve500() + return callback(request, **param_dict) def _get_traceback(self, exc_info=None): "Helper function to return the traceback as a string" diff --git a/django/core/handlers/modpython.py b/django/core/handlers/modpython.py index 5a20ce9f67..5fc41a048b 100644 --- a/django/core/handlers/modpython.py +++ b/django/core/handlers/modpython.py @@ -16,13 +16,34 @@ class ModPythonRequest(http.HttpRequest): self.path = req.uri def __repr__(self): + # Since this is called as part of error handling, we need to be very + # robust against potentially malformed input. + try: + get = pformat(self.GET) + except: + get = '<could not parse>' + try: + post = pformat(self.POST) + except: + post = '<could not parse>' + try: + cookies = pformat(self.COOKIES) + except: + cookies = '<could not parse>' + try: + meta = pformat(self.META) + except: + meta = '<could not parse>' return '<ModPythonRequest\npath:%s,\nGET:%s,\nPOST:%s,\nCOOKIES:%s,\nMETA:%s>' % \ - (self.path, pformat(self.GET), pformat(self.POST), pformat(self.COOKIES), - pformat(self.META)) + (self.path, get, post, cookies, meta) def get_full_path(self): return '%s%s' % (self.path, self._req.args and ('?' + self._req.args) or '') + def is_secure(self): + # Note: modpython 3.2.10+ has req.is_https(), but we need to support previous versions + return self._req.subprocess_env.has_key('HTTPS') and self._req.subprocess_env['HTTPS'] == 'on' + def _load_post_and_files(self): "Populates self._post and self._files" if self._req.headers_in.has_key('content-type') and self._req.headers_in['content-type'].startswith('multipart'): @@ -119,10 +140,6 @@ class ModPythonHandler(BaseHandler): # that use settings now can work from django.conf import settings - if settings.ENABLE_PSYCO: - import psyco - psyco.profile() - # if we need to set up middleware, now that settings works we can do it now. if self._request_middleware is None: self.load_middleware() @@ -130,7 +147,7 @@ class ModPythonHandler(BaseHandler): dispatcher.send(signal=signals.request_started) try: request = ModPythonRequest(req) - response = self.get_response(req.uri, request) + response = self.get_response(request) # Apply response middleware for middleware_method in self._response_middleware: @@ -140,21 +157,20 @@ class ModPythonHandler(BaseHandler): dispatcher.send(signal=signals.request_finished) # Convert our custom HttpResponse object back into the mod_python req. - populate_apache_request(response, req) - return 0 # mod_python.apache.OK + req.content_type = response['Content-Type'] + for key, value in response.headers.items(): + if key != 'Content-Type': + req.headers_out[key] = value + for c in response.cookies.values(): + req.headers_out.add('Set-Cookie', c.output(header='')) + req.status = response.status_code + try: + for chunk in response: + req.write(chunk) + finally: + response.close() -def populate_apache_request(http_response, mod_python_req): - "Populates the mod_python request object with an HttpResponse" - from django.conf import settings - mod_python_req.content_type = http_response['Content-Type'] - for key, value in http_response.headers.items(): - if key != 'Content-Type': - mod_python_req.headers_out[key] = value - for c in http_response.cookies.values(): - mod_python_req.headers_out.add('Set-Cookie', c.output(header='')) - mod_python_req.status = http_response.status_code - for chunk in http_response.iterator: - mod_python_req.write(chunk) + return 0 # mod_python.apache.OK def handler(req): # mod_python hooks into this function. diff --git a/django/core/handlers/wsgi.py b/django/core/handlers/wsgi.py index 00a9a2ca53..2998bd31f6 100644 --- a/django/core/handlers/wsgi.py +++ b/django/core/handlers/wsgi.py @@ -4,6 +4,11 @@ from django.dispatch import dispatcher from django.utils import datastructures from django import http from pprint import pformat +from shutil import copyfileobj +try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO # See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html STATUS_CODE_TEXT = { @@ -50,6 +55,21 @@ STATUS_CODE_TEXT = { 505: 'HTTP VERSION NOT SUPPORTED', } +def safe_copyfileobj(fsrc, fdst, length=16*1024, size=0): + """ + A version of shutil.copyfileobj that will not read more than 'size' bytes. + This makes it safe from clients sending more than CONTENT_LENGTH bytes of + data in the body. + """ + if not size: + return copyfileobj(fsrc, fdst, length) + while size > 0: + buf = fsrc.read(min(length, size)) + if not buf: + break + fdst.write(buf) + size -= len(buf) + class WSGIRequest(http.HttpRequest): def __init__(self, environ): self.environ = environ @@ -58,14 +78,33 @@ class WSGIRequest(http.HttpRequest): self.method = environ['REQUEST_METHOD'].upper() def __repr__(self): - from pprint import pformat - return '<DjangoRequest\nGET:%s,\nPOST:%s,\nCOOKIES:%s,\nMETA:%s>' % \ - (pformat(self.GET), pformat(self.POST), pformat(self.COOKIES), - pformat(self.META)) + # Since this is called as part of error handling, we need to be very + # robust against potentially malformed input. + try: + get = pformat(self.GET) + except: + get = '<could not parse>' + try: + post = pformat(self.POST) + except: + post = '<could not parse>' + try: + cookies = pformat(self.COOKIES) + except: + cookies = '<could not parse>' + try: + meta = pformat(self.META) + except: + meta = '<could not parse>' + return '<WSGIRequest\nGET:%s,\nPOST:%s,\nCOOKIES:%s,\nMETA:%s>' % \ + (get, post, cookies, meta) def get_full_path(self): return '%s%s' % (self.path, self.environ.get('QUERY_STRING', '') and ('?' + self.environ.get('QUERY_STRING', '')) or '') + def is_secure(self): + return self.environ.has_key('HTTPS') and self.environ['HTTPS'] == 'on' + def _load_post_and_files(self): # Populates self._post and self._files if self.method == 'POST': @@ -117,7 +156,11 @@ class WSGIRequest(http.HttpRequest): try: return self._raw_post_data except AttributeError: - self._raw_post_data = self.environ['wsgi.input'].read(int(self.environ["CONTENT_LENGTH"])) + buf = StringIO() + content_length = int(self.environ['CONTENT_LENGTH']) + safe_copyfileobj(self.environ['wsgi.input'], buf, size=content_length) + self._raw_post_data = buf.getvalue() + buf.close() return self._raw_post_data GET = property(_get_get, _set_get) @@ -131,10 +174,6 @@ class WSGIHandler(BaseHandler): def __call__(self, environ, start_response): from django.conf import settings - if settings.ENABLE_PSYCO: - import psyco - psyco.profile() - # Set up middleware if needed. We couldn't do this earlier, because # settings weren't available. if self._request_middleware is None: @@ -143,7 +182,7 @@ class WSGIHandler(BaseHandler): dispatcher.send(signal=signals.request_started) try: request = WSGIRequest(environ) - response = self.get_response(request.path, request) + response = self.get_response(request) # Apply response middleware for middleware_method in self._response_middleware: @@ -161,4 +200,4 @@ class WSGIHandler(BaseHandler): for c in response.cookies.values(): response_headers.append(('Set-Cookie', c.output(header=''))) start_response(status, response_headers) - return response.iterator + return response diff --git a/django/core/management.py b/django/core/management.py index aa1a8dcf7d..437a80d5af 100644 --- a/django/core/management.py +++ b/django/core/management.py @@ -103,7 +103,6 @@ def get_sql_create(app): known_models = set([model for model in _get_installed_models(_get_table_list()) if model not in app_models]) pending_references = {} - for model in app_models: output, references = _get_sql_model_create(model, known_models) final_output.extend(output) @@ -147,7 +146,7 @@ def _get_sql_model_create(model, known_models=set()): table_output = [] pending_references = {} for f in opts.fields: - if isinstance(f, models.ForeignKey): + if isinstance(f, (models.ForeignKey, models.OneToOneField)): rel_field = f.rel.get_related_field() data_type = get_rel_data_type(rel_field) else: @@ -347,7 +346,7 @@ def get_sql_initial_data_for_model(model): os.path.join(app_dir, "%s.sql" % opts.object_name.lower())] for sql_file in sql_files: if os.path.exists(sql_file): - fp = open(sql_file) + fp = open(sql_file, 'U') for statement in statements.split(fp.read()): if statement.strip(): output.append(statement + ";") @@ -398,21 +397,11 @@ get_sql_sequence_reset.help_doc = "Prints the SQL statements for resetting Postg get_sql_sequence_reset.args = APP_ARGS def get_sql_indexes(app): - "Returns a list of the CREATE INDEX SQL statements for the given app." - from django.db import backend, models + "Returns a list of the CREATE INDEX SQL statements for all models in the given app." + from django.db import models output = [] - for model in models.get_models(app): - for f in model._meta.fields: - if f.db_index: - unique = f.unique and 'UNIQUE ' or '' - output.append( - style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \ - style.SQL_TABLE('%s_%s' % (model._meta.db_table, f.column)) + ' ' + \ - style.SQL_KEYWORD('ON') + ' ' + \ - style.SQL_TABLE(backend.quote_name(model._meta.db_table)) + ' ' + \ - "(%s);" % style.SQL_FIELD(backend.quote_name(f.column)) - ) + output.extend(get_sql_indexes_for_model(model)) return output get_sql_indexes.help_doc = "Prints the CREATE INDEX SQL statements for the given model module name(s)." get_sql_indexes.args = APP_ARGS @@ -639,13 +628,30 @@ def get_sql_evolution_check_for_dead_fields(klass, new_table_name): output.append( '-- end warning' ) return output +def get_sql_indexes_for_model(model): + "Returns the CREATE INDEX SQL statements for a single model" + from django.db import backend + output = [] + + for f in model._meta.fields: + if f.db_index: + unique = f.unique and 'UNIQUE ' or '' + output.append( + style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \ + style.SQL_TABLE('%s_%s' % (model._meta.db_table, f.column)) + ' ' + \ + style.SQL_KEYWORD('ON') + ' ' + \ + style.SQL_TABLE(backend.quote_name(model._meta.db_table)) + ' ' + \ + "(%s);" % style.SQL_FIELD(backend.quote_name(f.column)) + ) + return output + def get_sql_all(app): "Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module." return get_sql_create(app) + get_sql_initial_data(app) + get_sql_indexes(app) get_sql_all.help_doc = "Prints the CREATE TABLE, initial-data and CREATE INDEX SQL statements for the given model module name(s)." get_sql_all.args = APP_ARGS -def syncdb(): +def syncdb(verbosity=1, interactive=True): "Creates the database tables for all apps in INSTALLED_APPS whose tables haven't already been created." from django.db import connection, transaction, models, get_creation_module from django.db.models import signals @@ -679,21 +685,22 @@ def syncdb(): pending_references = {} for app in models.get_apps(): + app_name = app.__name__.split('.')[-2] model_list = models.get_models(app) for model in model_list: # Create the model's database table, if it doesn't already exist. + if verbosity >= 2: + print "Processing %s.%s model" % (app_name, model._meta.object_name) if model._meta.db_table in table_list or model._meta.aka in table_list or len(set(model._meta.aka) & set(table_list))>0: continue sql, references = _get_sql_model_create(model, seen_models) seen_models.add(model) created_models.add(model) for refto, refs in references.items(): - try: - pending_references[refto].extend(refs) - except KeyError: - pending_references[refto] = refs + pending_references.setdefault(refto, []).extend(refs) sql.extend(_get_sql_for_pending_references(model, pending_references)) - print "Creating table %s" % model._meta.db_table + if verbosity >= 1: + print "Creating table %s" % model._meta.db_table for statement in sql: cursor.execute(statement) table_list.append(model._meta.db_table) @@ -702,7 +709,8 @@ def syncdb(): if model in created_models: sql = _get_many_to_many_sql_for_model(model) if sql: - print "Creating many-to-many tables for %s model" % model.__name__ + if verbosity >= 2: + print "Creating many-to-many tables for %s.%s model" % (app_name, model._meta.object_name) for statement in sql: cursor.execute(statement) @@ -715,8 +723,12 @@ def syncdb(): # Send the post_syncdb signal, so individual apps can do whatever they need # to do at this point. for app in models.get_apps(): + app_name = app.__name__.split('.')[-2] + if verbosity >= 2: + print "Running post-sync handlers for application", app_name dispatcher.send(signal=signals.post_syncdb, sender=app, - app=app, created_models=created_models) + app=app, created_models=created_models, + verbosity=verbosity, interactive=interactive) # Install initial data for the app (but only if this is a model we've # just created) @@ -724,13 +736,33 @@ def syncdb(): if model in created_models: initial_sql = get_sql_initial_data_for_model(model) if initial_sql: - print "Installing initial data for %s model" % model._meta.object_name + if verbosity >= 1: + print "Installing initial data for %s.%s model" % (app_name, model._meta.object_name) try: for sql in initial_sql: cursor.execute(sql) except Exception, e: - sys.stderr.write("Failed to install initial SQL data for %s model: %s" % \ - (model._meta.object_name, e)) + sys.stderr.write("Failed to install initial SQL data for %s.%s model: %s" % \ + (app_name, model._meta.object_name, e)) + transaction.rollback_unless_managed() + else: + transaction.commit_unless_managed() + + # Install SQL indicies for all newly created models + for app in models.get_apps(): + app_name = app.__name__.split('.')[-2] + for model in models.get_models(app): + if model in created_models: + index_sql = get_sql_indexes_for_model(model) + if index_sql: + if verbosity >= 1: + print "Installing index for %s.%s model" % (app_name, model._meta.object_name) + try: + for sql in index_sql: + cursor.execute(sql) + except Exception, e: + sys.stderr.write("Failed to install index for %s.%s model: %s" % \ + (app_name, model._meta.object_name, e)) transaction.rollback_unless_managed() else: transaction.commit_unless_managed() @@ -774,7 +806,7 @@ def diffsettings(): # Inspired by Postfix's "postconf -n". from django.conf import settings, global_settings - user_settings = _module_to_dict(settings) + user_settings = _module_to_dict(settings._target) default_settings = _module_to_dict(global_settings) output = [] @@ -818,9 +850,10 @@ The full error: """ % (app_name, app_name)) + style.ERROR_OUTPUT(str(e)) + '\n') install.help_doc = "Executes ``sqlall`` for the given app(s) in the current database." install.args = APP_ARGS -def reset(app): +def reset(app, interactive=True): "Executes the equivalent of 'get_sql_reset' in the current database." from django.db import connection, transaction + from django.conf import settings app_name = app.__name__.split('.')[-2] disable_termcolors() @@ -829,21 +862,26 @@ def reset(app): _check_for_validation_errors(app) sql_list = get_sql_reset(app) - confirm = raw_input(""" + if interactive: + confirm = raw_input(""" You have requested a database reset. -This will IRREVERSIBLY DESTROY any data in your database. +This will IRREVERSIBLY DESTROY any data for +the "%s" application in the database "%s". Are you sure you want to do this? -Type 'yes' to continue, or 'no' to cancel: """) +Type 'yes' to continue, or 'no' to cancel: """ % (app_name, settings.DATABASE_NAME)) + else: + confirm = 'yes' + if confirm == 'yes': try: cursor = connection.cursor() for sql in sql_list: cursor.execute(sql) except Exception, e: - sys.stderr.write(style.ERROR("""Error: %s couldn't be installed. Possible reasons: + sys.stderr.write(style.ERROR("""Error: %s couldn't be reset. Possible reasons: * The database isn't running or isn't configured correctly. - * At least one of the database tables already exists. + * At least one of the database tables doesn't exist. * The SQL was invalid. Hint: Look at the output of 'django-admin.py sqlreset %s'. That's the SQL this command wasn't able to run. The full error: """ % (app_name, app_name)) + style.ERROR_OUTPUT(str(e)) + '\n') @@ -1042,7 +1080,8 @@ def get_validation_errors(outfile, app=None): validates all models of all installed apps. Writes errors, if any, to outfile. Returns number of errors. """ - from django.db import models + from django.conf import settings + from django.db import models, connection from django.db.models.loading import get_app_errors from django.db.models.fields.related import RelatedObject @@ -1084,6 +1123,12 @@ def get_validation_errors(outfile, app=None): if f.db_index not in (None, True, False): e.add(opts, '"%s": "db_index" should be either None, True or False.' % f.name) + # Check that maxlength <= 255 if using older MySQL versions. + if settings.DATABASE_ENGINE == 'mysql': + db_version = connection.get_server_version() + if db_version < (5, 0, 3) and isinstance(f, (models.CharField, models.CommaSeparatedIntegerField, models.SlugField)) and f.maxlength > 255: + e.add(opts, '"%s": %s cannot have a "maxlength" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %s).' % (f.name, f.__class__.__name__, '.'.join([str(n) for n in db_version[:3]]))) + # Check to see if the related field will clash with any # existing fields, m2m fields, m2m related objects or related objects if f.rel: @@ -1125,27 +1170,32 @@ def get_validation_errors(outfile, app=None): rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name() rel_query_name = f.related_query_name() - for r in rel_opts.fields: - if r.name == rel_name: - e.add(opts, "Accessor for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) - if r.name == rel_query_name: - e.add(opts, "Reverse query name for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) - for r in rel_opts.many_to_many: - if r.name == rel_name: - e.add(opts, "Accessor for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) - if r.name == rel_query_name: - e.add(opts, "Reverse query name for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) - for r in rel_opts.get_all_related_many_to_many_objects(): - if r.field is not f: + # If rel_name is none, there is no reverse accessor. + # (This only occurs for symmetrical m2m relations to self). + # If this is the case, there are no clashes to check for this field, as + # there are no reverse descriptors for this field. + if rel_name is not None: + for r in rel_opts.fields: + if r.name == rel_name: + e.add(opts, "Accessor for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) + if r.name == rel_query_name: + e.add(opts, "Reverse query name for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) + for r in rel_opts.many_to_many: + if r.name == rel_name: + e.add(opts, "Accessor for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) + if r.name == rel_query_name: + e.add(opts, "Reverse query name for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) + for r in rel_opts.get_all_related_many_to_many_objects(): + if r.field is not f: + if r.get_accessor_name() == rel_name: + e.add(opts, "Accessor for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) + if r.get_accessor_name() == rel_query_name: + e.add(opts, "Reverse query name for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) + for r in rel_opts.get_all_related_objects(): if r.get_accessor_name() == rel_name: - e.add(opts, "Accessor for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) + e.add(opts, "Accessor for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) if r.get_accessor_name() == rel_query_name: - e.add(opts, "Reverse query name for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) - for r in rel_opts.get_all_related_objects(): - if r.get_accessor_name() == rel_name: - e.add(opts, "Accessor for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) - if r.get_accessor_name() == rel_query_name: - e.add(opts, "Reverse query name for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) + e.add(opts, "Reverse query name for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) # Check admin attribute. if opts.admin is not None: @@ -1175,7 +1225,8 @@ def get_validation_errors(outfile, app=None): try: f = opts.get_field(fn) except models.FieldDoesNotExist: - e.add(opts, '"admin.list_filter" refers to %r, which isn\'t a field.' % fn) + if not hasattr(cls, fn): + e.add(opts, '"admin.list_display_links" refers to %r, which isn\'t an attribute, method or property.' % fn) if fn not in opts.admin.list_display: e.add(opts, '"admin.list_display_links" refers to %r, which is not defined in "admin.list_display".' % fn) # list_filter @@ -1233,10 +1284,12 @@ def get_validation_errors(outfile, app=None): return len(e.errors) -def validate(outfile=sys.stdout): +def validate(outfile=sys.stdout, silent_success=False): "Validates all installed models." try: num_errors = get_validation_errors(outfile) + if silent_success and num_errors == 0: + return outfile.write('%s error%s found.\n' % (num_errors, num_errors != 1 and 's' or '')) except ImproperlyConfigured: outfile.write("Skipping validation because things aren't configured properly.") @@ -1259,7 +1312,7 @@ def _check_for_validation_errors(app=None): sys.stderr.write(s.read()) sys.exit(1) -def runserver(addr, port, use_reloader=True): +def runserver(addr, port, use_reloader=True, admin_media_dir=''): "Starts a lightweight Web server for development." from django.core.servers.basehttp import run, AdminMediaHandler, WSGIServerException from django.core.handlers.wsgi import WSGIHandler @@ -1277,7 +1330,10 @@ def runserver(addr, port, use_reloader=True): print "Development server is running at http://%s:%s/" % (addr, port) print "Quit the server with %s." % quit_command try: - run(addr, int(port), AdminMediaHandler(WSGIHandler())) + import django + path = admin_media_dir or django.__path__[0] + '/contrib/admin/media' + handler = AdminMediaHandler(WSGIHandler(), path) + run(addr, int(port), handler) except WSGIServerException, e: # Use helpful error messages instead of ugly tracebacks. ERRORS = { @@ -1298,7 +1354,7 @@ def runserver(addr, port, use_reloader=True): autoreload.main(inner_run) else: inner_run() -runserver.args = '[--noreload] [optional port number, or ipaddr:port]' +runserver.args = '[--noreload] [--adminmedia=ADMIN_MEDIA_PATH] [optional port number, or ipaddr:port]' def createcachetable(tablename): "Creates the table needed to use the SQL cache backend" @@ -1380,6 +1436,29 @@ def runfcgi(args): runfastcgi(args) runfcgi.args = '[various KEY=val options, use `runfcgi help` for help]' +def test(app_labels, verbosity=1): + "Runs the test suite for the specified applications" + from django.conf import settings + from django.db.models import get_app, get_apps + + if len(app_labels) == 0: + app_list = get_apps() + else: + app_list = [get_app(app_label) for app_label in app_labels] + + test_path = settings.TEST_RUNNER.split('.') + # Allow for Python 2.5 relative paths + if len(test_path) > 1: + test_module_name = '.'.join(test_path[:-1]) + else: + test_module_name = '.' + test_module = __import__(test_module_name, [],[],test_path[-1]) + test_runner = getattr(test_module, test_path[-1]) + + test_runner(app_list, verbosity) +test.help_doc = 'Runs the test suite for the specified applications, or the entire site if no apps are specified' +test.args = '[--verbosity] ' + APP_ARGS + # Utilities for command-line script DEFAULT_ACTION_MAPPING = { @@ -1405,6 +1484,7 @@ DEFAULT_ACTION_MAPPING = { 'startproject': startproject, 'syncdb': syncdb, 'validate': validate, + 'test':test, } NO_SQL_TRANSACTION = ( @@ -1455,8 +1535,15 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None): help='Lets you manually add a directory the Python path, e.g. "/home/djangoprojects/myproject".') parser.add_option('--plain', action='store_true', dest='plain', help='Tells Django to use plain Python, not IPython, for "shell" command.') + parser.add_option('--noinput', action='store_false', dest='interactive', default=True, + help='Tells Django to NOT prompt the user for input of any kind.') parser.add_option('--noreload', action='store_false', dest='use_reloader', default=True, help='Tells Django to NOT use the auto-reloader when running the development server.') + parser.add_option('--verbosity', action='store', dest='verbosity', default='1', + type='choice', choices=['0', '1', '2'], + help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'), + parser.add_option('--adminmedia', dest='admin_media_path', default='', help='Specifies the directory from which to serve admin media for runserver.'), + options, args = parser.parse_args(argv[1:]) # Take care of options. @@ -1483,8 +1570,10 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None): if action == 'shell': action_mapping[action](options.plain is True) - elif action in ('syncdb', 'validate', 'diffsettings', 'dbshell'): + elif action in ('validate', 'diffsettings', 'dbshell'): action_mapping[action]() + elif action == 'syncdb': + action_mapping[action](int(options.verbosity), options.interactive) elif action == 'inspectdb': try: for line in action_mapping[action](): @@ -1497,6 +1586,11 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None): action_mapping[action](args[1]) except IndexError: parser.print_usage_and_exit() + elif action == 'test': + try: + action_mapping[action](args[1:], int(options.verbosity)) + except IndexError: + parser.print_usage_and_exit() elif action in ('startapp', 'startproject'): try: name = args[1] @@ -1512,11 +1606,12 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None): addr, port = args[1].split(':') except ValueError: addr, port = '', args[1] - action_mapping[action](addr, port, options.use_reloader) + action_mapping[action](addr, port, options.use_reloader, options.admin_media_path) elif action == 'runfcgi': action_mapping[action](args[1:]) else: from django.db import models + validate(silent_success=True) try: mod_list = [models.get_app(app_label) for app_label in args[1:]] except ImportError, e: @@ -1527,7 +1622,10 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None): if action not in NO_SQL_TRANSACTION: print style.SQL_KEYWORD("BEGIN;") for mod in mod_list: - output = action_mapping[action](mod) + if action == 'reset': + output = action_mapping[action](mod, options.interactive) + else: + output = action_mapping[action](mod) if output: print '\n'.join(output) if action not in NO_SQL_TRANSACTION: diff --git a/django/core/paginator.py b/django/core/paginator.py index 195ad1009e..026fe0a675 100644 --- a/django/core/paginator.py +++ b/django/core/paginator.py @@ -1,4 +1,3 @@ -from copy import copy from math import ceil class InvalidPage(Exception): diff --git a/django/core/serializers/base.py b/django/core/serializers/base.py index e939c0c6e7..fb293c7c13 100644 --- a/django/core/serializers/base.py +++ b/django/core/serializers/base.py @@ -11,7 +11,7 @@ from django.db import models class SerializationError(Exception): """Something bad happened during serialization.""" pass - + class DeserializationError(Exception): """Something bad happened during deserialization.""" pass @@ -20,15 +20,15 @@ class Serializer(object): """ Abstract serializer base class. """ - + def serialize(self, queryset, **options): """ Serialize a queryset. """ self.options = options - + self.stream = options.get("stream", StringIO()) - + self.start_serialization() for obj in queryset: self.start_object(obj) @@ -44,61 +44,65 @@ class Serializer(object): self.end_object(obj) self.end_serialization() return self.getvalue() - + def get_string_value(self, obj, field): """ Convert a field's value to a string. """ if isinstance(field, models.DateTimeField): - value = getattr(obj, field.name).strftime("%Y-%m-%d %H:%M:%S") + value = getattr(obj, field.name) + if value is None: + value = '' + else: + value = value.strftime("%Y-%m-%d %H:%M:%S") elif isinstance(field, models.FileField): value = getattr(obj, "get_%s_url" % field.name, lambda: None)() else: value = field.flatten_data(follow=None, obj=obj).get(field.name, "") return str(value) - + def start_serialization(self): """ Called when serializing of the queryset starts. """ raise NotImplementedError - + def end_serialization(self): """ Called when serializing of the queryset ends. """ pass - + def start_object(self, obj): """ Called when serializing of an object starts. """ raise NotImplementedError - + def end_object(self, obj): """ Called when serializing of an object ends. """ pass - + def handle_field(self, obj, field): """ Called to handle each individual (non-relational) field on an object. """ raise NotImplementedError - + def handle_fk_field(self, obj, field): """ Called to handle a ForeignKey field. """ raise NotImplementedError - + def handle_m2m_field(self, obj, field): """ Called to handle a ManyToManyField. """ raise NotImplementedError - + def getvalue(self): """ Return the fully serialized queryset. @@ -109,7 +113,7 @@ class Deserializer(object): """ Abstract base deserializer class. """ - + def __init__(self, stream_or_string, **options): """ Init this serializer given a stream or a string @@ -123,39 +127,39 @@ class Deserializer(object): # deserialization starts (otherwise subclass calls to get_model() # and friends might fail...) models.get_apps() - + def __iter__(self): return self - + def next(self): """Iteration iterface -- return the next item in the stream""" raise NotImplementedError - + class DeserializedObject(object): """ A deserialzed model. - + Basically a container for holding the pre-saved deserialized data along with the many-to-many data saved with the object. - + Call ``save()`` to save the object (with the many-to-many data) to the database; call ``save(save_m2m=False)`` to save just the object fields (and not touch the many-to-many stuff.) """ - + def __init__(self, obj, m2m_data=None): self.object = obj self.m2m_data = m2m_data - + def __repr__(self): return "<DeserializedObject: %s>" % str(self.object) - + def save(self, save_m2m=True): self.object.save() if self.m2m_data and save_m2m: for accessor_name, object_list in self.m2m_data.items(): setattr(self.object, accessor_name, object_list) - - # prevent a second (possibly accidental) call to save() from saving + + # prevent a second (possibly accidental) call to save() from saving # the m2m data twice. self.m2m_data = None diff --git a/django/core/serializers/json.py b/django/core/serializers/json.py index dd6513db57..15770f160e 100644 --- a/django/core/serializers/json.py +++ b/django/core/serializers/json.py @@ -16,7 +16,7 @@ class Serializer(PythonSerializer): Convert a queryset to JSON. """ def end_serialization(self): - simplejson.dump(self.objects, self.stream, cls=DateTimeAwareJSONEncoder) + simplejson.dump(self.objects, self.stream, cls=DateTimeAwareJSONEncoder, **self.options) def getvalue(self): return self.stream.getvalue() @@ -41,11 +41,11 @@ class DateTimeAwareJSONEncoder(simplejson.JSONEncoder): TIME_FORMAT = "%H:%M:%S" def default(self, o): - if isinstance(o, datetime.date): + if isinstance(o, datetime.datetime): + return o.strftime("%s %s" % (self.DATE_FORMAT, self.TIME_FORMAT)) + elif isinstance(o, datetime.date): return o.strftime(self.DATE_FORMAT) elif isinstance(o, datetime.time): return o.strftime(self.TIME_FORMAT) - elif isinstance(o, datetime.datetime): - return o.strftime("%s %s" % (self.DATE_FORMAT, self.TIME_FORMAT)) else: - return super(self, DateTimeAwareJSONEncoder).default(o)
\ No newline at end of file + return super(DateTimeAwareJSONEncoder, self).default(o) diff --git a/django/core/serializers/python.py b/django/core/serializers/python.py index 7989e1d469..4181bc7f2b 100644 --- a/django/core/serializers/python.py +++ b/django/core/serializers/python.py @@ -79,7 +79,7 @@ def Deserializer(object_list, **options): elif field.rel and isinstance(field.rel, models.ManyToOneRel): try: data[field.name] = field.rel.to._default_manager.get(pk=field_value) - except RelatedModel.DoesNotExist: + except field.rel.to.DoesNotExist: data[field.name] = None # Handle all other fields diff --git a/django/core/servers/basehttp.py b/django/core/servers/basehttp.py index 259a931594..a16b8b675a 100644 --- a/django/core/servers/basehttp.py +++ b/django/core/servers/basehttp.py @@ -8,7 +8,7 @@ been reviewed for security issues. Don't use it for production use. """ from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer -from types import ListType, StringType, TupleType +from types import ListType, StringType import os, re, sys, time, urllib __version__ = "0.1" @@ -547,10 +547,6 @@ class WSGIRequestHandler(BaseHTTPRequestHandler): env['PATH_INFO'] = urllib.unquote(path) env['QUERY_STRING'] = query - - host = self.address_string() - if host != self.client_address[0]: - env['REMOTE_HOST'] = host env['REMOTE_ADDR'] = self.client_address[0] if self.headers.typeheader is None: @@ -598,11 +594,14 @@ class AdminMediaHandler(object): Use this ONLY LOCALLY, for development! This hasn't been tested for security and is not super efficient. """ - def __init__(self, application): + def __init__(self, application, media_dir=None): from django.conf import settings - import django self.application = application - self.media_dir = django.__path__[0] + '/contrib/admin/media' + if not media_dir: + import django + self.media_dir = django.__path__[0] + '/contrib/admin/media' + else: + self.media_dir = media_dir self.media_url = settings.ADMIN_MEDIA_PREFIX def __call__(self, environ, start_response): diff --git a/django/core/servers/fastcgi.py b/django/core/servers/fastcgi.py index dedc1f8ba1..c6507fe173 100644 --- a/django/core/servers/fastcgi.py +++ b/django/core/servers/fastcgi.py @@ -74,8 +74,9 @@ def fastcgi_help(message=None): print message return False -def runfastcgi(argset): +def runfastcgi(argset=[], **kwargs): options = FASTCGI_OPTIONS.copy() + options.update(kwargs) for x in argset: if "=" in x: k, v = x.split('=', 1) diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py index a1661a2ecd..45705cb223 100644 --- a/django/core/urlresolvers.py +++ b/django/core/urlresolvers.py @@ -15,7 +15,8 @@ class Resolver404(Http404): pass class NoReverseMatch(Exception): - pass + # Don't make this raise an error when used in a template. + silent_variable_failure = True def get_mod_func(callback): # Converts 'django.views.news.stories.story_detail' to @@ -86,10 +87,15 @@ class MatchChecker(object): class RegexURLPattern(object): def __init__(self, regex, callback, default_args=None): # regex is a string representing a regular expression. - # callback is something like 'foo.views.news.stories.story_detail', - # which represents the path to a module and a view function name. + # callback is either a string like 'foo.views.news.stories.story_detail' + # which represents the path to a module and a view function name, or a + # callable object (view). self.regex = re.compile(regex) - self.callback = callback + if callable(callback): + self._callback = callback + else: + self._callback = None + self._callback_str = callback self.default_args = default_args or {} def resolve(self, path): @@ -106,23 +112,28 @@ class RegexURLPattern(object): # In both cases, pass any extra_kwargs as **kwargs. kwargs.update(self.default_args) - try: # Lazily load self.func. - return self.func, args, kwargs - except AttributeError: - self.func = self.get_callback() - return self.func, args, kwargs + return self.callback, args, kwargs - def get_callback(self): - mod_name, func_name = get_mod_func(self.callback) + def _get_callback(self): + if self._callback is not None: + return self._callback + mod_name, func_name = get_mod_func(self._callback_str) try: - return getattr(__import__(mod_name, '', '', ['']), func_name) + self._callback = getattr(__import__(mod_name, '', '', ['']), func_name) except ImportError, e: raise ViewDoesNotExist, "Could not import %s. Error was: %s" % (mod_name, str(e)) except AttributeError, e: raise ViewDoesNotExist, "Tried %s in module %s. Error was: %s" % (func_name, mod_name, str(e)) + return self._callback + callback = property(_get_callback) def reverse(self, viewname, *args, **kwargs): - if viewname != self.callback: + mod_name, func_name = get_mod_func(viewname) + try: + lookup_view = getattr(__import__(mod_name, '', '', ['']), func_name) + except (ImportError, AttributeError): + raise NoReverseMatch + if lookup_view != self.callback: raise NoReverseMatch return self.reverse_helper(*args, **kwargs) @@ -130,12 +141,13 @@ class RegexURLPattern(object): return reverse_helper(self.regex, *args, **kwargs) class RegexURLResolver(object): - def __init__(self, regex, urlconf_name): + def __init__(self, regex, urlconf_name, default_kwargs=None): # regex is a string representing a regular expression. # urlconf_name is a string representing the module containing urlconfs. self.regex = re.compile(regex) self.urlconf_name = urlconf_name self.callback = None + self.default_kwargs = default_kwargs or {} def resolve(self, path): tried = [] @@ -149,7 +161,8 @@ class RegexURLResolver(object): tried.extend([(pattern.regex.pattern + ' ' + t) for t in e.args[0]['tried']]) else: if sub_match: - return sub_match[0], sub_match[1], dict(match.groupdict(), **sub_match[2]) + sub_match_dict = dict(self.default_kwargs, **sub_match[2]) + return sub_match[0], sub_match[1], dict(match.groupdict(), **sub_match_dict) tried.append(pattern.regex.pattern) raise Resolver404, {'tried': tried, 'path': new_path} @@ -183,21 +196,43 @@ class RegexURLResolver(object): def resolve500(self): return self._resolve_special('500') - def reverse(self, viewname, *args, **kwargs): + def reverse(self, lookup_view, *args, **kwargs): + if not callable(lookup_view): + mod_name, func_name = get_mod_func(lookup_view) + try: + lookup_view = getattr(__import__(mod_name, '', '', ['']), func_name) + except (ImportError, AttributeError): + raise NoReverseMatch for pattern in self.urlconf_module.urlpatterns: if isinstance(pattern, RegexURLResolver): try: - return pattern.reverse_helper(viewname, *args, **kwargs) + return pattern.reverse_helper(lookup_view, *args, **kwargs) except NoReverseMatch: continue - elif pattern.callback == viewname: + elif pattern.callback == lookup_view: try: return pattern.reverse_helper(*args, **kwargs) except NoReverseMatch: continue raise NoReverseMatch - def reverse_helper(self, viewname, *args, **kwargs): - sub_match = self.reverse(viewname, *args, **kwargs) + def reverse_helper(self, lookup_view, *args, **kwargs): + sub_match = self.reverse(lookup_view, *args, **kwargs) result = reverse_helper(self.regex, *args, **kwargs) return result + sub_match + +def resolve(path, urlconf=None): + if urlconf is None: + from django.conf import settings + urlconf = settings.ROOT_URLCONF + resolver = RegexURLResolver(r'^/', urlconf) + return resolver.resolve(path) + +def reverse(viewname, urlconf=None, args=None, kwargs=None): + args = args or [] + kwargs = kwargs or {} + if urlconf is None: + from django.conf import settings + urlconf = settings.ROOT_URLCONF + resolver = RegexURLResolver(r'^/', urlconf) + return '/' + resolver.reverse(viewname, *args, **kwargs) diff --git a/django/core/validators.py b/django/core/validators.py index 81bea23e36..4c3f59143e 100644 --- a/django/core/validators.py +++ b/django/core/validators.py @@ -13,7 +13,7 @@ from django.utils.translation import gettext, gettext_lazy, ngettext from django.utils.functional import Promise, lazy import re -_datere = r'(19|2\d)\d{2}-((?:0?[1-9])|(?:1[0-2]))-((?:0?[1-9])|(?:[12][0-9])|(?:3[0-1]))' +_datere = r'\d{4}-\d{1,2}-\d{1,2}' _timere = r'(?:[01]?[0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?' alnum_re = re.compile(r'^\w+$') alnumurl_re = re.compile(r'^[-\w/]+$') @@ -68,7 +68,7 @@ def isAlphaNumericURL(field_data, all_data): def isSlug(field_data, all_data): if not slug_re.search(field_data): - raise ValidationError, "This value must contain only letters, numbers, underscores or hyphens." + raise ValidationError, gettext("This value must contain only letters, numbers, underscores or hyphens.") def isLowerCase(field_data, all_data): if field_data.lower() != field_data: @@ -122,9 +122,29 @@ def isOnlyLetters(field_data, all_data): if not field_data.isalpha(): raise ValidationError, gettext("Only alphabetical characters are allowed here.") +def _isValidDate(date_string): + """ + A helper function used by isValidANSIDate and isValidANSIDatetime to + check if the date is valid. The date string is assumed to already be in + YYYY-MM-DD format. + """ + from datetime import date + # Could use time.strptime here and catch errors, but datetime.date below + # produces much friendlier error messages. + year, month, day = map(int, date_string.split('-')) + # This check is needed because strftime is used when saving the date + # value to the database, and strftime requires that the year be >=1900. + if year < 1900: + raise ValidationError, gettext('Year must be 1900 or later.') + try: + date(year, month, day) + except ValueError, e: + raise ValidationError, gettext('Invalid date: %s.' % e) + def isValidANSIDate(field_data, all_data): if not ansi_date_re.search(field_data): raise ValidationError, gettext('Enter a valid date in YYYY-MM-DD format.') + _isValidDate(field_data) def isValidANSITime(field_data, all_data): if not ansi_time_re.search(field_data): @@ -133,6 +153,7 @@ def isValidANSITime(field_data, all_data): def isValidANSIDatetime(field_data, all_data): if not ansi_datetime_re.search(field_data): raise ValidationError, gettext('Enter a valid date/time in YYYY-MM-DD HH:MM format.') + _isValidDate(field_data.split()[0]) def isValidEmail(field_data, all_data): if not email_re.search(field_data): @@ -227,9 +248,8 @@ def hasNoProfanities(field_data, all_data): catch 'motherfucker' as well. Raises a ValidationError such as: Watch your mouth! The words "f--k" and "s--t" are not allowed here. """ - bad_words = ['asshat', 'asshead', 'asshole', 'cunt', 'fuck', 'gook', 'nigger', 'shit'] # all in lower case field_data = field_data.lower() # normalize - words_seen = [w for w in bad_words if field_data.find(w) > -1] + words_seen = [w for w in settings.PROFANITIES_LIST if w in field_data] if words_seen: from django.utils.text import get_text_list plural = len(words_seen) > 1 @@ -352,10 +372,12 @@ class IsValidFloat(object): float(data) except ValueError: raise ValidationError, gettext("Please enter a valid decimal number.") - if len(data) > (self.max_digits + 1): + # Negative floats require more space to input. + max_allowed_length = data.startswith('-') and (self.max_digits + 2) or (self.max_digits + 1) + if len(data) > max_allowed_length: raise ValidationError, ngettext("Please enter a valid decimal number with at most %s total digit.", "Please enter a valid decimal number with at most %s total digits.", self.max_digits) % self.max_digits - if (not '.' in data and len(data) > (self.max_digits - self.decimal_places)) or ('.' in data and len(data) > (self.max_digits - (self.decimal_places - len(data.split('.')[1])) + 1)): + if (not '.' in data and len(data) > (max_allowed_length - self.decimal_places - 1)) or ('.' in data and len(data) > (max_allowed_length - (self.decimal_places - len(data.split('.')[1])))): raise ValidationError, ngettext( "Please enter a valid decimal number with a whole part of at most %s digit.", "Please enter a valid decimal number with a whole part of at most %s digits.", str(self.max_digits-self.decimal_places)) % str(self.max_digits-self.decimal_places) if '.' in data and len(data.split('.')[1]) > self.decimal_places: diff --git a/django/core/xheaders.py b/django/core/xheaders.py index e173bcbca8..69f6115839 100644 --- a/django/core/xheaders.py +++ b/django/core/xheaders.py @@ -13,9 +13,10 @@ def populate_xheaders(request, response, model, object_id): """ Adds the "X-Object-Type" and "X-Object-Id" headers to the given HttpResponse according to the given model and object_id -- but only if the - given HttpRequest object has an IP address within the INTERNAL_IPS setting. + given HttpRequest object has an IP address within the INTERNAL_IPS setting + or if the request is from a logged in staff member. """ from django.conf import settings - if request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS: + if request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS or (request.user.is_authenticated() and request.user.is_staff): response['X-Object-Type'] = "%s.%s" % (model._meta.app_label, model._meta.object_name.lower()) response['X-Object-Id'] = str(object_id) diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py index 50b76cc3a0..924c032b4c 100644 --- a/django/db/backends/mysql/base.py +++ b/django/db/backends/mysql/base.py @@ -13,6 +13,7 @@ except ImportError, e: from MySQLdb.converters import conversions from MySQLdb.constants import FIELD_TYPE import types +import re DatabaseError = Database.DatabaseError @@ -24,6 +25,12 @@ django_conversions.update({ FIELD_TYPE.TIME: util.typecast_time, }) +# This should match the numerical portion of the version numbers (we can treat +# versions like 5.0.24 and 5.0.24a as the same). Based on the list of version +# at http://dev.mysql.com/doc/refman/4.1/en/news.html and +# http://dev.mysql.com/doc/refman/5.0/en/news.html . +server_version_re = re.compile(r'(\d{1,2})\.(\d{1,2})\.(\d{1,2})') + # This is an extra debug layer over MySQL queries, to display warnings. # It's only used when DEBUG=True. class MysqlDebugWrapper: @@ -61,6 +68,7 @@ class DatabaseWrapper(local): def __init__(self): self.connection = None self.queries = [] + self.server_version = None def _valid_connection(self): if self.connection is not None: @@ -110,6 +118,16 @@ class DatabaseWrapper(local): self.connection.close() self.connection = None + def get_server_version(self): + if not self.server_version: + if not self._valid_connection(): + self.cursor() + m = server_version_re.match(self.connection.get_server_info()) + if not m: + raise Exception('Unable to determine MySQL version from version string %r' % self.connection.get_server_info()) + self.server_version = tuple([int(x) for x in m.groups()]) + return self.server_version + supports_constraints = True def quote_name(name): diff --git a/django/db/backends/mysql/introspection.py b/django/db/backends/mysql/introspection.py index 202fced1dc..7caf5fa060 100644 --- a/django/db/backends/mysql/introspection.py +++ b/django/db/backends/mysql/introspection.py @@ -36,13 +36,14 @@ def get_relations(cursor, table_name): SELECT column_name, referenced_table_name, referenced_column_name FROM information_schema.key_column_usage WHERE table_name = %s + AND table_schema = DATABASE() AND referenced_table_name IS NOT NULL AND referenced_column_name IS NOT NULL""", [table_name]) constraints.extend(cursor.fetchall()) except (ProgrammingError, OperationalError): # Fall back to "SHOW CREATE TABLE", for previous MySQL versions. # Go through all constraints and save the equal matches. - cursor.execute("SHOW CREATE TABLE %s" % table_name) + cursor.execute("SHOW CREATE TABLE %s" % quote_name(table_name)) for row in cursor.fetchall(): pos = 0 while True: diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py index 188c4bb678..dfe2df11dc 100644 --- a/django/db/backends/oracle/base.py +++ b/django/db/backends/oracle/base.py @@ -10,7 +10,6 @@ try: except ImportError, e: from django.core.exceptions import ImproperlyConfigured raise ImproperlyConfigured, "Error loading cx_Oracle module: %s" % e -import types DatabaseError = Database.Error diff --git a/django/db/backends/oracle/introspection.py b/django/db/backends/oracle/introspection.py index 656741e440..ecc8f372a8 100644 --- a/django/db/backends/oracle/introspection.py +++ b/django/db/backends/oracle/introspection.py @@ -1,5 +1,3 @@ -from django.db import transaction -from django.db.backends.oracle.base import quote_name import re foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)") diff --git a/django/db/backends/postgresql_psycopg2/base.py b/django/db/backends/postgresql_psycopg2/base.py index 55cba81b70..4c835d89fc 100644 --- a/django/db/backends/postgresql_psycopg2/base.py +++ b/django/db/backends/postgresql_psycopg2/base.py @@ -43,6 +43,7 @@ class DatabaseWrapper(local): self.connection = Database.connect(conn_string) self.connection.set_isolation_level(1) # make transactions transparent to all cursors cursor = self.connection.cursor() + cursor.tzinfo_factory = None cursor.execute("SET TIME ZONE %s", [settings.TIME_ZONE]) if settings.DEBUG: return util.CursorDebugWrapper(cursor, self) @@ -67,23 +68,9 @@ def quote_name(name): return name # Quoting once is enough. return '"%s"' % name -def dictfetchone(cursor): - "Returns a row from the cursor as a dict" - # TODO: cursor.dictfetchone() doesn't exist in psycopg2, - # but no Django code uses this. Safe to remove? - return cursor.dictfetchone() - -def dictfetchmany(cursor, number): - "Returns a certain number of rows from a cursor as a dict" - # TODO: cursor.dictfetchmany() doesn't exist in psycopg2, - # but no Django code uses this. Safe to remove? - return cursor.dictfetchmany(number) - -def dictfetchall(cursor): - "Returns all rows from a cursor as a dict" - # TODO: cursor.dictfetchall() doesn't exist in psycopg2, - # but no Django code uses this. Safe to remove? - return cursor.dictfetchall() +dictfetchone = util.dictfetchone +dictfetchmany = util.dictfetchmany +dictfetchall = util.dictfetchall def get_last_insert_id(cursor, table_name, pk_name): cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name)) diff --git a/django/db/backends/postgresql_psycopg2/introspection.py b/django/db/backends/postgresql_psycopg2/introspection.py index b991493d39..a546da8c45 100644 --- a/django/db/backends/postgresql_psycopg2/introspection.py +++ b/django/db/backends/postgresql_psycopg2/introspection.py @@ -1,4 +1,3 @@ -from django.db import transaction from django.db.backends.postgresql_psycopg2.base import quote_name def get_table_list(cursor): diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py index 5c884ff121..01e4b3aebf 100644 --- a/django/db/backends/sqlite3/base.py +++ b/django/db/backends/sqlite3/base.py @@ -4,10 +4,18 @@ SQLite3 backend for django. Requires pysqlite2 (http://pysqlite.org/). from django.db.backends import util try: - from pysqlite2 import dbapi2 as Database + try: + from sqlite3 import dbapi2 as Database + except ImportError: + from pysqlite2 import dbapi2 as Database except ImportError, e: + import sys from django.core.exceptions import ImproperlyConfigured - raise ImproperlyConfigured, "Error loading pysqlite2 module: %s" % e + if sys.version_info < (2, 5, 0): + module = 'pysqlite2' + else: + module = 'sqlite3' + raise ImproperlyConfigured, "Error loading %s module: %s" % (module, e) DatabaseError = Database.DatabaseError @@ -62,7 +70,10 @@ class DatabaseWrapper(local): self.connection.rollback() def close(self): - if self.connection is not None: + from django.conf import settings + # If database is in memory, closing the connection destroys the database. + # To prevent accidental data loss, ignore close requests on an in-memory db. + if self.connection is not None and settings.DATABASE_NAME != ":memory:": self.connection.close() self.connection = None diff --git a/django/db/backends/util.py b/django/db/backends/util.py index 74d33f42ca..3ec1b41485 100644 --- a/django/db/backends/util.py +++ b/django/db/backends/util.py @@ -98,7 +98,7 @@ def rev_typecast_boolean(obj, d): def _dict_helper(desc, row): "Returns a dictionary for the given cursor.description and result row." - return dict([(desc[col[0]][0], col[1]) for col in enumerate(row)]) + return dict(zip([col[0] for col in desc], row)) def dictfetchone(cursor): "Returns a row from the cursor as a dict" @@ -110,9 +110,11 @@ def dictfetchone(cursor): def dictfetchmany(cursor, number): "Returns a certain number of rows from a cursor as a dict" desc = cursor.description - return [_dict_helper(desc, row) for row in cursor.fetchmany(number)] + for row in cursor.fetchmany(number): + yield _dict_helper(desc, row) def dictfetchall(cursor): "Returns all rows from a cursor as a dict" desc = cursor.description - return [_dict_helper(desc, row) for row in cursor.fetchall()] + for row in cursor.fetchall(): + yield _dict_helper(desc, row) diff --git a/django/db/models/__init__.py b/django/db/models/__init__.py index 82b1238723..0308dd047a 100644 --- a/django/db/models/__init__.py +++ b/django/db/models/__init__.py @@ -16,6 +16,18 @@ from django.utils.text import capfirst # Admin stages. ADD, CHANGE, BOTH = 1, 2, 3 +# Decorator. Takes a function that returns a tuple in this format: +# (viewname, viewargs, viewkwargs) +# Returns a function that calls urlresolvers.reverse() on that data, to return +# the URL for those parameters. +def permalink(func): + from django.core.urlresolvers import reverse + def inner(*args, **kwargs): + bits = func(*args, **kwargs) + viewname = bits[0] + return reverse(bits[0], None, *bits[1:3]) + return inner + class LazyDate(object): """ Use in limit_choices_to to compare the field to dates calculated at run time @@ -35,7 +47,7 @@ class LazyDate(object): return "<LazyDate: %s>" % self.delta def __get_value__(self): - return datetime.datetime.now() + self.delta + return (datetime.datetime.now() + self.delta).date() def __getattr__(self, attr): return getattr(self.__get_value__(), attr) diff --git a/django/db/models/base.py b/django/db/models/base.py index c89033c491..bdae7eccc2 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -4,8 +4,7 @@ from django.core import validators from django.core.exceptions import ObjectDoesNotExist from django.db.models.fields import AutoField, ImageField, FieldDoesNotExist from django.db.models.fields.related import OneToOneRel, ManyToOneRel -from django.db.models.related import RelatedObject -from django.db.models.query import orderlist2sql, delete_objects +from django.db.models.query import delete_objects from django.db.models.options import Options, AdminOptions from django.db import connection, backend, transaction from django.db.models import signals @@ -45,7 +44,7 @@ class ModelBase(type): new_class._meta.app_label = model_module.__name__.split('.')[-2] # Bail out early if we have already created this class. - m = get_model(new_class._meta.app_label, name) + m = get_model(new_class._meta.app_label, name, False) if m is not None: return m @@ -69,7 +68,7 @@ class ModelBase(type): # the first class for this model to register with the framework. There # should only be one class for each model, so we must always return the # registered version. - return get_model(new_class._meta.app_label, name) + return get_model(new_class._meta.app_label, name, False) class Model(object): __metaclass__ = ModelBase @@ -177,11 +176,12 @@ class Model(object): # If it does already exist, do an UPDATE. if cursor.fetchone(): db_values = [f.get_db_prep_save(f.pre_save(self, False)) for f in non_pks] - cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \ - (backend.quote_name(self._meta.db_table), - ','.join(['%s=%%s' % backend.quote_name(f.column) for f in non_pks]), - backend.quote_name(self._meta.pk.column)), - db_values + [pk_val]) + if db_values: + cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \ + (backend.quote_name(self._meta.db_table), + ','.join(['%s=%%s' % backend.quote_name(f.column) for f in non_pks]), + backend.quote_name(self._meta.pk.column)), + db_values + [pk_val]) else: record_exists = False if not pk_set or not record_exists: diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index 98661fe36c..02b5ba8b9e 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -5,6 +5,7 @@ from django.core import validators from django import forms from django.core.exceptions import ObjectDoesNotExist from django.utils.functional import curry +from django.utils.itercompat import tee from django.utils.text import capfirst from django.utils.translation import gettext, gettext_lazy import datetime, os, time @@ -80,7 +81,7 @@ class Field(object): self.prepopulate_from = prepopulate_from self.unique_for_date, self.unique_for_month = unique_for_date, unique_for_month self.unique_for_year = unique_for_year - self.choices = choices or [] + self._choices = choices or [] self.radio_admin = radio_admin self.help_text = help_text self.db_column = db_column @@ -325,6 +326,14 @@ class Field(object): def bind(self, fieldmapping, original, bound_field_class): return bound_field_class(self, fieldmapping, original) + def _get_choices(self): + if hasattr(self._choices, 'next'): + choices, self._choices = tee(self._choices) + return choices + else: + return self._choices + choices = property(_get_choices) + class AutoField(Field): empty_strings_allowed = False def __init__(self, *args, **kwargs): @@ -368,8 +377,8 @@ class BooleanField(Field): def to_python(self, value): if value in (True, False): return value - if value in ('t', 'True'): return True - if value in ('f', 'False'): return False + if value in ('t', 'True', '1'): return True + if value in ('f', 'False', '0'): return False raise validators.ValidationError, gettext("This value must be either True or False.") def get_manipulator_field_objs(self): diff --git a/django/db/models/fields/generic.py b/django/db/models/fields/generic.py index 5f4de40e69..7d7651029c 100644 --- a/django/db/models/fields/generic.py +++ b/django/db/models/fields/generic.py @@ -117,7 +117,7 @@ class GenericRelation(RelatedField, Field): return self.object_id_field_name def m2m_reverse_name(self): - return self.model._meta.pk.attname + return self.object_id_field_name def contribute_to_class(self, cls, name): super(GenericRelation, self).contribute_to_class(cls, name) diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index 9a8a61878e..bd9262d55a 100644 --- a/django/db/models/fields/related.py +++ b/django/db/models/fields/related.py @@ -1,8 +1,8 @@ -from django.db import backend, connection, transaction +from django.db import backend, transaction from django.db.models import signals, get_model from django.db.models.fields import AutoField, Field, IntegerField, get_ul_class from django.db.models.related import RelatedObject -from django.utils.translation import gettext_lazy, string_concat +from django.utils.translation import gettext_lazy, string_concat, ngettext from django.utils.functional import curry from django.core import validators from django import forms @@ -23,9 +23,9 @@ def add_lookup(rel_cls, field): name = field.rel.to module = rel_cls.__module__ key = (module, name) - # Has the model already been loaded? + # Has the model already been loaded? # If so, resolve the string reference right away - model = get_model(rel_cls._meta.app_label,field.rel.to) + model = get_model(rel_cls._meta.app_label, field.rel.to, False) if model: field.rel.to = model field.do_related_class(model, rel_cls) @@ -46,7 +46,7 @@ def manipulator_valid_rel_key(f, self, field_data, all_data): "Validates that the value is a valid foreign key" klass = f.rel.to try: - klass._default_manager.get(pk=field_data) + klass._default_manager.get(**{f.rel.field_name: field_data}) except klass.DoesNotExist: raise validators.ValidationError, _("Please enter a valid %s.") % f.verbose_name @@ -79,11 +79,11 @@ class RelatedField(object): self.contribute_to_related_class(other, related) def get_db_prep_lookup(self, lookup_type, value): - # If we are doing a lookup on a Related Field, we must be - # comparing object instances. The value should be the PK of value, + # If we are doing a lookup on a Related Field, we must be + # comparing object instances. The value should be the PK of value, # not value itself. def pk_trace(value): - # Value may be a primary key, or an object held in a relation. + # Value may be a primary key, or an object held in a relation. # If it is an object, then we need to get the primary key value for # that object. In certain conditions (especially one-to-one relations), # the primary key may itself be an object - so we need to keep drilling @@ -94,8 +94,8 @@ class RelatedField(object): v = getattr(v, v._meta.pk.name) except AttributeError: pass - return v - + return v + if lookup_type == 'exact': return [pk_trace(value)] if lookup_type == 'in': @@ -103,7 +103,7 @@ class RelatedField(object): elif lookup_type == 'isnull': return [] raise TypeError, "Related Field has invalid lookup: %s" % lookup_type - + def _get_related_query_name(self, opts): # This method defines the name that can be used to identify this related object # in a table-spanning query. It uses the lower-cased object_name by default, @@ -618,7 +618,7 @@ class ManyToManyField(RelatedField, Field): msg = gettext_lazy('Separate multiple IDs with commas.') else: msg = gettext_lazy('Hold down "Control", or "Command" on a Mac, to select more than one.') - self.help_text = string_concat(self.help_text, msg) + self.help_text = string_concat(self.help_text, ' ', msg) def get_manipulator_field_objs(self): if self.rel.raw_id_admin: diff --git a/django/db/models/loading.py b/django/db/models/loading.py index c7920fa4e0..22f83bfd78 100644 --- a/django/db/models/loading.py +++ b/django/db/models/loading.py @@ -32,7 +32,7 @@ def get_apps(): _app_errors[app_name] = e return _app_list -def get_app(app_label, emptyOK = False): +def get_app(app_label, emptyOK=False): "Returns the module containing the models for the given app_label. If the app has no models in it and 'emptyOK' is True, returns None." get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish. for app_name in settings.INSTALLED_APPS: @@ -75,11 +75,15 @@ def get_models(app_mod=None): model_list.extend(get_models(app_mod)) return model_list -def get_model(app_label, model_name): +def get_model(app_label, model_name, seed_cache=True): """ - Returns the model matching the given app_label and case-insensitive model_name. + Returns the model matching the given app_label and case-insensitive + model_name. + Returns None if no model is found. """ + if seed_cache: + get_apps() try: model_dict = _app_models[app_label] except KeyError: diff --git a/django/db/models/manager.py b/django/db/models/manager.py index 46a1710c1c..6005874516 100644 --- a/django/db/models/manager.py +++ b/django/db/models/manager.py @@ -1,10 +1,7 @@ -from django.utils.functional import curry -from django.db import backend, connection from django.db.models.query import QuerySet from django.dispatch import dispatcher from django.db.models import signals from django.db.models.fields import FieldDoesNotExist -from django.utils.datastructures import SortedDict # Size of each "chunk" for get_iterator calls. # Larger values are slightly faster at the expense of more storage space. diff --git a/django/db/models/manipulators.py b/django/db/models/manipulators.py index 454c318e5d..83ddda844e 100644 --- a/django/db/models/manipulators.py +++ b/django/db/models/manipulators.py @@ -5,7 +5,7 @@ from django.db.models.fields import FileField, AutoField from django.dispatch import dispatcher from django.db.models import signals from django.utils.functional import curry -from django.utils.datastructures import DotExpandedDict, MultiValueDict +from django.utils.datastructures import DotExpandedDict from django.utils.text import capfirst import types @@ -76,7 +76,7 @@ class AutomaticManipulator(forms.Manipulator): # Add field for ordering. if self.change and self.opts.get_ordered_objects(): - self.fields.append(formfields.CommaSeparatedIntegerField(field_name="order_")) + self.fields.append(forms.CommaSeparatedIntegerField(field_name="order_")) def save(self, new_data): # TODO: big cleanup when core fields go -> use recursive manipulators. @@ -138,7 +138,7 @@ class AutomaticManipulator(forms.Manipulator): child_follow = self.follow.get(related.name, None) if child_follow: - obj_list = expanded_data[related.var_name].items() + obj_list = expanded_data.get(related.var_name, {}).items() if not obj_list: continue @@ -177,7 +177,7 @@ class AutomaticManipulator(forms.Manipulator): # case, because they'll be dealt with later. if f == related.field: - param = getattr(new_object, related.field.rel.field_name) + param = getattr(new_object, related.field.rel.get_related_field().attname) elif (not self.change) and isinstance(f, AutoField): param = None elif self.change and (isinstance(f, FileField) or not child_follow.get(f.name, None)): @@ -215,8 +215,11 @@ class AutomaticManipulator(forms.Manipulator): # Save many-to-many objects. for f in related.opts.many_to_many: if child_follow.get(f.name, None) and not f.rel.edit_inline: - was_changed = getattr(new_rel_obj, 'set_%s' % f.name)(rel_new_data[f.attname]) - if self.change and was_changed: + new_value = rel_new_data[f.attname] + if f.rel.raw_id_admin: + new_value = new_value[0] + setattr(new_rel_obj, f.name, f.rel.to.objects.filter(pk__in=new_value)) + if self.change: self.fields_changed.append('%s for %s "%s"' % (f.verbose_name, related.opts.verbose_name, new_rel_obj)) # If, in the change stage, all of the core fields were blank and @@ -300,7 +303,7 @@ def manipulator_validator_unique_together(field_name_list, opts, self, field_dat pass else: raise validators.ValidationError, _("%(object)s with this %(type)s already exists for the given %(field)s.") % \ - {'object': capfirst(opts.verbose_name), 'type': field_list[0].verbose_name, 'field': get_text_list(field_name_list[1:], 'and')} + {'object': capfirst(opts.verbose_name), 'type': field_list[0].verbose_name, 'field': get_text_list([f.verbose_name for f in field_list[1:]], 'and')} def manipulator_validator_unique_for_date(from_field, date_field, opts, lookup_type, self, field_data, all_data): from django.db.models.fields.related import ManyToOneRel diff --git a/django/db/models/query.py b/django/db/models/query.py index 2b4a13354b..53ed63ae5b 100644 --- a/django/db/models/query.py +++ b/django/db/models/query.py @@ -18,7 +18,7 @@ QUERY_TERMS = ( 'exact', 'iexact', 'contains', 'icontains', 'gt', 'gte', 'lt', 'lte', 'in', 'startswith', 'istartswith', 'endswith', 'iendswith', - 'range', 'year', 'month', 'day', 'isnull', + 'range', 'year', 'month', 'day', 'isnull', 'search', ) # Size of each "chunk" for get_iterator calls. @@ -707,34 +707,35 @@ def parse_lookup(kwarg_items, opts): joins, where, params = SortedDict(), [], [] for kwarg, value in kwarg_items: - if value is not None: - path = kwarg.split(LOOKUP_SEPARATOR) - # Extract the last elements of the kwarg. - # The very-last is the lookup_type (equals, like, etc). - # The second-last is the table column on which the lookup_type is - # to be performed. - # The exceptions to this are: - # 1) "pk", which is an implicit id__exact; - # if we find "pk", make the lookup_type "exact', and insert - # a dummy name of None, which we will replace when - # we know which table column to grab as the primary key. - # 2) If there is only one part, or the last part is not a query - # term, assume that the query is an __exact - lookup_type = path.pop() - if lookup_type == 'pk': - lookup_type = 'exact' - path.append(None) - elif len(path) == 0 or lookup_type not in QUERY_TERMS: - path.append(lookup_type) - lookup_type = 'exact' + path = kwarg.split(LOOKUP_SEPARATOR) + # Extract the last elements of the kwarg. + # The very-last is the lookup_type (equals, like, etc). + # The second-last is the table column on which the lookup_type is + # to be performed. If this name is 'pk', it will be substituted with + # the name of the primary key. + # If there is only one part, or the last part is not a query + # term, assume that the query is an __exact + lookup_type = path.pop() + if lookup_type == 'pk': + lookup_type = 'exact' + path.append(None) + elif len(path) == 0 or lookup_type not in QUERY_TERMS: + path.append(lookup_type) + lookup_type = 'exact' - if len(path) < 1: - raise TypeError, "Cannot parse keyword query %r" % kwarg + if len(path) < 1: + raise TypeError, "Cannot parse keyword query %r" % kwarg + + if value is None: + # Interpret '__exact=None' as the sql '= NULL'; otherwise, reject + # all uses of None as a query value. + if lookup_type != 'exact': + raise ValueError, "Cannot use None as a query value" - joins2, where2, params2 = lookup_inner(path, lookup_type, value, opts, opts.db_table, None) - joins.update(joins2) - where.extend(where2) - params.extend(params2) + joins2, where2, params2 = lookup_inner(path, lookup_type, value, opts, opts.db_table, None) + joins.update(joins2) + where.extend(where2) + params.extend(params2) return joins, where, params class FieldFound(Exception): @@ -766,7 +767,7 @@ def lookup_inner(path, lookup_type, value, opts, table, column): name = path.pop(0) # Has the primary key been requested? If so, expand it out # to be the name of the current class' primary key - if name is None: + if name is None or name == 'pk': name = current_opts.pk.name # Try to find the name in the fields associated with the current class diff --git a/django/db/models/related.py b/django/db/models/related.py index ee3b916cf4..ac1ec50ca2 100644 --- a/django/db/models/related.py +++ b/django/db/models/related.py @@ -131,6 +131,9 @@ class RelatedObject(object): # many-to-many objects. It uses the lower-cased object_name + "_set", # but this can be overridden with the "related_name" option. if self.field.rel.multiple: + # If this is a symmetrical m2m relation on self, there is no reverse accessor. + if getattr(self.field.rel, 'symmetrical', False) and self.model == self.parent_model: + return None return self.field.rel.related_name or (self.opts.object_name.lower() + '_set') else: return self.field.rel.related_name or (self.opts.object_name.lower()) diff --git a/django/dispatch/dispatcher.py b/django/dispatch/dispatcher.py index d93f696685..1a617b5946 100644 --- a/django/dispatch/dispatcher.py +++ b/django/dispatch/dispatcher.py @@ -6,24 +6,24 @@ system. Module attributes of note: - Any -- Singleton used to signal either "Any Sender" or - "Any Signal". See documentation of the _Any class. - Anonymous -- Singleton used to signal "Anonymous Sender" - See documentation of the _Anonymous class. + Any -- Singleton used to signal either "Any Sender" or + "Any Signal". See documentation of the _Any class. + Anonymous -- Singleton used to signal "Anonymous Sender" + See documentation of the _Anonymous class. Internal attributes: - WEAKREF_TYPES -- tuple of types/classes which represent - weak references to receivers, and thus must be de- - referenced on retrieval to retrieve the callable - object - connections -- { senderkey (id) : { signal : [receivers...]}} - senders -- { senderkey (id) : weakref(sender) } - used for cleaning up sender references on sender - deletion - sendersBack -- { receiverkey (id) : [senderkey (id)...] } - used for cleaning up receiver references on receiver - deletion, (considerably speeds up the cleanup process - vs. the original code.) + WEAKREF_TYPES -- tuple of types/classes which represent + weak references to receivers, and thus must be de- + referenced on retrieval to retrieve the callable + object + connections -- { senderkey (id) : { signal : [receivers...]}} + senders -- { senderkey (id) : weakref(sender) } + used for cleaning up sender references on sender + deletion + sendersBack -- { receiverkey (id) : [senderkey (id)...] } + used for cleaning up receiver references on receiver + deletion, (considerably speeds up the cleanup process + vs. the original code.) """ from __future__ import generators import types, weakref @@ -34,44 +34,44 @@ __cvsid__ = "$Id: dispatcher.py,v 1.9 2005/09/17 04:55:57 mcfletch Exp $" __version__ = "$Revision: 1.9 $"[11:-2] try: - True + True except NameError: - True = 1==1 - False = 1==0 + True = 1==1 + False = 1==0 class _Parameter: - """Used to represent default parameter values.""" - def __repr__(self): - return self.__class__.__name__ + """Used to represent default parameter values.""" + def __repr__(self): + return self.__class__.__name__ class _Any(_Parameter): - """Singleton used to signal either "Any Sender" or "Any Signal" + """Singleton used to signal either "Any Sender" or "Any Signal" - The Any object can be used with connect, disconnect, - send, or sendExact to signal that the parameter given - Any should react to all senders/signals, not just - a particular sender/signal. - """ + The Any object can be used with connect, disconnect, + send, or sendExact to signal that the parameter given + Any should react to all senders/signals, not just + a particular sender/signal. + """ Any = _Any() class _Anonymous(_Parameter): - """Singleton used to signal "Anonymous Sender" + """Singleton used to signal "Anonymous Sender" - The Anonymous object is used to signal that the sender - of a message is not specified (as distinct from being - "any sender"). Registering callbacks for Anonymous - will only receive messages sent without senders. Sending - with anonymous will only send messages to those receivers - registered for Any or Anonymous. + The Anonymous object is used to signal that the sender + of a message is not specified (as distinct from being + "any sender"). Registering callbacks for Anonymous + will only receive messages sent without senders. Sending + with anonymous will only send messages to those receivers + registered for Any or Anonymous. - Note: - The default sender for connect is Any, while the - default sender for send is Anonymous. This has - the effect that if you do not specify any senders - in either function then all messages are routed - as though there was a single sender (Anonymous) - being used everywhere. - """ + Note: + The default sender for connect is Any, while the + default sender for send is Anonymous. This has + the effect that if you do not specify any senders + in either function then all messages are routed + as though there was a single sender (Anonymous) + being used everywhere. + """ Anonymous = _Anonymous() WEAKREF_TYPES = (weakref.ReferenceType, saferef.BoundMethodWeakref) @@ -82,416 +82,416 @@ sendersBack = {} def connect(receiver, signal=Any, sender=Any, weak=True): - """Connect receiver to sender for signal + """Connect receiver to sender for signal - receiver -- a callable Python object which is to receive - messages/signals/events. Receivers must be hashable - objects. + receiver -- a callable Python object which is to receive + messages/signals/events. Receivers must be hashable + objects. - if weak is True, then receiver must be weak-referencable - (more precisely saferef.safeRef() must be able to create - a reference to the receiver). - - Receivers are fairly flexible in their specification, - as the machinery in the robustApply module takes care - of most of the details regarding figuring out appropriate - subsets of the sent arguments to apply to a given - receiver. + if weak is True, then receiver must be weak-referencable + (more precisely saferef.safeRef() must be able to create + a reference to the receiver). + + Receivers are fairly flexible in their specification, + as the machinery in the robustApply module takes care + of most of the details regarding figuring out appropriate + subsets of the sent arguments to apply to a given + receiver. - Note: - if receiver is itself a weak reference (a callable), - it will be de-referenced by the system's machinery, - so *generally* weak references are not suitable as - receivers, though some use might be found for the - facility whereby a higher-level library passes in - pre-weakrefed receiver references. + Note: + if receiver is itself a weak reference (a callable), + it will be de-referenced by the system's machinery, + so *generally* weak references are not suitable as + receivers, though some use might be found for the + facility whereby a higher-level library passes in + pre-weakrefed receiver references. - signal -- the signal to which the receiver should respond - - if Any, receiver will receive any signal from the - indicated sender (which might also be Any, but is not - necessarily Any). - - Otherwise must be a hashable Python object other than - None (DispatcherError raised on None). - - sender -- the sender to which the receiver should respond - - if Any, receiver will receive the indicated signals - from any sender. - - if Anonymous, receiver will only receive indicated - signals from send/sendExact which do not specify a - sender, or specify Anonymous explicitly as the sender. + signal -- the signal to which the receiver should respond + + if Any, receiver will receive any signal from the + indicated sender (which might also be Any, but is not + necessarily Any). + + Otherwise must be a hashable Python object other than + None (DispatcherError raised on None). + + sender -- the sender to which the receiver should respond + + if Any, receiver will receive the indicated signals + from any sender. + + if Anonymous, receiver will only receive indicated + signals from send/sendExact which do not specify a + sender, or specify Anonymous explicitly as the sender. - Otherwise can be any python object. - - weak -- whether to use weak references to the receiver - By default, the module will attempt to use weak - references to the receiver objects. If this parameter - is false, then strong references will be used. + Otherwise can be any python object. + + weak -- whether to use weak references to the receiver + By default, the module will attempt to use weak + references to the receiver objects. If this parameter + is false, then strong references will be used. - returns None, may raise DispatcherTypeError - """ - if signal is None: - raise errors.DispatcherTypeError( - 'Signal cannot be None (receiver=%r sender=%r)'%( receiver,sender) - ) - if weak: - receiver = saferef.safeRef(receiver, onDelete=_removeReceiver) - senderkey = id(sender) - if connections.has_key(senderkey): - signals = connections[senderkey] - else: - connections[senderkey] = signals = {} - # Keep track of senders for cleanup. - # Is Anonymous something we want to clean up? - if sender not in (None, Anonymous, Any): - def remove(object, senderkey=senderkey): - _removeSender(senderkey=senderkey) - # Skip objects that can not be weakly referenced, which means - # they won't be automatically cleaned up, but that's too bad. - try: - weakSender = weakref.ref(sender, remove) - senders[senderkey] = weakSender - except: - pass - - receiverID = id(receiver) - # get current set, remove any current references to - # this receiver in the set, including back-references - if signals.has_key(signal): - receivers = signals[signal] - _removeOldBackRefs(senderkey, signal, receiver, receivers) - else: - receivers = signals[signal] = [] - try: - current = sendersBack.get( receiverID ) - if current is None: - sendersBack[ receiverID ] = current = [] - if senderkey not in current: - current.append(senderkey) - except: - pass + returns None, may raise DispatcherTypeError + """ + if signal is None: + raise errors.DispatcherTypeError( + 'Signal cannot be None (receiver=%r sender=%r)'%( receiver,sender) + ) + if weak: + receiver = saferef.safeRef(receiver, onDelete=_removeReceiver) + senderkey = id(sender) + if connections.has_key(senderkey): + signals = connections[senderkey] + else: + connections[senderkey] = signals = {} + # Keep track of senders for cleanup. + # Is Anonymous something we want to clean up? + if sender not in (None, Anonymous, Any): + def remove(object, senderkey=senderkey): + _removeSender(senderkey=senderkey) + # Skip objects that can not be weakly referenced, which means + # they won't be automatically cleaned up, but that's too bad. + try: + weakSender = weakref.ref(sender, remove) + senders[senderkey] = weakSender + except: + pass + + receiverID = id(receiver) + # get current set, remove any current references to + # this receiver in the set, including back-references + if signals.has_key(signal): + receivers = signals[signal] + _removeOldBackRefs(senderkey, signal, receiver, receivers) + else: + receivers = signals[signal] = [] + try: + current = sendersBack.get( receiverID ) + if current is None: + sendersBack[ receiverID ] = current = [] + if senderkey not in current: + current.append(senderkey) + except: + pass - receivers.append(receiver) + receivers.append(receiver) def disconnect(receiver, signal=Any, sender=Any, weak=True): - """Disconnect receiver from sender for signal + """Disconnect receiver from sender for signal - receiver -- the registered receiver to disconnect - signal -- the registered signal to disconnect - sender -- the registered sender to disconnect - weak -- the weakref state to disconnect + receiver -- the registered receiver to disconnect + signal -- the registered signal to disconnect + sender -- the registered sender to disconnect + weak -- the weakref state to disconnect - disconnect reverses the process of connect, - the semantics for the individual elements are - logically equivalent to a tuple of - (receiver, signal, sender, weak) used as a key - to be deleted from the internal routing tables. - (The actual process is slightly more complex - but the semantics are basically the same). + disconnect reverses the process of connect, + the semantics for the individual elements are + logically equivalent to a tuple of + (receiver, signal, sender, weak) used as a key + to be deleted from the internal routing tables. + (The actual process is slightly more complex + but the semantics are basically the same). - Note: - Using disconnect is not required to cleanup - routing when an object is deleted, the framework - will remove routes for deleted objects - automatically. It's only necessary to disconnect - if you want to stop routing to a live object. - - returns None, may raise DispatcherTypeError or - DispatcherKeyError - """ - if signal is None: - raise errors.DispatcherTypeError( - 'Signal cannot be None (receiver=%r sender=%r)'%( receiver,sender) - ) - if weak: receiver = saferef.safeRef(receiver) - senderkey = id(sender) - try: - signals = connections[senderkey] - receivers = signals[signal] - except KeyError: - raise errors.DispatcherKeyError( - """No receivers found for signal %r from sender %r""" %( - signal, - sender - ) - ) - try: - # also removes from receivers - _removeOldBackRefs(senderkey, signal, receiver, receivers) - except ValueError: - raise errors.DispatcherKeyError( - """No connection to receiver %s for signal %s from sender %s""" %( - receiver, - signal, - sender - ) - ) - _cleanupConnections(senderkey, signal) + Note: + Using disconnect is not required to cleanup + routing when an object is deleted, the framework + will remove routes for deleted objects + automatically. It's only necessary to disconnect + if you want to stop routing to a live object. + + returns None, may raise DispatcherTypeError or + DispatcherKeyError + """ + if signal is None: + raise errors.DispatcherTypeError( + 'Signal cannot be None (receiver=%r sender=%r)'%( receiver,sender) + ) + if weak: receiver = saferef.safeRef(receiver) + senderkey = id(sender) + try: + signals = connections[senderkey] + receivers = signals[signal] + except KeyError: + raise errors.DispatcherKeyError( + """No receivers found for signal %r from sender %r""" %( + signal, + sender + ) + ) + try: + # also removes from receivers + _removeOldBackRefs(senderkey, signal, receiver, receivers) + except ValueError: + raise errors.DispatcherKeyError( + """No connection to receiver %s for signal %s from sender %s""" %( + receiver, + signal, + sender + ) + ) + _cleanupConnections(senderkey, signal) def getReceivers( sender = Any, signal = Any ): - """Get list of receivers from global tables + """Get list of receivers from global tables - This utility function allows you to retrieve the - raw list of receivers from the connections table - for the given sender and signal pair. + This utility function allows you to retrieve the + raw list of receivers from the connections table + for the given sender and signal pair. - Note: - there is no guarantee that this is the actual list - stored in the connections table, so the value - should be treated as a simple iterable/truth value - rather than, for instance a list to which you - might append new records. + Note: + there is no guarantee that this is the actual list + stored in the connections table, so the value + should be treated as a simple iterable/truth value + rather than, for instance a list to which you + might append new records. - Normally you would use liveReceivers( getReceivers( ...)) - to retrieve the actual receiver objects as an iterable - object. - """ - try: - return connections[id(sender)][signal] - except KeyError: - return [] + Normally you would use liveReceivers( getReceivers( ...)) + to retrieve the actual receiver objects as an iterable + object. + """ + try: + return connections[id(sender)][signal] + except KeyError: + return [] def liveReceivers(receivers): - """Filter sequence of receivers to get resolved, live receivers + """Filter sequence of receivers to get resolved, live receivers - This is a generator which will iterate over - the passed sequence, checking for weak references - and resolving them, then returning all live - receivers. - """ - for receiver in receivers: - if isinstance( receiver, WEAKREF_TYPES): - # Dereference the weak reference. - receiver = receiver() - if receiver is not None: - yield receiver - else: - yield receiver + This is a generator which will iterate over + the passed sequence, checking for weak references + and resolving them, then returning all live + receivers. + """ + for receiver in receivers: + if isinstance( receiver, WEAKREF_TYPES): + # Dereference the weak reference. + receiver = receiver() + if receiver is not None: + yield receiver + else: + yield receiver def getAllReceivers( sender = Any, signal = Any ): - """Get list of all receivers from global tables + """Get list of all receivers from global tables - This gets all receivers which should receive - the given signal from sender, each receiver should - be produced only once by the resulting generator - """ - receivers = {} - for set in ( - # Get receivers that receive *this* signal from *this* sender. - getReceivers( sender, signal ), - # Add receivers that receive *any* signal from *this* sender. - getReceivers( sender, Any ), - # Add receivers that receive *this* signal from *any* sender. - getReceivers( Any, signal ), - # Add receivers that receive *any* signal from *any* sender. - getReceivers( Any, Any ), - ): - for receiver in set: - if receiver: # filter out dead instance-method weakrefs - try: - if not receivers.has_key( receiver ): - receivers[receiver] = 1 - yield receiver - except TypeError: - # dead weakrefs raise TypeError on hash... - pass + This gets all receivers which should receive + the given signal from sender, each receiver should + be produced only once by the resulting generator + """ + receivers = {} + for set in ( + # Get receivers that receive *this* signal from *this* sender. + getReceivers( sender, signal ), + # Add receivers that receive *any* signal from *this* sender. + getReceivers( sender, Any ), + # Add receivers that receive *this* signal from *any* sender. + getReceivers( Any, signal ), + # Add receivers that receive *any* signal from *any* sender. + getReceivers( Any, Any ), + ): + for receiver in set: + if receiver: # filter out dead instance-method weakrefs + try: + if not receivers.has_key( receiver ): + receivers[receiver] = 1 + yield receiver + except TypeError: + # dead weakrefs raise TypeError on hash... + pass def send(signal=Any, sender=Anonymous, *arguments, **named): - """Send signal from sender to all connected receivers. - - signal -- (hashable) signal value, see connect for details + """Send signal from sender to all connected receivers. + + signal -- (hashable) signal value, see connect for details - sender -- the sender of the signal - - if Any, only receivers registered for Any will receive - the message. + sender -- the sender of the signal + + if Any, only receivers registered for Any will receive + the message. - if Anonymous, only receivers registered to receive - messages from Anonymous or Any will receive the message + if Anonymous, only receivers registered to receive + messages from Anonymous or Any will receive the message - Otherwise can be any python object (normally one - registered with a connect if you actually want - something to occur). + Otherwise can be any python object (normally one + registered with a connect if you actually want + something to occur). - arguments -- positional arguments which will be passed to - *all* receivers. Note that this may raise TypeErrors - if the receivers do not allow the particular arguments. - Note also that arguments are applied before named - arguments, so they should be used with care. + arguments -- positional arguments which will be passed to + *all* receivers. Note that this may raise TypeErrors + if the receivers do not allow the particular arguments. + Note also that arguments are applied before named + arguments, so they should be used with care. - named -- named arguments which will be filtered according - to the parameters of the receivers to only provide those - acceptable to the receiver. + named -- named arguments which will be filtered according + to the parameters of the receivers to only provide those + acceptable to the receiver. - Return a list of tuple pairs [(receiver, response), ... ] + Return a list of tuple pairs [(receiver, response), ... ] - if any receiver raises an error, the error propagates back - through send, terminating the dispatch loop, so it is quite - possible to not have all receivers called if a raises an - error. - """ - # Call each receiver with whatever arguments it can accept. - # Return a list of tuple pairs [(receiver, response), ... ]. - responses = [] - for receiver in liveReceivers(getAllReceivers(sender, signal)): - response = robustapply.robustApply( - receiver, - signal=signal, - sender=sender, - *arguments, - **named - ) - responses.append((receiver, response)) - return responses + if any receiver raises an error, the error propagates back + through send, terminating the dispatch loop, so it is quite + possible to not have all receivers called if a raises an + error. + """ + # Call each receiver with whatever arguments it can accept. + # Return a list of tuple pairs [(receiver, response), ... ]. + responses = [] + for receiver in liveReceivers(getAllReceivers(sender, signal)): + response = robustapply.robustApply( + receiver, + signal=signal, + sender=sender, + *arguments, + **named + ) + responses.append((receiver, response)) + return responses def sendExact( signal=Any, sender=Anonymous, *arguments, **named ): - """Send signal only to those receivers registered for exact message + """Send signal only to those receivers registered for exact message - sendExact allows for avoiding Any/Anonymous registered - handlers, sending only to those receivers explicitly - registered for a particular signal on a particular - sender. - """ - responses = [] - for receiver in liveReceivers(getReceivers(sender, signal)): - response = robustapply.robustApply( - receiver, - signal=signal, - sender=sender, - *arguments, - **named - ) - responses.append((receiver, response)) - return responses - + sendExact allows for avoiding Any/Anonymous registered + handlers, sending only to those receivers explicitly + registered for a particular signal on a particular + sender. + """ + responses = [] + for receiver in liveReceivers(getReceivers(sender, signal)): + response = robustapply.robustApply( + receiver, + signal=signal, + sender=sender, + *arguments, + **named + ) + responses.append((receiver, response)) + return responses + def _removeReceiver(receiver): - """Remove receiver from connections.""" - if not sendersBack: - # During module cleanup the mapping will be replaced with None - return False - backKey = id(receiver) - for senderkey in sendersBack.get(backKey,()): - try: - signals = connections[senderkey].keys() - except KeyError,err: - pass - else: - for signal in signals: - try: - receivers = connections[senderkey][signal] - except KeyError: - pass - else: - try: - receivers.remove( receiver ) - except Exception, err: - pass - _cleanupConnections(senderkey, signal) - try: - del sendersBack[ backKey ] - except KeyError: - pass - + """Remove receiver from connections.""" + if not sendersBack: + # During module cleanup the mapping will be replaced with None + return False + backKey = id(receiver) + for senderkey in sendersBack.get(backKey,()): + try: + signals = connections[senderkey].keys() + except KeyError,err: + pass + else: + for signal in signals: + try: + receivers = connections[senderkey][signal] + except KeyError: + pass + else: + try: + receivers.remove( receiver ) + except Exception, err: + pass + _cleanupConnections(senderkey, signal) + try: + del sendersBack[ backKey ] + except KeyError: + pass + def _cleanupConnections(senderkey, signal): - """Delete any empty signals for senderkey. Delete senderkey if empty.""" - try: - receivers = connections[senderkey][signal] - except: - pass - else: - if not receivers: - # No more connected receivers. Therefore, remove the signal. - try: - signals = connections[senderkey] - except KeyError: - pass - else: - del signals[signal] - if not signals: - # No more signal connections. Therefore, remove the sender. - _removeSender(senderkey) + """Delete any empty signals for senderkey. Delete senderkey if empty.""" + try: + receivers = connections[senderkey][signal] + except: + pass + else: + if not receivers: + # No more connected receivers. Therefore, remove the signal. + try: + signals = connections[senderkey] + except KeyError: + pass + else: + del signals[signal] + if not signals: + # No more signal connections. Therefore, remove the sender. + _removeSender(senderkey) def _removeSender(senderkey): - """Remove senderkey from connections.""" - _removeBackrefs(senderkey) - try: - del connections[senderkey] - except KeyError: - pass - # Senderkey will only be in senders dictionary if sender - # could be weakly referenced. - try: - del senders[senderkey] - except: - pass + """Remove senderkey from connections.""" + _removeBackrefs(senderkey) + try: + del connections[senderkey] + except KeyError: + pass + # Senderkey will only be in senders dictionary if sender + # could be weakly referenced. + try: + del senders[senderkey] + except: + pass def _removeBackrefs( senderkey): - """Remove all back-references to this senderkey""" - try: - signals = connections[senderkey] - except KeyError: - signals = None - else: - items = signals.items() - def allReceivers( ): - for signal,set in items: - for item in set: - yield item - for receiver in allReceivers(): - _killBackref( receiver, senderkey ) + """Remove all back-references to this senderkey""" + try: + signals = connections[senderkey] + except KeyError: + signals = None + else: + items = signals.items() + def allReceivers( ): + for signal,set in items: + for item in set: + yield item + for receiver in allReceivers(): + _killBackref( receiver, senderkey ) def _removeOldBackRefs(senderkey, signal, receiver, receivers): - """Kill old sendersBack references from receiver + """Kill old sendersBack references from receiver - This guards against multiple registration of the same - receiver for a given signal and sender leaking memory - as old back reference records build up. + This guards against multiple registration of the same + receiver for a given signal and sender leaking memory + as old back reference records build up. - Also removes old receiver instance from receivers - """ - try: - index = receivers.index(receiver) - # need to scan back references here and remove senderkey - except ValueError: - return False - else: - oldReceiver = receivers[index] - del receivers[index] - found = 0 - signals = connections.get(signal) - if signals is not None: - for sig,recs in connections.get(signal,{}).iteritems(): - if sig != signal: - for rec in recs: - if rec is oldReceiver: - found = 1 - break - if not found: - _killBackref( oldReceiver, senderkey ) - return True - return False - - + Also removes old receiver instance from receivers + """ + try: + index = receivers.index(receiver) + # need to scan back references here and remove senderkey + except ValueError: + return False + else: + oldReceiver = receivers[index] + del receivers[index] + found = 0 + signals = connections.get(signal) + if signals is not None: + for sig,recs in connections.get(signal,{}).iteritems(): + if sig != signal: + for rec in recs: + if rec is oldReceiver: + found = 1 + break + if not found: + _killBackref( oldReceiver, senderkey ) + return True + return False + + def _killBackref( receiver, senderkey ): - """Do the actual removal of back reference from receiver to senderkey""" - receiverkey = id(receiver) - set = sendersBack.get( receiverkey, () ) - while senderkey in set: - try: - set.remove( senderkey ) - except: - break - if not set: - try: - del sendersBack[ receiverkey ] - except KeyError: - pass - return True + """Do the actual removal of back reference from receiver to senderkey""" + receiverkey = id(receiver) + set = sendersBack.get( receiverkey, () ) + while senderkey in set: + try: + set.remove( senderkey ) + except: + break + if not set: + try: + del sendersBack[ receiverkey ] + except KeyError: + pass + return True diff --git a/django/dispatch/errors.py b/django/dispatch/errors.py index a2eb32ed75..a4c924dbe9 100644 --- a/django/dispatch/errors.py +++ b/django/dispatch/errors.py @@ -2,9 +2,9 @@ """ class DispatcherError(Exception): - """Base class for all Dispatcher errors""" + """Base class for all Dispatcher errors""" class DispatcherKeyError(KeyError, DispatcherError): - """Error raised when unknown (sender,signal) set specified""" + """Error raised when unknown (sender,signal) set specified""" class DispatcherTypeError(TypeError, DispatcherError): - """Error raised when inappropriate signal-type specified (None)""" + """Error raised when inappropriate signal-type specified (None)""" diff --git a/django/dispatch/license.txt b/django/dispatch/license.txt index 2f0b6b5ef2..8ff5d28613 100644 --- a/django/dispatch/license.txt +++ b/django/dispatch/license.txt @@ -1,34 +1,34 @@ PyDispatcher License - Copyright (c) 2001-2003, Patrick K. O'Brien and Contributors - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - The name of Patrick K. O'Brien, or the name of any Contributor, - may not be used to endorse or promote products derived from this - software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - OF THE POSSIBILITY OF SUCH DAMAGE. + Copyright (c) 2001-2003, Patrick K. O'Brien and Contributors + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + The name of Patrick K. O'Brien, or the name of any Contributor, + may not be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/django/dispatch/robust.py b/django/dispatch/robust.py index ba19934d43..8b1590de35 100644 --- a/django/dispatch/robust.py +++ b/django/dispatch/robust.py @@ -3,55 +3,55 @@ from django.dispatch.dispatcher import Any, Anonymous, liveReceivers, getAllRece from django.dispatch.robustapply import robustApply def sendRobust( - signal=Any, - sender=Anonymous, - *arguments, **named + signal=Any, + sender=Anonymous, + *arguments, **named ): - """Send signal from sender to all connected receivers catching errors - - signal -- (hashable) signal value, see connect for details + """Send signal from sender to all connected receivers catching errors + + signal -- (hashable) signal value, see connect for details - sender -- the sender of the signal - - if Any, only receivers registered for Any will receive - the message. + sender -- the sender of the signal + + if Any, only receivers registered for Any will receive + the message. - if Anonymous, only receivers registered to receive - messages from Anonymous or Any will receive the message + if Anonymous, only receivers registered to receive + messages from Anonymous or Any will receive the message - Otherwise can be any python object (normally one - registered with a connect if you actually want - something to occur). + Otherwise can be any python object (normally one + registered with a connect if you actually want + something to occur). - arguments -- positional arguments which will be passed to - *all* receivers. Note that this may raise TypeErrors - if the receivers do not allow the particular arguments. - Note also that arguments are applied before named - arguments, so they should be used with care. + arguments -- positional arguments which will be passed to + *all* receivers. Note that this may raise TypeErrors + if the receivers do not allow the particular arguments. + Note also that arguments are applied before named + arguments, so they should be used with care. - named -- named arguments which will be filtered according - to the parameters of the receivers to only provide those - acceptable to the receiver. + named -- named arguments which will be filtered according + to the parameters of the receivers to only provide those + acceptable to the receiver. - Return a list of tuple pairs [(receiver, response), ... ] + Return a list of tuple pairs [(receiver, response), ... ] - if any receiver raises an error (specifically any subclass of Exception), - the error instance is returned as the result for that receiver. - """ - # Call each receiver with whatever arguments it can accept. - # Return a list of tuple pairs [(receiver, response), ... ]. - responses = [] - for receiver in liveReceivers(getAllReceivers(sender, signal)): - try: - response = robustApply( - receiver, - signal=signal, - sender=sender, - *arguments, - **named - ) - except Exception, err: - responses.append((receiver, err)) - else: - responses.append((receiver, response)) - return responses + if any receiver raises an error (specifically any subclass of Exception), + the error instance is returned as the result for that receiver. + """ + # Call each receiver with whatever arguments it can accept. + # Return a list of tuple pairs [(receiver, response), ... ]. + responses = [] + for receiver in liveReceivers(getAllReceivers(sender, signal)): + try: + response = robustApply( + receiver, + signal=signal, + sender=sender, + *arguments, + **named + ) + except Exception, err: + responses.append((receiver, err)) + else: + responses.append((receiver, response)) + return responses diff --git a/django/dispatch/robustapply.py b/django/dispatch/robustapply.py index 0350e60cfc..14ba2b51ac 100644 --- a/django/dispatch/robustapply.py +++ b/django/dispatch/robustapply.py @@ -7,43 +7,41 @@ those which are acceptable. """ def function( receiver ): - """Get function-like callable object for given receiver + """Get function-like callable object for given receiver - returns (function_or_method, codeObject, fromMethod) + returns (function_or_method, codeObject, fromMethod) - If fromMethod is true, then the callable already - has its first argument bound - """ - if hasattr(receiver, '__call__'): - # receiver is a class instance; assume it is callable. - # Reassign receiver to the actual method that will be called. - if hasattr( receiver.__call__, 'im_func') or hasattr( receiver.__call__, 'im_code'): - receiver = receiver.__call__ - if hasattr( receiver, 'im_func' ): - # an instance-method... - return receiver, receiver.im_func.func_code, 1 - elif not hasattr( receiver, 'func_code'): - raise ValueError('unknown reciever type %s %s'%(receiver, type(receiver))) - return receiver, receiver.func_code, 0 + If fromMethod is true, then the callable already + has its first argument bound + """ + if hasattr(receiver, '__call__'): + # receiver is a class instance; assume it is callable. + # Reassign receiver to the actual method that will be called. + if hasattr( receiver.__call__, 'im_func') or hasattr( receiver.__call__, 'im_code'): + receiver = receiver.__call__ + if hasattr( receiver, 'im_func' ): + # an instance-method... + return receiver, receiver.im_func.func_code, 1 + elif not hasattr( receiver, 'func_code'): + raise ValueError('unknown reciever type %s %s'%(receiver, type(receiver))) + return receiver, receiver.func_code, 0 def robustApply(receiver, *arguments, **named): - """Call receiver with arguments and an appropriate subset of named - """ - receiver, codeObject, startIndex = function( receiver ) - acceptable = codeObject.co_varnames[startIndex+len(arguments):codeObject.co_argcount] - for name in codeObject.co_varnames[startIndex:startIndex+len(arguments)]: - if named.has_key( name ): - raise TypeError( - """Argument %r specified both positionally and as a keyword for calling %r"""% ( - name, receiver, - ) - ) - if not (codeObject.co_flags & 8): - # fc does not have a **kwds type parameter, therefore - # remove unacceptable arguments. - for arg in named.keys(): - if arg not in acceptable: - del named[arg] - return receiver(*arguments, **named) - -
\ No newline at end of file + """Call receiver with arguments and an appropriate subset of named + """ + receiver, codeObject, startIndex = function( receiver ) + acceptable = codeObject.co_varnames[startIndex+len(arguments):codeObject.co_argcount] + for name in codeObject.co_varnames[startIndex:startIndex+len(arguments)]: + if named.has_key( name ): + raise TypeError( + """Argument %r specified both positionally and as a keyword for calling %r"""% ( + name, receiver, + ) + ) + if not (codeObject.co_flags & 8): + # fc does not have a **kwds type parameter, therefore + # remove unacceptable arguments. + for arg in named.keys(): + if arg not in acceptable: + del named[arg] + return receiver(*arguments, **named) diff --git a/django/dispatch/saferef.py b/django/dispatch/saferef.py index 6b3eda1d38..74b7a41942 100644 --- a/django/dispatch/saferef.py +++ b/django/dispatch/saferef.py @@ -2,164 +2,164 @@ import weakref, traceback def safeRef(target, onDelete = None): - """Return a *safe* weak reference to a callable target + """Return a *safe* weak reference to a callable target - target -- the object to be weakly referenced, if it's a - bound method reference, will create a BoundMethodWeakref, - otherwise creates a simple weakref. - onDelete -- if provided, will have a hard reference stored - to the callable to be called after the safe reference - goes out of scope with the reference object, (either a - weakref or a BoundMethodWeakref) as argument. - """ - if hasattr(target, 'im_self'): - if target.im_self is not None: - # Turn a bound method into a BoundMethodWeakref instance. - # Keep track of these instances for lookup by disconnect(). - assert hasattr(target, 'im_func'), """safeRef target %r has im_self, but no im_func, don't know how to create reference"""%( target,) - reference = BoundMethodWeakref( - target=target, - onDelete=onDelete - ) - return reference - if callable(onDelete): - return weakref.ref(target, onDelete) - else: - return weakref.ref( target ) + target -- the object to be weakly referenced, if it's a + bound method reference, will create a BoundMethodWeakref, + otherwise creates a simple weakref. + onDelete -- if provided, will have a hard reference stored + to the callable to be called after the safe reference + goes out of scope with the reference object, (either a + weakref or a BoundMethodWeakref) as argument. + """ + if hasattr(target, 'im_self'): + if target.im_self is not None: + # Turn a bound method into a BoundMethodWeakref instance. + # Keep track of these instances for lookup by disconnect(). + assert hasattr(target, 'im_func'), """safeRef target %r has im_self, but no im_func, don't know how to create reference"""%( target,) + reference = BoundMethodWeakref( + target=target, + onDelete=onDelete + ) + return reference + if callable(onDelete): + return weakref.ref(target, onDelete) + else: + return weakref.ref( target ) class BoundMethodWeakref(object): - """'Safe' and reusable weak references to instance methods + """'Safe' and reusable weak references to instance methods - BoundMethodWeakref objects provide a mechanism for - referencing a bound method without requiring that the - method object itself (which is normally a transient - object) is kept alive. Instead, the BoundMethodWeakref - object keeps weak references to both the object and the - function which together define the instance method. + BoundMethodWeakref objects provide a mechanism for + referencing a bound method without requiring that the + method object itself (which is normally a transient + object) is kept alive. Instead, the BoundMethodWeakref + object keeps weak references to both the object and the + function which together define the instance method. - Attributes: - key -- the identity key for the reference, calculated - by the class's calculateKey method applied to the - target instance method - deletionMethods -- sequence of callable objects taking - single argument, a reference to this object which - will be called when *either* the target object or - target function is garbage collected (i.e. when - this object becomes invalid). These are specified - as the onDelete parameters of safeRef calls. - weakSelf -- weak reference to the target object - weakFunc -- weak reference to the target function + Attributes: + key -- the identity key for the reference, calculated + by the class's calculateKey method applied to the + target instance method + deletionMethods -- sequence of callable objects taking + single argument, a reference to this object which + will be called when *either* the target object or + target function is garbage collected (i.e. when + this object becomes invalid). These are specified + as the onDelete parameters of safeRef calls. + weakSelf -- weak reference to the target object + weakFunc -- weak reference to the target function - Class Attributes: - _allInstances -- class attribute pointing to all live - BoundMethodWeakref objects indexed by the class's - calculateKey(target) method applied to the target - objects. This weak value dictionary is used to - short-circuit creation so that multiple references - to the same (object, function) pair produce the - same BoundMethodWeakref instance. + Class Attributes: + _allInstances -- class attribute pointing to all live + BoundMethodWeakref objects indexed by the class's + calculateKey(target) method applied to the target + objects. This weak value dictionary is used to + short-circuit creation so that multiple references + to the same (object, function) pair produce the + same BoundMethodWeakref instance. - """ - _allInstances = weakref.WeakValueDictionary() - def __new__( cls, target, onDelete=None, *arguments,**named ): - """Create new instance or return current instance + """ + _allInstances = weakref.WeakValueDictionary() + def __new__( cls, target, onDelete=None, *arguments,**named ): + """Create new instance or return current instance - Basically this method of construction allows us to - short-circuit creation of references to already- - referenced instance methods. The key corresponding - to the target is calculated, and if there is already - an existing reference, that is returned, with its - deletionMethods attribute updated. Otherwise the - new instance is created and registered in the table - of already-referenced methods. - """ - key = cls.calculateKey(target) - current =cls._allInstances.get(key) - if current is not None: - current.deletionMethods.append( onDelete) - return current - else: - base = super( BoundMethodWeakref, cls).__new__( cls ) - cls._allInstances[key] = base - base.__init__( target, onDelete, *arguments,**named) - return base - def __init__(self, target, onDelete=None): - """Return a weak-reference-like instance for a bound method + Basically this method of construction allows us to + short-circuit creation of references to already- + referenced instance methods. The key corresponding + to the target is calculated, and if there is already + an existing reference, that is returned, with its + deletionMethods attribute updated. Otherwise the + new instance is created and registered in the table + of already-referenced methods. + """ + key = cls.calculateKey(target) + current =cls._allInstances.get(key) + if current is not None: + current.deletionMethods.append( onDelete) + return current + else: + base = super( BoundMethodWeakref, cls).__new__( cls ) + cls._allInstances[key] = base + base.__init__( target, onDelete, *arguments,**named) + return base + def __init__(self, target, onDelete=None): + """Return a weak-reference-like instance for a bound method - target -- the instance-method target for the weak - reference, must have im_self and im_func attributes - and be reconstructable via: - target.im_func.__get__( target.im_self ) - which is true of built-in instance methods. - onDelete -- optional callback which will be called - when this weak reference ceases to be valid - (i.e. either the object or the function is garbage - collected). Should take a single argument, - which will be passed a pointer to this object. - """ - def remove(weak, self=self): - """Set self.isDead to true when method or instance is destroyed""" - methods = self.deletionMethods[:] - del self.deletionMethods[:] - try: - del self.__class__._allInstances[ self.key ] - except KeyError: - pass - for function in methods: - try: - if callable( function ): - function( self ) - except Exception, e: - try: - traceback.print_exc() - except AttributeError, err: - print '''Exception during saferef %s cleanup function %s: %s'''%( - self, function, e - ) - self.deletionMethods = [onDelete] - self.key = self.calculateKey( target ) - self.weakSelf = weakref.ref(target.im_self, remove) - self.weakFunc = weakref.ref(target.im_func, remove) - self.selfName = str(target.im_self) - self.funcName = str(target.im_func.__name__) - def calculateKey( cls, target ): - """Calculate the reference key for this reference + target -- the instance-method target for the weak + reference, must have im_self and im_func attributes + and be reconstructable via: + target.im_func.__get__( target.im_self ) + which is true of built-in instance methods. + onDelete -- optional callback which will be called + when this weak reference ceases to be valid + (i.e. either the object or the function is garbage + collected). Should take a single argument, + which will be passed a pointer to this object. + """ + def remove(weak, self=self): + """Set self.isDead to true when method or instance is destroyed""" + methods = self.deletionMethods[:] + del self.deletionMethods[:] + try: + del self.__class__._allInstances[ self.key ] + except KeyError: + pass + for function in methods: + try: + if callable( function ): + function( self ) + except Exception, e: + try: + traceback.print_exc() + except AttributeError, err: + print '''Exception during saferef %s cleanup function %s: %s'''%( + self, function, e + ) + self.deletionMethods = [onDelete] + self.key = self.calculateKey( target ) + self.weakSelf = weakref.ref(target.im_self, remove) + self.weakFunc = weakref.ref(target.im_func, remove) + self.selfName = str(target.im_self) + self.funcName = str(target.im_func.__name__) + def calculateKey( cls, target ): + """Calculate the reference key for this reference - Currently this is a two-tuple of the id()'s of the - target object and the target function respectively. - """ - return (id(target.im_self),id(target.im_func)) - calculateKey = classmethod( calculateKey ) - def __str__(self): - """Give a friendly representation of the object""" - return """%s( %s.%s )"""%( - self.__class__.__name__, - self.selfName, - self.funcName, - ) - __repr__ = __str__ - def __nonzero__( self ): - """Whether we are still a valid reference""" - return self() is not None - def __cmp__( self, other ): - """Compare with another reference""" - if not isinstance (other,self.__class__): - return cmp( self.__class__, type(other) ) - return cmp( self.key, other.key) - def __call__(self): - """Return a strong reference to the bound method + Currently this is a two-tuple of the id()'s of the + target object and the target function respectively. + """ + return (id(target.im_self),id(target.im_func)) + calculateKey = classmethod( calculateKey ) + def __str__(self): + """Give a friendly representation of the object""" + return """%s( %s.%s )"""%( + self.__class__.__name__, + self.selfName, + self.funcName, + ) + __repr__ = __str__ + def __nonzero__( self ): + """Whether we are still a valid reference""" + return self() is not None + def __cmp__( self, other ): + """Compare with another reference""" + if not isinstance (other,self.__class__): + return cmp( self.__class__, type(other) ) + return cmp( self.key, other.key) + def __call__(self): + """Return a strong reference to the bound method - If the target cannot be retrieved, then will - return None, otherwise returns a bound instance - method for our object and function. + If the target cannot be retrieved, then will + return None, otherwise returns a bound instance + method for our object and function. - Note: - You may call this method any number of times, - as it does not invalidate the reference. - """ - target = self.weakSelf() - if target is not None: - function = self.weakFunc() - if function is not None: - return function.__get__(target) - return None + Note: + You may call this method any number of times, + as it does not invalidate the reference. + """ + target = self.weakSelf() + if target is not None: + function = self.weakFunc() + if function is not None: + return function.__get__(target) + return None diff --git a/django/forms/__init__.py b/django/forms/__init__.py index 4907bd76f7..5f47059f03 100644 --- a/django/forms/__init__.py +++ b/django/forms/__init__.py @@ -2,7 +2,7 @@ from django.core import validators from django.core.exceptions import PermissionDenied from django.utils.html import escape from django.conf import settings -from django.utils.translation import gettext, gettext_lazy, ngettext +from django.utils.translation import gettext, ngettext FORM_FIELD_ID_PREFIX = 'id_' @@ -54,6 +54,7 @@ class Manipulator(object): def get_validation_errors(self, new_data): "Returns dictionary mapping field_names to error-message lists" errors = {} + self.prepare(new_data) for field in self.fields: errors.update(field.get_validation_errors(new_data)) val_name = 'validate_%s' % field.field_name @@ -343,7 +344,7 @@ class FormField(object): def get_validation_errors(self, new_data): errors = {} if self.is_required and not new_data.get(self.field_name, False): - errors.setdefault(self.field_name, []).append(gettext_lazy('This field is required.')) + errors.setdefault(self.field_name, []).append(gettext('This field is required.')) return errors try: for validator in self.validator_list: @@ -434,10 +435,12 @@ class HiddenField(FormField): (self.get_id(), self.field_name, escape(data)) class CheckboxField(FormField): - def __init__(self, field_name, checked_by_default=False): + def __init__(self, field_name, checked_by_default=False, validator_list=None, is_required=False): + if validator_list is None: validator_list = [] self.field_name = field_name self.checked_by_default = checked_by_default - self.is_required, self.validator_list = False, [] # because the validator looks for these + self.is_required = is_required + self.validator_list = validator_list[:] def render(self, data): checked_html = '' @@ -636,9 +639,9 @@ class CheckboxSelectMultipleField(SelectMultipleField): if str(value) in str_data_list: checked_html = ' checked="checked"' field_name = '%s%s' % (self.field_name, value) - output.append('<li><input type="checkbox" id="%s" class="v%s" name="%s"%s /> <label for="%s">%s</label></li>' % \ - (self.get_id() + value , self.__class__.__name__, field_name, checked_html, - self.get_id() + value, choice)) + output.append('<li><input type="checkbox" id="%s" class="v%s" name="%s"%s value="on" /> <label for="%s">%s</label></li>' % \ + (self.get_id() + escape(value), self.__class__.__name__, field_name, checked_html, + self.get_id() + escape(value), choice)) output.append('</ul>') return '\n'.join(output) @@ -741,7 +744,7 @@ class FloatField(TextField): if validator_list is None: validator_list = [] self.max_digits, self.decimal_places = max_digits, decimal_places validator_list = [self.isValidFloat] + validator_list - TextField.__init__(self, field_name, max_digits+1, max_digits+1, is_required, validator_list) + TextField.__init__(self, field_name, max_digits+2, max_digits+2, is_required, validator_list) def isValidFloat(self, field_data, all_data): v = validators.IsValidFloat(self.max_digits, self.decimal_places) @@ -950,10 +953,7 @@ class USStateField(TextField): raise validators.CriticalValidationError, e.messages def html2python(data): - if data: - return data.upper() # Should always be stored in upper case - else: - return None + return data.upper() # Should always be stored in upper case html2python = staticmethod(html2python) class CommaSeparatedIntegerField(TextField): @@ -970,9 +970,19 @@ class CommaSeparatedIntegerField(TextField): except validators.ValidationError, e: raise validators.CriticalValidationError, e.messages + def render(self, data): + if data is None: + data = '' + elif isinstance(data, (list, tuple)): + data = ','.join(data) + return super(CommaSeparatedIntegerField, self).render(data) + class RawIdAdminField(CommaSeparatedIntegerField): def html2python(data): - return data.split(',') + if data: + return data.split(',') + else: + return [] html2python = staticmethod(html2python) class XMLLargeTextField(LargeTextField): diff --git a/django/http/__init__.py b/django/http/__init__.py index 8fb4b293fc..bb0e973aae 100644 --- a/django/http/__init__.py +++ b/django/http/__init__.py @@ -1,3 +1,4 @@ +import os from Cookie import SimpleCookie from pprint import pformat from urllib import urlencode, quote @@ -38,6 +39,9 @@ class HttpRequest(object): def get_full_path(self): return '' + def is_secure(self): + return os.environ.get("HTTPS") == "on" + def parse_file_upload(header_dict, post_data): "Returns a tuple of (POST MultiValueDict, FILES MultiValueDict)" import email, email.Message @@ -157,10 +161,10 @@ class HttpResponse(object): if not mimetype: mimetype = "%s; charset=%s" % (settings.DEFAULT_CONTENT_TYPE, settings.DEFAULT_CHARSET) if hasattr(content, '__iter__'): - self._iterator = content + self._container = content self._is_string = False else: - self._iterator = [content] + self._container = [content] self._is_string = True self.headers = {'Content-Type': mimetype} self.cookies = SimpleCookie() @@ -199,39 +203,47 @@ class HttpResponse(object): if val is not None: self.cookies[key][var.replace('_', '-')] = val - def delete_cookie(self, key): - try: - self.cookies[key]['max_age'] = 0 - except KeyError: - pass + def delete_cookie(self, key, path='/', domain=None): + self.cookies[key] = '' + if path is not None: + self.cookies[key]['path'] = path + if domain is not None: + self.cookies[key]['domain'] = path + self.cookies[key]['expires'] = 0 + self.cookies[key]['max-age'] = 0 def _get_content(self): - content = ''.join(self._iterator) + content = ''.join(self._container) if isinstance(content, unicode): content = content.encode(self._charset) return content def _set_content(self, value): - self._iterator = [value] + self._container = [value] self._is_string = True content = property(_get_content, _set_content) - def _get_iterator(self): - "Output iterator. Converts data into client charset if necessary." - for chunk in self._iterator: - if isinstance(chunk, unicode): - chunk = chunk.encode(self._charset) - yield chunk + def __iter__(self): + self._iterator = self._container.__iter__() + return self + + def next(self): + chunk = self._iterator.next() + if isinstance(chunk, unicode): + chunk = chunk.encode(self._charset) + return chunk - iterator = property(_get_iterator) + def close(self): + if hasattr(self._container, 'close'): + self._container.close() # The remaining methods partially implement the file-like object interface. # See http://docs.python.org/lib/bltin-file-objects.html def write(self, content): if not self._is_string: raise Exception, "This %s instance is not writable" % self.__class__ - self._iterator.append(content) + self._container.append(content) def flush(self): pass @@ -239,7 +251,7 @@ class HttpResponse(object): def tell(self): if not self._is_string: raise Exception, "This %s instance cannot tell its position" % self.__class__ - return sum([len(chunk) for chunk in self._iterator]) + return sum([len(chunk) for chunk in self._container]) class HttpResponseRedirect(HttpResponse): def __init__(self, redirect_to): diff --git a/django/middleware/cache.py b/django/middleware/cache.py index 80c8626db8..58800b24da 100644 --- a/django/middleware/cache.py +++ b/django/middleware/cache.py @@ -1,7 +1,6 @@ from django.conf import settings from django.core.cache import cache from django.utils.cache import get_cache_key, learn_cache_key, patch_response_headers -from django.http import HttpResponseNotModified class CacheMiddleware(object): """ @@ -10,6 +9,11 @@ class CacheMiddleware(object): Only parameter-less GET or HEAD-requests with status code 200 are cached. + If CACHE_MIDDLEWARE_ANONYMOUS_ONLY is set to True, only anonymous requests + (i.e., those node made by a logged-in user) will be cached. This is a + simple and effective way of avoiding the caching of the Django admin (and + any other user-specific content). + This middleware expects that a HEAD request is answered with a response exactly like the corresponding GET request. @@ -23,20 +27,31 @@ class CacheMiddleware(object): This middleware also sets ETag, Last-Modified, Expires and Cache-Control headers on the response object. """ - def __init__(self, cache_timeout=None, key_prefix=None): + def __init__(self, cache_timeout=None, key_prefix=None, cache_anonymous_only=None): self.cache_timeout = cache_timeout if cache_timeout is None: self.cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS self.key_prefix = key_prefix if key_prefix is None: self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX + if cache_anonymous_only is None: + self.cache_anonymous_only = getattr(settings, 'CACHE_MIDDLEWARE_ANONYMOUS_ONLY', False) + else: + self.cache_anonymous_only = cache_anonymous_only def process_request(self, request): "Checks whether the page is already cached and returns the cached version if available." + if self.cache_anonymous_only: + assert hasattr(request, 'user'), "The Django cache middleware with CACHE_MIDDLEWARE_ANONYMOUS_ONLY=True requires authentication middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.auth.middleware.AuthenticationMiddleware' before the CacheMiddleware." + if not request.method in ('GET', 'HEAD') or request.GET: request._cache_update_cache = False return None # Don't bother checking the cache. + if self.cache_anonymous_only and request.user.is_authenticated(): + request._cache_update_cache = False + return None # Don't cache requests from authenticated users. + cache_key = get_cache_key(request, self.key_prefix) if cache_key is None: request._cache_update_cache = True diff --git a/django/middleware/common.py b/django/middleware/common.py index a42c54751d..6283214fad 100644 --- a/django/middleware/common.py +++ b/django/middleware/common.py @@ -1,7 +1,8 @@ from django.conf import settings from django import http from django.core.mail import mail_managers -import md5, os +import md5 +import re class CommonMiddleware(object): """ @@ -44,7 +45,7 @@ class CommonMiddleware(object): if new_url != old_url: # Redirect if new_url[0]: - newurl = "%s://%s%s" % (os.environ.get('HTTPS') == 'on' and 'https' or 'http', new_url[0], new_url[1]) + newurl = "%s://%s%s" % (request.is_secure() and 'https' or 'http', new_url[0], new_url[1]) else: newurl = new_url[1] if request.GET: @@ -61,11 +62,12 @@ class CommonMiddleware(object): # send a note to the managers. domain = http.get_host(request) referer = request.META.get('HTTP_REFERER', None) - is_internal = referer and (domain in referer) + is_internal = _is_internal_request(domain, referer) path = request.get_full_path() if referer and not _is_ignorable_404(path) and (is_internal or '?' not in referer): + ua = request.META.get('HTTP_USER_AGENT', '<none>') mail_managers("Broken %slink on %s" % ((is_internal and 'INTERNAL ' or ''), domain), - "Referrer: %s\nRequested URL: %s\n" % (referer, request.get_full_path())) + "Referrer: %s\nRequested URL: %s\nUser agent: %s\n" % (referer, request.get_full_path(), ua)) return response # Use ETags, if requested. @@ -87,3 +89,8 @@ def _is_ignorable_404(uri): if uri.endswith(end): return True return False + +def _is_internal_request(domain, referer): + "Return true if the referring URL is the same domain as the current request" + # Different subdomains are treated as different domains. + return referer is not None and re.match("^https?://%s/" % re.escape(domain), referer) diff --git a/django/middleware/doc.py b/django/middleware/doc.py index 6600e588cd..48c155c392 100644 --- a/django/middleware/doc.py +++ b/django/middleware/doc.py @@ -7,11 +7,12 @@ class XViewMiddleware(object): """ def process_view(self, request, view_func, view_args, view_kwargs): """ - If the request method is HEAD and the IP is internal, quickly return - with an x-header indicating the view function. This is used by the - documentation module to lookup the view function for an arbitrary page. + If the request method is HEAD and either the IP is internal or the + user is a logged-in staff member, quickly return with an x-header + indicating the view function. This is used by the documentation module + to lookup the view function for an arbitrary page. """ - if request.method == 'HEAD' and request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS: + if request.method == 'HEAD' and (request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS or (request.user.is_authenticated() and request.user.is_staff)): response = http.HttpResponse() response['X-View'] = "%s.%s" % (view_func.__module__, view_func.__name__) return response diff --git a/django/middleware/gzip.py b/django/middleware/gzip.py index cc8a68406c..7d860abdb1 100644 --- a/django/middleware/gzip.py +++ b/django/middleware/gzip.py @@ -12,7 +12,11 @@ class GZipMiddleware(object): """ def process_response(self, request, response): patch_vary_headers(response, ('Accept-Encoding',)) - if response.has_header('Content-Encoding'): + + # Avoid gzipping if we've already got a content-encoding or if the + # content-type is Javascript (silly IE...) + is_js = "javascript" in response.headers.get('Content-Type', '').lower() + if response.has_header('Content-Encoding') or is_js: return response ae = request.META.get('HTTP_ACCEPT_ENCODING', '') diff --git a/django/middleware/http.py b/django/middleware/http.py index 12d0c0f683..3ebd8ffd1a 100644 --- a/django/middleware/http.py +++ b/django/middleware/http.py @@ -35,3 +35,27 @@ class ConditionalGetMiddleware(object): response.content = '' return response + +class SetRemoteAddrFromForwardedFor(object): + """ + Middleware that sets REMOTE_ADDR based on HTTP_X_FORWARDED_FOR, if the + latter is set. This is useful if you're sitting behind a reverse proxy that + causes each request's REMOTE_ADDR to be set to 127.0.0.1. + + Note that this does NOT validate HTTP_X_FORWARDED_FOR. If you're not behind + a reverse proxy that sets HTTP_X_FORWARDED_FOR automatically, do not use + this middleware. Anybody can spoof the value of HTTP_X_FORWARDED_FOR, and + because this sets REMOTE_ADDR based on HTTP_X_FORWARDED_FOR, that means + anybody can "fake" their IP address. Only use this when you can absolutely + trust the value of HTTP_X_FORWARDED_FOR. + """ + def process_request(self, request): + try: + real_ip = request.META['HTTP_X_FORWARDED_FOR'] + except KeyError: + return None + else: + # HTTP_X_FORWARDED_FOR can be a comma-separated list of IPs. + # Take just the first one. + real_ip = real_ip.split(",")[0] + request.META['REMOTE_ADDR'] = real_ip diff --git a/django/middleware/transaction.py b/django/middleware/transaction.py index 4128e012f2..96b1538d9d 100644 --- a/django/middleware/transaction.py +++ b/django/middleware/transaction.py @@ -1,4 +1,3 @@ -from django.conf import settings from django.db import transaction class TransactionMiddleware(object): diff --git a/django/template/__init__.py b/django/template/__init__.py index e898fc7636..60526b663d 100644 --- a/django/template/__init__.py +++ b/django/template/__init__.py @@ -66,6 +66,7 @@ __all__ = ('Template', 'Context', 'RequestContext', 'compile_string') TOKEN_TEXT = 0 TOKEN_VAR = 1 TOKEN_BLOCK = 2 +TOKEN_COMMENT = 3 # template syntax constants FILTER_SEPARATOR = '|' @@ -75,6 +76,8 @@ BLOCK_TAG_START = '{%' BLOCK_TAG_END = '%}' VARIABLE_TAG_START = '{{' VARIABLE_TAG_END = '}}' +COMMENT_TAG_START = '{#' +COMMENT_TAG_END = '#}' SINGLE_BRACE_START = '{' SINGLE_BRACE_END = '}' @@ -85,8 +88,9 @@ ALLOWED_VARIABLE_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01 UNKNOWN_SOURCE="<unknown source>" # match a variable or block tag and capture the entire tag, including start/end delimiters -tag_re = re.compile('(%s.*?%s|%s.*?%s)' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END), - re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END))) +tag_re = re.compile('(%s.*?%s|%s.*?%s|%s.*?%s)' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END), + re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END), + re.escape(COMMENT_TAG_START), re.escape(COMMENT_TAG_END))) # global dictionary of libraries that have been loaded using get_library libraries = {} @@ -137,13 +141,14 @@ class StringOrigin(Origin): return self.source class Template(object): - def __init__(self, template_string, origin=None): + def __init__(self, template_string, origin=None, name='<Unknown Template>'): "Compilation stage" if settings.TEMPLATE_DEBUG and origin == None: origin = StringOrigin(template_string) # Could do some crazy stack-frame stuff to record where this string # came from... self.nodelist = compile_string(template_string, origin) + self.name = name def __iter__(self): for node in self.nodelist: @@ -162,12 +167,12 @@ def compile_string(template_string, origin): class Token(object): def __init__(self, token_type, contents): - "The token_type must be TOKEN_TEXT, TOKEN_VAR or TOKEN_BLOCK" + "The token_type must be TOKEN_TEXT, TOKEN_VAR, TOKEN_BLOCK or TOKEN_COMMENT" self.token_type, self.contents = token_type, contents def __str__(self): return '<%s token: "%s...">' % \ - ({TOKEN_TEXT: 'Text', TOKEN_VAR: 'Var', TOKEN_BLOCK: 'Block'}[self.token_type], + ({TOKEN_TEXT: 'Text', TOKEN_VAR: 'Var', TOKEN_BLOCK: 'Block', TOKEN_COMMENT: 'Comment'}[self.token_type], self.contents[:20].replace('\n', '')) def split_contents(self): @@ -190,6 +195,8 @@ class Lexer(object): token = Token(TOKEN_VAR, token_string[len(VARIABLE_TAG_START):-len(VARIABLE_TAG_END)].strip()) elif token_string.startswith(BLOCK_TAG_START): token = Token(TOKEN_BLOCK, token_string[len(BLOCK_TAG_START):-len(BLOCK_TAG_END)].strip()) + elif token_string.startswith(COMMENT_TAG_START): + token = Token(TOKEN_COMMENT, '') else: token = Token(TOKEN_TEXT, token_string) return token @@ -358,7 +365,7 @@ class DebugParser(Parser): super(DebugParser, self).extend_nodelist(nodelist, node, token) def unclosed_block_tag(self, parse_until): - (command, source) = self.command_stack.pop() + command, source = self.command_stack.pop() msg = "Unclosed tag '%s'. Looking for one of: %s " % (command, ', '.join(parse_until)) raise self.source_error( source, msg) @@ -434,7 +441,7 @@ class TokenParser(object): while i < len(subject) and subject[i] != subject[p]: i += 1 if i >= len(subject): - raise TemplateSyntaxError, "Searching for value. Unexpected end of string in column %d: %s" % subject + raise TemplateSyntaxError, "Searching for value. Unexpected end of string in column %d: %s" % (i, subject) i += 1 res = subject[p:i] while i < len(subject) and subject[i] in (' ', '\t'): @@ -531,7 +538,7 @@ class FilterExpression(object): constant_arg, i18n_arg, var_arg = match.group("constant_arg", "i18n_arg", "var_arg") if i18n_arg: args.append((False, _(i18n_arg.replace(r'\"', '"')))) - elif constant_arg: + elif constant_arg is not None: args.append((False, constant_arg.replace(r'\"', '"'))) elif var_arg: args.append((True, var_arg)) @@ -548,9 +555,12 @@ class FilterExpression(object): obj = resolve_variable(self.var, context) except VariableDoesNotExist: if ignore_failures: - return None + obj = None else: - return settings.TEMPLATE_STRING_IF_INVALID + if settings.TEMPLATE_STRING_IF_INVALID: + return settings.TEMPLATE_STRING_IF_INVALID + else: + obj = settings.TEMPLATE_STRING_IF_INVALID for func, args in self.filters: arg_vals = [] for lookup, arg in args: @@ -614,11 +624,7 @@ def resolve_variable(path, context): (The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.') """ - if path == 'False': - current = False - elif path == 'True': - current = True - elif path[0].isdigit(): + if path[0].isdigit(): number_type = '.' in path and float or int try: current = number_type(path) @@ -708,9 +714,9 @@ class DebugNodeList(NodeList): if not hasattr(e, 'source'): e.source = node.source raise - except Exception: + except Exception, e: from sys import exc_info - wrapped = TemplateSyntaxError('Caught an exception while rendering.') + wrapped = TemplateSyntaxError('Caught an exception while rendering: %s' % e) wrapped.source = node.source wrapped.exc_info = exc_info() raise wrapped @@ -817,7 +823,7 @@ class Library(object): self.filters[name] = filter_func return filter_func else: - raise InvalidTemplateLibrary, "Unsupported arguments to Library.filter: (%r, %r, %r)", (name, compile_function, has_arg) + raise InvalidTemplateLibrary, "Unsupported arguments to Library.filter: (%r, %r)", (name, filter_func) def filter_function(self, func): self.filters[func.__name__] = func diff --git a/django/template/defaultfilters.py b/django/template/defaultfilters.py index 5d56ec0c49..cf1d3d5f6d 100644 --- a/django/template/defaultfilters.py +++ b/django/template/defaultfilters.py @@ -15,7 +15,7 @@ register = Library() def addslashes(value): "Adds slashes - useful for passing strings to JavaScript, for example." - return value.replace('"', '\\"').replace("'", "\\'") + return value.replace('\\', '\\\\').replace('"', '\\"').replace("'", "\\'") def capfirst(value): "Capitalizes the first character of the value" @@ -133,7 +133,7 @@ def wordwrap(value, arg): """ Wraps words at specified line length - Argument: number of words to wrap the text at. + Argument: number of characters to wrap the text at. """ from django.utils.text import wrap return wrap(str(value), int(arg)) @@ -339,7 +339,7 @@ def date(value, arg=None): def time(value, arg=None): "Formats a time according to the given format" from django.utils.dateformat import time_format - if not value: + if value in (None, ''): return '' if arg is None: arg = settings.TIME_FORMAT @@ -437,8 +437,8 @@ def pluralize(value, arg='s'): is used instead. If the provided argument contains a comma, the text before the comma is used for the singular case. """ - if not ',' in arg: - arg = ',' + arg + if not ',' in arg: + arg = ',' + arg bits = arg.split(',') if len(bits) > 2: return '' diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py index 0a4fe33d82..07e579bf9d 100644 --- a/django/template/defaulttags.py +++ b/django/template/defaulttags.py @@ -13,14 +13,18 @@ class CommentNode(Node): return '' class CycleNode(Node): - def __init__(self, cyclevars): + def __init__(self, cyclevars, variable_name=None): self.cyclevars = cyclevars self.cyclevars_len = len(cyclevars) self.counter = -1 + self.variable_name = variable_name def render(self, context): self.counter += 1 - return self.cyclevars[self.counter % self.cyclevars_len] + value = self.cyclevars[self.counter % self.cyclevars_len] + if self.variable_name: + context[self.variable_name] = value + return value class DebugNode(Node): def render(self, context): @@ -86,7 +90,7 @@ class ForNode(Node): parentloop = {} context.push() try: - values = self.sequence.resolve(context) + values = self.sequence.resolve(context, True) except VariableDoesNotExist: values = [] if values is None: @@ -125,6 +129,8 @@ class IfChangedNode(Node): self._last_seen = None def render(self, context): + if context.has_key('forloop') and context['forloop']['first']: + self._last_seen = None content = self.nodelist.render(context) if content != self._last_seen: firstloop = (self._last_seen == None) @@ -212,13 +218,13 @@ class RegroupNode(Node): self.var_name = var_name def render(self, context): - obj_list = self.target.resolve(context) - if obj_list == '': # target_var wasn't found in context; fail silently + obj_list = self.target.resolve(context, True) + if obj_list == None: # target_var wasn't found in context; fail silently context[self.var_name] = [] return '' output = [] # list of dictionaries in the format {'grouper': 'key', 'list': [list of contents]} for obj in obj_list: - grouper = self.expression.resolve(Context({'var': obj})) + grouper = self.expression.resolve(Context({'var': obj}), True) # TODO: Is this a sensible way to determine equality? if output and repr(output[-1]['grouper']) == repr(grouper): output[-1]['list'].append(obj) @@ -251,7 +257,7 @@ class SsiNode(Node): output = '' if self.parsed: try: - t = Template(output) + t = Template(output, name=self.filepath) return t.render(context) except TemplateSyntaxError, e: if settings.DEBUG: @@ -385,7 +391,7 @@ def cycle(parser, token): raise TemplateSyntaxError("Second 'cycle' argument must be 'as'") cyclevars = [v for v in args[1].split(",") if v] # split and kill blanks name = args[3] - node = CycleNode(cyclevars) + node = CycleNode(cyclevars, name) if not hasattr(parser, '_namedCycleNodes'): parser._namedCycleNodes = {} diff --git a/django/template/loader.py b/django/template/loader.py index ebca582ef9..03e6f8d49d 100644 --- a/django/template/loader.py +++ b/django/template/loader.py @@ -21,7 +21,7 @@ # installed, because pkg_resources is necessary to read eggs. from django.core.exceptions import ImproperlyConfigured -from django.template import Origin, StringOrigin, Template, Context, TemplateDoesNotExist, add_to_builtins +from django.template import Origin, Template, Context, TemplateDoesNotExist, add_to_builtins from django.conf import settings template_source_loaders = None @@ -76,14 +76,16 @@ def get_template(template_name): Returns a compiled Template object for the given template name, handling template inheritance recursively. """ - return get_template_from_string(*find_template_source(template_name)) + source, origin = find_template_source(template_name) + template = get_template_from_string(source, origin, template_name) + return template -def get_template_from_string(source, origin=None): +def get_template_from_string(source, origin=None, name=None): """ Returns a compiled Template object for the given template code, handling template inheritance recursively. """ - return Template(source, origin) + return Template(source, origin, name) def render_to_string(template_name, dictionary=None, context_instance=None): """ diff --git a/django/template/loader_tags.py b/django/template/loader_tags.py index e0d9a70a98..e329b1bb36 100644 --- a/django/template/loader_tags.py +++ b/django/template/loader_tags.py @@ -1,5 +1,5 @@ from django.template import TemplateSyntaxError, TemplateDoesNotExist, resolve_variable -from django.template import Library, Context, Node +from django.template import Library, Node from django.template.loader import get_template, get_template_from_string, find_template_source from django.conf import settings @@ -50,12 +50,14 @@ class ExtendsNode(Node): if self.parent_name_expr: error_msg += " Got this from the %r variable." % self.parent_name_expr #TODO nice repr. raise TemplateSyntaxError, error_msg + if hasattr(parent, 'render'): + return parent # parent is a Template object try: source, origin = find_template_source(parent, self.template_dirs) except TemplateDoesNotExist: raise TemplateSyntaxError, "Template %r cannot be extended, because it doesn't exist" % parent else: - return get_template_from_string(source, origin) + return get_template_from_string(source, origin, parent) def render(self, context): compiled_parent = self.get_parent(context) @@ -125,7 +127,7 @@ def do_block(parser, token): if block_name in parser.__loaded_blocks: raise TemplateSyntaxError, "'%s' tag with name '%s' appears more than once" % (bits[0], block_name) parser.__loaded_blocks.append(block_name) - except AttributeError: # parser._loaded_blocks isn't a list yet + except AttributeError: # parser.__loaded_blocks isn't a list yet parser.__loaded_blocks = [block_name] nodelist = parser.parse(('endblock',)) parser.delete_first_token() @@ -137,8 +139,9 @@ def do_extends(parser, token): This tag may be used in two ways: ``{% extends "base" %}`` (with quotes) uses the literal value "base" as the name of the parent template to extend, - or ``{% extends variable %}`` uses the value of ``variable`` as the name - of the parent template to extend. + or ``{% extends variable %}`` uses the value of ``variable`` as either the + name of the parent template to extend (if it evaluates to a string,) or as + the parent tempate itelf (if it evaluates to a Template object). """ bits = token.contents.split() if len(bits) != 2: diff --git a/django/template/loaders/filesystem.py b/django/template/loaders/filesystem.py index 0c94021fb8..d01f54c5fe 100644 --- a/django/template/loaders/filesystem.py +++ b/django/template/loaders/filesystem.py @@ -17,7 +17,7 @@ def load_template_source(template_name, template_dirs=None): return (open(filepath).read(), filepath) except IOError: tried.append(filepath) - if template_dirs: + if tried: error_msg = "Tried %s" % tried else: error_msg = "Your TEMPLATE_DIRS setting is empty. Change it to point to at least one template directory." diff --git a/django/templatetags/i18n.py b/django/templatetags/i18n.py index 6718a0fbac..bf6497f9aa 100644 --- a/django/templatetags/i18n.py +++ b/django/templatetags/i18n.py @@ -1,8 +1,7 @@ -from django.template import Node, NodeList, Template, Context, resolve_variable +from django.template import Node, resolve_variable from django.template import TemplateSyntaxError, TokenParser, Library -from django.template import TOKEN_BLOCK, TOKEN_TEXT, TOKEN_VAR +from django.template import TOKEN_TEXT, TOKEN_VAR from django.utils import translation -import re, sys register = Library() @@ -228,7 +227,7 @@ def do_block_translate(parser, token): break if countervar and counter: if token.contents.strip() != 'plural': - raise TemplateSyntaxError, "'blocktrans' doesn't allow other block tags inside it" % tag + raise TemplateSyntaxError, "'blocktrans' doesn't allow other block tags inside it" while parser.tokens: token = parser.next_token() if token.token_type in (TOKEN_VAR, TOKEN_TEXT): diff --git a/tests/othertests/__init__.py b/django/test/__init__.py index e69de29bb2..e69de29bb2 100644 --- a/tests/othertests/__init__.py +++ b/django/test/__init__.py diff --git a/django/test/client.py b/django/test/client.py new file mode 100644 index 0000000000..6e0b443f83 --- /dev/null +++ b/django/test/client.py @@ -0,0 +1,216 @@ +from cStringIO import StringIO +from django.core.handlers.base import BaseHandler +from django.core.handlers.wsgi import WSGIRequest +from django.dispatch import dispatcher +from django.http import urlencode, SimpleCookie +from django.test import signals +from django.utils.functional import curry + +class ClientHandler(BaseHandler): + """ + A HTTP Handler that can be used for testing purposes. + Uses the WSGI interface to compose requests, but returns + the raw HttpResponse object + """ + def __call__(self, environ): + from django.conf import settings + from django.core import signals + + # Set up middleware if needed. We couldn't do this earlier, because + # settings weren't available. + if self._request_middleware is None: + self.load_middleware() + + dispatcher.send(signal=signals.request_started) + try: + request = WSGIRequest(environ) + response = self.get_response(request) + + # Apply response middleware + for middleware_method in self._response_middleware: + response = middleware_method(request, response) + + finally: + dispatcher.send(signal=signals.request_finished) + + return response + +def store_rendered_templates(store, signal, sender, template, context): + "A utility function for storing templates and contexts that are rendered" + store.setdefault('template',[]).append(template) + store.setdefault('context',[]).append(context) + +def encode_multipart(boundary, data): + """ + A simple method for encoding multipart POST data from a dictionary of + form values. + + The key will be used as the form data name; the value will be transmitted + as content. If the value is a file, the contents of the file will be sent + as an application/octet-stream; otherwise, str(value) will be sent. + """ + lines = [] + for (key, value) in data.items(): + if isinstance(value, file): + lines.extend([ + '--' + boundary, + 'Content-Disposition: form-data; name="%s"' % key, + '', + '--' + boundary, + 'Content-Disposition: form-data; name="%s_file"; filename="%s"' % (key, value.name), + 'Content-Type: application/octet-stream', + '', + value.read() + ]) + else: + lines.extend([ + '--' + boundary, + 'Content-Disposition: form-data; name="%s"' % key, + '', + str(value) + ]) + + lines.extend([ + '--' + boundary + '--', + '', + ]) + return '\r\n'.join(lines) + +class Client: + """ + A class that can act as a client for testing purposes. + + It allows the user to compose GET and POST requests, and + obtain the response that the server gave to those requests. + The server Response objects are annotated with the details + of the contexts and templates that were rendered during the + process of serving the request. + + Client objects are stateful - they will retain cookie (and + thus session) details for the lifetime of the Client instance. + + This is not intended as a replacement for Twill/Selenium or + the like - it is here to allow testing against the + contexts and templates produced by a view, rather than the + HTML rendered to the end-user. + """ + def __init__(self, **defaults): + self.handler = ClientHandler() + self.defaults = defaults + self.cookie = SimpleCookie() + + def request(self, **request): + """ + The master request method. Composes the environment dictionary + and passes to the handler, returning the result of the handler. + Assumes defaults for the query environment, which can be overridden + using the arguments to the request. + """ + + environ = { + 'HTTP_COOKIE': self.cookie, + 'PATH_INFO': '/', + 'QUERY_STRING': '', + 'REQUEST_METHOD': 'GET', + 'SCRIPT_NAME': None, + 'SERVER_NAME': 'testserver', + 'SERVER_PORT': 80, + 'SERVER_PROTOCOL': 'HTTP/1.1', + } + environ.update(self.defaults) + environ.update(request) + + # Curry a data dictionary into an instance of + # the template renderer callback function + data = {} + on_template_render = curry(store_rendered_templates, data) + dispatcher.connect(on_template_render, signal=signals.template_rendered) + + response = self.handler(environ) + + # Add any rendered template detail to the response + # If there was only one template rendered (the most likely case), + # flatten the list to a single element + for detail in ('template', 'context'): + if data.get(detail): + if len(data[detail]) == 1: + setattr(response, detail, data[detail][0]); + else: + setattr(response, detail, data[detail]) + else: + setattr(response, detail, None) + + if response.cookies: + self.cookie.update(response.cookies) + + return response + + def get(self, path, data={}, **extra): + "Request a response from the server using GET." + r = { + 'CONTENT_LENGTH': None, + 'CONTENT_TYPE': 'text/html; charset=utf-8', + 'PATH_INFO': path, + 'QUERY_STRING': urlencode(data), + 'REQUEST_METHOD': 'GET', + } + r.update(extra) + + return self.request(**r) + + def post(self, path, data={}, **extra): + "Request a response from the server using POST." + + BOUNDARY = 'BoUnDaRyStRiNg' + + encoded = encode_multipart(BOUNDARY, data) + stream = StringIO(encoded) + r = { + 'CONTENT_LENGTH': len(encoded), + 'CONTENT_TYPE': 'multipart/form-data; boundary=%s' % BOUNDARY, + 'PATH_INFO': path, + 'REQUEST_METHOD': 'POST', + 'wsgi.input': stream, + } + r.update(extra) + + return self.request(**r) + + def login(self, path, username, password, **extra): + """ + A specialized sequence of GET and POST to log into a view that + is protected by a @login_required access decorator. + + path should be the URL of the page that is login protected. + + Returns the response from GETting the requested URL after + login is complete. Returns False if login process failed. + """ + # First, GET the page that is login protected. + # This page will redirect to the login page. + response = self.get(path) + if response.status_code != 302: + return False + + login_path, data = response['Location'].split('?') + next = data.split('=')[1] + + # Second, GET the login page; required to set up cookies + response = self.get(login_path, **extra) + if response.status_code != 200: + return False + + # Last, POST the login data. + form_data = { + 'username': username, + 'password': password, + 'next' : next, + } + response = self.post(login_path, data=form_data, **extra) + + # Login page should 302 redirect to the originally requested page + if response.status_code != 302 or response['Location'] != path: + return False + + # Since we are logged in, request the actual page again + return self.get(path) diff --git a/tests/doctest.py b/django/test/doctest.py index df7aa978d3..3b364f0a75 100644 --- a/tests/doctest.py +++ b/django/test/doctest.py @@ -1319,13 +1319,16 @@ class DocTestRunner: __LINECACHE_FILENAME_RE = re.compile(r'<doctest ' r'(?P<name>[\w\.]+)' r'\[(?P<examplenum>\d+)\]>$') - def __patched_linecache_getlines(self, filename): + def __patched_linecache_getlines(self, filename, module_globals=None): m = self.__LINECACHE_FILENAME_RE.match(filename) if m and m.group('name') == self.test.name: example = self.test.examples[int(m.group('examplenum'))] return example.source.splitlines(True) else: - return self.save_linecache_getlines(filename) + if sys.version_info < (2, 5, 0): + return self.save_linecache_getlines(filename) + else: + return self.save_linecache_getlines(filename, module_globals) def run(self, test, compileflags=None, out=None, clear_globs=True): """ @@ -2104,7 +2107,7 @@ def set_unittest_reportflags(flags): class DocTestCase(unittest.TestCase): def __init__(self, test, optionflags=0, setUp=None, tearDown=None, - checker=None): + checker=None, runner=DocTestRunner): unittest.TestCase.__init__(self) self._dt_optionflags = optionflags @@ -2112,6 +2115,7 @@ class DocTestCase(unittest.TestCase): self._dt_test = test self._dt_setUp = setUp self._dt_tearDown = tearDown + self._dt_runner = runner def setUp(self): test = self._dt_test @@ -2138,8 +2142,8 @@ class DocTestCase(unittest.TestCase): # so add the default reporting flags optionflags |= _unittest_reportflags - runner = DocTestRunner(optionflags=optionflags, - checker=self._dt_checker, verbose=False) + runner = self._dt_runner(optionflags=optionflags, + checker=self._dt_checker, verbose=False) try: runner.DIVIDER = "-"*70 @@ -2248,7 +2252,7 @@ class DocTestCase(unittest.TestCase): return "Doctest: " + self._dt_test.name def DocTestSuite(module=None, globs=None, extraglobs=None, test_finder=None, - **options): + test_class=DocTestCase, **options): """ Convert doctest tests for a module to a unittest test suite. @@ -2306,7 +2310,7 @@ def DocTestSuite(module=None, globs=None, extraglobs=None, test_finder=None, if filename[-4:] in (".pyc", ".pyo"): filename = filename[:-1] test.filename = filename - suite.addTest(DocTestCase(test, **options)) + suite.addTest(test_class(test, **options)) return suite diff --git a/django/test/signals.py b/django/test/signals.py new file mode 100644 index 0000000000..40748ff4fe --- /dev/null +++ b/django/test/signals.py @@ -0,0 +1 @@ +template_rendered = object()
\ No newline at end of file diff --git a/django/test/simple.py b/django/test/simple.py new file mode 100644 index 0000000000..628fa464d2 --- /dev/null +++ b/django/test/simple.py @@ -0,0 +1,85 @@ +import unittest, doctest +from django.conf import settings +from django.core import management +from django.test.utils import setup_test_environment, teardown_test_environment +from django.test.utils import create_test_db, destroy_test_db +from django.test.testcases import OutputChecker, DocTestRunner + +# The module name for tests outside models.py +TEST_MODULE = 'tests' + +doctestOutputChecker = OutputChecker() + +def build_suite(app_module): + "Create a complete Django test suite for the provided application module" + suite = unittest.TestSuite() + + # Load unit and doctests in the models.py file + suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(app_module)) + try: + suite.addTest(doctest.DocTestSuite(app_module, + checker=doctestOutputChecker, + runner=DocTestRunner)) + except ValueError: + # No doc tests in models.py + pass + + # Check to see if a separate 'tests' module exists parallel to the + # models module + try: + app_path = app_module.__name__.split('.')[:-1] + test_module = __import__('.'.join(app_path + [TEST_MODULE]), [], [], TEST_MODULE) + + suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(test_module)) + try: + suite.addTest(doctest.DocTestSuite(test_module, + checker=doctestOutputChecker, + runner=DocTestRunner)) + except ValueError: + # No doc tests in tests.py + pass + except ImportError, e: + # Couldn't import tests.py. Was it due to a missing file, or + # due to an import error in a tests.py that actually exists? + import os.path + from imp import find_module + try: + mod = find_module(TEST_MODULE, [os.path.dirname(app_module.__file__)]) + except ImportError: + # 'tests' module doesn't exist. Move on. + pass + else: + # The module exists, so there must be an import error in the + # test module itself. We don't need the module; close the file + # handle returned by find_module. + mod[0].close() + raise + + return suite + +def run_tests(module_list, verbosity=1, extra_tests=[]): + """ + Run the unit tests for all the modules in the provided list. + This testrunner will search each of the modules in the provided list, + looking for doctests and unittests in models.py or tests.py within + the module. A list of 'extra' tests may also be provided; these tests + will be added to the test suite. + """ + setup_test_environment() + + settings.DEBUG = False + suite = unittest.TestSuite() + + for module in module_list: + suite.addTest(build_suite(module)) + + for test in extra_tests: + suite.addTest(test) + + old_name = settings.DATABASE_NAME + create_test_db(verbosity) + management.syncdb(verbosity, interactive=False) + unittest.TextTestRunner(verbosity=verbosity).run(suite) + destroy_test_db(old_name, verbosity) + + teardown_test_environment() diff --git a/django/test/testcases.py b/django/test/testcases.py new file mode 100644 index 0000000000..1cfef6f19e --- /dev/null +++ b/django/test/testcases.py @@ -0,0 +1,30 @@ +import re, doctest, unittest +from django.db import transaction + +normalize_long_ints = lambda s: re.sub(r'(?<![\w])(\d+)L(?![\w])', '\\1', s) + +class OutputChecker(doctest.OutputChecker): + def check_output(self, want, got, optionflags): + ok = doctest.OutputChecker.check_output(self, want, got, optionflags) + + # Doctest does an exact string comparison of output, which means long + # integers aren't equal to normal integers ("22L" vs. "22"). The + # following code normalizes long integers so that they equal normal + # integers. + if not ok: + return normalize_long_ints(want) == normalize_long_ints(got) + return ok + +class DocTestRunner(doctest.DocTestRunner): + def __init__(self, *args, **kwargs): + doctest.DocTestRunner.__init__(self, *args, **kwargs) + self.optionflags = doctest.ELLIPSIS + + def report_unexpected_exception(self, out, test, example, exc_info): + doctest.DocTestRunner.report_unexpected_exception(self,out,test,example,exc_info) + + # Rollback, in case of database errors. Otherwise they'd have + # side effects on other tests. + from django.db import transaction + transaction.rollback_unless_managed() + diff --git a/django/test/utils.py b/django/test/utils.py new file mode 100644 index 0000000000..039a6dd7a2 --- /dev/null +++ b/django/test/utils.py @@ -0,0 +1,107 @@ +import sys, time +from django.conf import settings +from django.db import connection, transaction, backend +from django.dispatch import dispatcher +from django.test import signals +from django.template import Template + +# The prefix to put on the default database name when creating +# the test database. +TEST_DATABASE_PREFIX = 'test_' + +def instrumented_test_render(self, context): + """An instrumented Template render method, providing a signal + that can be intercepted by the test system Client + + """ + dispatcher.send(signal=signals.template_rendered, sender=self, template=self, context=context) + return self.nodelist.render(context) + +def setup_test_environment(): + """Perform any global pre-test setup. This involves: + + - Installing the instrumented test renderer + + """ + Template.original_render = Template.render + Template.render = instrumented_test_render + +def teardown_test_environment(): + """Perform any global post-test teardown. This involves: + + - Restoring the original test renderer + + """ + Template.render = Template.original_render + del Template.original_render + +def _set_autocommit(connection): + "Make sure a connection is in autocommit mode." + if hasattr(connection.connection, "autocommit"): + connection.connection.autocommit(True) + elif hasattr(connection.connection, "set_isolation_level"): + connection.connection.set_isolation_level(0) + +def create_test_db(verbosity=1, autoclobber=False): + if verbosity >= 1: + print "Creating test database..." + # If we're using SQLite, it's more convenient to test against an + # in-memory database. + if settings.DATABASE_ENGINE == "sqlite3": + TEST_DATABASE_NAME = ":memory:" + else: + if settings.TEST_DATABASE_NAME: + TEST_DATABASE_NAME = settings.TEST_DATABASE_NAME + else: + TEST_DATABASE_NAME = TEST_DATABASE_PREFIX + settings.DATABASE_NAME + + # Create the test database and connect to it. We need to autocommit + # if the database supports it because PostgreSQL doesn't allow + # CREATE/DROP DATABASE statements within transactions. + cursor = connection.cursor() + _set_autocommit(connection) + try: + cursor.execute("CREATE DATABASE %s" % backend.quote_name(TEST_DATABASE_NAME)) + except Exception, e: + sys.stderr.write("Got an error creating the test database: %s\n" % e) + if not autoclobber: + confirm = raw_input("It appears the test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_NAME) + if autoclobber or confirm == 'yes': + try: + if verbosity >= 1: + print "Destroying old test database..." + cursor.execute("DROP DATABASE %s" % backend.quote_name(TEST_DATABASE_NAME)) + if verbosity >= 1: + print "Creating test database..." + cursor.execute("CREATE DATABASE %s" % backend.quote_name(TEST_DATABASE_NAME)) + except Exception, e: + sys.stderr.write("Got an error recreating the test database: %s\n" % e) + sys.exit(2) + else: + print "Tests cancelled." + sys.exit(1) + + connection.close() + settings.DATABASE_NAME = TEST_DATABASE_NAME + + # Get a cursor (even though we don't need one yet). This has + # the side effect of initializing the test database. + cursor = connection.cursor() + +def destroy_test_db(old_database_name, verbosity=1): + # Unless we're using SQLite, remove the test database to clean up after + # ourselves. Connect to the previous database (not the test database) + # to do so, because it's not allowed to delete a database while being + # connected to it. + if verbosity >= 1: + print "Destroying test database..." + connection.close() + TEST_DATABASE_NAME = settings.DATABASE_NAME + settings.DATABASE_NAME = old_database_name + + if settings.DATABASE_ENGINE != "sqlite3": + cursor = connection.cursor() + _set_autocommit(connection) + time.sleep(1) # To avoid "database is being accessed by other users" errors. + cursor.execute("DROP DATABASE %s" % backend.quote_name(TEST_DATABASE_NAME)) + connection.close() diff --git a/django/utils/autoreload.py b/django/utils/autoreload.py index 6363af7835..e05b7fafe1 100644 --- a/django/utils/autoreload.py +++ b/django/utils/autoreload.py @@ -35,6 +35,14 @@ try: except ImportError: import dummy_thread as thread +# This import does nothing, but it's necessary to avoid some race conditions +# in the threading module. See http://code.djangoproject.com/ticket/2330 . +try: + import threading +except ImportError: + pass + + RUN_RELOADER = True def reloader_thread(): diff --git a/django/utils/datastructures.py b/django/utils/datastructures.py index 632e804f26..cecb4da170 100644 --- a/django/utils/datastructures.py +++ b/django/utils/datastructures.py @@ -14,6 +14,9 @@ class MergeDict(object): pass raise KeyError + def __contains__(self, key): + return self.has_key(key) + def get(self, key, default): try: return self[key] @@ -187,17 +190,23 @@ class MultiValueDict(dict): "Returns a copy of this object." return self.__deepcopy__() - def update(self, other_dict): - "update() extends rather than replaces existing key lists." - if isinstance(other_dict, MultiValueDict): - for key, value_list in other_dict.lists(): - self.setlistdefault(key, []).extend(value_list) - else: - try: - for key, value in other_dict.items(): - self.setlistdefault(key, []).append(value) - except TypeError: - raise ValueError, "MultiValueDict.update() takes either a MultiValueDict or dictionary" + def update(self, *args, **kwargs): + "update() extends rather than replaces existing key lists. Also accepts keyword args." + if len(args) > 1: + raise TypeError, "update expected at most 1 arguments, got %d", len(args) + if args: + other_dict = args[0] + if isinstance(other_dict, MultiValueDict): + for key, value_list in other_dict.lists(): + self.setlistdefault(key, []).extend(value_list) + else: + try: + for key, value in other_dict.items(): + self.setlistdefault(key, []).append(value) + except TypeError: + raise ValueError, "MultiValueDict.update() takes either a MultiValueDict or dictionary" + for key, value in kwargs.iteritems(): + self.setlistdefault(key, []).append(value) class DotExpandedDict(dict): """ diff --git a/django/utils/functional.py b/django/utils/functional.py index d1514d5728..e3c0a3c76b 100644 --- a/django/utils/functional.py +++ b/django/utils/functional.py @@ -1,6 +1,6 @@ -def curry(*args, **kwargs): +def curry(_curried_func, *args, **kwargs): def _curried(*moreargs, **morekwargs): - return args[0](*(args[1:]+moreargs), **dict(kwargs.items() + morekwargs.items())) + return _curried_func(*(args+moreargs), **dict(kwargs, **morekwargs)) return _curried class Promise: diff --git a/django/utils/itercompat.py b/django/utils/itercompat.py new file mode 100644 index 0000000000..370988bedb --- /dev/null +++ b/django/utils/itercompat.py @@ -0,0 +1,31 @@ +""" +Providing iterator functions that are not in all version of Python we support. +Where possible, we try to use the system-native version and only fall back to +these implementations if necessary. +""" + +import itertools + +def compat_tee(iterable): + """Return two independent iterators from a single iterable. + + Based on http://www.python.org/doc/2.3.5/lib/itertools-example.html + """ + # Note: Using a dictionary and a list as the default arguments here is + # deliberate and safe in this instance. + def gen(next, data={}, cnt=[0]): + dpop = data.pop + for i in itertools.count(): + if i == cnt[0]: + item = data[i] = next() + cnt[0] += 1 + else: + item = dpop(i) + yield item + next = iter(iterable).next + return gen(next), gen(next) + +if hasattr(itertools, 'tee'): + tee = itertools.tee +else: + tee = compat_tee diff --git a/django/utils/simplejson/scanner.py b/django/utils/simplejson/scanner.py index c2e9b6eb89..b9244cfed1 100644 --- a/django/utils/simplejson/scanner.py +++ b/django/utils/simplejson/scanner.py @@ -3,12 +3,11 @@ Iterator based sre token scanner """ import sre_parse, sre_compile, sre_constants from sre_constants import BRANCH, SUBPATTERN -from sre import VERBOSE, MULTILINE, DOTALL import re __all__ = ['Scanner', 'pattern'] -FLAGS = (VERBOSE | MULTILINE | DOTALL) +FLAGS = (re.VERBOSE | re.MULTILINE | re.DOTALL) class Scanner(object): def __init__(self, lexicon, flags=FLAGS): self.actions = [None] diff --git a/django/utils/termcolors.py b/django/utils/termcolors.py index 3ce1d5bb6b..17a600f899 100644 --- a/django/utils/termcolors.py +++ b/django/utils/termcolors.py @@ -2,8 +2,6 @@ termcolors.py """ -import types - color_names = ('black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white') foreground = dict([(color_names[x], '3%s' % x) for x in range(8)]) background = dict([(color_names[x], '4%s' % x) for x in range(8)]) diff --git a/django/utils/text.py b/django/utils/text.py index 7df9bc03b7..9e7bb3b6c4 100644 --- a/django/utils/text.py +++ b/django/utils/text.py @@ -94,7 +94,8 @@ def compress_string(s): return zbuf.getvalue() ustring_re = re.compile(u"([\u0080-\uffff])") -def javascript_quote(s): + +def javascript_quote(s, quote_double_quotes=False): def fix(match): return r"\u%04x" % ord(match.group(1)) @@ -104,9 +105,12 @@ def javascript_quote(s): elif type(s) != unicode: raise TypeError, s s = s.replace('\\', '\\\\') + s = s.replace('\r', '\\r') s = s.replace('\n', '\\n') s = s.replace('\t', '\\t') s = s.replace("'", "\\'") + if quote_double_quotes: + s = s.replace('"', '"') return str(ustring_re.sub(fix, s)) smart_split_re = re.compile('("(?:[^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'(?:[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'|[^\\s]+)') diff --git a/django/utils/translation/trans_null.py b/django/utils/translation/trans_null.py index ed25cae05b..75ad573357 100644 --- a/django/utils/translation/trans_null.py +++ b/django/utils/translation/trans_null.py @@ -17,3 +17,14 @@ get_language = lambda: settings.LANGUAGE_CODE get_language_bidi = lambda: settings.LANGUAGE_CODE in settings.LANGUAGES_BIDI get_date_formats = lambda: (settings.DATE_FORMAT, settings.DATETIME_FORMAT, settings.TIME_FORMAT) get_partial_date_formats = lambda: (settings.YEAR_MONTH_FORMAT, settings.MONTH_DAY_FORMAT) +check_for_language = lambda x: True + +def to_locale(language): + p = language.find('-') + if p >= 0: + return language[:p].lower()+'_'+language[p+1:].upper() + else: + return language.lower() + +def get_language_from_request(request): + return settings.LANGUAGE_CODE diff --git a/django/views/debug.py b/django/views/debug.py index 6cbbde987b..a7f44d17b3 100644 --- a/django/views/debug.py +++ b/django/views/debug.py @@ -3,10 +3,8 @@ from django.template import Template, Context, TemplateDoesNotExist from django.utils.html import escape from django.http import HttpResponseServerError, HttpResponseNotFound import os, re -from itertools import count, izip -from os.path import dirname, join as pathjoin -HIDDEN_SETTINGS = re.compile('SECRET|PASSWORD') +HIDDEN_SETTINGS = re.compile('SECRET|PASSWORD|PROFANITIES_LIST') def linebreak_iter(template_source): yield 0 @@ -117,14 +115,14 @@ def technical_500_response(request, exc_type, exc_value, tb): 'function': '?', 'lineno': '?', }] - t = Template(TECHNICAL_500_TEMPLATE) + t = Template(TECHNICAL_500_TEMPLATE, name='Technical 500 template') c = Context({ 'exception_type': exc_type.__name__, 'exception_value': exc_value, 'frames': frames, 'lastframe': frames[-1], 'request': request, - 'request_protocol': os.environ.get("HTTPS") == "on" and "https" or "http", + 'request_protocol': request.is_secure() and "https" or "http", 'settings': get_safe_settings(), 'template_info': template_info, 'template_does_not_exist': template_does_not_exist, @@ -143,20 +141,20 @@ def technical_404_response(request, exception): # tried exists but is an empty list. The URLconf must've been empty. return empty_urlconf(request) - t = Template(TECHNICAL_404_TEMPLATE) + t = Template(TECHNICAL_404_TEMPLATE, name='Technical 404 template') c = Context({ 'root_urlconf': settings.ROOT_URLCONF, 'urlpatterns': tried, 'reason': str(exception), 'request': request, - 'request_protocol': os.environ.get("HTTPS") == "on" and "https" or "http", + 'request_protocol': request.is_secure() and "https" or "http", 'settings': get_safe_settings(), }) return HttpResponseNotFound(t.render(c), mimetype='text/html') def empty_urlconf(request): "Create an empty URLconf 404 error response." - t = Template(EMPTY_URLCONF_TEMPLATE) + t = Template(EMPTY_URLCONF_TEMPLATE, name='Empty URLConf template') c = Context({ 'project_name': settings.SETTINGS_MODULE.split('.')[0] }) @@ -191,7 +189,7 @@ TECHNICAL_500_TEMPLATE = """ <head> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <meta name="robots" content="NONE,NOARCHIVE" /> - <title>{{ exception_type }} at {{ request.path }}</title> + <title>{{ exception_type }} at {{ request.path|escape }}</title> <style type="text/css"> html * { padding:0; margin:0; } body * { padding:10px 20px; } @@ -294,7 +292,7 @@ TECHNICAL_500_TEMPLATE = """ <body> <div id="summary"> - <h1>{{ exception_type }} at {{ request.path }}</h1> + <h1>{{ exception_type }} at {{ request.path|escape }}</h1> <h2>{{ exception_value|escape }}</h2> <table class="meta"> <tr> @@ -303,7 +301,7 @@ TECHNICAL_500_TEMPLATE = """ </tr> <tr> <th>Request URL:</th> - <td>{{ request_protocol }}://{{ request.META.HTTP_HOST }}{{ request.path }}</td> + <td>{{ request_protocol }}://{{ request.META.HTTP_HOST }}{{ request.path|escape }}</td> </tr> <tr> <th>Exception Type:</th> @@ -311,7 +309,7 @@ TECHNICAL_500_TEMPLATE = """ </tr> <tr> <th>Exception Value:</th> - <td>{{ exception_value }}</td> + <td>{{ exception_value|escape }}</td> </tr> <tr> <th>Exception Location:</th> @@ -414,7 +412,7 @@ Traceback (most recent call last):<br/> {{ frame.lineno }}. {{ frame.context_line|escape }}<br/> {% endif %} {% endfor %}<br/> - {{ exception_type }} at {{ request.path }}<br/> + {{ exception_type }} at {{ request.path|escape }}<br/> {{ exception_value|escape }}</code> </td> </tr> @@ -548,7 +546,7 @@ TECHNICAL_404_TEMPLATE = """ <html lang="en"> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> - <title>Page not found at {{ request.path }}</title> + <title>Page not found at {{ request.path|escape }}</title> <meta name="robots" content="NONE,NOARCHIVE" /> <style type="text/css"> html * { padding:0; margin:0; } @@ -578,7 +576,7 @@ TECHNICAL_404_TEMPLATE = """ </tr> <tr> <th>Request URL:</th> - <td>{{ request_protocol }}://{{ request.META.HTTP_HOST }}{{ request.path }}</td> + <td>{{ request_protocol }}://{{ request.META.HTTP_HOST }}{{ request.path|escape }}</td> </tr> </table> </div> @@ -593,7 +591,7 @@ TECHNICAL_404_TEMPLATE = """ <li>{{ pattern|escape }}</li> {% endfor %} </ol> - <p>The current URL, <code>{{ request.path }}</code>, didn't match any of these.</p> + <p>The current URL, <code>{{ request.path|escape }}</code>, didn't match any of these.</p> {% else %} <p>{{ reason|escape }}</p> {% endif %} diff --git a/django/views/decorators/cache.py b/django/views/decorators/cache.py index 5467ff501e..b04cc2340b 100644 --- a/django/views/decorators/cache.py +++ b/django/views/decorators/cache.py @@ -10,7 +10,6 @@ example, as that is unique across a Django project. Additionally, all headers from the response's Vary header will be taken into account on caching -- just like the middleware does. """ -import re from django.utils.decorators import decorator_from_middleware from django.utils.cache import patch_cache_control, add_never_cache_headers diff --git a/django/views/generic/create_update.py b/django/views/generic/create_update.py index b5fdd3e4cc..3a03fa59e4 100644 --- a/django/views/generic/create_update.py +++ b/django/views/generic/create_update.py @@ -4,9 +4,9 @@ from django import forms from django.db.models import FileField from django.contrib.auth.views import redirect_to_login from django.template import RequestContext -from django.core.paginator import ObjectPaginator, InvalidPage from django.http import Http404, HttpResponse, HttpResponseRedirect from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured +from django.utils.translation import gettext def create_object(request, model, template_name=None, template_loader=loader, extra_context=None, post_save_redirect=None, @@ -20,7 +20,7 @@ def create_object(request, model, template_name=None, the form wrapper for the object """ if extra_context is None: extra_context = {} - if login_required and request.user.is_anonymous(): + if login_required and not request.user.is_authenticated(): return redirect_to_login(request.path) manipulator = model.AddManipulator(follow=follow) @@ -39,8 +39,8 @@ def create_object(request, model, template_name=None, # No errors -- this means we can save the data! new_object = manipulator.save(new_data) - if not request.user.is_anonymous(): - request.user.message_set.create(message="The %s was created successfully." % model._meta.verbose_name) + if request.user.is_authenticated(): + request.user.message_set.create(message=gettext("The %(verbose_name)s was created successfully.") % {"verbose_name": model._meta.verbose_name}) # Redirect to the new object: first by trying post_save_redirect, # then by obj.get_absolute_url; fail if neither works. @@ -86,7 +86,7 @@ def update_object(request, model, object_id=None, slug=None, the original object being edited """ if extra_context is None: extra_context = {} - if login_required and request.user.is_anonymous(): + if login_required and not request.user.is_authenticated(): return redirect_to_login(request.path) # Look up the object to be edited @@ -102,7 +102,7 @@ def update_object(request, model, object_id=None, slug=None, except ObjectDoesNotExist: raise Http404, "No %s found for %s" % (model._meta.verbose_name, lookup_kwargs) - manipulator = model.ChangeManipulator(getattr(object, object._meta.pk.name), follow=follow) + manipulator = model.ChangeManipulator(getattr(object, object._meta.pk.attname), follow=follow) if request.POST: new_data = request.POST.copy() @@ -113,8 +113,8 @@ def update_object(request, model, object_id=None, slug=None, if not errors: object = manipulator.save(new_data) - if not request.user.is_anonymous(): - request.user.message_set.create(message="The %s was updated successfully." % model._meta.verbose_name) + if request.user.is_authenticated(): + request.user.message_set.create(message=gettext("The %(verbose_name)s was updated successfully.") % {"verbose_name": model._meta.verbose_name}) # Do a post-after-redirect so that reload works, etc. if post_save_redirect: @@ -142,7 +142,7 @@ def update_object(request, model, object_id=None, slug=None, else: c[key] = value response = HttpResponse(t.render(c)) - populate_xheaders(request, response, model, getattr(object, object._meta.pk.name)) + populate_xheaders(request, response, model, getattr(object, object._meta.pk.attname)) return response def delete_object(request, model, post_delete_redirect, @@ -162,7 +162,7 @@ def delete_object(request, model, post_delete_redirect, the original object being deleted """ if extra_context is None: extra_context = {} - if login_required and request.user.is_anonymous(): + if login_required and not request.user.is_authenticated(): return redirect_to_login(request.path) # Look up the object to be edited @@ -180,8 +180,8 @@ def delete_object(request, model, post_delete_redirect, if request.method == 'POST': object.delete() - if not request.user.is_anonymous(): - request.user.message_set.create(message="The %s was deleted." % model._meta.verbose_name) + if request.user.is_authenticated(): + request.user.message_set.create(message=gettext("The %(verbose_name)s was deleted.") % {"verbose_name": model._meta.verbose_name}) return HttpResponseRedirect(post_delete_redirect) else: if not template_name: @@ -196,5 +196,5 @@ def delete_object(request, model, post_delete_redirect, else: c[key] = value response = HttpResponse(t.render(c)) - populate_xheaders(request, response, model, getattr(object, object._meta.pk.name)) + populate_xheaders(request, response, model, getattr(object, object._meta.pk.attname)) return response diff --git a/django/views/generic/date_based.py b/django/views/generic/date_based.py index 7084cdfe5e..d13c0293be 100644 --- a/django/views/generic/date_based.py +++ b/django/views/generic/date_based.py @@ -1,13 +1,14 @@ from django.template import loader, RequestContext from django.core.exceptions import ObjectDoesNotExist from django.core.xheaders import populate_xheaders +from django.db.models.fields import DateTimeField from django.http import Http404, HttpResponse import datetime, time def archive_index(request, queryset, date_field, num_latest=15, template_name=None, template_loader=loader, extra_context=None, allow_empty=False, context_processors=None, - mimetype=None): + mimetype=None, allow_future=False): """ Generic top-level archive of date-based objects. @@ -20,7 +21,8 @@ def archive_index(request, queryset, date_field, num_latest=15, """ if extra_context is None: extra_context = {} model = queryset.model - queryset = queryset.filter(**{'%s__lte' % date_field: datetime.datetime.now()}) + if not allow_future: + queryset = queryset.filter(**{'%s__lte' % date_field: datetime.datetime.now()}) date_list = queryset.dates(date_field, 'year')[::-1] if not date_list and not allow_empty: raise Http404, "No %s available" % model._meta.verbose_name @@ -47,7 +49,7 @@ def archive_index(request, queryset, date_field, num_latest=15, def archive_year(request, year, queryset, date_field, template_name=None, template_loader=loader, extra_context=None, allow_empty=False, context_processors=None, template_object_name='object', mimetype=None, - make_object_list=False): + make_object_list=False, allow_future=False): """ Generic yearly archive view. @@ -67,8 +69,8 @@ def archive_year(request, year, queryset, date_field, template_name=None, lookup_kwargs = {'%s__year' % date_field: year} - # Only bother to check current date if the year isn't in the past. - if int(year) >= now.year: + # Only bother to check current date if the year isn't in the past and future objects aren't requested. + if int(year) >= now.year and not allow_future: lookup_kwargs['%s__lte' % date_field] = now date_list = queryset.filter(**lookup_kwargs).dates(date_field, 'month') if not date_list and not allow_empty: @@ -95,7 +97,7 @@ def archive_year(request, year, queryset, date_field, template_name=None, def archive_month(request, year, month, queryset, date_field, month_format='%b', template_name=None, template_loader=loader, extra_context=None, allow_empty=False, context_processors=None, - template_object_name='object', mimetype=None): + template_object_name='object', mimetype=None, allow_future=False): """ Generic monthly archive view. @@ -127,19 +129,28 @@ def archive_month(request, year, month, queryset, date_field, last_day = first_day.replace(month=first_day.month + 1) lookup_kwargs = {'%s__range' % date_field: (first_day, last_day)} - # Only bother to check current date if the month isn't in the past. - if last_day >= now.date(): + # Only bother to check current date if the month isn't in the past and future objects are requested. + if last_day >= now.date() and not allow_future: lookup_kwargs['%s__lte' % date_field] = now object_list = queryset.filter(**lookup_kwargs) if not object_list and not allow_empty: raise Http404 + + # Calculate the next month, if applicable. + if allow_future: + next_month = last_day + datetime.timedelta(days=1) + elif last_day < datetime.date.today(): + next_month = last_day + datetime.timedelta(days=1) + else: + next_month = None + if not template_name: template_name = "%s/%s_archive_month.html" % (model._meta.app_label, model._meta.object_name.lower()) t = template_loader.get_template(template_name) c = RequestContext(request, { '%s_list' % template_object_name: object_list, 'month': date, - 'next_month': (last_day < datetime.date.today()) and (last_day + datetime.timedelta(days=1)) or None, + 'next_month': next_month, 'previous_month': first_day - datetime.timedelta(days=1), }, context_processors) for key, value in extra_context.items(): @@ -152,7 +163,7 @@ def archive_month(request, year, month, queryset, date_field, def archive_week(request, year, week, queryset, date_field, template_name=None, template_loader=loader, extra_context=None, allow_empty=True, context_processors=None, - template_object_name='object', mimetype=None): + template_object_name='object', mimetype=None, allow_future=False): """ Generic weekly archive view. @@ -177,8 +188,8 @@ def archive_week(request, year, week, queryset, date_field, last_day = date + datetime.timedelta(days=7) lookup_kwargs = {'%s__range' % date_field: (first_day, last_day)} - # Only bother to check current date if the week isn't in the past. - if last_day >= now.date(): + # Only bother to check current date if the week isn't in the past and future objects aren't requested. + if last_day >= now.date() and not allow_future: lookup_kwargs['%s__lte' % date_field] = now object_list = queryset.filter(**lookup_kwargs) if not object_list and not allow_empty: @@ -201,7 +212,7 @@ def archive_day(request, year, month, day, queryset, date_field, month_format='%b', day_format='%d', template_name=None, template_loader=loader, extra_context=None, allow_empty=False, context_processors=None, template_object_name='object', - mimetype=None): + mimetype=None, allow_future=False): """ Generic daily archive view. @@ -225,16 +236,26 @@ def archive_day(request, year, month, day, queryset, date_field, model = queryset.model now = datetime.datetime.now() - lookup_kwargs = { - '%s__range' % date_field: (datetime.datetime.combine(date, datetime.time.min), datetime.datetime.combine(date, datetime.time.max)), - } + if isinstance(model._meta.get_field(date_field), DateTimeField): + lookup_kwargs = {'%s__range' % date_field: (datetime.datetime.combine(date, datetime.time.min), datetime.datetime.combine(date, datetime.time.max))} + else: + lookup_kwargs = {date_field: date} - # Only bother to check current date if the date isn't in the past. - if date >= now.date(): + # Only bother to check current date if the date isn't in the past and future objects aren't requested. + if date >= now.date() and not allow_future: lookup_kwargs['%s__lte' % date_field] = now object_list = queryset.filter(**lookup_kwargs) if not allow_empty and not object_list: raise Http404 + + # Calculate the next day, if applicable. + if allow_future: + next_day = date + datetime.timedelta(days=1) + elif date < datetime.date.today(): + next_day = date + datetime.timedelta(days=1) + else: + next_day = None + if not template_name: template_name = "%s/%s_archive_day.html" % (model._meta.app_label, model._meta.object_name.lower()) t = template_loader.get_template(template_name) @@ -242,7 +263,7 @@ def archive_day(request, year, month, day, queryset, date_field, '%s_list' % template_object_name: object_list, 'day': date, 'previous_day': date - datetime.timedelta(days=1), - 'next_day': (date < datetime.date.today()) and (date + datetime.timedelta(days=1)) or None, + 'next_day': next_day, }, context_processors) for key, value in extra_context.items(): if callable(value): @@ -267,7 +288,7 @@ def object_detail(request, year, month, day, queryset, date_field, month_format='%b', day_format='%d', object_id=None, slug=None, slug_field=None, template_name=None, template_name_field=None, template_loader=loader, extra_context=None, context_processors=None, - template_object_name='object', mimetype=None): + template_object_name='object', mimetype=None, allow_future=False): """ Generic detail view from year/month/day/slug or year/month/day/id structure. @@ -285,12 +306,13 @@ def object_detail(request, year, month, day, queryset, date_field, model = queryset.model now = datetime.datetime.now() - lookup_kwargs = { - '%s__range' % date_field: (datetime.datetime.combine(date, datetime.time.min), datetime.datetime.combine(date, datetime.time.max)), - } + if isinstance(model._meta.get_field(date_field), DateTimeField): + lookup_kwargs = {'%s__range' % date_field: (datetime.datetime.combine(date, datetime.time.min), datetime.datetime.combine(date, datetime.time.max))} + else: + lookup_kwargs = {date_field: date} - # Only bother to check current date if the date isn't in the past. - if date >= now.date(): + # Only bother to check current date if the date isn't in the past and future objects aren't requested. + if date >= now.date() and not allow_future: lookup_kwargs['%s__lte' % date_field] = now if object_id: lookup_kwargs['%s__exact' % model._meta.pk.name] = object_id diff --git a/django/views/static.py b/django/views/static.py index 072a01671e..3ec4ca14a1 100644 --- a/django/views/static.py +++ b/django/views/static.py @@ -1,5 +1,4 @@ from django.template import loader -from django.core.exceptions import ImproperlyConfigured from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponseNotModified from django.template import Template, Context, TemplateDoesNotExist import mimetypes @@ -82,7 +81,7 @@ def directory_index(path, fullpath): try: t = loader.get_template('static/directory_index') except TemplateDoesNotExist: - t = Template(DEFAULT_DIRECTORY_INDEX_TEMPLATE) + t = Template(DEFAULT_DIRECTORY_INDEX_TEMPLATE, name='Default directory index template') files = [] for f in os.listdir(fullpath): if not f.startswith('.'): diff --git a/docs/add_ons.txt b/docs/add_ons.txt index 90c98b7176..a0377700d7 100644 --- a/docs/add_ons.txt +++ b/docs/add_ons.txt @@ -2,12 +2,15 @@ The "contrib" add-ons ===================== -Django aims to follow Python's "batteries included" philosophy. It ships with a -variety of extra, optional tools that solve common Web-development problems. +Django aims to follow Python's `"batteries included" philosophy`_. It ships +with a variety of extra, optional tools that solve common Web-development +problems. This code lives in ``django/contrib`` in the Django distribution. Here's a rundown of the packages in ``contrib``: +.. _"batteries included" philosophy: http://docs.python.org/tut/node12.html#batteries-included + admin ===== @@ -150,6 +153,15 @@ See the `sites documentation`_. .. _sites documentation: http://www.djangoproject.com/documentation/sites/ +sitemaps +======== + +A framework for generating Google sitemap XML files. + +See the `sitemaps documentation`_. + +.. _sitemaps documentation: http://www.djangoproject.com/documentation/sitemaps/ + syndication =========== diff --git a/docs/admin_css.txt b/docs/admin_css.txt index 069012a84b..5822e26e45 100644 --- a/docs/admin_css.txt +++ b/docs/admin_css.txt @@ -82,7 +82,7 @@ There are also a few styles for styling text. .help This is a custom class for blocks of inline help text explaining the function of form elements. It makes text smaller and gray, and when applied - to ``p`` elements withing ``.form-row`` elements (see Form Styles below), + to ``p`` elements within ``.form-row`` elements (see Form Styles below), it will offset the text to align with the form field. Use this for help text, instead of ``small quiet``. It works on other elements, but try to put the class on a ``p`` whenever you can. @@ -118,8 +118,8 @@ additional class on the ``a`` for that tool. These are ``.addlink`` and Example from a changelist page:: <ul class="object-tools"> - <li><a href="/stories/add/" class="addlink">Add redirect</a></li> - </ul> + <li><a href="/stories/add/" class="addlink">Add redirect</a></li> + </ul> .. image:: http://media.djangoproject.com/img/doc/admincss/objecttools_01.gif :alt: Object tools on a changelist page @@ -170,4 +170,4 @@ Labels Form labels should always precede the field, except in the case of checkboxes and radio buttons, where the ``input`` should come first. Any explanation or help text should follow the ``label`` in a ``p`` with class -``.help``.
\ No newline at end of file +``.help``. diff --git a/docs/apache_auth.txt b/docs/apache_auth.txt index 72e0841305..b85057924b 100644 --- a/docs/apache_auth.txt +++ b/docs/apache_auth.txt @@ -6,7 +6,7 @@ Since keeping multiple authentication databases in sync is a common problem when dealing with Apache, you can configuring Apache to authenticate against Django's `authentication system`_ directly. For example, you could: - * Serve media files directly from Apache only to authenticated users. + * Serve static/media files directly from Apache only to authenticated users. * Authenticate access to a Subversion_ repository against Django users with a certain permission. diff --git a/docs/api_stability.txt b/docs/api_stability.txt new file mode 100644 index 0000000000..18885fbe63 --- /dev/null +++ b/docs/api_stability.txt @@ -0,0 +1,123 @@ +============= +API stability +============= + +Although Django has not reached a 1.0 release, the bulk of Django's public APIs are +stable as of the 0.95 release. This document explains which APIs will and will not +change before the 1.0 release. + +What "stable" means +=================== + +In this context, stable means: + + - All the public APIs -- everything documented in the linked documents, and + all methods that don't begin with an underscore -- will not be moved or + renamed without providing backwards-compatible aliases. + + - If new features are added to these APIs -- which is quite possible -- + they will not break or change the meaning of existing methods. In other + words, "stable" does not (necessarily) mean "complete." + + - If, for some reason, an API declared stable must be removed or replaced, it + will be declared deprecated but will remain in the API until at least + version 1.1. Warnings will be issued when the deprecated method is + called. + + - We'll only break backwards compatibility of these APIs if a bug or + security hole makes it completely unavoidable. + +Stable APIs +=========== + +These APIs are stable: + + - `Caching`_. + + - `Custom template tags and libraries`_ (with the possible exception for a + small change in the way templates are registered and loaded). + + - `Database lookup`_ (with the exception of validation; see below). + + - `django-admin utility`_. + + - `FastCGI integration`_. + + - `Flatpages`_. + + - `Generic views`_. + + - `Internationalization`_. + + - `Legacy database integration`_. + + - `Model definition`_ (with the exception of generic relations; see below). + + - `mod_python integration`_. + + - `Redirects`_. + + - `Request/response objects`_. + + - `Sending email`_. + + - `Sessions`_. + + - `Settings`_. + + - `Syndication`_. + + - `Template language`_ (with the exception of some possible disambiguation + of how tag arguments are passed to tags and filters). + + - `Transactions`_. + + - `URL dispatch`_. + +You'll notice that this list comprises the bulk of Django's APIs. That's right +-- most of the changes planned between now and Django 1.0 are either under the +hood, feature additions, or changes to a few select bits. A good estimate is +that 90% of Django can be considered forwards-compatible at this point. + +That said, these APIs should *not* be considered stable, and are likely to +change: + + - `Forms and validation`_ will most likely be completely rewritten to + deemphasize Manipulators in favor of validation-aware models. + + - `Serialization`_ is under heavy development; changes are likely. + + - The `authentication`_ framework is changing to be far more flexible, and + API changes may be necessary. + + - Generic relations will most likely be moved out of core and into the + content-types contrib package to avoid core dependancies on optional + components. + + - The comments framework, which is yet undocumented, will likely get a complete + rewrite before Django 1.0. Even if the change isn't quite that drastic, + there will at least be moderate changes. + +.. _caching: http://www.djangoproject.com/documentation/cache/ +.. _custom template tags and libraries: http://www.djangoproject.com/documentation/templates_python/ +.. _database lookup: http://www.djangoproject.com/documentation/db_api/ +.. _django-admin utility: http://www.djangoproject.com/documentation/django_admin/ +.. _fastcgi integration: http://www.djangoproject.com/documentation/fastcgi/ +.. _flatpages: http://www.djangoproject.com/documentation/flatpages/ +.. _generic views: http://www.djangoproject.com/documentation/generic_views/ +.. _internationalization: http://www.djangoproject.com/documentation/i18n/ +.. _legacy database integration: http://www.djangoproject.com/documentation/legacy_databases/ +.. _model definition: http://www.djangoproject.com/documentation/model_api/ +.. _mod_python integration: http://www.djangoproject.com/documentation/modpython/ +.. _redirects: http://www.djangoproject.com/documentation/redirects/ +.. _request/response objects: http://www.djangoproject.com/documentation/request_response/ +.. _sending email: http://www.djangoproject.com/documentation/email/ +.. _sessions: http://www.djangoproject.com/documentation/sessions/ +.. _settings: http://www.djangoproject.com/documentation/settings/ +.. _syndication: http://www.djangoproject.com/documentation/syndication/ +.. _template language: http://www.djangoproject.com/documentation/templates/ +.. _transactions: http://www.djangoproject.com/documentation/transactions/ +.. _url dispatch: http://www.djangoproject.com/documentation/url_dispatch/ +.. _forms and validation: http://www.djangoproject.com/documentation/forms/ +.. _serialization: http://www.djangoproject.com/documentation/serialization/ +.. _authentication: http://www.djangoproject.com/documentation/authentication/ diff --git a/docs/authentication.txt b/docs/authentication.txt index 68b9024a90..2a61ec82b5 100644 --- a/docs/authentication.txt +++ b/docs/authentication.txt @@ -66,8 +66,8 @@ Fields long and can contain any character. See the "Passwords" section below. * ``is_staff`` -- Boolean. Designates whether this user can access the admin site. - * ``is_active`` -- Boolean. Designates whether this user can log into the - Django admin. Set this to ``False`` instead of deleting accounts. + * ``is_active`` -- Boolean. Designates whether this account can be used + to log in. Set this flag to ``False`` instead of deleting accounts. * ``is_superuser`` -- Boolean. Designates that this user has all permissions without explicitly assigning them. * ``last_login`` -- A datetime of the user's last login. Is set to the @@ -82,20 +82,26 @@ Methods ``user_permissions``. ``User`` objects can access their related objects in the same way as any other `Django model`_:: - myuser.objects.groups = [group_list] - myuser.objects.groups.add(group, group,...) - myuser.objects.groups.remove(group, group,...) - myuser.objects.groups.clear() - myuser.objects.permissions = [permission_list] - myuser.objects.permissions.add(permission, permission, ...) - myuser.objects.permissions.remove(permission, permission, ...] - myuser.objects.permissions.clear() + myuser.groups = [group_list] + myuser.groups.add(group, group,...) + myuser.groups.remove(group, group,...) + myuser.groups.clear() + myuser.permissions = [permission_list] + myuser.permissions.add(permission, permission, ...) + myuser.permissions.remove(permission, permission, ...] + myuser.permissions.clear() In addition to those automatic API methods, ``User`` objects have the following custom methods: * ``is_anonymous()`` -- Always returns ``False``. This is a way of - comparing ``User`` objects to anonymous users. + differentiating ``User`` and ``AnonymousUser`` objects. Generally, you + should prefer using ``is_authenticated()`` to this method. + + * ``is_authenticated()`` -- Always returns ``True``. This is a way to + tell if the user has been authenticated. This does not imply any + permissions, and doesn't check if the user is active - it only indicates + that the user has provided a valid username and password. * ``get_full_name()`` -- Returns the ``first_name`` plus the ``last_name``, with a space in between. @@ -116,13 +122,16 @@ custom methods: * ``has_perm(perm)`` -- Returns ``True`` if the user has the specified permission, where perm is in the format ``"package.codename"``. + If the user is inactive, this method will always return ``False``. * ``has_perms(perm_list)`` -- Returns ``True`` if the user has each of the specified permissions, where each perm is in the format - ``"package.codename"``. + ``"package.codename"``. If the user is inactive, this method will + always return ``False``. * ``has_module_perms(package_name)`` -- Returns ``True`` if the user has any permissions in the given package (the Django app label). + If the user is inactive, this method will always return ``False``. * ``get_and_delete_messages()`` -- Returns a list of ``Message`` objects in the user's queue and deletes the messages from the queue. @@ -219,6 +228,7 @@ the ``django.contrib.auth.models.User`` interface, with these differences: * ``id`` is always ``None``. * ``is_anonymous()`` returns ``True`` instead of ``False``. + * ``is_authenticated()`` returns ``False`` instead of ``True``. * ``has_perm()`` always returns ``False``. * ``set_password()``, ``check_password()``, ``save()``, ``delete()``, ``set_groups()`` and ``set_permissions()`` raise ``NotImplementedError``. @@ -254,12 +264,12 @@ Once you have those middlewares installed, you'll be able to access ``request.user`` in views. ``request.user`` will give you a ``User`` object representing the currently logged-in user. If a user isn't currently logged in, ``request.user`` will be set to an instance of ``AnonymousUser`` (see the -previous section). You can tell them apart with ``is_anonymous()``, like so:: +previous section). You can tell them apart with ``is_authenticated()``, like so:: - if request.user.is_anonymous(): - # Do something for anonymous users. + if request.user.is_authenticated(): + # Do something for authenticated users. else: - # Do something for logged-in users. + # Do something for anonymous users. .. _request objects: http://www.djangoproject.com/documentation/request_response/#httprequest-objects .. _session documentation: http://www.djangoproject.com/documentation/sessions/ @@ -278,7 +288,10 @@ password is invalid, ``authenticate()`` returns ``None``. Example:: from django.contrib.auth import authenticate user = authenticate(username='john', password='secret') if user is not None: - print "You provided a correct username and password!" + if user.is_active: + print "You provided a correct username and password!" + else: + print "Your account has been disabled!" else: print "Your username and password were incorrect." @@ -296,10 +309,13 @@ This example shows how you might use both ``authenticate()`` and ``login()``:: password = request.POST['password'] user = authenticate(username=username, password=password) if user is not None: - login(request, user) - # Redirect to a success page. + if user.is_active: + login(request, user) + # Redirect to a success page. + else: + # Return a 'disabled account' error message else: - # Return an error message. + # Return an 'invalid login' error message. How to log a user out --------------------- @@ -323,19 +339,19 @@ The raw way ~~~~~~~~~~~ The simple, raw way to limit access to pages is to check -``request.user.is_anonymous()`` and either redirect to a login page:: +``request.user.is_authenticated()`` and either redirect to a login page:: from django.http import HttpResponseRedirect def my_view(request): - if request.user.is_anonymous(): + if not request.user.is_authenticated(): return HttpResponseRedirect('/login/?next=%s' % request.path) # ... ...or display an error message:: def my_view(request): - if request.user.is_anonymous(): + if not request.user.is_authenticated(): return render_to_response('myapp/login_error.html') # ... @@ -439,7 +455,7 @@ For example, this view checks to make sure the user is logged in and has the permission ``polls.can_vote``:: def my_view(request): - if request.user.is_anonymous() or not request.user.has_perm('polls.can_vote'): + if not (request.user.is_authenticated() and request.user.has_perm('polls.can_vote')): return HttpResponse("You can't vote in this poll.") # ... @@ -451,6 +467,10 @@ As a shortcut, you can use the convenient ``user_passes_test`` decorator:: # ... my_view = user_passes_test(lambda u: u.has_perm('polls.can_vote'))(my_view) +We're using this particular test as a relatively simple example. However, if +you just want to test whether a permission is available to a user, you can use +the ``permission_required()`` decorator, described later in this document. + Here's the same thing, using Python 2.4's decorator syntax:: from django.contrib.auth.decorators import user_passes_test @@ -483,6 +503,34 @@ Example in Python 2.4 syntax:: def my_view(request): # ... +The permission_required decorator +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**New in Django development version** + +It's a relatively common task to check whether a user has a particular +permission. For that reason, Django provides a shortcut for that case: the +``permission_required()`` decorator. Using this decorator, the earlier example +can be written as:: + + from django.contrib.auth.decorators import permission_required + + def my_view(request): + # ... + my_view = permission_required('polls.can_vote')(my_view) + +Note that ``permission_required()`` also takes an optional ``login_url`` +parameter. Example:: + + from django.contrib.auth.decorators import permission_required + + def my_view(request): + # ... + my_view = permission_required('polls.can_vote', login_url='/loginpage/')(my_view) + +As in the ``login_required`` decorator, ``login_url`` defaults to +``'/accounts/login/'``. + Limiting access to generic views -------------------------------- @@ -605,10 +653,10 @@ Users The currently logged-in user, either a ``User`` instance or an``AnonymousUser`` instance, is stored in the template variable ``{{ user }}``:: - {% if user.is_anonymous %} - <p>Welcome, new user. Please log in.</p> - {% else %} + {% if user.is_authenticated %} <p>Welcome, {{ user.username }}. Thanks for logging in.</p> + {% else %} + <p>Welcome, new user. Please log in.</p> {% endif %} Permissions @@ -672,7 +720,7 @@ timestamps. Messages are used by the Django admin after successful actions. For example, ``"The poll Foo was created successfully."`` is a message. -The API is simple:: +The API is simple: * To create a new message, use ``user_obj.message_set.create(message='message_text')``. diff --git a/docs/cache.txt b/docs/cache.txt index 2ef3d6503f..1795345ed9 100644 --- a/docs/cache.txt +++ b/docs/cache.txt @@ -230,8 +230,16 @@ Then, add the following required settings to your Django settings file: collisions. Use an empty string if you don't care. The cache middleware caches every page that doesn't have GET or POST -parameters. Additionally, ``CacheMiddleware`` automatically sets a few headers -in each ``HttpResponse``: +parameters. Optionally, if the ``CACHE_MIDDLEWARE_ANONYMOUS_ONLY`` setting is +``True``, only anonymous requests (i.e., not those made by a logged-in user) +will be cached. This is a simple and effective way of disabling caching for any +user-specific pages (include Django's admin interface). Note that if you use +``CACHE_MIDDLEWARE_ANONYMOUS_ONLY``, you should make sure you've activated +``AuthenticationMiddleware`` and that ``AuthenticationMiddleware`` appears +before ``CacheMiddleware`` in your ``MIDDLEWARE_CLASSES``. + +Additionally, ``CacheMiddleware`` automatically sets a few headers in each +``HttpResponse``: * Sets the ``Last-Modified`` header to the current date/time when a fresh (uncached) version of the page is requested. diff --git a/docs/contributing.txt b/docs/contributing.txt index d7552cdc7c..6ff0b038a3 100644 --- a/docs/contributing.txt +++ b/docs/contributing.txt @@ -168,6 +168,23 @@ Please follow these coding standards when writing code for inclusion in Django: {{foo}} + * In Django views, the first parameter in a view function should be called + ``request``. + + Do this:: + + def my_view(request, foo): + # ... + + Don't do this:: + + def my_view(req, foo): + # ... + + * Please don't put your name in the code. While we appreciate all + contributions to Django, our policy is not to publish individual + developer names in code -- for instance, at the top of Python modules. + Committing code =============== @@ -212,6 +229,10 @@ repository: first, then the "Fixed #abc." For example: "magic-removal: Fixed #123 -- Added whizbang feature." + For the curious: We're using a `Trac post-commit hook`_ for this. + + .. _Trac post-commit hook: http://trac.edgewall.org/browser/trunk/contrib/trac-post-commit-hook + * If your commit references a ticket in the Django `ticket tracker`_ but does *not* close the ticket, include the phrase "Refs #abc", where "abc" is the number of the ticket your commit references. We've rigged @@ -226,18 +247,23 @@ Django tarball. It's our policy to make sure all tests pass at all times. The tests cover: - * Models and the database API (``tests/testapp/models``). - * The cache system (``tests/otherthests/cache.py``). - * The ``django.utils.dateformat`` module (``tests/othertests/dateformat.py``). - * Database typecasts (``tests/othertests/db_typecasts.py``). - * The template system (``tests/othertests/templates.py`` and - ``tests/othertests/defaultfilters.py``). - * ``QueryDict`` objects (``tests/othertests/httpwrappers.py``). - * Markup template tags (``tests/othertests/markup.py``). - * The ``django.utils.timesince`` module (``tests/othertests/timesince.py``). + * Models and the database API (``tests/modeltests/``). + * The cache system (``tests/regressiontests/cache.py``). + * The ``django.utils.dateformat`` module (``tests/regressiontests/dateformat/``). + * Database typecasts (``tests/regressiontests/db_typecasts/``). + * The template system (``tests/regressiontests/templates/`` and + ``tests/regressiontests/defaultfilters/``). + * ``QueryDict`` objects (``tests/regressiontests/httpwrappers/``). + * Markup template tags (``tests/regressiontests/markup/``). We appreciate any and all contributions to the test suite! +The Django tests all use the testing infrastructure that ships with Django for +testing applications. See `Testing Django applications`_ for an explanation of +how to write new tests. + +.. _Testing Django applications: http://www.djangoproject.com/documentation/testing/ + Running the unit tests ---------------------- @@ -247,10 +273,14 @@ To run the tests, ``cd`` to the ``tests/`` directory and type:: Yes, the unit tests need a settings module, but only for database connection info -- the ``DATABASE_ENGINE``, ``DATABASE_USER`` and ``DATABASE_PASSWORD``. +You will also need a ``ROOT_URLCONF`` setting (its value is ignored; it just +needs to be present) and a ``SITE_ID`` setting (any integer value will do) in +order for all the tests to pass. -The unit tests will not touch your database; they create a new database, called -``django_test_db``, which is deleted when the tests are finished. This means -your user account needs permission to execute ``CREATE DATABASE``. +The unit tests will not touch your existing databases; they create a new +database, called ``django_test_db``, which is deleted when the tests are +finished. This means your user account needs permission to execute ``CREATE +DATABASE``. Requesting features =================== diff --git a/docs/db-api.txt b/docs/db-api.txt index ce6bb0ab3b..2f0c8b0589 100644 --- a/docs/db-api.txt +++ b/docs/db-api.txt @@ -578,6 +578,9 @@ related ``Person`` *and* the related ``City``:: p = b.author # Hits the database. c = p.hometown # Hits the database. +Note that ``select_related()`` does not follow foreign keys that have +``null=True``. + ``extra(select=None, where=None, params=None, tables=None)`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -715,12 +718,12 @@ The ``DoesNotExist`` exception inherits from A convenience method for creating an object and saving it all in one step. Thus:: p = Person.objects.create(first_name="Bruce", last_name="Springsteen") - + and:: p = Person(first_name="Bruce", last_name="Springsteen") p.save() - + are equivalent. ``get_or_create(**kwargs)`` @@ -873,15 +876,18 @@ The database API supports the following lookup types: exact ~~~~~ -Exact match. +Exact match. If the value provided for comparison is ``None``, it will +be interpreted as an SQL ``NULL`` (See isnull_ for more details). -Example:: +Examples:: Entry.objects.get(id__exact=14) + Entry.objects.get(id__exact=None) -SQL equivalent:: +SQL equivalents:: SELECT ... WHERE id = 14; + SELECT ... WHERE id = NULL; iexact ~~~~~~ @@ -1100,8 +1106,8 @@ such as January 3, July 3, etc. isnull ~~~~~~ -``NULL`` or ``IS NOT NULL`` match. Takes either ``True`` or ``False``, which -correspond to ``IS NULL`` and ``IS NOT NULL``, respectively. +Takes either ``True`` or ``False``, which correspond to SQL queries of +``IS NULL`` and ``IS NOT NULL``, respectively. Example:: @@ -1111,6 +1117,14 @@ SQL equivalent:: SELECT ... WHERE pub_date IS NULL; +.. admonition:: ``__isnull=True`` vs ``__exact=None`` + + There is an important difference between ``__isnull=True`` and + ``__exact=None``. ``__exact=None`` will *always* return an empty result + set, because SQL requires that no value is equal to ``NULL``. + ``__isnull`` determines if the field is currently holding the value + of ``NULL`` without performing a comparison. + search ~~~~~~ @@ -1137,7 +1151,7 @@ The pk lookup shortcut ---------------------- For convenience, Django provides a ``pk`` lookup type, which stands for -"primary_key". This is shorthand for "an exact lookup on the primary-key." +"primary_key". In the example ``Blog`` model, the primary key is the ``id`` field, so these three statements are equivalent:: @@ -1146,6 +1160,14 @@ three statements are equivalent:: Blog.objects.get(id=14) # __exact is implied Blog.objects.get(pk=14) # pk implies id__exact +The use of ``pk`` isn't limited to ``__exact`` queries -- any query term +can be combined with ``pk`` to perform a query on the primary key of a model:: + + # Get blogs entries with id 1, 4 and 7 + Blog.objects.filter(pk__in=[1,4,7]) + # Get all blog entries with id > 14 + Blog.objects.filter(pk__gt=14) + ``pk`` lookups also work across joins. For example, these three statements are equivalent:: @@ -1468,11 +1490,12 @@ the ``ForeignKey`` ``Manager`` has these additional methods: b.entry_set.remove(e) # Disassociates Entry e from Blog b. In order to prevent database inconsistency, this method only exists on - ``ForeignKey``s where ``null=True``. If the related field can't be set to - ``None`` (``NULL``), then an object can't be removed from a relation - without being added to another. In the above example, removing ``e`` from - ``b.entry_set()`` is equivalent to doing ``e.blog = None``, and because - the ``blog`` ``ForeignKey`` doesn't have ``null=True``, this is invalid. + ``ForeignKey`` objects where ``null=True``. If the related field can't be + set to ``None`` (``NULL``), then an object can't be removed from a + relation without being added to another. In the above example, removing + ``e`` from ``b.entry_set()`` is equivalent to doing ``e.blog = None``, + and because the ``blog`` ``ForeignKey`` doesn't have ``null=True``, this + is invalid. * ``clear()``: Removes all objects from the related object set. @@ -1507,7 +1530,7 @@ Many-to-many relationships -------------------------- Both ends of a many-to-many relationship get automatic API access to the other -end. The API works just as a "backward" one-to-many relationship. See _Backward +end. The API works just as a "backward" one-to-many relationship. See Backward_ above. The only difference is in the attribute naming: The model that defines the @@ -1556,13 +1579,13 @@ Queries over related objects ---------------------------- Queries involving related objects follow the same rules as queries involving -normal value fields. When specifying the the value for a query to match, you -may use either an object instance itself, or the primary key value for the +normal value fields. When specifying the the value for a query to match, you +may use either an object instance itself, or the primary key value for the object. For example, if you have a Blog object ``b`` with ``id=5``, the following three queries would be identical:: - + Entry.objects.filter(blog=b) # Query using object instance Entry.objects.filter(blog=b.id) # Query using id from instance Entry.objects.filter(blog=5) # Query using id directly diff --git a/docs/design_philosophies.txt b/docs/design_philosophies.txt index 17ed3ad6da..7fdc7ea01b 100644 --- a/docs/design_philosophies.txt +++ b/docs/design_philosophies.txt @@ -274,8 +274,8 @@ Loose coupling A view shouldn't care about which template system the developer uses -- or even whether a template system is used at all. -Designate between GET and POST ------------------------------- +Differentiate between GET and POST +---------------------------------- GET and POST are distinct; developers should explicitly use one or the other. The framework should make it easy to distinguish between GET and POST data. diff --git a/docs/django-admin.txt b/docs/django-admin.txt index 04d86aa3b4..7f9682b443 100644 --- a/docs/django-admin.txt +++ b/docs/django-admin.txt @@ -192,6 +192,14 @@ documentation. .. _serving static files: http://www.djangoproject.com/documentation/static_files/ +Turning off auto-reload +~~~~~~~~~~~~~~~~~~~~~~~ + +To disable auto-reloading of code while the development server is running, use the +``--noreload`` option, like so:: + + django-admin.py runserver --noreload + shell ----- @@ -284,6 +292,15 @@ this command to install the default apps. If you're installing the ``django.contrib.auth`` application, ``syncdb`` will give you the option of creating a superuser immediately. +test +---- + +**New in Django development version** + +Discover and run tests for all installed models. See `Testing Django applications`_ for more information. + +.. _testing django applications: ../testing/ + validate -------- @@ -330,6 +347,20 @@ setting the Python path for you. Displays a help message that includes a terse list of all available actions and options. +--noinput +--------- + +**New in Django development version** + +Inform django-admin that the user should NOT be prompted for any input. Useful +if the django-admin script will be executed as an unattended, automated +script. + +--noreload +---------- + +Disable the use of the auto-reloader when running the development server. + --version --------- @@ -340,6 +371,32 @@ Example output:: 0.9.1 0.9.1 (SVN) +--verbosity +----------- + +**New in Django development version** + +Example usage:: + + django-admin.py syncdb --verbosity=2 + +Verbosity determines the amount of notification and debug information that +will be printed to the console. '0' is no output, '1' is normal output, +and `2` is verbose output. + +--adminmedia +------------ + +**New in Django development version** + +Example usage:: + django-admin.py manage.py --adminmedia=/tmp/new-admin-style/ + +Tells Django where to find the various CSS and JavaScript files for the admin +interface when running the development server. Normally these files are served +out of the Django source tree, but because some designers customize these files +for their site, this option allows you to test against custom versions. + Extra niceties ============== diff --git a/docs/documentation.txt b/docs/documentation.txt new file mode 100644 index 0000000000..bacfb176b1 --- /dev/null +++ b/docs/documentation.txt @@ -0,0 +1,148 @@ +==================================== +How to read the Django documentation +==================================== + +We've put a lot of effort into making Django's documentation useful, easy to +read and as complete as possible. Here are a few tips on how to make the best +of it, along with some style guidelines. + +(Yes, this is documentation about documentation. Rest assured we have no plans +to write a document about how to read the document about documentation.) + +How documentation is updated +============================ + +Just as the Django code base is developed and improved on a daily basis, our +documentation is consistently improving. We improve documentation for several +reasons: + + * To make content fixes, such as grammar/typo corrections. + * To add information and/or examples to existing sections that need to be + expanded. + * To document Django features that aren't yet documented. (The list of + such features is shrinking but exists nonetheless.) + * To add documentation for new features as new features get added, or as + Django APIs or behaviors change. + +Django's documentation is kept in the same source control system as its code. +It lives in the `django/trunk/docs`_ directory of our Subversion repository. +Each document is a separate text file that covers a narrowly focused topic, +such as the "generic views" framework or how to construct a database model. + +.. _django/trunk/docs: http://code.djangoproject.com/browser/django/trunk/docs + +Where to get it +=============== + +You can read Django documentation in several ways. They are, in order of +preference: + +On the Web +---------- + +The most recent version of the Django documentation lives at +http://www.djangoproject.com/documentation/ . These HTML pages are generated +automatically from the text files in source control every 15 minutes. That +means they reflect the "latest and greatest" in Django -- they include the very +latest corrections and additions, and they discuss the latest Django features, +which may only be available to users of the Django development version. (See +"Differences between versions" below.) + +A key advantage of the Web-based documentation is the comment section at the +bottom of each document. This is an area for anybody to submit changes, +corrections and suggestions about the given document. The Django developers +frequently monitor the comments there and use them to improve the documentation +for everybody. + +We encourage you to help improve the docs: it's easy! Note, however, that +comments should explicitly relate to the documentation, rather than asking +broad tech-support questions. If you need help with your particular Django +setup, try the `django-users mailing list`_ instead of posting a comment to the +documentation. + +.. _django-users mailing list: http://groups.google.com/group/django-users + +In plain text +------------- + +For offline reading, or just for convenience, you can read the Django +documentation in plain text. + +If you're using an official release of Django, note that the zipped package +(tarball) of the code includes a ``docs/`` directory, which contains all the +documentation for that release. + +If you're using the development version of Django (aka the Subversion "trunk"), +note that the ``docs/`` directory contains all of the documentation. You can +``svn update`` it, just as you ``svn update`` the Python code, in order to get +the latest changes. + +You can check out the latest Django documentation from Subversion using this +shell command:: + + svn co http://code.djangoproject.com/svn/django/trunk/docs/ django_docs + +One low-tech way of taking advantage of the text documentation is by using the +Unix ``grep`` utility to search for a phrase in all of the documentation. For +example, this will show you each mention of the phrase "edit_inline" in any +Django document:: + + grep edit_inline /path/to/django/docs/*.txt + +Formatting +~~~~~~~~~~ + +The text documentation is written in ReST (ReStructured Text) format. That +means it's easy to read but is also formatted in a way that makes it easy to +convert into other formats, such as HTML. If you're interested, the script that +converts the ReST text docs into djangoproject.com's HTML lives at +`djangoproject.com/django_website/apps/docs/parts/build_documentation.py`_ in +the Django Subversion repository. + +.. _djangoproject.com/django_website/apps/docs/parts/build_documentation.py: http://code.djangoproject.com/browser/djangoproject.com/django_website/apps/docs/parts/build_documentation.py + +Differences between versions +============================ + +As previously mentioned, the text documentation in our Subversion repository +contains the "latest and greatest" changes and additions. These changes often +include documentation of new features added in the Django development version +-- the Subversion ("trunk") version of Django. For that reason, it's worth +pointing out our policy on keeping straight the documentation for various +versions of the framework. + +We follow this policy: + + * The primary documentation on djangoproject.com is an HTML version of the + latest docs in Subversion. These docs always correspond to the latest + official Django release, plus whatever features we've added/changed in + the framework *since* the latest release. + + * As we add features to Django's development version, we try to update the + documentation in the same Subversion commit transaction. + + * To distinguish feature changes/additions in the docs, we use the phrase + **New in Django development version**. In practice, this means that the + current documentation on djangoproject.com can be used by users of either + the latest release *or* the development version. + + * Documentation for a particular Django release is frozen once the version + has been released officially. It remains a snapshot of the docs as of the + moment of the release. We will make exceptions to this rule in + the case of retroactive security updates or other such retroactive + changes. Once documentation is frozen, we add a note to the top of each + frozen document that says "These docs are frozen for Django version XXX" + and links to the current version of that document. + + * Once a document is frozen for a Django release, we remove comments from + that page, in favor of having comments on the latest version of that + document. This is for the sake of maintainability and usability, so that + users have one, and only one, place to leave comments on a particular + document. We realize that some people may be stuck on a previous version + of Django, but we believe the usability problems with multiple versions + of a document the outweigh the benefits. + + * The `main documentation Web page`_ includes links to documentation for + all previous versions. + +.. _main documentation Web page: http://www.djangoproject.com/documentation/ diff --git a/docs/faq.txt b/docs/faq.txt index b374abfbf3..eaccc6be43 100644 --- a/docs/faq.txt +++ b/docs/faq.txt @@ -16,12 +16,17 @@ hours to take a complicated Web application from concept to public launch. At the same time, the World Online Web developers have consistently been perfectionists when it comes to following best practices of Web development. -Thus, Django was designed not only to allow fast Web development, but -*best-practice* Web development. +In fall 2003, the World Online developers (Adrian Holovaty and Simon Willison) +ditched PHP and began using Python to develop its Web sites. As they built +intensive, richly interactive sites such as Lawrence.com, they began to extract +a generic Web development framework that let them build Web applications more +and more quickly. They tweaked this framework constantly, adding improvements +over two years. -Django would not be possible without a whole host of open-source projects -- -`Apache`_, `Python`_, and `PostgreSQL`_ to name a few -- and we're thrilled to -be able to give something back to the open-source community. +In summer 2005, World Online decided to open-source the resulting software, +Django. Django would not be possible without a whole host of open-source +projects -- `Apache`_, `Python`_, and `PostgreSQL`_ to name a few -- and we're +thrilled to be able to give something back to the open-source community. .. _Apache: http://httpd.apache.org/ .. _Python: http://www.python.org/ @@ -42,8 +47,8 @@ Django is pronounced **JANG**-oh. Rhymes with FANG-oh. The "D" is silent. Is Django stable? ----------------- -Yes. World Online has been using Django for more than two years. Sites built on -Django have weathered traffic spikes of over one million hits an hour and a +Yes. World Online has been using Django for more than three years. Sites built +on Django have weathered traffic spikes of over one million hits an hour and a number of Slashdottings. Yes, it's quite stable. Does Django scale? @@ -98,10 +103,9 @@ Lawrence, Kansas, USA. On IRC, Simon goes by ``SimonW``. `Wilson Miner`_ - Wilson's design-fu makes us all look like rock stars. When not sneaking - into apartment complex swimming pools, he's the Commercial Development - Director for World Online, which means he makes the money that pays all our - paychecks. He lives in Lawrence, Kansas. + Wilson's design-fu makes us all look like rock stars. By day, he's an + interactive designer for `Apple`. Don't ask him what he's working on, or + he'll have to kill you. He lives in San Francisco. On IRC, Wilson goes by ``wilsonian``. @@ -113,6 +117,7 @@ Lawrence, Kansas, USA. .. _`simon.incutio.com`: http://simon.incutio.com/ .. _`Jacob Kaplan-Moss`: http://www.jacobian.org/ .. _`Wilson Miner`: http://www.wilsonminer.com/ +.. _`Apple`: http://www.apple.com/ Which sites use Django? ----------------------- @@ -156,7 +161,7 @@ logical to us. ----------------------------------------------------- We're well aware that there are other awesome Web frameworks out there, and -we're not adverse to borrowing ideas where appropriate. However, Django was +we're not averse to borrowing ideas where appropriate. However, Django was developed precisely because we were unhappy with the status quo, so please be aware that "because <Framework X>" does it is not going to be sufficient reason to add a given feature to Django. @@ -222,9 +227,7 @@ When will you release Django 1.0? Short answer: When we're comfortable with Django's APIs, have added all features that we feel are necessary to earn a "1.0" status, and are ready to -begin maintaining backwards compatibility. This should happen in a couple of -months or so, although it's entirely possible that it could happen earlier. -That translates into summer 2006. +begin maintaining backwards compatibility. The merging of Django's `magic-removal branch`_ went a long way toward Django 1.0. @@ -251,6 +254,16 @@ information than the docs that come with the latest Django release. .. _stored in revision control: http://code.djangoproject.com/browser/django/trunk/docs +Where can I find Django developers for hire? +-------------------------------------------- + +Consult our `developers for hire page`_ for a list of Django developers who +would be happy to help you. + +You might also be interested in posting a job to http://www.gypsyjobs.com/ . + +.. _developers for hire page: http://code.djangoproject.com/wiki/DevelopersForHire + Installation questions ====================== @@ -298,6 +311,18 @@ PostgreSQL fans, and MySQL_ and `SQLite 3`_ are also supported. .. _MySQL: http://www.mysql.com/ .. _`SQLite 3`: http://www.sqlite.org/ +Do I lose anything by using Python 2.3 versus newer Python versions, such as Python 2.5? +---------------------------------------------------------------------------------------- + +No. Django itself is guaranteed to work with any version of Python from 2.3 +and higher. + +If you use a Python version newer than 2.3, you will, of course, be able to +take advantage of newer Python features in your own code, along with the speed +improvements and other optimizations that have been made to the Python language +itself. But the Django framework itself should work equally well on 2.3 as it +does on 2.4 or 2.5. + Do I have to use mod_python? ---------------------------- @@ -472,7 +497,7 @@ specify an object to edit or delete. How do I add database-specific options to my CREATE TABLE statements, such as specifying MyISAM as the table type? ------------------------------------------------------------------------------------------------------------------ -We try to avoid adding special cases in the Django code to accomodate all the +We try to avoid adding special cases in the Django code to accommodate all the database-specific options such as table type, etc. If you'd like to use any of these options, create an `SQL initial data file`_ that contains ``ALTER TABLE`` statements that do what you want to do. The initial data files are executed in @@ -535,13 +560,26 @@ If you're sure your username and password are correct, make sure your user account has ``is_active`` and ``is_staff`` set to True. The admin site only allows access to users with those two fields both set to True. +How can I prevent the cache middleware from caching the admin site? +------------------------------------------------------------------- + +Set the ``CACHE_MIDDLEWARE_ANONYMOUS_ONLY`` setting to ``True``. See the +`cache documentation`_ for more information. + +.. _cache documentation: ../cache/#the-per-site-cache + How do I automatically set a field's value to the user who last edited the object in the admin? ----------------------------------------------------------------------------------------------- -At this point, you can't do this. But it's an oft-requested feature, so we're -discussing how it can be implemented. The problem is we don't want to couple -the model layer with the admin layer with the request layer (to get the current -user). It's a tricky problem. +At this point, Django doesn't have an official way to do this. But it's an oft-requested +feature, so we're discussing how it can be implemented. The problem is we don't want to couple +the model layer with the admin layer with the request layer (to get the current user). It's a +tricky problem. + +One person hacked up a `solution that doesn't require patching Django`_, but note that it's an +unofficial solution, and there's no guarantee it won't break at some point. + +.. _solution that doesn't require patching Django: http://lukeplant.me.uk/blog.php?id=1107301634 How do I limit admin access so that objects can only be edited by the users who created them? --------------------------------------------------------------------------------------------- @@ -597,12 +635,35 @@ like to make should be possible by editing the stylesheet. We've got a How do I create users without having to edit password hashes? ------------------------------------------------------------- -We don't recommend you create users via the admin interface, because at the -moment it requires you to edit password hashes manually. (Passwords are hashed -using one-way hash algorithms for security; there's currently no Web interface -for changing passwords by entering the actual password rather than the hash.) +If you'd like to use the admin site to create users, upgrade to the Django +development version, where this problem was fixed on Aug. 4, 2006. -To create a user, you'll have to use the Python API. See `creating users`_ for -full info. +You can also use the Python API. See `creating users`_ for full info. .. _creating users: http://www.djangoproject.com/documentation/authentication/#creating-users + +Contributing code +================= + +How can I get started contributing code to Django? +-------------------------------------------------- + +Thanks for asking! We've written an entire document devoted to this question. +It's titled `Contributing to Django`_. + +.. _Contributing to Django: http://www.djangoproject.com/documentation/contributing/ + +I submitted a bug fix in the ticket system several weeks ago. Why are you ignoring my patch? +-------------------------------------------------------------------------------------------- + +Don't worry: We're not ignoring you! + +It's important to understand there is a difference between "a ticket is being +ignored" and "a ticket has not been attended to yet." Django's ticket system +contains hundreds of open tickets, of various degrees of impact on end-user +functionality, and Django's developers have to review and prioritize. + +Besides, if your feature request stands no chance of inclusion in Django, we +won't ignore it -- we'll just close the ticket. So if your ticket is still +open, it doesn't mean we're ignoring you; it just means we haven't had time to +look at it yet. diff --git a/docs/fastcgi.txt b/docs/fastcgi.txt index 41d50d97a1..e2f4e933b4 100644 --- a/docs/fastcgi.txt +++ b/docs/fastcgi.txt @@ -270,7 +270,7 @@ In your Web root directory, add this to a file named ``.htaccess`` :: AddHandler fastcgi-script .fcgi RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f - RewriteRule ^/(.*)$ /mysite.fcgi/$1 [QSA,L] + RewriteRule ^(.*)$ mysite.fcgi/$1 [QSA,L] Then, create a small script that tells Apache how to spawn your FastCGI program. Create a file ``mysite.fcgi`` and place it in your Web directory, and @@ -289,7 +289,7 @@ be sure to make it executable :: os.environ['DJANGO_SETTINGS_MODULE'] = "myproject.settings" from django.core.servers.fastcgi import runfastcgi - runfastcgi(["method=threaded", "daemonize=false"]) + runfastcgi(method="threaded", daemonize="false") Restarting the spawned server ----------------------------- diff --git a/docs/forms.txt b/docs/forms.txt index 2fbe373744..4a4ba37289 100644 --- a/docs/forms.txt +++ b/docs/forms.txt @@ -136,7 +136,7 @@ template:: {% endblock %} Before we get back to the problems with these naive set of views, let's go over -some salient points of the above template:: +some salient points of the above template: * Field "widgets" are handled for you: ``{{ form.field }}`` automatically creates the "right" type of widget for the form, as you can see with the @@ -148,8 +148,8 @@ some salient points of the above template:: If you must use tables, use tables. If you're a semantic purist, you can probably find better HTML than in the above template. - * To avoid name conflicts, the ``id``s of form elements take the form - "id_*fieldname*". + * To avoid name conflicts, the ``id`` values of form elements take the + form "id_*fieldname*". By creating a creation form we've solved problem number 3 above, but we still don't have any validation. Let's revise the validation issue by writing a new @@ -211,7 +211,7 @@ Below is the finished view:: def create_place(request): manipulator = Place.AddManipulator() - if request.POST: + if request.method == 'POST': # If data was POSTed, we're trying to create a new Place. new_data = request.POST.copy() @@ -309,7 +309,7 @@ about editing an existing one? It's shockingly similar to creating a new one:: # Grab the Place object in question for future use. place = manipulator.original_object - if request.POST: + if request.method == 'POST': new_data = request.POST.copy() errors = manipulator.get_validation_errors(new_data) if not errors: @@ -321,7 +321,7 @@ about editing an existing one? It's shockingly similar to creating a new one:: else: errors = {} # This makes sure the form accurate represents the fields of the place. - new_data = place.__dict__ + new_data = manipulator.flatten_data() form = forms.FormWrapper(manipulator, new_data, errors) return render_to_response('places/edit_form.html', {'form': form, 'place': place}) @@ -336,10 +336,10 @@ The only real differences are: * ``ChangeManipulator.original_object`` stores the instance of the object being edited. - * We set ``new_data`` to the original object's ``__dict__``. This makes - sure the form fields contain the current values of the object. - ``FormWrapper`` does not modify ``new_data`` in any way, and templates - cannot, so this is perfectly safe. + * We set ``new_data`` based upon ``flatten_data()`` from the manipulator. + ``flatten_data()`` takes the data from the original object under + manipulation, and converts it into a data dictionary that can be used + to populate form elements with the existing values for the object. * The above example uses a different template, so create and edit can be "skinned" differently if needed, but the form chunk itself is completely @@ -391,7 +391,7 @@ Here's a simple function that might drive the above form:: def contact_form(request): manipulator = ContactManipulator() - if request.POST: + if request.method == 'POST': new_data = request.POST.copy() errors = manipulator.get_validation_errors(new_data) if not errors: @@ -405,6 +405,43 @@ Here's a simple function that might drive the above form:: form = forms.FormWrapper(manipulator, new_data, errors) return render_to_response('contact_form.html', {'form': form}) +``FileField`` and ``ImageField`` special cases +============================================== + +Dealing with ``FileField`` and ``ImageField`` objects is a little more +complicated. + +First, you'll need to make sure that your ``<form>`` element correctly defines +the ``enctype`` as ``"multipart/form-data"``, in order to upload files:: + + <form enctype="multipart/form-data" method="post" action="/foo/"> + +Next, you'll need to treat the field in the template slightly differently. A +``FileField`` or ``ImageField`` is represented by *two* HTML form elements. + +For example, given this field in a model:: + + photo = model.ImageField('/path/to/upload/location') + +You'd need to display two formfields in the template:: + + <p><label for="id_photo">Photo:</label> {{ form.photo }}{{ form.photo_file }}</p> + +The first bit (``{{ form.photo }}``) displays the currently-selected file, +while the second (``{{ form.photo_file }}``) actually contains the file upload +form field. Thus, at the validation layer you need to check the ``photo_file`` +key. + +Finally, in your view, make sure to access ``request.FILES``, rather than +``request.POST``, for the uploaded files. This is necessary because +``request.POST`` does not contain file-upload data. + +For example, following the ``new_data`` convention, you might do something like +this:: + + new_data = request.POST.copy() + new_data.update(request.FILES) + Validators ========== @@ -444,7 +481,33 @@ the data being validated. Also, because consistency in user interfaces is important, we strongly urge you to put punctuation at the end of your validation messages. -Ready-made Validators +When are validators called? +--------------------------- + +After a form has been submitted, Django first checks to see that all the +required fields are present and non-empty. For each field that passes that +test *and if the form submission contained data* for that field, all the +validators for that field are called in turn. The emphasized portion in the +last sentence is important: if a form field is not submitted (because it +contains no data -- which is normal HTML behavior), the validators are not +run against the field. + +This feature is particularly important for models using +``models.BooleanField`` or custom manipulators using things like +``forms.CheckBoxField``. If the checkbox is not selected, it will not +contribute to the form submission. + +If you would like your validator to run *always*, regardless of whether its +attached field contains any data, set the ``always_test`` attribute on the +validator function. For example:: + + def my_custom_validator(field_data, all_data): + # ... + my_custom_validator.always_test = True + +This validator will always be executed for any field it is attached to. + +Ready-made validators --------------------- Writing your own validator is not difficult, but there are some situations @@ -516,7 +579,7 @@ fails. If no message is passed in, a default message is used. ``ValidateIfOtherFieldEquals`` Takes three parameters: ``other_field``, ``other_value`` and ``validator_list``, in that order. If ``other_field`` has a value of - ``other_vaue``, then the validators in ``validator_list`` are all run + ``other_value``, then the validators in ``validator_list`` are all run against the current field. ``RequiredIfOtherFieldNotGiven`` diff --git a/docs/generic_views.txt b/docs/generic_views.txt index d14fe12418..99a9b7cf6b 100644 --- a/docs/generic_views.txt +++ b/docs/generic_views.txt @@ -127,7 +127,7 @@ If the given URL is ``None``, Django will return an ``HttpResponseGone`` (410). This example redirects from ``/foo/<id>/`` to ``/bar/<id>/``:: urlpatterns = patterns('django.views.generic.simple', - ('^foo/(?p<id>\d+)/$', 'redirect_to', {'url': '/bar/%(id)s/'}), + ('^foo/(?P<id>\d+)/$', 'redirect_to', {'url': '/bar/%(id)s/'}), ) This example returns a 410 HTTP error for requests to ``/bar/``:: @@ -148,7 +148,8 @@ are views for displaying drilldown pages for date-based data. **Description:** A top-level index page showing the "latest" objects, by date. Objects with -a date in the *future* are not included. +a date in the *future* are not included unless you set ``allow_future`` to +``True``. **Required arguments:** @@ -183,7 +184,12 @@ a date in the *future* are not included. the view's template. See the `RequestContext docs`_. * ``mimetype``: The MIME type to use for the resulting document. Defaults - to the value of the ``DEFAULT_MIME_TYPE`` setting. + to the value of the ``DEFAULT_CONTENT_TYPE`` setting. + + * ``allow_future``: A boolean specifying whether to include "future" + objects on this page, where "future" means objects in which the field + specified in ``date_field`` is greater than the current date/time. By + default, this is ``False``. **Template name:** @@ -217,7 +223,8 @@ In addition to ``extra_context``, the template's context will be: **Description:** A yearly archive page showing all available months in a given year. Objects -with a date in the *future* are not displayed. +with a date in the *future* are not displayed unless you set ``allow_future`` +to ``True``. **Required arguments:** @@ -263,7 +270,12 @@ with a date in the *future* are not displayed. this is ``False``. * ``mimetype``: The MIME type to use for the resulting document. Defaults - to the value of the ``DEFAULT_MIME_TYPE`` setting. + to the value of the ``DEFAULT_CONTENT_TYPE`` setting. + + * ``allow_future``: A boolean specifying whether to include "future" + objects on this page, where "future" means objects in which the field + specified in ``date_field`` is greater than the current date/time. By + default, this is ``False``. **Template name:** @@ -296,7 +308,8 @@ In addition to ``extra_context``, the template's context will be: **Description:** A monthly archive page showing all objects in a given month. Objects with a -date in the *future* are not displayed. +date in the *future* are not displayed unless you set ``allow_future`` to +``True``. **Required arguments:** @@ -344,7 +357,12 @@ date in the *future* are not displayed. determining the variable's name. * ``mimetype``: The MIME type to use for the resulting document. Defaults - to the value of the ``DEFAULT_MIME_TYPE`` setting. + to the value of the ``DEFAULT_CONTENT_TYPE`` setting. + + * ``allow_future``: A boolean specifying whether to include "future" + objects on this page, where "future" means objects in which the field + specified in ``date_field`` is greater than the current date/time. By + default, this is ``False``. **Template name:** @@ -378,7 +396,7 @@ In addition to ``extra_context``, the template's context will be: **Description:** A weekly archive page showing all objects in a given week. Objects with a date -in the *future* are not displayed. +in the *future* are not displayed unless you set ``allow_future`` to ``True``. **Required arguments:** @@ -420,7 +438,12 @@ in the *future* are not displayed. determining the variable's name. * ``mimetype``: The MIME type to use for the resulting document. Defaults - to the value of the ``DEFAULT_MIME_TYPE`` setting. + to the value of the ``DEFAULT_CONTENT_TYPE`` setting. + + * ``allow_future``: A boolean specifying whether to include "future" + objects on this page, where "future" means objects in which the field + specified in ``date_field`` is greater than the current date/time. By + default, this is ``False``. **Template name:** @@ -445,7 +468,8 @@ In addition to ``extra_context``, the template's context will be: **Description:** A day archive page showing all objects in a given day. Days in the future throw -a 404 error, regardless of whether any objects exist for future days. +a 404 error, regardless of whether any objects exist for future days, unless +you set ``allow_future`` to ``True``. **Required arguments:** @@ -499,7 +523,12 @@ a 404 error, regardless of whether any objects exist for future days. determining the variable's name. * ``mimetype``: The MIME type to use for the resulting document. Defaults - to the value of the ``DEFAULT_MIME_TYPE`` setting. + to the value of the ``DEFAULT_CONTENT_TYPE`` setting. + + * ``allow_future``: A boolean specifying whether to include "future" + objects on this page, where "future" means objects in which the field + specified in ``date_field`` is greater than the current date/time. By + default, this is ``False``. **Template name:** @@ -537,7 +566,9 @@ and today's date is used instead. **Description:** -A page representing an individual object. +A page representing an individual object. If the object has a date value in the +future, the view will throw a 404 error by default, unless you set +``allow_future`` to ``True``. **Required arguments:** @@ -602,7 +633,12 @@ A page representing an individual object. to use in the template context. By default, this is ``'object'``. * ``mimetype``: The MIME type to use for the resulting document. Defaults - to the value of the ``DEFAULT_MIME_TYPE`` setting. + to the value of the ``DEFAULT_CONTENT_TYPE`` setting. + + * ``allow_future``: A boolean specifying whether to include "future" + objects on this page, where "future" means objects in which the field + specified in ``date_field`` is greater than the current date/time. By + default, this is ``False``. **Template name:** @@ -671,7 +707,7 @@ A page representing a list of objects. determining the variable's name. * ``mimetype``: The MIME type to use for the resulting document. Defaults - to the value of the ``DEFAULT_MIME_TYPE`` setting. + to the value of the ``DEFAULT_CONTENT_TYPE`` setting. **Template name:** @@ -783,7 +819,7 @@ A page representing an individual object. to use in the template context. By default, this is ``'object'``. * ``mimetype``: The MIME type to use for the resulting document. Defaults - to the value of the ``DEFAULT_MIME_TYPE`` setting. + to the value of the ``DEFAULT_CONTENT_TYPE`` setting. **Template name:** diff --git a/docs/i18n.txt b/docs/i18n.txt index 212fb41488..4d0d92b082 100644 --- a/docs/i18n.txt +++ b/docs/i18n.txt @@ -48,9 +48,10 @@ bit of i18n-related overhead in certain places of the framework. If you don't use internationalization, you should take the two seconds to set ``USE_I18N = False`` in your settings file. If ``USE_I18N`` is set to ``False``, then Django will make some optimizations so as not to load the -internationalization machinery. +internationalization machinery. See the `documentation for USE_I18N`_. -See the `documentation for USE_I18N`_. +You'll probably also want to remove ``'django.core.context_processors.i18n'`` +from your ``TEMPLATE_CONTEXT_PROCESSORS`` setting. .. _documentation for USE_I18N: http://www.djangoproject.com/documentation/settings/#use-i18n @@ -224,11 +225,18 @@ block:: This will have {{ myvar }} inside. {% endblocktrans %} +If you need to bind more than one expression inside a ``blocktrans`` tag, +separate the pieces with ``and``:: + + {% blocktrans with book|title as book_t and author|title as author_t %} + This is {{ book_t }} by {{ author_t }} + {% endblocktrans %} + To pluralize, specify both the singular and plural forms with the ``{% plural %}`` tag, which appears within ``{% blocktrans %}`` and ``{% endblocktrans %}``. Example:: - {% blocktrans count list|counted as counter %} + {% blocktrans count list|count as counter %} There is only one {{ name }} object. {% plural %} There are {{ counter }} {{ name }} objects. @@ -306,7 +314,7 @@ marked for translation. It creates (or updates) a message file in the directory ``conf/locale``. In the ``de`` example, the file will be ``conf/locale/de/LC_MESSAGES/django.po``. -If run over your project source tree or your appliation source tree, it will +If run over your project source tree or your application source tree, it will do the same, but the location of the locale directory is ``locale/LANG/LC_MESSAGES`` (note the missing ``conf`` prefix). @@ -349,7 +357,7 @@ A quick explanation: Long messages are a special case. There, the first string directly after the ``msgstr`` (or ``msgid``) is an empty string. Then the content itself will be written over the next few lines as one string per line. Those strings are -directlyconcatenated. Don't forget trailing spaces within the strings; +directly concatenated. Don't forget trailing spaces within the strings; otherwise, they'll be tacked together without whitespace! .. admonition:: Mind your charset @@ -647,7 +655,7 @@ The ``javascript_catalog`` view ------------------------------- The main solution to these problems is the ``javascript_catalog`` view, which -sends out a JavaScript code library with functions that mimick the ``gettext`` +sends out a JavaScript code library with functions that mimic the ``gettext`` interface, plus an array of translation strings. Those translation strings are taken from the application, project or Django core, according to what you specify in either the {{{info_dict}}} or the URL. @@ -665,7 +673,7 @@ You hook it up like this:: Each string in ``packages`` should be in Python dotted-package syntax (the same format as the strings in ``INSTALLED_APPS``) and should refer to a package that contains a ``locale`` directory. If you specify multiple packages, all -those catalogs aremerged into one catalog. This is useful if you have +those catalogs are merged into one catalog. This is useful if you have JavaScript that uses strings from different applications. You can make the view dynamic by putting the packages into the URL pattern:: diff --git a/docs/install.txt b/docs/install.txt index 800c49b596..ff8e1a8318 100644 --- a/docs/install.txt +++ b/docs/install.txt @@ -77,44 +77,54 @@ It's easy either way. Installing the official version ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -1. Download Django-0.91.tar.gz from our `download page`_. -2. ``tar xzvf Django-0.91.tar.gz`` -3. ``cd Django-0.91`` +1. Download Django-0.95.tar.gz from our `download page`_. +2. ``tar xzvf Django-0.95.tar.gz`` +3. ``cd Django-0.95`` 4. ``sudo python setup.py install`` Note that the last command will automatically download and install setuptools_ if you don't already have it installed. This requires a working Internet +connection and may cause problems on Python 2.5. If you run into problems, +try using our development version by following the instructions below. The +development version no longer uses setuptools nor requires an Internet connection. -This will install Django in your Python installation's ``site-packages`` +The command will install Django in your Python installation's ``site-packages`` directory. -.. note:: - - Due to recent backwards-incompatible changes, it is strongly recommended - that you use the development version (below) for any new applications or - if you are just starting to work with Django. The 0.91 release is a - dead-end branch that is primarily of use for supporting legacy Django - applications. - .. _setuptools: http://peak.telecommunity.com/DevCenter/setuptools Installing the development version ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +If you'd like to be able to update your Django code occasionally with the +latest bug fixes and improvements, follow these instructions: + 1. Make sure you have Subversion_ installed. -2. ``svn co http://code.djangoproject.com/svn/django/trunk/ django_src`` -3. Symlink ``django_src/django`` so that ``django`` is within your Python - ``site-packages`` directory: +2. Check out the Django code into your Python ``site-packages`` directory. + On Linux / Mac OSX / Unix, do this:: - ``ln -s `pwd`/django_src/django /usr/lib/python2.3/site-packages/django`` + svn co http://code.djangoproject.com/svn/django/trunk/ django_src + ln -s `pwd`/django_src/django /usr/lib/python2.3/site-packages/django (In the above line, change ``python2.3`` to match your current Python version.) -You don't have to run ``python setup.py install``. + On Windows, do this:: + + svn co http://code.djangoproject.com/svn/django/trunk/django c:\Python24\lib\site-packages\django + +4. Copy the file ``django_src/django/bin/django-admin.py`` to somewhere on your + system path, such as ``/usr/local/bin`` (Unix) or ``C:\Python24\Scripts`` + (Windows). This step simply lets you type ``django-admin.py`` from within + any directory, rather than having to qualify the command with the full path + to the file. + +You *don't* have to run ``python setup.py install``, because that command +takes care of steps 3 and 4 for you. -When you want to update your code, just run the command ``svn update`` from -within the ``django_src`` directory. +When you want to update your copy of the Django source code, just run the +command ``svn update`` from within the ``django`` directory. When you do this, +Subversion will automatically download any changes. .. _`download page`: http://www.djangoproject.com/download/ .. _Subversion: http://subversion.tigris.org/ diff --git a/docs/middleware.txt b/docs/middleware.txt index bad00fd890..efc4d89569 100644 --- a/docs/middleware.txt +++ b/docs/middleware.txt @@ -63,7 +63,7 @@ Adds a few conveniences for perfectionists: last component in the path contains a period. So ``foo.com/bar`` is redirected to ``foo.com/bar/``, but ``foo.com/bar/file.txt`` is passed through unchanged. - + If ``PREPEND_WWW`` is ``True``, URLs that lack a leading "www." will be redirected to the same URL with a leading "www." @@ -101,6 +101,22 @@ Handles conditional GET operations. If the response has a ``ETag`` or Also removes the content from any response to a HEAD request and sets the ``Date`` and ``Content-Length`` response-headers. +django.middleware.http.SetRemoteAddrFromForwardedFor +---------------------------------------------------- + +**New in Django development version** + +Sets ``request['REMOTE_ADDR']`` based on ``request.['HTTP_X_FORWARDED_FOR']``, +if the latter is set. This is useful if you're sitting behind a reverse proxy +that causes each request's ``REMOTE_ADDR`` to be set to ``127.0.0.1``. + +**Important note:** This does NOT validate ``HTTP_X_FORWARDED_FOR``. If you're +not behind a reverse proxy that sets ``HTTP_X_FORWARDED_FOR`` automatically, do +not use this middleware. Anybody can spoof the value of +``HTTP_X_FORWARDED_FOR``, and because this sets ``REMOTE_ADDR`` based on +``HTTP_X_FORWARDED_FOR``, that means anybody can "fake" their IP address. Only +use this when you can absolutely trust the value of ``HTTP_X_FORWARDED_FOR``. + django.contrib.sessions.middleware.SessionMiddleware ---------------------------------------------------- diff --git a/docs/model-api.txt b/docs/model-api.txt index c4d57bf8c4..1aa8c811f4 100644 --- a/docs/model-api.txt +++ b/docs/model-api.txt @@ -188,7 +188,8 @@ JavaScript shortcuts. ~~~~~~~~~~~~~~ A ``CharField`` that checks that the value is a valid e-mail address. -This doesn't accept ``maxlength``. +This doesn't accept ``maxlength``; its ``maxlength`` is automatically set to +75. ``FileField`` ~~~~~~~~~~~~~ @@ -217,12 +218,27 @@ steps: subdirectory of ``MEDIA_ROOT`` it should upload files. 3. All that will be stored in your database is a path to the file - (relative to ``MEDIA_ROOT``). You'll must likely want to use the + (relative to ``MEDIA_ROOT``). You'll most likely want to use the convenience ``get_<fieldname>_url`` function provided by Django. For example, if your ``ImageField`` is called ``mug_shot``, you can get the absolute URL to your image in a template with ``{{ object.get_mug_shot_url }}``. +For example, say your ``MEDIA_ROOT`` is set to ``'/home/media'``, and +``upload_to`` is set to ``'photos/%Y/%m/%d'``. The ``'%Y/%m/%d'`` part of +``upload_to`` is strftime formatting; ``'%Y'`` is the four-digit year, +``'%m'`` is the two-digit month and ``'%d'`` is the two-digit day. If you +upload a file on Jan. 15, 2007, it will be saved in the directory +``/home/media/photos/2007/01/15``. + +Note that whenever you deal with uploaded files, you should pay close attention +to where you're uploading them and what type of files they are, to avoid +security holes. *Validate all uploaded files* so that you're sure the files are +what you think they are. For example, if you blindly let somebody upload files, +without validation, to a directory that's within your Web server's document +root, then somebody could upload a CGI or PHP script and execute that script by +visiting its URL on your site. Don't allow that. + .. _`strftime formatting`: http://docs.python.org/lib/module-time.html#l2h-1941 ``FilePathField`` @@ -528,7 +544,9 @@ The default value for the field. ``editable`` ~~~~~~~~~~~~ -If ``False``, the field will not be editable in the admin. Default is ``True``. +If ``False``, the field will not be editable in the admin or via form +processing using the object's ``AddManipulator`` or ``ChangeManipulator`` +classes. Default is ``True``. ``help_text`` ~~~~~~~~~~~~~ @@ -671,8 +689,9 @@ you can use the name of the model, rather than the model object itself:: class Manufacturer(models.Model): # ... -Note, however, that support for strings around model names in ``ForeignKey`` is -quite new, and it can be buggy in some cases. +Note, however, that you can only use strings to refer to models in the same +models.py file -- you cannot use a string to reference a model in a different +application, or to reference a model that has been imported from elsewhere. Behind the scenes, Django appends ``"_id"`` to the field name to create its database column name. In the above example, the database table for the ``Car`` @@ -794,7 +813,10 @@ here's how you'd represent that:: As with ``ForeignKey``, a relationship to self can be defined by using the string ``'self'`` instead of the model name, and you can refer to as-yet -undefined models by using a string containing the model name. +undefined models by using a string containing the model name. However, you +can only use strings to refer to models in the same models.py file -- you +cannot use a string to reference a model in a different application, or to +reference a model that has been imported from elsewhere. It's suggested, but not required, that the name of a ``ManyToManyField`` (``toppings`` in the example above) be a plural describing the set of related @@ -1203,10 +1225,13 @@ A few special cases to note about ``list_display``: of the related object. * ``ManyToManyField`` fields aren't supported, because that would entail - executing a separate SQL statement for each row in the table. + executing a separate SQL statement for each row in the table. If you + want to do this nonetheless, give your model a custom method, and add + that method's name to ``list_display``. (See below for more on custom + methods in ``list_display``.) - * If the field is a ``BooleanField``, Django will display a pretty "on" or - "off" icon instead of ``True`` or ``False``. + * If the field is a ``BooleanField`` or ``NullBooleanField``, Django will + display a pretty "on" or "off" icon instead of ``True`` or ``False``. * If the string given is a method of the model, Django will call it and display the output. This method should have a ``short_description`` @@ -1225,6 +1250,34 @@ A few special cases to note about ``list_display``: return self.birthday.strftime('%Y')[:3] + "0's" decade_born_in.short_description = 'Birth decade' + * If the string given is a method of the model, Django will HTML-escape the + output by default. If you'd rather not escape the output of the method, + give the method an ``allow_tags`` attribute whose value is ``True``. + + Here's a full example model:: + + class Person(models.Model): + first_name = models.CharField(maxlength=50) + last_name = models.CharField(maxlength=50) + color_code = models.CharField(maxlength=6) + + class Admin: + list_display = ('first_name', 'last_name', 'colored_name') + + def colored_name(self): + return '<span style="color: #%s;">%s %s</span>' % (self.color_code, self.first_name, self.last_name) + colored_name.allow_tags = True + + * The ``__str__()`` method is just as valid in ``list_display`` as any + other model method, so it's perfectly OK to do this:: + + list_display = ('__str__', 'some_other_field') + + * For any element of ``list_display`` that is not a field on the model, the + change list page will not allow ordering by that column. This is because + ordering is done at the database level, and Django has no way of knowing + how to order the result of a custom method at the SQL level. + ``list_display_links`` ---------------------- @@ -1349,6 +1402,41 @@ user searches for ``john lennon``, Django will do the equivalent of this SQL WHERE (first_name ILIKE '%john%' OR last_name ILIKE '%john%') AND (first_name ILIKE '%lennon%' OR last_name ILIKE '%lennon%') +**New in Django development version:** For faster and/or more restrictive +searches, prefix the field name with an operator: + +``^`` + Matches the beginning of the field. For example, if ``search_fields`` is + set to ``['^first_name', '^last_name']`` and a user searches for + ``john lennon``, Django will do the equivalent of this SQL ``WHERE`` + clause:: + + WHERE (first_name ILIKE 'john%' OR last_name ILIKE 'john%') + AND (first_name ILIKE 'lennon%' OR last_name ILIKE 'lennon%') + + This query is more efficient than the normal ``'%john%'`` query, because + the database only needs to check the beginning of a column's data, rather + than seeking through the entire column's data. Plus, if the column has an + index on it, some databases may be able to use the index for this query, + even though it's a ``LIKE`` query. + +``=`` + Matches exactly, case-insensitive. For example, if + ``search_fields`` is set to ``['=first_name', '=last_name']`` and + a user searches for ``john lennon``, Django will do the equivalent + of this SQL ``WHERE`` clause:: + + WHERE (first_name ILIKE 'john' OR last_name ILIKE 'john') + AND (first_name ILIKE 'lennon' OR last_name ILIKE 'lennon') + + Note that the query input is split by spaces, so, following this example, + it's not currently not possible to search for all records in which + ``first_name`` is exactly ``'john winston'`` (containing a space). + +``@`` + Performs a full-text match. This is like the default search method but uses + an index. Currently this is only available for MySQL. + Managers ======== diff --git a/docs/overview.txt b/docs/overview.txt index 5a399582e8..8e6274dd9a 100644 --- a/docs/overview.txt +++ b/docs/overview.txt @@ -159,7 +159,7 @@ of contents for your app, it contains a simple mapping between URL patterns and Python callback functions. URLconfs also serve to decouple URLs from Python code. -Here's what a URLconf might look like for the above ``Reporter``/``Article`` +Here's what a URLconf might look like for the ``Reporter``/``Article`` example above:: from django.conf.urls.defaults import * diff --git a/docs/release_notes_0.95.txt b/docs/release_notes_0.95.txt new file mode 100644 index 0000000000..3709cacf5a --- /dev/null +++ b/docs/release_notes_0.95.txt @@ -0,0 +1,126 @@ +================================= +Django version 0.95 release notes +================================= + + +Welcome to the Django 0.95 release. + +This represents a significant advance in Django development since the 0.91 +release in January 2006. The details of every change in this release would be +too extensive to list in full, but a summary is presented below. + +Suitability and API stability +============================= + +This release is intended to provide a stable reference point for developers +wanting to work on production-level applications that use Django. + +However, it's not the 1.0 release, and we'll be introducing further changes +before 1.0. For a clear look at which areas of the framework will change (and +which ones will *not* change) before 1.0, see the api-stability.txt file, which +lives in the docs/ directory of the distribution. + +You may have a need to use some of the features that are marked as +"subject to API change" in that document, but that's OK with us as long as it's +OK with you, and as long as you understand APIs may change in the future. + +Fortunately, most of Django's core APIs won't be changing before version 1.0. +There likely won't be as big of a change between 0.95 and 1.0 versions as there +was between 0.91 and 0.95. + +Changes and new features +======================== + +The major changes in this release (for developers currently using the 0.91 +release) are a result of merging the 'magic-removal' branch of development. +This branch removed a number of constraints in the way Django code had to be +written that were a consequence of decisions made in the early days of Django, +prior to its open-source release. It's now possible to write more natural, +Pythonic code that works as expected, and there's less "black magic" happening +behind the scenes. + +Aside from that, another main theme of this release is a dramatic increase in +usability. We've made countless improvements in error messages, documentation, +etc., to improve developers' quality of life. + +The new features and changes introduced in 0.95 include: + + * Django now uses a more consistent and natural filtering interface for + retrieving objects from the database. + + * User-defined models, functions and constants now appear in the module + namespace they were defined in. (Previously everything was magically + transferred to the django.models.* namespace.) + + * Some optional applications, such as the FlatPage, Sites and Redirects + apps, have been decoupled and moved into django.contrib. If you don't + want to use these applications, you no longer have to install their + database tables. + + * Django now has support for managing database transactions. + + * We've added the ability to write custom authentication and authorization + backends for authenticating users against alternate systems, such as + LDAP. + + * We've made it easier to add custom table-level functions to models, + through a new "Manager" API. + + * It's now possible to use Django without a database. This simply means + that the framework no longer requires you to have a working database set + up just to serve dynamic pages. In other words, you can just use + URLconfs/views on their own. Previously, the framework required that a + database be configured, regardless of whether you actually used it. + + * It's now more explicit and natural to override save() and delete() + methods on models, rather than needing to hook into the pre_save() and + post_save() method hooks. + + * Individual pieces of the framework now can be configured without + requiring the setting of an environment variable. This permits use of, + for example, the Django templating system inside other applications. + + * More and more parts of the framework have been internationalized, as + we've expanded internationalization (i18n) support. The Django + codebase, including code and templates, has now been translated, at least + in part, into 31 languages. From Arabic to Chinese to Hungarian to Welsh, + it is now possible to use Django's admin site in your native language. + +The number of changes required to port from 0.91-compatible code to the 0.95 +code base are significant in some cases. However, they are, for the most part, +reasonably routine and only need to be done once. A list of the necessary +changes is described in the `Removing The Magic`_ wiki page. There is also an +easy checklist_ for reference when undertaking the porting operation. + +.. _Removing The Magic: http://code.djangoproject.com/wiki/RemovingTheMagic +.. _checklist: http://code.djangoproject.com/wiki/MagicRemovalCheatSheet1 + +Problem reports and getting help +================================ + +Need help resolving a problem with Django? The documentation in the +distribution is also available online_ at the `Django website`_. The FAQ_ +document is especially recommended, as it contains a number of issues that +come up time and again. + +For more personalized help, the `django-users`_ mailing list is a very active +list, with more than 2,000 subscribers who can help you solve any sort of +Django problem. We recommend you search the archives first, though, because +many common questions appear with some regularity, and any particular problem +may already have been answered. + +Finally, for those who prefer the more immediate feedback offered by IRC, +there's a #django channel on irc.freenode.net that is regularly populated by +Django users and developers from around the world. Friendly people are usually +available at any hour of the day -- to help, or just to chat. + +.. _online: http://www.djangoproject.com/documentation/ +.. _Django website: http://www.djangoproject.com/ +.. _FAQ: http://www.djangoproject.com/documentation/faq/ +.. _django-users: http://groups.google.com/group/django-users + +Thanks for using Django! + +The Django Team +July 2006 + diff --git a/docs/request_response.txt b/docs/request_response.txt index 0bcb3a7f5b..006ac6b648 100644 --- a/docs/request_response.txt +++ b/docs/request_response.txt @@ -106,12 +106,12 @@ All attributes except ``session`` should be considered read-only. A ``django.contrib.auth.models.User`` object representing the currently logged-in user. If the user isn't currently logged in, ``user`` will be set to an instance of ``django.contrib.auth.models.AnonymousUser``. You - can tell them apart with ``is_anonymous()``, like so:: + can tell them apart with ``is_authenticated()``, like so:: - if request.user.is_anonymous(): - # Do something for anonymous users. - else: + if request.user.is_authenticated(): # Do something for logged-in users. + else: + # Do something for anonymous users. ``user`` is only available if your Django installation has the ``AuthenticationMiddleware`` activated. For more, see @@ -134,21 +134,25 @@ Methods ------- ``__getitem__(key)`` - Returns the GET/POST value for the given key, checking POST first, then - GET. Raises ``KeyError`` if the key doesn't exist. + Returns the GET/POST value for the given key, checking POST first, then + GET. Raises ``KeyError`` if the key doesn't exist. - This lets you use dictionary-accessing syntax on an ``HttpRequest`` - instance. Example: ``request["foo"]`` would return ``True`` if either - ``request.POST`` or ``request.GET`` had a ``"foo"`` key. + This lets you use dictionary-accessing syntax on an ``HttpRequest`` + instance. Example: ``request["foo"]`` would return ``True`` if either + ``request.POST`` or ``request.GET`` had a ``"foo"`` key. ``has_key()`` - Returns ``True`` or ``False``, designating whether ``request.GET`` or - ``request.POST`` has the given key. + Returns ``True`` or ``False``, designating whether ``request.GET`` or + ``request.POST`` has the given key. ``get_full_path()`` - Returns the ``path``, plus an appended query string, if applicable. + Returns the ``path``, plus an appended query string, if applicable. + + Example: ``"/music/bands/the_beatles/?print=true"`` - Example: ``"/music/bands/the_beatles/?print=true"`` +``is_secure()`` + Returns ``True`` if the request is secure; that is, if it was made with + HTTPS. QueryDict objects ----------------- @@ -337,9 +341,9 @@ hard-coded strings. If you use this technique, follow these guidelines: Methods ------- -``__init__(content='', mimetype=DEFAULT_MIME_TYPE)`` +``__init__(content='', mimetype=DEFAULT_CONTENT_TYPE)`` Instantiates an ``HttpResponse`` object with the given page content (a - string) and MIME type. The ``DEFAULT_MIME_TYPE`` is ``'text/html'``. + string) and MIME type. The ``DEFAULT_CONTENT_TYPE`` is ``'text/html'``. ``content`` can be an iterator or a string. If it's an iterator, it should return strings, and those strings will be joined together to form the @@ -376,10 +380,14 @@ Methods .. _`cookie Morsel`: http://www.python.org/doc/current/lib/morsel-objects.html -``delete_cookie(key)`` +``delete_cookie(key, path='/', domain=None)`` Deletes the cookie with the given key. Fails silently if the key doesn't exist. + The ``path`` and ``domain`` arguments are new in the Django development version. + Due to the way cookies work, ``path`` and ``domain`` should be the same + values you used in ``set_cookie()`` -- otherwise the cookie may not be deleted. + ``content`` Returns the content as a Python string, encoding it from a Unicode object if necessary. Note this is a property, not a method, so use ``r.content`` diff --git a/docs/serialization.txt b/docs/serialization.txt index 25199e7a50..aee1b9a3bb 100644 --- a/docs/serialization.txt +++ b/docs/serialization.txt @@ -3,12 +3,12 @@ Serializing Django objects ========================== .. note:: - + This API is currently under heavy development and may change -- perhaps drastically -- in the future. - + You have been warned. - + Django's serialization framework provides a mechanism for "translating" Django objects into other formats. Usually these other formats will be text-based and used for sending Django objects over a wire, but it's possible for a @@ -21,7 +21,7 @@ At the highest level, serializing data is a very simple operation:: from django.core import serializers data = serializers.serialize("xml", SomeModel.objects.all()) - + The arguments to the ``serialize`` function are the format to serialize the data to (see `Serialization formats`_) and a QuerySet_ to serialize. (Actually, the second argument can be any iterator that yields Django objects, @@ -34,7 +34,7 @@ You can also use a serializer object directly:: xml_serializer = serializers.get_serializer("xml") xml_serializer.serialize(queryset) data = xml_serializer.getvalue() - + This is useful if you want to serialize data directly to a file-like object (which includes a HTTPResponse_):: @@ -50,7 +50,7 @@ Deserializing data is also a fairly simple operation:: for obj in serializers.deserialize("xml", data): do_something_with(obj) - + As you can see, the ``deserialize`` function takes the same format argument as ``serialize``, a string or stream of data, and returns an iterator. @@ -69,7 +69,7 @@ something like:: for deserialized_object in serializers.deserialize("xml", data): if object_should_be_saved(deserialized_object): obj.save() - + In other words, the usual use is to examine the deserialized objects to make sure that they are "appropriate" for saving before doing so. Of course, if you trust your data source you could just save the object and move on. @@ -89,13 +89,28 @@ Django "ships" with a few included serializers: bundled with Django). ``python`` Translates to and from "simple" Python objects (lists, dicts, - strings, etc.). Not really all that useful on its own, but + strings, etc.). Not really all that useful on its own, but used as a base for other serializers. ========== ============================================================== .. _json: http://json.org/ .. _simplejson: http://undefined.org/python/#simplejson +Notes for specific serialization formats +---------------------------------------- + +json +~~~~ + +If you're using UTF-8 (or any other non-ASCII encoding) data with the JSON +serializer, you must pass ``ensure_ascii=False`` as a parameter to the +``serialize()`` call. Otherwise, the output won't be encoded correctly. + +For example:: + + json_serializer = serializers.get_serializer("json") + json_serializer.serialize(queryset, ensure_ascii=False, stream=response) + Writing custom serializers `````````````````````````` diff --git a/docs/sessions.txt b/docs/sessions.txt index c473d0a3db..d39f42c3bf 100644 --- a/docs/sessions.txt +++ b/docs/sessions.txt @@ -245,6 +245,17 @@ Default: ``'sessionid'`` The name of the cookie to use for sessions. This can be whatever you want. +SESSION_COOKIE_SECURE +--------------------- + +**New in Django development version** + +Default: ``False`` + +Whether to use a secure cookie for the session cookie. If this is set to +``True``, the cookie will be marked as "secure," which means browsers may +ensure that the cookie is only sent under an HTTPS connection. + SESSION_EXPIRE_AT_BROWSER_CLOSE ------------------------------- diff --git a/docs/settings.txt b/docs/settings.txt index 5b75e29172..272b20f753 100644 --- a/docs/settings.txt +++ b/docs/settings.txt @@ -401,15 +401,6 @@ Subject-line prefix for e-mail messages sent with ``django.core.mail.mail_admins or ``django.core.mail.mail_managers``. You'll probably want to include the trailing space. -ENABLE_PSYCO ------------- - -Default: ``False`` - -Whether to enable Psyco, which optimizes Python code. Requires Psyco_. - -.. _Psyco: http://psyco.sourceforge.net/ - IGNORABLE_404_ENDS ------------------ @@ -473,25 +464,36 @@ LANGUAGES Default: A tuple of all available languages. Currently, this is:: LANGUAGES = ( + ('ar', _('Arabic')), ('bn', _('Bengali')), ('cs', _('Czech')), ('cy', _('Welsh')), ('da', _('Danish')), ('de', _('German')), + ('el', _('Greek')), ('en', _('English')), ('es', _('Spanish')), + ('es_AR', _('Argentinean Spanish')), ('fr', _('French')), ('gl', _('Galician')), + ('hu', _('Hungarian')), + ('he', _('Hebrew')), ('is', _('Icelandic')), ('it', _('Italian')), + ('ja', _('Japanese')), + ('nl', _('Dutch')), ('no', _('Norwegian')), ('pt-br', _('Brazilian')), ('ro', _('Romanian')), ('ru', _('Russian')), ('sk', _('Slovak')), + ('sl', _('Slovenian')), ('sr', _('Serbian')), ('sv', _('Swedish')), + ('ta', _('Tamil')), + ('uk', _('Ukrainian')), ('zh-cn', _('Simplified Chinese')), + ('zh-tw', _('Traditional Chinese')), ) A tuple of two-tuples in the format (language code, language name). This @@ -526,7 +528,7 @@ any code that uses ``LANGUAGES`` at runtime. MANAGERS -------- -Default: ``ADMINS`` (Whatever ``ADMINS`` is set to) +Default: ``()`` (Empty tuple) A tuple in the same format as ``ADMINS`` that specifies who should get broken-link notifications when ``SEND_BROKEN_LINK_EMAILS=True``. @@ -585,6 +587,15 @@ Whether to prepend the "www." subdomain to URLs that don't have it. This is only used if ``CommonMiddleware`` is installed (see the `middleware docs`_). See also ``APPEND_SLASH``. +PROFANITIES_LIST +---------------- + +A tuple of profanities, as strings, that will trigger a validation error when +the ``hasNoProfanities`` validator is called. + +We don't list the default values here, because that would be profane. To see +the default values, see the file ``django/conf/global_settings.py``. + ROOT_URLCONF ------------ @@ -647,6 +658,18 @@ Default: ``'sessionid'`` The name of the cookie to use for sessions. This can be whatever you want. See the `session docs`_. +SESSION_COOKIE_SECURE +--------------------- + +**New in Django development version** + +Default: ``False`` + +Whether to use a secure cookie for the session cookie. If this is set to +``True``, the cookie will be marked as "secure," which means browsers may +ensure that the cookie is only sent under an HTTPS connection. +See the `session docs`_. + SESSION_EXPIRE_AT_BROWSER_CLOSE ------------------------------- @@ -731,6 +754,30 @@ misspelled) variables. See `How invalid variables are handled`_. .. _How invalid variables are handled: http://www.djangoproject.com/documentation/templates_python/#how-invalid-variables-are-handled +TEST_RUNNER +----------- + +**New in Django development version** + +Default: ``'django.test.simple.run_tests'`` + +The name of the method to use for starting the test suite. See +`Testing Django Applications`_. + +.. _Testing Django Applications: ../testing/ + +TEST_DATABASE_NAME +------------------ + +**New in Django development version** + +Default: ``None`` + +The name of database to use when running the test suite. If a value of +``None`` is specified, the test database will use the name ``'test_' + settings.DATABASE_NAME``. See `Testing Django Applications`_. + +.. _Testing Django Applications: ../testing/ + TIME_FORMAT ----------- @@ -760,6 +807,13 @@ Note that this is the time zone to which Django will convert all dates/times -- not necessarily the timezone of the server. For example, one server may serve multiple Django-powered sites, each with a separate time-zone setting. +Normally, Django sets the ``os.environ['TZ']`` variable to the time zone you +specify in the ``TIME_ZONE`` setting. Thus, all your views and models will +automatically operate in the correct time zone. However, if you're using the +manual configuration option (see below), Django will *not* touch the ``TZ`` +environment variable, and it'll be up to you to ensure your processes are +running in the correct environment. + USE_ETAGS --------- @@ -837,6 +891,15 @@ uppercase, with the same name as the settings described above. If a particular setting is not passed to ``configure()`` and is needed at some later point, Django will use the default setting value. +Configuring Django in this fashion is mostly necessary -- and, indeed, +recommended -- when you're using a piece of the framework inside a larger +application. + +Consequently, when configured via ``settings.configure()``, Django will not +make any modifications to the process environment variables. (See the +explanation of ``TIME_ZONE``, above, for why this would normally occur.) It's +assumed that you're already in full control of your environment in these cases. + Custom default settings ----------------------- diff --git a/docs/sitemaps.txt b/docs/sitemaps.txt new file mode 100644 index 0000000000..fec65572f2 --- /dev/null +++ b/docs/sitemaps.txt @@ -0,0 +1,320 @@ +===================== +The sitemap framework +===================== + +**New in Django development version**. + +Django comes with a high-level sitemap-generating framework that makes +creating `Google Sitemap`_ XML files easy. + +.. _Google Sitemap: http://www.google.com/webmasters/sitemaps/docs/en/protocol.html + +Overview +======== + +A sitemap is an XML file on your Web site that tells search-engine indexers how +frequently your pages change and how "important" certain pages are in relation +to other pages on your site. This information helps search engines index your +site. + +The Django sitemap framework automates the creation of this XML file by letting +you express this information in Python code. + +It works much like Django's `syndication framework`_. To create a sitemap, just +write a ``Sitemap`` class and point to it in your URLconf_. + +.. _syndication framework: http://www.djangoproject.com/documentation/syndication/ +.. _URLconf: http://www.djangoproject.com/documentation/url_dispatch/ + +Installation +============ + +To install the sitemap app, follow these steps: + + 1. Add ``'django.contrib.sitemaps'`` to your INSTALLED_APPS_ setting. + 2. Make sure ``'django.template.loaders.app_directories.load_template_source'`` + is in your TEMPLATE_LOADERS_ setting. It's in there by default, so + you'll only need to change this if you've changed that setting. + 3. Make sure you've installed the `sites framework`_. + +(Note: The sitemap application doesn't install any database tables. The only +reason it needs to go into ``INSTALLED_APPS`` is so that the +``load_template_source`` template loader can find the default templates.) + +.. _INSTALLED_APPS: http://www.djangoproject.com/documentation/settings/#installed-apps +.. _TEMPLATE_LOADERS: http://www.djangoproject.com/documentation/settings/#template-loaders +.. _sites framework: http://www.djangoproject.com/documentation/sites/ + +Initialization +============== + +To activate sitemap generation on your Django site, add this line to your +URLconf_: + + (r'^sitemap.xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps}) + +This tells Django to build a sitemap when a client accesses ``/sitemap.xml``. + +The name of the sitemap file is not important, but the location is. Google will +only index links in your sitemap for the current URL level and below. For +instance, if ``sitemap.xml`` lives in your root directory, it may reference any +URL in your site. However, if your sitemap lives at ``/content/sitemap.xml``, +it may only reference URLs that begin with ``/content/``. + +The sitemap view takes an extra, required argument: ``{'sitemaps': sitemaps}``. +``sitemaps`` should be a dictionary that maps a short section label (e.g., +``blog`` or ``news``) to its ``Sitemap`` class (e.g., ``BlogSitemap`` or +``NewsSitemap``). It may also map to an *instance* of a ``Sitemap`` class +(e.g., ``BlogSitemap(some_var)``). + +.. _URLconf: http://www.djangoproject.com/documentation/url_dispatch/ + +Sitemap classes +=============== + +A ``Sitemap`` class is a simple Python class that represents a "section" of +entries in your sitemap. For example, one ``Sitemap`` class could represent all +the entries of your weblog, while another could represent all of the events in +your events calendar. + +In the simplest case, all these sections get lumped together into one +``sitemap.xml``, but it's also possible to use the framework to generate a +sitemap index that references individual sitemap files, one per section. (See +`Creating a sitemap index`_ below.) + +``Sitemap`` classes must subclass ``django.contrib.sitemaps.Sitemap``. They can +live anywhere in your codebase. + +A simple example +================ + +Let's assume you have a blog system, with an ``Entry`` model, and you want your +sitemap to include all the links to your individual blog entries. Here's how +your sitemap class might look:: + + from django.contrib.sitemaps import Sitemap + from mysite.blog.models import Entry + + class BlogSitemap(Sitemap): + changefreq = "never" + priority = 0.5 + + def items(self): + return Entry.objects.filter(is_draft=False) + + def lastmod(self, obj): + return obj.pub_date + +Note: + + * ``changefreq`` and ``priority`` are class attributes corresponding to + ``<changefreq>`` and ``<priority>`` elements, respectively. They can be + made callable as functions, as ``lastmod`` was in the example. + * ``items()`` is simply a method that returns a list of objects. The objects + returned will get passed to any callable methods corresponding to a + sitemap property (``location``, ``lastmod``, ``changefreq``, and + ``priority``). + * ``lastmod`` should return a Python ``datetime`` object. + * There is no ``location`` method in this example, but you can provide it + in order to specify the URL for your object. By default, ``location()`` + calls ``get_absolute_url()`` on each object and returns the result. + +Sitemap class reference +======================= + +A ``Sitemap`` class can define the following methods/attributes: + +``items`` +--------- + +**Required.** A method that returns a list of objects. The framework doesn't +care what *type* of objects they are; all that matters is that these objects +get passed to the ``location()``, ``lastmod()``, ``changefreq()`` and +``priority()`` methods. + +``location`` +------------ + +**Optional.** Either a method or attribute. + +If it's a method, it should return the absolute URL for a given object as +returned by ``items()``. + +If it's an attribute, its value should be a string representing an absolute URL +to use for *every* object returned by ``items()``. + +In both cases, "absolute URL" means a URL that doesn't include the protocol or +domain. Examples: + + * Good: ``'/foo/bar/'`` + * Bad: ``'example.com/foo/bar/'`` + * Bad: ``'http://example.com/foo/bar/'`` + +If ``location`` isn't provided, the framework will call the +``get_absolute_url()`` method on each object as returned by ``items()``. + +``lastmod`` +----------- + +**Optional.** Either a method or attribute. + +If it's a method, it should take one argument -- an object as returned by +``items()`` -- and return that object's last-modified date/time, as a Python +``datetime.datetime`` object. + +If it's an attribute, its value should be a Python ``datetime.datetime`` object +representing the last-modified date/time for *every* object returned by +``items()``. + +``changefreq`` +-------------- + +**Optional.** Either a method or attribute. + +If it's a method, it should take one argument -- an object as returned by +``items()`` -- and return that object's change frequency, as a Python string. + +If it's an attribute, its value should be a string representing the change +frequency of *every* object returned by ``items()``. + +Possible values for ``changefreq``, whether you use a method or attribute, are: + + * ``'always'`` + * ``'hourly'`` + * ``'daily'`` + * ``'weekly'`` + * ``'monthly'`` + * ``'yearly'`` + * ``'never'`` + +``priority`` +------------ + +**Optional.** Either a method or attribute. + +If it's a method, it should take one argument -- an object as returned by +``items()`` -- and return that object's priority, as either a string or float. + +If it's an attribute, its value should be either a string or float representing +the priority of *every* object returned by ``items()``. + +Example values for ``priority``: ``0.4``, ``1.0``. The default priority of a +page is ``0.5``. See Google's documentation for more documentation. + +.. _Google's documentation: http://www.google.com/webmasters/sitemaps/docs/en/protocol.html + +Shortcuts +========= + +The sitemap framework provides a couple convenience classes for common cases: + +``FlatPageSitemap`` +------------------- + +The ``django.contrib.sitemaps.FlatPageSitemap`` class looks at all flatpages_ +defined for the current ``SITE_ID`` (see the `sites documentation`_) and +creates an entry in the sitemap. These entries include only the ``location`` +attribute -- not ``lastmod``, ``changefreq`` or ``priority``. + +.. _flatpages: http://www.djangoproject.com/documentation/flatpages/ +.. _sites documentation: http://www.djangoproject.com/documentation/sites/ + +``GenericSitemap`` +------------------ + +The ``GenericSitemap`` class works with any `generic views`_ you already have. +To use it, create an instance, passing in the same ``info_dict`` you pass to +the generic views. The only requirement is that the dictionary have a +``queryset`` entry. It may also have a ``date_field`` entry that specifies a +date field for objects retrieved from the ``queryset``. This will be used for +the ``lastmod`` attribute in the generated sitemap. You may also pass +``priority`` and ``changefreq`` keyword arguments to the ``GenericSitemap`` +constructor to specify these attributes for all URLs. + +.. _generic views: http://www.djangoproject.com/documentation/generic_views/ + +Example +------- + +Here's an example of a URLconf_ using both:: + + from django.conf.urls.defaults import * + from django.contrib.sitemaps import FlatPageSitemap, GenericSitemap + from mysite.blog.models import Entry + + info_dict = { + 'queryset': Entry.objects.all(), + 'date_field': 'pub_date', + } + + sitemaps = { + 'flatpages': FlatPageSitemap, + 'blog': GenericSitemap(info_dict, priority=0.6), + } + + urlpatterns = patterns('', + # some generic view using info_dict + # ... + + # the sitemap + (r'^sitemap.xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps}) + ) + +.. _URLconf: http://www.djangoproject.com/documentation/url_dispatch/ + +Creating a sitemap index +======================== + +The sitemap framework also has the ability to create a sitemap index that +references individual sitemap files, one per each section defined in your +``sitemaps`` dictionary. The only differences in usage are: + + * You use two views in your URLconf: ``django.contrib.sitemaps.views.index`` + and ``django.contrib.sitemaps.views.sitemap``. + * The ``django.contrib.sitemaps.views.sitemap`` view should take a + ``section`` keyword argument. + +Here is what the relevant URLconf lines would look like for the example above:: + + (r'^sitemap.xml$', 'django.contrib.sitemaps.views.index', {'sitemaps': sitemaps}) + (r'^sitemap-(?P<section>.+).xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps}) + +This will automatically generate a ``sitemap.xml`` file that references +both ``sitemap-flatpages.xml`` and ``sitemap-blog.xml``. The ``Sitemap`` +classes and the ``sitemaps`` dict don't change at all. + +Pinging Google +============== + +You may want to "ping" Google when your sitemap changes, to let it know to +reindex your site. The framework provides a function to do just that: +``django.contrib.sitemaps.ping_google()``. + +``ping_google()`` takes an optional argument, ``sitemap_url``, which should be +the absolute URL of your site's sitemap (e.g., ``'/sitemap.xml'``). If this +argument isn't provided, ``ping_google()`` will attempt to figure out your +sitemap by performing a reverse looking in your URLconf. + +``ping_google()`` raises the exception +``django.contrib.sitemaps.SitemapNotFound`` if it cannot determine your sitemap +URL. + +One useful way to call ``ping_google()`` is from a model's ``save()`` method:: + + from django.contrib.sitemaps import ping_google + + class Entry(models.Model): + # ... + def save(self): + super(Entry, self).save() + try: + ping_google() + except Exception: + # Bare 'except' because we could get a variety + # of HTTP-related exceptions. + pass + +A more efficient solution, however, would be to call ``ping_google()`` from a +cron script, or some other scheduled task. The function makes an HTTP request +to Google's servers, so you may not want to introduce that network overhead +each time you call ``save()``. diff --git a/docs/sites.txt b/docs/sites.txt index cca9f14f31..8c5f1fc64b 100644 --- a/docs/sites.txt +++ b/docs/sites.txt @@ -266,7 +266,18 @@ this:: If you attempt to use ``CurrentSiteManager`` and pass a field name that doesn't exist, Django will raise a ``ValueError``. +Finally, note that you'll probably want to keep a normal (non-site-specific) +``Manager`` on your model, even if you use ``CurrentSiteManager``. As explained +in the `manager documentation`_, if you define a manager manually, then Django +won't create the automatic ``objects = models.Manager()`` manager for you. +Also, note that certain parts of Django -- namely, the Django admin site and +generic views -- use whichever manager is defined *first* in the model, so if +you want your admin site to have access to all objects (not just site-specific +ones), put ``objects = models.Manager()`` in your model, before you define +``CurrentSiteManager``. + .. _manager: http://www.djangoproject.com/documentation/model_api/#managers +.. _manager documentation: http://www.djangoproject.com/documentation/model_api/#managers How Django uses the sites framework =================================== diff --git a/docs/syndication_feeds.txt b/docs/syndication_feeds.txt index c84785b20b..225b67eb02 100644 --- a/docs/syndication_feeds.txt +++ b/docs/syndication_feeds.txt @@ -427,7 +427,7 @@ This example illustrates all possible attributes and methods for a ``Feed`` clas author's e-mail as a normal Python string. """ - def author_name(self): + def author_email(self): """ Returns the feed's author's e-mail as a normal Python string. """ @@ -707,7 +707,7 @@ This example creates an Atom 1.0 feed and prints it to standard output:: ... title=u"My Weblog", ... link=u"http://www.example.com/", ... description=u"In which I write about what I ate today.", - ... language=u"en"), + ... language=u"en") >>> f.add_item(title=u"Hot dog today", ... link=u"http://www.example.com/entries/1/", ... description=u"<p>Today I had a Vienna Beef hot dog. It was pink, plump and perfect.</p>") diff --git a/docs/templates.txt b/docs/templates.txt index 4ba52b3263..0f0009b495 100644 --- a/docs/templates.txt +++ b/docs/templates.txt @@ -47,7 +47,7 @@ explained later in this document.:: JavaScript and CSV. You can use the template language for any text-based format. - Oh, and one more thing: Making humans edit XML is masochistic! + Oh, and one more thing: Making humans edit XML is sadistic! Variables ========= @@ -109,6 +109,21 @@ Some tags require beginning and ending tags (i.e. below describes all the built-in tags. You can create your own tags, if you know how to write Python code. +Comments +======== + +**New in Django development version** + +To comment-out part of a template, use the comment syntax: ``{# #}``. + +For example, this template would render as ``'hello'``:: + + {# greeting #}hello + +A comment can contain any template code, invalid or not. For example:: + + {# {% if foo %}bar{% else %} #} + Template inheritance ==================== @@ -141,6 +156,7 @@ It's easiest to understand template inheritance by starting with an example:: {% block content %}{% endblock %} </div> </body> + </html> This template, which we'll call ``base.html``, defines a simple HTML skeleton document that you might use for a simple two-column page. It's the job of @@ -196,6 +212,7 @@ like:: <p>This is my second entry.</p> </div> </body> + </html> Note that since the child template didn't define the ``sidebar`` block, the value from the parent template is used instead. Content within a ``{% block %}`` @@ -363,10 +380,15 @@ extends Signal that this template extends a parent template. -This tag may be used in two ways: ``{% extends "base.html" %}`` (with quotes) -uses the literal value "base.html" as the name of the parent template to -extend, or ``{% extends variable %}`` uses the value of ``variable`` as the -name of the parent template to extend. +This tag can be used in two ways: + + * ``{% extends "base.html" %}`` (with quotes) uses the literal value + ``"base.html"`` as the name of the parent template to extend. + + * ``{% extends variable %}`` uses the value of ``variable``. If the variable + evaluates to a string, Django will use that string as the name of the + parent template. If the variable evaluates to a ``Template`` object, + Django will use that object as the parent template. See `Template inheritance`_ for more information. @@ -493,6 +515,11 @@ If you need to combine ``and`` and ``or`` to do advanced logic, just use nested {% endif %} {% endif %} +Multiple uses of the same logical operator are fine, as long as you use the +same operator. For example, this is valid:: + + {% if athlete_list or coach_list or parent_list or teacher_list %} + ifchanged ~~~~~~~~~ @@ -528,6 +555,11 @@ The arguments can be hard-coded strings, so the following is valid:: ... {% endifequal %} +It is only possible to compare an argument to template variables or strings. +You cannot check for equality with Python objects such as ``True`` or +``False``. If you need to test if something is true or false, use the ``if`` +and ``ifnot`` tags instead. + ifnotequal ~~~~~~~~~~ @@ -951,13 +983,13 @@ any string. pluralize ~~~~~~~~~ -Returns a plural suffix if the value is not 1. By default, this suffix is ``'s'``. +Returns a plural suffix if the value is not 1. By default, this suffix is ``'s'``. Example:: You have {{ num_messages }} message{{ num_messages|pluralize }}. -For words that require a suffix other than ``'s'``, you can provide an alternate +For words that require a suffix other than ``'s'``, you can provide an alternate suffix as a parameter to the filter. Example:: @@ -1039,7 +1071,7 @@ Formats a date as the time since that date (i.e. "4 days, 6 hours"). Takes an optional argument that is a variable containing the date to use as the comparison point (without the argument, the comparison point is *now*). For example, if ``blog_date`` is a date instance representing midnight on 1 -June 2006, and ``comment_date`` is a date instanace for 08:00 on 1 June 2006, +June 2006, and ``comment_date`` is a date instance for 08:00 on 1 June 2006, then ``{{ comment_date|timesince:blog_date }}`` would return "8 hours". timeuntil diff --git a/docs/templates_python.txt b/docs/templates_python.txt index d353abb5bc..ae2582d7b8 100644 --- a/docs/templates_python.txt +++ b/docs/templates_python.txt @@ -198,25 +198,35 @@ some things to keep in mind: How invalid variables are handled ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -In Django 0.91, if a variable doesn't exist, the template system fails -silently. The variable is replaced with an empty string:: +Generally, if a variable doesn't exist, the template system inserts the +value of the ``TEMPLATE_STRING_IF_INVALID`` setting, which is set to ``''`` +(the empty string) by default. - >>> t = Template("My name is {{ my_name }}.") - >>> c = Context({"foo": "bar"}) - >>> t.render(c) - "My name is ." - -This applies to any level of lookup:: +Filters that are applied to an invalid variable will only be applied if +``TEMPLATE_STRING_IF_INVALID`` is set to ``''`` (the empty string). If +``TEMPLATE_STRING_IF_INVALID`` is set to any other value, variable +filters will be ignored. - >>> t = Template("My name is {{ person.fname }} {{ person.lname }}.") - >>> c = Context({"person": {"fname": "Stan"}}) - >>> t.render(c) - "My name is Stan ." +This behavior is slightly different for the ``if``, ``for`` and ``regroup`` +template tags. If an invalid variable is provided to one of these template +tags, the variable will be interpreted as ``None``. Filters are always +applied to invalid variables within these template tags. -If a variable doesn't exist, the template system inserts the value of the -``TEMPLATE_STRING_IF_INVALID`` setting, which is set to ``''`` (the empty -string) by default. +.. admonition:: For debug purposes only! + While ``TEMPLATE_STRING_IF_INVALID`` can be a useful debugging tool, + it is a bad idea to turn it on as a 'development default'. + + Many templates, including those in the Admin site, rely upon the + silence of the template system when a non-existent variable is + encountered. If you assign a value other than ``''`` to + ``TEMPLATE_STRING_IF_INVALID``, you will experience rendering + problems with these templates and sites. + + Generally, ``TEMPLATE_STRING_IF_INVALID`` should only be enabled + in order to debug a specific template problem, then cleared + once debugging is complete. + Playing with Context objects ---------------------------- @@ -274,9 +284,10 @@ an `HttpRequest object`_ as its first argument. For example:: The second difference is that it automatically populates the context with a few variables, according to your `TEMPLATE_CONTEXT_PROCESSORS setting`_. -The ``TEMPLATE_CONTEXT_PROCESSORS`` setting is a tuple of callables that take a -request object as their argument and return a dictionary of items to be merged -into the context. By default, ``TEMPLATE_CONTEXT_PROCESSORS`` is set to:: +The ``TEMPLATE_CONTEXT_PROCESSORS`` setting is a tuple of callables -- called +**context processors** -- that take a request object as their argument and +return a dictionary of items to be merged into the context. By default, +``TEMPLATE_CONTEXT_PROCESSORS`` is set to:: ("django.core.context_processors.auth", "django.core.context_processors.debug", @@ -300,6 +311,20 @@ optional, third positional argument, ``processors``. In this example, the 'foo': 'bar', }, [ip_address_processor]) +Note:: + If you're using Django's ``render_to_response()`` shortcut to populate a + template with the contents of a dictionary, your template will be passed a + ``Context`` instance by default (not a ``RequestContext``). To use a + ``RequestContext`` in your template rendering, pass an optional third + argument to ``render_to_response()``: a ``RequestContext`` + instance. Your code might look like this:: + + def some_view(request): + # ... + return render_to_response('my_template'html', + my_data_dictionary, + context_instance=RequestContext(request)) + Here's what each of the default processors does: .. _HttpRequest object: http://www.djangoproject.com/documentation/request_response/#httprequest-objects @@ -314,13 +339,22 @@ If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every * ``user`` -- An ``auth.User`` instance representing the currently logged-in user (or an ``AnonymousUser`` instance, if the client isn't logged in). See the `user authentication docs`. - * ``messages`` -- A list of ``auth.Message`` objects for the currently - logged-in user. - * ``perms`` -- An instance of ``django.core.context_processors.PermWrapper``, - representing the permissions that the currently logged-in user has. See - the `permissions docs`_. + + * ``messages`` -- A list of messages (as strings) for the currently + logged-in user. Behind the scenes, this calls + ``request.user.get_and_delete_messages()`` for every request. That method + collects the user's messages and deletes them from the database. + + Note that messages are set with ``user.add_message()``. See the + `message docs`_ for more. + + * ``perms`` -- An instance of + ``django.core.context_processors.PermWrapper``, representing the + permissions that the currently logged-in user has. See the `permissions + docs`_. .. _user authentication docs: http://www.djangoproject.com/documentation/authentication/#users +.. _message docs: http://www.djangoproject.com/documentation/authentication/#messages .. _permissions docs: http://www.djangoproject.com/documentation/authentication/#permissions django.core.context_processors.debug @@ -357,10 +391,22 @@ django.core.context_processors.request ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every -``DjangoContext`` will contain a variable ``request``, which is the current +``RequestContext`` will contain a variable ``request``, which is the current `HttpRequest object`_. Note that this processor is not enabled by default; you'll have to activate it. +Writing your own context processors +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A context processor has a very simple interface: It's just a Python function +that takes one argument, an ``HttpRequest`` object, and returns a dictionary +that gets added to the template context. Each context processor *must* return +a dictionary. + +Custom context processors can live anywhere in your code base. All Django cares +about is that your custom context processors are pointed-to by your +``TEMPLATE_CONTEXT_PROCESSORS`` setting. + Loading templates ----------------- @@ -758,17 +804,17 @@ will use the function's name as the tag name. Shortcut for simple tags ~~~~~~~~~~~~~~~~~~~~~~~~ -Many template tags take a single argument -- a string or a template variable -reference -- and return a string after doing some processing based solely on +Many template tags take a number of arguments -- strings or a template variables +-- and return a string after doing some processing based solely on the input argument and some external information. For example, the ``current_time`` tag we wrote above is of this variety: we give it a format string, it returns the time as a string. To ease the creation of the types of tags, Django provides a helper function, ``simple_tag``. This function, which is a method of -``django.template.Library``, takes a function that accepts one argument, wraps -it in a ``render`` function and the other necessary bits mentioned above and -registers it with the template system. +``django.template.Library``, takes a function that accepts any number of +arguments, wraps it in a ``render`` function and the other necessary bits +mentioned above and registers it with the template system. Our earlier ``current_time`` function could thus be written like this:: @@ -784,18 +830,23 @@ In Python 2.4, the decorator syntax also works:: ... A couple of things to note about the ``simple_tag`` helper function: - * Only the (single) argument is passed into our function. * Checking for the required number of arguments, etc, has already been done by the time our function is called, so we don't need to do that. * The quotes around the argument (if any) have already been stripped away, so we just receive a plain string. + * If the argument was a template variable, our function is passed the + current value of the variable, not the variable itself. + +When your template tag does not need access to the current context, writing a +function to work with the input values and using the ``simple_tag`` helper is +the easiest way to create a new tag. Inclusion tags ~~~~~~~~~~~~~~ Another common type of template tag is the type that displays some data by rendering *another* template. For example, Django's admin interface uses custom -template tags to display the buttons along the botton of the "add/change" form +template tags to display the buttons along the bottom of the "add/change" form pages. Those buttons always look the same, but the link targets change depending on the object being edited -- so they're a perfect case for using a small template that is filled with details from the current object. (In the admin's @@ -1041,7 +1092,7 @@ Configuring the template system in standalone mode .. note:: This section is only of interest to people trying to use the template - system as an output component in another application. If you are using the + system as an output component in another application. If you're using the template system as part of a Django application, nothing here applies to you. @@ -1058,7 +1109,7 @@ described in the `settings file`_ documentation. Simply import the appropriate pieces of the templating system and then, *before* you call any of the templating functions, call ``django.conf.settings.configure()`` with any settings you wish to specify. You might want to consider setting at least -``TEMPLATE_DIRS`` (if you are going to use template loaders), +``TEMPLATE_DIRS`` (if you're going to use template loaders), ``DEFAULT_CHARSET`` (although the default of ``utf-8`` is probably fine) and ``TEMPLATE_DEBUG``. All available settings are described in the `settings documentation`_, and any setting starting with *TEMPLATE_* diff --git a/docs/testing.txt b/docs/testing.txt new file mode 100644 index 0000000000..19eef9f071 --- /dev/null +++ b/docs/testing.txt @@ -0,0 +1,453 @@ +=========================== +Testing Django applications +=========================== + +**New in Django development version**. + +Automated testing is an extremely useful weapon in the bug-killing arsenal +of the modern developer. When initially writing code, a test suite can be +used to validate that code behaves as expected. When refactoring or +modifying code, tests serve as a guide to ensure that behavior hasn't +changed unexpectedly as a result of the refactor. + +Testing an web application is a complex task, as there are many +components of a web application that must be validated and tested. To +help you test your application, Django provides a test execution +framework, and range of utilities that can be used to stimulate and +inspect various facets of a web application. + + This testing framework is currently under development, and may change + slightly before the next official Django release. + + (That's *no* excuse not to write tests, though!) + +Writing tests +============= + +Tests in Django come in two forms: doctests and unit tests. + +Writing doctests +---------------- + +Doctests use Python's standard doctest_ module, which searches for tests in +your docstrings. Django's test runner looks for doctests in your ``models.py`` +file, and executes any that it finds. Django will also search for a file +called ``tests.py`` in the application directory (i.e., the directory that +holds ``models.py``). If a ``tests.py`` is found, it will also be searched +for doctests. + +.. admonition:: What's a **docstring**? + + A good explanation of docstrings (and some guidlines for using them + effectively) can be found in :PEP:`257`: + + A docstring is a string literal that occurs as the first statement in + a module, function, class, or method definition. Such a docstring + becomes the ``__doc__`` special attribute of that object. + + Since tests often make great documentation, doctest lets you put your + tests directly in your docstrings. + +You can put doctest strings on any object in your ``models.py``, but it's +common practice to put application-level doctests in the module docstring, and +model-level doctests in the docstring for each model. + +For example:: + + from django.db import model + + class Animal(models.Model): + """ + An animal that knows how to make noise + + # Create some animals + >>> lion = Animal.objects.create(name="lion", sound="roar") + >>> cat = Animal.objects.create(name="cat", sound="meow") + + # Make 'em speak + >>> lion.speak() + 'The lion says "roar"' + >>> cat.speak() + 'The cat says "meow"' + """ + + name = models.CharField(maxlength=20) + sound = models.CharField(maxlength=20) + + def speak(self): + return 'The %s says "%s"' % (self.name, self.sound) + +When you `run your tests`_, the test utility will find this docstring, notice +that portions of it look like an interactive Python session, and execute those +lines while checking that the results match. + +For more details about how doctest works, see the `standard library +documentation for doctest`_ + +.. _doctest: http://docs.python.org/lib/module-doctest.html +.. _standard library documentation for doctest: doctest_ + +Writing unittests +----------------- + +Like doctests, Django's unit tests use a standard library module: unittest_. +As with doctests, Django's test runner looks for any unit test cases defined +in ``models.py``, or in a ``tests.py`` file stored in the application +directory. + +An equivalent unittest test case for the above example would look like:: + + import unittest + from myapp.models import Animal + + class AnimalTestCase(unittest.TestCase): + + def setUp(self): + self.lion = Animal.objects.create(name="lion", sound="roar") + self.cat = Animal.objects.create(name="cat", sound="meow") + + def testSpeaking(self): + self.assertEquals(self.lion.speak(), 'The lion says "roar"') + self.assertEquals(self.cat.speak(), 'The cat says "meow"') + +When you `run your tests`_, the test utility will find all the test cases +(that is, subclasses of ``unittest.TestCase``) in ``models.py`` and +``tests.py``, automatically build a test suite out of those test cases, +and run that suite. + +For more details about ``unittest``, see the `standard library unittest +documentation`_. + +.. _unittest: http://docs.python.org/lib/module-unittest.html +.. _standard library unittest documentation: unittest_ +.. _run your tests: `Running tests`_ + +Which should I use? +------------------- + +Choosing a test framework is often contentious, so Django simply supports +both of the standard Python test frameworks. Choosing one is up to each +developer's personal tastes; each is supported equally. Since each test +system has different benefits, the best approach is probably to use both +together, picking the test system to match the type of tests you need to +write. + +For developers new to testing, however, this choice can seem +confusing, so here are a few key differences to help you decide weather +doctests or unit tests are right for you. + +If you've been using Python for a while, ``doctest`` will probably feel more +"pythonic". It's designed to make writing tests as easy as possible, so +there's no overhead of writing classes or methods; you simply put tests in +docstrings. This gives the added advantage of given your modules automatic +documentation -- well-written doctests can kill both the documentation and the +testing bird with a single stone. + +For developers just getting started with testing, using doctests will probably +get you started faster. + +The ``unittest`` framework will probably feel very familiar to developers +coming from Java. Since ``unittest`` is inspired by Java's JUnit, if +you've used testing frameworks in other languages that similarly were +inspired by JUnit, ``unittest`` should also feel pretty familiar. + +Since ``unittest`` is organized around classes and methods, if you need +to write a bunch of tests that all share similar code, you can easily use +subclass to abstract common tasks; this makes test code shorter and cleaner. +There's also support for explicit setup and/or cleanup routines, which give +you a high level of control over the environment your test cases run in. + +Again, remember that you can use both systems side-by-side (even in the same +app). In the end, most projects will eventually end up using both; each shines +in different circumstances. + +Testing Tools +============= + +To assist in testing various features of your application, Django provides +tools that can be used to establish tests and test conditions. + +* `Test Client`_ +* Fixtures_ + +Test Client +----------- + +The Test Client is a simple dummy browser. It allows you to simulate +GET and POST requests on a URL, and observe the response that is received. +This allows you to test that the correct view is executed for a given URL, +and that the view constructs the correct response. + +As the response is generated, the Test Client gathers details on the +Template and Context objects that were used to generate the response. These +Templates and Contexts are then provided as part of the response, and can be +used as test conditions. + +.. admonition:: Test Client vs Browser Automation? + + The Test Client is not intended as a replacement for Twill_, Selenium_, + or other browser automation frameworks - it is intended to allow + testing of the contexts and templates produced by a view, + rather than the HTML rendered to the end-user. + + A comprehensive test suite should use a combination of both: Test Client + tests to establish that the correct view is being called and that + the view is collecting the correct context data, and Browser Automation + tests to check that user interface behaves as expected. + +.. _Twill: http://twill.idyll.org/ +.. _Selenium: http://www.openqa.org/selenium/ + +The Test Client is stateful; if a cookie is returned as part of a response, +that cookie is provided as part of the next request issued to that Client +instance. Expiry policies for these cookies are not followed; if you want +a cookie to expire, either delete it manually from ``client.cookies``, or +create a new Client instance (which will effectively delete all cookies). + +Making requests +~~~~~~~~~~~~~~~ + +Creating an instance of ``Client`` (``django.test.client.Client``) requires +no arguments at time of construction. Once constructed, the following methods +can be invoked on the ``Client`` instance. + +``get(path, data={})`` + Make a GET request on the provided ``path``. The key-value pairs in the + data dictionary will be used to create a GET data payload. For example:: + + c = Client() + c.get('/customers/details/', {'name':'fred', 'age':7}) + + will result in the evaluation of a GET request equivalent to:: + + http://yoursite.com/customers/details/?name='fred'&age=7 + +``post(path, data={})`` + Make a POST request on the provided ``path``. The key-value pairs in the + data dictionary will be used to create the POST data payload. This payload + will be transmitted with the mimetype ``multipart/form-data``. + + However submitting files is a special case. To POST a file, you need only + provide the file field name as a key, and a file handle to the file you wish to + upload as a value. The Test Client will populate the two POST fields (i.e., + ``field`` and ``field_file``) required by FileField. For example:: + + c = Client() + f = open('wishlist.doc') + c.post('/customers/wishes/', {'name':'fred', 'attachment':f}) + f.close() + + will result in the evaluation of a POST request on ``/customers/wishes/``, + with a POST dictionary that contains `name`, `attachment` (containing the + file name), and `attachment_file` (containing the file data). Note that you + need to manually close the file after it has been provided to the POST. + +``login(path, username, password)`` + In a production site, it is likely that some views will be protected with + the @login_required URL provided by ``django.contrib.auth``. Interacting + with a URL that has been login protected is a slightly complex operation, + so the Test Client provides a simple URL to automate the login process. A + call to ``login()`` stimulates the series of GET and POST calls required + to log a user into a @login_required protected URL. + + If login is possible, the final return value of ``login()`` is the response + that is generated by issuing a GET request on the protected URL. If login + is not possible, ``login()`` returns False. + + Note that since the test suite will be executed using the test database, + which contains no users by default. As a result, logins for your production + site will not work. You will need to create users as part of the test suite + to be able to test logins to your application. + +Testing Responses +~~~~~~~~~~~~~~~~~ + +The ``get()``, ``post()`` and ``login()`` methods all return a Response +object. This Response object has the following properties that can be used +for testing purposes: + + =============== ========================================================== + Property Description + =============== ========================================================== + ``status_code`` The HTTP status of the response. See RFC2616_ for a + full list of HTTP status codes. + + ``content`` The body of the response. The is the final page + content as rendered by the view, or any error message + (such as the URL for a 302 redirect). + + ``template`` The Template instance that was used to render the final + content. Testing ``template.name`` can be particularly + useful; if the template was loaded from a file, + ``template.name`` will be the file name that was loaded. + + If multiple templates were rendered, (e.g., if one + template includes another template),``template`` will + be a list of Template objects, in the order in which + they were rendered. + + ``context`` The Context that was used to render the template that + produced the response content. + + As with ``template``, if multiple templates were rendered + ``context`` will be a list of Context objects, stored in + the order in which they were rendered. + =============== ========================================================== + +.. _RFC2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html + +The following is a simple unit test using the Test Client:: + + import unittest + from django.test.client import Client + + class SimpleTest(unittest.TestCase): + def setUp(self): + # Every test needs a client + self.client = Client() + def test_details(self): + # Issue a GET request + response = self.client.get('/customer/details/') + + # Check that the respose is 200 OK + self.failUnlessEqual(response.status_code, 200) + # Check that the rendered context contains 5 customers + self.failUnlessEqual(len(response.context['customers']), 5) + +Fixtures +-------- + +Feature still to come... + +Running tests +============= + +Run your tests using your project's ``manage.py`` utility:: + + $ ./manage.py test + +If you only want to run tests for a particular application, add the +application name to the command line. For example, if your +``INSTALLED_APPS`` contains ``myproject.polls`` and ``myproject.animals``, +but you only want to run the animals unit tests, run:: + + $ ./manage.py test animals + +When you run your tests, you'll see a bunch of text flow by as the test +database is created and models are initialized. This test database is +created from scratch every time you run your tests. + +By default, the test database gets its name by prepending ``test_`` to +the database name specified by the ``DATABASE_NAME`` setting; all other +database settings will the same as they would be for the project normally. +If you wish to use a name other than the default for the test database, +you can use the ``TEST_DATABASE_NAME`` setting to provide a name. + +Once the test database has been established, Django will run your tests. +If everything goes well, at the end you'll see:: + + ---------------------------------------------------------------------- + Ran 22 tests in 0.221s + + OK + +If there are test failures, however, you'll see full details about what tests +failed:: + + ====================================================================== + FAIL: Doctest: ellington.core.throttle.models + ---------------------------------------------------------------------- + Traceback (most recent call last): + File "/dev/django/test/doctest.py", line 2153, in runTest + raise self.failureException(self.format_failure(new.getvalue())) + AssertionError: Failed doctest test for myapp.models + File "/dev/myapp/models.py", line 0, in models + + ---------------------------------------------------------------------- + File "/dev/myapp/models.py", line 14, in myapp.models + Failed example: + throttle.check("actor A", "action one", limit=2, hours=1) + Expected: + True + Got: + False + + ---------------------------------------------------------------------- + Ran 2 tests in 0.048s + + FAILED (failures=1) + +When the tests have all been executed, the test database is destroyed. + +Using a different testing framework +=================================== + +Doctest and Unittest are not the only Python testing frameworks. While +Django doesn't provide explicit support these alternative frameworks, +it does provide a mechanism to allow you to invoke tests constructed for +an alternative framework as if they were normal Django tests. + +When you run ``./manage.py test``, Django looks at the ``TEST_RUNNER`` +setting to determine what to do. By default, ``TEST_RUNNER`` points to ``django.test.simple.run_tests``. This method defines the default Django +testing behavior. This behavior involves: + +#. Performing global pre-test setup +#. Creating the test database +#. Running ``syncdb`` to install models and initial data into the test database +#. Looking for Unit Tests and Doctests in ``models.py`` and ``tests.py`` file for each installed application +#. Running the Unit Tests and Doctests that are found +#. Destroying the test database. +#. Performing global post-test teardown + +If you define your own test runner method and point ``TEST_RUNNER`` +at that method, Django will execute your test runner whenever you run +``./manage.py test``. In this way, it is possible to use any test +framework that can be executed from Python code. + +Defining a test runner +---------------------- +By convention, a test runner should be called ``run_tests``; however, you +can call it anything you want. The only requirement is that it accept two +arguments: + +``run_tests(module_list, verbosity=1)`` + The module list is the list of Python modules that contain the models to be + tested. This is the same format returned by ``django.db.models.get_apps()`` + + Verbosity determines the amount of notification and debug information that + will be printed to the console; '0' is no output, '1' is normal output, + and `2` is verbose output. + +Testing utilities +----------------- + +To assist in the creation of your own test runner, Django provides +a number of utility methods in the ``django.test.utils`` module. + +``setup_test_environment()`` + Performs any global pre-test setup, such as the installing the + instrumentation of the template rendering system. + +``teardown_test_environment()`` + Performs any global post-test teardown, such as removing the instrumentation + of the template rendering system. + +``create_test_db(verbosity=1, autoclobber=False)`` + Creates a new test database, and run ``syncdb`` against it. + + ``verbosity`` has the same behavior as in the test runner. + + ``Autoclobber`` describes the behavior that will occur if a database with + the same name as the test database is discovered. If ``autoclobber`` is False, + the user will be asked to approve destroying the existing database. ``sys.exit`` + is called if the user does not approve. If autoclobber is ``True``, the database + will be destroyed without consulting the user. + + ``create_test_db()`` has the side effect of modifying + ``settings.DATABASE_NAME`` to match the name of the test database. + +``destroy_test_db(old_database_name, verbosity=1)`` + Destroys the database with the name ``settings.DATABASE_NAME`` matching, + and restores the value of ``settings.DATABASE_NAME`` to the provided name. + + ``verbosity`` has the same behavior as in the test runner. diff --git a/docs/transactions.txt b/docs/transactions.txt index c1cd5aa984..2b0755a257 100644 --- a/docs/transactions.txt +++ b/docs/transactions.txt @@ -2,7 +2,8 @@ Managing database transactions ============================== -Django gives you a few ways to control how database transactions are managed. +Django gives you a few ways to control how database transactions are managed, +if you're using a database that supports transactions. Django's default transaction behavior ===================================== @@ -144,3 +145,19 @@ Thus, this is best used in situations where you want to run your own transaction-controlling middleware or do something really strange. In almost all situations, you'll be better off using the default behavior, or the transaction middleware, and only modify selected functions as needed. + +Transactions in MySQL +===================== + +If you're using MySQL, your tables may or may not support transactions; it +depends on your MySQL version and the table types you're using. (By +"table types," we mean something like "InnoDB" or "MyISAM".) MySQL transaction +peculiarities are outside the scope of this article, but the MySQL site has +`information on MySQL transactions`_. + +If your MySQL setup does *not* support transactions, then Django will function +in auto-commit mode: Statements will be executed and committed as soon as +they're called. If your MySQL setup *does* support transactions, Django will +handle transactions as explained in this document. + +.. _information on MySQL transactions: http://dev.mysql.com/books/mysqlpress/mysql-tutorial/ch10.html diff --git a/docs/tutorial01.txt b/docs/tutorial01.txt index c353e1ab4b..1113b603da 100644 --- a/docs/tutorial01.txt +++ b/docs/tutorial01.txt @@ -81,7 +81,7 @@ the following output on the command line:: Validating models... 0 errors found. - Django version 0.95 (post-magic-removal), using settings 'mysite.settings' + Django version 0.95, using settings 'mysite.settings' Development server is running at http://127.0.0.1:8000/ Quit the server with CONTROL-C (Unix) or CTRL-BREAK (Windows). @@ -346,6 +346,8 @@ Note the following: the SQL to the database. If you're interested, also run the following commands: + * ``python manage.py validate polls`` -- Checks for any errors in the + construction of your models. * ``python manage.py sqlinitialdata polls`` -- Outputs any initial data required for Django's admin framework and your models. diff --git a/docs/tutorial02.txt b/docs/tutorial02.txt index 84eae3eb83..f6d4045fa3 100644 --- a/docs/tutorial02.txt +++ b/docs/tutorial02.txt @@ -54,7 +54,8 @@ http://127.0.0.1:8000/admin/. You should see the admin's login screen: Enter the admin site ==================== -Now, try logging in. You should see the Django admin index page: +Now, try logging in. (You created a superuser account in the first part of this +tutorial, remember?) You should see the Django admin index page: .. image:: http://media.djangoproject.com/img/doc/tutorial/admin02t.png :alt: Django admin index page @@ -376,16 +377,16 @@ By default, ``TEMPLATE_DIRS`` is empty. So, let's add a line to it, to tell Django where our templates live:: TEMPLATE_DIRS = ( - "/home/mytemplates", # Change this to your own directory. + "/home/my_username/mytemplates", # Change this to your own directory. ) Now copy the template ``admin/base_site.html`` from within the default Django admin template directory (``django/contrib/admin/templates``) into an ``admin`` subdirectory of whichever directory you're using in ``TEMPLATE_DIRS``. For -example, if your ``TEMPLATE_DIRS`` includes ``"/home/mytemplates"``, as above, -then copy ``django/contrib/admin/templates/admin/base_site.html`` to -``/home/mytemplates/admin/base_site.html``. Don't forget that ``admin`` -subdirectory. +example, if your ``TEMPLATE_DIRS`` includes ``"/home/my_username/mytemplates"``, +as above, then copy ``django/contrib/admin/templates/admin/base_site.html`` to +``/home/my_username/mytemplates/admin/base_site.html``. Don't forget that +``admin`` subdirectory. Then, just edit the file and replace the generic Django text with your own site's name and URL as you see fit. diff --git a/docs/tutorial03.txt b/docs/tutorial03.txt index 3a830eb76f..c4c1b4c546 100644 --- a/docs/tutorial03.txt +++ b/docs/tutorial03.txt @@ -91,7 +91,7 @@ Finally, it calls that ``detail()`` function like so:: The ``poll_id='23'`` part comes from ``(?P<poll_id>\d+)``. Using parenthesis around a pattern "captures" the text matched by that pattern and sends it as an argument to the view function; the ``?P<poll_id>`` defines the name that will be used to -identify the matched pattern; and ``\d+`` is a regular experession to match a sequence of +identify the matched pattern; and ``\d+`` is a regular expression to match a sequence of digits (i.e., a number). Because the URL patterns are regular expressions, there really is no limit on @@ -189,7 +189,7 @@ publication date:: from django.http import HttpResponse def index(request): - latest_poll_list = Poll.objects.all().order_by('-pub_date') + latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5] output = ', '.join([p.question for p in latest_poll_list]) return HttpResponse(output) @@ -202,7 +202,7 @@ So let's use Django's template system to separate the design from Python:: from django.http import HttpResponse def index(request): - latest_poll_list = Poll.objects.all().order_by('-pub_date') + latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5] t = loader.get_template('polls/index.html') c = Context({ 'latest_poll_list': latest_poll_list, @@ -257,7 +257,7 @@ provides a shortcut. Here's the full ``index()`` view, rewritten:: from mysite.polls.models import Poll def index(request): - latest_poll_list = Poll.objects.all().order_by('-pub_date') + latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5] return render_to_response('polls/index.html', {'latest_poll_list': latest_poll_list}) Note that we no longer need to import ``loader``, ``Context`` or @@ -288,7 +288,7 @@ exception if a poll with the requested ID doesn't exist. A shortcut: get_object_or_404() ------------------------------- -It's a very common idiom to use ``get_object()`` and raise ``Http404`` if the +It's a very common idiom to use ``get()`` and raise ``Http404`` if the object doesn't exist. Django provides a shortcut. Here's the ``detail()`` view, rewritten:: @@ -313,8 +313,8 @@ exist. foremost design goals of Django is to maintain loose coupling. There's also a ``get_list_or_404()`` function, which works just as -``get_object_or_404()`` -- except using ``get_list()`` instead of -``get_object()``. It raises ``Http404`` if the list is empty. +``get_object_or_404()`` -- except using ``filter()`` instead of +``get()``. It raises ``Http404`` if the list is empty. Write a 404 (page not found) view ================================= diff --git a/docs/tutorial04.txt b/docs/tutorial04.txt index 8ef4a03c6d..c5e2ea3cea 100644 --- a/docs/tutorial04.txt +++ b/docs/tutorial04.txt @@ -198,7 +198,7 @@ By default, the ``object_detail`` generic view uses a template called ``vote()``. Similarly, the ``object_list`` generic view uses a template called -``<app name>/<module name>_list.html``. Thus, rename ``poll/index.html`` to +``<app name>/<module name>_list.html``. Thus, rename ``polls/index.html`` to ``polls/poll_list.html``. Because we have more than one entry in the URLconf that uses ``object_detail`` @@ -206,8 +206,8 @@ for the polls app, we manually specify a template name for the results view: ``template_name='polls/results.html'``. Otherwise, both views would use the same template. Note that we use ``dict()`` to return an altered dictionary in place. -In previous versions of the tutorial, the templates have been provided with a context -that contains the ``poll` and ``latest_poll_list`` context variables. However, +In previous parts of the tutorial, the templates have been provided with a context +that contains the ``poll`` and ``latest_poll_list`` context variables. However, the generic views provide the variables ``object`` and ``object_list`` as context. Therefore, you need to change your templates to match the new context variables. Go through your templates, and modify any reference to ``latest_poll_list`` to diff --git a/docs/url_dispatch.txt b/docs/url_dispatch.txt index 498a906d5e..00a7af027a 100644 --- a/docs/url_dispatch.txt +++ b/docs/url_dispatch.txt @@ -263,12 +263,12 @@ Here's the example URLconf from the `Django overview`_:: from django.conf.urls.defaults import * urlpatterns = patterns('', - (r'^articles/(\d{4})/$', 'myproject.news.views.year_archive'), - (r'^articles/(\d{4})/(\d{2})/$', 'myproject.news.views.month_archive'), - (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'myproject.news.views.article_detail'), + (r'^articles/(\d{4})/$', 'mysite.news.views.year_archive'), + (r'^articles/(\d{4})/(\d{2})/$', 'mysite.news.views.month_archive'), + (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'mysite.news.views.article_detail'), ) -In this example, each view has a common prefix -- ``'myproject.news.views'``. +In this example, each view has a common prefix -- ``'mysite.news.views'``. Instead of typing that out for each entry in ``urlpatterns``, you can use the first argument to the ``patterns()`` function to specify a prefix to apply to each view function. @@ -277,7 +277,7 @@ With this in mind, the above example can be written more concisely as:: from django.conf.urls.defaults import * - urlpatterns = patterns('myproject.news.views', + urlpatterns = patterns('mysite.news.views', (r'^articles/(\d{4})/$', 'year_archive'), (r'^articles/(\d{4})/(\d{2})/$', 'month_archive'), (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'article_detail'), @@ -389,3 +389,90 @@ to pass metadata and options to views. .. _generic views: http://www.djangoproject.com/documentation/generic_views/ .. _syndication framework: http://www.djangoproject.com/documentation/syndication/ + +Passing extra options to ``include()`` +-------------------------------------- + +**New in the Django development version.** + +Similarly, you can pass extra options to ``include()``. When you pass extra +options to ``include()``, *each* line in the included URLconf will be passed +the extra options. + +For example, these two URLconf sets are functionally identical: + +Set one:: + + # main.py + urlpatterns = patterns('', + (r'^blog/', include('inner'), {'blogid': 3}), + ) + + # inner.py + urlpatterns = patterns('', + (r'^archive/$', 'mysite.views.archive'), + (r'^about/$', 'mysite.views.about'), + ) + +Set two:: + + # main.py + urlpatterns = patterns('', + (r'^blog/', include('inner')), + ) + + # inner.py + urlpatterns = patterns('', + (r'^archive/$', 'mysite.views.archive', {'blogid': 3}), + (r'^about/$', 'mysite.views.about', {'blogid': 3}), + ) + +Note that extra options will *always* be passed to *every* line in the included +URLconf, regardless of whether the line's view actually accepts those options +as valid. For this reason, this technique is only useful if you're certain that +every view in the the included URLconf accepts the extra options you're passing. + +Passing callable objects instead of strings +=========================================== + +**New in the Django development version.** + +Some developers find it more natural to pass the actual Python function object +rather than a string containing the path to its module. This alternative is +supported -- you can pass any callable object as the view. + +For example, given this URLconf in "string" notation:: + + urlpatterns = patterns('', + (r'^archive/$', 'mysite.views.archive'), + (r'^about/$', 'mysite.views.about'), + (r'^contact/$', 'mysite.views.contact'), + ) + +You can accomplish the same thing by passing objects rather than strings. Just +be sure to import the objects:: + + from mysite.views import archive, about, contact + + urlpatterns = patterns('', + (r'^archive/$', archive), + (r'^about/$', about), + (r'^contact/$', contact), + ) + +The following example is functionally identical. It's just a bit more compact +because it imports the module that contains the views, rather than importing +each view individually:: + + from mysite import views + + urlpatterns = patterns('', + (r'^archive/$', views.archive), + (r'^about/$', views.about), + (r'^contact/$', views.contact), + ) + +The style you use is up to you. + +Note that if you use this technique -- passing objects rather than strings -- +the view prefix (as explained in "The view prefix" above) will have no effect. diff --git a/ez_setup.py b/ez_setup.py deleted file mode 100644 index fe3983fef0..0000000000 --- a/ez_setup.py +++ /dev/null @@ -1,231 +0,0 @@ -#!python -"""Bootstrap setuptools installation - -If you want to use setuptools in your package's setup.py, just include this -file in the same directory with it, and add this to the top of your setup.py:: - - from ez_setup import use_setuptools - use_setuptools() - -If you want to require a specific version of setuptools, set a download -mirror, or use an alternate download directory, you can do so by supplying -the appropriate options to ``use_setuptools()``. - -This file can also be run as a script to install or upgrade setuptools. -""" -import sys -DEFAULT_VERSION = "0.6a10" -DEFAULT_URL = "http://cheeseshop.python.org/packages/%s/s/setuptools/" % sys.version[:3] - -md5_data = { - 'setuptools-0.5a13-py2.3.egg': '85edcf0ef39bab66e130d3f38f578c86', - 'setuptools-0.5a13-py2.4.egg': 'ede4be600e3890e06d4ee5e0148e092a', - 'setuptools-0.6a1-py2.3.egg': 'ee819a13b924d9696b0d6ca6d1c5833d', - 'setuptools-0.6a1-py2.4.egg': '8256b5f1cd9e348ea6877b5ddd56257d', - 'setuptools-0.6a10-py2.3.egg': '162d8357f1aff2b0349c6c247ee62987', - 'setuptools-0.6a10-py2.4.egg': '803a2d8db501c1ac3b5b6fb4e907f788', - 'setuptools-0.6a10dev_r42346-py2.3.egg': 'a7899272cfceb6aa60094ae8928b8077', - 'setuptools-0.6a10dev_r42346-py2.4.egg': '5d42a64adca9aedb409f83ecf22156a5', - 'setuptools-0.6a2-py2.3.egg': 'b98da449da411267c37a738f0ab625ba', - 'setuptools-0.6a2-py2.4.egg': 'be5b88bc30aed63fdefd2683be135c3b', - 'setuptools-0.6a3-py2.3.egg': 'ee0e325de78f23aab79d33106dc2a8c8', - 'setuptools-0.6a3-py2.4.egg': 'd95453d525a456d6c23e7a5eea89a063', - 'setuptools-0.6a4-py2.3.egg': 'e958cbed4623bbf47dd1f268b99d7784', - 'setuptools-0.6a4-py2.4.egg': '7f33c3ac2ef1296f0ab4fac1de4767d8', - 'setuptools-0.6a5-py2.3.egg': '748408389c49bcd2d84f6ae0b01695b1', - 'setuptools-0.6a5-py2.4.egg': '999bacde623f4284bfb3ea77941d2627', - 'setuptools-0.6a6-py2.3.egg': '7858139f06ed0600b0d9383f36aca24c', - 'setuptools-0.6a6-py2.4.egg': 'c10d20d29acebce0dc76219dc578d058', - 'setuptools-0.6a7-py2.3.egg': 'cfc4125ddb95c07f9500adc5d6abef6f', - 'setuptools-0.6a7-py2.4.egg': 'c6d62dab4461f71aed943caea89e6f20', - 'setuptools-0.6a8-py2.3.egg': '2f18eaaa3f544f5543ead4a68f3b2e1a', - 'setuptools-0.6a8-py2.4.egg': '799018f2894f14c9f8bcb2b34e69b391', - 'setuptools-0.6a9-py2.3.egg': '8e438ad70438b07b0d8f82cae42b278f', - 'setuptools-0.6a9-py2.4.egg': '8f6e01fc12fb1cd006dc0d6c04327ec1', -} - -import sys, os - -def _validate_md5(egg_name, data): - if egg_name in md5_data: - from md5 import md5 - digest = md5(data).hexdigest() - if digest != md5_data[egg_name]: - print >>sys.stderr, ( - "md5 validation of %s failed! (Possible download problem?)" - % egg_name - ) - sys.exit(2) - return data - - -def use_setuptools( - version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, - download_delay=15 -): - """Automatically find/download setuptools and make it available on sys.path - - `version` should be a valid setuptools version number that is available - as an egg for download under the `download_base` URL (which should end with - a '/'). `to_dir` is the directory where setuptools will be downloaded, if - it is not already available. If `download_delay` is specified, it should - be the number of seconds that will be paused before initiating a download, - should one be required. If an older version of setuptools is installed, - this routine will print a message to ``sys.stderr`` and raise SystemExit in - an attempt to abort the calling script. - """ - try: - import setuptools - if setuptools.__version__ == '0.0.1': - print >>sys.stderr, ( - "You have an obsolete version of setuptools installed. Please\n" - "remove it from your system entirely before rerunning this script." - ) - sys.exit(2) - except ImportError: - egg = download_setuptools(version, download_base, to_dir, download_delay) - sys.path.insert(0, egg) - import setuptools; setuptools.bootstrap_install_from = egg - - import pkg_resources - try: - pkg_resources.require("setuptools>="+version) - - except pkg_resources.VersionConflict: - # XXX could we install in a subprocess here? - print >>sys.stderr, ( - "The required version of setuptools (>=%s) is not available, and\n" - "can't be installed while this script is running. Please install\n" - " a more recent version first." - ) % version - sys.exit(2) - -def download_setuptools( - version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, - delay = 15 -): - """Download setuptools from a specified location and return its filename - - `version` should be a valid setuptools version number that is available - as an egg for download under the `download_base` URL (which should end - with a '/'). `to_dir` is the directory where the egg will be downloaded. - `delay` is the number of seconds to pause before an actual download attempt. - """ - import urllib2, shutil - egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) - url = download_base + egg_name - saveto = os.path.join(to_dir, egg_name) - src = dst = None - if not os.path.exists(saveto): # Avoid repeated downloads - try: - from distutils import log - if delay: - log.warn(""" ---------------------------------------------------------------------------- -This script requires setuptools version %s to run (even to display -help). I will attempt to download it for you (from -%s), but -you may need to enable firewall access for this script first. -I will start the download in %d seconds. - -(Note: if this machine does not have network access, please obtain the file - - %s - -and place it in this directory before rerunning this script.) ----------------------------------------------------------------------------""", - version, download_base, delay, url - ); from time import sleep; sleep(delay) - log.warn("Downloading %s", url) - src = urllib2.urlopen(url) - # Read/write all in one block, so we don't create a corrupt file - # if the download is interrupted. - data = _validate_md5(egg_name, src.read()) - dst = open(saveto,"wb"); dst.write(data) - finally: - if src: src.close() - if dst: dst.close() - return os.path.realpath(saveto) - -def main(argv, version=DEFAULT_VERSION): - """Install or upgrade setuptools and EasyInstall""" - - try: - import setuptools - except ImportError: - import tempfile, shutil - tmpdir = tempfile.mkdtemp(prefix="easy_install-") - try: - egg = download_setuptools(version, to_dir=tmpdir, delay=0) - sys.path.insert(0,egg) - from setuptools.command.easy_install import main - main(list(argv)+[egg]) - finally: - shutil.rmtree(tmpdir) - else: - if setuptools.__version__ == '0.0.1': - # tell the user to uninstall obsolete version - use_setuptools(version) - - req = "setuptools>="+version - import pkg_resources - try: - pkg_resources.require(req) - except pkg_resources.VersionConflict: - try: - from setuptools.command.easy_install import main - except ImportError: - from easy_install import main - main(list(argv)+[download_setuptools(delay=0)]) - sys.exit(0) # try to force an exit - else: - if argv: - from setuptools.command.easy_install import main - main(argv) - else: - print "Setuptools version",version,"or greater has been installed." - print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' - - - -def update_md5(filenames): - """Update our built-in md5 registry""" - - import re - from md5 import md5 - - for name in filenames: - base = os.path.basename(name) - f = open(name,'rb') - md5_data[base] = md5(f.read()).hexdigest() - f.close() - - data = [" %r: %r,\n" % it for it in md5_data.items()] - data.sort() - repl = "".join(data) - - import inspect - srcfile = inspect.getsourcefile(sys.modules[__name__]) - f = open(srcfile, 'rb'); src = f.read(); f.close() - - match = re.search("\nmd5_data = {\n([^}]+)}", src) - if not match: - print >>sys.stderr, "Internal error!" - sys.exit(2) - - src = src[:match.start(1)] + repl + src[match.end(1):] - f = open(srcfile,'w') - f.write(src) - f.close() - - -if __name__=='__main__': - if len(sys.argv)>2 and sys.argv[1]=='--md5update': - update_md5(sys.argv[2:]) - else: - main(sys.argv[1:]) - - - - - diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000000..d3d908abf5 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,3 @@ +[bdist_rpm] +doc_files = docs/*.txt + @@ -1,7 +1,25 @@ -import ez_setup # From http://peak.telecommunity.com/DevCenter/setuptools -ez_setup.use_setuptools() +from distutils.core import setup +from distutils.command.install import INSTALL_SCHEMES +import os -from setuptools import setup, find_packages +# Tell distutils to put the data_files in platform-specific installation +# locations. See here for an explanation: +# http://groups.google.com/group/comp.lang.python/browse_thread/thread/35ec7b2fed36eaec/2105ee4d9e8042cb +for scheme in INSTALL_SCHEMES.values(): + scheme['data'] = scheme['purelib'] + +# Compile the list of packages available, because distutils doesn't have +# an easy way to do this. +packages, data_files = [], [] +root_dir = os.path.join(os.path.dirname(__file__), 'django') +for dirpath, dirnames, filenames in os.walk(root_dir): + # Ignore dirnames that start with '.' + for i, dirname in enumerate(dirnames): + if dirname.startswith('.'): del dirnames[i] + if '__init__.py' in filenames: + packages.append(dirpath.replace('/', '.')) + else: + data_files.append((dirpath, [os.path.join(dirpath, f) for f in filenames])) setup( name = "Django", @@ -10,51 +28,7 @@ setup( author = 'Lawrence Journal-World', author_email = 'holovaty@gmail.com', description = 'A high-level Python Web framework that encourages rapid development and clean, pragmatic design.', - license = 'BSD', - packages = find_packages(exclude=['examples', 'examples.*']), - package_data = { - '': ['*.TXT'], - 'django.conf': ['locale/ar/LC_MESSAGES/*', - 'locale/bn/LC_MESSAGES/*', - 'locale/cs/LC_MESSAGES/*', - 'locale/cy/LC_MESSAGES/*', - 'locale/da/LC_MESSAGES/*', - 'locale/de/LC_MESSAGES/*', - 'locale/el/LC_MESSAGES/*', - 'locale/en/LC_MESSAGES/*', - 'locale/es/LC_MESSAGES/*', - 'locale/es_AR/LC_MESSAGES/*', - 'locale/fr/LC_MESSAGES/*', - 'locale/gl/LC_MESSAGES/*', - 'locale/hu/LC_MESSAGES/*', - 'locale/he/LC_MESSAGES/*', - 'locale/is/LC_MESSAGES/*', - 'locale/it/LC_MESSAGES/*', - 'locale/ja/LC_MESSAGES/*', - 'locale/nl/LC_MESSAGES/*', - 'locale/no/LC_MESSAGES/*', - 'locale/pl/LC_MESSAGES/*', - 'locale/pt_BR/LC_MESSAGES/*', - 'locale/ro/LC_MESSAGES/*', - 'locale/ru/LC_MESSAGES/*', - 'locale/sk/LC_MESSAGES/*', - 'locale/sl/LC_MESSAGES/*', - 'locale/sr/LC_MESSAGES/*', - 'locale/sv/LC_MESSAGES/*', - 'locale/uk/LC_MESSAGES/*', - 'locale/zh_CN/LC_MESSAGES/*', - 'locale/zh_TW/LC_MESSAGES/*'], - 'django.contrib.admin': ['templates/admin/*.html', - 'templates/admin_doc/*.html', - 'templates/registration/*.html', - 'templates/widget/*.html', - 'media/css/*.css', - 'media/img/admin/*.gif', - 'media/img/admin/*.png', - 'media/js/*.js', - 'media/js/admin/*js'], - 'django.contrib.comments': ['templates/comments/*.html'], - }, + packages = packages, + data_files = data_files, scripts = ['django/bin/django-admin.py'], - zip_safe = False, ) diff --git a/tests/modeltests/basic/models.py b/tests/modeltests/basic/models.py index 78d943eb97..5638865f31 100644 --- a/tests/modeltests/basic/models.py +++ b/tests/modeltests/basic/models.py @@ -13,8 +13,7 @@ class Article(models.Model): def __str__(self): return self.headline -API_TESTS = """ - +__test__ = {'API_TESTS': """ # No articles are in the system yet. >>> Article.objects.all() [] @@ -87,6 +86,10 @@ DoesNotExist: Article matching query does not exist. >>> Article.objects.get(pk=1) <Article: Area woman programs in Python> +# pk can be used as a shortcut for the primary key name in any query +>>> Article.objects.filter(pk__in=[1]) +[<Article: Area woman programs in Python>] + # Model instances of the same type and same ID are considered equal. >>> a = Article.objects.get(pk=1) >>> b = Article.objects.get(pk=1) @@ -314,14 +317,14 @@ AttributeError: Manager isn't accessible via Article instances >>> Article.objects.all() [<Article: Article 6>, <Article: Default headline>, <Article: Article 7>, <Article: Updated article 8>] -""" +"""} from django.conf import settings building_docs = getattr(settings, 'BUILDING_DOCS', False) if building_docs or settings.DATABASE_ENGINE == 'postgresql': - API_TESTS += """ + __test__['API_TESTS'] += """ # In PostgreSQL, microsecond-level precision is available. >>> a9 = Article(headline='Article 9', pub_date=datetime(2005, 7, 31, 12, 30, 45, 180)) >>> a9.save() @@ -330,7 +333,7 @@ datetime.datetime(2005, 7, 31, 12, 30, 45, 180) """ if building_docs or settings.DATABASE_ENGINE == 'mysql': - API_TESTS += """ + __test__['API_TESTS'] += """ # In MySQL, microsecond-level precision isn't available. You'll lose # microsecond-level precision once the data is saved. >>> a9 = Article(headline='Article 9', pub_date=datetime(2005, 7, 31, 12, 30, 45, 180)) @@ -339,7 +342,7 @@ if building_docs or settings.DATABASE_ENGINE == 'mysql': datetime.datetime(2005, 7, 31, 12, 30, 45) """ -API_TESTS += """ +__test__['API_TESTS'] += """ # You can manually specify the primary key when creating a new object. >>> a101 = Article(id=101, headline='Article 101', pub_date=datetime(2005, 7, 31, 12, 30, 45)) diff --git a/tests/modeltests/choices/models.py b/tests/modeltests/choices/models.py index 881fb29fd2..37d36fe1d8 100644 --- a/tests/modeltests/choices/models.py +++ b/tests/modeltests/choices/models.py @@ -23,7 +23,7 @@ class Person(models.Model): def __str__(self): return self.name -API_TESTS = """ +__test__ = {'API_TESTS':""" >>> a = Person(name='Adrian', gender='M') >>> a.save() >>> s = Person(name='Sara', gender='F') @@ -36,4 +36,4 @@ API_TESTS = """ 'Male' >>> s.get_gender_display() 'Female' -""" +"""} diff --git a/tests/modeltests/custom_columns/models.py b/tests/modeltests/custom_columns/models.py index 7d8c52d137..e88fa80da2 100644 --- a/tests/modeltests/custom_columns/models.py +++ b/tests/modeltests/custom_columns/models.py @@ -15,7 +15,7 @@ class Person(models.Model): def __str__(self): return '%s %s' % (self.first_name, self.last_name) -API_TESTS = """ +__test__ = {'API_TESTS':""" # Create a Person. >>> p = Person(first_name='John', last_name='Smith') >>> p.save() @@ -50,4 +50,4 @@ AttributeError: 'Person' object has no attribute 'firstname' Traceback (most recent call last): ... AttributeError: 'Person' object has no attribute 'last' -""" +"""} diff --git a/tests/modeltests/custom_managers/models.py b/tests/modeltests/custom_managers/models.py index 1c4e91b526..99df875275 100644 --- a/tests/modeltests/custom_managers/models.py +++ b/tests/modeltests/custom_managers/models.py @@ -58,7 +58,7 @@ class Car(models.Model): def __str__(self): return self.name -API_TESTS = """ +__test__ = {'API_TESTS':""" >>> p1 = Person(first_name='Bugs', last_name='Bunny', fun=True) >>> p1.save() >>> p2 = Person(first_name='Droopy', last_name='Dog', fun=False) @@ -104,4 +104,4 @@ True # to the first manager defined in the class. In this case, it's "cars". >>> Car._default_manager.order_by('name') [<Car: Corvette>, <Car: Neon>] -""" +"""} diff --git a/tests/modeltests/custom_methods/models.py b/tests/modeltests/custom_methods/models.py index e314d97264..e8fb751d54 100644 --- a/tests/modeltests/custom_methods/models.py +++ b/tests/modeltests/custom_methods/models.py @@ -36,7 +36,7 @@ class Article(models.Model): # positional arguments to Article(). return [self.__class__(*row) for row in cursor.fetchall()] -API_TESTS = """ +__test__ = {'API_TESTS':""" # Create a couple of Articles. >>> from datetime import date >>> a = Article(id=None, headline='Area man programs in Python', pub_date=date(2005, 7, 27)) @@ -55,4 +55,4 @@ False [<Article: Area man programs in Python>] >>> b.articles_from_same_day_2() [<Article: Area man programs in Python>] -""" +"""} diff --git a/tests/modeltests/custom_pk/models.py b/tests/modeltests/custom_pk/models.py index f7b790ca21..fd0901da3c 100644 --- a/tests/modeltests/custom_pk/models.py +++ b/tests/modeltests/custom_pk/models.py @@ -27,7 +27,7 @@ class Business(models.Model): def __str__(self): return self.name -API_TESTS = """ +__test__ = {'API_TESTS':""" >>> dan = Employee(employee_code='ABC123', first_name='Dan', last_name='Jones') >>> dan.save() >>> Employee.objects.all() @@ -51,6 +51,10 @@ DoesNotExist: Employee matching query does not exist. >>> Employee.objects.get(employee_code__exact='ABC123') <Employee: Dan Jones> +# pk can be used as a substitute for the primary key. +>>> Employee.objects.filter(pk__in=['ABC123','XYZ456']) +[<Employee: Fran Bones>, <Employee: Dan Jones>] + # Fran got married and changed her last name. >>> fran = Employee.objects.get(pk='XYZ456') >>> fran.last_name = 'Jones' @@ -88,4 +92,4 @@ DoesNotExist: Employee matching query does not exist. >>> Business.objects.filter(employees__first_name__startswith='Fran') [<Business: Sears>] -""" +"""} diff --git a/tests/modeltests/empty/models.py b/tests/modeltests/empty/models.py index c50878398d..0e5d572504 100644 --- a/tests/modeltests/empty/models.py +++ b/tests/modeltests/empty/models.py @@ -10,7 +10,7 @@ from django.db import models class Empty(models.Model): pass -API_TESTS = """ +__test__ = {'API_TESTS':""" >>> m = Empty() >>> m.id >>> m.save() @@ -20,5 +20,7 @@ API_TESTS = """ 2 >>> m.id is not None True +>>> existing = Empty(m.id) +>>> existing.save() -""" +"""} diff --git a/tests/modeltests/field_defaults/models.py b/tests/modeltests/field_defaults/models.py index 0d69ffd8be..da4cd38974 100644 --- a/tests/modeltests/field_defaults/models.py +++ b/tests/modeltests/field_defaults/models.py @@ -19,7 +19,7 @@ class Article(models.Model): def __str__(self): return self.headline -API_TESTS = """ +__test__ = {'API_TESTS':""" >>> from datetime import datetime # No articles are in the system yet. @@ -48,4 +48,4 @@ API_TESTS = """ >>> d = now - a.pub_date >>> d.seconds < 5 True -""" +"""} diff --git a/tests/modeltests/generic_relations/models.py b/tests/modeltests/generic_relations/models.py index e9a81a19e8..eb64d7ec3d 100644 --- a/tests/modeltests/generic_relations/models.py +++ b/tests/modeltests/generic_relations/models.py @@ -53,7 +53,7 @@ class Mineral(models.Model): def __str__(self): return self.name -API_TESTS = """ +__test__ = {'API_TESTS':""" # Create the world in 7 lines of code... >>> lion = Animal(common_name="Lion", latin_name="Panthera leo") >>> platypus = Animal(common_name="Platypus", latin_name="Ornithorhynchus anatinus") @@ -105,4 +105,4 @@ API_TESTS = """ [<TaggedItem: shiny>] >>> TaggedItem.objects.filter(content_type__pk=ctype.id, object_id=quartz.id) [<TaggedItem: clearish>] -""" +"""} diff --git a/tests/modeltests/get_latest/models.py b/tests/modeltests/get_latest/models.py index 42e7a14ec7..84c6273818 100644 --- a/tests/modeltests/get_latest/models.py +++ b/tests/modeltests/get_latest/models.py @@ -3,9 +3,9 @@ Models can have a ``get_latest_by`` attribute, which should be set to the name of a DateField or DateTimeField. If ``get_latest_by`` exists, the model's -module will get a ``get_latest()`` function, which will return the latest -object in the database according to that field. "Latest" means "having the -date farthest into the future." +manager will get a ``latest()`` method, which will return the latest object in +the database according to that field. "Latest" means "having the date farthest +into the future." """ from django.db import models @@ -29,8 +29,8 @@ class Person(models.Model): def __str__(self): return self.name -API_TESTS = """ -# Because no Articles exist yet, get_latest() raises ArticleDoesNotExist. +__test__ = {'API_TESTS':""" +# Because no Articles exist yet, latest() raises ArticleDoesNotExist. >>> Article.objects.latest() Traceback (most recent call last): ... @@ -76,4 +76,4 @@ AssertionError: latest() requires either a field_name parameter or 'get_latest_b >>> Person.objects.latest('birthday') <Person: Stephanie> -""" +"""} diff --git a/tests/modeltests/get_or_create/models.py b/tests/modeltests/get_or_create/models.py index 10a8721afc..b4f39ceded 100644 --- a/tests/modeltests/get_or_create/models.py +++ b/tests/modeltests/get_or_create/models.py @@ -15,7 +15,7 @@ class Person(models.Model): def __str__(self): return '%s %s' % (self.first_name, self.last_name) -API_TESTS = """ +__test__ = {'API_TESTS':""" # Acting as a divine being, create an Person. >>> from datetime import date >>> p = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9)) @@ -49,4 +49,4 @@ True False >>> Person.objects.count() 2 -""" +"""} diff --git a/tests/modeltests/invalid_models/models.py b/tests/modeltests/invalid_models/models.py index eb305b4e92..2299cd85e6 100644 --- a/tests/modeltests/invalid_models/models.py +++ b/tests/modeltests/invalid_models/models.py @@ -68,17 +68,36 @@ class SelfClashForeign(models.Model): foreign_1 = models.ForeignKey("SelfClashForeign", related_name='id') foreign_2 = models.ForeignKey("SelfClashForeign", related_name='src_safe') +class ValidM2M(models.Model): + src_safe = models.CharField(maxlength=10) + validm2m = models.CharField(maxlength=10) + + # M2M fields are symmetrical by default. Symmetrical M2M fields + # on self don't require a related accessor, so many potential + # clashes are avoided. + validm2m_set = models.ManyToManyField("ValidM2M") + + m2m_1 = models.ManyToManyField("ValidM2M", related_name='id') + m2m_2 = models.ManyToManyField("ValidM2M", related_name='src_safe') + + m2m_3 = models.ManyToManyField('self') + m2m_4 = models.ManyToManyField('self') + class SelfClashM2M(models.Model): src_safe = models.CharField(maxlength=10) selfclashm2m = models.CharField(maxlength=10) - selfclashm2m_set = models.ManyToManyField("SelfClashM2M") - m2m_1 = models.ManyToManyField("SelfClashM2M", related_name='id') - m2m_2 = models.ManyToManyField("SelfClashM2M", related_name='src_safe') - + # Non-symmetrical M2M fields _do_ have related accessors, so + # there is potential for clashes. + selfclashm2m_set = models.ManyToManyField("SelfClashM2M", symmetrical=False) + + m2m_1 = models.ManyToManyField("SelfClashM2M", related_name='id', symmetrical=False) + m2m_2 = models.ManyToManyField("SelfClashM2M", related_name='src_safe', symmetrical=False) + m2m_3 = models.ManyToManyField('self', symmetrical=False) + m2m_4 = models.ManyToManyField('self', symmetrical=False) -error_log = """invalid_models.fielderrors: "charfield": CharFields require a "maxlength" attribute. +model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "maxlength" attribute. invalid_models.fielderrors: "floatfield": FloatFields require a "decimal_places" attribute. invalid_models.fielderrors: "floatfield": FloatFields require a "max_digits" attribute. invalid_models.fielderrors: "filefield": FileFields require an "upload_to" attribute. @@ -147,9 +166,17 @@ invalid_models.selfclashforeign: Accessor for field 'foreign_2' clashes with fie invalid_models.selfclashforeign: Reverse query name for field 'foreign_2' clashes with field 'SelfClashForeign.src_safe'. Add a related_name argument to the definition for 'foreign_2'. invalid_models.selfclashm2m: Accessor for m2m field 'selfclashm2m_set' clashes with m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'selfclashm2m_set'. invalid_models.selfclashm2m: Reverse query name for m2m field 'selfclashm2m_set' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'selfclashm2m_set'. +invalid_models.selfclashm2m: Accessor for m2m field 'selfclashm2m_set' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'selfclashm2m_set'. invalid_models.selfclashm2m: Accessor for m2m field 'm2m_1' clashes with field 'SelfClashM2M.id'. Add a related_name argument to the definition for 'm2m_1'. invalid_models.selfclashm2m: Accessor for m2m field 'm2m_2' clashes with field 'SelfClashM2M.src_safe'. Add a related_name argument to the definition for 'm2m_2'. invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_1' clashes with field 'SelfClashM2M.id'. Add a related_name argument to the definition for 'm2m_1'. invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_2' clashes with field 'SelfClashM2M.src_safe'. Add a related_name argument to the definition for 'm2m_2'. +invalid_models.selfclashm2m: Accessor for m2m field 'm2m_3' clashes with m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_3'. +invalid_models.selfclashm2m: Accessor for m2m field 'm2m_3' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_3'. +invalid_models.selfclashm2m: Accessor for m2m field 'm2m_3' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_3'. +invalid_models.selfclashm2m: Accessor for m2m field 'm2m_4' clashes with m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_4'. +invalid_models.selfclashm2m: Accessor for m2m field 'm2m_4' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_4'. +invalid_models.selfclashm2m: Accessor for m2m field 'm2m_4' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_4'. +invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_3' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'm2m_3'. +invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_4' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'm2m_4'. """ - diff --git a/tests/modeltests/lookup/models.py b/tests/modeltests/lookup/models.py index a2c0a14158..09c3aa7aa8 100644 --- a/tests/modeltests/lookup/models.py +++ b/tests/modeltests/lookup/models.py @@ -15,7 +15,7 @@ class Article(models.Model): def __str__(self): return self.headline -API_TESTS = """ +__test__ = {'API_TESTS':r""" # Create a couple of Articles. >>> from datetime import datetime >>> a1 = Article(headline='Article 1', pub_date=datetime(2005, 7, 26)) @@ -161,13 +161,14 @@ DoesNotExist: Article matching query does not exist. <Article: Article 1> # Underscores and percent signs have special meaning in the underlying -# database library, but Django handles the quoting of them automatically. +# SQL code, but Django handles the quoting of them automatically. >>> a8 = Article(headline='Article_ with underscore', pub_date=datetime(2005, 11, 20)) >>> a8.save() >>> Article.objects.filter(headline__startswith='Article') [<Article: Article_ with underscore>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: Article 1>] >>> Article.objects.filter(headline__startswith='Article_') [<Article: Article_ with underscore>] + >>> a9 = Article(headline='Article% with percent sign', pub_date=datetime(2005, 11, 21)) >>> a9.save() >>> Article.objects.filter(headline__startswith='Article') @@ -182,4 +183,12 @@ DoesNotExist: Article matching query does not exist. [<Article: Article% with percent sign>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: Article 1>] >>> Article.objects.exclude(headline="Article 7") [<Article: Article% with percent sign>, <Article: Article_ with underscore>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 1>] -""" + +# Backslashes also have special meaning in the underlying SQL code, but Django +# automatically quotes them appropriately. +>>> a10 = Article(headline='Article with \\ backslash', pub_date=datetime(2005, 11, 22)) +>>> a10.save() +>>> Article.objects.filter(headline__contains='\\') +[<Article: Article with \ backslash>] + +"""} diff --git a/tests/modeltests/m2m_and_m2o/models.py b/tests/modeltests/m2m_and_m2o/models.py index f43fb12d9e..7fc66ed5a0 100644 --- a/tests/modeltests/m2m_and_m2o/models.py +++ b/tests/modeltests/m2m_and_m2o/models.py @@ -21,7 +21,7 @@ class Issue(models.Model): ordering = ('num',) -API_TESTS = """ +__test__ = {'API_TESTS':""" >>> Issue.objects.all() [] >>> r = User(username='russell') @@ -62,4 +62,4 @@ API_TESTS = """ [<Issue: 1>, <Issue: 2>, <Issue: 3>] >>> Issue.objects.filter(Q(client=r.id) | Q(cc__id__exact=r.id)) [<Issue: 1>, <Issue: 2>, <Issue: 3>] -""" +"""} diff --git a/tests/modeltests/m2m_intermediary/models.py b/tests/modeltests/m2m_intermediary/models.py index 848d035c39..b917db6189 100644 --- a/tests/modeltests/m2m_intermediary/models.py +++ b/tests/modeltests/m2m_intermediary/models.py @@ -34,7 +34,7 @@ class Writer(models.Model): def __str__(self): return '%s (%s)' % (self.reporter, self.position) -API_TESTS = """ +__test__ = {'API_TESTS':""" # Create a few Reporters. >>> r1 = Reporter(first_name='John', last_name='Smith') >>> r1.save() @@ -65,4 +65,4 @@ API_TESTS = """ <Article: This is a test> >>> r1.writer_set.all() [<Writer: John Smith (Main writer)>] -""" +"""} diff --git a/tests/modeltests/m2m_multiple/models.py b/tests/modeltests/m2m_multiple/models.py index e4fef75f19..5a1aa122a9 100644 --- a/tests/modeltests/m2m_multiple/models.py +++ b/tests/modeltests/m2m_multiple/models.py @@ -28,7 +28,7 @@ class Article(models.Model): def __str__(self): return self.headline -API_TESTS = """ +__test__ = {'API_TESTS':""" >>> from datetime import datetime >>> c1 = Category(name='Sports') @@ -76,4 +76,4 @@ API_TESTS = """ [] >>> c4.secondary_article_set.all() [<Article: Area man steals>, <Article: Area man runs>] -""" +"""} diff --git a/tests/modeltests/m2m_recursive/models.py b/tests/modeltests/m2m_recursive/models.py index dace32d565..9f31cf92c0 100644 --- a/tests/modeltests/m2m_recursive/models.py +++ b/tests/modeltests/m2m_recursive/models.py @@ -22,7 +22,7 @@ class Person(models.Model): def __str__(self): return self.name -API_TESTS = """ +__test__ = {'API_TESTS':""" >>> a = Person(name='Anne') >>> a.save() >>> b = Person(name='Bill') @@ -189,4 +189,4 @@ API_TESTS = """ >>> d.stalkers.all() [<Person: Chuck>] -""" +"""} diff --git a/tests/modeltests/m2o_recursive/models.py b/tests/modeltests/m2o_recursive/models.py index 44881b5a2f..0b528faf9e 100644 --- a/tests/modeltests/m2o_recursive/models.py +++ b/tests/modeltests/m2o_recursive/models.py @@ -19,7 +19,7 @@ class Category(models.Model): def __str__(self): return self.name -API_TESTS = """ +__test__ = {'API_TESTS':""" # Create a few Category objects. >>> r = Category(id=None, name='Root category', parent=None) >>> r.save() @@ -37,4 +37,4 @@ None [] >>> c.parent <Category: Root category> -""" +"""} diff --git a/tests/modeltests/m2o_recursive2/models.py b/tests/modeltests/m2o_recursive2/models.py index 93185c6a4c..5b7c5447ad 100644 --- a/tests/modeltests/m2o_recursive2/models.py +++ b/tests/modeltests/m2o_recursive2/models.py @@ -17,7 +17,7 @@ class Person(models.Model): def __str__(self): return self.full_name -API_TESTS = """ +__test__ = {'API_TESTS':""" # Create two Person objects -- the mom and dad in our family. >>> dad = Person(full_name='John Smith Senior', mother=None, father=None) >>> dad.save() @@ -40,4 +40,4 @@ API_TESTS = """ [] >>> kid.fathers_child_set.all() [] -""" +"""} diff --git a/tests/modeltests/manipulators/models.py b/tests/modeltests/manipulators/models.py index f7b20d52ac..e5b8be55b5 100644 --- a/tests/modeltests/manipulators/models.py +++ b/tests/modeltests/manipulators/models.py @@ -21,7 +21,7 @@ class Album(models.Model): def __str__(self): return self.name -API_TESTS = """ +__test__ = {'API_TESTS':""" >>> from django.utils.datastructures import MultiValueDict # Create a Musician object via the default AddManipulator. @@ -88,4 +88,4 @@ True <Album: Ultimate Ella> >>> a2.release_date datetime.date(2005, 2, 13) -""" +"""} diff --git a/tests/modeltests/many_to_many/models.py b/tests/modeltests/many_to_many/models.py index 0e989a0fbe..357f3ca629 100644 --- a/tests/modeltests/many_to_many/models.py +++ b/tests/modeltests/many_to_many/models.py @@ -28,7 +28,7 @@ class Article(models.Model): class Meta: ordering = ('headline',) -API_TESTS = """ +__test__ = {'API_TESTS':""" # Create a couple of Publications. >>> p1 = Publication(id=None, title='The Python Journal') >>> p1.save() @@ -231,4 +231,4 @@ API_TESTS = """ >>> p1.article_set.all() [<Article: NASA uses Python>] -""" +"""} diff --git a/tests/modeltests/many_to_one/models.py b/tests/modeltests/many_to_one/models.py index d202975128..82eb3257d0 100644 --- a/tests/modeltests/many_to_one/models.py +++ b/tests/modeltests/many_to_one/models.py @@ -25,7 +25,7 @@ class Article(models.Model): class Meta: ordering = ('headline',) -API_TESTS = """ +__test__ = {'API_TESTS':""" # Create a few Reporters. >>> r = Reporter(first_name='John', last_name='Smith', email='john@example.com') >>> r.save() @@ -263,4 +263,4 @@ TypeError: Cannot resolve keyword 'reporter_id' into field >>> Article.objects.all() [] -""" +"""} diff --git a/tests/modeltests/many_to_one_null/models.py b/tests/modeltests/many_to_one_null/models.py index b1936b9861..fb0f6ac3b7 100644 --- a/tests/modeltests/many_to_one_null/models.py +++ b/tests/modeltests/many_to_one_null/models.py @@ -23,7 +23,7 @@ class Article(models.Model): def __str__(self): return self.headline -API_TESTS = """ +__test__ = {'API_TESTS':""" # Create a Reporter. >>> r = Reporter(name='John Smith') >>> r.save() @@ -121,4 +121,4 @@ DoesNotExist: <Article: Fourth> is not related to <Reporter: John Smith>. >>> Article.objects.filter(reporter__isnull=True) [<Article: First>, <Article: Fourth>] -""" +"""} diff --git a/tests/modeltests/model_inheritance/models.py b/tests/modeltests/model_inheritance/models.py index 473cf24a9f..babef73e0a 100644 --- a/tests/modeltests/model_inheritance/models.py +++ b/tests/modeltests/model_inheritance/models.py @@ -26,7 +26,7 @@ class ItalianRestaurant(Restaurant): def __str__(self): return "%s the italian restaurant" % self.name -API_TESTS = """ +__test__ = {'API_TESTS':""" # Make sure Restaurant has the right fields in the right order. >>> [f.name for f in Restaurant._meta.fields] ['id', 'name', 'address', 'serves_hot_dogs', 'serves_pizza'] @@ -50,4 +50,4 @@ API_TESTS = """ >>> ir.save() -""" +"""} diff --git a/tests/modeltests/mutually_referential/models.py b/tests/modeltests/mutually_referential/models.py index 07b52effbc..5a3897d21a 100644 --- a/tests/modeltests/mutually_referential/models.py +++ b/tests/modeltests/mutually_referential/models.py @@ -14,7 +14,7 @@ class Child(Model): name = CharField(maxlength=100) parent = ForeignKey(Parent) -API_TESTS = """ +__test__ = {'API_TESTS':""" # Create a Parent >>> q = Parent(name='Elizabeth') >>> q.save() @@ -29,4 +29,4 @@ API_TESTS = """ >>> q.delete() -"""
\ No newline at end of file +"""}
\ No newline at end of file diff --git a/tests/modeltests/one_to_one/models.py b/tests/modeltests/one_to_one/models.py index f95556c08d..7488204ff1 100644 --- a/tests/modeltests/one_to_one/models.py +++ b/tests/modeltests/one_to_one/models.py @@ -30,7 +30,15 @@ class Waiter(models.Model): def __str__(self): return "%s the waiter at %s" % (self.name, self.restaurant) -API_TESTS = """ +class ManualPrimaryKey(models.Model): + primary_key = models.CharField(maxlength=10, primary_key=True) + name = models.CharField(maxlength = 50) + +class RelatedModel(models.Model): + link = models.OneToOneField(ManualPrimaryKey) + name = models.CharField(maxlength = 50) + +__test__ = {'API_TESTS':""" # Create a couple of Places. >>> p1 = Place(name='Demon Dogs', address='944 W. Fullerton') >>> p1.save() @@ -151,4 +159,10 @@ DoesNotExist: Restaurant matching query does not exist. # Delete the restaurant; the waiter should also be removed >>> r = Restaurant.objects.get(pk=1) >>> r.delete() -""" + +# One-to-one fields still work if you create your own primary key +>>> o1 = ManualPrimaryKey(primary_key="abc123", name="primary") +>>> o1.save() +>>> o2 = RelatedModel(link=o1, name="secondary") +>>> o2.save() +"""} diff --git a/tests/modeltests/or_lookups/models.py b/tests/modeltests/or_lookups/models.py index 80dc35f2b1..2de18edc1f 100644 --- a/tests/modeltests/or_lookups/models.py +++ b/tests/modeltests/or_lookups/models.py @@ -23,7 +23,7 @@ class Article(models.Model): def __str__(self): return self.headline -API_TESTS = """ +__test__ = {'API_TESTS':""" >>> from datetime import datetime >>> from django.db.models import Q @@ -101,4 +101,4 @@ API_TESTS = """ [<Article: Hello>] >>> Article.objects.complex_filter(Q(pk=1) | Q(pk=2)) [<Article: Hello>, <Article: Goodbye>] -""" +"""} diff --git a/tests/modeltests/ordering/models.py b/tests/modeltests/ordering/models.py index b22568c900..110ae3d7fc 100644 --- a/tests/modeltests/ordering/models.py +++ b/tests/modeltests/ordering/models.py @@ -24,7 +24,7 @@ class Article(models.Model): def __str__(self): return self.headline -API_TESTS = """ +__test__ = {'API_TESTS':""" # Create a couple of Articles. >>> from datetime import datetime >>> a1 = Article(headline='Article 1', pub_date=datetime(2005, 7, 26)) @@ -64,4 +64,4 @@ API_TESTS = """ # don't know what order the output will be in. >>> Article.objects.order_by('?') [...] -""" +"""} diff --git a/tests/modeltests/pagination/models.py b/tests/modeltests/pagination/models.py index 165b251d35..ea2385dc79 100644 --- a/tests/modeltests/pagination/models.py +++ b/tests/modeltests/pagination/models.py @@ -15,7 +15,7 @@ class Article(models.Model): def __str__(self): return self.headline -API_TESTS = """ +__test__ = {'API_TESTS':""" # prepare a list of objects for pagination >>> from datetime import datetime >>> for x in range(1, 10): @@ -64,4 +64,4 @@ True >>> paginator.last_on_page(1) 9 -""" +"""} diff --git a/tests/modeltests/properties/models.py b/tests/modeltests/properties/models.py index 3b0133bf8a..4ba6b1a808 100644 --- a/tests/modeltests/properties/models.py +++ b/tests/modeltests/properties/models.py @@ -20,7 +20,7 @@ class Person(models.Model): full_name_2 = property(_get_full_name, _set_full_name) -API_TESTS = """ +__test__ = {'API_TESTS':""" >>> a = Person(first_name='John', last_name='Lennon') >>> a.save() >>> a.full_name @@ -37,4 +37,4 @@ AttributeError: can't set attribute >>> a2.save() >>> a2.first_name 'Paul' -""" +"""} diff --git a/tests/modeltests/reserved_names/models.py b/tests/modeltests/reserved_names/models.py index db9196bebe..affe3f649d 100644 --- a/tests/modeltests/reserved_names/models.py +++ b/tests/modeltests/reserved_names/models.py @@ -24,7 +24,7 @@ class Thing(models.Model): def __str__(self): return self.when -API_TESTS = """ +__test__ = {'API_TESTS':""" >>> import datetime >>> day1 = datetime.date(2005, 1, 1) >>> day2 = datetime.date(2006, 2, 2) @@ -53,4 +53,4 @@ b >>> Thing.objects.filter(where__month=1) [<Thing: a>] -""" +"""} diff --git a/tests/modeltests/reverse_lookup/models.py b/tests/modeltests/reverse_lookup/models.py index b8c4466021..7e6712676f 100644 --- a/tests/modeltests/reverse_lookup/models.py +++ b/tests/modeltests/reverse_lookup/models.py @@ -27,7 +27,7 @@ class Choice(models.Model): def __str(self): return self.name -API_TESTS = """ +__test__ = {'API_TESTS':""" >>> john = User(name="John Doe") >>> john.save() >>> jim = User(name="Jim Bo") @@ -56,4 +56,4 @@ API_TESTS = """ Traceback (most recent call last): ... TypeError: Cannot resolve keyword 'choice' into field -""" +"""} diff --git a/tests/modeltests/save_delete_hooks/models.py b/tests/modeltests/save_delete_hooks/models.py index f01a2932d3..6e24c308ba 100644 --- a/tests/modeltests/save_delete_hooks/models.py +++ b/tests/modeltests/save_delete_hooks/models.py @@ -24,7 +24,7 @@ class Person(models.Model): super(Person, self).delete() # Call the "real" delete() method print "After deletion" -API_TESTS = """ +__test__ = {'API_TESTS':""" >>> p1 = Person(first_name='John', last_name='Smith') >>> p1.save() Before save @@ -39,4 +39,4 @@ After deletion >>> Person.objects.all() [] -""" +"""} diff --git a/tests/modeltests/serializers/models.py b/tests/modeltests/serializers/models.py index ccf565c365..d1d10b43c0 100644 --- a/tests/modeltests/serializers/models.py +++ b/tests/modeltests/serializers/models.py @@ -37,7 +37,7 @@ class Article(models.Model): def __str__(self): return self.headline -API_TESTS = """ +__test__ = {'API_TESTS':""" # Create some data: >>> from datetime import datetime >>> sports = Category(name="Sports") @@ -118,4 +118,4 @@ API_TESTS = """ >>> Article.objects.all() [<Article: Just kidding; I love TV poker>, <Article: Time to reform copyright>] -""" +"""} diff --git a/tests/modeltests/str/models.py b/tests/modeltests/str/models.py index 4e4228ac89..81230d538c 100644 --- a/tests/modeltests/str/models.py +++ b/tests/modeltests/str/models.py @@ -17,7 +17,7 @@ class Article(models.Model): def __str__(self): return self.headline -API_TESTS = """ +__test__ = {'API_TESTS':""" # Create an Article. >>> from datetime import datetime >>> a = Article(headline='Area man programs in Python', pub_date=datetime(2005, 7, 28)) @@ -28,4 +28,4 @@ API_TESTS = """ >>> a <Article: Area man programs in Python> -""" +"""} diff --git a/tests/modeltests/test_client/__init__.py b/tests/modeltests/test_client/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/modeltests/test_client/__init__.py diff --git a/tests/modeltests/test_client/management.py b/tests/modeltests/test_client/management.py new file mode 100644 index 0000000000..9b5a5c498e --- /dev/null +++ b/tests/modeltests/test_client/management.py @@ -0,0 +1,10 @@ +from django.dispatch import dispatcher +from django.db.models import signals +import models as test_client_app +from django.contrib.auth.models import User + +def setup_test(app, created_models, verbosity): + # Create a user account for the login-based tests + User.objects.create_user('testclient','testclient@example.com', 'password') + +dispatcher.connect(setup_test, sender=test_client_app, signal=signals.post_syncdb) diff --git a/tests/modeltests/test_client/models.py b/tests/modeltests/test_client/models.py new file mode 100644 index 0000000000..c5b1a241ca --- /dev/null +++ b/tests/modeltests/test_client/models.py @@ -0,0 +1,101 @@ +""" +39. Testing using the Test Client + +The test client is a class that can act like a simple +browser for testing purposes. + +It allows the user to compose GET and POST requests, and +obtain the response that the server gave to those requests. +The server Response objects are annotated with the details +of the contexts and templates that were rendered during the +process of serving the request. + +Client objects are stateful - they will retain cookie (and +thus session) details for the lifetime of the Client instance. + +This is not intended as a replacement for Twill,Selenium, or +other browser automation frameworks - it is here to allow +testing against the contexts and templates produced by a view, +rather than the HTML rendered to the end-user. + +""" +from django.test.client import Client +import unittest + +class ClientTest(unittest.TestCase): + def setUp(self): + "Set up test environment" + self.client = Client() + + def test_get_view(self): + "GET a view" + response = self.client.get('/test_client/get_view/') + + # Check some response details + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context['var'], 42) + self.assertEqual(response.template.name, 'GET Template') + self.failUnless('This is a test.' in response.content) + + def test_get_post_view(self): + "GET a view that normally expects POSTs" + response = self.client.get('/test_client/post_view/', {}) + + # Check some response details + self.assertEqual(response.status_code, 200) + self.assertEqual(response.template.name, 'Empty POST Template') + + def test_empty_post(self): + "POST an empty dictionary to a view" + response = self.client.post('/test_client/post_view/', {}) + + # Check some response details + self.assertEqual(response.status_code, 200) + self.assertEqual(response.template.name, 'Empty POST Template') + + def test_post_view(self): + "POST some data to a view" + post_data = { + 'value': 37 + } + response = self.client.post('/test_client/post_view/', post_data) + + # Check some response details + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context['data'], '37') + self.assertEqual(response.template.name, 'POST Template') + self.failUnless('Data received' in response.content) + + def test_redirect(self): + "GET a URL that redirects elsewhere" + response = self.client.get('/test_client/redirect_view/') + + # Check that the response was a 302 (redirect) + self.assertEqual(response.status_code, 302) + + def test_unknown_page(self): + "GET an invalid URL" + response = self.client.get('/test_client/unknown_view/') + + # Check that the response was a 404 + self.assertEqual(response.status_code, 404) + + def test_view_with_login(self): + "Request a page that is protected with @login_required" + + # Get the page without logging in. Should result in 302. + response = self.client.get('/test_client/login_protected_view/') + self.assertEqual(response.status_code, 302) + + # Request a page that requires a login + response = self.client.login('/test_client/login_protected_view/', 'testclient', 'password') + self.assertTrue(response) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context['user'].username, 'testclient') + self.assertEqual(response.template.name, 'Login Template') + + def test_view_with_bad_login(self): + "Request a page that is protected with @login, but use bad credentials" + + response = self.client.login('/test_client/login_protected_view/', 'otheruser', 'nopassword') + self.assertFalse(response) diff --git a/tests/modeltests/test_client/urls.py b/tests/modeltests/test_client/urls.py new file mode 100644 index 0000000000..09bba5c007 --- /dev/null +++ b/tests/modeltests/test_client/urls.py @@ -0,0 +1,9 @@ +from django.conf.urls.defaults import * +import views + +urlpatterns = patterns('', + (r'^get_view/$', views.get_view), + (r'^post_view/$', views.post_view), + (r'^redirect_view/$', views.redirect_view), + (r'^login_protected_view/$', views.login_protected_view), +) diff --git a/tests/modeltests/test_client/views.py b/tests/modeltests/test_client/views.py new file mode 100644 index 0000000000..bf131032eb --- /dev/null +++ b/tests/modeltests/test_client/views.py @@ -0,0 +1,35 @@ +from django.template import Context, Template +from django.http import HttpResponse, HttpResponseRedirect +from django.contrib.auth.decorators import login_required + +def get_view(request): + "A simple view that expects a GET request, and returns a rendered template" + t = Template('This is a test. {{ var }} is the value.', name='GET Template') + c = Context({'var': 42}) + + return HttpResponse(t.render(c)) + +def post_view(request): + """A view that expects a POST, and returns a different template depending + on whether any POST data is available + """ + if request.POST: + t = Template('Data received: {{ data }} is the value.', name='POST Template') + c = Context({'data': request.POST['value']}) + else: + t = Template('Viewing POST page.', name='Empty POST Template') + c = Context() + + return HttpResponse(t.render(c)) + +def redirect_view(request): + "A view that redirects all requests to the GET view" + return HttpResponseRedirect('/test_client/get_view/') + +@login_required +def login_protected_view(request): + "A simple view that is login protected." + t = Template('This is a login protected test. Username is {{ user.username }}.', name='Login Template') + c = Context({'user': request.user}) + + return HttpResponse(t.render(c)) diff --git a/tests/modeltests/transactions/models.py b/tests/modeltests/transactions/models.py index 92e0f38f47..e1fad8063e 100644 --- a/tests/modeltests/transactions/models.py +++ b/tests/modeltests/transactions/models.py @@ -17,16 +17,16 @@ class Reporter(models.Model): def __str__(self): return "%s %s" % (self.first_name, self.last_name) -API_TESTS = """ +__test__ = {'API_TESTS':""" >>> from django.db import connection, transaction -""" +"""} from django.conf import settings building_docs = getattr(settings, 'BUILDING_DOCS', False) if building_docs or settings.DATABASE_ENGINE != 'mysql': - API_TESTS += """ + __test__['API_TESTS'] += """ # the default behavior is to autocommit after each save() action >>> def create_a_reporter_then_fail(first, last): ... a = Reporter(first_name=first, last_name=last) diff --git a/tests/modeltests/validation/models.py b/tests/modeltests/validation/models.py index 57811f25a5..a9a3d3f485 100644 --- a/tests/modeltests/validation/models.py +++ b/tests/modeltests/validation/models.py @@ -20,7 +20,7 @@ class Person(models.Model): def __str__(self): return self.name -API_TESTS = """ +__test__ = {'API_TESTS':""" >>> import datetime >>> valid_params = { @@ -146,4 +146,4 @@ u'john@example.com' >>> p.validate() {'email': ['Enter a valid e-mail address.']} -""" +"""} diff --git a/tests/othertests/cache.py b/tests/othertests/cache.py deleted file mode 100644 index 81f2c20328..0000000000 --- a/tests/othertests/cache.py +++ /dev/null @@ -1,60 +0,0 @@ -# Unit tests for cache framework -# Uses whatever cache backend is set in the test settings file. - -from django.core.cache import cache -import time - -# functions/classes for complex data type tests -def f(): - return 42 -class C: - def m(n): - return 24 - -# simple set/get -cache.set("key", "value") -assert cache.get("key") == "value" - -# get with non-existent keys -assert cache.get("does not exist") is None -assert cache.get("does not exist", "bang!") == "bang!" - -# get_many -cache.set('a', 'a') -cache.set('b', 'b') -cache.set('c', 'c') -cache.set('d', 'd') -assert cache.get_many(['a', 'c', 'd']) == {'a' : 'a', 'c' : 'c', 'd' : 'd'} -assert cache.get_many(['a', 'b', 'e']) == {'a' : 'a', 'b' : 'b'} - -# delete -cache.set("key1", "spam") -cache.set("key2", "eggs") -assert cache.get("key1") == "spam" -cache.delete("key1") -assert cache.get("key1") is None -assert cache.get("key2") == "eggs" - -# has_key -cache.set("hello", "goodbye") -assert cache.has_key("hello") == True -assert cache.has_key("goodbye") == False - -# test data types -stuff = { - 'string' : 'this is a string', - 'int' : 42, - 'list' : [1, 2, 3, 4], - 'tuple' : (1, 2, 3, 4), - 'dict' : {'A': 1, 'B' : 2}, - 'function' : f, - 'class' : C, -} -for (key, value) in stuff.items(): - cache.set(key, value) - assert cache.get(key) == value - -# expiration -cache.set('expire', 'very quickly', 1) -time.sleep(2) -assert cache.get("expire") == None diff --git a/tests/othertests/markup.py b/tests/othertests/markup.py deleted file mode 100644 index 3fa5a3a883..0000000000 --- a/tests/othertests/markup.py +++ /dev/null @@ -1,68 +0,0 @@ -# Quick tests for the markup templatetags (django.contrib.markup) - -from django.template import Template, Context, add_to_builtins - -add_to_builtins('django.contrib.markup.templatetags.markup') - -# find out if markup modules are installed and tailor the test appropriately -try: - import textile -except ImportError: - textile = None - -try: - import markdown -except ImportError: - markdown = None - -try: - import docutils -except ImportError: - docutils = None - -# simple examples 'cause this isn't actually testing the markup, just -# that the filters work as advertised - -### test textile - -textile_content = """Paragraph 1 - -Paragraph 2 with "quotes" and @code@""" - -t = Template("{{ textile_content|textile }}") -rendered = t.render(Context(locals())).strip() -if textile: - assert rendered == """<p>Paragraph 1</p> - -<p>Paragraph 2 with “quotes” and <code>code</code></p>""" -else: - assert rendered == textile_content - -### test markdown - -markdown_content = """Paragraph 1 - -## An h2""" - -t = Template("{{ markdown_content|markdown }}") -rendered = t.render(Context(locals())).strip() -if markdown: - assert rendered == """<p>Paragraph 1</p><h2>An h2</h2>""" -else: - assert rendered == markdown_content - -### test rest - -rest_content = """Paragraph 1 - -Paragraph 2 with a link_ - -.. _link: http://www.example.com/""" - -t = Template("{{ rest_content|restructuredtext }}") -rendered = t.render(Context(locals())).strip() -if docutils: - assert rendered =="""<p>Paragraph 1</p> -<p>Paragraph 2 with a <a class="reference" href="http://www.example.com/">link</a></p>""" -else: - assert rendered == rest_content diff --git a/tests/othertests/templates.py b/tests/othertests/templates.py deleted file mode 100644 index d3b09c5310..0000000000 --- a/tests/othertests/templates.py +++ /dev/null @@ -1,625 +0,0 @@ -from django.conf import settings - - -from django import template -from django.template import loader -from django.utils.translation import activate, deactivate, install -from django.utils.tzinfo import LocalTimezone -from datetime import datetime, timedelta -import traceback - -################################# -# Custom template tag for tests # -################################# - -register = template.Library() - -class EchoNode(template.Node): - def __init__(self, contents): - self.contents = contents - - def render(self, context): - return " ".join(self.contents) - -def do_echo(parser, token): - return EchoNode(token.contents.split()[1:]) - -register.tag("echo", do_echo) - -template.libraries['django.templatetags.testtags'] = register - -##################################### -# Helper objects for template tests # -##################################### - -class SomeException(Exception): - silent_variable_failure = True - -class SomeOtherException(Exception): - pass - -class SomeClass: - def __init__(self): - self.otherclass = OtherClass() - - def method(self): - return "SomeClass.method" - - def method2(self, o): - return o - - def method3(self): - raise SomeException - - def method4(self): - raise SomeOtherException - -class OtherClass: - def method(self): - return "OtherClass.method" - -# NOW and NOW_tz are used by timesince tag tests. -NOW = datetime.now() -NOW_tz = datetime.now(LocalTimezone(datetime.now())) - -# SYNTAX -- -# 'template_name': ('template contents', 'context dict', 'expected string output' or Exception class) -TEMPLATE_TESTS = { - - ### BASIC SYNTAX ########################################################## - - # Plain text should go through the template parser untouched - 'basic-syntax01': ("something cool", {}, "something cool"), - - # Variables should be replaced with their value in the current context - 'basic-syntax02': ("{{ headline }}", {'headline':'Success'}, "Success"), - - # More than one replacement variable is allowed in a template - 'basic-syntax03': ("{{ first }} --- {{ second }}", {"first" : 1, "second" : 2}, "1 --- 2"), - - # Fail silently when a variable is not found in the current context - 'basic-syntax04': ("as{{ missing }}df", {}, "asINVALIDdf"), - - # A variable may not contain more than one word - 'basic-syntax06': ("{{ multi word variable }}", {}, template.TemplateSyntaxError), - - # Raise TemplateSyntaxError for empty variable tags - 'basic-syntax07': ("{{ }}", {}, template.TemplateSyntaxError), - 'basic-syntax08': ("{{ }}", {}, template.TemplateSyntaxError), - - # Attribute syntax allows a template to call an object's attribute - 'basic-syntax09': ("{{ var.method }}", {"var": SomeClass()}, "SomeClass.method"), - - # Multiple levels of attribute access are allowed - 'basic-syntax10': ("{{ var.otherclass.method }}", {"var": SomeClass()}, "OtherClass.method"), - - # Fail silently when a variable's attribute isn't found - 'basic-syntax11': ("{{ var.blech }}", {"var": SomeClass()}, "INVALID"), - - # Raise TemplateSyntaxError when trying to access a variable beginning with an underscore - 'basic-syntax12': ("{{ var.__dict__ }}", {"var": SomeClass()}, template.TemplateSyntaxError), - - # Raise TemplateSyntaxError when trying to access a variable containing an illegal character - 'basic-syntax13': ("{{ va>r }}", {}, template.TemplateSyntaxError), - 'basic-syntax14': ("{{ (var.r) }}", {}, template.TemplateSyntaxError), - 'basic-syntax15': ("{{ sp%am }}", {}, template.TemplateSyntaxError), - 'basic-syntax16': ("{{ eggs! }}", {}, template.TemplateSyntaxError), - 'basic-syntax17': ("{{ moo? }}", {}, template.TemplateSyntaxError), - - # Attribute syntax allows a template to call a dictionary key's value - 'basic-syntax18': ("{{ foo.bar }}", {"foo" : {"bar" : "baz"}}, "baz"), - - # Fail silently when a variable's dictionary key isn't found - 'basic-syntax19': ("{{ foo.spam }}", {"foo" : {"bar" : "baz"}}, "INVALID"), - - # Fail silently when accessing a non-simple method - 'basic-syntax20': ("{{ var.method2 }}", {"var": SomeClass()}, "INVALID"), - - # Basic filter usage - 'basic-syntax21': ("{{ var|upper }}", {"var": "Django is the greatest!"}, "DJANGO IS THE GREATEST!"), - - # Chained filters - 'basic-syntax22': ("{{ var|upper|lower }}", {"var": "Django is the greatest!"}, "django is the greatest!"), - - # Raise TemplateSyntaxError for space between a variable and filter pipe - 'basic-syntax23': ("{{ var |upper }}", {}, template.TemplateSyntaxError), - - # Raise TemplateSyntaxError for space after a filter pipe - 'basic-syntax24': ("{{ var| upper }}", {}, template.TemplateSyntaxError), - - # Raise TemplateSyntaxError for a nonexistent filter - 'basic-syntax25': ("{{ var|does_not_exist }}", {}, template.TemplateSyntaxError), - - # Raise TemplateSyntaxError when trying to access a filter containing an illegal character - 'basic-syntax26': ("{{ var|fil(ter) }}", {}, template.TemplateSyntaxError), - - # Raise TemplateSyntaxError for invalid block tags - 'basic-syntax27': ("{% nothing_to_see_here %}", {}, template.TemplateSyntaxError), - - # Raise TemplateSyntaxError for empty block tags - 'basic-syntax28': ("{% %}", {}, template.TemplateSyntaxError), - - # Chained filters, with an argument to the first one - 'basic-syntax29': ('{{ var|removetags:"b i"|upper|lower }}', {"var": "<b><i>Yes</i></b>"}, "yes"), - - # Escaped string as argument - 'basic-syntax30': (r'{{ var|default_if_none:" endquote\" hah" }}', {"var": None}, ' endquote" hah'), - - # Variable as argument - 'basic-syntax31': (r'{{ var|default_if_none:var2 }}', {"var": None, "var2": "happy"}, 'happy'), - - # Default argument testing - 'basic-syntax32': (r'{{ var|yesno:"yup,nup,mup" }} {{ var|yesno }}', {"var": True}, 'yup yes'), - - # Fail silently for methods that raise an exception with a "silent_variable_failure" attribute - 'basic-syntax33': (r'1{{ var.method3 }}2', {"var": SomeClass()}, "1INVALID2"), - - # In methods that raise an exception without a "silent_variable_attribute" set to True, - # the exception propogates - 'basic-syntax34': (r'1{{ var.method4 }}2', {"var": SomeClass()}, SomeOtherException), - - # Escaped backslash in argument - 'basic-syntax35': (r'{{ var|default_if_none:"foo\bar" }}', {"var": None}, r'foo\bar'), - - # Escaped backslash using known escape char - 'basic-syntax35': (r'{{ var|default_if_none:"foo\now" }}', {"var": None}, r'foo\now'), - - ### COMMENT TAG ########################################################### - 'comment-tag01': ("{% comment %}this is hidden{% endcomment %}hello", {}, "hello"), - 'comment-tag02': ("{% comment %}this is hidden{% endcomment %}hello{% comment %}foo{% endcomment %}", {}, "hello"), - - # Comment tag can contain invalid stuff. - 'comment-tag03': ("foo{% comment %} {% if %} {% endcomment %}", {}, "foo"), - 'comment-tag04': ("foo{% comment %} {% endblock %} {% endcomment %}", {}, "foo"), - 'comment-tag05': ("foo{% comment %} {% somerandomtag %} {% endcomment %}", {}, "foo"), - - ### CYCLE TAG ############################################################# - 'cycle01': ('{% cycle a %}', {}, template.TemplateSyntaxError), - 'cycle02': ('{% cycle a,b,c as abc %}{% cycle abc %}', {}, 'ab'), - 'cycle03': ('{% cycle a,b,c as abc %}{% cycle abc %}{% cycle abc %}', {}, 'abc'), - 'cycle04': ('{% cycle a,b,c as abc %}{% cycle abc %}{% cycle abc %}{% cycle abc %}', {}, 'abca'), - 'cycle05': ('{% cycle %}', {}, template.TemplateSyntaxError), - 'cycle06': ('{% cycle a %}', {}, template.TemplateSyntaxError), - 'cycle07': ('{% cycle a,b,c as foo %}{% cycle bar %}', {}, template.TemplateSyntaxError), - - ### EXCEPTIONS ############################################################ - - # Raise exception for invalid template name - 'exception01': ("{% extends 'nonexistent' %}", {}, template.TemplateSyntaxError), - - # Raise exception for invalid template name (in variable) - 'exception02': ("{% extends nonexistent %}", {}, template.TemplateSyntaxError), - - # Raise exception for extra {% extends %} tags - 'exception03': ("{% extends 'inheritance01' %}{% block first %}2{% endblock %}{% extends 'inheritance16' %}", {}, template.TemplateSyntaxError), - - # Raise exception for custom tags used in child with {% load %} tag in parent, not in child - 'exception04': ("{% extends 'inheritance17' %}{% block first %}{% echo 400 %}5678{% endblock %}", {}, template.TemplateSyntaxError), - - ### FILTER TAG ############################################################ - 'filter01': ('{% filter upper %}{% endfilter %}', {}, ''), - 'filter02': ('{% filter upper %}django{% endfilter %}', {}, 'DJANGO'), - 'filter03': ('{% filter upper|lower %}django{% endfilter %}', {}, 'django'), - - ### FIRSTOF TAG ########################################################### - 'firstof01': ('{% firstof a b c %}', {'a':0,'b':0,'c':0}, ''), - 'firstof02': ('{% firstof a b c %}', {'a':1,'b':0,'c':0}, '1'), - 'firstof03': ('{% firstof a b c %}', {'a':0,'b':2,'c':0}, '2'), - 'firstof04': ('{% firstof a b c %}', {'a':0,'b':0,'c':3}, '3'), - 'firstof05': ('{% firstof a b c %}', {'a':1,'b':2,'c':3}, '1'), - 'firstof06': ('{% firstof %}', {}, template.TemplateSyntaxError), - - ### FOR TAG ############################################################### - 'for-tag01': ("{% for val in values %}{{ val }}{% endfor %}", {"values": [1, 2, 3]}, "123"), - 'for-tag02': ("{% for val in values reversed %}{{ val }}{% endfor %}", {"values": [1, 2, 3]}, "321"), - 'for-tag-vars01': ("{% for val in values %}{{ forloop.counter }}{% endfor %}", {"values": [6, 6, 6]}, "123"), - 'for-tag-vars02': ("{% for val in values %}{{ forloop.counter0 }}{% endfor %}", {"values": [6, 6, 6]}, "012"), - 'for-tag-vars03': ("{% for val in values %}{{ forloop.revcounter }}{% endfor %}", {"values": [6, 6, 6]}, "321"), - 'for-tag-vars04': ("{% for val in values %}{{ forloop.revcounter0 }}{% endfor %}", {"values": [6, 6, 6]}, "210"), - - ### IF TAG ################################################################ - 'if-tag01': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": True}, "yes"), - 'if-tag02': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": False}, "no"), - 'if-tag03': ("{% if foo %}yes{% else %}no{% endif %}", {}, "no"), - - # AND - 'if-tag-and01': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'), - 'if-tag-and02': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'), - 'if-tag-and03': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'), - 'if-tag-and04': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'), - 'if-tag-and05': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': False}, 'no'), - 'if-tag-and06': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'bar': False}, 'no'), - 'if-tag-and07': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True}, 'no'), - 'if-tag-and08': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'bar': True}, 'no'), - - # OR - 'if-tag-or01': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'), - 'if-tag-or02': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'), - 'if-tag-or03': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'), - 'if-tag-or04': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'), - 'if-tag-or05': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': False}, 'no'), - 'if-tag-or06': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'bar': False}, 'no'), - 'if-tag-or07': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': True}, 'yes'), - 'if-tag-or08': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'bar': True}, 'yes'), - - # TODO: multiple ORs - - # NOT - 'if-tag-not01': ("{% if not foo %}no{% else %}yes{% endif %}", {'foo': True}, 'yes'), - 'if-tag-not02': ("{% if not %}yes{% else %}no{% endif %}", {'foo': True}, 'no'), - 'if-tag-not03': ("{% if not %}yes{% else %}no{% endif %}", {'not': True}, 'yes'), - 'if-tag-not04': ("{% if not not %}no{% else %}yes{% endif %}", {'not': True}, 'yes'), - 'if-tag-not05': ("{% if not not %}no{% else %}yes{% endif %}", {}, 'no'), - - 'if-tag-not06': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {}, 'no'), - 'if-tag-not07': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'), - 'if-tag-not08': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'), - 'if-tag-not09': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'), - 'if-tag-not10': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'), - - 'if-tag-not11': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {}, 'no'), - 'if-tag-not12': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'), - 'if-tag-not13': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'), - 'if-tag-not14': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'), - 'if-tag-not15': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'), - - 'if-tag-not16': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {}, 'yes'), - 'if-tag-not17': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'), - 'if-tag-not18': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'), - 'if-tag-not19': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'), - 'if-tag-not20': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'), - - 'if-tag-not21': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {}, 'yes'), - 'if-tag-not22': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'), - 'if-tag-not23': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'), - 'if-tag-not24': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'), - 'if-tag-not25': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'), - - 'if-tag-not26': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {}, 'yes'), - 'if-tag-not27': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'), - 'if-tag-not28': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'), - 'if-tag-not29': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'), - 'if-tag-not30': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'), - - 'if-tag-not31': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {}, 'yes'), - 'if-tag-not32': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'), - 'if-tag-not33': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'), - 'if-tag-not34': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'), - 'if-tag-not35': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'), - - # AND and OR raises a TemplateSyntaxError - 'if-tag-error01': ("{% if foo or bar and baz %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, template.TemplateSyntaxError), - 'if-tag-error02': ("{% if foo and %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError), - 'if-tag-error03': ("{% if foo or %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError), - 'if-tag-error04': ("{% if not foo and %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError), - 'if-tag-error05': ("{% if not foo or %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError), - - ### IFCHANGED TAG ######################################################### - 'ifchanged01': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,2,3) }, '123'), - 'ifchanged02': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,1,3) }, '13'), - 'ifchanged03': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,1,1) }, '1'), - - ### IFEQUAL TAG ########################################################### - 'ifequal01': ("{% ifequal a b %}yes{% endifequal %}", {"a": 1, "b": 2}, ""), - 'ifequal02': ("{% ifequal a b %}yes{% endifequal %}", {"a": 1, "b": 1}, "yes"), - 'ifequal03': ("{% ifequal a b %}yes{% else %}no{% endifequal %}", {"a": 1, "b": 2}, "no"), - 'ifequal04': ("{% ifequal a b %}yes{% else %}no{% endifequal %}", {"a": 1, "b": 1}, "yes"), - 'ifequal05': ("{% ifequal a 'test' %}yes{% else %}no{% endifequal %}", {"a": "test"}, "yes"), - 'ifequal06': ("{% ifequal a 'test' %}yes{% else %}no{% endifequal %}", {"a": "no"}, "no"), - 'ifequal07': ('{% ifequal a "test" %}yes{% else %}no{% endifequal %}', {"a": "test"}, "yes"), - 'ifequal08': ('{% ifequal a "test" %}yes{% else %}no{% endifequal %}', {"a": "no"}, "no"), - 'ifequal09': ('{% ifequal a "test" %}yes{% else %}no{% endifequal %}', {}, "no"), - 'ifequal10': ('{% ifequal a b %}yes{% else %}no{% endifequal %}', {}, "yes"), - - # SMART SPLITTING - 'ifequal-split01': ('{% ifequal a "test man" %}yes{% else %}no{% endifequal %}', {}, "no"), - 'ifequal-split02': ('{% ifequal a "test man" %}yes{% else %}no{% endifequal %}', {'a': 'foo'}, "no"), - 'ifequal-split03': ('{% ifequal a "test man" %}yes{% else %}no{% endifequal %}', {'a': 'test man'}, "yes"), - 'ifequal-split04': ("{% ifequal a 'test man' %}yes{% else %}no{% endifequal %}", {'a': 'test man'}, "yes"), - 'ifequal-split05': ("{% ifequal a 'i \"love\" you' %}yes{% else %}no{% endifequal %}", {'a': ''}, "no"), - 'ifequal-split06': ("{% ifequal a 'i \"love\" you' %}yes{% else %}no{% endifequal %}", {'a': 'i "love" you'}, "yes"), - 'ifequal-split07': ("{% ifequal a 'i \"love\" you' %}yes{% else %}no{% endifequal %}", {'a': 'i love you'}, "no"), - 'ifequal-split08': (r"{% ifequal a 'I\'m happy' %}yes{% else %}no{% endifequal %}", {'a': "I'm happy"}, "yes"), - 'ifequal-split09': (r"{% ifequal a 'slash\man' %}yes{% else %}no{% endifequal %}", {'a': r"slash\man"}, "yes"), - 'ifequal-split10': (r"{% ifequal a 'slash\man' %}yes{% else %}no{% endifequal %}", {'a': r"slashman"}, "no"), - - ### IFNOTEQUAL TAG ######################################################## - 'ifnotequal01': ("{% ifnotequal a b %}yes{% endifnotequal %}", {"a": 1, "b": 2}, "yes"), - 'ifnotequal02': ("{% ifnotequal a b %}yes{% endifnotequal %}", {"a": 1, "b": 1}, ""), - 'ifnotequal03': ("{% ifnotequal a b %}yes{% else %}no{% endifnotequal %}", {"a": 1, "b": 2}, "yes"), - 'ifnotequal04': ("{% ifnotequal a b %}yes{% else %}no{% endifnotequal %}", {"a": 1, "b": 1}, "no"), - - ### INCLUDE TAG ########################################################### - 'include01': ('{% include "basic-syntax01" %}', {}, "something cool"), - 'include02': ('{% include "basic-syntax02" %}', {'headline': 'Included'}, "Included"), - 'include03': ('{% include template_name %}', {'template_name': 'basic-syntax02', 'headline': 'Included'}, "Included"), - 'include04': ('a{% include "nonexistent" %}b', {}, "ab"), - - ### INHERITANCE ########################################################### - - # Standard template with no inheritance - 'inheritance01': ("1{% block first %}_{% endblock %}3{% block second %}_{% endblock %}", {}, '1_3_'), - - # Standard two-level inheritance - 'inheritance02': ("{% extends 'inheritance01' %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {}, '1234'), - - # Three-level with no redefinitions on third level - 'inheritance03': ("{% extends 'inheritance02' %}", {}, '1234'), - - # Two-level with no redefinitions on second level - 'inheritance04': ("{% extends 'inheritance01' %}", {}, '1_3_'), - - # Two-level with double quotes instead of single quotes - 'inheritance05': ('{% extends "inheritance02" %}', {}, '1234'), - - # Three-level with variable parent-template name - 'inheritance06': ("{% extends foo %}", {'foo': 'inheritance02'}, '1234'), - - # Two-level with one block defined, one block not defined - 'inheritance07': ("{% extends 'inheritance01' %}{% block second %}5{% endblock %}", {}, '1_35'), - - # Three-level with one block defined on this level, two blocks defined next level - 'inheritance08': ("{% extends 'inheritance02' %}{% block second %}5{% endblock %}", {}, '1235'), - - # Three-level with second and third levels blank - 'inheritance09': ("{% extends 'inheritance04' %}", {}, '1_3_'), - - # Three-level with space NOT in a block -- should be ignored - 'inheritance10': ("{% extends 'inheritance04' %} ", {}, '1_3_'), - - # Three-level with both blocks defined on this level, but none on second level - 'inheritance11': ("{% extends 'inheritance04' %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {}, '1234'), - - # Three-level with this level providing one and second level providing the other - 'inheritance12': ("{% extends 'inheritance07' %}{% block first %}2{% endblock %}", {}, '1235'), - - # Three-level with this level overriding second level - 'inheritance13': ("{% extends 'inheritance02' %}{% block first %}a{% endblock %}{% block second %}b{% endblock %}", {}, '1a3b'), - - # A block defined only in a child template shouldn't be displayed - 'inheritance14': ("{% extends 'inheritance01' %}{% block newblock %}NO DISPLAY{% endblock %}", {}, '1_3_'), - - # A block within another block - 'inheritance15': ("{% extends 'inheritance01' %}{% block first %}2{% block inner %}inner{% endblock %}{% endblock %}", {}, '12inner3_'), - - # A block within another block (level 2) - 'inheritance16': ("{% extends 'inheritance15' %}{% block inner %}out{% endblock %}", {}, '12out3_'), - - # {% load %} tag (parent -- setup for exception04) - 'inheritance17': ("{% load testtags %}{% block first %}1234{% endblock %}", {}, '1234'), - - # {% load %} tag (standard usage, without inheritance) - 'inheritance18': ("{% load testtags %}{% echo this that theother %}5678", {}, 'this that theother5678'), - - # {% load %} tag (within a child template) - 'inheritance19': ("{% extends 'inheritance01' %}{% block first %}{% load testtags %}{% echo 400 %}5678{% endblock %}", {}, '140056783_'), - - # Two-level inheritance with {{ block.super }} - 'inheritance20': ("{% extends 'inheritance01' %}{% block first %}{{ block.super }}a{% endblock %}", {}, '1_a3_'), - - # Three-level inheritance with {{ block.super }} from parent - 'inheritance21': ("{% extends 'inheritance02' %}{% block first %}{{ block.super }}a{% endblock %}", {}, '12a34'), - - # Three-level inheritance with {{ block.super }} from grandparent - 'inheritance22': ("{% extends 'inheritance04' %}{% block first %}{{ block.super }}a{% endblock %}", {}, '1_a3_'), - - # Three-level inheritance with {{ block.super }} from parent and grandparent - 'inheritance23': ("{% extends 'inheritance20' %}{% block first %}{{ block.super }}b{% endblock %}", {}, '1_ab3_'), - - ### I18N ################################################################## - - # {% spaceless %} tag - 'spaceless01': ("{% spaceless %} <b> <i> text </i> </b> {% endspaceless %}", {}, "<b> <i> text </i> </b>"), - 'spaceless02': ("{% spaceless %} <b> \n <i> text </i> \n </b> {% endspaceless %}", {}, "<b> <i> text </i> </b>"), - 'spaceless03': ("{% spaceless %}<b><i>text</i></b>{% endspaceless %}", {}, "<b><i>text</i></b>"), - - # simple translation of a string delimited by ' - 'i18n01': ("{% load i18n %}{% trans 'xxxyyyxxx' %}", {}, "xxxyyyxxx"), - - # simple translation of a string delimited by " - 'i18n02': ('{% load i18n %}{% trans "xxxyyyxxx" %}', {}, "xxxyyyxxx"), - - # simple translation of a variable - 'i18n03': ('{% load i18n %}{% blocktrans %}{{ anton }}{% endblocktrans %}', {'anton': 'xxxyyyxxx'}, "xxxyyyxxx"), - - # simple translation of a variable and filter - 'i18n04': ('{% load i18n %}{% blocktrans with anton|lower as berta %}{{ berta }}{% endblocktrans %}', {'anton': 'XXXYYYXXX'}, "xxxyyyxxx"), - - # simple translation of a string with interpolation - 'i18n05': ('{% load i18n %}{% blocktrans %}xxx{{ anton }}xxx{% endblocktrans %}', {'anton': 'yyy'}, "xxxyyyxxx"), - - # simple translation of a string to german - 'i18n06': ('{% load i18n %}{% trans "Page not found" %}', {'LANGUAGE_CODE': 'de'}, "Seite nicht gefunden"), - - # translation of singular form - 'i18n07': ('{% load i18n %}{% blocktrans count number as counter %}singular{% plural %}plural{% endblocktrans %}', {'number': 1}, "singular"), - - # translation of plural form - 'i18n08': ('{% load i18n %}{% blocktrans count number as counter %}singular{% plural %}plural{% endblocktrans %}', {'number': 2}, "plural"), - - # simple non-translation (only marking) of a string to german - 'i18n09': ('{% load i18n %}{% trans "Page not found" noop %}', {'LANGUAGE_CODE': 'de'}, "Page not found"), - - # translation of a variable with a translated filter - 'i18n10': ('{{ bool|yesno:_("ja,nein") }}', {'bool': True}, 'ja'), - - # translation of a variable with a non-translated filter - 'i18n11': ('{{ bool|yesno:"ja,nein" }}', {'bool': True}, 'ja'), - - # usage of the get_available_languages tag - 'i18n12': ('{% load i18n %}{% get_available_languages as langs %}{% for lang in langs %}{% ifequal lang.0 "de" %}{{ lang.0 }}{% endifequal %}{% endfor %}', {}, 'de'), - - # translation of a constant string - 'i18n13': ('{{ _("Page not found") }}', {'LANGUAGE_CODE': 'de'}, 'Seite nicht gefunden'), - - ### MULTILINE ############################################################# - - 'multiline01': (""" - Hello, - boys. - How - are - you - gentlemen. - """, - {}, - """ - Hello, - boys. - How - are - you - gentlemen. - """), - - ### REGROUP TAG ########################################################### - 'regroup01': ('{% regroup data by bar as grouped %}' + \ - '{% for group in grouped %}' + \ - '{{ group.grouper }}:' + \ - '{% for item in group.list %}' + \ - '{{ item.foo }}' + \ - '{% endfor %},' + \ - '{% endfor %}', - {'data': [ {'foo':'c', 'bar':1}, - {'foo':'d', 'bar':1}, - {'foo':'a', 'bar':2}, - {'foo':'b', 'bar':2}, - {'foo':'x', 'bar':3} ]}, - '1:cd,2:ab,3:x,'), - - # Test for silent failure when target variable isn't found - 'regroup02': ('{% regroup data by bar as grouped %}' + \ - '{% for group in grouped %}' + \ - '{{ group.grouper }}:' + \ - '{% for item in group.list %}' + \ - '{{ item.foo }}' + \ - '{% endfor %},' + \ - '{% endfor %}', - {}, 'INVALID:INVALIDINVALIDINVALIDINVALIDINVALIDINVALIDINVALID,'), - - ### TEMPLATETAG TAG ####################################################### - 'templatetag01': ('{% templatetag openblock %}', {}, '{%'), - 'templatetag02': ('{% templatetag closeblock %}', {}, '%}'), - 'templatetag03': ('{% templatetag openvariable %}', {}, '{{'), - 'templatetag04': ('{% templatetag closevariable %}', {}, '}}'), - 'templatetag05': ('{% templatetag %}', {}, template.TemplateSyntaxError), - 'templatetag06': ('{% templatetag foo %}', {}, template.TemplateSyntaxError), - 'templatetag07': ('{% templatetag openbrace %}', {}, '{'), - 'templatetag08': ('{% templatetag closebrace %}', {}, '}'), - 'templatetag09': ('{% templatetag openbrace %}{% templatetag openbrace %}', {}, '{{'), - 'templatetag10': ('{% templatetag closebrace %}{% templatetag closebrace %}', {}, '}}'), - - ### WIDTHRATIO TAG ######################################################## - 'widthratio01': ('{% widthratio a b 0 %}', {'a':50,'b':100}, '0'), - 'widthratio02': ('{% widthratio a b 100 %}', {'a':0,'b':0}, ''), - 'widthratio03': ('{% widthratio a b 100 %}', {'a':0,'b':100}, '0'), - 'widthratio04': ('{% widthratio a b 100 %}', {'a':50,'b':100}, '50'), - 'widthratio05': ('{% widthratio a b 100 %}', {'a':100,'b':100}, '100'), - - # 62.5 should round to 63 - 'widthratio06': ('{% widthratio a b 100 %}', {'a':50,'b':80}, '63'), - - # 71.4 should round to 71 - 'widthratio07': ('{% widthratio a b 100 %}', {'a':50,'b':70}, '71'), - - # Raise exception if we don't have 3 args, last one an integer - 'widthratio08': ('{% widthratio %}', {}, template.TemplateSyntaxError), - 'widthratio09': ('{% widthratio a b %}', {'a':50,'b':100}, template.TemplateSyntaxError), - 'widthratio10': ('{% widthratio a b 100.0 %}', {'a':50,'b':100}, template.TemplateSyntaxError), - - ### NOW TAG ######################################################## - # Simple case - 'now01' : ('{% now "j n Y"%}', {}, str(datetime.now().day) + ' ' + str(datetime.now().month) + ' ' + str(datetime.now().year)), - - # Check parsing of escaped and special characters - 'now02' : ('{% now "j "n" Y"%}', {}, template.TemplateSyntaxError), -# 'now03' : ('{% now "j \"n\" Y"%}', {}, str(datetime.now().day) + '"' + str(datetime.now().month) + '"' + str(datetime.now().year)), -# 'now04' : ('{% now "j \nn\n Y"%}', {}, str(datetime.now().day) + '\n' + str(datetime.now().month) + '\n' + str(datetime.now().year)) - - ### TIMESINCE TAG ################################################## - # Default compare with datetime.now() - 'timesince01' : ('{{ a|timesince }}', {'a':datetime.now() + timedelta(minutes=-1)}, '1 minute'), - 'timesince02' : ('{{ a|timesince }}', {'a':(datetime.now() - timedelta(days=1))}, '1 day'), - 'timesince03' : ('{{ a|timesince }}', {'a':(datetime.now() - - timedelta(hours=1, minutes=25))}, '1 hour, 25 minutes'), - - # Compare to a given parameter - 'timesince04' : ('{{ a|timesince:b }}', {'a':NOW + timedelta(days=2), 'b':NOW + timedelta(days=1)}, '1 day'), - 'timesince05' : ('{{ a|timesince:b }}', {'a':NOW + timedelta(days=2, minutes=1), 'b':NOW + timedelta(days=2)}, '1 minute'), - - # Check that timezone is respected - 'timesince06' : ('{{ a|timesince:b }}', {'a':NOW_tz + timedelta(hours=8), 'b':NOW_tz}, '8 hours'), - - ### TIMEUNTIL TAG ################################################## - # Default compare with datetime.now() - 'timeuntil01' : ('{{ a|timeuntil }}', {'a':datetime.now() + timedelta(minutes=2)}, '2 minutes'), - 'timeuntil02' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(days=1))}, '1 day'), - 'timeuntil03' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(hours=8, minutes=10))}, '8 hours, 10 minutes'), - - # Compare to a given parameter - 'timeuntil04' : ('{{ a|timeuntil:b }}', {'a':NOW - timedelta(days=1), 'b':NOW - timedelta(days=2)}, '1 day'), - 'timeuntil05' : ('{{ a|timeuntil:b }}', {'a':NOW - timedelta(days=2), 'b':NOW - timedelta(days=2, minutes=1)}, '1 minute'), -} - -def test_template_loader(template_name, template_dirs=None): - "A custom template loader that loads the unit-test templates." - try: - return (TEMPLATE_TESTS[template_name][0] , "test:%s" % template_name) - except KeyError: - raise template.TemplateDoesNotExist, template_name - -def run_tests(verbosity=0, standalone=False): - # Register our custom template loader. - old_template_loaders = loader.template_source_loaders - loader.template_source_loaders = [test_template_loader] - - failed_tests = [] - tests = TEMPLATE_TESTS.items() - tests.sort() - - # Turn TEMPLATE_DEBUG off, because tests assume that. - old_td, settings.TEMPLATE_DEBUG = settings.TEMPLATE_DEBUG, False - # Set TEMPLATE_STRING_IF_INVALID to a known string - old_invalid, settings.TEMPLATE_STRING_IF_INVALID = settings.TEMPLATE_STRING_IF_INVALID, 'INVALID' - - for name, vals in tests: - install() - if 'LANGUAGE_CODE' in vals[1]: - activate(vals[1]['LANGUAGE_CODE']) - else: - activate('en-us') - try: - output = loader.get_template(name).render(template.Context(vals[1])) - except Exception, e: - if e.__class__ == vals[2]: - if verbosity: - print "Template test: %s -- Passed" % name - else: - if verbosity: - traceback.print_exc() - print "Template test: %s -- FAILED. Got %s, exception: %s" % (name, e.__class__, e) - failed_tests.append(name) - continue - if 'LANGUAGE_CODE' in vals[1]: - deactivate() - if output == vals[2]: - if verbosity: - print "Template test: %s -- Passed" % name - else: - if verbosity: - print "Template test: %s -- FAILED. Expected %r, got %r" % (name, vals[2], output) - failed_tests.append(name) - loader.template_source_loaders = old_template_loaders - deactivate() - settings.TEMPLATE_DEBUG = old_td - settings.TEMPLATE_STRING_IF_INVALID = old_invalid - - if failed_tests and not standalone: - msg = "Template tests %s failed." % failed_tests - if not verbosity: - msg += " Re-run tests with -v1 to see actual failures" - raise Exception, msg - -if __name__ == "__main__": - settings.configure() - run_tests(1, True) diff --git a/tests/regressiontests/cache/__init__.py b/tests/regressiontests/cache/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/cache/__init__.py diff --git a/tests/regressiontests/cache/models.py b/tests/regressiontests/cache/models.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/cache/models.py diff --git a/tests/regressiontests/cache/tests.py b/tests/regressiontests/cache/tests.py new file mode 100644 index 0000000000..cf58ab321a --- /dev/null +++ b/tests/regressiontests/cache/tests.py @@ -0,0 +1,71 @@ +# Unit tests for cache framework +# Uses whatever cache backend is set in the test settings file. + +from django.core.cache import cache +import time, unittest + +# functions/classes for complex data type tests +def f(): + return 42 +class C: + def m(n): + return 24 + +class Cache(unittest.TestCase): + def test_simple(self): + # simple set/get + cache.set("key", "value") + self.assertEqual(cache.get("key"), "value") + + def test_non_existent(self): + # get with non-existent keys + self.assertEqual(cache.get("does not exist"), None) + self.assertEqual(cache.get("does not exist", "bang!"), "bang!") + + def test_get_many(self): + # get_many + cache.set('a', 'a') + cache.set('b', 'b') + cache.set('c', 'c') + cache.set('d', 'd') + self.assertEqual(cache.get_many(['a', 'c', 'd']), {'a' : 'a', 'c' : 'c', 'd' : 'd'}) + self.assertEqual(cache.get_many(['a', 'b', 'e']), {'a' : 'a', 'b' : 'b'}) + + def test_delete(self): + # delete + cache.set("key1", "spam") + cache.set("key2", "eggs") + self.assertEqual(cache.get("key1"), "spam") + cache.delete("key1") + self.assertEqual(cache.get("key1"), None) + self.assertEqual(cache.get("key2"), "eggs") + + def test_has_key(self): + # has_key + cache.set("hello", "goodbye") + self.assertEqual(cache.has_key("hello"), True) + self.assertEqual(cache.has_key("goodbye"), False) + + def test_data_types(self): + # test data types + stuff = { + 'string' : 'this is a string', + 'int' : 42, + 'list' : [1, 2, 3, 4], + 'tuple' : (1, 2, 3, 4), + 'dict' : {'A': 1, 'B' : 2}, + 'function' : f, + 'class' : C, + } + for (key, value) in stuff.items(): + cache.set(key, value) + self.assertEqual(cache.get(key), value) + + def test_expiration(self): + # expiration + cache.set('expire', 'very quickly', 1) + time.sleep(2) + self.assertEqual(cache.get("expire"), None) + +if __name__ == '__main__': + unittest.main()
\ No newline at end of file diff --git a/tests/regressiontests/dateformat/__init__.py b/tests/regressiontests/dateformat/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/dateformat/__init__.py diff --git a/tests/regressiontests/dateformat/models.py b/tests/regressiontests/dateformat/models.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/dateformat/models.py diff --git a/tests/othertests/dateformat.py b/tests/regressiontests/dateformat/tests.py index 0287587b4a..6e28759a92 100644 --- a/tests/othertests/dateformat.py +++ b/tests/regressiontests/dateformat/tests.py @@ -21,22 +21,22 @@ r""" '7' >>> format(my_birthday, 'N') 'July' ->>> format(my_birthday, 'O') -'+0100' +>>> no_tz or format(my_birthday, 'O') == '+0100' +True >>> format(my_birthday, 'P') '10 p.m.' ->>> format(my_birthday, 'r') -'Sun, 8 Jul 1979 22:00:00 +0100' +>>> no_tz or format(my_birthday, 'r') == 'Sun, 8 Jul 1979 22:00:00 +0100' +True >>> format(my_birthday, 's') '00' >>> format(my_birthday, 'S') 'th' >>> format(my_birthday, 't') '31' ->>> format(my_birthday, 'T') -'CET' ->>> format(my_birthday, 'U') -'300531600' +>>> no_tz or format(my_birthday, 'T') == 'CET' +True +>>> no_tz or format(my_birthday, 'U') == '300531600' +True >>> format(my_birthday, 'w') '0' >>> format(my_birthday, 'W') @@ -47,17 +47,17 @@ r""" '1979' >>> format(my_birthday, 'z') '189' ->>> format(my_birthday, 'Z') -'3600' +>>> no_tz or format(my_birthday, 'Z') == '3600' +True ->>> format(summertime, 'I') -'1' ->>> format(summertime, 'O') -'+0200' ->>> format(wintertime, 'I') -'0' ->>> format(wintertime, 'O') -'+0100' +>>> no_tz or format(summertime, 'I') == '1' +True +>>> no_tz or format(summertime, 'O') == '+0200' +True +>>> no_tz or format(wintertime, 'I') == '0' +True +>>> no_tz or format(wintertime, 'O') == '+0100' +True >>> format(my_birthday, r'Y z \C\E\T') '1979 189 CET' @@ -73,7 +73,11 @@ format = dateformat.format os.environ['TZ'] = 'Europe/Copenhagen' translation.activate('en-us') -time.tzset() +try: + time.tzset() + no_tz = False +except AttributeError: + no_tz = True my_birthday = datetime.datetime(1979, 7, 8, 22, 00) summertime = datetime.datetime(2005, 10, 30, 1, 00) diff --git a/tests/regressiontests/db_typecasts/__init__.py b/tests/regressiontests/db_typecasts/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/db_typecasts/__init__.py diff --git a/tests/regressiontests/db_typecasts/models.py b/tests/regressiontests/db_typecasts/models.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/db_typecasts/models.py diff --git a/tests/othertests/db_typecasts.py b/tests/regressiontests/db_typecasts/tests.py index ffc9b34aec..f4b77fe3a6 100644 --- a/tests/othertests/db_typecasts.py +++ b/tests/regressiontests/db_typecasts/tests.py @@ -1,7 +1,7 @@ # Unit tests for typecast functions in django.db.backends.util from django.db.backends import util as typecasts -import datetime +import datetime, unittest TEST_CASES = { 'typecast_date': ( @@ -45,7 +45,12 @@ TEST_CASES = { ), } -for k, v in TEST_CASES.items(): - for inpt, expected in v: - got = getattr(typecasts, k)(inpt) - assert got == expected, "In %s: %r doesn't match %r. Got %r instead." % (k, inpt, expected, got) +class DBTypeCasts(unittest.TestCase): + def test_typeCasts(self): + for k, v in TEST_CASES.items(): + for inpt, expected in v: + got = getattr(typecasts, k)(inpt) + assert got == expected, "In %s: %r doesn't match %r. Got %r instead." % (k, inpt, expected, got) + +if __name__ == '__main__': + unittest.main()
\ No newline at end of file diff --git a/tests/regressiontests/defaultfilters/__init__.py b/tests/regressiontests/defaultfilters/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/defaultfilters/__init__.py diff --git a/tests/regressiontests/defaultfilters/models.py b/tests/regressiontests/defaultfilters/models.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/defaultfilters/models.py diff --git a/tests/othertests/defaultfilters.py b/tests/regressiontests/defaultfilters/tests.py index 1636b948d0..32d6ef5202 100644 --- a/tests/othertests/defaultfilters.py +++ b/tests/regressiontests/defaultfilters/tests.py @@ -15,6 +15,9 @@ r""" >>> addslashes('"double quotes" and \'single quotes\'') '\\"double quotes\\" and \\\'single quotes\\\'' +>>> addslashes(r'\ : backslashes, too') +'\\\\ : backslashes, too' + >>> capfirst('hello world') 'Hello world' @@ -231,6 +234,9 @@ False >>> time(datetime.time(13), "h") '01' +>>> time(datetime.time(0), "h") +'12' + # real testing is done in timesince.py, where we can provide our own 'now' >>> timesince(datetime.datetime.now() - datetime.timedelta(1)) '1 day' diff --git a/tests/regressiontests/httpwrappers/__init__.py b/tests/regressiontests/httpwrappers/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/httpwrappers/__init__.py diff --git a/tests/regressiontests/httpwrappers/models.py b/tests/regressiontests/httpwrappers/models.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/httpwrappers/models.py diff --git a/tests/othertests/httpwrappers.py b/tests/regressiontests/httpwrappers/tests.py index 385c3048d9..385c3048d9 100644 --- a/tests/othertests/httpwrappers.py +++ b/tests/regressiontests/httpwrappers/tests.py diff --git a/tests/regressiontests/initial_sql_regress/models.py b/tests/regressiontests/initial_sql_regress/models.py index c4cf12bdf7..dedbba8e5c 100644 --- a/tests/regressiontests/initial_sql_regress/models.py +++ b/tests/regressiontests/initial_sql_regress/models.py @@ -7,7 +7,7 @@ from django.db import models class Simple(models.Model): name = models.CharField(maxlength = 50) -API_TESTS = "" +__test__ = {'API_TESTS':""} # NOTE: The format of the included SQL file for this test suite is important. # It must end with a trailing newline in order to test the fix for #2161. diff --git a/tests/regressiontests/initial_sql_regress/sql/simple.sql b/tests/regressiontests/initial_sql_regress/sql/simple.sql index ddb08bc91f..ca9bd40dab 100644 --- a/tests/regressiontests/initial_sql_regress/sql/simple.sql +++ b/tests/regressiontests/initial_sql_regress/sql/simple.sql @@ -4,4 +4,5 @@ INSERT INTO initial_sql_regress_simple (name) VALUES ('Ringo'); INSERT INTO initial_sql_regress_simple (name) VALUES ('George'); INSERT INTO initial_sql_regress_simple (name) VALUES ('Miles O''Brien'); INSERT INTO initial_sql_regress_simple (name) VALUES ('Semicolon;Man'); +INSERT INTO initial_sql_regress_simple (name) VALUES ('This line has a Windows line ending');
diff --git a/tests/regressiontests/many_to_one_regress/models.py b/tests/regressiontests/many_to_one_regress/models.py index 485e928777..6c067446b1 100644 --- a/tests/regressiontests/many_to_one_regress/models.py +++ b/tests/regressiontests/many_to_one_regress/models.py @@ -10,4 +10,4 @@ class Second(models.Model): # created (the field names being lower-cased versions of their opposite # classes is important here). -API_TESTS = "" +__test__ = {'API_TESTS':""} diff --git a/tests/regressiontests/markup/__init__.py b/tests/regressiontests/markup/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/markup/__init__.py diff --git a/tests/regressiontests/markup/models.py b/tests/regressiontests/markup/models.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/markup/models.py diff --git a/tests/regressiontests/markup/tests.py b/tests/regressiontests/markup/tests.py new file mode 100644 index 0000000000..bd3f52b9dd --- /dev/null +++ b/tests/regressiontests/markup/tests.py @@ -0,0 +1,69 @@ +# Quick tests for the markup templatetags (django.contrib.markup) + +from django.template import Template, Context, add_to_builtins +import re +import unittest + +add_to_builtins('django.contrib.markup.templatetags.markup') + +class Templates(unittest.TestCase): + def test_textile(self): + try: + import textile + except ImportError: + textile = None + + textile_content = """Paragraph 1 + +Paragraph 2 with "quotes" and @code@""" + + t = Template("{{ textile_content|textile }}") + rendered = t.render(Context(locals())).strip() + if textile: + self.assertEqual(rendered, """<p>Paragraph 1</p> + +<p>Paragraph 2 with “quotes” and <code>code</code></p>""") + else: + self.assertEqual(rendered, textile_content) + + def test_markdown(self): + try: + import markdown + except ImportError: + markdown = None + + markdown_content = """Paragraph 1 + +## An h2""" + + t = Template("{{ markdown_content|markdown }}") + rendered = t.render(Context(locals())).strip() + if markdown: + pattern = re.compile("""<p>Paragraph 1\s*</p>\s*<h2>\s*An h2</h2>""") + self.assert_(pattern.match(rendered)) + else: + self.assertEqual(rendered, markdown_content) + + def test_docutils(self): + try: + import docutils + except ImportError: + docutils = None + + rest_content = """Paragraph 1 + +Paragraph 2 with a link_ + +.. _link: http://www.example.com/""" + + t = Template("{{ rest_content|restructuredtext }}") + rendered = t.render(Context(locals())).strip() + if docutils: + self.assertEqual(rendered, """<p>Paragraph 1</p> +<p>Paragraph 2 with a <a class="reference" href="http://www.example.com/">link</a></p>""") + else: + self.assertEqual(rendered, rest_content) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/regressiontests/null_queries/__init__.py b/tests/regressiontests/null_queries/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/null_queries/__init__.py diff --git a/tests/regressiontests/null_queries/models.py b/tests/regressiontests/null_queries/models.py new file mode 100644 index 0000000000..09024f18c2 --- /dev/null +++ b/tests/regressiontests/null_queries/models.py @@ -0,0 +1,54 @@ +from django.db import models + +class Poll(models.Model): + question = models.CharField(maxlength=200) + + def __str__(self): + return "Q: %s " % self.question + +class Choice(models.Model): + poll = models.ForeignKey(Poll) + choice = models.CharField(maxlength=200) + + def __str__(self): + return "Choice: %s in poll %s" % (self.choice, self.poll) + +__test__ = {'API_TESTS':""" +# Regression test for the use of None as a query value. None is interpreted as +# an SQL NULL, but only in __exact queries. +# Set up some initial polls and choices +>>> p1 = Poll(question='Why?') +>>> p1.save() +>>> c1 = Choice(poll=p1, choice='Because.') +>>> c1.save() +>>> c2 = Choice(poll=p1, choice='Why Not?') +>>> c2.save() + +# Exact query with value None returns nothing (=NULL in sql) +>>> Choice.objects.filter(id__exact=None) +[] + +# Valid query, but fails because foo isn't a keyword +>>> Choice.objects.filter(foo__exact=None) +Traceback (most recent call last): +... +TypeError: Cannot resolve keyword 'foo' into field + +# Can't use None on anything other than __exact +>>> Choice.objects.filter(id__gt=None) +Traceback (most recent call last): +... +ValueError: Cannot use None as a query value + +# Can't use None on anything other than __exact +>>> Choice.objects.filter(foo__gt=None) +Traceback (most recent call last): +... +ValueError: Cannot use None as a query value + +# Related managers use __exact=None implicitly if the object hasn't been saved. +>>> p2 = Poll(question="How?") +>>> p2.choice_set.all() +[] + +"""} diff --git a/tests/regressiontests/one_to_one_regress/models.py b/tests/regressiontests/one_to_one_regress/models.py index 6cc1df4e5c..b81f4266e1 100644 --- a/tests/regressiontests/one_to_one_regress/models.py +++ b/tests/regressiontests/one_to_one_regress/models.py @@ -22,7 +22,7 @@ class Favorites(models.Model): def __str__(self): return "Favorites for %s" % self.name -API_TESTS = """ +__test__ = {'API_TESTS':""" # Regression test for #1064 and #1506: Check that we create models via the m2m # relation if the remote model has a OneToOneField. >>> p1 = Place(name='Demon Dogs', address='944 W. Fullerton') @@ -34,4 +34,4 @@ API_TESTS = """ >>> f.restaurants = [r] >>> f.restaurants.all() [<Restaurant: Demon Dogs the restaurant>] -""" +"""} diff --git a/tests/regressiontests/string_lookup/models.py b/tests/regressiontests/string_lookup/models.py index a4582ca4e9..441bb3f8a3 100644 --- a/tests/regressiontests/string_lookup/models.py +++ b/tests/regressiontests/string_lookup/models.py @@ -34,7 +34,7 @@ class Base(models.Model): def __str__(self): return "Base %s" % self.name -API_TESTS = """ +__test__ = {'API_TESTS':""" # Regression test for #1661 and #1662: Check that string form referencing of models works, # both as pre and post reference, on all RelatedField types. @@ -66,4 +66,4 @@ API_TESTS = """ >>> child1.parent <Base: Base Base1> -""" +"""} diff --git a/tests/regressiontests/templates/__init__.py b/tests/regressiontests/templates/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/templates/__init__.py diff --git a/tests/regressiontests/templates/models.py b/tests/regressiontests/templates/models.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/templates/models.py diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py new file mode 100644 index 0000000000..ef31b853ca --- /dev/null +++ b/tests/regressiontests/templates/tests.py @@ -0,0 +1,667 @@ +from django.conf import settings + +if __name__ == '__main__': + # When running this file in isolation, we need to set up the configuration + # before importing 'template'. + settings.configure() + +from django import template +from django.template import loader +from django.utils.translation import activate, deactivate, install +from django.utils.tzinfo import LocalTimezone +from datetime import datetime, timedelta +import unittest + +################################# +# Custom template tag for tests # +################################# + +register = template.Library() + +class EchoNode(template.Node): + def __init__(self, contents): + self.contents = contents + + def render(self, context): + return " ".join(self.contents) + +def do_echo(parser, token): + return EchoNode(token.contents.split()[1:]) + +register.tag("echo", do_echo) + +template.libraries['django.templatetags.testtags'] = register + +##################################### +# Helper objects for template tests # +##################################### + +class SomeException(Exception): + silent_variable_failure = True + +class SomeOtherException(Exception): + pass + +class SomeClass: + def __init__(self): + self.otherclass = OtherClass() + + def method(self): + return "SomeClass.method" + + def method2(self, o): + return o + + def method3(self): + raise SomeException + + def method4(self): + raise SomeOtherException + +class OtherClass: + def method(self): + return "OtherClass.method" + +class Templates(unittest.TestCase): + def test_templates(self): + # NOW and NOW_tz are used by timesince tag tests. + NOW = datetime.now() + NOW_tz = datetime.now(LocalTimezone(datetime.now())) + + # SYNTAX -- + # 'template_name': ('template contents', 'context dict', 'expected string output' or Exception class) + TEMPLATE_TESTS = { + + ### BASIC SYNTAX ########################################################## + + # Plain text should go through the template parser untouched + 'basic-syntax01': ("something cool", {}, "something cool"), + + # Variables should be replaced with their value in the current context + 'basic-syntax02': ("{{ headline }}", {'headline':'Success'}, "Success"), + + # More than one replacement variable is allowed in a template + 'basic-syntax03': ("{{ first }} --- {{ second }}", {"first" : 1, "second" : 2}, "1 --- 2"), + + # Fail silently when a variable is not found in the current context + 'basic-syntax04': ("as{{ missing }}df", {}, ("asdf","asINVALIDdf")), + + # A variable may not contain more than one word + 'basic-syntax06': ("{{ multi word variable }}", {}, template.TemplateSyntaxError), + + # Raise TemplateSyntaxError for empty variable tags + 'basic-syntax07': ("{{ }}", {}, template.TemplateSyntaxError), + 'basic-syntax08': ("{{ }}", {}, template.TemplateSyntaxError), + + # Attribute syntax allows a template to call an object's attribute + 'basic-syntax09': ("{{ var.method }}", {"var": SomeClass()}, "SomeClass.method"), + + # Multiple levels of attribute access are allowed + 'basic-syntax10': ("{{ var.otherclass.method }}", {"var": SomeClass()}, "OtherClass.method"), + + # Fail silently when a variable's attribute isn't found + 'basic-syntax11': ("{{ var.blech }}", {"var": SomeClass()}, ("","INVALID")), + + # Raise TemplateSyntaxError when trying to access a variable beginning with an underscore + 'basic-syntax12': ("{{ var.__dict__ }}", {"var": SomeClass()}, template.TemplateSyntaxError), + + # Raise TemplateSyntaxError when trying to access a variable containing an illegal character + 'basic-syntax13': ("{{ va>r }}", {}, template.TemplateSyntaxError), + 'basic-syntax14': ("{{ (var.r) }}", {}, template.TemplateSyntaxError), + 'basic-syntax15': ("{{ sp%am }}", {}, template.TemplateSyntaxError), + 'basic-syntax16': ("{{ eggs! }}", {}, template.TemplateSyntaxError), + 'basic-syntax17': ("{{ moo? }}", {}, template.TemplateSyntaxError), + + # Attribute syntax allows a template to call a dictionary key's value + 'basic-syntax18': ("{{ foo.bar }}", {"foo" : {"bar" : "baz"}}, "baz"), + + # Fail silently when a variable's dictionary key isn't found + 'basic-syntax19': ("{{ foo.spam }}", {"foo" : {"bar" : "baz"}}, ("","INVALID")), + + # Fail silently when accessing a non-simple method + 'basic-syntax20': ("{{ var.method2 }}", {"var": SomeClass()}, ("","INVALID")), + + # Basic filter usage + 'basic-syntax21': ("{{ var|upper }}", {"var": "Django is the greatest!"}, "DJANGO IS THE GREATEST!"), + + # Chained filters + 'basic-syntax22': ("{{ var|upper|lower }}", {"var": "Django is the greatest!"}, "django is the greatest!"), + + # Raise TemplateSyntaxError for space between a variable and filter pipe + 'basic-syntax23': ("{{ var |upper }}", {}, template.TemplateSyntaxError), + + # Raise TemplateSyntaxError for space after a filter pipe + 'basic-syntax24': ("{{ var| upper }}", {}, template.TemplateSyntaxError), + + # Raise TemplateSyntaxError for a nonexistent filter + 'basic-syntax25': ("{{ var|does_not_exist }}", {}, template.TemplateSyntaxError), + + # Raise TemplateSyntaxError when trying to access a filter containing an illegal character + 'basic-syntax26': ("{{ var|fil(ter) }}", {}, template.TemplateSyntaxError), + + # Raise TemplateSyntaxError for invalid block tags + 'basic-syntax27': ("{% nothing_to_see_here %}", {}, template.TemplateSyntaxError), + + # Raise TemplateSyntaxError for empty block tags + 'basic-syntax28': ("{% %}", {}, template.TemplateSyntaxError), + + # Chained filters, with an argument to the first one + 'basic-syntax29': ('{{ var|removetags:"b i"|upper|lower }}', {"var": "<b><i>Yes</i></b>"}, "yes"), + + # Escaped string as argument + 'basic-syntax30': (r'{{ var|default_if_none:" endquote\" hah" }}', {"var": None}, ' endquote" hah'), + + # Variable as argument + 'basic-syntax31': (r'{{ var|default_if_none:var2 }}', {"var": None, "var2": "happy"}, 'happy'), + + # Default argument testing + 'basic-syntax32': (r'{{ var|yesno:"yup,nup,mup" }} {{ var|yesno }}', {"var": True}, 'yup yes'), + + # Fail silently for methods that raise an exception with a "silent_variable_failure" attribute + 'basic-syntax33': (r'1{{ var.method3 }}2', {"var": SomeClass()}, ("12", "1INVALID2")), + + # In methods that raise an exception without a "silent_variable_attribute" set to True, + # the exception propogates + 'basic-syntax34': (r'1{{ var.method4 }}2', {"var": SomeClass()}, SomeOtherException), + + # Escaped backslash in argument + 'basic-syntax35': (r'{{ var|default_if_none:"foo\bar" }}', {"var": None}, r'foo\bar'), + + # Escaped backslash using known escape char + 'basic-syntax35': (r'{{ var|default_if_none:"foo\now" }}', {"var": None}, r'foo\now'), + + # Empty strings can be passed as arguments to filters + 'basic-syntax36': (r'{{ var|join:"" }}', {'var': ['a', 'b', 'c']}, 'abc'), + + ### COMMENT SYNTAX ######################################################## + 'comment-syntax01': ("{# this is hidden #}hello", {}, "hello"), + 'comment-syntax02': ("{# this is hidden #}hello{# foo #}", {}, "hello"), + + # Comments can contain invalid stuff. + 'comment-syntax03': ("foo{# {% if %} #}", {}, "foo"), + 'comment-syntax04': ("foo{# {% endblock %} #}", {}, "foo"), + 'comment-syntax05': ("foo{# {% somerandomtag %} #}", {}, "foo"), + 'comment-syntax06': ("foo{# {% #}", {}, "foo"), + 'comment-syntax07': ("foo{# %} #}", {}, "foo"), + 'comment-syntax08': ("foo{# %} #}bar", {}, "foobar"), + 'comment-syntax09': ("foo{# {{ #}", {}, "foo"), + 'comment-syntax10': ("foo{# }} #}", {}, "foo"), + 'comment-syntax11': ("foo{# { #}", {}, "foo"), + 'comment-syntax12': ("foo{# } #}", {}, "foo"), + + ### COMMENT TAG ########################################################### + 'comment-tag01': ("{% comment %}this is hidden{% endcomment %}hello", {}, "hello"), + 'comment-tag02': ("{% comment %}this is hidden{% endcomment %}hello{% comment %}foo{% endcomment %}", {}, "hello"), + + # Comment tag can contain invalid stuff. + 'comment-tag03': ("foo{% comment %} {% if %} {% endcomment %}", {}, "foo"), + 'comment-tag04': ("foo{% comment %} {% endblock %} {% endcomment %}", {}, "foo"), + 'comment-tag05': ("foo{% comment %} {% somerandomtag %} {% endcomment %}", {}, "foo"), + + ### CYCLE TAG ############################################################# + 'cycle01': ('{% cycle a %}', {}, template.TemplateSyntaxError), + 'cycle02': ('{% cycle a,b,c as abc %}{% cycle abc %}', {}, 'ab'), + 'cycle03': ('{% cycle a,b,c as abc %}{% cycle abc %}{% cycle abc %}', {}, 'abc'), + 'cycle04': ('{% cycle a,b,c as abc %}{% cycle abc %}{% cycle abc %}{% cycle abc %}', {}, 'abca'), + 'cycle05': ('{% cycle %}', {}, template.TemplateSyntaxError), + 'cycle06': ('{% cycle a %}', {}, template.TemplateSyntaxError), + 'cycle07': ('{% cycle a,b,c as foo %}{% cycle bar %}', {}, template.TemplateSyntaxError), + 'cycle08': ('{% cycle a,b,c as foo %}{% cycle foo %}{{ foo }}{{ foo }}{% cycle foo %}{{ foo }}', {}, 'abbbcc'), + + ### EXCEPTIONS ############################################################ + + # Raise exception for invalid template name + 'exception01': ("{% extends 'nonexistent' %}", {}, template.TemplateSyntaxError), + + # Raise exception for invalid template name (in variable) + 'exception02': ("{% extends nonexistent %}", {}, template.TemplateSyntaxError), + + # Raise exception for extra {% extends %} tags + 'exception03': ("{% extends 'inheritance01' %}{% block first %}2{% endblock %}{% extends 'inheritance16' %}", {}, template.TemplateSyntaxError), + + # Raise exception for custom tags used in child with {% load %} tag in parent, not in child + 'exception04': ("{% extends 'inheritance17' %}{% block first %}{% echo 400 %}5678{% endblock %}", {}, template.TemplateSyntaxError), + + ### FILTER TAG ############################################################ + 'filter01': ('{% filter upper %}{% endfilter %}', {}, ''), + 'filter02': ('{% filter upper %}django{% endfilter %}', {}, 'DJANGO'), + 'filter03': ('{% filter upper|lower %}django{% endfilter %}', {}, 'django'), + + ### FIRSTOF TAG ########################################################### + 'firstof01': ('{% firstof a b c %}', {'a':0,'b':0,'c':0}, ''), + 'firstof02': ('{% firstof a b c %}', {'a':1,'b':0,'c':0}, '1'), + 'firstof03': ('{% firstof a b c %}', {'a':0,'b':2,'c':0}, '2'), + 'firstof04': ('{% firstof a b c %}', {'a':0,'b':0,'c':3}, '3'), + 'firstof05': ('{% firstof a b c %}', {'a':1,'b':2,'c':3}, '1'), + 'firstof06': ('{% firstof %}', {}, template.TemplateSyntaxError), + + ### FOR TAG ############################################################### + 'for-tag01': ("{% for val in values %}{{ val }}{% endfor %}", {"values": [1, 2, 3]}, "123"), + 'for-tag02': ("{% for val in values reversed %}{{ val }}{% endfor %}", {"values": [1, 2, 3]}, "321"), + 'for-tag-vars01': ("{% for val in values %}{{ forloop.counter }}{% endfor %}", {"values": [6, 6, 6]}, "123"), + 'for-tag-vars02': ("{% for val in values %}{{ forloop.counter0 }}{% endfor %}", {"values": [6, 6, 6]}, "012"), + 'for-tag-vars03': ("{% for val in values %}{{ forloop.revcounter }}{% endfor %}", {"values": [6, 6, 6]}, "321"), + 'for-tag-vars04': ("{% for val in values %}{{ forloop.revcounter0 }}{% endfor %}", {"values": [6, 6, 6]}, "210"), + + ### IF TAG ################################################################ + 'if-tag01': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": True}, "yes"), + 'if-tag02': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": False}, "no"), + 'if-tag03': ("{% if foo %}yes{% else %}no{% endif %}", {}, "no"), + + # AND + 'if-tag-and01': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'), + 'if-tag-and02': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'), + 'if-tag-and03': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'), + 'if-tag-and04': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'), + 'if-tag-and05': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': False}, 'no'), + 'if-tag-and06': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'bar': False}, 'no'), + 'if-tag-and07': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True}, 'no'), + 'if-tag-and08': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'bar': True}, 'no'), + + # OR + 'if-tag-or01': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'), + 'if-tag-or02': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'), + 'if-tag-or03': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'), + 'if-tag-or04': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'), + 'if-tag-or05': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': False}, 'no'), + 'if-tag-or06': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'bar': False}, 'no'), + 'if-tag-or07': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': True}, 'yes'), + 'if-tag-or08': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'bar': True}, 'yes'), + + # TODO: multiple ORs + + # NOT + 'if-tag-not01': ("{% if not foo %}no{% else %}yes{% endif %}", {'foo': True}, 'yes'), + 'if-tag-not02': ("{% if not %}yes{% else %}no{% endif %}", {'foo': True}, 'no'), + 'if-tag-not03': ("{% if not %}yes{% else %}no{% endif %}", {'not': True}, 'yes'), + 'if-tag-not04': ("{% if not not %}no{% else %}yes{% endif %}", {'not': True}, 'yes'), + 'if-tag-not05': ("{% if not not %}no{% else %}yes{% endif %}", {}, 'no'), + + 'if-tag-not06': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {}, 'no'), + 'if-tag-not07': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'), + 'if-tag-not08': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'), + 'if-tag-not09': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'), + 'if-tag-not10': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'), + + 'if-tag-not11': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {}, 'no'), + 'if-tag-not12': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'), + 'if-tag-not13': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'), + 'if-tag-not14': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'), + 'if-tag-not15': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'), + + 'if-tag-not16': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {}, 'yes'), + 'if-tag-not17': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'), + 'if-tag-not18': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'), + 'if-tag-not19': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'), + 'if-tag-not20': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'), + + 'if-tag-not21': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {}, 'yes'), + 'if-tag-not22': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'), + 'if-tag-not23': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'), + 'if-tag-not24': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'), + 'if-tag-not25': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'), + + 'if-tag-not26': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {}, 'yes'), + 'if-tag-not27': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'), + 'if-tag-not28': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'), + 'if-tag-not29': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'), + 'if-tag-not30': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'), + + 'if-tag-not31': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {}, 'yes'), + 'if-tag-not32': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'), + 'if-tag-not33': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'), + 'if-tag-not34': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'), + 'if-tag-not35': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'), + + # AND and OR raises a TemplateSyntaxError + 'if-tag-error01': ("{% if foo or bar and baz %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, template.TemplateSyntaxError), + 'if-tag-error02': ("{% if foo and %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError), + 'if-tag-error03': ("{% if foo or %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError), + 'if-tag-error04': ("{% if not foo and %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError), + 'if-tag-error05': ("{% if not foo or %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError), + + ### IFCHANGED TAG ######################################################### + 'ifchanged01': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,2,3) }, '123'), + 'ifchanged02': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,1,3) }, '13'), + 'ifchanged03': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,1,1) }, '1'), + 'ifchanged04': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}', { 'num': (1, 2, 3), 'numx': (2, 2, 2)}, '122232'), + 'ifchanged05': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}', { 'num': (1, 1, 1), 'numx': (1, 2, 3)}, '1123123123'), + 'ifchanged06': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}', { 'num': (1, 1, 1), 'numx': (2, 2, 2)}, '1222'), + 'ifchanged07': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% for y in numy %}{% ifchanged %}{{ y }}{% endifchanged %}{% endfor %}{% endfor %}{% endfor %}', { 'num': (1, 1, 1), 'numx': (2, 2, 2), 'numy': (3, 3, 3)}, '1233323332333'), + + ### IFEQUAL TAG ########################################################### + 'ifequal01': ("{% ifequal a b %}yes{% endifequal %}", {"a": 1, "b": 2}, ""), + 'ifequal02': ("{% ifequal a b %}yes{% endifequal %}", {"a": 1, "b": 1}, "yes"), + 'ifequal03': ("{% ifequal a b %}yes{% else %}no{% endifequal %}", {"a": 1, "b": 2}, "no"), + 'ifequal04': ("{% ifequal a b %}yes{% else %}no{% endifequal %}", {"a": 1, "b": 1}, "yes"), + 'ifequal05': ("{% ifequal a 'test' %}yes{% else %}no{% endifequal %}", {"a": "test"}, "yes"), + 'ifequal06': ("{% ifequal a 'test' %}yes{% else %}no{% endifequal %}", {"a": "no"}, "no"), + 'ifequal07': ('{% ifequal a "test" %}yes{% else %}no{% endifequal %}', {"a": "test"}, "yes"), + 'ifequal08': ('{% ifequal a "test" %}yes{% else %}no{% endifequal %}', {"a": "no"}, "no"), + 'ifequal09': ('{% ifequal a "test" %}yes{% else %}no{% endifequal %}', {}, "no"), + 'ifequal10': ('{% ifequal a b %}yes{% else %}no{% endifequal %}', {}, "yes"), + + # SMART SPLITTING + 'ifequal-split01': ('{% ifequal a "test man" %}yes{% else %}no{% endifequal %}', {}, "no"), + 'ifequal-split02': ('{% ifequal a "test man" %}yes{% else %}no{% endifequal %}', {'a': 'foo'}, "no"), + 'ifequal-split03': ('{% ifequal a "test man" %}yes{% else %}no{% endifequal %}', {'a': 'test man'}, "yes"), + 'ifequal-split04': ("{% ifequal a 'test man' %}yes{% else %}no{% endifequal %}", {'a': 'test man'}, "yes"), + 'ifequal-split05': ("{% ifequal a 'i \"love\" you' %}yes{% else %}no{% endifequal %}", {'a': ''}, "no"), + 'ifequal-split06': ("{% ifequal a 'i \"love\" you' %}yes{% else %}no{% endifequal %}", {'a': 'i "love" you'}, "yes"), + 'ifequal-split07': ("{% ifequal a 'i \"love\" you' %}yes{% else %}no{% endifequal %}", {'a': 'i love you'}, "no"), + 'ifequal-split08': (r"{% ifequal a 'I\'m happy' %}yes{% else %}no{% endifequal %}", {'a': "I'm happy"}, "yes"), + 'ifequal-split09': (r"{% ifequal a 'slash\man' %}yes{% else %}no{% endifequal %}", {'a': r"slash\man"}, "yes"), + 'ifequal-split10': (r"{% ifequal a 'slash\man' %}yes{% else %}no{% endifequal %}", {'a': r"slashman"}, "no"), + + ### IFNOTEQUAL TAG ######################################################## + 'ifnotequal01': ("{% ifnotequal a b %}yes{% endifnotequal %}", {"a": 1, "b": 2}, "yes"), + 'ifnotequal02': ("{% ifnotequal a b %}yes{% endifnotequal %}", {"a": 1, "b": 1}, ""), + 'ifnotequal03': ("{% ifnotequal a b %}yes{% else %}no{% endifnotequal %}", {"a": 1, "b": 2}, "yes"), + 'ifnotequal04': ("{% ifnotequal a b %}yes{% else %}no{% endifnotequal %}", {"a": 1, "b": 1}, "no"), + + ### INCLUDE TAG ########################################################### + 'include01': ('{% include "basic-syntax01" %}', {}, "something cool"), + 'include02': ('{% include "basic-syntax02" %}', {'headline': 'Included'}, "Included"), + 'include03': ('{% include template_name %}', {'template_name': 'basic-syntax02', 'headline': 'Included'}, "Included"), + 'include04': ('a{% include "nonexistent" %}b', {}, "ab"), + + ### INHERITANCE ########################################################### + + # Standard template with no inheritance + 'inheritance01': ("1{% block first %}_{% endblock %}3{% block second %}_{% endblock %}", {}, '1_3_'), + + # Standard two-level inheritance + 'inheritance02': ("{% extends 'inheritance01' %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {}, '1234'), + + # Three-level with no redefinitions on third level + 'inheritance03': ("{% extends 'inheritance02' %}", {}, '1234'), + + # Two-level with no redefinitions on second level + 'inheritance04': ("{% extends 'inheritance01' %}", {}, '1_3_'), + + # Two-level with double quotes instead of single quotes + 'inheritance05': ('{% extends "inheritance02" %}', {}, '1234'), + + # Three-level with variable parent-template name + 'inheritance06': ("{% extends foo %}", {'foo': 'inheritance02'}, '1234'), + + # Two-level with one block defined, one block not defined + 'inheritance07': ("{% extends 'inheritance01' %}{% block second %}5{% endblock %}", {}, '1_35'), + + # Three-level with one block defined on this level, two blocks defined next level + 'inheritance08': ("{% extends 'inheritance02' %}{% block second %}5{% endblock %}", {}, '1235'), + + # Three-level with second and third levels blank + 'inheritance09': ("{% extends 'inheritance04' %}", {}, '1_3_'), + + # Three-level with space NOT in a block -- should be ignored + 'inheritance10': ("{% extends 'inheritance04' %} ", {}, '1_3_'), + + # Three-level with both blocks defined on this level, but none on second level + 'inheritance11': ("{% extends 'inheritance04' %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {}, '1234'), + + # Three-level with this level providing one and second level providing the other + 'inheritance12': ("{% extends 'inheritance07' %}{% block first %}2{% endblock %}", {}, '1235'), + + # Three-level with this level overriding second level + 'inheritance13': ("{% extends 'inheritance02' %}{% block first %}a{% endblock %}{% block second %}b{% endblock %}", {}, '1a3b'), + + # A block defined only in a child template shouldn't be displayed + 'inheritance14': ("{% extends 'inheritance01' %}{% block newblock %}NO DISPLAY{% endblock %}", {}, '1_3_'), + + # A block within another block + 'inheritance15': ("{% extends 'inheritance01' %}{% block first %}2{% block inner %}inner{% endblock %}{% endblock %}", {}, '12inner3_'), + + # A block within another block (level 2) + 'inheritance16': ("{% extends 'inheritance15' %}{% block inner %}out{% endblock %}", {}, '12out3_'), + + # {% load %} tag (parent -- setup for exception04) + 'inheritance17': ("{% load testtags %}{% block first %}1234{% endblock %}", {}, '1234'), + + # {% load %} tag (standard usage, without inheritance) + 'inheritance18': ("{% load testtags %}{% echo this that theother %}5678", {}, 'this that theother5678'), + + # {% load %} tag (within a child template) + 'inheritance19': ("{% extends 'inheritance01' %}{% block first %}{% load testtags %}{% echo 400 %}5678{% endblock %}", {}, '140056783_'), + + # Two-level inheritance with {{ block.super }} + 'inheritance20': ("{% extends 'inheritance01' %}{% block first %}{{ block.super }}a{% endblock %}", {}, '1_a3_'), + + # Three-level inheritance with {{ block.super }} from parent + 'inheritance21': ("{% extends 'inheritance02' %}{% block first %}{{ block.super }}a{% endblock %}", {}, '12a34'), + + # Three-level inheritance with {{ block.super }} from grandparent + 'inheritance22': ("{% extends 'inheritance04' %}{% block first %}{{ block.super }}a{% endblock %}", {}, '1_a3_'), + + # Three-level inheritance with {{ block.super }} from parent and grandparent + 'inheritance23': ("{% extends 'inheritance20' %}{% block first %}{{ block.super }}b{% endblock %}", {}, '1_ab3_'), + + # Inheritance from local context without use of template loader + 'inheritance24': ("{% extends context_template %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {'context_template': template.Template("1{% block first %}_{% endblock %}3{% block second %}_{% endblock %}")}, '1234'), + + # Inheritance from local context with variable parent template + 'inheritance25': ("{% extends context_template.1 %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {'context_template': [template.Template("Wrong"), template.Template("1{% block first %}_{% endblock %}3{% block second %}_{% endblock %}")]}, '1234'), + + ### I18N ################################################################## + + # {% spaceless %} tag + 'spaceless01': ("{% spaceless %} <b> <i> text </i> </b> {% endspaceless %}", {}, "<b> <i> text </i> </b>"), + 'spaceless02': ("{% spaceless %} <b> \n <i> text </i> \n </b> {% endspaceless %}", {}, "<b> <i> text </i> </b>"), + 'spaceless03': ("{% spaceless %}<b><i>text</i></b>{% endspaceless %}", {}, "<b><i>text</i></b>"), + + # simple translation of a string delimited by ' + 'i18n01': ("{% load i18n %}{% trans 'xxxyyyxxx' %}", {}, "xxxyyyxxx"), + + # simple translation of a string delimited by " + 'i18n02': ('{% load i18n %}{% trans "xxxyyyxxx" %}', {}, "xxxyyyxxx"), + + # simple translation of a variable + 'i18n03': ('{% load i18n %}{% blocktrans %}{{ anton }}{% endblocktrans %}', {'anton': 'xxxyyyxxx'}, "xxxyyyxxx"), + + # simple translation of a variable and filter + 'i18n04': ('{% load i18n %}{% blocktrans with anton|lower as berta %}{{ berta }}{% endblocktrans %}', {'anton': 'XXXYYYXXX'}, "xxxyyyxxx"), + + # simple translation of a string with interpolation + 'i18n05': ('{% load i18n %}{% blocktrans %}xxx{{ anton }}xxx{% endblocktrans %}', {'anton': 'yyy'}, "xxxyyyxxx"), + + # simple translation of a string to german + 'i18n06': ('{% load i18n %}{% trans "Page not found" %}', {'LANGUAGE_CODE': 'de'}, "Seite nicht gefunden"), + + # translation of singular form + 'i18n07': ('{% load i18n %}{% blocktrans count number as counter %}singular{% plural %}plural{% endblocktrans %}', {'number': 1}, "singular"), + + # translation of plural form + 'i18n08': ('{% load i18n %}{% blocktrans count number as counter %}singular{% plural %}plural{% endblocktrans %}', {'number': 2}, "plural"), + + # simple non-translation (only marking) of a string to german + 'i18n09': ('{% load i18n %}{% trans "Page not found" noop %}', {'LANGUAGE_CODE': 'de'}, "Page not found"), + + # translation of a variable with a translated filter + 'i18n10': ('{{ bool|yesno:_("ja,nein") }}', {'bool': True}, 'ja'), + + # translation of a variable with a non-translated filter + 'i18n11': ('{{ bool|yesno:"ja,nein" }}', {'bool': True}, 'ja'), + + # usage of the get_available_languages tag + 'i18n12': ('{% load i18n %}{% get_available_languages as langs %}{% for lang in langs %}{% ifequal lang.0 "de" %}{{ lang.0 }}{% endifequal %}{% endfor %}', {}, 'de'), + + # translation of a constant string + 'i18n13': ('{{ _("Page not found") }}', {'LANGUAGE_CODE': 'de'}, 'Seite nicht gefunden'), + + ### HANDLING OF TEMPLATE_TAG_IF_INVALID ################################### + + 'invalidstr01': ('{{ var|default:"Foo" }}', {}, ('Foo','INVALID')), + 'invalidstr02': ('{{ var|default_if_none:"Foo" }}', {}, ('','INVALID')), + 'invalidstr03': ('{% for v in var %}({{ v }}){% endfor %}', {}, ''), + 'invalidstr04': ('{% if var %}Yes{% else %}No{% endif %}', {}, 'No'), + 'invalidstr04': ('{% if var|default:"Foo" %}Yes{% else %}No{% endif %}', {}, 'Yes'), + + ### MULTILINE ############################################################# + + 'multiline01': (""" + Hello, + boys. + How + are + you + gentlemen. + """, + {}, + """ + Hello, + boys. + How + are + you + gentlemen. + """), + + ### REGROUP TAG ########################################################### + 'regroup01': ('{% regroup data by bar as grouped %}' + \ + '{% for group in grouped %}' + \ + '{{ group.grouper }}:' + \ + '{% for item in group.list %}' + \ + '{{ item.foo }}' + \ + '{% endfor %},' + \ + '{% endfor %}', + {'data': [ {'foo':'c', 'bar':1}, + {'foo':'d', 'bar':1}, + {'foo':'a', 'bar':2}, + {'foo':'b', 'bar':2}, + {'foo':'x', 'bar':3} ]}, + '1:cd,2:ab,3:x,'), + + # Test for silent failure when target variable isn't found + 'regroup02': ('{% regroup data by bar as grouped %}' + \ + '{% for group in grouped %}' + \ + '{{ group.grouper }}:' + \ + '{% for item in group.list %}' + \ + '{{ item.foo }}' + \ + '{% endfor %},' + \ + '{% endfor %}', + {}, ''), + + ### TEMPLATETAG TAG ####################################################### + 'templatetag01': ('{% templatetag openblock %}', {}, '{%'), + 'templatetag02': ('{% templatetag closeblock %}', {}, '%}'), + 'templatetag03': ('{% templatetag openvariable %}', {}, '{{'), + 'templatetag04': ('{% templatetag closevariable %}', {}, '}}'), + 'templatetag05': ('{% templatetag %}', {}, template.TemplateSyntaxError), + 'templatetag06': ('{% templatetag foo %}', {}, template.TemplateSyntaxError), + 'templatetag07': ('{% templatetag openbrace %}', {}, '{'), + 'templatetag08': ('{% templatetag closebrace %}', {}, '}'), + 'templatetag09': ('{% templatetag openbrace %}{% templatetag openbrace %}', {}, '{{'), + 'templatetag10': ('{% templatetag closebrace %}{% templatetag closebrace %}', {}, '}}'), + + ### WIDTHRATIO TAG ######################################################## + 'widthratio01': ('{% widthratio a b 0 %}', {'a':50,'b':100}, '0'), + 'widthratio02': ('{% widthratio a b 100 %}', {'a':0,'b':0}, ''), + 'widthratio03': ('{% widthratio a b 100 %}', {'a':0,'b':100}, '0'), + 'widthratio04': ('{% widthratio a b 100 %}', {'a':50,'b':100}, '50'), + 'widthratio05': ('{% widthratio a b 100 %}', {'a':100,'b':100}, '100'), + + # 62.5 should round to 63 + 'widthratio06': ('{% widthratio a b 100 %}', {'a':50,'b':80}, '63'), + + # 71.4 should round to 71 + 'widthratio07': ('{% widthratio a b 100 %}', {'a':50,'b':70}, '71'), + + # Raise exception if we don't have 3 args, last one an integer + 'widthratio08': ('{% widthratio %}', {}, template.TemplateSyntaxError), + 'widthratio09': ('{% widthratio a b %}', {'a':50,'b':100}, template.TemplateSyntaxError), + 'widthratio10': ('{% widthratio a b 100.0 %}', {'a':50,'b':100}, template.TemplateSyntaxError), + + ### NOW TAG ######################################################## + # Simple case + 'now01' : ('{% now "j n Y"%}', {}, str(datetime.now().day) + ' ' + str(datetime.now().month) + ' ' + str(datetime.now().year)), + + # Check parsing of escaped and special characters + 'now02' : ('{% now "j "n" Y"%}', {}, template.TemplateSyntaxError), + # 'now03' : ('{% now "j \"n\" Y"%}', {}, str(datetime.now().day) + '"' + str(datetime.now().month) + '"' + str(datetime.now().year)), + # 'now04' : ('{% now "j \nn\n Y"%}', {}, str(datetime.now().day) + '\n' + str(datetime.now().month) + '\n' + str(datetime.now().year)) + + ### TIMESINCE TAG ################################################## + # Default compare with datetime.now() + 'timesince01' : ('{{ a|timesince }}', {'a':datetime.now() + timedelta(minutes=-1, seconds = -10)}, '1 minute'), + 'timesince02' : ('{{ a|timesince }}', {'a':(datetime.now() - timedelta(days=1, minutes = 1))}, '1 day'), + 'timesince03' : ('{{ a|timesince }}', {'a':(datetime.now() - + timedelta(hours=1, minutes=25, seconds = 10))}, '1 hour, 25 minutes'), + + # Compare to a given parameter + 'timesince04' : ('{{ a|timesince:b }}', {'a':NOW + timedelta(days=2), 'b':NOW + timedelta(days=1)}, '1 day'), + 'timesince05' : ('{{ a|timesince:b }}', {'a':NOW + timedelta(days=2, minutes=1), 'b':NOW + timedelta(days=2)}, '1 minute'), + + # Check that timezone is respected + 'timesince06' : ('{{ a|timesince:b }}', {'a':NOW_tz + timedelta(hours=8), 'b':NOW_tz}, '8 hours'), + + ### TIMEUNTIL TAG ################################################## + # Default compare with datetime.now() + 'timeuntil01' : ('{{ a|timeuntil }}', {'a':datetime.now() + timedelta(minutes=2, seconds = 10)}, '2 minutes'), + 'timeuntil02' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(days=1, seconds = 10))}, '1 day'), + 'timeuntil03' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(hours=8, minutes=10, seconds = 10))}, '8 hours, 10 minutes'), + + # Compare to a given parameter + 'timeuntil04' : ('{{ a|timeuntil:b }}', {'a':NOW - timedelta(days=1), 'b':NOW - timedelta(days=2)}, '1 day'), + 'timeuntil05' : ('{{ a|timeuntil:b }}', {'a':NOW - timedelta(days=2), 'b':NOW - timedelta(days=2, minutes=1)}, '1 minute'), + } + + # Register our custom template loader. + def test_template_loader(template_name, template_dirs=None): + "A custom template loader that loads the unit-test templates." + try: + return (TEMPLATE_TESTS[template_name][0] , "test:%s" % template_name) + except KeyError: + raise template.TemplateDoesNotExist, template_name + + old_template_loaders = loader.template_source_loaders + loader.template_source_loaders = [test_template_loader] + + failures = [] + tests = TEMPLATE_TESTS.items() + tests.sort() + + # Turn TEMPLATE_DEBUG off, because tests assume that. + old_td, settings.TEMPLATE_DEBUG = settings.TEMPLATE_DEBUG, False + + # Set TEMPLATE_STRING_IF_INVALID to a known string + old_invalid = settings.TEMPLATE_STRING_IF_INVALID + + for name, vals in tests: + install() + + if isinstance(vals[2], tuple): + normal_string_result = vals[2][0] + invalid_string_result = vals[2][1] + else: + normal_string_result = vals[2] + invalid_string_result = vals[2] + + if 'LANGUAGE_CODE' in vals[1]: + activate(vals[1]['LANGUAGE_CODE']) + else: + activate('en-us') + + for invalid_str, result in [('', normal_string_result), + ('INVALID', invalid_string_result)]: + settings.TEMPLATE_STRING_IF_INVALID = invalid_str + try: + output = loader.get_template(name).render(template.Context(vals[1])) + except Exception, e: + if e.__class__ != result: + failures.append("Template test (TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Got %s, exception: %s" % (invalid_str, name, e.__class__, e)) + continue + if output != result: + failures.append("Template test (TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Expected %r, got %r" % (invalid_str, name, result, output)) + + if 'LANGUAGE_CODE' in vals[1]: + deactivate() + + loader.template_source_loaders = old_template_loaders + deactivate() + settings.TEMPLATE_DEBUG = old_td + settings.TEMPLATE_STRING_IF_INVALID = old_invalid + + self.assertEqual(failures, [], '\n'.join(failures)) + +if __name__ == "__main__": + unittest.main() diff --git a/tests/regressiontests/urlpatterns_reverse/__init__.py b/tests/regressiontests/urlpatterns_reverse/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/urlpatterns_reverse/__init__.py diff --git a/tests/regressiontests/urlpatterns_reverse/models.py b/tests/regressiontests/urlpatterns_reverse/models.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/urlpatterns_reverse/models.py diff --git a/tests/regressiontests/urlpatterns_reverse/tests.py b/tests/regressiontests/urlpatterns_reverse/tests.py new file mode 100644 index 0000000000..8f571ac66c --- /dev/null +++ b/tests/regressiontests/urlpatterns_reverse/tests.py @@ -0,0 +1,39 @@ +"Unit tests for reverse URL lookup" + +from django.core.urlresolvers import reverse_helper, NoReverseMatch +import re, unittest + +test_data = ( + ('^places/(\d+)/$', 'places/3/', [3], {}), + ('^places/(\d+)/$', 'places/3/', ['3'], {}), + ('^places/(\d+)/$', NoReverseMatch, ['a'], {}), + ('^places/(\d+)/$', NoReverseMatch, [], {}), + ('^places/(?P<id>\d+)/$', 'places/3/', [], {'id': 3}), + ('^people/(?P<name>\w+)/$', 'people/adrian/', ['adrian'], {}), + ('^people/(?P<name>\w+)/$', 'people/adrian/', [], {'name': 'adrian'}), + ('^people/(?P<name>\w+)/$', NoReverseMatch, ['name with spaces'], {}), + ('^people/(?P<name>\w+)/$', NoReverseMatch, [], {'name': 'name with spaces'}), + ('^people/(?P<name>\w+)/$', NoReverseMatch, [], {}), + ('^hardcoded/$', 'hardcoded/', [], {}), + ('^hardcoded/$', 'hardcoded/', ['any arg'], {}), + ('^hardcoded/$', 'hardcoded/', [], {'kwarg': 'foo'}), + ('^people/(?P<state>\w\w)/(?P<name>\w+)/$', 'people/il/adrian/', [], {'state': 'il', 'name': 'adrian'}), + ('^people/(?P<state>\w\w)/(?P<name>\d)/$', NoReverseMatch, [], {'state': 'il', 'name': 'adrian'}), + ('^people/(?P<state>\w\w)/(?P<name>\w+)/$', NoReverseMatch, [], {'state': 'il'}), + ('^people/(?P<state>\w\w)/(?P<name>\w+)/$', NoReverseMatch, [], {'name': 'adrian'}), + ('^people/(?P<state>\w\w)/(\w+)/$', NoReverseMatch, ['il'], {'name': 'adrian'}), + ('^people/(?P<state>\w\w)/(\w+)/$', 'people/il/adrian/', ['adrian'], {'state': 'il'}), +) + +class URLPatternReverse(unittest.TestCase): + def test_urlpattern_reverse(self): + for regex, expected, args, kwargs in test_data: + try: + got = reverse_helper(re.compile(regex), *args, **kwargs) + except NoReverseMatch, e: + self.assertEqual(expected, NoReverseMatch) + else: + self.assertEquals(got, expected) + +if __name__ == "__main__": + run_tests(1) diff --git a/tests/runtests.py b/tests/runtests.py index b98a739249..359fca2bf5 100755 --- a/tests/runtests.py +++ b/tests/runtests.py @@ -1,23 +1,12 @@ #!/usr/bin/env python -import os, re, sys, time, traceback - -# doctest is included in the same package as this module, because this testing -# framework uses features only available in the Python 2.4 version of doctest, -# and Django aims to work with Python 2.3+. -import doctest +import os, sys, traceback +import unittest MODEL_TESTS_DIR_NAME = 'modeltests' -OTHER_TESTS_DIR = "othertests" REGRESSION_TESTS_DIR_NAME = 'regressiontests' TEST_DATABASE_NAME = 'django_test_db' - -error_list = [] -def log_error(model_name, title, description): - error_list.append({ - 'title': "%r module: %s" % (model_name, title), - 'description': description, - }) +TEST_TEMPLATE_DIR = 'templates' MODEL_TEST_DIR = os.path.join(os.path.dirname(__file__), MODEL_TESTS_DIR_NAME) REGRESSION_TEST_DIR = os.path.join(os.path.dirname(__file__), REGRESSION_TESTS_DIR_NAME) @@ -37,258 +26,113 @@ def get_test_models(): models = [] for loc, dirpath in (MODEL_TESTS_DIR_NAME, MODEL_TEST_DIR), (REGRESSION_TESTS_DIR_NAME, REGRESSION_TEST_DIR): for f in os.listdir(dirpath): - if f.startswith('__init__') or f.startswith('.') or f.startswith('sql'): + if f.startswith('__init__') or f.startswith('.') or f.startswith('sql') or f.startswith('invalid'): continue models.append((loc, f)) return models -class DjangoDoctestRunner(doctest.DocTestRunner): - def __init__(self, verbosity_level, *args, **kwargs): - self.verbosity_level = verbosity_level - doctest.DocTestRunner.__init__(self, *args, **kwargs) - self._checker = DjangoDoctestOutputChecker() - self.optionflags = doctest.ELLIPSIS - - def report_start(self, out, test, example): - if self.verbosity_level > 1: - out(" >>> %s\n" % example.source.strip()) - - def report_failure(self, out, test, example, got): - log_error(test.name, "API test failed", - "Code: %r\nLine: %s\nExpected: %r\nGot: %r" % (example.source.strip(), example.lineno, example.want, got)) - - def report_unexpected_exception(self, out, test, example, exc_info): - from django.db import transaction - tb = ''.join(traceback.format_exception(*exc_info)[1:]) - log_error(test.name, "API test raised an exception", - "Code: %r\nLine: %s\nException: %s" % (example.source.strip(), example.lineno, tb)) - # Rollback, in case of database errors. Otherwise they'd have - # side effects on other tests. - transaction.rollback_unless_managed() - -normalize_long_ints = lambda s: re.sub(r'(?<![\w])(\d+)L(?![\w])', '\\1', s) - -class DjangoDoctestOutputChecker(doctest.OutputChecker): - def check_output(self, want, got, optionflags): - ok = doctest.OutputChecker.check_output(self, want, got, optionflags) - - # Doctest does an exact string comparison of output, which means long - # integers aren't equal to normal integers ("22L" vs. "22"). The - # following code normalizes long integers so that they equal normal - # integers. - if not ok: - return normalize_long_ints(want) == normalize_long_ints(got) - return ok - -class TestRunner: - def __init__(self, verbosity_level=0, which_tests=None): - self.verbosity_level = verbosity_level - self.which_tests = which_tests - - def output(self, required_level, message): - if self.verbosity_level > required_level - 1: - print message - - def run_tests(self): - from django.conf import settings - - # An empty access of the settings to force the default options to be - # installed prior to assigning to them. - settings.INSTALLED_APPS - - # Manually set INSTALLED_APPS to point to the test models. - settings.INSTALLED_APPS = ALWAYS_INSTALLED_APPS + ['.'.join(a) for a in get_test_models()] - - # Manually set DEBUG and USE_I18N. - settings.DEBUG = False - settings.USE_I18N = True - - from django.db import connection +def get_invalid_models(): + models = [] + for loc, dirpath in (MODEL_TESTS_DIR_NAME, MODEL_TEST_DIR), (REGRESSION_TESTS_DIR_NAME, REGRESSION_TEST_DIR): + for f in os.listdir(dirpath): + if f.startswith('__init__') or f.startswith('.') or f.startswith('sql'): + continue + if f.startswith('invalid'): + models.append((loc, f)) + return models + +class InvalidModelTestCase(unittest.TestCase): + def __init__(self, model_label): + unittest.TestCase.__init__(self) + self.model_label = model_label + + def runTest(self): from django.core import management - import django.db.models - - # Determine which models we're going to test. - test_models = get_test_models() - if 'othertests' in self.which_tests: - self.which_tests.remove('othertests') - run_othertests = True - if not self.which_tests: - test_models = [] - else: - run_othertests = not self.which_tests - - if self.which_tests: - # Only run the specified tests. - bad_models = [m for m in self.which_tests if (MODEL_TESTS_DIR_NAME, m) not in test_models and (REGRESSION_TESTS_DIR_NAME, m) not in test_models] - if bad_models: - sys.stderr.write("Models not found: %s\n" % bad_models) - sys.exit(1) - else: - all_tests = [] - for test in self.which_tests: - for loc in MODEL_TESTS_DIR_NAME, REGRESSION_TESTS_DIR_NAME: - if (loc, test) in test_models: - all_tests.append((loc, test)) - test_models = all_tests - - self.output(0, "Running tests with database %r" % settings.DATABASE_ENGINE) - - # If we're using SQLite, it's more convenient to test against an - # in-memory database. - if settings.DATABASE_ENGINE == "sqlite3": - global TEST_DATABASE_NAME - TEST_DATABASE_NAME = ":memory:" - else: - # Create the test database and connect to it. We need to autocommit - # if the database supports it because PostgreSQL doesn't allow - # CREATE/DROP DATABASE statements within transactions. - cursor = connection.cursor() - self._set_autocommit(connection) - self.output(1, "Creating test database") - try: - cursor.execute("CREATE DATABASE %s" % TEST_DATABASE_NAME) - except Exception, e: - sys.stderr.write("Got an error creating the test database: %s\n" % e) - confirm = raw_input("It appears the test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_NAME) - if confirm == 'yes': - cursor.execute("DROP DATABASE %s" % TEST_DATABASE_NAME) - cursor.execute("CREATE DATABASE %s" % TEST_DATABASE_NAME) - else: - print "Tests cancelled." - return - connection.close() - old_database_name = settings.DATABASE_NAME - settings.DATABASE_NAME = TEST_DATABASE_NAME - - # Initialize the test database. - cursor = connection.cursor() - from django.db.models.loading import load_app - # Install the core always installed apps - for app in ALWAYS_INSTALLED_APPS: - self.output(1, "Installing contrib app %s" % app) - mod = load_app(app) - management.install(mod) - - # Run the tests for each test model. - self.output(1, "Running app tests") - for model_dir, model_name in test_models: - self.output(1, "%s model: Importing" % model_name) - try: - mod = load_app(model_dir + '.' + model_name) - except Exception, e: - log_error(model_name, "Error while importing", ''.join(traceback.format_exception(*sys.exc_info())[1:])) - continue - - if not getattr(mod, 'error_log', None): - # Model is not marked as an invalid model - self.output(1, "%s.%s model: Installing" % (model_dir, model_name)) - management.install(mod) - - # Run the API tests. - p = doctest.DocTestParser() - test_namespace = dict([(m._meta.object_name, m) \ - for m in django.db.models.get_models(mod)]) - dtest = p.get_doctest(mod.API_TESTS, test_namespace, model_name, None, None) - # Manually set verbose=False, because "-v" command-line parameter - # has side effects on doctest TestRunner class. - runner = DjangoDoctestRunner(verbosity_level=verbosity_level, verbose=False) - self.output(1, "%s.%s model: Running tests" % (model_dir, model_name)) - runner.run(dtest, clear_globs=True, out=sys.stdout.write) - else: - # Check that model known to be invalid is invalid for the right reasons. - self.output(1, "%s.%s model: Validating" % (model_dir, model_name)) - - from cStringIO import StringIO - s = StringIO() - count = management.get_validation_errors(s, mod) - s.seek(0) - error_log = s.read() - actual = error_log.split('\n') - expected = mod.error_log.split('\n') - - unexpected = [err for err in actual if err not in expected] - missing = [err for err in expected if err not in actual] + from cStringIO import StringIO - if unexpected or missing: - unexpected_log = '\n'.join(unexpected) - missing_log = '\n'.join(missing) - log_error(model_name, - "Validator found %d validation errors, %d expected" % (count, len(expected) - 1), - "Missing errors:\n%s\n\nUnexpected errors:\n%s" % (missing_log, unexpected_log)) + try: + module = load_app(self.model_label) + except Exception, e: + self.fail('Unable to load invalid model module') + + s = StringIO() + count = management.get_validation_errors(s, module) + s.seek(0) + error_log = s.read() + actual = error_log.split('\n') + expected = module.model_errors.split('\n') - if run_othertests: - # Run the non-model tests in the other tests dir - self.output(1, "Running other tests") - other_tests_dir = os.path.join(os.path.dirname(__file__), OTHER_TESTS_DIR) - test_modules = [f[:-3] for f in os.listdir(other_tests_dir) if f.endswith('.py') and not f.startswith('__init__')] - for module in test_modules: - self.output(1, "%s module: Importing" % module) - try: - mod = __import__("othertests." + module, '', '', ['']) - except Exception, e: - log_error(module, "Error while importing", ''.join(traceback.format_exception(*sys.exc_info())[1:])) - continue - if mod.__doc__: - p = doctest.DocTestParser() - dtest = p.get_doctest(mod.__doc__, mod.__dict__, module, None, None) - runner = DjangoDoctestRunner(verbosity_level=verbosity_level, verbose=False) - self.output(1, "%s module: running tests" % module) - runner.run(dtest, clear_globs=True, out=sys.stdout.write) - if hasattr(mod, "run_tests") and callable(mod.run_tests): - self.output(1, "%s module: running tests" % module) - try: - mod.run_tests(verbosity_level) - except Exception, e: - log_error(module, "Exception running tests", ''.join(traceback.format_exception(*sys.exc_info())[1:])) - continue + unexpected = [err for err in actual if err not in expected] + missing = [err for err in expected if err not in actual] - # Unless we're using SQLite, remove the test database to clean up after - # ourselves. Connect to the previous database (not the test database) - # to do so, because it's not allowed to delete a database while being - # connected to it. - if settings.DATABASE_ENGINE != "sqlite3": - connection.close() - settings.DATABASE_NAME = old_database_name - cursor = connection.cursor() - self.output(1, "Deleting test database") - self._set_autocommit(connection) - time.sleep(1) # To avoid "database is being accessed by other users" errors. - cursor.execute("DROP DATABASE %s" % TEST_DATABASE_NAME) + self.assert_(not unexpected, "Unexpected Errors: " + '\n'.join(unexpected)) + self.assert_(not missing, "Missing Errors: " + '\n'.join(missing)) - # Display output. - if error_list: - for d in error_list: - print - print d['title'] - print "=" * len(d['title']) - print d['description'] - print "%s error%s:" % (len(error_list), len(error_list) != 1 and 's' or '') - else: - print "All tests passed." +def django_tests(verbosity, tests_to_run): + from django.conf import settings + from django.db.models.loading import get_apps, load_app - def _set_autocommit(self, connection): - """ - Make sure a connection is in autocommit mode. - """ - if hasattr(connection.connection, "autocommit"): - connection.connection.autocommit(True) - elif hasattr(connection.connection, "set_isolation_level"): - connection.connection.set_isolation_level(0) + old_installed_apps = settings.INSTALLED_APPS + old_test_database_name = settings.TEST_DATABASE_NAME + old_root_urlconf = settings.ROOT_URLCONF + old_template_dirs = settings.TEMPLATE_DIRS + + # Redirect some settings for the duration of these tests + settings.TEST_DATABASE_NAME = TEST_DATABASE_NAME + settings.INSTALLED_APPS = ALWAYS_INSTALLED_APPS + settings.ROOT_URLCONF = 'urls' + settings.TEMPLATE_DIRS = (os.path.join(os.path.dirname(__file__), TEST_TEMPLATE_DIR),) + + # load all the ALWAYS_INSTALLED_APPS + get_apps() + + # Load all the test model apps + test_models = [] + for model_dir, model_name in get_test_models(): + model_label = '.'.join([model_dir, model_name]) + try: + # if the model was named on the command line, or + # no models were named (i.e., run all), import + # this model and add it to the list to test. + if not tests_to_run or model_name in tests_to_run: + if verbosity >= 1: + print "Importing model %s" % model_name + mod = load_app(model_label) + settings.INSTALLED_APPS.append(model_label) + test_models.append(mod) + except Exception, e: + sys.stderr.write("Error while importing %s:" % model_name + ''.join(traceback.format_exception(*sys.exc_info())[1:])) + continue + # Add tests for invalid models + extra_tests = [] + for model_dir, model_name in get_invalid_models(): + model_label = '.'.join([model_dir, model_name]) + if not tests_to_run or model_name in tests_to_run: + extra_tests.append(InvalidModelTestCase(model_label)) + + # Run the test suite, including the extra validation tests. + from django.test.simple import run_tests + run_tests(test_models, verbosity, extra_tests=extra_tests) + + # Restore the old settings + settings.INSTALLED_APPS = old_installed_apps + settings.TESTS_DATABASE_NAME = old_test_database_name + settings.ROOT_URLCONF = old_root_urlconf + settings.TEMPLATE_DIRS = old_template_dirs + if __name__ == "__main__": from optparse import OptionParser usage = "%prog [options] [model model model ...]" parser = OptionParser(usage=usage) - parser.add_option('-v', help='How verbose should the output be? Choices are 0, 1 and 2, where 2 is most verbose. Default is 0.', - type='choice', choices=['0', '1', '2']) + parser.add_option('-v','--verbosity', action='store', dest='verbosity', default='0', + type='choice', choices=['0', '1', '2'], + help='Verbosity level; 0=minimal output, 1=normal output, 2=all output') parser.add_option('--settings', help='Python path to settings module, e.g. "myproject.settings". If this isn\'t provided, the DJANGO_SETTINGS_MODULE environment variable will be used.') options, args = parser.parse_args() - verbosity_level = 0 - if options.v: - verbosity_level = int(options.v) if options.settings: os.environ['DJANGO_SETTINGS_MODULE'] = options.settings - t = TestRunner(verbosity_level, args) - t.run_tests() + + django_tests(int(options.verbosity), args) diff --git a/tests/templates/404.html b/tests/templates/404.html new file mode 100644 index 0000000000..da627e2222 --- /dev/null +++ b/tests/templates/404.html @@ -0,0 +1 @@ +Django Internal Tests: 404 Error
\ No newline at end of file diff --git a/tests/templates/500.html b/tests/templates/500.html new file mode 100644 index 0000000000..ff028cbeb0 --- /dev/null +++ b/tests/templates/500.html @@ -0,0 +1 @@ +Django Internal Tests: 500 Error
\ No newline at end of file diff --git a/tests/templates/login.html b/tests/templates/login.html new file mode 100644 index 0000000000..8a0974c9a1 --- /dev/null +++ b/tests/templates/login.html @@ -0,0 +1,19 @@ +<html> +<head></head> +<body> +<h1>Django Internal Tests: Login</h1> +{% if form.has_errors %} +<p>Your username and password didn't match. Please try again.</p> +{% endif %} + +<form method="post" action="."> +<table> +<tr><td><label for="id_username">Username:</label></td><td>{{ form.username }}</td></tr> +<tr><td><label for="id_password">Password:</label></td><td>{{ form.password }}</td></tr> +</table> + +<input type="submit" value="login" /> +<input type="hidden" name="next" value="{{ next }}" /> +</form> +</body> +</html>
\ No newline at end of file diff --git a/tests/urls.py b/tests/urls.py new file mode 100644 index 0000000000..39d5aaee6b --- /dev/null +++ b/tests/urls.py @@ -0,0 +1,10 @@ +from django.conf.urls.defaults import * + +urlpatterns = patterns('', + # test_client modeltest urls + (r'^test_client/', include('modeltests.test_client.urls')), + + # Always provide the auth system login and logout views + (r'^accounts/login/$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}), + (r'^accounts/logout/$', 'django.contrib.auth.views.login'), +) |
