summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--oslo_i18n/_message.py20
-rw-r--r--oslo_i18n/tests/test_message.py15
2 files changed, 35 insertions, 0 deletions
diff --git a/oslo_i18n/_message.py b/oslo_i18n/_message.py
index 0bd83c5..6ea94bc 100644
--- a/oslo_i18n/_message.py
+++ b/oslo_i18n/_message.py
@@ -78,6 +78,26 @@ class Message(six.text_type):
:returns: the translated message in unicode
"""
+ # We did a bad thing here. We shadowed the unicode built-in translate,
+ # which means there are circumstances where this function may be called
+ # with a desired_locale that is a non-string sequence or mapping type.
+ # This will not only result in incorrect behavior, it also fails
+ # because things like lists are not hashable, and we use the value in
+ # desired_locale as part of a dict key. If we see a non-string
+ # desired_locale, we know that the caller did not intend to call this
+ # form of translate and we should instead pass that along to the
+ # unicode implementation of translate.
+ #
+ # Unfortunately this doesn't entirely solve the problem as it would be
+ # possible for a caller to use a string as the mapping type and in that
+ # case we can't tell which version of translate they intended to call.
+ # That doesn't seem to be a common thing to do though. str.maketrans
+ # returns a dict, and that is probably the way most callers will create
+ # their mapping.
+ if (desired_locale is not None and
+ not isinstance(desired_locale, six.string_types)):
+ return super(Message, self).translate(desired_locale)
+
translated_message = Message._translate_msgid(self.msgid,
self.domain,
desired_locale,
diff --git a/oslo_i18n/tests/test_message.py b/oslo_i18n/tests/test_message.py
index 559e5d0..629238a 100644
--- a/oslo_i18n/tests/test_message.py
+++ b/oslo_i18n/tests/test_message.py
@@ -616,6 +616,21 @@ class MessageTestCase(test_base.BaseTestCase):
self.assertEqual(zh_translation, msg.translate('zh'))
self.assertEqual(fr_translation, msg.translate('fr'))
+ def test_translate_with_dict(self):
+ msg = _message.Message('abc')
+ # This dict is what you get back from str.maketrans('abc', 'xyz')
+ # We can't actually call that here because it doesn't exist on py2
+ # and the string.maketrans that does behaves differently.
+ self.assertEqual('xyz', msg.translate({97: 120, 98: 121, 99: 122}))
+
+ def test_translate_with_list(self):
+ msg = _message.Message('abc')
+ table = [six.unichr(x) for x in range(128)]
+ table[ord('a')] = 'b'
+ table[ord('b')] = 'c'
+ table[ord('c')] = 'd'
+ self.assertEqual('bcd', msg.translate(table))
+
class TranslateMsgidTest(test_base.BaseTestCase):