diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py index 3d94f22348..dd40ac5de2 100644 --- a/django/utils/translation/trans_real.py +++ b/django/utils/translation/trans_real.py @@ -292,15 +292,20 @@ def do_translate(message, translation_function): # str() is allowing a bytestring message to remain bytestring on Python 2 eol_message = message.replace(str('\r\n'), str('\n')).replace(str('\r'), str('\n')) - t = getattr(_active, "value", None) - if t is not None: - result = getattr(t, translation_function)(eol_message) + + if len(eol_message) == 0: + # Returns an empty value of the corresponding type if an empty message + # is given, instead of metadata, which is the default gettext behavior. + result = type(message)("") else: - if _default is None: - _default = translation(settings.LANGUAGE_CODE) - result = getattr(_default, translation_function)(eol_message) + _default = _default or translation(settings.LANGUAGE_CODE) + translation_object = getattr(_active, "value", _default) + + result = getattr(translation_object, translation_function)(eol_message) + if isinstance(message, SafeData): return mark_safe(result) + return result diff --git a/tests/i18n/tests.py b/tests/i18n/tests.py index 321f3b17e2..9cf979ab16 100644 --- a/tests/i18n/tests.py +++ b/tests/i18n/tests.py @@ -345,6 +345,16 @@ class TranslationTests(TestCase): """ self.assertEqual('django', six.text_type(string_concat("dja", "ngo"))) + def test_empty_value(self): + """ + Empty value must stay empty after being translated (#23196). + """ + with translation.override('de'): + self.assertEqual("", ugettext("")) + self.assertEqual(b"", gettext(b"")) + s = mark_safe("") + self.assertEqual(s, ugettext(s)) + def test_safe_status(self): """ Translating a string requiring no auto-escaping shouldn't change the "safe" status.