summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorg Bauer <gb@hugo.westfalen.de>2005-11-03 11:25:18 +0000
committerGeorg Bauer <gb@hugo.westfalen.de>2005-11-03 11:25:18 +0000
commitb60d7ff98582798723fe64da12089d93e92bab85 (patch)
tree1ca1cb2a5b7fd7ac51d6199543b1e41ab06f8e16
parentdf1e0ef61bbf95a86ea1a1dfedccd7b5517cf6f7 (diff)
i18n: implemented the proposed syntax change to {% trans %} and {% blocktrans %}
git-svn-id: http://code.djangoproject.com/svn/django/branches/i18n@1061 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rwxr-xr-xdjango/bin/make-messages.py25
-rw-r--r--django/conf/locale/de/LC_MESSAGES/django.mobin17758 -> 17824 bytes
-rw-r--r--django/conf/locale/de/LC_MESSAGES/django.po172
-rw-r--r--django/contrib/admin/templates/admin/404.html7
-rw-r--r--django/contrib/admin/templates/admin/500.html9
-rw-r--r--django/contrib/admin/templates/admin/base.html5
-rw-r--r--django/contrib/admin/templates/admin/base_site.html5
-rw-r--r--django/contrib/admin/templates/admin/delete_confirmation.html7
-rw-r--r--django/contrib/admin/templates/admin/index.html13
-rw-r--r--django/contrib/admin/templates/admin/login.html9
-rw-r--r--django/contrib/admin/templates/admin/object_history.html11
-rw-r--r--django/contrib/admin/templates/registration/logged_out.html7
-rw-r--r--django/contrib/admin/templates/registration/password_change_done.html9
-rw-r--r--django/contrib/admin/templates/registration/password_change_form.html17
-rw-r--r--django/contrib/admin/templates/registration/password_reset_done.html9
-rw-r--r--django/contrib/admin/templates/registration/password_reset_email.html15
-rw-r--r--django/contrib/admin/templates/registration/password_reset_form.html11
-rw-r--r--django/core/template/__init__.py113
-rw-r--r--django/templatetags/i18n.py210
-rw-r--r--django/utils/translation.py88
20 files changed, 558 insertions, 184 deletions
diff --git a/django/bin/make-messages.py b/django/bin/make-messages.py
index d8c5299e62..c78faac694 100755
--- a/django/bin/make-messages.py
+++ b/django/bin/make-messages.py
@@ -5,6 +5,8 @@ import os
import sys
import getopt
+from django.utils.translation import templateize
+
localedir = None
if os.path.isdir(os.path.join('conf', 'locale')):
@@ -44,29 +46,6 @@ if lang is not None:
elif all:
languages = [el for el in os.listdir(localedir) if not el.startswith('.')]
-dot_re = re.compile('\S')
-def blank(src):
- return dot_re.sub('p', src)
-
-def templateize(src):
- o = []
- going = 1
- while going:
- start = src.find('{')
- if start >= 0 and src[start+1] in ('{', '%'):
- o.append(blank(src[:start]))
- end = src.find(src[start+1] == '{' and '}}' or '%}', start)
- if end >= 0:
- o.append(src[start:end+2])
- src = src[end+2:]
- else:
- o.append(blank(src[start:]))
- going = 0
- else:
- o.append(blank(src))
- going = 0
- return ''.join(o)
-
for lang in languages:
print "processing language", lang
diff --git a/django/conf/locale/de/LC_MESSAGES/django.mo b/django/conf/locale/de/LC_MESSAGES/django.mo
index d9f0aea348..c8b9157d0c 100644
--- a/django/conf/locale/de/LC_MESSAGES/django.mo
+++ b/django/conf/locale/de/LC_MESSAGES/django.mo
Binary files differ
diff --git a/django/conf/locale/de/LC_MESSAGES/django.po b/django/conf/locale/de/LC_MESSAGES/django.po
index 19b8b726fb..e2481e89ce 100644
--- a/django/conf/locale/de/LC_MESSAGES/django.po
+++ b/django/conf/locale/de/LC_MESSAGES/django.po
@@ -7,44 +7,45 @@ msgid ""
msgstr ""
"Project-Id-Version: Django 1.0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2005-10-24 00:03+0200\n"
+"POT-Creation-Date: 2005-11-03 12:21+0100\n"
"PO-Revision-Date: 2005-10-08 00:03+0200\n"
"Last-Translator: Georg Bauer <gb@bofh.ms>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=iso-8859-1\n"
"Content-Transfer-Encoding: 8bit\n"
-#: contrib/admin/templates/admin/object_history.html:4
-#: contrib/admin/templates/admin/base.html:28
-#: contrib/admin/templates/registration/password_change_done.html:3
-#: contrib/admin/templates/registration/password_reset_form.html:3
-#: contrib/admin/templates/registration/logged_out.html:3
-#: contrib/admin/templates/registration/password_reset_done.html:3
-#: contrib/admin/templates/registration/password_change_form.html:3
+#: contrib/admin/templates/admin/object_history.html:5
+#: contrib/admin/templates/admin/500.html:4
+#: contrib/admin/templates/admin/base.html:29
+#: 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
msgid "Home"
msgstr "Start"
-#: contrib/admin/templates/admin/object_history.html:4
+#: contrib/admin/templates/admin/object_history.html:5
msgid "History"
msgstr "Geschichte"
-#: contrib/admin/templates/admin/object_history.html:17
+#: contrib/admin/templates/admin/object_history.html:18
msgid "Date/time"
msgstr "Datum/Zeit"
-#: contrib/admin/templates/admin/object_history.html:18 models/auth.py:47
+#: contrib/admin/templates/admin/object_history.html:19 models/auth.py:47
msgid "User"
msgstr "Benutzer"
-#: contrib/admin/templates/admin/object_history.html:19
+#: contrib/admin/templates/admin/object_history.html:20
msgid "Action"
msgstr "Aktion"
-#: contrib/admin/templates/admin/object_history.html:25
+#: contrib/admin/templates/admin/object_history.html:26
msgid "DATE_WITH_TIME_FULL"
msgstr "j. N Y, H:i"
-#: contrib/admin/templates/admin/object_history.html:35
+#: 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."
@@ -52,23 +53,27 @@ msgstr ""
"Dieses Objekt hat keine Änderungsgeschichte. Es wurde möglicherweise nicht "
"über diese Verwaltungsseiten angelegt."
-#: contrib/admin/templates/admin/base_site.html:3
+#: contrib/admin/templates/admin/base_site.html:4
msgid "Django site admin"
msgstr "Django Systemverwaltung"
-#: contrib/admin/templates/admin/base_site.html:6
+#: contrib/admin/templates/admin/base_site.html:7
msgid "Django administration"
msgstr "Django Verwaltung"
-#: contrib/admin/templates/admin/500.html:5
+#: contrib/admin/templates/admin/500.html:4
+msgid "Server error"
+msgstr "Serverfehler"
+
+#: contrib/admin/templates/admin/500.html:6
msgid "Server error (500)"
msgstr "Serverfehler (500)"
-#: contrib/admin/templates/admin/500.html:8
+#: contrib/admin/templates/admin/500.html:9
msgid "Server Error <em>(500)</em>"
msgstr "Serverfehler <em>(500)</em>"
-#: contrib/admin/templates/admin/500.html:9
+#: 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."
@@ -77,72 +82,72 @@ msgstr ""
"eMail weitergegeben und sollte bald behoben sein. Vielen Dank für Ihr "
"Verständnis."
-#: contrib/admin/templates/admin/404.html:3
-#: contrib/admin/templates/admin/404.html:7
+#: contrib/admin/templates/admin/404.html:4
+#: contrib/admin/templates/admin/404.html:8
msgid "Page not found"
msgstr "Seite nicht gefunden"
-#: contrib/admin/templates/admin/404.html:9
+#: contrib/admin/templates/admin/404.html:10
msgid "We're sorry, but the requested page could not be found."
msgstr ""
"Es tut uns leid, aber die angeforderte Seite kann nicht gefunden werden."
-#: contrib/admin/templates/admin/index.html:26
+#: contrib/admin/templates/admin/index.html:27
msgid "Add"
msgstr "Zufügen"
-#: contrib/admin/templates/admin/index.html:32
+#: contrib/admin/templates/admin/index.html:33
msgid "Change"
msgstr "Ändern"
-#: contrib/admin/templates/admin/index.html:42
+#: contrib/admin/templates/admin/index.html:43
msgid "You don't have permission to edit anything."
msgstr "Sie haben keine Berechtigung irgendwas zu ändern."
-#: contrib/admin/templates/admin/index.html:50
+#: contrib/admin/templates/admin/index.html:51
msgid "Recent Actions"
msgstr "Kürzliche Aktionen"
-#: contrib/admin/templates/admin/index.html:51
+#: contrib/admin/templates/admin/index.html:52
msgid "My Actions"
msgstr "Meine Aktionen"
-#: contrib/admin/templates/admin/index.html:55
+#: contrib/admin/templates/admin/index.html:56
msgid "None available"
msgstr "Keine vorhanden"
-#: contrib/admin/templates/admin/login.html:14
+#: contrib/admin/templates/admin/login.html:15
msgid "Username:"
msgstr "Benutzername:"
-#: contrib/admin/templates/admin/login.html:17
+#: contrib/admin/templates/admin/login.html:18
msgid "Password:"
msgstr "Passwort:"
-#: contrib/admin/templates/admin/login.html:19
+#: contrib/admin/templates/admin/login.html:20
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/login.html:23
+#: contrib/admin/templates/admin/login.html:24
msgid "Log in"
msgstr "Anmelden"
-#: contrib/admin/templates/admin/base.html:22
+#: contrib/admin/templates/admin/base.html:23
msgid "Welcome,"
msgstr "Willkommen,"
-#: contrib/admin/templates/admin/base.html:22
+#: contrib/admin/templates/admin/base.html:23
msgid "Change password"
msgstr "Passwort ändern"
-#: contrib/admin/templates/admin/base.html:22
+#: contrib/admin/templates/admin/base.html:23
msgid "Log out"
msgstr "Abmelden"
-#: contrib/admin/templates/admin/delete_confirmation.html:6
+#: contrib/admin/templates/admin/delete_confirmation.html:7
#, python-format
msgid ""
-"Deleting the %(object_name)s '%(object)s' would result in deleting related "
+"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 ""
@@ -150,7 +155,7 @@ msgstr ""
"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:13
+#: contrib/admin/templates/admin/delete_confirmation.html:14
#, python-format
msgid ""
"Are you sure you want to delete the %(object_name)s \"%(object)s\"? All of "
@@ -159,34 +164,33 @@ 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:"
-#: contrib/admin/templates/admin/delete_confirmation.html:17
+#: contrib/admin/templates/admin/delete_confirmation.html:18
msgid "Yes, I'm sure"
msgstr "Ja, ich bin sicher"
-#: contrib/admin/templates/registration/password_change_done.html:3
-#: contrib/admin/templates/registration/password_change_form.html:3
-#: contrib/admin/templates/registration/password_change_form.html:5
-#: contrib/admin/templates/registration/password_change_form.html:9
+#: 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 "Kennwort ändern"
-#: contrib/admin/templates/registration/password_change_done.html:5
-#: contrib/admin/templates/registration/password_change_done.html:9
+#: contrib/admin/templates/registration/password_change_done.html:6
+#: contrib/admin/templates/registration/password_change_done.html:10
msgid "Password change successful"
msgstr "Erfolgreiche Kennwortänderung"
-#: contrib/admin/templates/registration/password_change_done.html:11
+#: contrib/admin/templates/registration/password_change_done.html:12
msgid "Your password was changed."
msgstr "Ihr Kennwort wurde geändert."
-#: contrib/admin/templates/registration/password_reset_form.html:3
-#: contrib/admin/templates/registration/password_reset_form.html:5
-#: contrib/admin/templates/registration/password_reset_form.html:9
-#: contrib/admin/templates/registration/password_reset_done.html:3
+#: contrib/admin/templates/registration/password_reset_form.html:4
+#: contrib/admin/templates/registration/password_reset_form.html:6
+#: contrib/admin/templates/registration/password_reset_done.html:4
msgid "Password reset"
msgstr "Kennwort zurücksetzen"
-#: contrib/admin/templates/registration/password_reset_form.html:11
+#: 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."
@@ -195,28 +199,28 @@ msgstr ""
"wir setzen das Kennwort auf einen neuen Wert und schicken den per eMail an "
"Sie raus."
-#: contrib/admin/templates/registration/password_reset_form.html:15
+#: contrib/admin/templates/registration/password_reset_form.html:16
msgid "E-mail address:"
msgstr "eMail-Adresse:"
-#: contrib/admin/templates/registration/password_reset_form.html:15
+#: contrib/admin/templates/registration/password_reset_form.html:16
msgid "Reset my password"
msgstr "Mein Kennwort zurücksetzen"
-#: contrib/admin/templates/registration/logged_out.html:7
+#: contrib/admin/templates/registration/logged_out.html:8
msgid "Thanks for spending some quality time with the Web site today."
msgstr "Danke, dass Sie eine Weile bei uns waren."
-#: contrib/admin/templates/registration/logged_out.html:9
+#: contrib/admin/templates/registration/logged_out.html:10
msgid "Log in again"
msgstr "Neu anmelden"
-#: contrib/admin/templates/registration/password_reset_done.html:5
-#: contrib/admin/templates/registration/password_reset_done.html:9
+#: contrib/admin/templates/registration/password_reset_done.html:6
+#: contrib/admin/templates/registration/password_reset_done.html:10
msgid "Password reset successful"
msgstr "Erfolgreich Kennwort zurückgesetzt"
-#: contrib/admin/templates/registration/password_reset_done.html:11
+#: 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."
@@ -224,7 +228,7 @@ msgstr ""
"Wir haben Ihnen ein neues Kennwort per eMail zugeschickt an die Adresse, die "
"Sie uns gegeben haben. Es sollte in Kürze ankommen."
-#: contrib/admin/templates/registration/password_change_form.html:11
+#: 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."
@@ -233,49 +237,49 @@ msgstr ""
"dann zweimal (um sicherzustellen, das Sie es korrekt eingegeben haben) das "
"neue Kennwort ein."
-#: contrib/admin/templates/registration/password_change_form.html:16
+#: contrib/admin/templates/registration/password_change_form.html:17
msgid "Old password:"
msgstr "altes Kennwort:"
-#: contrib/admin/templates/registration/password_change_form.html:18
+#: contrib/admin/templates/registration/password_change_form.html:19
msgid "New password:"
msgstr "neues Kennwort:"
-#: contrib/admin/templates/registration/password_change_form.html:20
+#: contrib/admin/templates/registration/password_change_form.html:21
msgid "Confirm password:"
msgstr "Kennwortwiederholung:"
-#: contrib/admin/templates/registration/password_change_form.html:22
+#: contrib/admin/templates/registration/password_change_form.html:23
msgid "Change my password"
msgstr "Mein Kennwort ändern"
-#: contrib/admin/templates/registration/password_reset_email.html:1
+#: contrib/admin/templates/registration/password_reset_email.html:2
msgid "You're receiving this e-mail because you requested a password reset"
msgstr "Sie erhalten diese Mail, weil Sie ein neues Kennwort"
-#: contrib/admin/templates/registration/password_reset_email.html:2
+#: contrib/admin/templates/registration/password_reset_email.html:3
#, python-format
msgid "for your user account at %(site_name)s"
msgstr "für ihren Benutzer bei %(site_name)s angefordert haben."
-#: contrib/admin/templates/registration/password_reset_email.html:4
+#: contrib/admin/templates/registration/password_reset_email.html:5
#, python-format
msgid "Your new password is: %(new_password)s"
msgstr "Ihr neues Kennwort ist: %(new_password)s"
-#: contrib/admin/templates/registration/password_reset_email.html:6
+#: contrib/admin/templates/registration/password_reset_email.html:7
msgid "Feel free to change this password by going to this page:"
msgstr "Sie können das Kennwort auf folgender Seite ändern:"
-#: contrib/admin/templates/registration/password_reset_email.html:10
+#: contrib/admin/templates/registration/password_reset_email.html:11
msgid "Your username, in case you've forgotten:"
msgstr "Ihr Benutzername, falls Sie ihn vergessen haben:"
-#: contrib/admin/templates/registration/password_reset_email.html:12
+#: contrib/admin/templates/registration/password_reset_email.html:13
msgid "Thanks for using our site!"
msgstr "Vielen Dank, das Sie unsere Seiten benutzen!"
-#: contrib/admin/templates/registration/password_reset_email.html:14
+#: contrib/admin/templates/registration/password_reset_email.html:15
#, python-format
msgid "The %(site_name)s team"
msgstr "Das Team von %(site_name)s"
@@ -653,44 +657,48 @@ msgid "Message"
msgstr "Mitteilung"
#: conf/global_settings.py:37
+msgid "Czech"
+msgstr "Tschechisch"
+
+#: conf/global_settings.py:38
msgid "German"
msgstr "Deutsch"
-#: conf/global_settings.py:38
+#: conf/global_settings.py:39
msgid "English"
msgstr "Englisch"
-#: conf/global_settings.py:39
+#: conf/global_settings.py:40
msgid "Spanish"
msgstr "Spanisch"
-#: conf/global_settings.py:40
+#: conf/global_settings.py:41
msgid "French"
msgstr "Französisch"
-#: conf/global_settings.py:41
+#: conf/global_settings.py:42
msgid "Galician"
msgstr "Galicisch"
-#: conf/global_settings.py:42
+#: conf/global_settings.py:43
msgid "Italian"
msgstr "Italienisch"
-#: conf/global_settings.py:43
+#: conf/global_settings.py:44
msgid "Brazilian"
msgstr "Brasilianisch"
-#: conf/global_settings.py:44
+#: conf/global_settings.py:45
msgid "Russian"
msgstr "Russisch"
-#: conf/global_settings.py:45
-msgid "Serbic"
+#: conf/global_settings.py:46
+msgid "Serbian"
msgstr "Serbisch"
-#: conf/global_settings.py:46
-msgid "Czech"
-msgstr "Tschechisch"
+#: conf/global_settings.py:47
+msgid "Traditional Chinese"
+msgstr ""
#: core/validators.py:58
msgid "This value must contain only letters, numbers and underscores."
diff --git a/django/contrib/admin/templates/admin/404.html b/django/contrib/admin/templates/admin/404.html
index 031d9d9877..d791f565ba 100644
--- a/django/contrib/admin/templates/admin/404.html
+++ b/django/contrib/admin/templates/admin/404.html
@@ -1,11 +1,12 @@
{% extends "admin/base_site" %}
+{% load i18n %}
-{% block title %}{{ _('Page not found') }}{% endblock %}
+{% block title %}{% trans 'Page not found' %}{% endblock %}
{% block content %}
-<h2>{{ _('Page not found') }}</h2>
+<h2>{% trans 'Page not found' %}</h2>
-<p>{{ _("We're sorry, but the requested page could not be found.") }}</p>
+<p>{% trans "We're sorry, but the requested page could not be found." %}</p>
{% endblock %}
diff --git a/django/contrib/admin/templates/admin/500.html b/django/contrib/admin/templates/admin/500.html
index 75856d407e..9d3e3de32c 100644
--- a/django/contrib/admin/templates/admin/500.html
+++ b/django/contrib/admin/templates/admin/500.html
@@ -1,11 +1,12 @@
{% extends "admin/base_site" %}
+{% load i18n %}
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="/">Home</a> &rsaquo; Server error</div>{% endblock %}
+{% block breadcrumbs %}<div class="breadcrumbs"><a href="/">{% trans "Home" %}</a> &rsaquo; {% trans "Server error" %}</div>{% endblock %}
-{% block title %}{{ _('Server error (500)') }}{% endblock %}
+{% block title %}{% trans 'Server error (500)' %}{% endblock %}
{% block content %}
-<h1>{{ _('Server Error <em>(500)</em>') }}</h1>
-<p>{{ _("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.") }}</p>
+<h1>{% trans 'Server Error <em>(500)</em>' %}</h1>
+<p>{% trans "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." %}</p>
{% endblock %}
diff --git a/django/contrib/admin/templates/admin/base.html b/django/contrib/admin/templates/admin/base.html
index a007a9c788..0c0ae4aabd 100644
--- a/django/contrib/admin/templates/admin/base.html
+++ b/django/contrib/admin/templates/admin/base.html
@@ -6,6 +6,7 @@
{% block extrastyle %}{% endblock %}
{% block extrahead %}{% endblock %}
</head>
+{% load i18n %}
<body class="{% if is_popup %}popup {% endif %}{% block bodyclass %}{% endblock %}">
@@ -19,13 +20,13 @@
{% block branding %}{% endblock %}
</div>
{% if not user.is_anonymous %}
- <div id="user-tools">{{ _('Welcome,') }} <strong>{% if user.first_name %}{{ user.first_name }}{% else %}{{ user.username }}{% endif %}</strong>. <br />{% block userlinks %}<a href="/admin/password_change/">{{ _('Change password') }}</a> / <a href="/admin/logout/">{{ _('Log out') }}</a>{% endblock %}</div>
+ <div id="user-tools">{% trans 'Welcome,' %} <strong>{% if user.first_name %}{{ user.first_name }}{% else %}{{ user.username }}{% endif %}</strong>. <br />{% block userlinks %}<a href="/admin/password_change/">{% trans 'Change password' %}</a> / <a href="/admin/logout/">{% trans 'Log out' %}</a>{% endblock %}</div>
{% endif %}
{% block nav-global %}{% endblock %}
<br class="clear" />
</div>
<!-- END Header -->
- {% block breadcrumbs %}<div class="breadcrumbs"><a href="/">{{ _('Home') }}</a>{% if title %} &rsaquo; {{ title }}{% endif %}</div>{% endblock %}
+ {% block breadcrumbs %}<div class="breadcrumbs"><a href="/">{% trans 'Home' %}</a>{% if title %} &rsaquo; {{ title }}{% endif %}</div>{% endblock %}
{% endif %}
{% if messages %}
diff --git a/django/contrib/admin/templates/admin/base_site.html b/django/contrib/admin/templates/admin/base_site.html
index 6494951be3..cb2ea43254 100644
--- a/django/contrib/admin/templates/admin/base_site.html
+++ b/django/contrib/admin/templates/admin/base_site.html
@@ -1,9 +1,10 @@
{% extends "admin/base" %}
+{% load i18n %}
-{% block title %}{{ title }} | {{ _('Django site admin') }}{% endblock %}
+{% block title %}{{ title }} | {% trans 'Django site admin' %}{% endblock %}
{% block branding %}
-<h1 id="site-name">{{ _('Django administration') }}</h1>
+<h1 id="site-name">{% trans 'Django administration' %}</h1>
<h2 id="site-url"><a href="http://www.example.com/">example.com</a></h2>
{% endblock %}
diff --git a/django/contrib/admin/templates/admin/delete_confirmation.html b/django/contrib/admin/templates/admin/delete_confirmation.html
index 4881e0825e..0bff003980 100644
--- a/django/contrib/admin/templates/admin/delete_confirmation.html
+++ b/django/contrib/admin/templates/admin/delete_confirmation.html
@@ -1,20 +1,21 @@
{% extends "admin/base_site" %}
+{% load i18n %}
{% block content %}
{% if perms_lacking %}
- <p>{{ _("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:") }}</p>
+ <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>
<ul>
{% for obj in perms_lacking %}
<li>{{ obj }}</li>
{% endfor %}
</ul>
{% else %}
- <p>{{ _('Are you sure you want to delete the %(object_name)s "%(object)s"? All of the following related items will be deleted:') }}</p>
+ <p>{% blocktrans %}Are you sure you want to delete the {{ object_name }} "{{ object }}"? All of the following related items will be deleted:{% endblocktrans %}</p>
<ul>{{ deleted_objects|unordered_list }}</ul>
<form action="" method="post">
<input type="hidden" name="post" value="yes" />
- <input type="submit" value="{{ _("Yes, I'm sure") }}" />
+ <input type="submit" value="{% trans "Yes, I'm sure" %}" />
</form>
{% endif %}
diff --git a/django/contrib/admin/templates/admin/index.html b/django/contrib/admin/templates/admin/index.html
index 0620caa7bc..9822ed92c2 100644
--- a/django/contrib/admin/templates/admin/index.html
+++ b/django/contrib/admin/templates/admin/index.html
@@ -1,4 +1,5 @@
{% extends "admin/base_site" %}
+{% load i18n %}
{% block coltype %}colMS{% endblock %}
{% block bodyclass %}dashboard{% endblock %}
@@ -23,13 +24,13 @@
{% endif %}
{% if model.perms.add %}
- <td class="x50"><a href="{{ model.admin_url }}add/" class="addlink">{{ _('Add') }}</a></td>
+ <td class="x50"><a href="{{ model.admin_url }}add/" class="addlink">{% trans 'Add' %}</a></td>
{% else %}
<td class="x50">&nbsp;</td>
{% endif %}
{% if model.perms.change %}
- <td class="x75"><a href="{{ model.admin_url }}" class="changelink">{{ _('Change') }}</a></td>
+ <td class="x75"><a href="{{ model.admin_url }}" class="changelink">{% trans 'Change' %}</a></td>
{% else %}
<td class="x75">&nbsp;</td>
{% endif %}
@@ -39,7 +40,7 @@
</div>
{% endfor %}
{% else %}
- <p>{{ _("You don't have permission to edit anything.") }}</p>
+ <p>{% trans "You don't have permission to edit anything." %}</p>
{% endif %}
</div>
{% endblock %}
@@ -47,12 +48,12 @@
{% block sidebar %}
<div id="content-related">
<div class="module" id="recent-actions-module">
- <h2>{{ _('Recent Actions') }}</h2>
- <h3>{{ _('My Actions') }}</h3>
+ <h2>{% trans 'Recent Actions' %}</h2>
+ <h3>{% trans 'My Actions' %}</h3>
{% load log %}
{% get_admin_log 10 as admin_log for_user user %}
{% if not admin_log %}
- <p>{{ _('None available') }}</p>
+ <p>{% trans 'None available' %}</p>
{% else %}
<ul class="actionlist">
{% for entry in admin_log %}
diff --git a/django/contrib/admin/templates/admin/login.html b/django/contrib/admin/templates/admin/login.html
index 72891e797d..ea823e1020 100644
--- a/django/contrib/admin/templates/admin/login.html
+++ b/django/contrib/admin/templates/admin/login.html
@@ -1,4 +1,5 @@
{% extends "admin/base_site" %}
+{% load i18n %}
{% block breadcrumbs %}{% endblock %}
@@ -11,16 +12,16 @@
<form action="{{ app_path }}" method="post">
<p class="aligned">
-<label for="id_username">{{ _('Username:') }}</label> <input type="text" name="username" id="id_username" />
+<label for="id_username">{% trans 'Username:' %}</label> <input type="text" name="username" id="id_username" />
</p>
<p class="aligned">
-<label for="id_password">{{ _('Password:') }}</label> <input type="password" name="password" id="id_password" />
+<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">{{ _('Have you <a href="/password_reset/">forgotten your password</a>?') }}</span>{% endcomment %}
+<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 %}
</p>
<div class="aligned ">
-<label>&nbsp;</label><input type="submit" value="{{ _('Log in') }}" />
+<label>&nbsp;</label><input type="submit" value="{% trans 'Log in' %}" />
</div>
</form>
diff --git a/django/contrib/admin/templates/admin/object_history.html b/django/contrib/admin/templates/admin/object_history.html
index 5c1114307a..847cfdf2af 100644
--- a/django/contrib/admin/templates/admin/object_history.html
+++ b/django/contrib/admin/templates/admin/object_history.html
@@ -1,7 +1,8 @@
{% extends "admin/base_site" %}
+{% load i18n %}
{% block breadcrumbs %}
-<div class="breadcrumbs"><a href="../../../../">{{ _('Home') }}</a> &rsaquo; <a href="../../">{{ module_name }}</a> &rsaquo; <a href="../">{{ object|truncatewords:"18" }}</a> &rsaquo; {{ _('History') }}</div>
+<div class="breadcrumbs"><a href="../../../../">{% trans 'Home' %}</a> &rsaquo; <a href="../../">{{ module_name }}</a> &rsaquo; <a href="../">{{ object|truncatewords:"18" }}</a> &rsaquo; {% trans 'History' %}</div>
{% endblock %}
{% block content %}
@@ -14,9 +15,9 @@
<table id="change-history">
<thead>
<tr>
- <th>{{ _('Date/time') }}</th>
- <th>{{ _('User') }}</th>
- <th>{{ _('Action') }}</th>
+ <th>{% trans 'Date/time' %}</th>
+ <th>{% trans 'User' %}</th>
+ <th>{% trans 'Action' %}</th>
</tr>
</thead>
<tbody>
@@ -32,7 +33,7 @@
{% else %}
- <p>{{ _("This object doesn't have a change history. It probably wasn't added via this admin site.") }}</p>
+ <p>{% trans "This object doesn't have a change history. It probably wasn't added via this admin site." %}</p>
{% endif %}
diff --git a/django/contrib/admin/templates/registration/logged_out.html b/django/contrib/admin/templates/registration/logged_out.html
index 253845c31a..756f82aadc 100644
--- a/django/contrib/admin/templates/registration/logged_out.html
+++ b/django/contrib/admin/templates/registration/logged_out.html
@@ -1,11 +1,12 @@
{% extends "admin/base_site" %}
+{% load i18n %}
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{{ _('Home') }}</a></div>{% endblock %}
+{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{% trans 'Home' %}</a></div>{% endblock %}
{% block content %}
-<p>{{ _("Thanks for spending some quality time with the Web site today.") }}</p>
+<p>{% trans "Thanks for spending some quality time with the Web site today." %}</p>
-<p><a href="../">{{ _('Log in again') }}</a></p>
+<p><a href="../">{% trans 'Log in again' %}</a></p>
{% endblock %}
diff --git a/django/contrib/admin/templates/registration/password_change_done.html b/django/contrib/admin/templates/registration/password_change_done.html
index 5c1acd32f9..f163e55a68 100644
--- a/django/contrib/admin/templates/registration/password_change_done.html
+++ b/django/contrib/admin/templates/registration/password_change_done.html
@@ -1,13 +1,14 @@
{% extends "admin/base_site" %}
+{% load i18n %}
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{{ _('Home') }}</a> &rsaquo; {{ _('Password change') }}</div>{% endblock %}
+{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{% trans 'Home' %}</a> &rsaquo; {% trans 'Password change' %}</div>{% endblock %}
-{% block title %}{{ _('Password change successful') }}{% endblock %}
+{% block title %}{% trans 'Password change successful' %}{% endblock %}
{% block content %}
-<h1>{{ _('Password change successful') }}</h1>
+<h1>{% trans 'Password change successful' %}</h1>
-<p>{{ _('Your password was changed.') }}</p>
+<p>{% trans 'Your password was changed.' %}</p>
{% endblock %}
diff --git a/django/contrib/admin/templates/registration/password_change_form.html b/django/contrib/admin/templates/registration/password_change_form.html
index acb2bef2ab..32e5569458 100644
--- a/django/contrib/admin/templates/registration/password_change_form.html
+++ b/django/contrib/admin/templates/registration/password_change_form.html
@@ -1,25 +1,26 @@
{% extends "admin/base_site" %}
+{% load i18n %}
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{{ _('Home') }}</a> &rsaquo; {{ _('Password change') }}</div>{% endblock %}
+{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{% trans 'Home' %}</a> &rsaquo; {% trans 'Password change' %}</div>{% endblock %}
-{% block title %}{{ _('Password change') }}{% endblock %}
+{% block title %}{% trans 'Password change' %}{% endblock %}
{% block content %}
-<h1>{{ _('Password change') }}</h1>
+<h1>{% trans 'Password change' %}</h1>
-<p>{{ _("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.") }}</p>
+<p>{% trans "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." %}</p>
<form action="" method="post">
{% if form.old_password.errors %}{{ form.old_password.html_error_list }}{% endif %}
-<p class="aligned wide"><label for="id_old_password">{{ _('Old password:') }}</label>{{ form.old_password }}</p>
+<p class="aligned wide"><label for="id_old_password">{% trans 'Old password:' %}</label>{{ form.old_password }}</p>
{% if form.new_password1.errors %}{{ form.new_password1.html_error_list }}{% endif %}
-<p class="aligned wide"><label for="id_new_password1">{{ _('New password:') }}</label>{{ form.new_password1 }}</p>
+<p class="aligned wide"><label for="id_new_password1">{% trans 'New password:' %}</label>{{ form.new_password1 }}</p>
{% if form.new_password2.errors %}{{ form.new_password2.html_error_list }}{% endif %}
-<p class="aligned wide"><label for="id_new_password2">{{ _('Confirm password:') }}</label>{{ form.new_password2 }}</p>
+<p class="aligned wide"><label for="id_new_password2">{% trans 'Confirm password:' %}</label>{{ form.new_password2 }}</p>
-<p><input type="submit" value="{{ _('Change my password') }}" /></p>
+<p><input type="submit" value="{% trans 'Change my password' %}" /></p>
</form>
{% endblock %}
diff --git a/django/contrib/admin/templates/registration/password_reset_done.html b/django/contrib/admin/templates/registration/password_reset_done.html
index 29f0b84452..dff293c931 100644
--- a/django/contrib/admin/templates/registration/password_reset_done.html
+++ b/django/contrib/admin/templates/registration/password_reset_done.html
@@ -1,13 +1,14 @@
{% extends "admin/base_site" %}
+{% load i18n %}
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{{ _('Home') }}</a> &rsaquo; {{ _('Password reset') }}</div>{% endblock %}
+{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{% trans 'Home' %}</a> &rsaquo; {% trans 'Password reset' %}</div>{% endblock %}
-{% block title %}{{ _('Password reset successful') }}{% endblock %}
+{% block title %}{% trans 'Password reset successful' %}{% endblock %}
{% block content %}
-<h1>{{ _('Password reset successful') }}</h1>
+<h1>{% trans 'Password reset successful' %}</h1>
-<p>{{ _("We've e-mailed a new password to the e-mail address you submitted. You should be receiving it shortly.") }}</p>
+<p>{% trans "We've e-mailed a new password to the e-mail address you submitted. You should be receiving it shortly." %}</p>
{% endblock %}
diff --git a/django/contrib/admin/templates/registration/password_reset_email.html b/django/contrib/admin/templates/registration/password_reset_email.html
index 08ca2c142d..b9a0257392 100644
--- a/django/contrib/admin/templates/registration/password_reset_email.html
+++ b/django/contrib/admin/templates/registration/password_reset_email.html
@@ -1,14 +1,15 @@
-{{ _("You're receiving this e-mail because you requested a password reset") }}
-{{ _("for your user account at %(site_name)s") }}.
+{% load i18n %}
+{% trans "You're receiving this e-mail because you requested a password reset" %}
+{% trans "for your user account at %(site_name)s" %}.
-{{ _("Your new password is: %(new_password)s") }}
+{% trans "Your new password is: %(new_password)s" %}
-{{ _("Feel free to change this password by going to this page:") }}
+{% trans "Feel free to change this password by going to this page:" %}
http://{{ domain }}/password_change/
-{{ _("Your username, in case you've forgotten:") }} {{ user.username }}
+{% trans "Your username, in case you've forgotten:" %} {{ user.username }}
-{{ _("Thanks for using our site!") }}
+{% trans "Thanks for using our site!" %}
-{{ _("The %(site_name)s team") }}
+{% trans "The %(site_name)s team" %}
diff --git a/django/contrib/admin/templates/registration/password_reset_form.html b/django/contrib/admin/templates/registration/password_reset_form.html
index 5e2e24e51c..8db1ede42f 100644
--- a/django/contrib/admin/templates/registration/password_reset_form.html
+++ b/django/contrib/admin/templates/registration/password_reset_form.html
@@ -1,18 +1,19 @@
{% extends "admin/base_site" %}
+{% load i18n %}
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{{ _('Home') }}</a> &rsaquo; {{ _('Password reset') }}</div>{% endblock %}
+{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{% trans 'Home' %}</a> &rsaquo; {% trans 'Password reset' %}</div>{% endblock %}
-{% block title %}{{ _("Password reset") }}{% endblock %}
+{% block title %}{% trans "Password reset" %}{% endblock %}
{% block content %}
-<h1>{{ _("Password reset") }}</h1>
+<h1>{% trans "Password reset") }}</h1>
-<p>{{ _("Forgotten your password? Enter your e-mail address below, and we'll reset your password and e-mail the new one to you.") }}</p>
+<p>{% trans "Forgotten your password? Enter your e-mail address below, and we'll reset your password and e-mail the new one to you." %}</p>
<form action="" method="post">
{% if form.email.errors %}{{ form.email.html_error_list }}{% endif %}
-<p><label for="id_email">{{ _('E-mail address:') }}</label> {{ form.email }} <input type="submit" value="{{ _('Reset my password') }}" /></p>
+<p><label for="id_email">{% trans 'E-mail address:' %}</label> {{ form.email }} <input type="submit" value="{% trans 'Reset my password' %}" /></p>
</form>
{% endblock %}
diff --git a/django/core/template/__init__.py b/django/core/template/__init__.py
index 9a63098005..0011cb2c9a 100644
--- a/django/core/template/__init__.py
+++ b/django/core/template/__init__.py
@@ -234,6 +234,97 @@ class Parser:
def delete_first_token(self):
del self.tokens[0]
+class TokenParser:
+ """
+ You need to subclass this class and implement the
+ top method to parse your template line. When instantiating
+ the parser, you pass in the line from the django template
+ parser.
+
+ If your tag needs to know what tag name it was called with,
+ you find it in the tagname instance variable of the parser.
+ """
+
+ def __init__(self, subject):
+ self.subject = subject
+ self.pointer = 0
+ self.backout = []
+ self.tagname = self.tag()
+
+ def top(self):
+ """
+ You need to overload this method to do the actual parsing
+ and return the result.
+ """
+ raise NotImplemented
+
+ def more(self):
+ """
+ This returns True if there is more stuff in the tag.
+ """
+ return self.pointer < len(self.subject)
+
+ def back(self):
+ """
+ This method undos the last microparser. This can be
+ used for lookahead and backtracking.
+ """
+ if not len(self.backout):
+ raise TemplateSyntaxError, "back called without some previous parsing"
+ self.pointer = self.backout.pop()
+
+ def tag(self):
+ """
+ This microparser just returns the next tag from the line.
+ """
+ subject = self.subject
+ i = self.pointer
+ if i >= len(subject):
+ raise TemplateSyntaxError, "expected another tag, found end of string: %s" % subject
+ p = i
+ while i < len(subject) and subject[i] not in (' ', '\t'):
+ i += 1
+ s = subject[p:i]
+ while i < len(subject) and subject[i] in (' ', '\t'):
+ i += 1
+ self.backout.append(self.pointer)
+ self.pointer = i
+ return s
+
+ def value(self):
+ """
+ This microparser parses for a value - some string constant or
+ variable name.
+ """
+ subject = self.subject
+ i = self.pointer
+ if i >= len(subject):
+ raise TemplateSyntaxError, "searching for value expected another value, found end of string: %s" % subject
+ if subject[i] in ('"', "'"):
+ p = i
+ i += 1
+ 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
+ i += 1
+ res = subject[p:i]
+ while i < len(subject) and subject[i] in (' ', '\t'):
+ i += 1
+ self.backout.append(self.pointer)
+ self.pointer = i
+ return res
+ else:
+ p = i
+ while i < len(subject) and subject[i] not in (' ', '\t'):
+ i += 1
+ s = subject[p:i]
+ while i < len(subject) and subject[i] in (' ', '\t'):
+ i += 1
+ self.backout.append(self.pointer)
+ self.pointer = i
+ return s
+
class FilterParser:
"""Parse a variable token and its optional filters (all as a single string),
and return a list of tuples of the filter name and arguments.
@@ -257,13 +348,13 @@ class FilterParser:
self.current_filter_arg = None
# First read the variable part - decide on wether we need
# to parse a string or a variable by peeking into the stream
- if self.peek_char() in ('_', '"', "'"):
+ if self.peek_char() in ('"', "'"):
self.var = self.read_constant_string_token()
else:
self.var = self.read_alphanumeric_token()
if not self.var:
raise TemplateSyntaxError, "Could not read variable name: '%s'" % self.s
- if self.var.find(VARIABLE_ATTRIBUTE_SEPARATOR + '_') > -1 or (self.var[0] == '_' and not self.var.startswith('_(')):
+ if self.var.find(VARIABLE_ATTRIBUTE_SEPARATOR + '_') > -1 or self.var[0] == '_':
raise TemplateSyntaxError, "Variables and attributes may not begin with underscores: '%s'" % self.var
# Have we reached the end?
if self.current is None:
@@ -288,19 +379,10 @@ class FilterParser:
def read_constant_string_token(self):
"""Read a constant string that must be delimited by either "
- or ' characters. The string is returned with it's delimiters
- and a possible i18n tag."""
+ or ' characters. The string is returned with it's delimiters."""
val = ''
- i18n = False
qchar = None
self.next_char()
- if self.current == '_':
- self.next_char()
- if self.current != '(':
- raise TemplateSyntaxError, "Bad character (expecting '(') '%s'" % self.current
- i18n = True
- val = '_('
- self.next_char()
if not self.current in ('"', "'"):
raise TemplateSyntaxError, "Bad character (expecting '\"' or ''') '%s'" % self.current
qchar = self.current
@@ -311,11 +393,6 @@ class FilterParser:
break
val += self.current
val += self.current
- if i18n:
- self.next_char()
- if self.current != ')':
- raise TemplateSyntaxError, "Bad character (expecting ')') '%s'" % self.current
- val += self.current
self.next_char()
return val
@@ -430,8 +507,6 @@ def resolve_variable(path, context):
"""
if path[0] in ('"', "'") and path[0] == path[-1]:
current = path[1:-1]
- elif path.startswith('_(') and path.endswith(')') and path[2] in ("'", '"') and path[-2] == path[2]:
- current = _(path[3:-2]) % context
else:
current = context
bits = path.split(VARIABLE_ATTRIBUTE_SEPARATOR)
diff --git a/django/templatetags/i18n.py b/django/templatetags/i18n.py
new file mode 100644
index 0000000000..37f7175593
--- /dev/null
+++ b/django/templatetags/i18n.py
@@ -0,0 +1,210 @@
+"Default tags used by the template system, available to all templates."
+
+from django.core.template import Node, NodeList, Template, Context, resolve_variable, resolve_variable_with_filters, registered_filters
+from django.core.template import TemplateSyntaxError, register_tag, TokenParser
+from django.core.template import TOKEN_BLOCK, TOKEN_TEXT, TOKEN_VAR
+from django.utils import translation
+
+import sys
+import re
+
+class GetAvailableLanguagesNode(Node):
+
+ def __init__(self, variable):
+ self.variable = variable
+
+ def render(self, context):
+ from django.conf.settings import LANGUAGES
+ context[self.variable] = LANGUAGES
+ return ''
+
+class GetCurrentLanguage(Node):
+
+ def __init__(self, variable):
+ self.variable = variable
+
+ def render(self, context):
+ context[self.variable] = translation.get_language()
+ return ''
+
+class TranslateNode(Node):
+
+ def __init__(self, value, noop):
+ self.value = value
+ self.noop = noop
+
+ def render(self, context):
+ value = resolve_variable(self.value, context)
+ if self.noop:
+ return value
+ else:
+ return translation.gettext(value)
+
+class BlockTranslateNode(Node):
+
+ def __init__(self, extra_context, singular, plural=None, countervar=None, counter=None):
+ self.extra_context = extra_context
+ self.singular = singular
+ self.plural = plural
+ self.countervar = countervar
+ self.counter = counter
+
+ def render_token_list(self, tokens):
+ result = []
+ for token in tokens:
+ if token.token_type == TOKEN_TEXT:
+ result.append(token.contents)
+ elif token.token_type == TOKEN_VAR:
+ result.append('%%(%s)s' % token.contents)
+ return ''.join(result)
+
+ def render(self, context):
+ context.push()
+ for var,val in self.extra_context.items():
+ context[var] = resolve_variable_with_filters(val, context)
+ singular = self.render_token_list(self.singular) % context
+ if self.plural and self.countervar and self.counter:
+ count = resolve_variable_with_filters(self.counter, context)
+ context[self.countervar] = count
+ plural = self.render_token_list(self.plural) % context
+ result = translation.ngettext(singular, plural, count) % context
+ else:
+ result = translation.gettext(singular) % context
+ context.pop()
+ return result
+
+def do_get_available_languages(parser, token):
+ """
+ This will store a list of available languages
+ in the context.
+
+ Usage is as follows::
+
+ {% get_available_languages as languages %}
+ {% for language in languages %}
+ ...
+ {% endfor %}
+
+ This will just pull the LANGUAGES setting from
+ your setting file (or the default settings) and
+ put it into the named variable.
+ """
+
+ args = token.contents.split()
+ if len(args) != 3 or args[1] != 'as':
+ raise TemplateSyntaxError, "'get_available_languages' requires 'as variable' (got %r)" % args
+ return GetAvailableLanguagesNode(args[2])
+
+def do_get_current_language(parser, token):
+ """
+ This will store the current language in
+ the context.
+
+ Usage is as follows::
+
+ {% get_current_language as language %}
+
+ This will fetch the currently active language and
+ put it's value into the ``language`` context
+ variable.
+ """
+
+ args = token.contents.split()
+ if len(args) != 3 or args[1] != 'as':
+ raise TemplateSyntaxError, "'get_available_languages' requires 'as variable' (got %r)" % args
+ return GetAvailableLanguagesNode(args[2])
+
+def do_translate(parser, token):
+ """
+ This will mark a string for translation and will
+ translate the string for the current language.
+
+ Usage is like this::
+
+ {% trans "this is a test" %}
+
+ This will mark the string for translation so it will
+ be pulled out by mark-messages.py into the .po files
+ and will run the string through the translation engine.
+
+ There is a second form::
+
+ {% trans "this is a test" noop %}
+
+ This will only mark for translation, but will return
+ the string unchanged. Use it when you need to store
+ values into forms that should be translated later on.
+
+ You can use variables instead of constant strings
+ to translate stuff you marked somewhere else::
+
+ {% trans variable %}
+
+ This will just try to translate the contents of
+ the variable ``variable``. Make sure that the string
+ in there is something that is in the .po file.
+ """
+ args = token.contents.split(None, 1)
+ p = args[1].rfind(' ')
+ noop = False
+ value = ''
+ if p >= 0 and args[1][p:].strip() == 'noop':
+ value = args[1][:p].strip()
+ else:
+ value = args[1]
+ return TranslateNode(value, noop)
+
+def do_block_translate(parser, token):
+ """
+ """
+ class BlockTranslateParser(TokenParser):
+
+ def top(self):
+ countervar = None
+ counter = None
+ extra_context = {}
+ while self.more():
+ tag = self.tag()
+ if tag == 'with' or tag == 'and':
+ value = self.value()
+ if self.tag() != 'as':
+ raise TemplateSyntaxError, "variable bindings in 'blocktrans' must be 'with value as variable'"
+ extra_context[self.tag()] = value
+ elif tag == 'count':
+ counter = self.value()
+ if self.tag() != 'as':
+ raise TemplateSyntaxError, "counter specification in 'blocktrans' must be 'count value as variable'"
+ countervar = self.tag()
+ else:
+ raise TemplateSyntaxError, "unknown subtag %s for 'blocktrans' found" % tag
+ return (countervar, counter, extra_context)
+
+ (countervar, counter, extra_context) = BlockTranslateParser(token.contents).top()
+
+ singular = []
+ plural = []
+ while parser.tokens:
+ token = parser.next_token()
+ if token.token_type in (TOKEN_VAR, TOKEN_TEXT):
+ singular.append(token)
+ else:
+ break
+ if countervar and counter:
+ if token.contents.strip() != 'plural':
+ raise TemplateSyntaxError, "'blocktrans' doesn't allow other block tags inside it" % tag
+ while parser.tokens:
+ token = parser.next_token()
+ if token.token_type in (TOKEN_VAR, TOKEN_TEXT):
+ plural.append(token)
+ else:
+ break
+ if token.contents.strip() != 'endblocktrans':
+ raise TemplateSyntaxError, "'blocktrans' doesn't allow other block tags (seen %r) inside it" % token.contents
+
+ return BlockTranslateNode(extra_context, singular, plural, countervar, counter)
+
+register_tag('get_available_languages', do_get_available_languages)
+register_tag('get_curent_language', do_get_current_language)
+register_tag('trans', do_translate)
+register_tag('blocktrans', do_block_translate)
+
diff --git a/django/utils/translation.py b/django/utils/translation.py
index e4de5a8c64..a8b9192bc6 100644
--- a/django/utils/translation.py
+++ b/django/utils/translation.py
@@ -1,8 +1,10 @@
"translation helper functions"
import os
+import re
import sys
import gettext as gettext_module
+from cStringIO import StringIO
from django.utils.functional import lazy
@@ -349,3 +351,89 @@ def install():
"""
__builtins__['_'] = gettext
+
+dot_re = re.compile(r'\S')
+def blankout(src, char):
+ """
+ This is used in the templateize function and changes every
+ non-whitespace character to the given char.
+ """
+ return dot_re.sub(char, src)
+
+inline_re = re.compile(r"""^\s*trans\s+((?:".*?")|(?:'.*?'))\s*""")
+block_re = re.compile(r"""^\s*blocktrans(?:\s+|$)""")
+endblock_re = re.compile(r"""^\s*endblocktrans$""")
+plural_re = re.compile(r"""^\s*plural$""")
+def templateize(src):
+ from django.core.template import tokenize, TOKEN_TEXT, TOKEN_VAR, TOKEN_BLOCK
+ """
+ This function turns a django template into something that is
+ understood by xgettext. It does so by translating the django
+ translation tags into standard gettext function invocations.
+ """
+ out = StringIO()
+ intrans = False
+ inplural = False
+ singular = []
+ plural = []
+ for t in tokenize(src):
+ if intrans:
+ if t.token_type == TOKEN_BLOCK:
+ endbmatch = endblock_re.match(t.contents)
+ pluralmatch = plural_re.match(t.contents)
+ if endbmatch:
+ if inplural:
+ out.write(' ngettext(%r,%r,count) ' % (''.join(singular), ''.join(plural)))
+ for part in singular:
+ out.write(blankout(part, 'S'))
+ for part in plural:
+ out.write(blankout(part, 'P'))
+ else:
+ out.write(' gettext(%r) ' % ''.join(singular))
+ for part in singular:
+ out.write(blankout(part, 'S'))
+ intrans = False
+ inplural = False
+ singular = []
+ plural = []
+ elif pluralmatch:
+ inplural = True
+ else:
+ raise SyntaxError, "translation blocks must not include other block tags: %s" % t.contents
+ elif t.token_type == TOKEN_VAR:
+ if inplural:
+ plural.append('%%(%s)s' % t.contents)
+ else:
+ singular.append('%%(%s)s' % t.contents)
+ elif t.token_type == TOKEN_TEXT:
+ if inplural:
+ plural.append(t.contents)
+ else:
+ singular.append(t.contents)
+ else:
+ if t.token_type == TOKEN_BLOCK:
+ imatch = inline_re.match(t.contents)
+ bmatch = block_re.match(t.contents)
+ if imatch:
+ g = imatch.group(1)
+ if g[0] == '"': g = g.strip('"')
+ elif g[0] == "'": g = g.strip("'")
+ out.write(' gettext(%r) ' % g)
+ elif bmatch:
+ intrans = True
+ inplural = False
+ singular = []
+ plural = []
+ else:
+ out.write(blankout(t.contents, 'B'))
+ elif t.token_type == TOKEN_VAR:
+ parts = t.contents.split('|')
+ for p in parts:
+ if p.find(':_(') >= 0:
+ out.write(' %s ' % p.split(':',1)[1])
+ else:
+ out.write(blankout(p, 'F'))
+ else:
+ out.write(blankout(t.contents, 'X'))
+ return out.getvalue()
+