From fece74ca3e56342bee43f561404c19128a613628 Mon Sep 17 00:00:00 2001 From: Brant Knudson Date: Mon, 27 Oct 2014 10:54:48 -0500 Subject: I18n Keystoneclient didn't provide translated messages. With this change, the messages are marked for translation. DocImpact Implements: blueprint keystoneclient-i18n Change-Id: I85263a71671a1dffed524185266e6bb7ae559630 --- keystoneclient/_discover.py | 22 ++++++++------- keystoneclient/access.py | 3 +- keystoneclient/auth/base.py | 4 ++- keystoneclient/auth/identity/base.py | 12 ++++---- keystoneclient/auth/identity/generic/base.py | 10 ++++--- keystoneclient/auth/identity/v3.py | 14 +++++----- keystoneclient/base.py | 9 ++++-- keystoneclient/common/cms.py | 25 +++++++++-------- keystoneclient/contrib/auth/v3/saml2.py | 32 ++++++++++++---------- keystoneclient/contrib/ec2/utils.py | 8 ++++-- keystoneclient/discover.py | 14 ++++++---- keystoneclient/exceptions.py | 5 ++-- keystoneclient/generic/client.py | 11 ++++---- keystoneclient/generic/shell.py | 12 ++++---- keystoneclient/httpclient.py | 22 +++++++++------ keystoneclient/i18n.py | 37 +++++++++++++++++++++++++ keystoneclient/service_catalog.py | 35 ++++++++++++++++++------ keystoneclient/session.py | 34 ++++++++++++----------- keystoneclient/v2_0/client.py | 12 ++++---- keystoneclient/v2_0/shell.py | 41 ++++++++++++++-------------- keystoneclient/v2_0/tokens.py | 4 ++- keystoneclient/v3/client.py | 14 ++++++---- keystoneclient/v3/contrib/endpoint_filter.py | 13 +++++---- keystoneclient/v3/contrib/endpoint_policy.py | 11 ++++---- keystoneclient/v3/contrib/oauth1/core.py | 3 +- keystoneclient/v3/contrib/trusts.py | 5 ++-- keystoneclient/v3/credentials.py | 3 +- keystoneclient/v3/endpoints.py | 3 +- keystoneclient/v3/role_assignments.py | 29 ++++++++++---------- keystoneclient/v3/roles.py | 9 +++--- keystoneclient/v3/users.py | 19 +++++++------ requirements.txt | 1 + tox.ini | 3 ++ 33 files changed, 293 insertions(+), 186 deletions(-) create mode 100644 keystoneclient/i18n.py diff --git a/keystoneclient/_discover.py b/keystoneclient/_discover.py index 8816209..9ecf616 100644 --- a/keystoneclient/_discover.py +++ b/keystoneclient/_discover.py @@ -25,6 +25,7 @@ import logging import re from keystoneclient import exceptions +from keystoneclient.i18n import _, _LI, _LW from keystoneclient import utils @@ -65,7 +66,7 @@ def get_version_data(session, url, authenticated=None): pass err_text = resp.text[:50] + '...' if len(resp.text) > 50 else resp.text - msg = 'Invalid Response - Bad version data returned: %s' % err_text + msg = _('Invalid Response - Bad version data returned: %s') % err_text raise exceptions.DiscoveryFailure(msg) @@ -99,7 +100,7 @@ def normalize_version_number(version): except Exception: pass - raise TypeError('Invalid version specified: %s' % version) + raise TypeError(_('Invalid version specified: %s') % version) def version_match(required, candidate): @@ -159,8 +160,8 @@ class Discover(object): try: status = v['status'] except KeyError: - _LOGGER.warning('Skipping over invalid version data. ' - 'No stability status in version.') + _LOGGER.warning(_LW('Skipping over invalid version data. ' + 'No stability status in version.')) continue status = status.lower() @@ -198,13 +199,14 @@ class Discover(object): try: version_str = v['id'] except KeyError: - _LOGGER.info('Skipping invalid version data. Missing ID.') + _LOGGER.info(_LI('Skipping invalid version data. Missing ID.')) continue try: links = v['links'] except KeyError: - _LOGGER.info('Skipping invalid version data. Missing links') + _LOGGER.info( + _LI('Skipping invalid version data. Missing links')) continue version_number = normalize_version_number(version_str) @@ -214,15 +216,15 @@ class Discover(object): rel = link['rel'] url = link['href'] except (KeyError, TypeError): - _LOGGER.info('Skipping invalid version link. ' - 'Missing link URL or relationship.') + _LOGGER.info(_LI('Skipping invalid version link. ' + 'Missing link URL or relationship.')) continue if rel.lower() == 'self': break else: - _LOGGER.info('Skipping invalid version data. ' - 'Missing link to endpoint.') + _LOGGER.info(_LI('Skipping invalid version data. ' + 'Missing link to endpoint.')) continue versions.append({'version': version_number, diff --git a/keystoneclient/access.py b/keystoneclient/access.py index c7cd115..6786674 100644 --- a/keystoneclient/access.py +++ b/keystoneclient/access.py @@ -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) diff --git a/keystoneclient/auth/base.py b/keystoneclient/auth/base.py index 66e6a18..fda9d9a 100644 --- a/keystoneclient/auth/base.py +++ b/keystoneclient/auth/base.py @@ -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 diff --git a/keystoneclient/auth/identity/base.py b/keystoneclient/auth/identity/base.py index a58de2a..aae24c3 100644 --- a/keystoneclient/auth/identity/base.py +++ b/keystoneclient/auth/identity/base.py @@ -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) diff --git a/keystoneclient/auth/identity/generic/base.py b/keystoneclient/auth/identity/generic/base.py index 94d48ec..631eebd 100644 --- a/keystoneclient/auth/identity/generic/base.py +++ b/keystoneclient/auth/identity/generic/base.py @@ -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): diff --git a/keystoneclient/auth/identity/v3.py b/keystoneclient/auth/identity/v3.py index 99d7562..e0f6b08 100644 --- a/keystoneclient/auth/identity/v3.py +++ b/keystoneclient/auth/identity/v3.py @@ -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 diff --git a/keystoneclient/base.py b/keystoneclient/base.py index 2571a37..030afef 100644 --- a/keystoneclient/base.py +++ b/keystoneclient/base.py @@ -27,6 +27,7 @@ from six.moves import urllib from keystoneclient import auth from keystoneclient import exceptions +from keystoneclient.i18n import _ from keystoneclient.openstack.common.apiclient import base @@ -219,7 +220,7 @@ class Manager(object): management=management, **kwargs) except KeyError: - raise exceptions.ClientException("Invalid update method: %s" + raise exceptions.ClientException(_("Invalid update method: %s") % method) # PUT requests may not return a body if body: @@ -244,7 +245,8 @@ class ManagerWithFind(Manager): num = len(rl) if num == 0: - msg = "No %s matching %s." % (self.resource_class.__name__, kwargs) + msg = _("No %(name)s matching %(kwargs)s.") % { + 'name': self.resource_class.__name__, 'kwargs': kwargs} raise exceptions.NotFound(404, msg) elif num > 1: raise exceptions.NoUniqueMatch @@ -395,7 +397,8 @@ class CrudManager(Manager): num = len(rl) if num == 0: - msg = "No %s matching %s." % (self.resource_class.__name__, kwargs) + msg = _("No %(name)s matching %(kwargs)s.") % { + 'name': self.resource_class.__name__, 'kwargs': kwargs} raise exceptions.NotFound(404, msg) elif num > 1: raise exceptions.NoUniqueMatch diff --git a/keystoneclient/common/cms.py b/keystoneclient/common/cms.py index 343b303..6e40b18 100644 --- a/keystoneclient/common/cms.py +++ b/keystoneclient/common/cms.py @@ -28,6 +28,7 @@ import zlib import six from keystoneclient import exceptions +from keystoneclient.i18n import _, _LE, _LW subprocess = None @@ -73,8 +74,9 @@ def _check_files_accessible(files): except IOError as e: # Catching IOError means there is an issue with # the given file. - err = ('Hit OSError in _process_communicate_handle_oserror()\n' - 'Likely due to %s: %s') % (try_file, e.strerror) + err = _('Hit OSError in _process_communicate_handle_oserror()\n' + 'Likely due to %(file)s: %(error)s') % {'file': try_file, + 'error': e.strerror} # Emulate openssl behavior, which returns with code 2 when # access to a file failed: @@ -122,8 +124,9 @@ def _encoding_for_form(inform): elif inform == PKIZ_CMS_FORM: encoding = 'hex' else: - raise ValueError('"inform" must be either %s or %s' % - (PKI_ASN1_FORM, PKIZ_CMS_FORM)) + raise ValueError( + _('"inform" must be one of: %s') % ','.join((PKI_ASN1_FORM, + PKIZ_CMS_FORM))) return encoding @@ -296,8 +299,8 @@ def is_asn1_token(token): def is_ans1_token(token): """Deprecated. Use is_asn1_token() instead.""" - LOG.warning('The function is_ans1_token() is deprecated, ' - 'use is_asn1_token() instead.') + LOG.warning(_LW('The function is_ans1_token() is deprecated, ' + 'use is_asn1_token() instead.')) return is_asn1_token(token) @@ -344,13 +347,13 @@ def cms_sign_data(data_to_sign, signing_cert_file_name, signing_key_file_name, process, data, (signing_cert_file_name, signing_key_file_name)) if retcode or ('Error' in err): - LOG.error('Signing error: %s', err) + LOG.error(_LE('Signing error: %s'), err) if retcode == 3: - LOG.error('Signing error: Unable to load certificate - ' - 'ensure you have configured PKI with ' - '"keystone-manage pki_setup"') + LOG.error(_LE('Signing error: Unable to load certificate - ' + 'ensure you have configured PKI with ' + '"keystone-manage pki_setup"')) else: - LOG.error('Signing error: %s', err) + LOG.error(_LE('Signing error: %s'), err) raise subprocess.CalledProcessError(retcode, 'openssl') if outform == PKI_ASN1_FORM: return output.decode('utf-8') diff --git a/keystoneclient/contrib/auth/v3/saml2.py b/keystoneclient/contrib/auth/v3/saml2.py index 4ff0ef7..47a74e5 100644 --- a/keystoneclient/contrib/auth/v3/saml2.py +++ b/keystoneclient/contrib/auth/v3/saml2.py @@ -20,6 +20,7 @@ from six.moves import urllib from keystoneclient import access from keystoneclient.auth.identity import v3 from keystoneclient import exceptions +from keystoneclient.i18n import _ class _BaseSAMLPlugin(v3.AuthConstructor): @@ -30,7 +31,7 @@ class _BaseSAMLPlugin(v3.AuthConstructor): @staticmethod def _first(_list): if len(_list) != 1: - raise IndexError("Only single element list is acceptable") + raise IndexError(_("Only single element list is acceptable")) return _list[0] @staticmethod @@ -80,8 +81,8 @@ class Saml2UnscopedTokenAuthMethod(v3.AuthMethod): _method_parameters = [] def get_auth_data(self, session, auth, headers, **kwargs): - raise exceptions.MethodNotImplemented(('This method should never ' - 'be called')) + raise exceptions.MethodNotImplemented(_('This method should never ' + 'be called')) class Saml2UnscopedToken(_BaseSAMLPlugin): @@ -211,9 +212,9 @@ class Saml2UnscopedToken(_BaseSAMLPlugin): authenticated=False) # prepare error message and raise an exception. - msg = ("Consumer URLs from Service Provider %(service_provider)s " - "%(sp_consumer_url)s and Identity Provider " - "%(identity_provider)s %(idp_consumer_url)s are not equal") + msg = _("Consumer URLs from Service Provider %(service_provider)s " + "%(sp_consumer_url)s and Identity Provider " + "%(identity_provider)s %(idp_consumer_url)s are not equal") msg = msg % { 'service_provider': self.token_url, 'sp_consumer_url': sp_response_consumer_url, @@ -257,8 +258,8 @@ class Saml2UnscopedToken(_BaseSAMLPlugin): try: self.saml2_authn_request = etree.XML(sp_response.content) except etree.XMLSyntaxError as e: - msg = ("SAML2: Error parsing XML returned " - "from Service Provider, reason: %s" % e) + msg = _("SAML2: Error parsing XML returned " + "from Service Provider, reason: %s") % e raise exceptions.AuthorizationFailure(msg) relay_state = self.saml2_authn_request.xpath( @@ -288,8 +289,8 @@ class Saml2UnscopedToken(_BaseSAMLPlugin): try: self.saml2_idp_authn_response = etree.XML(idp_response.content) except etree.XMLSyntaxError as e: - msg = ("SAML2: Error parsing XML returned " - "from Identity Provider, reason: %s" % e) + msg = _("SAML2: Error parsing XML returned " + "from Identity Provider, reason: %s") % e raise exceptions.AuthorizationFailure(msg) idp_response_consumer_url = self.saml2_idp_authn_response.xpath( @@ -736,8 +737,8 @@ class ADFSUnscopedToken(_BaseSAMLPlugin): except exceptions.InternalServerError as e: reason = _get_failure(e) raise exceptions.AuthorizationFailure(reason) - msg = ("Error parsing XML returned from " - "the ADFS Identity Provider, reason: %s") + msg = _("Error parsing XML returned from " + "the ADFS Identity Provider, reason: %s") self.adfs_token = self.str_to_xml(response.content, msg) def _prepare_sp_request(self): @@ -803,8 +804,9 @@ class ADFSUnscopedToken(_BaseSAMLPlugin): """ if self._cookies(session) is False: raise exceptions.AuthorizationFailure( - "Session object doesn't contain a cookie, therefore you are " - "not allowed to enter the Identity Provider's protected area.") + _("Session object doesn't contain a cookie, therefore you are " + "not allowed to enter the Identity Provider's protected " + "area.")) self.authenticated_response = session.get(self.token_url, authenticated=False) @@ -883,4 +885,4 @@ class Saml2ScopedToken(v3.Token): super(Saml2ScopedToken, self).__init__(auth_url, token, **kwargs) if not (self.project_id or self.domain_id): raise exceptions.ValidationError( - 'Neither project nor domain specified') + _('Neither project nor domain specified')) diff --git a/keystoneclient/contrib/ec2/utils.py b/keystoneclient/contrib/ec2/utils.py index 899b95a..d093b6e 100644 --- a/keystoneclient/contrib/ec2/utils.py +++ b/keystoneclient/contrib/ec2/utils.py @@ -24,6 +24,8 @@ import re import six from six.moves import urllib +from keystoneclient.i18n import _ + class Ec2Signer(object): """Utility class which adds allows a request to be signed with an AWS style @@ -91,10 +93,10 @@ class Ec2Signer(object): credentials['body_hash']) if signature_version is not None: - raise Exception('Unknown signature version: %s' % + raise Exception(_('Unknown signature version: %s') % signature_version) else: - raise Exception('Unexpected signature format') + raise Exception(_('Unexpected signature format')) @staticmethod def _get_utf8_value(value): @@ -257,7 +259,7 @@ class Ec2Signer(object): credential_date = credential_split[1] param_date = date_param() if not param_date.startswith(credential_date): - raise Exception('Request date mismatch error') + raise Exception(_('Request date mismatch error')) # Create the string to sign # http://docs.aws.amazon.com/general/latest/gr/ diff --git a/keystoneclient/discover.py b/keystoneclient/discover.py index 982683a..0f79134 100644 --- a/keystoneclient/discover.py +++ b/keystoneclient/discover.py @@ -16,6 +16,7 @@ import six from keystoneclient import _discover from keystoneclient import exceptions +from keystoneclient.i18n import _ from keystoneclient import session as client_session from keystoneclient import utils from keystoneclient.v2_0 import client as v2_client @@ -122,9 +123,9 @@ class Discover(_discover.Discover): url = auth_url if not url: - raise exceptions.DiscoveryFailure('Not enough information to ' - 'determine URL. Provide either ' - 'auth_url or endpoint') + raise exceptions.DiscoveryFailure( + _('Not enough information to determine URL. Provide either ' + 'auth_url or endpoint')) self._client_kwargs = kwargs super(Discover, self).__init__(session, url, @@ -213,10 +214,11 @@ class Discover(_discover.Discover): version_data = all_versions[-1] if not version_data: - msg = 'Could not find a suitable endpoint' + msg = _('Could not find a suitable endpoint') if version: - msg += ' for client version: %s' % str(version) + msg = _('Could not find a suitable endpoint for client ' + 'version: %s') % str(version) raise exceptions.VersionNotAvailable(msg) @@ -228,7 +230,7 @@ class Discover(_discover.Discover): client_class = _CLIENT_VERSIONS[version_data['version'][0]] except KeyError: version = '.'.join(str(v) for v in version_data['version']) - msg = 'No client available for version: %s' % version + msg = _('No client available for version: %s') % version raise exceptions.DiscoveryFailure(msg) # kwargs should take priority over stored kwargs. diff --git a/keystoneclient/exceptions.py b/keystoneclient/exceptions.py index 0370dd6..d516a25 100644 --- a/keystoneclient/exceptions.py +++ b/keystoneclient/exceptions.py @@ -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) diff --git a/keystoneclient/generic/client.py b/keystoneclient/generic/client.py index 3c81268..7892739 100644 --- a/keystoneclient/generic/client.py +++ b/keystoneclient/generic/client.py @@ -19,6 +19,7 @@ from six.moves.urllib import parse as urlparse from keystoneclient import exceptions from keystoneclient import httpclient +from keystoneclient.i18n import _ _logger = logging.getLogger(__name__) @@ -94,7 +95,7 @@ class Client(httpclient.HTTPClient): try: results = {} if 'version' in body: - results['message'] = "Keystone found at %s" % url + results['message'] = _("Keystone found at %s") % url version = body['version'] # Stable/diablo incorrect format id, status, version_url = ( @@ -105,7 +106,7 @@ class Client(httpclient.HTTPClient): return results elif 'versions' in body: # Correct format - results['message'] = "Keystone found at %s" % url + results['message'] = _("Keystone found at %s") % url for version in body['versions']['values']: id, status, version_url = ( self._get_version_info(version, url)) @@ -114,8 +115,8 @@ class Client(httpclient.HTTPClient): "url": version_url} return results else: - results['message'] = ("Unrecognized response from %s" - % url) + results['message'] = ( + _("Unrecognized response from %s") % url) return results except KeyError: raise exceptions.AuthorizationFailure() @@ -159,7 +160,7 @@ class Client(httpclient.HTTPClient): extensions = body['extensions'] else: return dict(message=( - 'Unrecognized extensions response from %s' % url)) + _('Unrecognized extensions response from %s') % url)) return dict(self._get_extension_info(e) for e in extensions) elif resp.status_code == 305: diff --git a/keystoneclient/generic/shell.py b/keystoneclient/generic/shell.py index 4f9bd33..e5330a5 100644 --- a/keystoneclient/generic/shell.py +++ b/keystoneclient/generic/shell.py @@ -16,6 +16,7 @@ import six from keystoneclient.generic import client +from keystoneclient.i18n import _ from keystoneclient import utils @@ -37,13 +38,14 @@ def do_discover(cs, args): print(versions['message']) for key, version in six.iteritems(versions): if key != 'message': - print(" - supports version %s (%s) here %s" % - (version['id'], version['status'], version['url'])) + print(_(" - supports version %(id)s (%(status)s) here " + "%(url)s") % + version) extensions = cs.discover_extensions(version['url']) if extensions: for key, extension in six.iteritems(extensions): if key != 'message': - print(" - and %s: %s" % - (key, extension)) + print(_(" - and %(key)s: %(extension)s") % + {'key': key, 'extension': extension}) else: - print("No Keystone-compatible endpoint found") + print(_("No Keystone-compatible endpoint found")) diff --git a/keystoneclient/httpclient.py b/keystoneclient/httpclient.py index f8470ba..670cb64 100644 --- a/keystoneclient/httpclient.py +++ b/keystoneclient/httpclient.py @@ -55,6 +55,7 @@ from keystoneclient import access from keystoneclient.auth import base from keystoneclient import baseclient from keystoneclient import exceptions +from keystoneclient.i18n import _, _LI, _LW from keystoneclient import session as client_session from keystoneclient import utils @@ -265,7 +266,7 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin): # keyring setup if use_keyring and keyring is None: - _logger.warning('Failed to load keyring modules.') + _logger.warning(_LW('Failed to load keyring modules.')) self.use_keyring = use_keyring and keyring is not None self.force_new_token = force_new_token self.stale_duration = stale_duration or access.STALE_TOKEN_DURATION @@ -476,7 +477,8 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin): auth_ref = None except Exception as e: auth_ref = None - _logger.warning('Unable to retrieve token from keyring %s', e) + _logger.warning( + _LW('Unable to retrieve token from keyring %s'), e) return (keyring_key, auth_ref) def store_auth_ref_into_keyring(self, keyring_key): @@ -489,7 +491,8 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin): keyring_key, pickle.dumps(self.auth_ref)) except Exception as e: - _logger.warning("Failed to store token into keyring %s", e) + _logger.warning( + _LW("Failed to store token into keyring %s"), e) def _process_management_url(self, region_name): try: @@ -511,14 +514,14 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin): if self.auth_ref.project_scoped: if not self.auth_ref.tenant_id: raise exceptions.AuthorizationFailure( - "Token didn't provide tenant_id") + _("Token didn't provide tenant_id")) self._process_management_url(region_name) self.project_name = self.auth_ref.tenant_name self.project_id = self.auth_ref.tenant_id if not self.auth_ref.user_id: raise exceptions.AuthorizationFailure( - "Token didn't provide user_id") + _("Token didn't provide user_id")) self.user_id = self.auth_ref.user_id @@ -620,10 +623,11 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin): try: return self.request(url, method, **kwargs) except exceptions.MissingAuthPlugin: - _logger.info('Cannot get authenticated endpoint without an ' - 'auth plugin') + _logger.info(_LI('Cannot get authenticated endpoint without an ' + 'auth plugin')) raise exceptions.AuthorizationFailure( - 'Current authorization does not have a known management url') + _('Current authorization does not have a known management ' + 'url')) def get(self, url, **kwargs): return self._cs_request(url, 'GET', **kwargs) @@ -656,7 +660,7 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin): try: var_name = self.deprecated_session_variables[name] except KeyError: - raise AttributeError("Unknown Attribute: %s" % name) + raise AttributeError(_("Unknown Attribute: %s") % name) return getattr(self.session, var_name or name) diff --git a/keystoneclient/i18n.py b/keystoneclient/i18n.py new file mode 100644 index 0000000..fd1c03a --- /dev/null +++ b/keystoneclient/i18n.py @@ -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 diff --git a/keystoneclient/service_catalog.py b/keystoneclient/service_catalog.py index cf85ed7..7c9085b 100644 --- a/keystoneclient/service_catalog.py +++ b/keystoneclient/service_catalog.py @@ -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 diff --git a/keystoneclient/session.py b/keystoneclient/session.py index aab90f9..8a1aeb7 100644 --- a/keystoneclient/session.py +++ b/keystoneclient/session.py @@ -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() diff --git a/keystoneclient/v2_0/client.py b/keystoneclient/v2_0/client.py index 062678f..030632b 100644 --- a/keystoneclient/v2_0/client.py +++ b/keystoneclient/v2_0/client.py @@ -18,6 +18,7 @@ import logging from keystoneclient.auth.identity import v2 as v2_auth from keystoneclient import exceptions from keystoneclient import httpclient +from keystoneclient.i18n import _ from keystoneclient.v2_0 import ec2 from keystoneclient.v2_0 import endpoints from keystoneclient.v2_0 import extensions @@ -163,7 +164,7 @@ class Client(httpclient.HTTPClient): """ try: if auth_url is None: - raise ValueError("Cannot authenticate without an auth_url") + raise ValueError(_("Cannot authenticate without an auth_url")) new_kwargs = {'trust_id': trust_id, 'tenant_id': project_id or tenant_id, @@ -175,7 +176,7 @@ class Client(httpclient.HTTPClient): plugin = v2_auth.Password(auth_url, username, password, **new_kwargs) else: - msg = 'A username and password or token is required.' + msg = _('A username and password or token is required.') raise exceptions.AuthorizationFailure(msg) return plugin.get_auth_ref(self.session) @@ -183,8 +184,9 @@ class Client(httpclient.HTTPClient): _logger.debug("Authorization Failed.") raise except exceptions.EndpointNotFound: - msg = 'There was no suitable authentication url for this request' + msg = ( + _('There was no suitable authentication url for this request')) raise exceptions.AuthorizationFailure(msg) except Exception as e: - raise exceptions.AuthorizationFailure("Authorization Failed: " - "%s" % e) + raise exceptions.AuthorizationFailure( + _("Authorization Failed: %s") % e) diff --git a/keystoneclient/v2_0/shell.py b/keystoneclient/v2_0/shell.py index 976fb1e..a2cb1ab 100755 --- a/keystoneclient/v2_0/shell.py +++ b/keystoneclient/v2_0/shell.py @@ -29,6 +29,7 @@ import sys from oslo.utils import strutils import six +from keystoneclient.i18n import _ from keystoneclient import utils from keystoneclient.v2_0 import client @@ -38,9 +39,9 @@ ASK_FOR_PASSWORD = object() def require_service_catalog(f): - msg = ('Configuration error: Client configured to run without a service ' - 'catalog. Run the client using --os-auth-url or OS_AUTH_URL, ' - 'instead of --os-endpoint or OS_SERVICE_ENDPOINT, for example.') + msg = _('Configuration error: Client configured to run without a service ' + 'catalog. Run the client using --os-auth-url or OS_AUTH_URL, ' + 'instead of --os-endpoint or OS_SERVICE_ENDPOINT, for example.') def wrapped(kc, args): if not kc.has_service_catalog(): @@ -121,15 +122,15 @@ def do_user_update(kc, args): kwargs['enabled'] = strutils.bool_from_string(args.enabled) if not len(kwargs): - print("User not updated, no arguments present.") + print(_("User not updated, no arguments present.")) return user = utils.find_resource(kc.users, args.user) try: kc.users.update(user, **kwargs) - print('User has been updated.') + print(_('User has been updated.')) except Exception as e: - print('Unable to update user: %s' % e) + print(_('Unable to update user: %s') % e) @utils.arg('--pass', metavar='', dest='passwd', required=False, @@ -141,8 +142,8 @@ def do_user_password_update(kc, args): user = utils.find_resource(kc.users, args.user) new_passwd = args.passwd or utils.prompt_for_password() if new_passwd is None: - msg = ("\nPlease specify password using the --pass option " - "or using the prompt") + msg = (_("\nPlease specify password using the --pass option " + "or using the prompt")) sys.exit(msg) kc.users.update_password(user, new_passwd) @@ -163,20 +164,20 @@ def do_password_update(kc, args): if args.currentpasswd is not None: currentpasswd = args.currentpasswd if currentpasswd is None: - currentpasswd = getpass.getpass('Current Password: ') + currentpasswd = getpass.getpass(_('Current Password: ')) newpasswd = args.newpasswd while newpasswd is None: - passwd1 = getpass.getpass('New Password: ') - passwd2 = getpass.getpass('Repeat New Password: ') + passwd1 = getpass.getpass(_('New Password: ')) + passwd2 = getpass.getpass(_('Repeat New Password: ')) if passwd1 == passwd2: newpasswd = passwd1 kc.users.update_own_password(currentpasswd, newpasswd) if args.os_password != newpasswd: - print("You should update the password you are using to authenticate " - "to match your new password") + print(_("You should update the password you are using to authenticate " + "to match your new password")) @utils.arg('user', metavar='', help='Name or ID of user to delete.') @@ -234,7 +235,7 @@ def do_tenant_update(kc, args): kwargs.update({'enabled': strutils.bool_from_string(args.enabled)}) if kwargs == {}: - print("Tenant not updated, no arguments present.") + print(_("Tenant not updated, no arguments present.")) return tenant.update(**kwargs) @@ -450,9 +451,9 @@ def do_ec2_credentials_delete(kc, args): args.user_id = kc.auth_user_id try: kc.ec2.delete(args.user_id, args.access) - print('Credential has been deleted.') + print(_('Credential has been deleted.')) except Exception as e: - print('Unable to delete credential: %s' % e) + print(_('Unable to delete credential: %s') % e) @utils.arg('--service', metavar='', default=None, @@ -463,7 +464,7 @@ def do_catalog(kc, args): endpoints = kc.service_catalog.get_endpoints(service_type=args.service) for (service, service_endpoints) in six.iteritems(endpoints): if len(service_endpoints) > 0: - print("Service: %s" % service) + print(_("Service: %s") % service) for ep in service_endpoints: utils.print_dict(ep) @@ -489,7 +490,7 @@ def do_endpoint_get(kc, args): if args.attr and args.value: kwargs.update({'attr': args.attr, 'filter_value': args.value}) elif args.attr or args.value: - print('Both --attr and --value required.') + print(_('Both --attr and --value required.')) return url = kc.service_catalog.url_for(**kwargs) @@ -531,9 +532,9 @@ def do_endpoint_delete(kc, args): """Delete a service endpoint.""" try: kc.endpoints.delete(args.id) - print('Endpoint has been deleted.') + print(_('Endpoint has been deleted.')) except Exception: - print('Unable to delete endpoint.') + print(_('Unable to delete endpoint.')) @utils.arg('--wrap', metavar='', default=0, diff --git a/keystoneclient/v2_0/tokens.py b/keystoneclient/v2_0/tokens.py index e5a21d4..fb48738 100644 --- a/keystoneclient/v2_0/tokens.py +++ b/keystoneclient/v2_0/tokens.py @@ -13,6 +13,7 @@ from keystoneclient import auth from keystoneclient import base from keystoneclient import exceptions +from keystoneclient.i18n import _ from keystoneclient import utils @@ -45,7 +46,8 @@ class TokenManager(base.Manager): params = {"auth": {"passwordCredentials": {"username": username, "password": password}}} else: - raise ValueError('A username and password or token is required.') + raise ValueError( + _('A username and password or token is required.')) if tenant_id: params['auth']['tenantId'] = tenant_id elif tenant_name: diff --git a/keystoneclient/v3/client.py b/keystoneclient/v3/client.py index 1967e8e..662629c 100644 --- a/keystoneclient/v3/client.py +++ b/keystoneclient/v3/client.py @@ -20,6 +20,7 @@ from oslo.serialization import jsonutils from keystoneclient.auth.identity import v3 as v3_auth from keystoneclient import exceptions from keystoneclient import httpclient +from keystoneclient.i18n import _ from keystoneclient.v3.contrib import endpoint_filter from keystoneclient.v3.contrib import endpoint_policy from keystoneclient.v3.contrib import federation @@ -203,7 +204,7 @@ EndpointPolicyManager` if self.auth_ref.domain_scoped: if not self.auth_ref.domain_id: raise exceptions.AuthorizationFailure( - "Token didn't provide domain_id") + _("Token didn't provide domain_id")) self._process_management_url(kwargs.get('region_name')) self.domain_name = self.auth_ref.domain_name self.domain_id = self.auth_ref.domain_id @@ -235,7 +236,7 @@ EndpointPolicyManager` """ try: if auth_url is None: - raise ValueError("Cannot authenticate without an auth_url") + raise ValueError(_("Cannot authenticate without an auth_url")) auth_methods = [] @@ -251,7 +252,7 @@ EndpointPolicyManager` auth_methods.append(m) if not auth_methods: - msg = 'A user and password or token is required.' + msg = _('A user and password or token is required.') raise exceptions.AuthorizationFailure(msg) plugin = v3_auth.Auth(auth_url, auth_methods, @@ -268,8 +269,9 @@ EndpointPolicyManager` _logger.debug('Authorization failed.') raise except exceptions.EndpointNotFound: - msg = 'There was no suitable authentication url for this request' + msg = _('There was no suitable authentication url for this' + ' request') raise exceptions.AuthorizationFailure(msg) except Exception as e: - raise exceptions.AuthorizationFailure('Authorization failed: ' - '%s' % e) + raise exceptions.AuthorizationFailure( + _('Authorization failed: %s') % e) diff --git a/keystoneclient/v3/contrib/endpoint_filter.py b/keystoneclient/v3/contrib/endpoint_filter.py index c0a1eef..3e3b7ef 100644 --- a/keystoneclient/v3/contrib/endpoint_filter.py +++ b/keystoneclient/v3/contrib/endpoint_filter.py @@ -14,6 +14,7 @@ from keystoneclient import base from keystoneclient import exceptions +from keystoneclient.i18n import _ class EndpointFilterManager(base.Manager): @@ -31,7 +32,7 @@ class EndpointFilterManager(base.Manager): elif endpoint_id: api_path = '/endpoints/%s/projects' % (endpoint_id) else: - msg = 'Must specify a project, an endpoint, or both' + msg = _('Must specify a project, an endpoint, or both') raise exceptions.ValidationError(msg) return self.OS_EP_FILTER_EXT + api_path @@ -39,7 +40,7 @@ class EndpointFilterManager(base.Manager): def add_endpoint_to_project(self, project, endpoint): """Create a project-endpoint association.""" if not (project and endpoint): - raise ValueError('project and endpoint are required') + raise ValueError(_('project and endpoint are required')) base_url = self._build_base_url(project=project, endpoint=endpoint) @@ -48,7 +49,7 @@ class EndpointFilterManager(base.Manager): def delete_endpoint_from_project(self, project, endpoint): """Remove a project-endpoint association.""" if not (project and endpoint): - raise ValueError('project and endpoint are required') + raise ValueError(_('project and endpoint are required')) base_url = self._build_base_url(project=project, endpoint=endpoint) @@ -57,7 +58,7 @@ class EndpointFilterManager(base.Manager): def check_endpoint_in_project(self, project, endpoint): """Checks if project-endpoint association exist.""" if not (project and endpoint): - raise ValueError('project and endpoint are required') + raise ValueError(_('project and endpoint are required')) base_url = self._build_base_url(project=project, endpoint=endpoint) @@ -66,7 +67,7 @@ class EndpointFilterManager(base.Manager): def list_endpoints_for_project(self, project): """List all endpoints for a given project.""" if not project: - raise ValueError('project is required') + raise ValueError(_('project is required')) base_url = self._build_base_url(project=project) return super(EndpointFilterManager, self)._list( @@ -77,7 +78,7 @@ class EndpointFilterManager(base.Manager): def list_projects_for_endpoint(self, endpoint): """List all projects for a given endpoint.""" if not endpoint: - raise ValueError('endpoint is required') + raise ValueError(_('endpoint is required')) base_url = self._build_base_url(endpoint=endpoint) return super(EndpointFilterManager, self)._list( diff --git a/keystoneclient/v3/contrib/endpoint_policy.py b/keystoneclient/v3/contrib/endpoint_policy.py index 9d4d997..c473ad6 100644 --- a/keystoneclient/v3/contrib/endpoint_policy.py +++ b/keystoneclient/v3/contrib/endpoint_policy.py @@ -13,6 +13,7 @@ # under the License. from keystoneclient import base +from keystoneclient.i18n import _ from keystoneclient.v3 import policies @@ -24,7 +25,7 @@ class EndpointPolicyManager(base.Manager): def _act_on_policy_association_for_endpoint( self, policy, endpoint, action): if not (policy and endpoint): - raise ValueError('policy and endpoint are required') + raise ValueError(_('policy and endpoint are required')) policy_id = base.getid(policy) endpoint_id = base.getid(endpoint) @@ -52,7 +53,7 @@ class EndpointPolicyManager(base.Manager): def _act_on_policy_association_for_service(self, policy, service, action): if not (policy and service): - raise ValueError('policy and service are required') + raise ValueError(_('policy and service are required')) policy_id = base.getid(policy) service_id = base.getid(service) @@ -81,7 +82,7 @@ class EndpointPolicyManager(base.Manager): def _act_on_policy_association_for_region_and_service( self, policy, region, service, action): if not (policy and region and service): - raise ValueError('policy, region and service are required') + raise ValueError(_('policy, region and service are required')) policy_id = base.getid(policy) region_id = base.getid(region) @@ -121,7 +122,7 @@ class EndpointPolicyManager(base.Manager): """ if not endpoint: - raise ValueError('endpoint is required') + raise ValueError(_('endpoint is required')) endpoint_id = base.getid(endpoint) url = ('/endpoints/%(endpoint_id)s/%(ext_name)s/policy') % { @@ -141,7 +142,7 @@ class EndpointPolicyManager(base.Manager): """ if not policy: - raise ValueError('policy is required') + raise ValueError(_('policy is required')) policy_id = base.getid(policy) url = ('/policies/%(policy_id)s/%(ext_name)s/endpoints') % { diff --git a/keystoneclient/v3/contrib/oauth1/core.py b/keystoneclient/v3/contrib/oauth1/core.py index 36823f0..8d10325 100644 --- a/keystoneclient/v3/contrib/oauth1/core.py +++ b/keystoneclient/v3/contrib/oauth1/core.py @@ -11,6 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +from keystoneclient.i18n import _ from keystoneclient.v3.contrib.oauth1 import access_tokens from keystoneclient.v3.contrib.oauth1 import consumers from keystoneclient.v3.contrib.oauth1 import request_tokens @@ -59,6 +60,6 @@ class OAuthManagerOptionalImportProxy(object): def __getattribute__(self, name): if name in ('access_tokens', 'consumers', 'request_tokens'): raise NotImplementedError( - 'To use %r oauthlib must be installed' % name) + _('To use %r oauthlib must be installed') % name) return super(OAuthManagerOptionalImportProxy, self).__getattribute__(name) diff --git a/keystoneclient/v3/contrib/trusts.py b/keystoneclient/v3/contrib/trusts.py index 70e9d8e..0fb75ca 100644 --- a/keystoneclient/v3/contrib/trusts.py +++ b/keystoneclient/v3/contrib/trusts.py @@ -14,6 +14,7 @@ from oslo.utils import timeutils from keystoneclient import base from keystoneclient import exceptions +from keystoneclient.i18n import _ class Trust(base.Resource): @@ -75,8 +76,8 @@ class TrustManager(base.CrudManager): **kwargs) def update(self): - raise exceptions.MethodNotImplemented('Update not supported' - ' for trusts') + raise exceptions.MethodNotImplemented( + _('Update not supported for trusts')) def list(self, trustee_user=None, trustor_user=None, **kwargs): """List Trusts.""" diff --git a/keystoneclient/v3/credentials.py b/keystoneclient/v3/credentials.py index be28cc5..833a32f 100644 --- a/keystoneclient/v3/credentials.py +++ b/keystoneclient/v3/credentials.py @@ -15,6 +15,7 @@ # under the License. from keystoneclient import base +from keystoneclient.i18n import _ from keystoneclient import utils @@ -46,7 +47,7 @@ class CredentialManager(base.CrudManager): return data else: raise ValueError( - "Credential requires blob to be specified") + _("Credential requires blob to be specified")) @utils.positional(1, enforcement=utils.positional.WARN) def create(self, user, type, blob=None, data=None, project=None, **kwargs): diff --git a/keystoneclient/v3/endpoints.py b/keystoneclient/v3/endpoints.py index 3f9dfbd..eeddc4c 100644 --- a/keystoneclient/v3/endpoints.py +++ b/keystoneclient/v3/endpoints.py @@ -16,6 +16,7 @@ from keystoneclient import base from keystoneclient import exceptions +from keystoneclient.i18n import _ from keystoneclient import utils @@ -45,7 +46,7 @@ class EndpointManager(base.CrudManager): def _validate_interface(self, interface): if interface is not None and interface not in VALID_INTERFACES: - msg = '"interface" must be one of: %s' + msg = _('"interface" must be one of: %s') msg = msg % ', '.join(VALID_INTERFACES) raise exceptions.ValidationError(msg) diff --git a/keystoneclient/v3/role_assignments.py b/keystoneclient/v3/role_assignments.py index 5394c3d..6518e43 100644 --- a/keystoneclient/v3/role_assignments.py +++ b/keystoneclient/v3/role_assignments.py @@ -12,6 +12,7 @@ from keystoneclient import base from keystoneclient import exceptions +from keystoneclient.i18n import _ class RoleAssignment(base.Resource): @@ -37,12 +38,12 @@ class RoleAssignmentManager(base.CrudManager): def _check_not_user_and_group(self, user, group): if user and group: - msg = 'Specify either a user or group, not both' + msg = _('Specify either a user or group, not both') raise exceptions.ValidationError(msg) def _check_not_domain_and_project(self, domain, project): if domain and project: - msg = 'Specify either a domain or project, not both' + msg = _('Specify either a domain or project, not both') raise exceptions.ValidationError(msg) def list(self, user=None, group=None, project=None, domain=None, role=None, @@ -87,25 +88,25 @@ class RoleAssignmentManager(base.CrudManager): return super(RoleAssignmentManager, self).list(**query_params) def create(self, **kwargs): - raise exceptions.MethodNotImplemented('Create not supported for' - ' role assignments') + raise exceptions.MethodNotImplemented( + _('Create not supported for role assignments')) def update(self, **kwargs): - raise exceptions.MethodNotImplemented('Update not supported for' - ' role assignments') + raise exceptions.MethodNotImplemented( + _('Update not supported for role assignments')) def get(self, **kwargs): - raise exceptions.MethodNotImplemented('Get not supported for' - ' role assignments') + raise exceptions.MethodNotImplemented( + _('Get not supported for role assignments')) def find(self, **kwargs): - raise exceptions.MethodNotImplemented('Find not supported for' - ' role assignments') + raise exceptions.MethodNotImplemented( + _('Find not supported for role assignments')) def put(self, **kwargs): - raise exceptions.MethodNotImplemented('Put not supported for' - ' role assignments') + raise exceptions.MethodNotImplemented( + _('Put not supported for role assignments')) def delete(self, **kwargs): - raise exceptions.MethodNotImplemented('Delete not supported for' - ' role assignments') + raise exceptions.MethodNotImplemented( + _('Delete not supported for role assignments')) diff --git a/keystoneclient/v3/roles.py b/keystoneclient/v3/roles.py index 40c624a..3eb68d1 100644 --- a/keystoneclient/v3/roles.py +++ b/keystoneclient/v3/roles.py @@ -16,6 +16,7 @@ from keystoneclient import base from keystoneclient import exceptions +from keystoneclient.i18n import _ from keystoneclient import utils @@ -59,18 +60,18 @@ class RoleManager(base.CrudManager): def _require_domain_xor_project(self, domain, project): if domain and project: - msg = 'Specify either a domain or project, not both' + msg = _('Specify either a domain or project, not both') raise exceptions.ValidationError(msg) elif not (domain or project): - msg = 'Must specify either a domain or project' + msg = _('Must specify either a domain or project') raise exceptions.ValidationError(msg) def _require_user_xor_group(self, user, group): if user and group: - msg = 'Specify either a user or group, not both' + msg = _('Specify either a user or group, not both') raise exceptions.ValidationError(msg) elif not (user or group): - msg = 'Must specify either a user or group' + msg = _('Must specify either a user or group') raise exceptions.ValidationError(msg) @utils.positional(1, enforcement=utils.positional.WARN) diff --git a/keystoneclient/v3/users.py b/keystoneclient/v3/users.py index 140c785..3343d50 100644 --- a/keystoneclient/v3/users.py +++ b/keystoneclient/v3/users.py @@ -18,6 +18,7 @@ import logging from keystoneclient import base from keystoneclient import exceptions +from keystoneclient.i18n import _, _LW from keystoneclient import utils LOG = logging.getLogger(__name__) @@ -41,7 +42,7 @@ class UserManager(base.CrudManager): def _require_user_and_group(self, user, group): if not (user and group): - msg = 'Specify both a user and a group' + msg = _('Specify both a user and a group') raise exceptions.ValidationError(msg) @utils.positional(1, enforcement=utils.positional.WARN) @@ -58,8 +59,8 @@ class UserManager(base.CrudManager): will be used. """ if project: - LOG.warning("The project argument is deprecated, " - "use default_project instead.") + LOG.warning(_LW("The project argument is deprecated, " + "use default_project instead.")) default_project_id = base.getid(default_project) or base.getid(project) user_data = base.filter_none(name=name, domain_id=base.getid(domain), @@ -92,8 +93,8 @@ class UserManager(base.CrudManager): will be used. """ if project: - LOG.warning("The project argument is deprecated, " - "use default_project instead.") + LOG.warning(_LW("The project argument is deprecated, " + "use default_project instead.")) default_project_id = base.getid(default_project) or base.getid(project) if group: base_url = '/groups/%s' % base.getid(group) @@ -124,8 +125,8 @@ class UserManager(base.CrudManager): will be used. """ if project: - LOG.warning("The project argument is deprecated, " - "use default_project instead.") + LOG.warning(_LW("The project argument is deprecated, " + "use default_project instead.")) default_project_id = base.getid(default_project) or base.getid(project) user_data = base.filter_none(name=name, domain_id=base.getid(domain), @@ -145,11 +146,11 @@ class UserManager(base.CrudManager): def update_password(self, old_password, new_password): """Update the password for the user the token belongs to.""" if not (old_password and new_password): - msg = 'Specify both the current password and a new password' + msg = _('Specify both the current password and a new password') raise exceptions.ValidationError(msg) if old_password == new_password: - msg = 'Old password and new password must be different.' + msg = _('Old password and new password must be different.') raise exceptions.ValidationError(msg) params = {'user': {'password': new_password, diff --git a/requirements.txt b/requirements.txt index 99f6a23..dfee64b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -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 diff --git a/tox.ini b/tox.ini index f8a984d..57db9c0 100644 --- a/tox.ini +++ b/tox.ini @@ -45,3 +45,6 @@ exclude = .venv,.tox,dist,doc,*egg,build,*openstack/common* commands= python setup.py build_sphinx +[hacking] +import_exceptions = + keystoneclient.i18n -- cgit v1.2.1