diff --git a/django/utils/translation/__init__.py b/django/utils/translation/__init__.py
index febde40..673a783 100644
--- a/django/utils/translation/__init__.py
+++ b/django/utils/translation/__init__.py
@@ -64,14 +64,12 @@ ugettext_noop = gettext_noop
 def gettext(message):
     return _trans.gettext(message)
 
+ugettext = gettext
+
 def ngettext(singular, plural, number):
     return _trans.ngettext(singular, plural, number)
 
-def ugettext(message):
-    return _trans.ugettext(message)
-
-def ungettext(singular, plural, number):
-    return _trans.ungettext(singular, plural, number)
+ungettext = ngettext
 
 def pgettext(context, message):
     return _trans.pgettext(context, message)
@@ -79,10 +77,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)
-ungettext_lazy = lazy(ungettext, six.text_type)
-ugettext_lazy = lazy(ugettext, six.text_type)
+ungettext_lazy = ngettext_lazy = lazy(ngettext, six.text_type)
+ugettext_lazy = gettext_lazy = lazy(gettext, six.text_type)
 pgettext_lazy = lazy(pgettext, six.text_type)
 npgettext_lazy = lazy(npgettext, six.text_type)
 
diff --git a/django/utils/translation/trans_null.py b/django/utils/translation/trans_null.py
index 5c51468..92d1205 100644
--- a/django/utils/translation/trans_null.py
+++ b/django/utils/translation/trans_null.py
@@ -7,18 +7,15 @@ from django.utils.encoding import force_text
 from django.utils.safestring import mark_safe, SafeData
 
 def ngettext(singular, plural, number):
-    if number == 1: return singular
-    return plural
-ngettext_lazy = ngettext
-
-def ungettext(singular, plural, number):
-    return force_text(ngettext(singular, plural, number))
+    if number == 1: return force_text(singular)
+    return force_text(plural)
+ngettext_lazy = ungettext = ngettext
 
 def pgettext(context, message):
-    return ugettext(message)
+    return gettext(message)
 
 def npgettext(context, singular, plural, number):
-    return ungettext(singular, plural, number)
+    return ngettext(singular, plural, number)
 
 activate = lambda x: None
 deactivate = deactivate_all = lambda: None
@@ -38,15 +35,12 @@ TECHNICAL_ID_MAP = {
 }
 
 def gettext(message):
-    result = TECHNICAL_ID_MAP.get(message, message)
+    result = TECHNICAL_ID_MAP.get(message, force_text(message))
     if isinstance(message, SafeData):
         return mark_safe(result)
     return result
 
-def ugettext(message):
-    return force_text(gettext(message))
-
-gettext_noop = gettext_lazy = _ = gettext
+gettext_noop = gettext_lazy = ugettext = _ = gettext
 
 def to_locale(language):
     p = language.find('-')
diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py
index 9e6eadc..afb3160 100644
--- a/django/utils/translation/trans_real.py
+++ b/django/utils/translation/trans_real.py
@@ -259,14 +259,13 @@ def do_translate(message, translation_function):
     return result
 
 def gettext(message):
-    return do_translate(message, 'gettext')
-
-if six.PY3:
-    ugettext = gettext
-else:
-    def ugettext(message):
+    if six.PY3:
+        return do_translate(message, 'gettext')
+    else:
         return do_translate(message, 'ugettext')
 
+ugettext = gettext
+
 def pgettext(context, message):
     result = ugettext("%s%s%s" % (context, CONTEXT_SEPARATOR, message))
     if CONTEXT_SEPARATOR in result:
@@ -296,21 +295,16 @@ def do_ntranslate(singular, plural, number, translation_function):
 
 def ngettext(singular, plural, number):
     """
-    Returns a UTF-8 bytestring of the translation of either the singular or
+    Returns a unicode string of the translation of either the singular or
     plural, based on the 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.
-        """
+    if six.PY3:
+        return do_ntranslate(singular, plural, number, 'ngettext')
+    else:
         return do_ntranslate(singular, plural, number, 'ungettext')
 
+ungettext = ngettext
+
 def npgettext(context, singular, plural, number):
     result = ungettext("%s%s%s" % (context, CONTEXT_SEPARATOR, singular),
                        "%s%s%s" % (context, CONTEXT_SEPARATOR, plural),
diff --git a/docs/ref/utils.txt b/docs/ref/utils.txt
index 97643c2..6c3e99d 100644
--- a/docs/ref/utils.txt
+++ b/docs/ref/utils.txt
@@ -595,13 +595,15 @@ For a complete discussion on the usage of the following see the
 :doc:`translation documentation </topics/i18n/translation>`.
 
 .. function:: gettext(message)
-
-    Translates ``message`` and returns it in a UTF-8 bytestring
-
 .. function:: ugettext(message)
 
     Translates ``message`` and returns it in a unicode string
 
+    .. versionchanged:: 1.5
+
+    ``gettext`` used to return an UTF8-encoded string. Both ``gettext`` and
+    ``ugettext`` return now Unicode.
+
 .. function:: pgettext(context, message)
 
     Translates ``message`` given the ``context`` and returns
