diff options
| author | Tom Christie | 2014-11-19 12:15:05 +0000 | 
|---|---|---|
| committer | Tom Christie | 2014-11-19 12:15:05 +0000 | 
| commit | 6cb6510132b319c96b28bea732032aaf2d495895 (patch) | |
| tree | 3d6bd80aa18d311e36b13523aa9b5d2f04286fef /rest_framework/exceptions.py | |
| parent | 3eaf92e893ccb9b6c16c746cc24cc3c49297202b (diff) | |
| download | django-rest-framework-6cb6510132b319c96b28bea732032aaf2d495895.tar.bz2 | |
Use translatable error strings. Refs #2063.
Diffstat (limited to 'rest_framework/exceptions.py')
| -rw-r--r-- | rest_framework/exceptions.py | 74 | 
1 files changed, 56 insertions, 18 deletions
| diff --git a/rest_framework/exceptions.py b/rest_framework/exceptions.py index 0b06d6e6..dbab6684 100644 --- a/rest_framework/exceptions.py +++ b/rest_framework/exceptions.py @@ -5,7 +5,11 @@ In addition Django's built in 403 and 404 exceptions are handled.  (`django.http.Http404` and `django.core.exceptions.PermissionDenied`)  """  from __future__ import unicode_literals + +from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ungettext_lazy  from rest_framework import status +from rest_framework.compat import force_text  import math @@ -15,10 +19,13 @@ 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 occured')      def __init__(self, detail=None): -        self.detail = detail or self.default_detail +        if detail is not None: +            self.detail = force_text(detail) +        else: +            self.detail = force_text(self.default_detail)      def __str__(self):          return self.detail @@ -31,6 +38,19 @@ class APIException(Exception):  # from rest_framework import serializers  # raise serializers.ValidationError('Value was invalid') +def force_text_recursive(data): +    if isinstance(data, list): +        return [ +            force_text_recursive(item) for item in data +        ] +    elif isinstance(data, dict): +        return dict([ +            (key, force_text_recursive(value)) +            for key, value in data.items() +        ]) +    return force_text(data) + +  class ValidationError(APIException):      status_code = status.HTTP_400_BAD_REQUEST @@ -39,7 +59,7 @@ class ValidationError(APIException):          # The details should always be coerced to a list if not already.          if not isinstance(detail, dict) and not isinstance(detail, list):              detail = [detail] -        self.detail = detail +        self.detail = force_text_recursive(detail)      def __str__(self):          return str(self.detail) @@ -47,59 +67,77 @@ class ValidationError(APIException):  class ParseError(APIException):      status_code = status.HTTP_400_BAD_REQUEST -    default_detail = 'Malformed request.' +    default_detail = _('Malformed request.')  class AuthenticationFailed(APIException):      status_code = status.HTTP_401_UNAUTHORIZED -    default_detail = 'Incorrect authentication credentials.' +    default_detail = _('Incorrect authentication credentials.')  class NotAuthenticated(APIException):      status_code = status.HTTP_401_UNAUTHORIZED -    default_detail = 'Authentication credentials were not provided.' +    default_detail = _('Authentication credentials were not provided.')  class PermissionDenied(APIException):      status_code = status.HTTP_403_FORBIDDEN -    default_detail = 'You do not have permission to perform this action.' +    default_detail = _('You do not have permission to perform this action.')  class MethodNotAllowed(APIException):      status_code = status.HTTP_405_METHOD_NOT_ALLOWED -    default_detail = "Method '%s' not allowed." +    default_detail = _("Method '%s' not allowed.")      def __init__(self, method, detail=None): -        self.detail = detail or (self.default_detail % method) +        if detail is not None: +            self.detail = force_text(detail) +        else: +            self.detail = force_text(self.default_detail) % 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): -        self.detail = detail or self.default_detail +        if detail is not None: +            self.detail = force_text(detail) +        else: +            self.detail = force_text(self.default_detail)          self.available_renderers = available_renderers  class UnsupportedMediaType(APIException):      status_code = status.HTTP_415_UNSUPPORTED_MEDIA_TYPE -    default_detail = "Unsupported media type '%s' in request." +    default_detail = _("Unsupported media type '%s' in request.")      def __init__(self, media_type, detail=None): -        self.detail = detail or (self.default_detail % media_type) +        if detail is not None: +            self.detail = force_text(detail) +        else: +            self.detail = force_text(self.default_detail) % media_type  class Throttled(APIException):      status_code = status.HTTP_429_TOO_MANY_REQUESTS -    default_detail = 'Request was throttled.' -    extra_detail = " Expected available in %d second%s." +    default_detail = _('Request was throttled.') +    extra_detail = ungettext_lazy( +        'Expected available in %(wait)d second.', +        'Expected available in %(wait)d seconds.', +        'wait' +    )      def __init__(self, wait=None, detail=None): +        if detail is not None: +            self.detail = force_text(detail) +        else: +            self.detail = force_text(self.default_detail) +          if wait is None: -            self.detail = detail or self.default_detail              self.wait = None          else: -            format = (detail or self.default_detail) + self.extra_detail -            self.detail = format % (wait, wait != 1 and 's' or '')              self.wait = math.ceil(wait) +            self.detail += ' ' + force_text( +                self.extra_detail % {'wait': self.wait} +            ) | 
