mirror of https://github.com/django/django.git
Fixed #30892 -- Fixed slugify() and admin's URLify.js for "İ".
Thanks Luis Nell for the implementation idea and very detailed report. Co-Authored-By: Mariusz Felisiak <felisiak.mariusz@gmail.com>
This commit is contained in:
parent
cf5d4701dc
commit
b2bd08bb7a
1
AUTHORS
1
AUTHORS
|
@ -185,6 +185,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
Christian Metts
|
Christian Metts
|
||||||
Christian Oudard <christian.oudard@gmail.com>
|
Christian Oudard <christian.oudard@gmail.com>
|
||||||
Christian Tanzer <tanzer@swing.co.at>
|
Christian Tanzer <tanzer@swing.co.at>
|
||||||
|
Christoffer Sjöbergsson
|
||||||
Christophe Pettus <xof@thebuild.com>
|
Christophe Pettus <xof@thebuild.com>
|
||||||
Christopher Adams <http://christopheradams.info>
|
Christopher Adams <http://christopheradams.info>
|
||||||
Christopher Babiak <chrisbabiak@gmail.com>
|
Christopher Babiak <chrisbabiak@gmail.com>
|
||||||
|
|
|
@ -177,6 +177,7 @@
|
||||||
var r = new RegExp('\\b(' + removeList.join('|') + ')\\b', 'gi');
|
var r = new RegExp('\\b(' + removeList.join('|') + ')\\b', 'gi');
|
||||||
s = s.replace(r, '');
|
s = s.replace(r, '');
|
||||||
}
|
}
|
||||||
|
s = s.toLowerCase(); // convert to lowercase
|
||||||
// if downcode doesn't hit, the char will be stripped here
|
// if downcode doesn't hit, the char will be stripped here
|
||||||
if (allowUnicode) {
|
if (allowUnicode) {
|
||||||
// Keep Unicode letters including both lowercase and uppercase
|
// Keep Unicode letters including both lowercase and uppercase
|
||||||
|
@ -189,7 +190,7 @@
|
||||||
s = s.replace(/[-\s]+/g, '-'); // convert spaces to hyphens
|
s = s.replace(/[-\s]+/g, '-'); // convert spaces to hyphens
|
||||||
s = s.substring(0, num_chars); // trim to first num_chars chars
|
s = s.substring(0, num_chars); // trim to first num_chars chars
|
||||||
s = s.replace(/-+$/g, ''); // trim any trailing hyphens
|
s = s.replace(/-+$/g, ''); // trim any trailing hyphens
|
||||||
return s.toLowerCase(); // convert to lowercase
|
return s;
|
||||||
}
|
}
|
||||||
window.URLify = URLify;
|
window.URLify = URLify;
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -402,7 +402,7 @@ def slugify(value, allow_unicode=False):
|
||||||
value = unicodedata.normalize('NFKC', value)
|
value = unicodedata.normalize('NFKC', value)
|
||||||
else:
|
else:
|
||||||
value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore').decode('ascii')
|
value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore').decode('ascii')
|
||||||
value = re.sub(r'[^\w\s-]', '', value).strip().lower()
|
value = re.sub(r'[^\w\s-]', '', value.lower()).strip()
|
||||||
return re.sub(r'[-\s]+', '-', value)
|
return re.sub(r'[-\s]+', '-', value)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -830,10 +830,10 @@ appropriate entities.
|
||||||
Converts a string to a URL slug by:
|
Converts a string to a URL slug by:
|
||||||
|
|
||||||
#. Converting to ASCII if ``allow_unicode`` is ``False`` (the default).
|
#. Converting to ASCII if ``allow_unicode`` is ``False`` (the default).
|
||||||
|
#. Converting to lowercase.
|
||||||
#. Removing characters that aren't alphanumerics, underscores, hyphens, or
|
#. Removing characters that aren't alphanumerics, underscores, hyphens, or
|
||||||
whitespace.
|
whitespace.
|
||||||
#. Removing leading and trailing whitespace.
|
#. Removing leading and trailing whitespace.
|
||||||
#. Converting to lowercase.
|
|
||||||
#. Replacing any whitespace or repeated dashes with single dashes.
|
#. Replacing any whitespace or repeated dashes with single dashes.
|
||||||
|
|
||||||
For example::
|
For example::
|
||||||
|
|
|
@ -4442,13 +4442,13 @@ class SeleniumTests(AdminSeleniumTestCase):
|
||||||
# Main form ----------------------------------------------------------
|
# Main form ----------------------------------------------------------
|
||||||
self.selenium.find_element_by_id('id_pubdate').send_keys('2012-02-18')
|
self.selenium.find_element_by_id('id_pubdate').send_keys('2012-02-18')
|
||||||
self.select_option('#id_status', 'option two')
|
self.select_option('#id_status', 'option two')
|
||||||
self.selenium.find_element_by_id('id_name').send_keys(' this is the mAin nÀMë and it\'s awεšomeııı')
|
self.selenium.find_element_by_id('id_name').send_keys(' this is the mAin nÀMë and it\'s awεšomeıııİ')
|
||||||
slug1 = self.selenium.find_element_by_id('id_slug1').get_attribute('value')
|
slug1 = self.selenium.find_element_by_id('id_slug1').get_attribute('value')
|
||||||
slug2 = self.selenium.find_element_by_id('id_slug2').get_attribute('value')
|
slug2 = self.selenium.find_element_by_id('id_slug2').get_attribute('value')
|
||||||
slug3 = self.selenium.find_element_by_id('id_slug3').get_attribute('value')
|
slug3 = self.selenium.find_element_by_id('id_slug3').get_attribute('value')
|
||||||
self.assertEqual(slug1, 'main-name-and-its-awesomeiii-2012-02-18')
|
self.assertEqual(slug1, 'main-name-and-its-awesomeiiii-2012-02-18')
|
||||||
self.assertEqual(slug2, 'option-two-main-name-and-its-awesomeiii')
|
self.assertEqual(slug2, 'option-two-main-name-and-its-awesomeiiii')
|
||||||
self.assertEqual(slug3, 'this-is-the-main-n\xe0m\xeb-and-its-aw\u03b5\u0161ome\u0131\u0131\u0131')
|
self.assertEqual(slug3, 'this-is-the-main-n\xe0m\xeb-and-its-aw\u03b5\u0161ome\u0131\u0131\u0131i')
|
||||||
|
|
||||||
# Stacked inlines ----------------------------------------------------
|
# Stacked inlines ----------------------------------------------------
|
||||||
# Initial inline
|
# Initial inline
|
||||||
|
@ -4526,11 +4526,12 @@ class SeleniumTests(AdminSeleniumTestCase):
|
||||||
self.selenium.find_element_by_xpath('//input[@value="Save"]').click()
|
self.selenium.find_element_by_xpath('//input[@value="Save"]').click()
|
||||||
self.assertEqual(MainPrepopulated.objects.all().count(), 1)
|
self.assertEqual(MainPrepopulated.objects.all().count(), 1)
|
||||||
MainPrepopulated.objects.get(
|
MainPrepopulated.objects.get(
|
||||||
name=' this is the mAin nÀMë and it\'s awεšomeııı',
|
name=' this is the mAin nÀMë and it\'s awεšomeıııİ',
|
||||||
pubdate='2012-02-18',
|
pubdate='2012-02-18',
|
||||||
status='option two',
|
status='option two',
|
||||||
slug1='main-name-and-its-awesomeiii-2012-02-18',
|
slug1='main-name-and-its-awesomeiiii-2012-02-18',
|
||||||
slug2='option-two-main-name-and-its-awesomeiii',
|
slug2='option-two-main-name-and-its-awesomeiiii',
|
||||||
|
slug3='this-is-the-main-nàmë-and-its-awεšomeıııi',
|
||||||
)
|
)
|
||||||
self.assertEqual(RelatedPrepopulated.objects.all().count(), 4)
|
self.assertEqual(RelatedPrepopulated.objects.all().count(), 4)
|
||||||
RelatedPrepopulated.objects.get(
|
RelatedPrepopulated.objects.get(
|
||||||
|
|
|
@ -196,6 +196,7 @@ class TestUtilsText(SimpleTestCase):
|
||||||
('foo ıç bar', 'foo-ıç-bar', True),
|
('foo ıç bar', 'foo-ıç-bar', True),
|
||||||
(' foo ıç bar', 'foo-ıç-bar', True),
|
(' foo ıç bar', 'foo-ıç-bar', True),
|
||||||
('你好', '你好', True),
|
('你好', '你好', True),
|
||||||
|
('İstanbul', 'istanbul', True),
|
||||||
)
|
)
|
||||||
for value, output, is_unicode in items:
|
for value, output, is_unicode in items:
|
||||||
self.assertEqual(text.slugify(value, allow_unicode=is_unicode), output)
|
self.assertEqual(text.slugify(value, allow_unicode=is_unicode), output)
|
||||||
|
|
Loading…
Reference in New Issue