- diff --git a/django/utils/encoding.py b/django/utils/encoding.py
- index 7b80f13..25d4574 100644
- --- a/django/utils/encoding.py
- +++ b/django/utils/encoding.py
- @@ -94,7 +94,7 @@ def force_text(s, encoding='utf-8', strings_only=False, errors='strict'):
- if strings_only and is_protected_type(s):
- return s
- try:
- - if not isinstance(s, six.string_types):
- + if not isinstance(s, (bytes, six.string_types)):
- if hasattr(s, '__unicode__'):
- s = s.__unicode__()
- else:
- diff --git a/django/utils/translation/__init__.py b/django/utils/translation/__init__.py
- index febde40..39bcf2d 100644
- --- a/django/utils/translation/__init__.py
- +++ b/django/utils/translation/__init__.py
- @@ -79,8 +79,8 @@ def pgettext(context, message):
- def npgettext(context, singular, plural, number):
- return _trans.npgettext(context, singular, plural, number)
- -ngettext_lazy = lazy(ngettext, bytes)
- -gettext_lazy = lazy(gettext, bytes)
- +ngettext_lazy = lazy(ngettext, str)
- +gettext_lazy = lazy(gettext, str)
- ungettext_lazy = lazy(ungettext, six.text_type)
- ugettext_lazy = lazy(ugettext, six.text_type)
- pgettext_lazy = lazy(pgettext, six.text_type)
- diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py
- index 9e6eadc..3dbbd11 100644
- --- a/django/utils/translation/trans_real.py
- +++ b/django/utils/translation/trans_real.py
- @@ -9,7 +9,7 @@ import gettext as gettext_module
- from threading import local
- from django.utils.importlib import import_module
- -from django.utils.encoding import smart_str, smart_text
- +from django.utils.encoding import force_text, smart_str, smart_text
- from django.utils.safestring import mark_safe, SafeData
- from django.utils import six
- from django.utils.six import StringIO
- @@ -261,10 +261,10 @@ def do_translate(message, translation_function):
- def gettext(message):
- return do_translate(message, 'gettext')
- -if six.PY3:
- - ugettext = gettext
- -else:
- - def ugettext(message):
- +def ugettext(message):
- + if six.PY3:
- + return do_translate(force_text(message), 'gettext')
- + else:
- return do_translate(message, 'ugettext')
- def pgettext(context, message):
- @@ -301,14 +301,10 @@ def ngettext(singular, plural, number):
- """
- return do_ntranslate(singular, plural, number, 'ngettext')
- -if six.PY3:
- - ungettext = ngettext
- -else:
- - def ungettext(singular, plural, number):
- - """
- - Returns a unicode strings of the translation of either the singular or
- - plural, based on the number.
- - """
- +def ungettext(singular, plural, number):
- + if six.PY3:
- + return do_ntranslate(force_text(singular), force_text(plural), number, 'ngettext')
- + else:
- return do_ntranslate(singular, plural, number, 'ungettext')
- def npgettext(context, singular, plural, number):
- diff --git a/tests/regressiontests/i18n/tests.py b/tests/regressiontests/i18n/tests.py
- index 9ca66bd..9332c20 100644
- --- a/tests/regressiontests/i18n/tests.py
- +++ b/tests/regressiontests/i18n/tests.py
- @@ -236,8 +236,18 @@ class TranslationTests(TestCase):
- self.assertEqual(SafeString, type(s))
- with translation.override('de', deactivate=True):
- self.assertEqual(SafeUnicode, type(ugettext(s)))
- - self.assertEqual('aPassword', SafeString('a') + s)
- - self.assertEqual('Passworda', s + SafeString('a'))
- + self.assertEqual(b'aPassword', SafeString(b'a') + s)
- + self.assertEqual(b'Passworda', s + SafeString(b'a'))
- + self.assertEqual(b'Passworda', s + mark_safe(b'a'))
- + self.assertEqual(b'aPassword', mark_safe(b'a') + s)
- + self.assertEqual(b'as', mark_safe(b'a') + mark_safe(b's'))
- + # Same tests for SafeUnicode
- + s = mark_safe('Password')
- + self.assertEqual(SafeUnicode, type(s))
- + with translation.override('de', deactivate=True):
- + self.assertEqual(SafeUnicode, type(ugettext(s)))
- + self.assertEqual('aPassword', SafeUnicode('a') + s)
- + self.assertEqual('Passworda', s + SafeUnicode('a'))
- self.assertEqual('Passworda', s + mark_safe('a'))
- self.assertEqual('aPassword', mark_safe('a') + s)
- self.assertEqual('as', mark_safe('a') + mark_safe('s'))