Keystoneclient didn't provide translated messages. With this
change, the messages are marked for translation.

DocImpact

Implements: blueprint keystoneclient-i18n

Change-Id: I85263a71671a1dffed524185266e6bb7ae559630
This commit is contained in:
Brant Knudson 2014-10-27 10:54:48 -05:00 committed by Jamie Lennox
parent 47d27ec784
commit 961c1048cd
11 changed files with 114 additions and 44 deletions

View File

@ -19,6 +19,7 @@ import datetime
from oslo.utils import timeutils
from keystoneclient.i18n import _
from keystoneclient import service_catalog
@ -63,7 +64,7 @@ class AccessInfo(dict):
else:
auth_ref = AccessInfoV2(**kwargs)
else:
raise NotImplementedError('Unrecognized auth response')
raise NotImplementedError(_('Unrecognized auth response'))
else:
auth_ref = AccessInfoV2(**kwargs)

View File

@ -17,6 +17,8 @@ import six
import stevedore
from keystoneclient import exceptions
from keystoneclient.i18n import _
# NOTE(jamielennox): The AUTH_INTERFACE is a special value that can be
# requested from get_endpoint. If a plugin receives this as the value of
@ -40,7 +42,7 @@ def get_plugin_class(name):
name=name,
invoke_on_load=False)
except RuntimeError:
msg = 'The plugin %s could not be found' % name
msg = _('The plugin %s could not be found') % name
raise exceptions.NoMatchingPlugin(msg)
return mgr.driver

View File

@ -19,6 +19,7 @@ import six
from keystoneclient import _discover
from keystoneclient.auth import base
from keystoneclient import exceptions
from keystoneclient.i18n import _LW
from keystoneclient import utils
LOG = logging.getLogger(__name__)
@ -181,9 +182,9 @@ class BaseIdentityPlugin(base.BaseAuthPlugin):
return self.auth_url
if not service_type:
LOG.warn('Plugin cannot return an endpoint without knowing the '
'service type that is required. Add service_type to '
'endpoint filtering data.')
LOG.warn(_LW('Plugin cannot return an endpoint without knowing '
'the service type that is required. Add service_type '
'to endpoint filtering data.'))
return None
if not interface:
@ -216,8 +217,9 @@ class BaseIdentityPlugin(base.BaseAuthPlugin):
# NOTE(jamielennox): Again if we can't contact the server we fall
# back to just returning the URL from the catalog. This may not be
# the best default but we need it for now.
LOG.warn('Failed to contact the endpoint at %s for discovery. '
'Fallback to using that endpoint as the base url.', url)
LOG.warn(_LW('Failed to contact the endpoint at %s for discovery. '
'Fallback to using that endpoint as the base url.'),
url)
else:
url = disc.url_for(version)

View File

@ -20,6 +20,8 @@ import six.moves.urllib.parse as urlparse
from keystoneclient import _discover
from keystoneclient.auth.identity import base
from keystoneclient import exceptions
from keystoneclient.i18n import _, _LW
LOG = logging.getLogger(__name__)
@ -127,9 +129,9 @@ class BaseGenericPlugin(base.BaseIdentityPlugin):
except (exceptions.DiscoveryFailure,
exceptions.HTTPError,
exceptions.ConnectionError):
LOG.warn('Discovering versions from the identity service failed '
'when creating the password plugin. Attempting to '
'determine version from URL.')
LOG.warn(_LW('Discovering versions from the identity service '
'failed when creating the password plugin. '
'Attempting to determine version from URL.'))
url_parts = urlparse.urlparse(self.auth_url)
path = url_parts.path.lower()
@ -163,7 +165,7 @@ class BaseGenericPlugin(base.BaseIdentityPlugin):
return plugin
# so there were no URLs that i could use for auth of any version.
msg = 'Could not determine a suitable URL for the plugin'
msg = _('Could not determine a suitable URL for the plugin')
raise exceptions.DiscoveryFailure(msg)
def get_auth_ref(self, session, **kwargs):

View File

@ -19,6 +19,7 @@ import six
from keystoneclient import access
from keystoneclient.auth.identity import base
from keystoneclient import exceptions
from keystoneclient.i18n import _
from keystoneclient import utils
_logger = logging.getLogger(__name__)
@ -84,18 +85,17 @@ class Auth(base.BaseIdentityPlugin):
ident[name] = auth_data
if not ident:
raise exceptions.AuthorizationFailure('Authentication method '
'required (e.g. password)')
raise exceptions.AuthorizationFailure(
_('Authentication method required (e.g. password)'))
mutual_exclusion = [bool(self.domain_id or self.domain_name),
bool(self.project_id or self.project_name),
bool(self.trust_id)]
if sum(mutual_exclusion) > 1:
raise exceptions.AuthorizationFailure('Authentication cannot be '
'scoped to multiple '
'targets. Pick one of: '
'project, domain or trust')
raise exceptions.AuthorizationFailure(
_('Authentication cannot be scoped to multiple targets. Pick '
'one of: project, domain or trust'))
if self.domain_id:
body['auth']['scope'] = {'domain': {'id': self.domain_id}}
@ -165,7 +165,7 @@ class AuthMethod(object):
setattr(self, param, kwargs.pop(param, None))
if kwargs:
msg = "Unexpected Attributes: %s" % ", ".join(kwargs.keys())
msg = _("Unexpected Attributes: %s") % ", ".join(kwargs.keys())
raise AttributeError(msg)
@classmethod

View File

@ -16,6 +16,7 @@
Exception definitions.
"""
from keystoneclient.i18n import _
from keystoneclient.openstack.common.apiclient.exceptions import * # noqa
# NOTE(akurilin): This alias should be left here to support backwards
@ -31,7 +32,7 @@ class CertificateConfigError(Exception):
"""Error reading the certificate."""
def __init__(self, output):
self.output = output
msg = 'Unable to load certificate.'
msg = _('Unable to load certificate.')
super(CertificateConfigError, self).__init__(msg)
@ -39,7 +40,7 @@ class CMSError(Exception):
"""Error reading the certificate."""
def __init__(self, output):
self.output = output
msg = 'Unable to sign or verify data.'
msg = _('Unable to sign or verify data.')
super(CMSError, self).__init__(msg)

37
keystoneclient/i18n.py Normal file
View File

@ -0,0 +1,37 @@
# Copyright 2014 IBM Corp.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""oslo.i18n integration module.
See http://docs.openstack.org/developer/oslo.i18n/usage.html .
"""
from oslo import i18n
_translators = i18n.TranslatorFactory(domain='keystoneclient')
# The primary translation function using the well-known name "_"
_ = _translators.primary
# Translators for log levels.
#
# The abbreviated names are meant to reflect the usual use of a short
# name like '_'. The "L" is for "log" and the other letter comes from
# the level.
_LI = _translators.log_info
_LW = _translators.log_warning
_LE = _translators.log_error
_LC = _translators.log_critical

View File

@ -21,6 +21,7 @@ import abc
import six
from keystoneclient import exceptions
from keystoneclient.i18n import _
from keystoneclient import utils
@ -36,7 +37,7 @@ class ServiceCatalog(object):
elif ServiceCatalogV2.is_valid(resource_dict):
return ServiceCatalogV2(resource_dict, region_name)
else:
raise NotImplementedError('Unrecognized auth response')
raise NotImplementedError(_('Unrecognized auth response'))
def __init__(self, region_name=None):
self._region_name = region_name
@ -208,7 +209,7 @@ class ServiceCatalog(object):
"""
if not self.get_data():
raise exceptions.EmptyCatalog('The service catalog is empty.')
raise exceptions.EmptyCatalog(_('The service catalog is empty.'))
urls = self.get_urls(attr=attr,
filter_value=filter_value,
@ -222,12 +223,30 @@ class ServiceCatalog(object):
except Exception:
pass
msg = '%s endpoint for %s service' % (endpoint_type, service_type)
if service_name:
msg += ' named %s' % service_name
if region_name:
msg += ' in %s region' % region_name
msg += ' not found'
if service_name and region_name:
msg = (_('%(endpoint_type)s endpoint for %(service_type)s service '
'named %(service_name)s in %(region_name)s region not '
'found') %
{'endpoint_type': endpoint_type,
'service_type': service_type, 'service_name': service_name,
'region_name': region_name})
elif service_name:
msg = (_('%(endpoint_type)s endpoint for %(service_type)s service '
'named %(service_name)s not found') %
{'endpoint_type': endpoint_type,
'service_type': service_type,
'service_name': service_name})
elif region_name:
msg = (_('%(endpoint_type)s endpoint for %(service_type)s service '
'in %(region_name)s region not found') %
{'endpoint_type': endpoint_type,
'service_type': service_type, 'region_name': region_name})
else:
msg = (_('%(endpoint_type)s endpoint for %(service_type)s service '
'not found') %
{'endpoint_type': endpoint_type,
'service_type': service_type})
raise exceptions.EndpointNotFound(msg)
@abc.abstractmethod

View File

@ -25,6 +25,7 @@ import six
from six.moves import urllib
from keystoneclient import exceptions
from keystoneclient.i18n import _, _LI, _LW
from keystoneclient import utils
osprofiler_web = importutils.try_import("osprofiler.web")
@ -40,10 +41,10 @@ def _positive_non_zero_float(argument_value):
try:
value = float(argument_value)
except ValueError:
msg = "%s must be a float" % argument_value
msg = _("%s must be a float") % argument_value
raise argparse.ArgumentTypeError(msg)
if value <= 0:
msg = "%s must be greater than 0" % argument_value
msg = _("%s must be greater than 0") % argument_value
raise argparse.ArgumentTypeError(msg)
return value
@ -274,7 +275,7 @@ class Session(object):
token = self.get_token(auth)
if not token:
raise exceptions.AuthorizationFailure("No token Available")
raise exceptions.AuthorizationFailure(_("No token Available"))
headers['X-Auth-Token'] = token
@ -372,20 +373,20 @@ class Session(object):
try:
resp = self.session.request(method, url, **kwargs)
except requests.exceptions.SSLError:
msg = 'SSL exception connecting to %s' % url
msg = _('SSL exception connecting to %s') % url
raise exceptions.SSLError(msg)
except requests.exceptions.Timeout:
msg = 'Request to %s timed out' % url
msg = _('Request to %s timed out') % url
raise exceptions.RequestTimeout(msg)
except requests.exceptions.ConnectionError:
msg = 'Unable to establish connection to %s' % url
msg = _('Unable to establish connection to %s') % url
raise exceptions.ConnectionRefused(msg)
except (exceptions.RequestTimeout, exceptions.ConnectionRefused) as e:
if connect_retries <= 0:
raise
_logger.info('Failure: %s. Retrying in %.1fs.',
e, connect_retry_delay)
_logger.info(_LI('Failure: %(e)s. Retrying in %(delay).1fs.'),
{'e': e, 'delay': connect_retry_delay})
time.sleep(connect_retry_delay)
return self._send_request(
@ -411,8 +412,8 @@ class Session(object):
try:
location = resp.headers['location']
except KeyError:
_logger.warn("Failed to redirect request to %s as new "
"location was not provided.", resp.url)
_logger.warn(_LW("Failed to redirect request to %s as new "
"location was not provided."), resp.url)
else:
# NOTE(jamielennox): We don't pass through connect_retry_delay.
# This request actually worked so we can reset the delay count.
@ -508,13 +509,13 @@ class Session(object):
auth = self.auth
if not auth:
raise exceptions.MissingAuthPlugin("Token Required")
raise exceptions.MissingAuthPlugin(_("Token Required"))
try:
return auth.get_token(self)
except exceptions.HttpError as exc:
raise exceptions.AuthorizationFailure("Authentication failure: "
"%s" % exc)
raise exceptions.AuthorizationFailure(
_("Authentication failure: %s") % exc)
def get_endpoint(self, auth=None, **kwargs):
"""Get an endpoint as provided by the auth plugin.
@ -531,8 +532,9 @@ class Session(object):
auth = self.auth
if not auth:
raise exceptions.MissingAuthPlugin('An auth plugin is required to '
'determine the endpoint URL.')
raise exceptions.MissingAuthPlugin(
_('An auth plugin is required to determine the endpoint '
'URL.'))
return auth.get_endpoint(self, **kwargs)
@ -543,7 +545,7 @@ class Session(object):
auth = self.auth
if not auth:
msg = 'Auth plugin not available to invalidate'
msg = _('Auth plugin not available to invalidate')
raise exceptions.MissingAuthPlugin(msg)
return auth.invalidate()

View File

@ -9,6 +9,7 @@ Babel>=1.3
iso8601>=0.1.9
netaddr>=0.7.12
oslo.config>=1.4.0 # Apache-2.0
oslo.i18n>=1.0.0 # Apache-2.0
oslo.serialization>=1.0.0 # Apache-2.0
oslo.utils>=1.0.0 # Apache-2.0
PrettyTable>=0.7,<0.8

View File

@ -45,3 +45,6 @@ exclude = .venv,.tox,dist,doc,*egg,build,*openstack/common*
commands=
python setup.py build_sphinx
[hacking]
import_exceptions =
keystoneclient.i18n