def test_translate_message_with_object_param(self, mock_translation): message_with_params = 'A message: %s' es_translation = 'A message in Spanish: %s' param = 'A Message param' param_translation = 'A Message param in Spanish' translations = {message_with_params: es_translation, param: param_translation} translator = fakes.FakeTranslations.translator({'es': translations}) mock_translation.side_effect = translator msg = _message.Message(message_with_params) param_msg = _message.Message(param) # Here we are testing translation of a Message with another object # that can be translated via its unicode() representation, this is # very common for instance when modding an Exception with a Message obj = utils.SomeObject(param_msg) msg = msg % obj 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'))
def test_message_id_and_message_text(self): message = _message.Message('1') self.assertEqual('1', message.msgid) self.assertEqual('1', message) message = _message.Message('1', msgtext='A') self.assertEqual('1', message.msgid) self.assertEqual('A', message)
def test_translate_message_with_message_parameters(self, mock_translation): message_with_params = 'A message with params: %s %s' es_translation = 'A message with params in Spanish: %s %s' message_param = 'A message param' es_param_translation = 'A message param in Spanish' another_message_param = 'Another message param' another_es_param_translation = 'Another message param in Spanish' translations = {message_with_params: es_translation, message_param: es_param_translation, another_message_param: another_es_param_translation} translator = fakes.FakeTranslations.translator({'es': translations}) mock_translation.side_effect = translator msg = _message.Message(message_with_params) param_1 = _message.Message(message_param) param_2 = _message.Message(another_message_param) msg = msg % (param_1, param_2) default_translation = message_with_params % (message_param, 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'))
def test_emit_translated_message_with_named_args(self, mock_translation): log_message = 'A message to be logged %(arg1)s $(arg2)s' log_message_translation = 'Chinese msg to be logged %(arg1)s $(arg2)s' log_arg_1 = 'Arg1 to be logged' log_arg_1_translation = 'Arg1 to be logged in Chinese' log_arg_2 = 'Arg2 to be logged' log_arg_2_translation = 'Arg2 to be logged in Chinese' translations = { log_message: log_message_translation, log_arg_1: log_arg_1_translation, log_arg_2: log_arg_2_translation } translations_map = {'zh_CN': translations} translator = fakes.FakeTranslations.translator(translations_map) mock_translation.side_effect = translator msg = _message.Message(log_message) arg_1 = _message.Message(log_arg_1) arg_2 = _message.Message(log_arg_2) self.logger.info(msg, {'arg1': arg_1, 'arg2': arg_2}) translation = log_message_translation % { 'arg1': log_arg_1_translation, 'arg2': log_arg_2_translation } self.assertIn(translation, self.stream.getvalue())
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(result.translate(), "Values: 1 2") # Apply again to make sure other path works as well params = {'val1': 3, 'val2': utils.NoDeepCopyObject(4)} result = _message.Message(msgid) % params self.assertEqual(result.translate(), "Values: 3 4")
def test_translate_message_non_default_locale(self, mock_translation, mock_getdefaultlocale): message_with_params = 'A message with params: %(param)s' es_translation = 'A message with params in Spanish: %(param)s' zh_translation = 'A message with params in Chinese: %(param)s' fr_translation = 'A message with params in French: %(param)s' message_param = 'A Message param' es_param_translation = 'A message param in Spanish' zh_param_translation = 'A message param in Chinese' fr_param_translation = 'A message param in French' es_translations = { message_with_params: es_translation, message_param: es_param_translation } zh_translations = { message_with_params: zh_translation, message_param: zh_param_translation } fr_translations = { message_with_params: fr_translation, message_param: fr_param_translation } translator = fakes.FakeTranslations.translator({ 'es': es_translations, 'zh': zh_translations, 'fr': fr_translations }) mock_translation.side_effect = translator mock_getdefaultlocale.return_value = ('es', ) msg = _message.Message(message_with_params) msg_param = _message.Message(message_param) msg = msg % {'param': msg_param} es_translation = es_translation % {'param': es_param_translation} zh_translation = zh_translation % {'param': zh_param_translation} fr_translation = fr_translation % {'param': fr_param_translation} # Because sys.getdefaultlocale() was Spanish, # the default translation will be to Spanish self.assertEqual(es_translation, msg) self.assertEqual(es_translation, msg.translation()) self.assertEqual(es_translation, msg.translation('es')) # Translation into other locales still works self.assertEqual(zh_translation, msg.translation('zh')) self.assertEqual(fr_translation, msg.translation('fr'))
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])
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))
def test_translate_message_bad_translation(self, mock_log, mock_translation): message_with_params = 'A message: %s' es_translation = 'A message in Spanish: %s %s' param = 'A Message param' translations = {message_with_params: es_translation} translator = fakes.FakeTranslations.translator({'es': translations}) mock_translation.side_effect = translator with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") msg = _message.Message(message_with_params) msg = msg % param default_translation = message_with_params % param 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 # marker 'u' in front of the string representations so the test # removes that to have the same result in python 2.7 and 3.4 self.assertEqual( "Failed to insert replacement values into " "translated message A message in Spanish: %s %s " "(Original: 'A message: %s'): " "not enough arguments for format string", str(w[0].message).replace("u'", "'")) mock_log.debug.assert_called_with(('Failed to insert replacement ' 'values into translated message ' '%s (Original: %r): %s'), es_translation, message_with_params, mock.ANY)
def f(msgsingle, msgplural, msgcount): """oslo.i18n.gettextutils plural translation function.""" if _lazy.USE_LAZY: msgid = (msgsingle, msgplural, msgcount) return _message.Message(msgid, domain=domain, has_plural_form=True) return m(msgsingle, msgplural, msgcount)
def test_mod_with_missing_arg(self): msgid = "Test that we handle missing args %(arg1)s %(arg2)s" params = {'arg1': 'test1'} e = self.assertRaises(KeyError, lambda: _message.Message(msgid) % params) self.assertIn('arg2', six.text_type(e), 'Missing key \'arg2\' was not flagged')
def test_mod_with_missing_named_parameters(self): msgid = ("Some string with params: %(param1)s %(param2)s" " and a missing one %(missing)s") params = {'param1': 'test', 'param2': 'test2'} test_me = lambda: _message.Message(msgid) % params # Just like with strings missing named parameters raise KeyError self.assertRaises(KeyError, test_me)
def lazy(self, msg): """Return a lazily translated message. :param msg: Input message string. May optionally include positional or named string interpolation markers. :type msg: str or unicode """ return _message.Message(msg, domain=self.domain)
def test_mod_with_dict_parameter(self): msgid = "Test that we can inject a dictionary %s" params = {'description': 'test1'} result = _message.Message(msgid) % params expected = msgid % params self.assertEqual(expected, result) self.assertEqual(expected, result.translate())
def test_translate_message_with_named_parameters(self, mock_translation): message_with_params = 'A message with params: %(param)s' es_translation = 'A message with params in Spanish: %(param)s' message_param = 'A Message param' es_param_translation = 'A message param in Spanish' translations = {message_with_params: es_translation, message_param: es_param_translation} translator = fakes.FakeTranslations.translator({'es': translations}) mock_translation.side_effect = translator msg = _message.Message(message_with_params) msg_param = _message.Message(message_param) msg = msg % {'param': msg_param} 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'))
def test_mod_copies_parameters(self): msgid = "Found object: %(current_value)s" changing_dict = {'current_value': 1} # A message created with some params result = _message.Message(msgid) % changing_dict # The parameters may change changing_dict['current_value'] = 2 # Even if the param changes when the message is # translated it should use the original param self.assertEqual(result.translate(), 'Found object: 1')
def test_translate(self, mock_translation): en_message = 'A message in the default locale' es_translation = 'A message in Spanish' message = _message.Message(en_message) es_translations = {en_message: es_translation} translations_map = {'es': es_translations} translator = fakes.FakeTranslations.translator(translations_map) mock_translation.side_effect = translator self.assertEqual(es_translation, message.translate('es'))
def test_emit_translated_message_with_args(self, mock_translation): log_message = 'A message to be logged %s' log_message_translation = 'A message to be logged in Chinese %s' log_arg = 'Arg to be logged' log_arg_translation = 'An arg to be logged in Chinese' translations = { log_message: log_message_translation, log_arg: log_arg_translation } translations_map = {'zh_CN': translations} translator = fakes.FakeTranslations.translator(translations_map) mock_translation.side_effect = translator msg = _message.Message(log_message) arg = _message.Message(log_arg) self.logger.info(msg, arg) self.assertIn(log_message_translation % log_arg_translation, self.stream.getvalue())
def test_mod_deep_copies_parameters(self): msgid = "Found list: %(current_list)s" changing_list = list([1, 2, 3]) params = {'current_list': changing_list} # Apply the params result = _message.Message(msgid) % params # Change the list changing_list.append(4) # Even though the list changed the message # translation should use the original list self.assertEqual(result.translate(), "Found list: [1, 2, 3]")
def test_mod_returns_a_copy(self): msgid = "Some msgid string: %(test1)s %(test2)s" message = _message.Message(msgid) m1 = message % {'test1': 'foo', 'test2': 'bar'} m2 = message % {'test1': 'foo2', 'test2': 'bar2'} self.assertIsNot(message, m1) self.assertIsNot(message, m2) self.assertEqual(m1.translate(), msgid % {'test1': 'foo', 'test2': 'bar'}) self.assertEqual(m2.translate(), msgid % {'test1': 'foo2', 'test2': 'bar2'})
def test_mod_with_extra_parameters(self): msgid = "Some string with params: %(param1)s %(param2)s" params = {'param1': 'test', 'param2': 'test2', 'param3': 'notinstring'} result = _message.Message(msgid) % params expected = msgid % params self.assertEqual(expected, result) self.assertEqual(expected, result.translation()) # Make sure unused params still there self.assertEqual(params.keys(), result.params.keys())
def test_mod_with_named_parameters_no_space(self): msgid = ("Request: %(method)s http://%(server)s:" "%(port)s%(url)s with headers %(headers)s") params = {'method': 'POST', 'server': 'test1', 'port': 1234, 'url': 'test2', 'headers': {'h1': 'val1'}} result = _message.Message(msgid) % params expected = msgid % params self.assertEqual(result, expected) self.assertEqual(result.translate(), expected)
def test_translate(self, mock_translation): en_message = 'A message in the default locale' es_translation = 'A message in Spanish' message = _message.Message(en_message) es_translations = {en_message: es_translation} translations_map = {'es': es_translations} translator = fakes.FakeTranslations.translator(translations_map) mock_translation.side_effect = translator # translate() works on msgs and on objects whose unicode reps are msgs obj = utils.SomeObject(message) self.assertEqual(es_translation, _translate.translate(message, 'es')) self.assertEqual(es_translation, _translate.translate(obj, 'es'))
def f(ctx, msg): """oslo.i18n.gettextutils translation with context function.""" if _lazy.USE_LAZY: msgid = (ctx, msg) return _message.Message(msgid, domain=domain, has_contextual_form=True) msgctx = "%s%s%s" % (ctx, CONTEXT_SEPARATOR, msg) s = m(msgctx) if CONTEXT_SEPARATOR in s: # Translation not found return msg return s
def test_translate_message_from_unicoded_object(self, mock_translation): en_message = 'A message in the default locale' es_translation = 'A message in Spanish' message = _message.Message(en_message) es_translations = {en_message: es_translation} translations_map = {'es': es_translations} translator = fakes.FakeTranslations.translator(translations_map) mock_translation.side_effect = translator # Here we are not testing the Message object directly but the result # of unicoding() an object whose unicode representation is a Message obj = utils.SomeObject(message) unicoded_obj = six.text_type(obj) self.assertEqual(es_translation, unicoded_obj.translate('es'))
def test_mod_with_named_parameters(self): msgid = ("%(description)s\nCommand: %(cmd)s\n" "Exit code: %(exit_code)s\nStdout: %(stdout)r\n" "Stderr: %(stderr)r %%(something)s") params = {'description': 'test1', 'cmd': 'test2', 'exit_code': 'test3', 'stdout': 'test4', 'stderr': 'test5', 'something': 'trimmed'} result = _message.Message(msgid) % params expected = msgid % params self.assertEqual(result, expected) self.assertEqual(result.translate(), expected)
def test_translate_message_with_param(self, mock_translation): message_with_params = 'A message: %s' es_translation = 'A message in Spanish: %s' param = 'A Message param' translations = {message_with_params: es_translation} translator = fakes.FakeTranslations.translator({'es': translations}) mock_translation.side_effect = translator msg = _message.Message(message_with_params) msg = msg % param 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'))
def test_multiple_mod_with_named_parameter(self): msgid = ("%(description)s\nCommand: %(cmd)s\n" "Exit code: %(exit_code)s\nStdout: %(stdout)r\n" "Stderr: %(stderr)r") params = { 'description': 'test1', 'cmd': 'test2', 'exit_code': 'test3', 'stdout': 'test4', 'stderr': 'test5' } # Run string interpolation the first time to make a new Message first = _message.Message(msgid) % params # Run string interpolation on the new Message, to replicate # one of the error paths with some Exception classes we've # implemented in OpenStack. We should receive a second Message # object, but the translation results should be the same. # # The production code that triggers this problem does something # like: # # msg = _('there was a problem %(name)s') % {'name': 'some value'} # LOG.error(msg) # raise BadExceptionClass(msg) # # where BadExceptionClass does something like: # # class BadExceptionClass(Exception): # def __init__(self, msg, **kwds): # super(BadExceptionClass, self).__init__(msg % kwds) # expected = first % {} # Base message id should be the same self.assertEqual(first.msgid, expected.msgid) # Preserved arguments should be the same self.assertEqual(first.params, expected.params) # Should have different objects self.assertIsNot(expected, first) # Final translations should be the same self.assertEqual(expected.translation(), first.translation())
def test_create_message_non_english_default_locale(self, mock_translation, mock_getdefaultlocale): msgid = 'A message in English' es_translation = 'A message in Spanish' es_translations = {msgid: es_translation} translations_map = {'es': es_translations} translator = fakes.FakeTranslations.translator(translations_map) mock_translation.side_effect = translator mock_getdefaultlocale.return_value = ('es', ) message = _message.Message(msgid) # 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.translation())
def test_translate_multiple_languages(self, mock_translation): en_message = 'A message in the default locale' es_translation = 'A message in Spanish' zh_translation = 'A message in Chinese' message = _message.Message(en_message) es_translations = {en_message: es_translation} zh_translations = {en_message: zh_translation} translations_map = {'es': es_translations, 'zh': zh_translations} translator = fakes.FakeTranslations.translator(translations_map) mock_translation.side_effect = translator 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'))