Deprecate Message.translate in favor of Message.translation
It shadows the unicode function of the same name, and there's no way to entirely disambiguate the two based on the parameter passed in. This change deprecates Message.translate and makes it a wrapper around the new function, Message.translation. Note that we never documented calling Message.translate directly. The documented way to get the translated form of a Message is to call the _translate.translate function in this project, so chances are that this public API change will have little actual impact on users. Change-Id: I0c617937f5af7467d1454f72acd0474ae2ce0293 Closes-Bug: 1841796
This commit is contained in:
parent
f8fa059c46
commit
2249925846
@ -69,15 +69,12 @@ class Message(six.text_type):
|
||||
return msg
|
||||
|
||||
def translate(self, desired_locale=None):
|
||||
"""Translate this message to the desired locale.
|
||||
"""DEPRECATED: Use ``translation`` instead
|
||||
|
||||
:param desired_locale: The desired locale to translate the message to,
|
||||
if no locale is provided the message will be
|
||||
translated to the system's default locale.
|
||||
|
||||
:returns: the translated message in unicode
|
||||
This is a compatibility shim to allow callers a chance to move away
|
||||
from using this function, which shadows a built-in function from our
|
||||
parent class.
|
||||
"""
|
||||
|
||||
# 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.
|
||||
@ -97,7 +94,24 @@ class Message(six.text_type):
|
||||
if (desired_locale is not None and
|
||||
not isinstance(desired_locale, six.string_types)):
|
||||
return super(Message, self).translate(desired_locale)
|
||||
warnings.warn('Message.translate called with a string argument. '
|
||||
'If your intent was to translate the message into '
|
||||
'another language, please call Message.translation '
|
||||
'instead. If your intent was to call "translate" as '
|
||||
'defined by the str/unicode type, please use a dict or '
|
||||
'list mapping instead. String mappings will not work '
|
||||
'until this compatibility shim is removed.')
|
||||
return self.translation(desired_locale)
|
||||
|
||||
def translation(self, desired_locale=None):
|
||||
"""Translate this message to the desired locale.
|
||||
|
||||
:param desired_locale: The desired locale to translate the message to,
|
||||
if no locale is provided the message will be
|
||||
translated to the system's default locale.
|
||||
|
||||
:returns: the translated message in unicode
|
||||
"""
|
||||
translated_message = Message._translate_msgid(self.msgid,
|
||||
self.domain,
|
||||
desired_locale,
|
||||
|
@ -45,7 +45,7 @@ def translate(obj, desired_locale=None):
|
||||
if isinstance(message, _message.Message):
|
||||
# Even after unicoding() we still need to check if we are
|
||||
# running with translatable unicode before translating
|
||||
return message.translate(desired_locale)
|
||||
return message.translation(desired_locale)
|
||||
return obj
|
||||
|
||||
|
||||
|
@ -65,11 +65,11 @@ class MessageTestCase(test_base.BaseTestCase):
|
||||
# The base representation of the message is in Spanish, as well as
|
||||
# the default translation, since the default locale was Spanish.
|
||||
self.assertEqual(es_translation, message)
|
||||
self.assertEqual(es_translation, message.translate())
|
||||
self.assertEqual(es_translation, message.translation())
|
||||
|
||||
def test_translate_returns_unicode(self):
|
||||
def test_translation_returns_unicode(self):
|
||||
message = _message.Message('some %s') % 'message'
|
||||
self.assertIsInstance(message.translate(), six.text_type)
|
||||
self.assertIsInstance(message.translation(), six.text_type)
|
||||
|
||||
def test_mod_with_named_parameters(self):
|
||||
msgid = ("%(description)s\nCommand: %(cmd)s\n"
|
||||
@ -86,7 +86,7 @@ class MessageTestCase(test_base.BaseTestCase):
|
||||
|
||||
expected = msgid % params
|
||||
self.assertEqual(expected, result)
|
||||
self.assertEqual(expected, result.translate())
|
||||
self.assertEqual(expected, result.translation())
|
||||
|
||||
def test_multiple_mod_with_named_parameter(self):
|
||||
msgid = ("%(description)s\nCommand: %(cmd)s\n"
|
||||
@ -131,7 +131,7 @@ class MessageTestCase(test_base.BaseTestCase):
|
||||
self.assertIsNot(expected, first)
|
||||
|
||||
# Final translations should be the same
|
||||
self.assertEqual(expected.translate(), first.translate())
|
||||
self.assertEqual(expected.translation(), first.translation())
|
||||
|
||||
def test_mod_with_named_parameters_no_space(self):
|
||||
msgid = ("Request: %(method)s http://%(server)s:"
|
||||
@ -146,7 +146,7 @@ class MessageTestCase(test_base.BaseTestCase):
|
||||
|
||||
expected = msgid % params
|
||||
self.assertEqual(expected, result)
|
||||
self.assertEqual(expected, result.translate())
|
||||
self.assertEqual(expected, result.translation())
|
||||
|
||||
def test_mod_with_dict_parameter(self):
|
||||
msgid = "Test that we can inject a dictionary %s"
|
||||
@ -156,7 +156,7 @@ class MessageTestCase(test_base.BaseTestCase):
|
||||
|
||||
expected = msgid % params
|
||||
self.assertEqual(expected, result)
|
||||
self.assertEqual(expected, result.translate())
|
||||
self.assertEqual(expected, result.translation())
|
||||
|
||||
def test_mod_with_wrong_field_type_in_trans(self):
|
||||
msgid = "Correct type %(arg1)s"
|
||||
@ -174,7 +174,7 @@ class MessageTestCase(test_base.BaseTestCase):
|
||||
trans.return_value.gettext.return_value = wrong_type
|
||||
else:
|
||||
trans.return_value.ugettext.return_value = wrong_type
|
||||
trans_result = result.translate()
|
||||
trans_result = result.translation()
|
||||
expected = msgid % params
|
||||
self.assertEqual(expected, trans_result)
|
||||
|
||||
@ -204,10 +204,10 @@ class MessageTestCase(test_base.BaseTestCase):
|
||||
|
||||
for message, result in zip(messages, results):
|
||||
self.assertEqual(type(result), _message.Message)
|
||||
self.assertEqual(message, result.translate())
|
||||
self.assertEqual(message, result.translation())
|
||||
|
||||
# simulate writing out as string
|
||||
result_str = '%s' % result.translate()
|
||||
result_str = '%s' % result.translation()
|
||||
self.assertEqual(result_str, message)
|
||||
self.assertEqual(message, result)
|
||||
|
||||
@ -220,7 +220,7 @@ class MessageTestCase(test_base.BaseTestCase):
|
||||
changing_dict['current_value'] = 2
|
||||
# Even if the param changes when the message is
|
||||
# translated it should use the original param
|
||||
self.assertEqual('Found object: 1', result.translate())
|
||||
self.assertEqual('Found object: 1', result.translation())
|
||||
|
||||
def test_mod_deep_copies_parameters(self):
|
||||
msgid = "Found list: %(current_list)s"
|
||||
@ -232,26 +232,26 @@ class MessageTestCase(test_base.BaseTestCase):
|
||||
changing_list.append(4)
|
||||
# Even though the list changed the message
|
||||
# translation should use the original list
|
||||
self.assertEqual("Found list: [1, 2, 3]", result.translate())
|
||||
self.assertEqual("Found list: [1, 2, 3]", result.translation())
|
||||
|
||||
def test_mod_deep_copies_param_nodeep_param(self):
|
||||
msgid = "Value: %s"
|
||||
params = utils.NoDeepCopyObject(5)
|
||||
# Apply the params
|
||||
result = _message.Message(msgid) % params
|
||||
self.assertEqual("Value: 5", result.translate())
|
||||
self.assertEqual("Value: 5", result.translation())
|
||||
|
||||
def test_mod_deep_copies_param_nodeep_dict(self):
|
||||
msgid = "Values: %(val1)s %(val2)s"
|
||||
params = {'val1': 1, 'val2': utils.NoDeepCopyObject(2)}
|
||||
# Apply the params
|
||||
result = _message.Message(msgid) % params
|
||||
self.assertEqual("Values: 1 2", result.translate())
|
||||
self.assertEqual("Values: 1 2", result.translation())
|
||||
|
||||
# Apply again to make sure other path works as well
|
||||
params = {'val1': 3, 'val2': utils.NoDeepCopyObject(4)}
|
||||
result = _message.Message(msgid) % params
|
||||
self.assertEqual("Values: 3 4", result.translate())
|
||||
self.assertEqual("Values: 3 4", result.translation())
|
||||
|
||||
def test_mod_returns_a_copy(self):
|
||||
msgid = "Some msgid string: %(test1)s %(test2)s"
|
||||
@ -261,16 +261,16 @@ class MessageTestCase(test_base.BaseTestCase):
|
||||
|
||||
self.assertIsNot(message, m1)
|
||||
self.assertIsNot(message, m2)
|
||||
self.assertEqual(m1.translate(),
|
||||
self.assertEqual(m1.translation(),
|
||||
msgid % {'test1': 'foo', 'test2': 'bar'})
|
||||
self.assertEqual(m2.translate(),
|
||||
self.assertEqual(m2.translation(),
|
||||
msgid % {'test1': 'foo2', 'test2': 'bar2'})
|
||||
|
||||
def test_mod_with_none_parameter(self):
|
||||
msgid = "Some string with params: %s"
|
||||
message = _message.Message(msgid) % None
|
||||
self.assertEqual(msgid % None, message)
|
||||
self.assertEqual(msgid % None, message.translate())
|
||||
self.assertEqual(msgid % None, message.translation())
|
||||
|
||||
def test_mod_with_missing_parameters(self):
|
||||
msgid = "Some string with params: %s %s"
|
||||
@ -288,7 +288,7 @@ class MessageTestCase(test_base.BaseTestCase):
|
||||
|
||||
expected = msgid % params
|
||||
self.assertEqual(expected, result)
|
||||
self.assertEqual(expected, result.translate())
|
||||
self.assertEqual(expected, result.translation())
|
||||
|
||||
# Make sure unused params still there
|
||||
self.assertEqual(params.keys(), result.params.keys())
|
||||
@ -304,7 +304,7 @@ class MessageTestCase(test_base.BaseTestCase):
|
||||
self.assertRaises(TypeError, test_me)
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate(self, mock_translation):
|
||||
def test_translation(self, mock_translation):
|
||||
en_message = 'A message in the default locale'
|
||||
es_translation = 'A message in Spanish'
|
||||
message = _message.Message(en_message)
|
||||
@ -314,7 +314,7 @@ class MessageTestCase(test_base.BaseTestCase):
|
||||
translator = fakes.FakeTranslations.translator(translations_map)
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
self.assertEqual(es_translation, message.translate('es'))
|
||||
self.assertEqual(es_translation, message.translation('es'))
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate_message_from_unicoded_object(self, mock_translation):
|
||||
@ -331,7 +331,7 @@ class MessageTestCase(test_base.BaseTestCase):
|
||||
obj = utils.SomeObject(message)
|
||||
unicoded_obj = six.text_type(obj)
|
||||
|
||||
self.assertEqual(es_translation, unicoded_obj.translate('es'))
|
||||
self.assertEqual(es_translation, unicoded_obj.translation('es'))
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate_multiple_languages(self, mock_translation):
|
||||
@ -347,11 +347,11 @@ class MessageTestCase(test_base.BaseTestCase):
|
||||
translator = fakes.FakeTranslations.translator(translations_map)
|
||||
mock_translation.side_effect = translator
|
||||
|
||||
self.assertEqual(es_translation, message.translate('es'))
|
||||
self.assertEqual(zh_translation, message.translate('zh'))
|
||||
self.assertEqual(en_message, message.translate(None))
|
||||
self.assertEqual(en_message, message.translate('en'))
|
||||
self.assertEqual(en_message, message.translate('XX'))
|
||||
self.assertEqual(es_translation, message.translation('es'))
|
||||
self.assertEqual(zh_translation, message.translation('zh'))
|
||||
self.assertEqual(en_message, message.translation(None))
|
||||
self.assertEqual(en_message, message.translation('en'))
|
||||
self.assertEqual(en_message, message.translation('XX'))
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate_message_with_param(self, mock_translation):
|
||||
@ -368,8 +368,8 @@ class MessageTestCase(test_base.BaseTestCase):
|
||||
|
||||
default_translation = message_with_params % param
|
||||
expected_translation = es_translation % param
|
||||
self.assertEqual(expected_translation, msg.translate('es'))
|
||||
self.assertEqual(default_translation, msg.translate('XX'))
|
||||
self.assertEqual(expected_translation, msg.translation('es'))
|
||||
self.assertEqual(default_translation, msg.translation('XX'))
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
@mock.patch('oslo_i18n._message.LOG')
|
||||
@ -390,7 +390,7 @@ class MessageTestCase(test_base.BaseTestCase):
|
||||
msg = msg % param
|
||||
default_translation = message_with_params % param
|
||||
|
||||
self.assertEqual(default_translation, msg.translate('es'))
|
||||
self.assertEqual(default_translation, msg.translation('es'))
|
||||
|
||||
self.assertEqual(1, len(w))
|
||||
# Note(gibi): in python 3.4 str.__repr__ does not put the unicode
|
||||
@ -475,8 +475,8 @@ class MessageTestCase(test_base.BaseTestCase):
|
||||
default_translation = message_with_params % param
|
||||
expected_translation = es_translation % param_translation
|
||||
|
||||
self.assertEqual(expected_translation, msg.translate('es'))
|
||||
self.assertEqual(default_translation, msg.translate('XX'))
|
||||
self.assertEqual(expected_translation, msg.translation('es'))
|
||||
self.assertEqual(default_translation, msg.translation('XX'))
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate_message_with_param_from_unicoded_obj(self,
|
||||
@ -498,8 +498,8 @@ class MessageTestCase(test_base.BaseTestCase):
|
||||
obj = utils.SomeObject(msg)
|
||||
unicoded_obj = six.text_type(obj)
|
||||
|
||||
self.assertEqual(expected_translation, unicoded_obj.translate('es'))
|
||||
self.assertEqual(default_translation, unicoded_obj.translate('XX'))
|
||||
self.assertEqual(expected_translation, unicoded_obj.translation('es'))
|
||||
self.assertEqual(default_translation, unicoded_obj.translation('XX'))
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate_message_with_message_parameter(self, mock_translation):
|
||||
@ -519,8 +519,8 @@ class MessageTestCase(test_base.BaseTestCase):
|
||||
|
||||
default_translation = message_with_params % message_param
|
||||
expected_translation = es_translation % es_param_translation
|
||||
self.assertEqual(expected_translation, msg.translate('es'))
|
||||
self.assertEqual(default_translation, msg.translate('XX'))
|
||||
self.assertEqual(expected_translation, msg.translation('es'))
|
||||
self.assertEqual(default_translation, msg.translation('XX'))
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate_message_with_message_parameters(self, mock_translation):
|
||||
@ -546,8 +546,8 @@ class MessageTestCase(test_base.BaseTestCase):
|
||||
another_message_param)
|
||||
expected_translation = es_translation % (es_param_translation,
|
||||
another_es_param_translation)
|
||||
self.assertEqual(expected_translation, msg.translate('es'))
|
||||
self.assertEqual(default_translation, msg.translate('XX'))
|
||||
self.assertEqual(expected_translation, msg.translation('es'))
|
||||
self.assertEqual(default_translation, msg.translation('XX'))
|
||||
|
||||
@mock.patch('gettext.translation')
|
||||
def test_translate_message_with_named_parameters(self, mock_translation):
|
||||
@ -567,8 +567,8 @@ class MessageTestCase(test_base.BaseTestCase):
|
||||
|
||||
default_translation = message_with_params % {'param': message_param}
|
||||
expected_translation = es_translation % {'param': es_param_translation}
|
||||
self.assertEqual(expected_translation, msg.translate('es'))
|
||||
self.assertEqual(default_translation, msg.translate('XX'))
|
||||
self.assertEqual(expected_translation, msg.translation('es'))
|
||||
self.assertEqual(default_translation, msg.translation('XX'))
|
||||
|
||||
@mock.patch('locale.getdefaultlocale')
|
||||
@mock.patch('gettext.translation')
|
||||
@ -609,13 +609,15 @@ class MessageTestCase(test_base.BaseTestCase):
|
||||
# Because sys.getdefaultlocale() was Spanish,
|
||||
# the default translation will be to Spanish
|
||||
self.assertEqual(es_translation, msg)
|
||||
self.assertEqual(es_translation, msg.translate())
|
||||
self.assertEqual(es_translation, msg.translate('es'))
|
||||
self.assertEqual(es_translation, msg.translation())
|
||||
self.assertEqual(es_translation, msg.translation('es'))
|
||||
|
||||
# Translation into other locales still works
|
||||
self.assertEqual(zh_translation, msg.translate('zh'))
|
||||
self.assertEqual(fr_translation, msg.translate('fr'))
|
||||
self.assertEqual(zh_translation, msg.translation('zh'))
|
||||
self.assertEqual(fr_translation, msg.translation('fr'))
|
||||
|
||||
# TODO(bnemec): Remove these three tests when the translate compatibility
|
||||
# shim is removed.
|
||||
def test_translate_with_dict(self):
|
||||
msg = _message.Message('abc')
|
||||
# This dict is what you get back from str.maketrans('abc', 'xyz')
|
||||
@ -631,6 +633,15 @@ class MessageTestCase(test_base.BaseTestCase):
|
||||
table[ord('c')] = 'd'
|
||||
self.assertEqual('bcd', msg.translate(table))
|
||||
|
||||
@mock.patch('warnings.warn')
|
||||
def test_translate_warning(self, mock_warn):
|
||||
msg = _message.Message('a message')
|
||||
msg.translate('es')
|
||||
self.assertTrue(mock_warn.called, 'No warning found')
|
||||
# Make sure it was our warning
|
||||
self.assertIn('Message.translate called with a string argument.',
|
||||
mock_warn.call_args[0][0])
|
||||
|
||||
|
||||
class TranslateMsgidTest(test_base.BaseTestCase):
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user