Skip to content

Commit 953badb

Browse files
committed
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes. Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702 git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
1 parent 4c958b1 commit 953badb

File tree

193 files changed

+3000
-1598
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

193 files changed

+3000
-1598
lines changed

AUTHORS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ answer newbie questions, and generally made Django that much better:
113113
Simon Greenhill <[email protected]>
114114
Owen Griffiths
115115
Espen Grindhaug <http://grindhaug.org/>
116+
Thomas Güttler <[email protected]>
116117
Brian Harring <[email protected]>
117118
Brant Harris
118119
Hawkeye
@@ -147,6 +148,7 @@ answer newbie questions, and generally made Django that much better:
147148
Bruce Kroeze <http://coderseye.com/>
148149
Joseph Kocherhans
149150
151+
150152
151153
Nick Lane <[email protected]>
152154
Stuart Langridge <http://www.kryogenix.org/>

django/bin/make-messages.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ def make_messages():
103103
open(os.path.join(dirpath, '%s.py' % file), "wb").write(templatize(src))
104104
thefile = '%s.py' % file
105105
if verbose: sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
106-
cmd = 'xgettext %s -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % (
106+
cmd = 'xgettext %s -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --keyword=ugettext_noop --keyword=ugettext_lazy --keyword=ungettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % (
107107
os.path.exists(potfile) and '--omit-header' or '', domain, os.path.join(dirpath, thefile))
108108
(stdin, stdout, stderr) = os.popen3(cmd, 'b')
109109
msgs = stdout.read()

django/conf/global_settings.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@
9797
DEFAULT_CONTENT_TYPE = 'text/html'
9898
DEFAULT_CHARSET = 'utf-8'
9999

100+
# Encoding of files read from disk (template and initial SQL files).
101+
FILE_CHARSET = 'utf-8'
102+
100103
# E-mail address that error messages come from.
101104
SERVER_EMAIL = 'root@localhost'
102105

django/contrib/admin/filterspecs.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
"""
88

99
from django.db import models
10+
from django.utils.encoding import smart_unicode, iri_to_uri
11+
from django.utils.translation import ugettext as _
1012
import datetime
1113

1214
class FilterSpec(object):
@@ -37,12 +39,12 @@ def title(self):
3739
def output(self, cl):
3840
t = []
3941
if self.has_output():
40-
t.append(_('<h3>By %s:</h3>\n<ul>\n') % self.title())
42+
t.append(_(u'<h3>By %s:</h3>\n<ul>\n') % self.title())
4143

4244
for choice in self.choices(cl):
43-
t.append('<li%s><a href="%s">%s</a></li>\n' % \
45+
t.append(u'<li%s><a href="%s">%s</a></li>\n' % \
4446
((choice['selected'] and ' class="selected"' or ''),
45-
choice['query_string'] ,
47+
iri_to_uri(choice['query_string']),
4648
choice['display']))
4749
t.append('</ul>\n\n')
4850
return "".join(t)
@@ -70,7 +72,7 @@ def choices(self, cl):
7072
'display': _('All')}
7173
for val in self.lookup_choices:
7274
pk_val = getattr(val, self.field.rel.to._meta.pk.attname)
73-
yield {'selected': self.lookup_val == str(pk_val),
75+
yield {'selected': self.lookup_val == smart_unicode(pk_val),
7476
'query_string': cl.get_query_string({self.lookup_kwarg: pk_val}),
7577
'display': val}
7678

@@ -87,7 +89,7 @@ def choices(self, cl):
8789
'query_string': cl.get_query_string({}, [self.lookup_kwarg]),
8890
'display': _('All')}
8991
for k, v in self.field.choices:
90-
yield {'selected': str(k) == self.lookup_val,
92+
yield {'selected': smart_unicode(k) == self.lookup_val,
9193
'query_string': cl.get_query_string({self.lookup_kwarg: k}),
9294
'display': v}
9395

@@ -168,7 +170,7 @@ def choices(self, cl):
168170
'query_string': cl.get_query_string({}, [self.field.name]),
169171
'display': _('All')}
170172
for val in self.lookup_choices:
171-
val = str(val[self.field.name])
173+
val = smart_unicode(val[self.field.name])
172174
yield {'selected': self.lookup_val == val,
173175
'query_string': cl.get_query_string({self.field.name: val}),
174176
'display': val}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,110 @@
1+
var LATIN_MAP =
2+
{
3+
'À': 'A', 'Á': 'A', 'Â': 'A', 'Ã': 'A', 'Ä': 'A', 'Å': 'A', 'Æ': 'AE', 'Ç':
4+
'C', 'È': 'E', 'É': 'E', 'Ê': 'E', 'Ë': 'E', 'Ì': 'I', 'Í': 'I', 'Î': 'I',
5+
'Ï': 'I', 'Ð': 'D', 'Ñ': 'N', 'Ò': 'O', 'Ó': 'O', 'Ô': 'O', 'Õ': 'O', 'Ö':
6+
'O', 'Ø': 'O', 'Ù': 'U', 'Ú': 'U', 'Û': 'U', 'Ü': 'U', 'Ý': 'Y', 'Þ': 'TH',
7+
'ß': 'ss', 'à':'a', 'á':'a', 'â': 'a', 'ã': 'a', 'ä': 'a', 'å': 'a', 'æ':
8+
'ae', 'ç': 'c', 'è': 'e', 'é': 'e', 'ê': 'e', 'ë': 'e', 'ì': 'i', 'í': 'i',
9+
'î': 'i', 'ï': 'i', 'ð': 'o', 'ñ': 'n', 'ò': 'o', 'ó': 'o', 'ô': 'o', 'õ':
10+
'o', 'ö': 'o', 'ø': 'o', 'ù': 'u', 'ú': 'u', 'û': 'u', 'ü': 'u', 'ý': 'y',
11+
'þ': 'th', 'ÿ': 'y',
12+
}
13+
var LATIN_SYMBOLS_MAP =
14+
{
15+
'©':'(c)',
16+
}
17+
var GREEK_MAP =
18+
{
19+
'α':'a', 'β':'b', 'γ':'g', 'δ':'d', 'ε':'e', 'ζ':'z', 'η':'h', 'θ':'8',
20+
'ι':'i', 'κ':'k', 'λ':'l', 'μ':'m', 'ν':'n', 'ξ':'3', 'ο':'o', 'π':'p',
21+
'ρ':'r', 'σ':'s', 'τ':'t', 'υ':'y', 'φ':'f', 'χ':'x', 'ψ':'ps', 'ω':'w',
22+
'ά':'a', 'έ':'e', 'ί':'i', 'ό':'o', 'ύ':'y', 'ή':'h', 'ώ':'w', 'ς':'s',
23+
'ϊ':'i', 'ΰ':'y', 'ϋ':'y', 'ΐ':'i',
24+
'Α':'A', 'Β':'B', 'Γ':'G', 'Δ':'D', 'Ε':'E', 'Ζ':'Z', 'Η':'H', 'Θ':'8',
25+
'Ι':'I', 'Κ':'K', 'Λ':'L', 'Μ':'M', 'Ν':'N', 'Ξ':'3', 'Ο':'O', 'Π':'P',
26+
'Ρ':'R', 'Σ':'S', 'Τ':'T', 'Υ':'Y', 'Φ':'F', 'Χ':'X', 'Ψ':'PS', 'Ω':'W',
27+
'Ά':'A', 'Έ':'E', 'Ί':'I', 'Ό':'O', 'Ύ':'Y', 'Ή':'H', 'Ώ':'W', 'Ϊ':'I',
28+
'Ϋ':'Y'
29+
}
30+
var TURKISH_MAP = {
31+
'ş':'s', 'Ş':'S', 'ı':'i', 'İ':'I', 'ç':'c', 'Ç':'C', 'ü':'u', 'Ü':'U',
32+
'ö':'o', 'Ö':'O', 'ğ':'g', 'Ğ':'G',
33+
}
34+
// var RUSSIAN_MAP =
35+
// {
36+
// }
37+
38+
var ALL_DOWNCODE_MAPS=new Array()
39+
ALL_DOWNCODE_MAPS[0]=LATIN_MAP
40+
ALL_DOWNCODE_MAPS[1]=LATIN_SYMBOLS_MAP
41+
ALL_DOWNCODE_MAPS[2]=GREEK_MAP
42+
ALL_DOWNCODE_MAPS[3]=TURKISH_MAP
43+
//ALL_DOWNCODE_MAPS[4]=RUSSIAN_MAP
44+
45+
var Downcoder = new Object();
46+
Downcoder.Initialize = function()
47+
{
48+
if (Downcoder.map) // already made
49+
return ;
50+
Downcoder.map ={}
51+
Downcoder.chars = '' ;
52+
for(var i in ALL_DOWNCODE_MAPS)
53+
{
54+
var lookup = ALL_DOWNCODE_MAPS[i]
55+
for (var c in lookup)
56+
{
57+
Downcoder.map[c] = lookup[c] ;
58+
Downcoder.chars += c ;
59+
}
60+
}
61+
Downcoder.regex = new RegExp('[' + Downcoder.chars + ']|[^' + Downcoder.chars + ']+','g') ;
62+
}
63+
64+
downcode= function( slug )
65+
{
66+
Downcoder.Initialize() ;
67+
var downcoded =""
68+
var pieces = slug.match(Downcoder.regex);
69+
if(pieces)
70+
{
71+
for (var i = 0 ; i < pieces.length ; i++)
72+
{
73+
if (pieces[i].length == 1)
74+
{
75+
var mapped = Downcoder.map[pieces[i]] ;
76+
if (mapped != null)
77+
{
78+
downcoded+=mapped;
79+
continue ;
80+
}
81+
}
82+
downcoded+=pieces[i];
83+
}
84+
}
85+
else
86+
{
87+
downcoded = slug;
88+
}
89+
return downcoded;
90+
}
91+
92+
193
function URLify(s, num_chars) {
294
// changes, e.g., "Petty theft" to "petty_theft"
395
// remove all these words from the string before urlifying
96+
s = downcode(s);
497
removelist = ["a", "an", "as", "at", "before", "but", "by", "for", "from",
598
"is", "in", "into", "like", "of", "off", "on", "onto", "per",
699
"since", "than", "the", "this", "that", "to", "up", "via",
7100
"with"];
8101
r = new RegExp('\\b(' + removelist.join('|') + ')\\b', 'gi');
9102
s = s.replace(r, '');
103+
// if downcode doesn't hit, the char will be stripped here
10104
s = s.replace(/[^-\w\s]/g, ''); // remove unneeded chars
11105
s = s.replace(/^\s+|\s+$/g, ''); // trim leading/trailing spaces
12106
s = s.replace(/[-\s]+/g, '-'); // convert spaces to hyphens
13107
s = s.toLowerCase(); // convert to lowercase
14108
return s.substring(0, num_chars);// trim to first num_chars chars
15109
}
110+

django/contrib/admin/models.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
from django.db import models
22
from django.contrib.contenttypes.models import ContentType
33
from django.contrib.auth.models import User
4-
from django.utils.translation import gettext_lazy as _
4+
from django.utils.translation import ugettext_lazy as _
5+
from django.utils.encoding import smart_unicode
56

67
ADDITION = 1
78
CHANGE = 2
89
DELETION = 3
910

1011
class LogEntryManager(models.Manager):
1112
def log_action(self, user_id, content_type_id, object_id, object_repr, action_flag, change_message=''):
12-
e = self.model(None, None, user_id, content_type_id, str(object_id), object_repr[:200], action_flag, change_message)
13+
e = self.model(None, None, user_id, content_type_id, smart_unicode(object_id), object_repr[:200], action_flag, change_message)
1314
e.save()
1415

1516
class LogEntry(models.Model):
@@ -28,7 +29,7 @@ class Meta:
2829
ordering = ('-action_time',)
2930

3031
def __repr__(self):
31-
return str(self.action_time)
32+
return smart_unicode(self.action_time)
3233

3334
def is_addition(self):
3435
return self.action_flag == ADDITION
@@ -48,4 +49,4 @@ def get_admin_url(self):
4849
Returns the admin URL to edit the object represented by this log entry.
4950
This is relative to the Django admin index page.
5051
"""
51-
return "%s/%s/%s/" % (self.content_type.app_label, self.content_type.model, self.object_id)
52+
return u"%s/%s/%s/" % (self.content_type.app_label, self.content_type.model, self.object_id)

django/contrib/admin/templates/admin/filter.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ <h3>{% blocktrans with title|escape as filter_title %} By {{ filter_title }} {%
33
<ul>
44
{% for choice in choices %}
55
<li{% if choice.selected %} class="selected"{% endif %}>
6-
<a href="{{ choice.query_string }}">{{ choice.display|escape }}</a></li>
6+
<a href="{{ choice.query_string|iriencode }}">{{ choice.display|escape }}</a></li>
77
{% endfor %}
88
</ul>

django/contrib/admin/templatetags/admin_list.py

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
from django.utils import dateformat
77
from django.utils.html import escape
88
from django.utils.text import capfirst
9-
from django.utils.translation import get_date_formats, get_partial_date_formats
9+
from django.utils.translation import get_date_formats, get_partial_date_formats, ugettext as _
10+
from django.utils.encoding import smart_unicode, smart_str, force_unicode
1011
from django.template import Library
1112
import datetime
1213

@@ -16,11 +17,11 @@
1617

1718
def paginator_number(cl,i):
1819
if i == DOT:
19-
return '... '
20+
return u'... '
2021
elif i == cl.page_num:
21-
return '<span class="this-page">%d</span> ' % (i+1)
22+
return u'<span class="this-page">%d</span> ' % (i+1)
2223
else:
23-
return '<a href="%s"%s>%d</a> ' % (cl.get_query_string({PAGE_VAR: i}), (i == cl.paginator.pages-1 and ' class="end"' or ''), i+1)
24+
return u'<a href="%s"%s>%d</a> ' % (cl.get_query_string({PAGE_VAR: i}), (i == cl.paginator.pages-1 and ' class="end"' or ''), i+1)
2425
paginator_number = register.simple_tag(paginator_number)
2526

2627
def pagination(cl):
@@ -75,10 +76,12 @@ def result_headers(cl):
7576
admin_order_field = None
7677
except models.FieldDoesNotExist:
7778
# For non-field list_display values, check for the function
78-
# attribute "short_description". If that doesn't exist, fall
79-
# back to the method name. And __str__ is a special-case.
80-
if field_name == '__str__':
81-
header = lookup_opts.verbose_name
79+
# attribute "short_description". If that doesn't exist, fall back
80+
# to the method name. And __str__ and __unicode__ are special-cases.
81+
if field_name == '__unicode__':
82+
header = force_unicode(lookup_opts.verbose_name)
83+
elif field_name == '__str__':
84+
header = smart_str(lookup_opts.verbose_name)
8285
else:
8386
attr = getattr(cl.model, field_name) # Let AttributeErrors propagate.
8487
try:
@@ -114,7 +117,7 @@ def result_headers(cl):
114117

115118
def _boolean_icon(field_val):
116119
BOOLEAN_MAPPING = {True: 'yes', False: 'no', None: 'unknown'}
117-
return '<img src="%simg/admin/icon-%s.gif" alt="%s" />' % (settings.ADMIN_MEDIA_PREFIX, BOOLEAN_MAPPING[field_val], field_val)
120+
return u'<img src="%simg/admin/icon-%s.gif" alt="%s" />' % (settings.ADMIN_MEDIA_PREFIX, BOOLEAN_MAPPING[field_val], field_val)
118121

119122
def items_for_result(cl, result):
120123
first = True
@@ -136,7 +139,7 @@ def items_for_result(cl, result):
136139
allow_tags = True
137140
result_repr = _boolean_icon(attr)
138141
else:
139-
result_repr = str(attr)
142+
result_repr = smart_unicode(attr)
140143
except (AttributeError, ObjectDoesNotExist):
141144
result_repr = EMPTY_CHANGELIST_VALUE
142145
else:
@@ -179,19 +182,19 @@ def items_for_result(cl, result):
179182
elif f.choices:
180183
result_repr = dict(f.choices).get(field_val, EMPTY_CHANGELIST_VALUE)
181184
else:
182-
result_repr = escape(str(field_val))
183-
if result_repr == '':
185+
result_repr = escape(field_val)
186+
if force_unicode(result_repr) == '':
184187
result_repr = '&nbsp;'
185188
# If list_display_links not defined, add the link tag to the first field
186-
if (first and not cl.lookup_opts.admin.list_display_links) or field_name in cl.lookup_opts.admin.list_display_links:
189+
if (first and not cl.lookup_opts.admin.list_display_links) or field_name in cl.lookup_opts.admin.list_display_links:
187190
table_tag = {True:'th', False:'td'}[first]
188191
first = False
189192
url = cl.url_for_result(result)
190-
result_id = str(getattr(result, pk)) # str() is needed in case of 23L (long ints)
191-
yield ('<%s%s><a href="%s"%s>%s</a></%s>' % \
193+
result_id = smart_unicode(getattr(result, pk)) # conversion to string is needed in case of 23L (long ints)
194+
yield (u'<%s%s><a href="%s"%s>%s</a></%s>' % \
192195
(table_tag, row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %r); return false;"' % result_id or ''), result_repr, table_tag))
193196
else:
194-
yield ('<td%s>%s</td>' % (row_class, result_repr))
197+
yield (u'<td%s>%s</td>' % (row_class, result_repr))
195198

196199
def results(cl):
197200
for res in cl.result_list:

0 commit comments

Comments
 (0)