i18n - Make string translatable

Since internationalization should be enabled in Watcher CLI/SDK,
this patchset refactors the watcherclient codebase to wrap
previously untranslatable strings with i18n translation functions
so we can import them for translation into the .pot template file.

Change-Id: Ibb987e66b95e009e33b596add8c96ecb193a3773
Implements: blueprint support-translation
This commit is contained in:
David.T 2016-01-12 02:20:35 +01:00 committed by David TARDIVEL
parent 4b2f948e7a
commit 740dcf7bc2
12 changed files with 592 additions and 23 deletions

View File

@ -36,3 +36,17 @@ all_files = 1
[bdist_wheel]
universal = 1
[compile_catalog]
directory = watcherclient/locale
domain = watcherclient
[update_catalog]
domain = watcherclient
output_dir = watcherclient/locale
input_file = watcherclient/locale/watcherclient.pot
[extract_messages]
keywords = _ gettext ngettext l_ lazy_gettext
mapping_file = babel.cfg
output_file = watcherclient/locale/watcherclient.pot

View File

@ -43,4 +43,4 @@ commands =
commands = python setup.py bdist_wheel
[hacking]
import_exceptions = watcher._i18n
import_exceptions = watcherclient._i18n

View File

@ -15,11 +15,21 @@
import oslo_i18n
_translators = oslo_i18n.TranslatorFactory(domain='watcherclient')
DOMAIN = "watcherclient"
_translators = oslo_i18n.TranslatorFactory(domain=DOMAIN)
# The primary translation function using the well-known name "_"
_ = _translators.primary
# The contextual translation function using the name "_C"
# requires oslo.i18n >=2.1.0
_C = _translators.contextual_form
# The plural translation function using the name "_P"
# requires oslo.i18n >=2.1.0
_P = _translators.plural_form
# Translators for log levels.
#
# The abbreviated names are meant to reflect the usual use of a short
@ -29,3 +39,7 @@ _LI = _translators.log_info
_LW = _translators.log_warning
_LE = _translators.log_error
_LC = _translators.log_critical
def get_available_languages():
return oslo_i18n.get_available_languages(DOMAIN)

View File

@ -15,7 +15,7 @@
from keystoneclient.v2_0 import client as ksclient
import oslo_i18n
from watcherclient.common.i18n import _
from watcherclient._i18n import _
from watcherclient.common import utils
from watcherclient import exceptions as exc

View File

@ -44,8 +44,8 @@ from oslo_utils import strutils
import six
from six.moves.urllib import parse
from watcherclient._i18n import _
from watcherclient.common.apiclient import exceptions
from watcherclient.common.i18n import _
def getid(obj):

View File

@ -38,7 +38,7 @@ import sys
import six
from watcherclient.common.i18n import _
from watcherclient._i18n import _
class ClientException(Exception):

View File

@ -30,7 +30,7 @@ import prettytable
import six
from six import moves
from watcherclient.common.i18n import _
from watcherclient._i18n import _
class MissingArgs(Exception):

View File

@ -26,6 +26,7 @@ from keystoneclient import adapter
import six
import six.moves.urllib.parse as urlparse
from watcherclient._i18n import _, _LW, _LE
from watcherclient import exceptions as exc
@ -83,8 +84,8 @@ class HTTPClient(object):
elif parts.scheme == 'http':
_class = six.moves.http_client.HTTPConnection
else:
msg = 'Unsupported scheme: %s' % parts.scheme
raise exc.EndpointException(msg)
raise exc.EndpointException(
_('Unsupported scheme: %s'), parts.scheme)
return (_class, _args, _kwargs)
@ -157,15 +158,14 @@ class HTTPClient(object):
conn.request(method, conn_url, **kwargs)
resp = conn.getresponse()
except socket.gaierror as e:
message = ("Error finding address for %(url)s: %(e)s"
% dict(url=url, e=e))
raise exc.EndpointNotFound(message)
raise exc.EndpointNotFound(
_("Error finding address for %(url)s: %(e)s"),
url=url, e=e)
except (socket.error, socket.timeout) as e:
endpoint = self.endpoint
message = ("Error communicating with %(endpoint)s %(e)s"
% dict(endpoint=endpoint, e=e))
raise exc.ConnectionRefused(message)
raise exc.ConnectionRefused(
_("Error communicating with %(endpoint)s %(e)s"),
endpoint=endpoint, e=e)
body_iter = ResponseBodyIterator(resp)
# Read body into string if it isn't obviously image data
@ -178,7 +178,7 @@ class HTTPClient(object):
self.log_http_response(resp)
if 400 <= resp.status < 600:
LOG.warn("Request returned failure status.")
LOG.warn(_LW("Request returned failure status."))
error_json = _extract_error_json(body_str)
raise exc.from_response(
resp, error_json.get('faultstring'),
@ -210,7 +210,7 @@ class HTTPClient(object):
try:
body = json.loads(body)
except ValueError:
LOG.error('Could not decode response body as JSON')
LOG.error(_LE('Could not decode response body as JSON'))
else:
body = None
@ -334,7 +334,7 @@ class SessionClient(adapter.LegacyJsonAdapter):
try:
body = resp.json()
except ValueError:
LOG.error('Could not decode response body as JSON')
LOG.error(_LE('Could not decode response body as JSON'))
else:
body = None

View File

@ -22,7 +22,7 @@ import json
from oslo_utils import importutils
from watcherclient.common.i18n import _
from watcherclient._i18n import _
from watcherclient import exceptions as exc

View File

@ -0,0 +1,271 @@
# French translations for python-watcherclient.
# Copyright (C) 2016 ORGANIZATION
# This file is distributed under the same license as the
# python-watcherclient project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2016.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: python-watcherclient 0.20.1.dev4\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2016-01-12 01:58+0100\n"
"PO-Revision-Date: 2016-01-12 02:05+0100\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: fr\n"
"Language-Team: fr <LL@li.org>\n"
"Plural-Forms: nplurals=2; plural=(n > 1)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.1.1\n"
#: watcherclient/client.py:103
msgid "Must provide Keystone credentials or user-defined endpoint and token"
msgstr ""
#: watcherclient/shell.py:279
#, python-format
msgid ""
"Unable to determine the Keystone version to authenticate with using the "
"given auth_url. Identity service may not support API version discovery. "
"Please provide a versioned auth_url instead. %s"
msgstr ""
#: watcherclient/shell.py:344
msgid ""
"Unable to determine the Keystone version to authenticate with using the "
"given auth_url."
msgstr ""
#: watcherclient/shell.py:380
msgid ""
"You must provide a username via either --os-username or via "
"env[OS_USERNAME]"
msgstr ""
#: watcherclient/shell.py:396
msgid ""
"You must provide a password via either --os-password, env[OS_PASSWORD], "
"or prompted response"
msgstr ""
#: watcherclient/shell.py:403
msgid ""
"You must provide a project name or project id via --os-project-name, "
"--os-project-id, env[OS_PROJECT_ID] or env[OS_PROJECT_NAME]. You may use"
" os-project and os-tenant interchangeably."
msgstr ""
#: watcherclient/shell.py:410
msgid ""
"You must provide an auth url via either --os-auth-url or via "
"env[OS_AUTH_URL]"
msgstr ""
#: watcherclient/shell.py:473
msgid "Invalid OpenStack Identity credentials"
msgstr ""
#: watcherclient/shell.py:483
#, python-format
msgid "'%s' is not a valid subcommand"
msgstr ""
#: watcherclient/common/cliutils.py:40
#, python-format
msgid "Missing arguments: %s"
msgstr ""
#: watcherclient/common/cliutils.py:158
#, python-format
msgid ""
"Field labels list %(labels)s has different number of elements than fields"
" list %(fields)s"
msgstr ""
#: watcherclient/common/http.py:88
#, python-format
msgid "Unsupported scheme: %s"
msgstr ""
#: watcherclient/common/http.py:162
#, python-format
msgid "Error finding address for %(url)s: %(e)s"
msgstr ""
#: watcherclient/common/http.py:167
#, python-format
msgid "Error communicating with %(endpoint)s %(e)s"
msgstr ""
#: watcherclient/common/utils.py:87
#, python-format
msgid "Attributes must be a list of PATH=VALUE not \"%s\""
msgstr ""
#: watcherclient/common/utils.py:120
#, python-format
msgid "Unknown PATCH operation: %s"
msgstr ""
#: watcherclient/common/utils.py:136
#, python-format
msgid "Expected non-negative --limit, got %s"
msgstr ""
#: watcherclient/common/utils.py:147
#, python-format
msgid ""
"%(sort_key)s is an invalid field for sorting, valid values for --sort-key"
" are: %(valid)s"
msgstr ""
#: watcherclient/common/utils.py:155
#, python-format
msgid ""
"%s is an invalid value for sort direction, valid values for --sort-dir "
"are: 'asc', 'desc'"
msgstr ""
#: watcherclient/common/apiclient/base.py:244
#: watcherclient/common/apiclient/base.py:401
#, python-format
msgid "No %(name)s matching %(args)s."
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:83
#, python-format
msgid "Authentication failed. Missing options: %s"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:92
#, python-format
msgid "AuthSystemNotFound: %r"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:115
#, python-format
msgid "AmbiguousEndpoints: %r"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:122
msgid "HTTP Error"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:142
msgid "HTTP Redirection"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:150
msgid "HTTP Client Error"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:159
msgid "HTTP Server Error"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:169
msgid "Multiple Choices"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:178
msgid "Bad Request"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:188
msgid "Unauthorized"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:197
msgid "Payment Required"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:207
msgid "Forbidden"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:217
msgid "Not Found"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:227
msgid "Method Not Allowed"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:237
msgid "Not Acceptable"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:246
msgid "Proxy Authentication Required"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:255
msgid "Request Timeout"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:265
msgid "Conflict"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:275
msgid "Gone"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:285
msgid "Length Required"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:295
msgid "Precondition Failed"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:304
msgid "Request Entity Too Large"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:321
msgid "Request-URI Too Long"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:331
msgid "Unsupported Media Type"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:341
msgid "Requested Range Not Satisfiable"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:350
msgid "Expectation Failed"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:360
msgid "Unprocessable Entity"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:369
msgid "Internal Server Error"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:380
msgid "Not Implemented"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:390
msgid "Bad Gateway"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:399
msgid "Service Unavailable"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:409
msgid "Gateway Timeout"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:418
msgid "HTTP Version Not Supported"
msgstr ""

View File

@ -0,0 +1,269 @@
# Translations template for python-watcherclient.
# Copyright (C) 2016 ORGANIZATION
# This file is distributed under the same license as the
# python-watcherclient project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2016.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: python-watcherclient 0.20.1.dev4\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2016-01-12 01:58+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.1.1\n"
#: watcherclient/client.py:103
msgid "Must provide Keystone credentials or user-defined endpoint and token"
msgstr ""
#: watcherclient/shell.py:279
#, python-format
msgid ""
"Unable to determine the Keystone version to authenticate with using the "
"given auth_url. Identity service may not support API version discovery. "
"Please provide a versioned auth_url instead. %s"
msgstr ""
#: watcherclient/shell.py:344
msgid ""
"Unable to determine the Keystone version to authenticate with using the "
"given auth_url."
msgstr ""
#: watcherclient/shell.py:380
msgid ""
"You must provide a username via either --os-username or via "
"env[OS_USERNAME]"
msgstr ""
#: watcherclient/shell.py:396
msgid ""
"You must provide a password via either --os-password, env[OS_PASSWORD], "
"or prompted response"
msgstr ""
#: watcherclient/shell.py:403
msgid ""
"You must provide a project name or project id via --os-project-name, "
"--os-project-id, env[OS_PROJECT_ID] or env[OS_PROJECT_NAME]. You may use"
" os-project and os-tenant interchangeably."
msgstr ""
#: watcherclient/shell.py:410
msgid ""
"You must provide an auth url via either --os-auth-url or via "
"env[OS_AUTH_URL]"
msgstr ""
#: watcherclient/shell.py:473
msgid "Invalid OpenStack Identity credentials"
msgstr ""
#: watcherclient/shell.py:483
#, python-format
msgid "'%s' is not a valid subcommand"
msgstr ""
#: watcherclient/common/cliutils.py:40
#, python-format
msgid "Missing arguments: %s"
msgstr ""
#: watcherclient/common/cliutils.py:158
#, python-format
msgid ""
"Field labels list %(labels)s has different number of elements than fields"
" list %(fields)s"
msgstr ""
#: watcherclient/common/http.py:88
#, python-format
msgid "Unsupported scheme: %s"
msgstr ""
#: watcherclient/common/http.py:162
#, python-format
msgid "Error finding address for %(url)s: %(e)s"
msgstr ""
#: watcherclient/common/http.py:167
#, python-format
msgid "Error communicating with %(endpoint)s %(e)s"
msgstr ""
#: watcherclient/common/utils.py:87
#, python-format
msgid "Attributes must be a list of PATH=VALUE not \"%s\""
msgstr ""
#: watcherclient/common/utils.py:120
#, python-format
msgid "Unknown PATCH operation: %s"
msgstr ""
#: watcherclient/common/utils.py:136
#, python-format
msgid "Expected non-negative --limit, got %s"
msgstr ""
#: watcherclient/common/utils.py:147
#, python-format
msgid ""
"%(sort_key)s is an invalid field for sorting, valid values for --sort-key"
" are: %(valid)s"
msgstr ""
#: watcherclient/common/utils.py:155
#, python-format
msgid ""
"%s is an invalid value for sort direction, valid values for --sort-dir "
"are: 'asc', 'desc'"
msgstr ""
#: watcherclient/common/apiclient/base.py:244
#: watcherclient/common/apiclient/base.py:401
#, python-format
msgid "No %(name)s matching %(args)s."
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:83
#, python-format
msgid "Authentication failed. Missing options: %s"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:92
#, python-format
msgid "AuthSystemNotFound: %r"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:115
#, python-format
msgid "AmbiguousEndpoints: %r"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:122
msgid "HTTP Error"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:142
msgid "HTTP Redirection"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:150
msgid "HTTP Client Error"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:159
msgid "HTTP Server Error"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:169
msgid "Multiple Choices"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:178
msgid "Bad Request"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:188
msgid "Unauthorized"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:197
msgid "Payment Required"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:207
msgid "Forbidden"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:217
msgid "Not Found"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:227
msgid "Method Not Allowed"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:237
msgid "Not Acceptable"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:246
msgid "Proxy Authentication Required"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:255
msgid "Request Timeout"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:265
msgid "Conflict"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:275
msgid "Gone"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:285
msgid "Length Required"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:295
msgid "Precondition Failed"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:304
msgid "Request Entity Too Large"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:321
msgid "Request-URI Too Long"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:331
msgid "Unsupported Media Type"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:341
msgid "Requested Range Not Satisfiable"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:350
msgid "Expectation Failed"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:360
msgid "Unprocessable Entity"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:369
msgid "Internal Server Error"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:380
msgid "Not Implemented"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:390
msgid "Bad Gateway"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:399
msgid "Service Unavailable"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:409
msgid "Gateway Timeout"
msgstr ""
#: watcherclient/common/apiclient/exceptions.py:418
msgid "HTTP Version Not Supported"
msgstr ""

View File

@ -31,9 +31,9 @@ from keystoneclient import session as kssession
import six.moves.urllib.parse as urlparse
import watcherclient
from watcherclient._i18n import _
from watcherclient import client as watcher_client
from watcherclient.common import cliutils
from watcherclient.common.i18n import _
from watcherclient.common import utils
from watcherclient import exceptions as exc
@ -340,9 +340,10 @@ class WatcherShell(object):
# support only v2
auth = self._get_keystone_v2_auth(v2_auth_url, **kwargs)
else:
raise exc.CommandError('Unable to determine the Keystone version '
'to authenticate with using the given '
'auth_url.')
raise exc.CommandError(
_('Unable to determine the Keystone version '
'to authenticate with using the given '
'auth_url.'))
return auth