diff options
author | James Carey <jecarey@us.ibm.com> | 2014-07-03 20:40:44 +0000 |
---|---|---|
committer | James Carey <jecarey@us.ibm.com> | 2014-07-07 15:39:16 +0000 |
commit | 3d90045d2d1ce1df89f75937f415e3982e111063 (patch) | |
tree | 5b3316322c2d1139d3f13d1e9e2e2c8511883b88 | |
parent | 53a232ef9dfed6bf3654847703b968906cec66d1 (diff) | |
download | oslo-incubator-3d90045d2d1ce1df89f75937f415e3982e111063.tar.gz |
Backport code for i18n to check lazy at runtime
Currently in the oslo-incubator version of i18n support
the TranslationFactory generates a direct translation
method based on the passed lazy parameter. This means that
when the default is assigned to _ during its intial import,
lazy isn't specified, which defaults to False, so the
TranslationFactory returns a method that does not support
lazy translation.
The _ method is not changed until enable_lazy is called, thus
any import of _ prior to that will cache the initial method
that does not support lazy translation even when it has been
enabled.
This problem was exposed by the cinder test case:
cinder/tests/test_wsgi.py
test
test_cinder_exception_with_localized_explanation
when the file:
cinder/api/middleware/fault.py
had the line:
from cinder.openstack.common.gettextutils import _
added to it.
This behavior is corrected in the i18n library such that the
generated method checks the global _lazy.USE_LAZY to determine
if lazy translation should be used in commit:
Iae22668 Check the lazy flag at runtime
Note that this removes the lazy parameter from the signature of
install and the TranslationFactory to match the library.
Change-Id: If1832b012d4b72708d0850367a1ec55cb0cd63e8
-rw-r--r-- | openstack/common/gettextutils.py | 63 | ||||
-rw-r--r-- | tests/unit/test_gettext.py | 47 |
2 files changed, 45 insertions, 65 deletions
diff --git a/openstack/common/gettextutils.py b/openstack/common/gettextutils.py index 87229a93..59545c49 100644 --- a/openstack/common/gettextutils.py +++ b/openstack/common/gettextutils.py @@ -23,7 +23,6 @@ Usual usage in an openstack.common module: """ import copy -import functools import gettext import locale from logging import handlers @@ -42,7 +41,7 @@ class TranslatorFactory(object): """Create translator functions """ - def __init__(self, domain, lazy=False, localedir=None): + def __init__(self, domain, localedir=None): """Establish a set of translation functions for the domain. :param domain: Name of translation domain, @@ -55,7 +54,6 @@ class TranslatorFactory(object): :type localedir: str """ self.domain = domain - self.lazy = lazy if localedir is None: localedir = os.environ.get(domain.upper() + '_LOCALEDIR') self.localedir = localedir @@ -75,16 +73,19 @@ class TranslatorFactory(object): """ if domain is None: domain = self.domain - if self.lazy: - return functools.partial(Message, domain=domain) - t = gettext.translation( - domain, - localedir=self.localedir, - fallback=True, - ) - if six.PY3: - return t.gettext - return t.ugettext + t = gettext.translation(domain, + localedir=self.localedir, + fallback=True) + # Use the appropriate method of the translation object based + # on the python version. + m = t.gettext if six.PY3 else t.ugettext + + def f(msg): + """oslo.i18n.gettextutils translation function.""" + if USE_LAZY: + return Message(msg, domain=domain) + return m(msg) + return f @property def primary(self): @@ -147,19 +148,11 @@ def enable_lazy(): your project is importing _ directly instead of using the gettextutils.install() way of importing the _ function. """ - # FIXME(dhellmann): This function will be removed in oslo.i18n, - # because the TranslatorFactory makes it superfluous. - global _, _LI, _LW, _LE, _LC, USE_LAZY - tf = TranslatorFactory('oslo', lazy=True) - _ = tf.primary - _LI = tf.log_info - _LW = tf.log_warning - _LE = tf.log_error - _LC = tf.log_critical + global USE_LAZY USE_LAZY = True -def install(domain, lazy=False): +def install(domain): """Install a _() function using the given translation domain. Given a translation domain, install a _() function using gettext's @@ -170,26 +163,14 @@ def install(domain, lazy=False): a translation-domain-specific environment variable (e.g. NOVA_LOCALEDIR). + Note that to enable lazy translation, enable_lazy must be + called. + :param domain: the translation domain - :param lazy: indicates whether or not to install the lazy _() function. - The lazy _() introduces a way to do deferred translation - of messages by installing a _ that builds Message objects, - instead of strings, which can then be lazily translated into - any available locale. """ - if lazy: - from six import moves - tf = TranslatorFactory(domain, lazy=True) - moves.builtins.__dict__['_'] = tf.primary - else: - localedir = '%s_LOCALEDIR' % domain.upper() - if six.PY3: - gettext.install(domain, - localedir=os.environ.get(localedir)) - else: - gettext.install(domain, - localedir=os.environ.get(localedir), - unicode=True) + from six import moves + tf = TranslatorFactory(domain) + moves.builtins.__dict__['_'] = tf.primary class Message(six.text_type): diff --git a/tests/unit/test_gettext.py b/tests/unit/test_gettext.py index 47490534..1d9d6ad2 100644 --- a/tests/unit/test_gettext.py +++ b/tests/unit/test_gettext.py @@ -39,6 +39,7 @@ class GettextTest(test_base.BaseTestCase): self.mox = moxfixture.mox # remember so we can reset to it later self._USE_LAZY = gettextutils.USE_LAZY + gettextutils.USE_LAZY = False def tearDown(self): # reset to value before test @@ -59,28 +60,14 @@ class GettextTest(test_base.BaseTestCase): gettextutils.install('blaa') self.assertTrue(isinstance(_('A String'), six.text_type)) # noqa - gettextutils.install('blaa', lazy=True) + def test_gettextutils_install_with_enable(self): + gettextutils.install('blaa') + self.assertTrue(isinstance(_('A String'), six.text_type)) # noqa + + gettextutils.enable_lazy() self.assertTrue(isinstance(_('A Message'), # noqa gettextutils.Message)) - def test_gettext_install_looks_up_localedir(self): - with mock.patch('os.environ.get') as environ_get: - with mock.patch('gettext.install') as gettext_install: - environ_get.return_value = '/foo/bar' - - gettextutils.install('blaa') - - environ_get.assert_called_once_with('BLAA_LOCALEDIR') - if six.PY3: - gettext_install.assert_called_once_with( - 'blaa', - localedir='/foo/bar') - else: - gettext_install.assert_called_once_with( - 'blaa', - localedir='/foo/bar', - unicode=True) - def test_get_available_languages(self): # All the available languages for which locale data is available def _mock_locale_identifiers(): @@ -718,9 +705,21 @@ class TranslationHandlerTestCase(test_base.BaseTestCase): class TranslatorFactoryTest(test_base.BaseTestCase): + def setUp(self): + super(TranslatorFactoryTest, self).setUp() + # remember so we can reset to it later + self._USE_LAZY = gettextutils.USE_LAZY + gettextutils.USE_LAZY = False + + def tearDown(self): + # reset to value before test + gettextutils.USE_LAZY = self._USE_LAZY + super(TranslatorFactoryTest, self).tearDown() + def test_lazy(self): with mock.patch.object(gettextutils, 'Message') as msg: - tf = gettextutils.TranslatorFactory('domain', lazy=True) + tf = gettextutils.TranslatorFactory('domain') + gettextutils.enable_lazy() tf.primary('some text') msg.assert_called_with('some text', domain='domain') @@ -731,7 +730,7 @@ class TranslatorFactoryTest(test_base.BaseTestCase): translation.return_value = trans trans.gettext.side_effect = AssertionError( 'should have called ugettext') - tf = gettextutils.TranslatorFactory('domain', lazy=False) + tf = gettextutils.TranslatorFactory('domain') tf.primary('some text') trans.ugettext.assert_called_with('some text') @@ -742,14 +741,14 @@ class TranslatorFactoryTest(test_base.BaseTestCase): translation.return_value = trans trans.ugettext.side_effect = AssertionError( 'should have called gettext') - tf = gettextutils.TranslatorFactory('domain', lazy=False) + tf = gettextutils.TranslatorFactory('domain') tf.primary('some text') trans.gettext.assert_called_with('some text') def test_log_level_domain_name(self): with mock.patch.object(gettextutils.TranslatorFactory, '_make_translation_func') as mtf: - tf = gettextutils.TranslatorFactory('domain', lazy=False) + tf = gettextutils.TranslatorFactory('domain') tf._make_log_translation_func('mylevel') mtf.assert_called_with('domain-log-mylevel') @@ -765,7 +764,7 @@ class LogLevelTranslationsTest(test_base.BaseTestCase): def test(self): with mock.patch.object(gettextutils.TranslatorFactory, '_make_translation_func') as mtf: - tf = gettextutils.TranslatorFactory('domain', lazy=False) + tf = gettextutils.TranslatorFactory('domain') getattr(tf, 'log_%s' % self.level) mtf.assert_called_with('domain-log-%s' % self.level) |