diff --git a/localized_fields/value.py b/localized_fields/value.py index ce88304..b2c30b9 100644 --- a/localized_fields/value.py +++ b/localized_fields/value.py @@ -1,5 +1,7 @@ import collections +from typing import Optional + from django.conf import settings from django.utils import translation @@ -98,10 +100,10 @@ class LocalizedValue(dict): for val in value: self._interpret_value(val) - def __str__(self) -> str: - """Gets the value in the current language, or falls - back to the primary language if there's no value - in the current language.""" + def translate(self) -> Optional[str]: + """Gets the value in the current language or falls + back to the next language if there's no value in the + current language.""" fallbacks = getattr(settings, 'LOCALIZED_FIELDS_FALLBACKS', {}) @@ -112,9 +114,16 @@ class LocalizedValue(dict): for lang_code in languages: value = self.get(lang_code) if value: - return value or '' + return value or None - return '' + return None + + def __str__(self) -> str: + """Gets the value in the current language or falls + back to the next language if there's no value in the + current language.""" + + return self.translate() or '' def __eq__(self, other): """Compares :paramref:self to :paramref:other for diff --git a/tests/test_value.py b/tests/test_value.py index 10b4674..e722a46 100644 --- a/tests/test_value.py +++ b/tests/test_value.py @@ -1,7 +1,7 @@ -from django.conf import settings -from django.test import TestCase -from django.utils import translation from django.db.models import F +from django.conf import settings +from django.utils import translation +from django.test import TestCase, override_settings from localized_fields.value import LocalizedValue @@ -90,18 +90,6 @@ class LocalizedValueTestCase(TestCase): assert localized_value.get(language) == value assert getattr(localized_value, language) == value - @staticmethod - def test_str(): - """Tests whether the :see:LocalizedValue - class's __str__ works properly.""" - - keys = get_init_values() - localized_value = LocalizedValue(keys) - - for language, value in keys.items(): - translation.activate(language) - assert str(localized_value) == value - @staticmethod def test_eq(): """Tests whether the __eq__ operator @@ -116,9 +104,21 @@ class LocalizedValueTestCase(TestCase): assert a != b @staticmethod - def test_str_fallback(): + def test_translate(): """Tests whether the :see:LocalizedValue - class's __str__'s fallback functionality + class's __str__ works properly.""" + + keys = get_init_values() + localized_value = LocalizedValue(keys) + + for language, value in keys.items(): + translation.activate(language) + assert localized_value.translate() == value + + @staticmethod + def test_translate_fallback(): + """Tests whether the :see:LocalizedValue + class's translate()'s fallback functionality works properly.""" test_value = 'myvalue' @@ -131,13 +131,13 @@ class LocalizedValueTestCase(TestCase): # make sure that, by default it returns # the value in the default language - assert str(localized_value) == test_value + assert localized_value.translate() == test_value # make sure that it falls back to the # primary language when there's no value # available in the current language translation.activate(other_language) - assert str(localized_value) == test_value + assert localized_value.translate() == test_value # make sure that it's just __str__ falling # back and that for the other language @@ -145,12 +145,35 @@ class LocalizedValueTestCase(TestCase): assert localized_value.get(other_language) != test_value @staticmethod - def test_str_fallback_custom_fallback(): + def test_translate_none(): + """Tests whether the :see:LocalizedValue + class's translate() method properly returns + None when there is no value.""" + + # with no value, we always expect it to return None + localized_value = LocalizedValue() + assert localized_value.translate() == None + assert str(localized_value) == '' + + # with no value for the default language, the default + # behavior is to return None, unless a custom fallback + # chain is configured, which there is not for this test + other_language = settings.LANGUAGES[-1][0] + localized_value = LocalizedValue({ + other_language: 'hey' + }) + + translation.activate(settings.LANGUAGE_CODE) + assert localized_value.translate() == None + assert str(localized_value) == '' + + @staticmethod + def test_translate_fallback_custom_fallback(): """Tests whether the :see:LocalizedValue class's - __str__'s fallback functionality properly respects + translate()'s fallback functionality properly respects the LOCALIZED_FIELDS_FALLBACKS setting.""" - settings.LOCALIZED_FIELDS_FALLBACKS = { + fallbacks = { 'nl': ['ro'] } @@ -159,8 +182,9 @@ class LocalizedValueTestCase(TestCase): 'ro': 'ro' }) - with translation.override('nl'): - assert str(localized_value) == 'ro' + with override_settings(LOCALIZED_FIELDS_FALLBACKS=fallbacks): + with translation.override('nl'): + assert localized_value.translate() == 'ro' @staticmethod def test_deconstruct():