Skip to content

Commit

Permalink
Merged Unicode branch into trunk (r4952:5608). This should be fully
Browse files Browse the repository at this point in the history
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
  • Loading branch information
malcolmt committed Jul 4, 2007
1 parent 4c958b1 commit 953badb
Show file tree
Hide file tree
Showing 193 changed files with 3,000 additions and 1,598 deletions.
2 changes: 2 additions & 0 deletions AUTHORS
Expand Up @@ -113,6 +113,7 @@ answer newbie questions, and generally made Django that much better:
Simon Greenhill <dev@simon.net.nz>
Owen Griffiths
Espen Grindhaug <http://grindhaug.org/>
Thomas Güttler <hv@tbz-pariv.de>
Brian Harring <ferringb@gmail.com>
Brant Harris
Hawkeye
Expand Down Expand Up @@ -147,6 +148,7 @@ answer newbie questions, and generally made Django that much better:
Bruce Kroeze <http://coderseye.com/>
Joseph Kocherhans
konrad@gwu.edu
kurtiss@meetro.com
lakin.wecker@gmail.com
Nick Lane <nick.lane.au@gmail.com>
Stuart Langridge <http://www.kryogenix.org/>
Expand Down
2 changes: 1 addition & 1 deletion django/bin/make-messages.py
Expand Up @@ -103,7 +103,7 @@ def make_messages():
open(os.path.join(dirpath, '%s.py' % file), "wb").write(templatize(src))
thefile = '%s.py' % file
if verbose: sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
cmd = 'xgettext %s -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % (
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"' % (
os.path.exists(potfile) and '--omit-header' or '', domain, os.path.join(dirpath, thefile))
(stdin, stdout, stderr) = os.popen3(cmd, 'b')
msgs = stdout.read()
Expand Down
3 changes: 3 additions & 0 deletions django/conf/global_settings.py
Expand Up @@ -97,6 +97,9 @@
DEFAULT_CONTENT_TYPE = 'text/html'
DEFAULT_CHARSET = 'utf-8'

# Encoding of files read from disk (template and initial SQL files).
FILE_CHARSET = 'utf-8'

# E-mail address that error messages come from.
SERVER_EMAIL = 'root@localhost'

Expand Down
14 changes: 8 additions & 6 deletions django/contrib/admin/filterspecs.py
Expand Up @@ -7,6 +7,8 @@
"""

from django.db import models
from django.utils.encoding import smart_unicode, iri_to_uri
from django.utils.translation import ugettext as _
import datetime

class FilterSpec(object):
Expand Down Expand Up @@ -37,12 +39,12 @@ def title(self):
def output(self, cl):
t = []
if self.has_output():
t.append(_('<h3>By %s:</h3>\n<ul>\n') % self.title())
t.append(_(u'<h3>By %s:</h3>\n<ul>\n') % self.title())

for choice in self.choices(cl):
t.append('<li%s><a href="%s">%s</a></li>\n' % \
t.append(u'<li%s><a href="%s">%s</a></li>\n' % \
((choice['selected'] and ' class="selected"' or ''),
choice['query_string'] ,
iri_to_uri(choice['query_string']),
choice['display']))
t.append('</ul>\n\n')
return "".join(t)
Expand Down Expand Up @@ -70,7 +72,7 @@ def choices(self, cl):
'display': _('All')}
for val in self.lookup_choices:
pk_val = getattr(val, self.field.rel.to._meta.pk.attname)
yield {'selected': self.lookup_val == str(pk_val),
yield {'selected': self.lookup_val == smart_unicode(pk_val),
'query_string': cl.get_query_string({self.lookup_kwarg: pk_val}),
'display': val}

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

Expand Down Expand Up @@ -168,7 +170,7 @@ def choices(self, cl):
'query_string': cl.get_query_string({}, [self.field.name]),
'display': _('All')}
for val in self.lookup_choices:
val = str(val[self.field.name])
val = smart_unicode(val[self.field.name])
yield {'selected': self.lookup_val == val,
'query_string': cl.get_query_string({self.field.name: val}),
'display': val}
Expand Down
95 changes: 95 additions & 0 deletions django/contrib/admin/media/js/urlify.js
@@ -1,15 +1,110 @@
var LATIN_MAP =
{
'À': 'A', 'Á': 'A', 'Â': 'A', 'Ã': 'A', 'Ä': 'A', 'Å': 'A', 'Æ': 'AE', 'Ç':
'C', 'È': 'E', 'É': 'E', 'Ê': 'E', 'Ë': 'E', 'Ì': 'I', 'Í': 'I', 'Î': 'I',
'Ï': 'I', 'Ð': 'D', 'Ñ': 'N', 'Ò': 'O', 'Ó': 'O', 'Ô': 'O', 'Õ': 'O', 'Ö':
'O', 'Ø': 'O', 'Ù': 'U', 'Ú': 'U', 'Û': 'U', 'Ü': 'U', 'Ý': 'Y', 'Þ': 'TH',
'ß': 'ss', 'à':'a', 'á':'a', 'â': 'a', 'ã': 'a', 'ä': 'a', 'å': 'a', 'æ':
'ae', 'ç': 'c', 'è': 'e', 'é': 'e', 'ê': 'e', 'ë': 'e', 'ì': 'i', 'í': 'i',
'î': 'i', 'ï': 'i', 'ð': 'o', 'ñ': 'n', 'ò': 'o', 'ó': 'o', 'ô': 'o', 'õ':
'o', 'ö': 'o', 'ø': 'o', 'ù': 'u', 'ú': 'u', 'û': 'u', 'ü': 'u', 'ý': 'y',
'þ': 'th', 'ÿ': 'y',
}
var LATIN_SYMBOLS_MAP =
{
'©':'(c)',
}
var GREEK_MAP =
{
'α':'a', 'β':'b', 'γ':'g', 'δ':'d', 'ε':'e', 'ζ':'z', 'η':'h', 'θ':'8',
'ι':'i', 'κ':'k', 'λ':'l', 'μ':'m', 'ν':'n', 'ξ':'3', 'ο':'o', 'π':'p',
'ρ':'r', 'σ':'s', 'τ':'t', 'υ':'y', 'φ':'f', 'χ':'x', 'ψ':'ps', 'ω':'w',
'ά':'a', 'έ':'e', 'ί':'i', 'ό':'o', 'ύ':'y', 'ή':'h', 'ώ':'w', 'ς':'s',
'ϊ':'i', 'ΰ':'y', 'ϋ':'y', 'ΐ':'i',
'Α':'A', 'Β':'B', 'Γ':'G', 'Δ':'D', 'Ε':'E', 'Ζ':'Z', 'Η':'H', 'Θ':'8',
'Ι':'I', 'Κ':'K', 'Λ':'L', 'Μ':'M', 'Ν':'N', 'Ξ':'3', 'Ο':'O', 'Π':'P',
'Ρ':'R', 'Σ':'S', 'Τ':'T', 'Υ':'Y', 'Φ':'F', 'Χ':'X', 'Ψ':'PS', 'Ω':'W',
'Ά':'A', 'Έ':'E', 'Ί':'I', 'Ό':'O', 'Ύ':'Y', 'Ή':'H', 'Ώ':'W', 'Ϊ':'I',
'Ϋ':'Y'
}
var TURKISH_MAP = {
'ş':'s', 'Ş':'S', 'ı':'i', 'İ':'I', 'ç':'c', 'Ç':'C', 'ü':'u', 'Ü':'U',
'ö':'o', 'Ö':'O', 'ğ':'g', 'Ğ':'G',
}
// var RUSSIAN_MAP =
// {
// }

var ALL_DOWNCODE_MAPS=new Array()
ALL_DOWNCODE_MAPS[0]=LATIN_MAP
ALL_DOWNCODE_MAPS[1]=LATIN_SYMBOLS_MAP
ALL_DOWNCODE_MAPS[2]=GREEK_MAP
ALL_DOWNCODE_MAPS[3]=TURKISH_MAP
//ALL_DOWNCODE_MAPS[4]=RUSSIAN_MAP

var Downcoder = new Object();
Downcoder.Initialize = function()
{
if (Downcoder.map) // already made
return ;
Downcoder.map ={}
Downcoder.chars = '' ;
for(var i in ALL_DOWNCODE_MAPS)
{
var lookup = ALL_DOWNCODE_MAPS[i]
for (var c in lookup)
{
Downcoder.map[c] = lookup[c] ;
Downcoder.chars += c ;
}
}
Downcoder.regex = new RegExp('[' + Downcoder.chars + ']|[^' + Downcoder.chars + ']+','g') ;
}

downcode= function( slug )
{
Downcoder.Initialize() ;
var downcoded =""
var pieces = slug.match(Downcoder.regex);
if(pieces)
{
for (var i = 0 ; i < pieces.length ; i++)
{
if (pieces[i].length == 1)
{
var mapped = Downcoder.map[pieces[i]] ;
if (mapped != null)
{
downcoded+=mapped;
continue ;
}
}
downcoded+=pieces[i];
}
}
else
{
downcoded = slug;
}
return downcoded;
}


function URLify(s, num_chars) {
// changes, e.g., "Petty theft" to "petty_theft"
// remove all these words from the string before urlifying
s = downcode(s);
removelist = ["a", "an", "as", "at", "before", "but", "by", "for", "from",
"is", "in", "into", "like", "of", "off", "on", "onto", "per",
"since", "than", "the", "this", "that", "to", "up", "via",
"with"];
r = new RegExp('\\b(' + removelist.join('|') + ')\\b', 'gi');
s = s.replace(r, '');
// if downcode doesn't hit, the char will be stripped here
s = s.replace(/[^-\w\s]/g, ''); // remove unneeded chars
s = s.replace(/^\s+|\s+$/g, ''); // trim leading/trailing spaces
s = s.replace(/[-\s]+/g, '-'); // convert spaces to hyphens
s = s.toLowerCase(); // convert to lowercase
return s.substring(0, num_chars);// trim to first num_chars chars
}

9 changes: 5 additions & 4 deletions django/contrib/admin/models.py
@@ -1,15 +1,16 @@
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import User
from django.utils.translation import gettext_lazy as _
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_unicode

ADDITION = 1
CHANGE = 2
DELETION = 3

class LogEntryManager(models.Manager):
def log_action(self, user_id, content_type_id, object_id, object_repr, action_flag, change_message=''):
e = self.model(None, None, user_id, content_type_id, str(object_id), object_repr[:200], action_flag, change_message)
e = self.model(None, None, user_id, content_type_id, smart_unicode(object_id), object_repr[:200], action_flag, change_message)
e.save()

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

def __repr__(self):
return str(self.action_time)
return smart_unicode(self.action_time)

def is_addition(self):
return self.action_flag == ADDITION
Expand All @@ -48,4 +49,4 @@ def get_admin_url(self):
Returns the admin URL to edit the object represented by this log entry.
This is relative to the Django admin index page.
"""
return "%s/%s/%s/" % (self.content_type.app_label, self.content_type.model, self.object_id)
return u"%s/%s/%s/" % (self.content_type.app_label, self.content_type.model, self.object_id)
2 changes: 1 addition & 1 deletion django/contrib/admin/templates/admin/filter.html
Expand Up @@ -3,6 +3,6 @@ <h3>{% blocktrans with title|escape as filter_title %} By {{ filter_title }} {%
<ul>
{% for choice in choices %}
<li{% if choice.selected %} class="selected"{% endif %}>
<a href="{{ choice.query_string }}">{{ choice.display|escape }}</a></li>
<a href="{{ choice.query_string|iriencode }}">{{ choice.display|escape }}</a></li>
{% endfor %}
</ul>
35 changes: 19 additions & 16 deletions django/contrib/admin/templatetags/admin_list.py
Expand Up @@ -6,7 +6,8 @@
from django.utils import dateformat
from django.utils.html import escape
from django.utils.text import capfirst
from django.utils.translation import get_date_formats, get_partial_date_formats
from django.utils.translation import get_date_formats, get_partial_date_formats, ugettext as _
from django.utils.encoding import smart_unicode, smart_str, force_unicode
from django.template import Library
import datetime

Expand All @@ -16,11 +17,11 @@

def paginator_number(cl,i):
if i == DOT:
return '... '
return u'... '
elif i == cl.page_num:
return '<span class="this-page">%d</span> ' % (i+1)
return u'<span class="this-page">%d</span> ' % (i+1)
else:
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)
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)
paginator_number = register.simple_tag(paginator_number)

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

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

def items_for_result(cl, result):
first = True
Expand All @@ -136,7 +139,7 @@ def items_for_result(cl, result):
allow_tags = True
result_repr = _boolean_icon(attr)
else:
result_repr = str(attr)
result_repr = smart_unicode(attr)
except (AttributeError, ObjectDoesNotExist):
result_repr = EMPTY_CHANGELIST_VALUE
else:
Expand Down Expand Up @@ -179,19 +182,19 @@ def items_for_result(cl, result):
elif f.choices:
result_repr = dict(f.choices).get(field_val, EMPTY_CHANGELIST_VALUE)
else:
result_repr = escape(str(field_val))
if result_repr == '':
result_repr = escape(field_val)
if force_unicode(result_repr) == '':
result_repr = '&nbsp;'
# 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:
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 ('<%s%s><a href="%s"%s>%s</a></%s>' % \
result_id = smart_unicode(getattr(result, pk)) # conversion to string is needed in case of 23L (long ints)
yield (u'<%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))
yield (u'<td%s>%s</td>' % (row_class, result_repr))

def results(cl):
for res in cl.result_list:
Expand Down

0 comments on commit 953badb

Please sign in to comment.