Add LocalizedValue.translate()

LocalizedValue.translate() behaves the exact same as the str(..) cast
works, with the exception that it returns None if there is no value
instead of an empty string. This makes it easier to implement custom
value classes on top of the LocalizedValue class.

Behavior for str(..) stays the same as it was.
This commit is contained in:
Swen Kooij 2018-06-14 07:57:02 +03:00
parent db4324fbf3
commit def7dae640
2 changed files with 63 additions and 30 deletions

View File

@ -1,5 +1,7 @@
import collections import collections
from typing import Optional
from django.conf import settings from django.conf import settings
from django.utils import translation from django.utils import translation
@ -98,10 +100,10 @@ class LocalizedValue(dict):
for val in value: for val in value:
self._interpret_value(val) self._interpret_value(val)
def __str__(self) -> str: def translate(self) -> Optional[str]:
"""Gets the value in the current language, or falls """Gets the value in the current language or falls
back to the primary language if there's no value back to the next language if there's no value in the
in the current language.""" current language."""
fallbacks = getattr(settings, 'LOCALIZED_FIELDS_FALLBACKS', {}) fallbacks = getattr(settings, 'LOCALIZED_FIELDS_FALLBACKS', {})
@ -112,9 +114,16 @@ class LocalizedValue(dict):
for lang_code in languages: for lang_code in languages:
value = self.get(lang_code) value = self.get(lang_code)
if value: 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): def __eq__(self, other):
"""Compares :paramref:self to :paramref:other for """Compares :paramref:self to :paramref:other for

View File

@ -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.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 from localized_fields.value import LocalizedValue
@ -90,18 +90,6 @@ class LocalizedValueTestCase(TestCase):
assert localized_value.get(language) == value assert localized_value.get(language) == value
assert getattr(localized_value, 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 @staticmethod
def test_eq(): def test_eq():
"""Tests whether the __eq__ operator """Tests whether the __eq__ operator
@ -116,9 +104,21 @@ class LocalizedValueTestCase(TestCase):
assert a != b assert a != b
@staticmethod @staticmethod
def test_str_fallback(): def test_translate():
"""Tests whether the :see:LocalizedValue """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.""" works properly."""
test_value = 'myvalue' test_value = 'myvalue'
@ -131,13 +131,13 @@ class LocalizedValueTestCase(TestCase):
# make sure that, by default it returns # make sure that, by default it returns
# the value in the default language # 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 # make sure that it falls back to the
# primary language when there's no value # primary language when there's no value
# available in the current language # available in the current language
translation.activate(other_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 # make sure that it's just __str__ falling
# back and that for the other language # back and that for the other language
@ -145,12 +145,35 @@ class LocalizedValueTestCase(TestCase):
assert localized_value.get(other_language) != test_value assert localized_value.get(other_language) != test_value
@staticmethod @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 """Tests whether the :see:LocalizedValue class's
__str__'s fallback functionality properly respects translate()'s fallback functionality properly respects
the LOCALIZED_FIELDS_FALLBACKS setting.""" the LOCALIZED_FIELDS_FALLBACKS setting."""
settings.LOCALIZED_FIELDS_FALLBACKS = { fallbacks = {
'nl': ['ro'] 'nl': ['ro']
} }
@ -159,8 +182,9 @@ class LocalizedValueTestCase(TestCase):
'ro': 'ro' 'ro': 'ro'
}) })
with override_settings(LOCALIZED_FIELDS_FALLBACKS=fallbacks):
with translation.override('nl'): with translation.override('nl'):
assert str(localized_value) == 'ro' assert localized_value.translate() == 'ro'
@staticmethod @staticmethod
def test_deconstruct(): def test_deconstruct():