diff options
Diffstat (limited to 'rest_framework')
| -rw-r--r-- | rest_framework/authentication.py | 17 | ||||
| -rw-r--r-- | rest_framework/authtoken/serializers.py | 2 | ||||
| -rw-r--r-- | rest_framework/exceptions.py | 34 | ||||
| -rw-r--r-- | rest_framework/fields.py | 41 | ||||
| -rw-r--r-- | rest_framework/generics.py | 12 | ||||
| -rw-r--r-- | rest_framework/locale/en_US/LC_MESSAGES/django.po | 316 | ||||
| -rw-r--r-- | rest_framework/relations.py | 6 | ||||
| -rw-r--r-- | rest_framework/serializers.py | 2 | ||||
| -rw-r--r-- | rest_framework/versioning.py | 2 |
9 files changed, 374 insertions, 58 deletions
diff --git a/rest_framework/authentication.py b/rest_framework/authentication.py index 124ef68a..11db0585 100644 --- a/rest_framework/authentication.py +++ b/rest_framework/authentication.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals import base64 from django.contrib.auth import authenticate from django.middleware.csrf import CsrfViewMiddleware +from django.utils.translation import ugettext_lazy as _ from rest_framework import exceptions, HTTP_HEADER_ENCODING from rest_framework.authtoken.models import Token @@ -65,16 +66,16 @@ class BasicAuthentication(BaseAuthentication): return None if len(auth) == 1: - msg = 'Invalid basic header. No credentials provided.' + msg = _('Invalid basic header. No credentials provided.') raise exceptions.AuthenticationFailed(msg) elif len(auth) > 2: - msg = 'Invalid basic header. Credentials string should not contain spaces.' + msg = _('Invalid basic header. Credentials string should not contain spaces.') raise exceptions.AuthenticationFailed(msg) try: auth_parts = base64.b64decode(auth[1]).decode(HTTP_HEADER_ENCODING).partition(':') except (TypeError, UnicodeDecodeError): - msg = 'Invalid basic header. Credentials not correctly base64 encoded' + msg = _('Invalid basic header. Credentials not correctly base64 encoded.') raise exceptions.AuthenticationFailed(msg) userid, password = auth_parts[0], auth_parts[2] @@ -86,7 +87,7 @@ class BasicAuthentication(BaseAuthentication): """ user = authenticate(username=userid, password=password) if user is None or not user.is_active: - raise exceptions.AuthenticationFailed('Invalid username/password') + raise exceptions.AuthenticationFailed(_('Invalid username/password.')) return (user, None) def authenticate_header(self, request): @@ -152,10 +153,10 @@ class TokenAuthentication(BaseAuthentication): return None if len(auth) == 1: - msg = 'Invalid token header. No credentials provided.' + msg = _('Invalid token header. No credentials provided.') raise exceptions.AuthenticationFailed(msg) elif len(auth) > 2: - msg = 'Invalid token header. Token string should not contain spaces.' + msg = _('Invalid token header. Token string should not contain spaces.') raise exceptions.AuthenticationFailed(msg) return self.authenticate_credentials(auth[1]) @@ -164,10 +165,10 @@ class TokenAuthentication(BaseAuthentication): try: token = self.model.objects.get(key=key) except self.model.DoesNotExist: - raise exceptions.AuthenticationFailed('Invalid token') + raise exceptions.AuthenticationFailed(_('Invalid token.')) if not token.user.is_active: - raise exceptions.AuthenticationFailed('User inactive or deleted') + raise exceptions.AuthenticationFailed(_('User inactive or deleted.')) return (token.user, token) diff --git a/rest_framework/authtoken/serializers.py b/rest_framework/authtoken/serializers.py index f31dded1..37ade255 100644 --- a/rest_framework/authtoken/serializers.py +++ b/rest_framework/authtoken/serializers.py @@ -23,7 +23,7 @@ class AuthTokenSerializer(serializers.Serializer): msg = _('Unable to log in with provided credentials.') raise exceptions.ValidationError(msg) else: - msg = _('Must include "username" and "password"') + msg = _('Must include "username" and "password".') raise exceptions.ValidationError(msg) attrs['user'] = user diff --git a/rest_framework/exceptions.py b/rest_framework/exceptions.py index bcfd8961..f954c13e 100644 --- a/rest_framework/exceptions.py +++ b/rest_framework/exceptions.py @@ -7,8 +7,7 @@ In addition Django's built in 403 and 404 exceptions are handled. from __future__ import unicode_literals from django.utils import six from django.utils.encoding import force_text -from django.utils.translation import ugettext_lazy as _ -from django.utils.translation import ungettext_lazy +from django.utils.translation import ugettext_lazy as _, ungettext from rest_framework import status import math @@ -36,7 +35,7 @@ class APIException(Exception): Subclasses should provide `.status_code` and `.default_detail` properties. """ status_code = status.HTTP_500_INTERNAL_SERVER_ERROR - default_detail = _('A server error occured') + default_detail = _('A server error occurred.') def __init__(self, detail=None): if detail is not None: @@ -91,23 +90,23 @@ class PermissionDenied(APIException): class NotFound(APIException): status_code = status.HTTP_404_NOT_FOUND - default_detail = _('Not found') + default_detail = _('Not found.') class MethodNotAllowed(APIException): status_code = status.HTTP_405_METHOD_NOT_ALLOWED - default_detail = _("Method '%s' not allowed.") + default_detail = _('Method "{method}" not allowed.') def __init__(self, method, detail=None): if detail is not None: self.detail = force_text(detail) else: - self.detail = force_text(self.default_detail) % method + self.detail = force_text(self.default_detail).format(method=method) class NotAcceptable(APIException): status_code = status.HTTP_406_NOT_ACCEPTABLE - default_detail = _('Could not satisfy the request Accept header') + default_detail = _('Could not satisfy the request Accept header.') def __init__(self, detail=None, available_renderers=None): if detail is not None: @@ -119,23 +118,22 @@ class NotAcceptable(APIException): class UnsupportedMediaType(APIException): status_code = status.HTTP_415_UNSUPPORTED_MEDIA_TYPE - default_detail = _("Unsupported media type '%s' in request.") + default_detail = _('Unsupported media type "{media_type}" in request.') def __init__(self, media_type, detail=None): if detail is not None: self.detail = force_text(detail) else: - self.detail = force_text(self.default_detail) % media_type + self.detail = force_text(self.default_detail).format( + media_type=media_type + ) class Throttled(APIException): status_code = status.HTTP_429_TOO_MANY_REQUESTS default_detail = _('Request was throttled.') - extra_detail = ungettext_lazy( - 'Expected available in %(wait)d second.', - 'Expected available in %(wait)d seconds.', - 'wait' - ) + extra_detail_singular = 'Expected available in {wait} second.' + extra_detail_plural = 'Expected available in {wait} seconds.' def __init__(self, wait=None, detail=None): if detail is not None: @@ -147,6 +145,8 @@ class Throttled(APIException): self.wait = None else: self.wait = math.ceil(wait) - self.detail += ' ' + force_text( - self.extra_detail % {'wait': self.wait} - ) + self.detail += ' ' + force_text(ungettext( + self.extra_detail_singular.format(wait=self.wait), + self.extra_detail_plural.format(wait=self.wait), + self.wait + )) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index cc9410aa..342564d3 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -483,7 +483,7 @@ class Field(object): class BooleanField(Field): default_error_messages = { - 'invalid': _('`{input}` is not a valid boolean.') + 'invalid': _('"{input}" is not a valid boolean.') } default_empty_html = False initial = False @@ -511,7 +511,7 @@ class BooleanField(Field): class NullBooleanField(Field): default_error_messages = { - 'invalid': _('`{input}` is not a valid boolean.') + 'invalid': _('"{input}" is not a valid boolean.') } initial = None TRUE_VALUES = set(('t', 'T', 'true', 'True', 'TRUE', '1', 1, True)) @@ -611,7 +611,7 @@ class RegexField(CharField): class SlugField(CharField): default_error_messages = { - 'invalid': _("Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens.") + 'invalid': _('Enter a valid "slug" consisting of letters, numbers, underscores or hyphens.') } def __init__(self, **kwargs): @@ -623,7 +623,7 @@ class SlugField(CharField): class URLField(CharField): default_error_messages = { - 'invalid': _("Enter a valid URL.") + 'invalid': _('Enter a valid URL.') } def __init__(self, **kwargs): @@ -639,7 +639,7 @@ class IntegerField(Field): 'invalid': _('A valid integer is required.'), 'max_value': _('Ensure this value is less than or equal to {max_value}.'), 'min_value': _('Ensure this value is greater than or equal to {min_value}.'), - 'max_string_length': _('String value too large') + 'max_string_length': _('String value too large.') } MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs. @@ -670,10 +670,10 @@ class IntegerField(Field): class FloatField(Field): default_error_messages = { - 'invalid': _("A valid number is required."), + 'invalid': _('A valid number is required.'), 'max_value': _('Ensure this value is less than or equal to {max_value}.'), 'min_value': _('Ensure this value is greater than or equal to {min_value}.'), - 'max_string_length': _('String value too large') + 'max_string_length': _('String value too large.') } MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs. @@ -709,7 +709,7 @@ class DecimalField(Field): 'max_digits': _('Ensure that there are no more than {max_digits} digits in total.'), 'max_decimal_places': _('Ensure that there are no more than {max_decimal_places} decimal places.'), 'max_whole_digits': _('Ensure that there are no more than {max_whole_digits} digits before the decimal point.'), - 'max_string_length': _('String value too large') + 'max_string_length': _('String value too large.') } MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs. @@ -792,7 +792,7 @@ class DecimalField(Field): class DateTimeField(Field): default_error_messages = { - 'invalid': _('Datetime has wrong format. Use one of these formats instead: {format}'), + 'invalid': _('Datetime has wrong format. Use one of these formats instead: {format}.'), 'date': _('Expected a datetime but got a date.'), } format = api_settings.DATETIME_FORMAT @@ -857,7 +857,7 @@ class DateTimeField(Field): class DateField(Field): default_error_messages = { - 'invalid': _('Date has wrong format. Use one of these formats instead: {format}'), + 'invalid': _('Date has wrong format. Use one of these formats instead: {format}.'), 'datetime': _('Expected a date but got a datetime.'), } format = api_settings.DATE_FORMAT @@ -915,7 +915,7 @@ class DateField(Field): class TimeField(Field): default_error_messages = { - 'invalid': _('Time has wrong format. Use one of these formats instead: {format}'), + 'invalid': _('Time has wrong format. Use one of these formats instead: {format}.'), } format = api_settings.TIME_FORMAT input_formats = api_settings.TIME_INPUT_FORMATS @@ -971,7 +971,7 @@ class TimeField(Field): class ChoiceField(Field): default_error_messages = { - 'invalid_choice': _('`{input}` is not a valid choice.') + 'invalid_choice': _('"{input}" is not a valid choice.') } def __init__(self, choices, **kwargs): @@ -1015,8 +1015,8 @@ class ChoiceField(Field): class MultipleChoiceField(ChoiceField): default_error_messages = { - 'invalid_choice': _('`{input}` is not a valid choice.'), - 'not_a_list': _('Expected a list of items but got type `{input_type}`.') + 'invalid_choice': _('"{input}" is not a valid choice.'), + 'not_a_list': _('Expected a list of items but got type "{input_type}".') } default_empty_html = [] @@ -1046,10 +1046,10 @@ class MultipleChoiceField(ChoiceField): class FileField(Field): default_error_messages = { - 'required': _("No file was submitted."), - 'invalid': _("The submitted data was not a file. Check the encoding type on the form."), - 'no_name': _("No filename could be determined."), - 'empty': _("The submitted file is empty."), + 'required': _('No file was submitted.'), + 'invalid': _('The submitted data was not a file. Check the encoding type on the form.'), + 'no_name': _('No filename could be determined.'), + 'empty': _('The submitted file is empty.'), 'max_length': _('Ensure this filename has at most {max_length} characters (it has {length}).'), } use_url = api_settings.UPLOADED_FILES_USE_URL @@ -1092,8 +1092,7 @@ class FileField(Field): class ImageField(FileField): default_error_messages = { 'invalid_image': _( - 'Upload a valid image. The file you uploaded was either not an ' - 'image or a corrupted image.' + 'Upload a valid image. The file you uploaded was either not an image or a corrupted image.' ), } @@ -1118,7 +1117,7 @@ class ListField(Field): child = None initial = [] default_error_messages = { - 'not_a_list': _('Expected a list of items but got type `{input_type}`') + 'not_a_list': _('Expected a list of items but got type "{input_type}".') } def __init__(self, *args, **kwargs): diff --git a/rest_framework/generics.py b/rest_framework/generics.py index e6db155e..0d709c37 100644 --- a/rest_framework/generics.py +++ b/rest_framework/generics.py @@ -119,15 +119,15 @@ class GenericAPIView(views.APIView): if page == 'last': page_number = paginator.num_pages else: - raise Http404(_("Page is not 'last', nor can it be converted to an int.")) + raise Http404(_('Choose a valid page number. Page numbers must be a whole number, or must be the string "last".')) + try: page = paginator.page(page_number) except InvalidPage as exc: - error_format = _('Invalid page (%(page_number)s): %(message)s') - raise Http404(error_format % { - 'page_number': page_number, - 'message': six.text_type(exc) - }) + error_format = _('Invalid page "{page_number}": {message}.') + raise Http404(error_format.format( + page_number=page_number, message=six.text_type(exc) + )) return page diff --git a/rest_framework/locale/en_US/LC_MESSAGES/django.po b/rest_framework/locale/en_US/LC_MESSAGES/django.po new file mode 100644 index 00000000..d98225ce --- /dev/null +++ b/rest_framework/locale/en_US/LC_MESSAGES/django.po @@ -0,0 +1,316 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-07 18:21+0000\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" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: authentication.py:69 +msgid "Invalid basic header. No credentials provided." +msgstr "" + +#: authentication.py:72 +msgid "Invalid basic header. Credentials string should not contain spaces." +msgstr "" + +#: authentication.py:78 +msgid "Invalid basic header. Credentials not correctly base64 encoded." +msgstr "" + +#: authentication.py:90 +msgid "Invalid username/password." +msgstr "" + +#: authentication.py:156 +msgid "Invalid token header. No credentials provided." +msgstr "" + +#: authentication.py:159 +msgid "Invalid token header. Token string should not contain spaces." +msgstr "" + +#: authentication.py:168 +msgid "Invalid token." +msgstr "" + +#: authentication.py:171 +msgid "User inactive or deleted." +msgstr "" + +#: authtoken/serializers.py:20 +msgid "User account is disabled." +msgstr "" + +#: authtoken/serializers.py:23 +msgid "Unable to log in with provided credentials." +msgstr "" + +#: authtoken/serializers.py:26 +msgid "Must include \"username\" and \"password\"." +msgstr "" + +#: exceptions.py:38 +msgid "A server error occurred." +msgstr "" + +#: exceptions.py:73 +msgid "Malformed request." +msgstr "" + +#: exceptions.py:78 +msgid "Incorrect authentication credentials." +msgstr "" + +#: exceptions.py:83 +msgid "Authentication credentials were not provided." +msgstr "" + +#: exceptions.py:88 +msgid "You do not have permission to perform this action." +msgstr "" + +#: exceptions.py:93 +msgid "Not found." +msgstr "" + +#: exceptions.py:98 +msgid "Method \"{method}\" not allowed." +msgstr "" + +#: exceptions.py:109 +msgid "Could not satisfy the request Accept header." +msgstr "" + +#: exceptions.py:121 +msgid "Unsupported media type \"{media_type}\" in request." +msgstr "" + +#: exceptions.py:134 +msgid "Request was throttled." +msgstr "" + +#: fields.py:152 relations.py:131 relations.py:155 validators.py:77 +#: validators.py:155 +msgid "This field is required." +msgstr "" + +#: fields.py:153 +msgid "This field may not be null." +msgstr "" + +#: fields.py:480 fields.py:508 +msgid "\"{input}\" is not a valid boolean." +msgstr "" + +#: fields.py:543 +msgid "This field may not be blank." +msgstr "" + +#: fields.py:544 fields.py:1252 +msgid "Ensure this field has no more than {max_length} characters." +msgstr "" + +#: fields.py:545 +msgid "Ensure this field has at least {min_length} characters." +msgstr "" + +#: fields.py:587 +msgid "Enter a valid email address." +msgstr "" + +#: fields.py:604 +msgid "This value does not match the required pattern." +msgstr "" + +#: fields.py:615 +msgid "" +"Enter a valid \"slug\" consisting of letters, numbers, underscores or " +"hyphens." +msgstr "" + +#: fields.py:627 +msgid "Enter a valid URL." +msgstr "" + +#: fields.py:640 +msgid "A valid integer is required." +msgstr "" + +#: fields.py:641 fields.py:675 fields.py:708 +msgid "Ensure this value is less than or equal to {max_value}." +msgstr "" + +#: fields.py:642 fields.py:676 fields.py:709 +msgid "Ensure this value is greater than or equal to {min_value}." +msgstr "" + +#: fields.py:643 fields.py:677 fields.py:713 +msgid "String value too large." +msgstr "" + +#: fields.py:674 fields.py:707 +msgid "A valid number is required." +msgstr "" + +#: fields.py:710 +msgid "Ensure that there are no more than {max_digits} digits in total." +msgstr "" + +#: fields.py:711 +msgid "Ensure that there are no more than {max_decimal_places} decimal places." +msgstr "" + +#: fields.py:712 +msgid "" +"Ensure that there are no more than {max_whole_digits} digits before the " +"decimal point." +msgstr "" + +#: fields.py:796 +msgid "Datetime has wrong format. Use one of these formats instead: {format}." +msgstr "" + +#: fields.py:797 +msgid "Expected a datetime but got a date." +msgstr "" + +#: fields.py:861 +msgid "Date has wrong format. Use one of these formats instead: {format}." +msgstr "" + +#: fields.py:862 +msgid "Expected a date but got a datetime." +msgstr "" + +#: fields.py:919 +msgid "Time has wrong format. Use one of these formats instead: {format}." +msgstr "" + +#: fields.py:975 fields.py:1019 +msgid "\"{input}\" is not a valid choice." +msgstr "" + +#: fields.py:1020 fields.py:1121 serializers.py:476 +msgid "Expected a list of items but got type \"{input_type}\"." +msgstr "" + +#: fields.py:1050 +msgid "No file was submitted." +msgstr "" + +#: fields.py:1051 +msgid "The submitted data was not a file. Check the encoding type on the form." +msgstr "" + +#: fields.py:1052 +msgid "No filename could be determined." +msgstr "" + +#: fields.py:1053 +msgid "The submitted file is empty." +msgstr "" + +#: fields.py:1054 +msgid "" +"Ensure this filename has at most {max_length} characters (it has {length})." +msgstr "" + +#: fields.py:1096 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "" + +#: generics.py:123 +msgid "" +"Choose a valid page number. Page numbers must be a whole number, or must be " +"the string \"last\"." +msgstr "" + +#: generics.py:128 +msgid "Invalid page \"{page_number}\": {message}." +msgstr "" + +#: relations.py:132 +msgid "Invalid pk \"{pk_value}\" - object does not exist." +msgstr "" + +#: relations.py:133 +msgid "Incorrect type. Expected pk value, received {data_type}." +msgstr "" + +#: relations.py:156 +msgid "Invalid hyperlink - No URL match." +msgstr "" + +#: relations.py:157 +msgid "Invalid hyperlink - Incorrect URL match." +msgstr "" + +#: relations.py:158 +msgid "Invalid hyperlink - Object does not exist." +msgstr "" + +#: relations.py:159 +msgid "Incorrect type. Expected URL string, received {data_type}." +msgstr "" + +#: relations.py:294 +msgid "Object with {slug_name}={value} does not exist." +msgstr "" + +#: relations.py:295 +msgid "Invalid value." +msgstr "" + +#: serializers.py:299 +msgid "Invalid data. Expected a dictionary, but got {datatype}." +msgstr "" + +#: validators.py:22 +msgid "This field must be unique." +msgstr "" + +#: validators.py:76 +msgid "The fields {field_names} must make a unique set." +msgstr "" + +#: validators.py:219 +msgid "This field must be unique for the \"{date_field}\" date." +msgstr "" + +#: validators.py:234 +msgid "This field must be unique for the \"{date_field}\" month." +msgstr "" + +#: validators.py:247 +msgid "This field must be unique for the \"{date_field}\" year." +msgstr "" + +#: versioning.py:39 +msgid "Invalid version in \"Accept\" header." +msgstr "" + +#: versioning.py:70 versioning.py:112 +msgid "Invalid version in URL path." +msgstr "" + +#: versioning.py:138 +msgid "Invalid version in hostname." +msgstr "" + +#: versioning.py:160 +msgid "Invalid version in query parameter." +msgstr "" diff --git a/rest_framework/relations.py b/rest_framework/relations.py index 7b119291..05ac3d1c 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -129,7 +129,7 @@ class StringRelatedField(RelatedField): class PrimaryKeyRelatedField(RelatedField): default_error_messages = { 'required': _('This field is required.'), - 'does_not_exist': _("Invalid pk '{pk_value}' - object does not exist."), + 'does_not_exist': _('Invalid pk "{pk_value}" - object does not exist.'), 'incorrect_type': _('Incorrect type. Expected pk value, received {data_type}.'), } @@ -153,7 +153,7 @@ class HyperlinkedRelatedField(RelatedField): default_error_messages = { 'required': _('This field is required.'), - 'no_match': _('Invalid hyperlink - No URL match'), + 'no_match': _('Invalid hyperlink - No URL match.'), 'incorrect_match': _('Invalid hyperlink - Incorrect URL match.'), 'does_not_exist': _('Invalid hyperlink - Object does not exist.'), 'incorrect_type': _('Incorrect type. Expected URL string, received {data_type}.'), @@ -291,7 +291,7 @@ class SlugRelatedField(RelatedField): """ default_error_messages = { - 'does_not_exist': _("Object with {slug_name}={value} does not exist."), + 'does_not_exist': _('Object with {slug_name}={value} does not exist.'), 'invalid': _('Invalid value.'), } diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index d1bd3ec3..77d3f202 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -479,7 +479,7 @@ class ListSerializer(BaseSerializer): many = True default_error_messages = { - 'not_a_list': _('Expected a list of items but got type `{input_type}`.') + 'not_a_list': _('Expected a list of items but got type "{input_type}".') } def __init__(self, *args, **kwargs): diff --git a/rest_framework/versioning.py b/rest_framework/versioning.py index 440efd13..e31c71e9 100644 --- a/rest_framework/versioning.py +++ b/rest_framework/versioning.py @@ -36,7 +36,7 @@ class AcceptHeaderVersioning(BaseVersioning): Host: example.com Accept: application/json; version=1.0 """ - invalid_version_message = _("Invalid version in 'Accept' header.") + invalid_version_message = _('Invalid version in "Accept" header.') def determine_version(self, request, *args, **kwargs): media_type = _MediaType(request.accepted_media_type) |
