diff options
| author | Tom Christie | 2015-02-13 13:38:44 +0000 | 
|---|---|---|
| committer | Tom Christie | 2015-02-13 13:38:44 +0000 | 
| commit | 4248a8d3fc725d9ae3fe7aaaad7ee12479ab07ab (patch) | |
| tree | c38485aec717a35de8691c3d55bd50ba3e4aae6d /rest_framework | |
| parent | 84260b5dd66cc31858898ff11d5300a73083cca1 (diff) | |
| parent | ad32e14360a23ee3e93ff54ca206c64009d184c9 (diff) | |
| download | django-rest-framework-4248a8d3fc725d9ae3fe7aaaad7ee12479ab07ab.tar.bz2 | |
Merge pull request #2198 from tomchristie/version-3.1
Version 3.1
Diffstat (limited to 'rest_framework')
74 files changed, 9176 insertions, 1145 deletions
| diff --git a/rest_framework/authentication.py b/rest_framework/authentication.py index f7601fb1..f0702286 100644 --- a/rest_framework/authentication.py +++ b/rest_framework/authentication.py @@ -3,14 +3,10 @@ Provides various authentication policies.  """  from __future__ import unicode_literals  import base64 -  from django.contrib.auth import authenticate -from django.core.exceptions import ImproperlyConfigured  from django.middleware.csrf import CsrfViewMiddleware -from django.conf import settings +from django.utils.translation import ugettext_lazy as _  from rest_framework import exceptions, HTTP_HEADER_ENCODING -from rest_framework.compat import oauth, oauth_provider, oauth_provider_store -from rest_framework.compat import oauth2_provider, provider_now, check_nonce  from rest_framework.authtoken.models import Token @@ -70,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] @@ -90,8 +86,13 @@ class BasicAuthentication(BaseAuthentication):          Authenticate the userid and password against username and password.          """          user = authenticate(username=userid, password=password) -        if user is None or not user.is_active: -            raise exceptions.AuthenticationFailed('Invalid username/password') + +        if user is None: +            raise exceptions.AuthenticationFailed(_('Invalid username/password.')) + +        if not user.is_active: +            raise exceptions.AuthenticationFailed(_('User inactive or deleted.')) +          return (user, None)      def authenticate_header(self, request): @@ -157,10 +158,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]) @@ -169,190 +170,12 @@ class TokenAuthentication(BaseAuthentication):          try:              token = self.model.objects.select_related('user').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)      def authenticate_header(self, request):          return 'Token' - - -class OAuthAuthentication(BaseAuthentication): -    """ -    OAuth 1.0a authentication backend using `django-oauth-plus` and `oauth2`. - -    Note: The `oauth2` package actually provides oauth1.0a support.  Urg. -          We import it from the `compat` module as `oauth`. -    """ -    www_authenticate_realm = 'api' - -    def __init__(self, *args, **kwargs): -        super(OAuthAuthentication, self).__init__(*args, **kwargs) - -        if oauth is None: -            raise ImproperlyConfigured( -                "The 'oauth2' package could not be imported." -                "It is required for use with the 'OAuthAuthentication' class.") - -        if oauth_provider is None: -            raise ImproperlyConfigured( -                "The 'django-oauth-plus' package could not be imported." -                "It is required for use with the 'OAuthAuthentication' class.") - -    def authenticate(self, request): -        """ -        Returns two-tuple of (user, token) if authentication succeeds, -        or None otherwise. -        """ -        try: -            oauth_request = oauth_provider.utils.get_oauth_request(request) -        except oauth.Error as err: -            raise exceptions.AuthenticationFailed(err.message) - -        if not oauth_request: -            return None - -        oauth_params = oauth_provider.consts.OAUTH_PARAMETERS_NAMES - -        found = any(param for param in oauth_params if param in oauth_request) -        missing = list(param for param in oauth_params if param not in oauth_request) - -        if not found: -            # OAuth authentication was not attempted. -            return None - -        if missing: -            # OAuth was attempted but missing parameters. -            msg = 'Missing parameters: %s' % (', '.join(missing)) -            raise exceptions.AuthenticationFailed(msg) - -        if not self.check_nonce(request, oauth_request): -            msg = 'Nonce check failed' -            raise exceptions.AuthenticationFailed(msg) - -        try: -            consumer_key = oauth_request.get_parameter('oauth_consumer_key') -            consumer = oauth_provider_store.get_consumer(request, oauth_request, consumer_key) -        except oauth_provider.store.InvalidConsumerError: -            msg = 'Invalid consumer token: %s' % oauth_request.get_parameter('oauth_consumer_key') -            raise exceptions.AuthenticationFailed(msg) - -        if consumer.status != oauth_provider.consts.ACCEPTED: -            msg = 'Invalid consumer key status: %s' % consumer.get_status_display() -            raise exceptions.AuthenticationFailed(msg) - -        try: -            token_param = oauth_request.get_parameter('oauth_token') -            token = oauth_provider_store.get_access_token(request, oauth_request, consumer, token_param) -        except oauth_provider.store.InvalidTokenError: -            msg = 'Invalid access token: %s' % oauth_request.get_parameter('oauth_token') -            raise exceptions.AuthenticationFailed(msg) - -        try: -            self.validate_token(request, consumer, token) -        except oauth.Error as err: -            raise exceptions.AuthenticationFailed(err.message) - -        user = token.user - -        if not user.is_active: -            msg = 'User inactive or deleted: %s' % user.username -            raise exceptions.AuthenticationFailed(msg) - -        return (token.user, token) - -    def authenticate_header(self, request): -        """ -        If permission is denied, return a '401 Unauthorized' response, -        with an appropriate 'WWW-Authenticate' header. -        """ -        return 'OAuth realm="%s"' % self.www_authenticate_realm - -    def validate_token(self, request, consumer, token): -        """ -        Check the token and raise an `oauth.Error` exception if invalid. -        """ -        oauth_server, oauth_request = oauth_provider.utils.initialize_server_request(request) -        oauth_server.verify_request(oauth_request, consumer, token) - -    def check_nonce(self, request, oauth_request): -        """ -        Checks nonce of request, and return True if valid. -        """ -        oauth_nonce = oauth_request['oauth_nonce'] -        oauth_timestamp = oauth_request['oauth_timestamp'] -        return check_nonce(request, oauth_request, oauth_nonce, oauth_timestamp) - - -class OAuth2Authentication(BaseAuthentication): -    """ -    OAuth 2 authentication backend using `django-oauth2-provider` -    """ -    www_authenticate_realm = 'api' -    allow_query_params_token = settings.DEBUG - -    def __init__(self, *args, **kwargs): -        super(OAuth2Authentication, self).__init__(*args, **kwargs) - -        if oauth2_provider is None: -            raise ImproperlyConfigured( -                "The 'django-oauth2-provider' package could not be imported. " -                "It is required for use with the 'OAuth2Authentication' class.") - -    def authenticate(self, request): -        """ -        Returns two-tuple of (user, token) if authentication succeeds, -        or None otherwise. -        """ - -        auth = get_authorization_header(request).split() - -        if len(auth) == 1: -            msg = 'Invalid bearer header. No credentials provided.' -            raise exceptions.AuthenticationFailed(msg) -        elif len(auth) > 2: -            msg = 'Invalid bearer header. Token string should not contain spaces.' -            raise exceptions.AuthenticationFailed(msg) - -        if auth and auth[0].lower() == b'bearer': -            access_token = auth[1] -        elif 'access_token' in request.POST: -            access_token = request.POST['access_token'] -        elif 'access_token' in request.GET and self.allow_query_params_token: -            access_token = request.GET['access_token'] -        else: -            return None - -        return self.authenticate_credentials(request, access_token) - -    def authenticate_credentials(self, request, access_token): -        """ -        Authenticate the request, given the access token. -        """ - -        try: -            token = oauth2_provider.oauth2.models.AccessToken.objects.select_related('user') -            # provider_now switches to timezone aware datetime when -            # the oauth2_provider version supports to it. -            token = token.get(token=access_token, expires__gt=provider_now()) -        except oauth2_provider.oauth2.models.AccessToken.DoesNotExist: -            raise exceptions.AuthenticationFailed('Invalid token') - -        user = token.user - -        if not user.is_active: -            msg = 'User inactive or deleted: %s' % user.get_username() -            raise exceptions.AuthenticationFailed(msg) - -        return (user, token) - -    def authenticate_header(self, request): -        """ -        Bearer is the only finalized type currently - -        Check details on the `OAuth2Authentication.authenticate` method -        """ -        return 'Bearer realm="%s"' % self.www_authenticate_realm 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/compat.py b/rest_framework/compat.py index 36413394..50f37014 100644 --- a/rest_framework/compat.py +++ b/rest_framework/compat.py @@ -5,15 +5,13 @@ versions of django/python, and compatibility wrappers around optional packages.  # flake8: noqa  from __future__ import unicode_literals - -import inspect -  from django.core.exceptions import ImproperlyConfigured +from django.conf import settings  from django.utils.encoding import force_text  from django.utils.six.moves.urllib.parse import urlparse as _urlparse -from django.conf import settings  from django.utils import six  import django +import inspect  def unicode_repr(instance): @@ -33,6 +31,13 @@ def unicode_to_repr(value):      return value +def unicode_http_header(value): +    # Coerce HTTP header value to unicode. +    if isinstance(value, six.binary_type): +        return value.decode('iso-8859-1') +    return value + +  def total_seconds(timedelta):      # TimeDelta.total_seconds() is only available in Python 2.7      if hasattr(timedelta, 'total_seconds'): @@ -232,77 +237,13 @@ except ImportError:      apply_markdown = None -# Yaml is optional -try: -    import yaml -except ImportError: -    yaml = None - - -# XML is optional -try: -    import defusedxml.ElementTree as etree -except ImportError: -    etree = None - - -# OAuth2 is optional -try: -    # Note: The `oauth2` package actually provides oauth1.0a support.  Urg. -    import oauth2 as oauth -except ImportError: -    oauth = None - - -# OAuthProvider is optional -try: -    import oauth_provider -    from oauth_provider.store import store as oauth_provider_store - -    # check_nonce's calling signature in django-oauth-plus changes sometime -    # between versions 2.0 and 2.2.1 -    def check_nonce(request, oauth_request, oauth_nonce, oauth_timestamp): -        check_nonce_args = inspect.getargspec(oauth_provider_store.check_nonce).args -        if 'timestamp' in check_nonce_args: -            return oauth_provider_store.check_nonce( -                request, oauth_request, oauth_nonce, oauth_timestamp -            ) -        return oauth_provider_store.check_nonce( -            request, oauth_request, oauth_nonce -        ) - -except (ImportError, ImproperlyConfigured): -    oauth_provider = None -    oauth_provider_store = None -    check_nonce = None - - -# OAuth 2 support is optional -try: -    import provider as oauth2_provider -    from provider import scope as oauth2_provider_scope -    from provider import constants as oauth2_constants - -    if oauth2_provider.__version__ in ('0.2.3', '0.2.4'): -        # 0.2.3 and 0.2.4 are supported version that do not support -        # timezone aware datetimes -        import datetime - -        provider_now = datetime.datetime.now -    else: -        # Any other supported version does use timezone aware datetimes -        from django.utils.timezone import now as provider_now -except ImportError: -    oauth2_provider = None -    oauth2_provider_scope = None -    oauth2_constants = None -    provider_now = None -  # `separators` argument to `json.dumps()` differs between 2.x and 3.x  # See: http://bugs.python.org/issue22767  if six.PY3:      SHORT_SEPARATORS = (',', ':')      LONG_SEPARATORS = (', ', ': ') +    INDENT_SEPARATORS = (',', ': ')  else:      SHORT_SEPARATORS = (b',', b':')      LONG_SEPARATORS = (b', ', b': ') +    INDENT_SEPARATORS = (b',', b': ') diff --git a/rest_framework/exceptions.py b/rest_framework/exceptions.py index 1f381e4e..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: @@ -89,20 +88,25 @@ class PermissionDenied(APIException):      default_detail = _('You do not have permission to perform this action.') +class NotFound(APIException): +    status_code = status.HTTP_404_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: @@ -114,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: @@ -142,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 71a9f193..a5348922 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -484,7 +484,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 @@ -512,7 +512,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)) @@ -555,6 +555,7 @@ class CharField(Field):      def __init__(self, **kwargs):          self.allow_blank = kwargs.pop('allow_blank', False) +        self.trim_whitespace = kwargs.pop('trim_whitespace', True)          max_length = kwargs.pop('max_length', None)          min_length = kwargs.pop('min_length', None)          super(CharField, self).__init__(**kwargs) @@ -576,7 +577,8 @@ class CharField(Field):          return super(CharField, self).run_validation(data)      def to_internal_value(self, data): -        return six.text_type(data) +        value = six.text_type(data) +        return value.strip() if self.trim_whitespace else value      def to_representation(self, value):          return six.text_type(value) @@ -592,12 +594,6 @@ class EmailField(CharField):          validator = EmailValidator(message=self.error_messages['invalid'])          self.validators.append(validator) -    def to_internal_value(self, data): -        return six.text_type(data).strip() - -    def to_representation(self, value): -        return six.text_type(value).strip() -  class RegexField(CharField):      default_error_messages = { @@ -612,7 +608,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): @@ -624,7 +620,7 @@ class SlugField(CharField):  class URLField(CharField):      default_error_messages = { -        'invalid': _("Enter a valid URL.") +        'invalid': _('Enter a valid URL.')      }      def __init__(self, **kwargs): @@ -657,7 +653,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. @@ -688,10 +684,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. @@ -727,7 +723,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. @@ -810,7 +806,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 @@ -875,7 +871,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 @@ -933,7 +929,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 @@ -989,7 +985,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): @@ -1033,8 +1029,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 = [] @@ -1064,10 +1060,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 @@ -1110,8 +1106,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.'          ),      } @@ -1149,7 +1144,7 @@ class ListField(Field):      child = _UnvalidatedField()      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): @@ -1186,7 +1181,7 @@ class DictField(Field):      child = _UnvalidatedField()      initial = []      default_error_messages = { -        'not_a_dict': _('Expected a dictionary of items but got type `{input_type}`') +        'not_a_dict': _('Expected a dictionary of items but got type "{input_type}".')      }      def __init__(self, *args, **kwargs): @@ -1197,9 +1192,9 @@ class DictField(Field):      def get_value(self, dictionary):          # We override the default field access in order to support -        # lists in HTML forms. +        # dictionaries in HTML forms.          if html.is_html_input(dictionary): -            return html.parse_html_list(dictionary, prefix=self.field_name) +            return html.parse_html_dict(dictionary, prefix=self.field_name)          return dictionary.get(self.field_name, empty)      def to_internal_value(self, data): diff --git a/rest_framework/filters.py b/rest_framework/filters.py index d3f55a44..9a84efa2 100644 --- a/rest_framework/filters.py +++ b/rest_framework/filters.py @@ -114,7 +114,7 @@ class OrderingFilter(BaseFilterBackend):      ordering_param = api_settings.ORDERING_PARAM      ordering_fields = None -    def get_ordering(self, request): +    def get_ordering(self, request, queryset, view):          """          Ordering is set by a comma delimited ?ordering=... query parameter. @@ -124,7 +124,13 @@ class OrderingFilter(BaseFilterBackend):          """          params = request.query_params.get(self.ordering_param)          if params: -            return [param.strip() for param in params.split(',')] +            fields = [param.strip() for param in params.split(',')] +            ordering = self.remove_invalid_fields(queryset, fields, view) +            if ordering: +                return ordering + +        # No ordering was included, or all the ordering fields were invalid +        return self.get_default_ordering(view)      def get_default_ordering(self, view):          ordering = getattr(view, 'ordering', None) @@ -132,7 +138,7 @@ class OrderingFilter(BaseFilterBackend):              return (ordering,)          return ordering -    def remove_invalid_fields(self, queryset, ordering, view): +    def remove_invalid_fields(self, queryset, fields, view):          valid_fields = getattr(view, 'ordering_fields', self.ordering_fields)          if valid_fields is None: @@ -152,18 +158,10 @@ class OrderingFilter(BaseFilterBackend):              valid_fields = [field.name for field in queryset.model._meta.fields]              valid_fields += queryset.query.aggregates.keys() -        return [term for term in ordering if term.lstrip('-') in valid_fields] +        return [term for term in fields if term.lstrip('-') in valid_fields]      def filter_queryset(self, request, queryset, view): -        ordering = self.get_ordering(request) - -        if ordering: -            # Skip any incorrect parameters -            ordering = self.remove_invalid_fields(queryset, ordering, view) - -        if not ordering: -            # Use 'ordering' attribute by default -            ordering = self.get_default_ordering(view) +        ordering = self.get_ordering(request, queryset, view)          if ordering:              return queryset.order_by(*ordering) diff --git a/rest_framework/generics.py b/rest_framework/generics.py index e6db155e..61dcb84a 100644 --- a/rest_framework/generics.py +++ b/rest_framework/generics.py @@ -2,29 +2,13 @@  Generic views that provide commonly needed behaviour.  """  from __future__ import unicode_literals - -from django.core.paginator import Paginator, InvalidPage  from django.db.models.query import QuerySet  from django.http import Http404  from django.shortcuts import get_object_or_404 as _get_object_or_404 -from django.utils import six -from django.utils.translation import ugettext as _  from rest_framework import views, mixins  from rest_framework.settings import api_settings -def strict_positive_int(integer_string, cutoff=None): -    """ -    Cast a string to a strictly positive integer. -    """ -    ret = int(integer_string) -    if ret <= 0: -        raise ValueError() -    if cutoff: -        ret = min(ret, cutoff) -    return ret - -  def get_object_or_404(queryset, *filter_args, **filter_kwargs):      """      Same as Django's standard shortcut, but make sure to also raise 404 @@ -40,7 +24,6 @@ class GenericAPIView(views.APIView):      """      Base class for all other generic views.      """ -      # You'll need to either set these attributes,      # or override `get_queryset()`/`get_serializer_class()`.      # If you are overriding a view method, it is important that you call @@ -50,146 +33,16 @@ class GenericAPIView(views.APIView):      queryset = None      serializer_class = None -    # If you want to use object lookups other than pk, set this attribute. +    # If you want to use object lookups other than pk, set 'lookup_field'.      # For more complex lookup requirements override `get_object()`.      lookup_field = 'pk'      lookup_url_kwarg = None -    # Pagination settings -    paginate_by = api_settings.PAGINATE_BY -    paginate_by_param = api_settings.PAGINATE_BY_PARAM -    max_paginate_by = api_settings.MAX_PAGINATE_BY -    pagination_serializer_class = api_settings.DEFAULT_PAGINATION_SERIALIZER_CLASS -    page_kwarg = 'page' -      # The filter backend classes to use for queryset filtering      filter_backends = api_settings.DEFAULT_FILTER_BACKENDS -    # The following attribute may be subject to change, -    # and should be considered private API. -    paginator_class = Paginator - -    def get_serializer_context(self): -        """ -        Extra context provided to the serializer class. -        """ -        return { -            'request': self.request, -            'format': self.format_kwarg, -            'view': self -        } - -    def get_serializer(self, *args, **kwargs): -        """ -        Return the serializer instance that should be used for validating and -        deserializing input, and for serializing output. -        """ -        serializer_class = self.get_serializer_class() -        kwargs['context'] = self.get_serializer_context() -        return serializer_class(*args, **kwargs) - -    def get_pagination_serializer(self, page): -        """ -        Return a serializer instance to use with paginated data. -        """ -        class SerializerClass(self.pagination_serializer_class): -            class Meta: -                object_serializer_class = self.get_serializer_class() - -        pagination_serializer_class = SerializerClass -        context = self.get_serializer_context() -        return pagination_serializer_class(instance=page, context=context) - -    def paginate_queryset(self, queryset): -        """ -        Paginate a queryset if required, either returning a page object, -        or `None` if pagination is not configured for this view. -        """ -        page_size = self.get_paginate_by() -        if not page_size: -            return None - -        paginator = self.paginator_class(queryset, page_size) -        page_kwarg = self.kwargs.get(self.page_kwarg) -        page_query_param = self.request.query_params.get(self.page_kwarg) -        page = page_kwarg or page_query_param or 1 -        try: -            page_number = paginator.validate_number(page) -        except InvalidPage: -            if page == 'last': -                page_number = paginator.num_pages -            else: -                raise Http404(_("Page is not 'last', nor can it be converted to an int.")) -        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) -            }) - -        return page - -    def filter_queryset(self, queryset): -        """ -        Given a queryset, filter it with whichever filter backend is in use. - -        You are unlikely to want to override this method, although you may need -        to call it either from a list view, or from a custom `get_object` -        method if you want to apply the configured filtering backend to the -        default queryset. -        """ -        for backend in self.get_filter_backends(): -            queryset = backend().filter_queryset(self.request, queryset, self) -        return queryset - -    def get_filter_backends(self): -        """ -        Returns the list of filter backends that this view requires. -        """ -        return list(self.filter_backends) - -    # The following methods provide default implementations -    # that you may want to override for more complex cases. - -    def get_paginate_by(self): -        """ -        Return the size of pages to use with pagination. - -        If `PAGINATE_BY_PARAM` is set it will attempt to get the page size -        from a named query parameter in the url, eg. ?page_size=100 - -        Otherwise defaults to using `self.paginate_by`. -        """ -        if self.paginate_by_param: -            try: -                return strict_positive_int( -                    self.request.query_params[self.paginate_by_param], -                    cutoff=self.max_paginate_by -                ) -            except (KeyError, ValueError): -                pass - -        return self.paginate_by - -    def get_serializer_class(self): -        """ -        Return the class to use for the serializer. -        Defaults to using `self.serializer_class`. - -        You may want to override this if you need to provide different -        serializations depending on the incoming request. - -        (Eg. admins get full serialization, others get basic serialization) -        """ -        assert self.serializer_class is not None, ( -            "'%s' should either include a `serializer_class` attribute, " -            "or override the `get_serializer_class()` method." -            % self.__class__.__name__ -        ) - -        return self.serializer_class +    # The style to use for queryset pagination. +    pagination_class = api_settings.DEFAULT_PAGINATION_CLASS      def get_queryset(self):          """ @@ -246,6 +99,83 @@ class GenericAPIView(views.APIView):          return obj +    def get_serializer(self, *args, **kwargs): +        """ +        Return the serializer instance that should be used for validating and +        deserializing input, and for serializing output. +        """ +        serializer_class = self.get_serializer_class() +        kwargs['context'] = self.get_serializer_context() +        return serializer_class(*args, **kwargs) + +    def get_serializer_class(self): +        """ +        Return the class to use for the serializer. +        Defaults to using `self.serializer_class`. + +        You may want to override this if you need to provide different +        serializations depending on the incoming request. + +        (Eg. admins get full serialization, others get basic serialization) +        """ +        assert self.serializer_class is not None, ( +            "'%s' should either include a `serializer_class` attribute, " +            "or override the `get_serializer_class()` method." +            % self.__class__.__name__ +        ) + +        return self.serializer_class + +    def get_serializer_context(self): +        """ +        Extra context provided to the serializer class. +        """ +        return { +            'request': self.request, +            'format': self.format_kwarg, +            'view': self +        } + +    def filter_queryset(self, queryset): +        """ +        Given a queryset, filter it with whichever filter backend is in use. + +        You are unlikely to want to override this method, although you may need +        to call it either from a list view, or from a custom `get_object` +        method if you want to apply the configured filtering backend to the +        default queryset. +        """ +        for backend in list(self.filter_backends): +            queryset = backend().filter_queryset(self.request, queryset, self) +        return queryset + +    @property +    def paginator(self): +        """ +        The paginator instance associated with the view, or `None`. +        """ +        if not hasattr(self, '_paginator'): +            if self.pagination_class is None: +                self._paginator = None +            else: +                self._paginator = self.pagination_class() +        return self._paginator + +    def paginate_queryset(self, queryset): +        """ +        Return a single page of results, or `None` if pagination is disabled. +        """ +        if self.paginator is None: +            return None +        return self.paginator.paginate_queryset(queryset, self.request, view=self) + +    def get_paginated_response(self, data): +        """ +        Return a paginated style `Response` object for the given output data. +        """ +        assert self.paginator is not None +        return self.paginator.get_paginated_response(data) +  # Concrete view classes that provide method handlers  # by composing the mixin classes with the base view. diff --git a/rest_framework/locale/ar/LC_MESSAGES/django.mo b/rest_framework/locale/ar/LC_MESSAGES/django.moBinary files differ new file mode 100644 index 00000000..fe1b676c --- /dev/null +++ b/rest_framework/locale/ar/LC_MESSAGES/django.mo diff --git a/rest_framework/locale/ar/LC_MESSAGES/django.po b/rest_framework/locale/ar/LC_MESSAGES/django.po new file mode 100644 index 00000000..a910a7c9 --- /dev/null +++ b/rest_framework/locale/ar/LC_MESSAGES/django.po @@ -0,0 +1,325 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +#  +# Translators: +# Eyad Toma <d.eyad.t@gmail.com>, 2015 +msgid "" +msgstr "" +"Project-Id-Version: Django REST framework\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-30 16:23+0000\n" +"PO-Revision-Date: 2015-01-30 16:27+0000\n" +"Last-Translator: Thomas Christie <tom@tomchristie.com>\n" +"Language-Team: Arabic (http://www.transifex.com/projects/p/django-rest-framework/language/ar/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: ar\n" +"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\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 "المستخدم غير مفعل او تم حذفه." + +#: 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:153 relations.py:132 relations.py:156 validators.py:77 +#: validators.py:155 +msgid "This field is required." +msgstr "هذا الحقل مطلوب." + +#: fields.py:154 +msgid "This field may not be null." +msgstr "لا يمكن لهذا الحقل ان يكون فارغاً null." + +#: fields.py:487 fields.py:515 +msgid "\"{input}\" is not a valid boolean." +msgstr "\"{input}\" ليس قيمة منطقية." + +#: fields.py:550 +msgid "This field may not be blank." +msgstr "لا يمكن لهذا الحقل ان يكون فارغاً." + +#: fields.py:551 fields.py:1324 +msgid "Ensure this field has no more than {max_length} characters." +msgstr "تأكد ان الحقل لا يزيد عن {max_length} محرف." + +#: fields.py:552 +msgid "Ensure this field has at least {min_length} characters." +msgstr "تأكد ان الحقل {min_length} محرف على الاقل." + +#: 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:638 +msgid "\"{value}\" is not a valid UUID." +msgstr "" + +#: fields.py:657 +msgid "A valid integer is required." +msgstr "الرجاء إدخال رقم صحيح صالح." + +#: fields.py:658 fields.py:692 fields.py:725 +msgid "Ensure this value is less than or equal to {max_value}." +msgstr "تأكد ان القيمة أقل أو تساوي {max_value}." + +#: fields.py:659 fields.py:693 fields.py:726 +msgid "Ensure this value is greater than or equal to {min_value}." +msgstr "تأكد ان القيمة أكبر أو تساوي {min_value}." + +#: fields.py:660 fields.py:694 fields.py:730 +msgid "String value too large." +msgstr "" + +#: fields.py:691 fields.py:724 +msgid "A valid number is required." +msgstr "الرجاء إدخال رقم صالح." + +#: fields.py:727 +msgid "Ensure that there are no more than {max_digits} digits in total." +msgstr "تأكد ان القيمة لا تحوي أكثر من {max_digits} رقم." + +#: fields.py:728 +msgid "" +"Ensure that there are no more than {max_decimal_places} decimal places." +msgstr "" + +#: fields.py:729 +msgid "" +"Ensure that there are no more than {max_whole_digits} digits before the " +"decimal point." +msgstr "" + +#: fields.py:813 +msgid "Datetime has wrong format. Use one of these formats instead: {format}." +msgstr "صيغة التاريخ و الوقت غير صحيحة. عليك أن تستخدم واحدة من هذه الصيغ التالية: {format}." + +#: fields.py:814 +msgid "Expected a datetime but got a date." +msgstr "" + +#: fields.py:878 +msgid "Date has wrong format. Use one of these formats instead: {format}." +msgstr "صيغة التاريخ غير صحيحة. عليك أن تستخدم واحدة من هذه الصيغ التالية: {format}." + +#: fields.py:879 +msgid "Expected a date but got a datetime." +msgstr "" + +#: fields.py:936 +msgid "Time has wrong format. Use one of these formats instead: {format}." +msgstr "صيغة الوقت غير صحيحة. عليك أن تستخدم واحدة من هذه الصيغ التالية: {format}." + +#: fields.py:992 fields.py:1036 +msgid "\"{input}\" is not a valid choice." +msgstr "\"{input}\" ليست واحدة من الخيارات الصالحة." + +#: fields.py:1037 fields.py:1151 serializers.py:482 +msgid "Expected a list of items but got type \"{input_type}\"." +msgstr "" + +#: fields.py:1067 +msgid "No file was submitted." +msgstr "لم يتم إرسال أي ملف." + +#: fields.py:1068 +msgid "" +"The submitted data was not a file. Check the encoding type on the form." +msgstr "" + +#: fields.py:1069 +msgid "No filename could be determined." +msgstr "" + +#: fields.py:1070 +msgid "The submitted file is empty." +msgstr "الملف الذي تم إرساله فارغ." + +#: fields.py:1071 +msgid "" +"Ensure this filename has at most {max_length} characters (it has {length})." +msgstr "تأكد ان اسم الملف لا يحوي أكثر من {max_length} محرف (الإسم المرسل يحوي {length} محرف)." + +#: fields.py:1113 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "" + +#: fields.py:1188 +msgid "Expected a dictionary of items but got type \"{input_type}\"." +msgstr "" + +#: pagination.py:221 +msgid "Invalid page \"{page_number}\": {message}." +msgstr "رقم الصفحة \"{page_number}\" غير صالح : {message}." + +#: pagination.py:442 +msgid "Invalid cursor" +msgstr "" + +#: relations.py:133 +msgid "Invalid pk \"{pk_value}\" - object does not exist." +msgstr "معرف العنصر \"{pk_value}\" غير صالح -  العنصر غير موجود." + +#: relations.py:134 +msgid "Incorrect type. Expected pk value, received {data_type}." +msgstr "" + +#: relations.py:157 +msgid "Invalid hyperlink - No URL match." +msgstr "" + +#: relations.py:158 +msgid "Invalid hyperlink - Incorrect URL match." +msgstr "" + +#: relations.py:159 +msgid "Invalid hyperlink - Object does not exist." +msgstr "" + +#: relations.py:160 +msgid "Incorrect type. Expected URL string, received {data_type}." +msgstr "" + +#: relations.py:295 +msgid "Object with {slug_name}={value} does not exist." +msgstr "" + +#: relations.py:296 +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 "" + +#: 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 "يجب أن تتضمن \"اسم المستخدم\" و \"كلمة المرور\"." diff --git a/rest_framework/locale/cs/LC_MESSAGES/django.mo b/rest_framework/locale/cs/LC_MESSAGES/django.moBinary files differ new file mode 100644 index 00000000..a5e67713 --- /dev/null +++ b/rest_framework/locale/cs/LC_MESSAGES/django.mo diff --git a/rest_framework/locale/cs/LC_MESSAGES/django.po b/rest_framework/locale/cs/LC_MESSAGES/django.po new file mode 100644 index 00000000..50e7034b --- /dev/null +++ b/rest_framework/locale/cs/LC_MESSAGES/django.po @@ -0,0 +1,325 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +#  +# Translators: +# Jirka Vejrazka <Jirka.Vejrazka@gmail.com>, 2015 +msgid "" +msgstr "" +"Project-Id-Version: Django REST framework\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-30 16:23+0000\n" +"PO-Revision-Date: 2015-01-30 16:27+0000\n" +"Last-Translator: Thomas Christie <tom@tomchristie.com>\n" +"Language-Team: Czech (http://www.transifex.com/projects/p/django-rest-framework/language/cs/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: cs\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" + +#: authentication.py:69 +msgid "Invalid basic header. No credentials provided." +msgstr "Chybná hlavička. Nebyly poskytnuty přihlašovací údaje." + +#: authentication.py:72 +msgid "Invalid basic header. Credentials string should not contain spaces." +msgstr "Chybná hlavička. Přihlašovací údaje by neměly obsahovat mezery." + +#: authentication.py:78 +msgid "Invalid basic header. Credentials not correctly base64 encoded." +msgstr "Chybná hlavička. Přihlašovací údaje nebyly správně zakódovány pomocí base64." + +#: authentication.py:90 +msgid "Invalid username/password." +msgstr "Chybné uživatelské jméno nebo heslo." + +#: authentication.py:156 +msgid "Invalid token header. No credentials provided." +msgstr "Chybná hlavička tokenu. Nebyly zadány přihlašovací údaje." + +#: authentication.py:159 +msgid "Invalid token header. Token string should not contain spaces." +msgstr "Chybná hlavička tokenu. Přihlašovací údaje by neměly obsahovat mezery." + +#: authentication.py:168 +msgid "Invalid token." +msgstr "Chybný token." + +#: authentication.py:171 +msgid "User inactive or deleted." +msgstr "Uživatelský účet je neaktivní nebo byl smazán." + +#: exceptions.py:38 +msgid "A server error occurred." +msgstr "Chyba na straně serveru." + +#: exceptions.py:73 +msgid "Malformed request." +msgstr "Neplatný formát požadavku." + +#: exceptions.py:78 +msgid "Incorrect authentication credentials." +msgstr "Chybné přihlašovací údaje." + +#: exceptions.py:83 +msgid "Authentication credentials were not provided." +msgstr "Přihlašovací údaje nebyly zadány." + +#: exceptions.py:88 +msgid "You do not have permission to perform this action." +msgstr "K této akci nemáte oprávnění." + +#: exceptions.py:93 +msgid "Not found." +msgstr "Nenalezeno." + +#: exceptions.py:98 +msgid "Method \"{method}\" not allowed." +msgstr "Metoda \"{method}\" není povolena." + +#: exceptions.py:109 +msgid "Could not satisfy the request Accept header." +msgstr "Nelze vyhovět požadavku v hlavičce Accept." + +#: exceptions.py:121 +msgid "Unsupported media type \"{media_type}\" in request." +msgstr "Nepodporovaný media type \"{media_type}\" v požadavku." + +#: exceptions.py:134 +msgid "Request was throttled." +msgstr "Pořadavek byl limitován kvůli omezení počtu požadavků za časovou periodu." + +#: fields.py:153 relations.py:132 relations.py:156 validators.py:77 +#: validators.py:155 +msgid "This field is required." +msgstr "Toto pole je vyžadováno." + +#: fields.py:154 +msgid "This field may not be null." +msgstr "Toto pole nesmí být prázdné (null)." + +#: fields.py:487 fields.py:515 +msgid "\"{input}\" is not a valid boolean." +msgstr "\"{input}\" nelze použít jako typ boolean." + +#: fields.py:550 +msgid "This field may not be blank." +msgstr "Toto pole nesmí být prázdné.." + +#: fields.py:551 fields.py:1324 +msgid "Ensure this field has no more than {max_length} characters." +msgstr "Zkontrolujte, že toto pole není delší než {max_length} znaků." + +#: fields.py:552 +msgid "Ensure this field has at least {min_length} characters." +msgstr "Zkontrolujte, že toto obsahuje alespoň {min_length} znaků" + +#: fields.py:587 +msgid "Enter a valid email address." +msgstr "Vložte platnou e-mailovou adresu." + +#: fields.py:604 +msgid "This value does not match the required pattern." +msgstr "Hodnota v tomto poli neodpovídá požadovanému formátu." + +#: fields.py:615 +msgid "" +"Enter a valid \"slug\" consisting of letters, numbers, underscores or " +"hyphens." +msgstr "Vložte platnou \"zkrácenou formu\" obsahující pouze malá písmena, čísla, spojovník nebo podtržítko." + +#: fields.py:627 +msgid "Enter a valid URL." +msgstr "Vložte platný odkaz." + +#: fields.py:638 +msgid "\"{value}\" is not a valid UUID." +msgstr "" + +#: fields.py:657 +msgid "A valid integer is required." +msgstr "Je vyžadováno číslo." + +#: fields.py:658 fields.py:692 fields.py:725 +msgid "Ensure this value is less than or equal to {max_value}." +msgstr "Zkontrolujte, že hodnota je menší nebo rovna {max_value}." + +#: fields.py:659 fields.py:693 fields.py:726 +msgid "Ensure this value is greater than or equal to {min_value}." +msgstr "Zkontrolujte, že hodnota je větší nebo rovna {min_value}." + +#: fields.py:660 fields.py:694 fields.py:730 +msgid "String value too large." +msgstr "Řetězec je příliš dlouhý" + +#: fields.py:691 fields.py:724 +msgid "A valid number is required." +msgstr "Je vyžadováno číslo." + +#: fields.py:727 +msgid "Ensure that there are no more than {max_digits} digits in total." +msgstr "Zkontrolujte, že číslo neobsahuje více než {max_digits} čislic." + +#: fields.py:728 +msgid "" +"Ensure that there are no more than {max_decimal_places} decimal places." +msgstr "Zkontrolujte, že číslo nemá více než {max_decimal_places} desetinných míst." + +#: fields.py:729 +msgid "" +"Ensure that there are no more than {max_whole_digits} digits before the " +"decimal point." +msgstr "Zkontrolujte, že číslo neobsahuje více než {max_whole_digits} čislic před desetinnou čárkou." + +#: fields.py:813 +msgid "Datetime has wrong format. Use one of these formats instead: {format}." +msgstr "Chybný formát data a času. Použijte jeden z těchto formátů: {format}." + +#: fields.py:814 +msgid "Expected a datetime but got a date." +msgstr "Bylo zadáno pouze datum místo data a času." + +#: fields.py:878 +msgid "Date has wrong format. Use one of these formats instead: {format}." +msgstr "Chybný formát data. Použijte jeden z těchto formátů: {format}." + +#: fields.py:879 +msgid "Expected a date but got a datetime." +msgstr "Bylo zadáno datum a čas, místo samotného data." + +#: fields.py:936 +msgid "Time has wrong format. Use one of these formats instead: {format}." +msgstr "Chybný formát času. Použijte jeden z těchto formátů: {format}." + +#: fields.py:992 fields.py:1036 +msgid "\"{input}\" is not a valid choice." +msgstr "\"{input}\" není platnou možností." + +#: fields.py:1037 fields.py:1151 serializers.py:482 +msgid "Expected a list of items but got type \"{input_type}\"." +msgstr "Byl očekáván seznam položek ale nalezen \"{input_type}\"." + +#: fields.py:1067 +msgid "No file was submitted." +msgstr "Nebyl zaslán žádný soubor." + +#: fields.py:1068 +msgid "" +"The submitted data was not a file. Check the encoding type on the form." +msgstr "Zaslaná data neobsahují soubor. Zkontrolujte typ kódování ve formuláři." + +#: fields.py:1069 +msgid "No filename could be determined." +msgstr "Nebylo možno zjistit jméno souboru." + +#: fields.py:1070 +msgid "The submitted file is empty." +msgstr "Zaslaný soubor je prázdný." + +#: fields.py:1071 +msgid "" +"Ensure this filename has at most {max_length} characters (it has {length})." +msgstr "Zajistěte, aby jméno souboru obsahovalo maximálně {max_length} znaků (teď má {length} znaků)." + +#: fields.py:1113 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "Nahrajte platný obrázek. Nahraný soubor buď není obrázkem, nebo je poškozen." + +#: fields.py:1188 +msgid "Expected a dictionary of items but got type \"{input_type}\"." +msgstr "" + +#: pagination.py:221 +msgid "Invalid page \"{page_number}\": {message}." +msgstr "Chybné čislo stránky \"{page_number}\": {message}." + +#: pagination.py:442 +msgid "Invalid cursor" +msgstr "" + +#: relations.py:133 +msgid "Invalid pk \"{pk_value}\" - object does not exist." +msgstr "Chybný primární klíč \"{pk_value}\" - objekt neexistuje." + +#: relations.py:134 +msgid "Incorrect type. Expected pk value, received {data_type}." +msgstr "Chybný typ. Byl přijat typ {data_type} místo hodnoty primárního klíče." + +#: relations.py:157 +msgid "Invalid hyperlink - No URL match." +msgstr "Chybný odkaz - nebyla nalezena žádní shoda." + +#: relations.py:158 +msgid "Invalid hyperlink - Incorrect URL match." +msgstr "Chybný odkaz - byla nalezena neplatná shoda." + +#: relations.py:159 +msgid "Invalid hyperlink - Object does not exist." +msgstr "Chybný odkaz - objekt neexistuje." + +#: relations.py:160 +msgid "Incorrect type. Expected URL string, received {data_type}." +msgstr "Chybný typ. Byl přijat typ {data_type} místo očekávaného odkazu." + +#: relations.py:295 +msgid "Object with {slug_name}={value} does not exist." +msgstr "Objekt s {slug_name}={value} neexistuje." + +#: relations.py:296 +msgid "Invalid value." +msgstr "Chybná hodnota." + +#: serializers.py:299 +msgid "Invalid data. Expected a dictionary, but got {datatype}." +msgstr "Chybná data. Byl přijat typ {datatype} místo očakávaného slovníku." + +#: validators.py:22 +msgid "This field must be unique." +msgstr "Tato položka musí být unikátní." + +#: validators.py:76 +msgid "The fields {field_names} must make a unique set." +msgstr "Položka {field_names} musí tvořit unikátní množinu." + +#: validators.py:219 +msgid "This field must be unique for the \"{date_field}\" date." +msgstr "Tato položka musí být pro datum \"{date_field}\" unikátní." + +#: validators.py:234 +msgid "This field must be unique for the \"{date_field}\" month." +msgstr "Tato položka musí být pro měsíc \"{date_field}\" unikátní." + +#: validators.py:247 +msgid "This field must be unique for the \"{date_field}\" year." +msgstr "Tato položka musí být pro rok \"{date_field}\" unikátní." + +#: versioning.py:39 +msgid "Invalid version in \"Accept\" header." +msgstr "Chybné číslo verze v hlavičce Accept" + +#: versioning.py:70 versioning.py:112 +msgid "Invalid version in URL path." +msgstr "Chybné číslo verze v odkazu." + +#: versioning.py:138 +msgid "Invalid version in hostname." +msgstr "Chybné číslo verze v hostname." + +#: versioning.py:160 +msgid "Invalid version in query parameter." +msgstr "Chybné čislo verze v URL parametru." + +#: authtoken/serializers.py:20 +msgid "User account is disabled." +msgstr "Uživatelský účet je zamčen." + +#: authtoken/serializers.py:23 +msgid "Unable to log in with provided credentials." +msgstr "Se zadanými údaji nebylo možné se přihlásit." + +#: authtoken/serializers.py:26 +msgid "Must include \"username\" and \"password\"." +msgstr "Musí obsahovat \"uživatelské jméno! a \"heslo\"." diff --git a/rest_framework/locale/da/LC_MESSAGES/django.mo b/rest_framework/locale/da/LC_MESSAGES/django.moBinary files differ new file mode 100644 index 00000000..f947f907 --- /dev/null +++ b/rest_framework/locale/da/LC_MESSAGES/django.mo diff --git a/rest_framework/locale/da/LC_MESSAGES/django.po b/rest_framework/locale/da/LC_MESSAGES/django.po new file mode 100644 index 00000000..e00ffadf --- /dev/null +++ b/rest_framework/locale/da/LC_MESSAGES/django.po @@ -0,0 +1,325 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +#  +# Translators: +# Mikkel Munch Mortensen <3xm@detfalskested.dk>, 2015 +msgid "" +msgstr "" +"Project-Id-Version: Django REST framework\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-30 16:23+0000\n" +"PO-Revision-Date: 2015-01-30 16:27+0000\n" +"Last-Translator: Thomas Christie <tom@tomchristie.com>\n" +"Language-Team: Danish (http://www.transifex.com/projects/p/django-rest-framework/language/da/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: da\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: authentication.py:69 +msgid "Invalid basic header. No credentials provided." +msgstr "Ugyldig basic header. Ingen legitimation angivet." + +#: authentication.py:72 +msgid "Invalid basic header. Credentials string should not contain spaces." +msgstr "Ugyldig basic header. Legitimationsstrenge må ikke indeholde mellemrum." + +#: authentication.py:78 +msgid "Invalid basic header. Credentials not correctly base64 encoded." +msgstr "Ugyldig basic header. Legitimationen er ikke base64 encoded på korrekt vis." + +#: authentication.py:90 +msgid "Invalid username/password." +msgstr "Ugyldigt brugernavn/kodeord." + +#: authentication.py:156 +msgid "Invalid token header. No credentials provided." +msgstr "Ugyldig token header." + +#: authentication.py:159 +msgid "Invalid token header. Token string should not contain spaces." +msgstr "Ugyldig token header. Token-strenge må ikke indeholde mellemrum." + +#: authentication.py:168 +msgid "Invalid token." +msgstr "Ugyldigt token." + +#: authentication.py:171 +msgid "User inactive or deleted." +msgstr "Inaktiv eller slettet bruger." + +#: exceptions.py:38 +msgid "A server error occurred." +msgstr "Der er sket en serverfejl." + +#: exceptions.py:73 +msgid "Malformed request." +msgstr "Misdannet forespørgsel." + +#: exceptions.py:78 +msgid "Incorrect authentication credentials." +msgstr "Ugyldig legitimation til autentificering." + +#: exceptions.py:83 +msgid "Authentication credentials were not provided." +msgstr "Legitimation til autentificering blev ikke angivet." + +#: exceptions.py:88 +msgid "You do not have permission to perform this action." +msgstr "Du har ikke lov til at udføre denne handling." + +#: exceptions.py:93 +msgid "Not found." +msgstr "Ikke fundet." + +#: exceptions.py:98 +msgid "Method \"{method}\" not allowed." +msgstr "Metoden \"{method}\" er ikke tilladt." + +#: exceptions.py:109 +msgid "Could not satisfy the request Accept header." +msgstr "Kunne ikke efterkomme forespørgslens Accept header." + +#: exceptions.py:121 +msgid "Unsupported media type \"{media_type}\" in request." +msgstr "Forespørgslens media type, \"{media_type}\", er ikke understøttet." + +#: exceptions.py:134 +msgid "Request was throttled." +msgstr "Forespørgslen blev neddroslet." + +#: fields.py:153 relations.py:132 relations.py:156 validators.py:77 +#: validators.py:155 +msgid "This field is required." +msgstr "Dette felt er påkrævet." + +#: fields.py:154 +msgid "This field may not be null." +msgstr "Dette felt må ikke være null." + +#: fields.py:487 fields.py:515 +msgid "\"{input}\" is not a valid boolean." +msgstr "\"{input}\" er ikke en tilladt boolsk værdi." + +#: fields.py:550 +msgid "This field may not be blank." +msgstr "Dette felt må ikke være tomt." + +#: fields.py:551 fields.py:1324 +msgid "Ensure this field has no more than {max_length} characters." +msgstr "Tjek at dette felt ikke indeholder flere end {max_length} tegn." + +#: fields.py:552 +msgid "Ensure this field has at least {min_length} characters." +msgstr "Tjek at dette felt indeholder mindst {min_length} tegn." + +#: fields.py:587 +msgid "Enter a valid email address." +msgstr "Angiv en gyldig e-mailadresse." + +#: fields.py:604 +msgid "This value does not match the required pattern." +msgstr "Denne værdi passer ikke med det påkrævede mønster." + +#: fields.py:615 +msgid "" +"Enter a valid \"slug\" consisting of letters, numbers, underscores or " +"hyphens." +msgstr "Indtast en gyldig \"slug\", bestående af bogstaver, tal, bund- og bindestreger." + +#: fields.py:627 +msgid "Enter a valid URL." +msgstr "Indtast en gyldig URL." + +#: fields.py:638 +msgid "\"{value}\" is not a valid UUID." +msgstr "" + +#: fields.py:657 +msgid "A valid integer is required." +msgstr "Et gyldigt heltal er påkrævet." + +#: fields.py:658 fields.py:692 fields.py:725 +msgid "Ensure this value is less than or equal to {max_value}." +msgstr "Tjek at værdien er mindre end eller lig med {max_value}." + +#: fields.py:659 fields.py:693 fields.py:726 +msgid "Ensure this value is greater than or equal to {min_value}." +msgstr "Tjek at værdien er større end eller lig med {min_value}." + +#: fields.py:660 fields.py:694 fields.py:730 +msgid "String value too large." +msgstr "Strengværdien er for stor." + +#: fields.py:691 fields.py:724 +msgid "A valid number is required." +msgstr "Et gyldigt tal er påkrævet." + +#: fields.py:727 +msgid "Ensure that there are no more than {max_digits} digits in total." +msgstr "Tjek at der ikke er flere end {max_digits} cifre i alt." + +#: fields.py:728 +msgid "" +"Ensure that there are no more than {max_decimal_places} decimal places." +msgstr "Tjek at der ikke er flere end {max_decimal_places} cifre efter kommaet." + +#: fields.py:729 +msgid "" +"Ensure that there are no more than {max_whole_digits} digits before the " +"decimal point." +msgstr "Tjek at der ikke er flere end {max_whole_digits} cifre før kommaet." + +#: fields.py:813 +msgid "Datetime has wrong format. Use one of these formats instead: {format}." +msgstr "Datotid har et forkert format. Brug i stedet et af disse formater: {format}." + +#: fields.py:814 +msgid "Expected a datetime but got a date." +msgstr "Forventede en datotid, men fik en dato." + +#: fields.py:878 +msgid "Date has wrong format. Use one of these formats instead: {format}." +msgstr "Dato har et forkert format. Brug i stedet et af disse formater: {format}." + +#: fields.py:879 +msgid "Expected a date but got a datetime." +msgstr "Forventede en dato men fik en datotid." + +#: fields.py:936 +msgid "Time has wrong format. Use one of these formats instead: {format}." +msgstr "Klokkeslæt har forkert format. Brug i stedet et af disse formater: {format}. " + +#: fields.py:992 fields.py:1036 +msgid "\"{input}\" is not a valid choice." +msgstr "\"{input}\" er ikke et gyldigt valg." + +#: fields.py:1037 fields.py:1151 serializers.py:482 +msgid "Expected a list of items but got type \"{input_type}\"." +msgstr "Forventede en liste, men fik noget af typen \"{input_type}\"." + +#: fields.py:1067 +msgid "No file was submitted." +msgstr "Ingen medsendt fil." + +#: fields.py:1068 +msgid "" +"The submitted data was not a file. Check the encoding type on the form." +msgstr "Det medsendte data var ikke en fil. Tjek typen af indkodning på formularen." + +#: fields.py:1069 +msgid "No filename could be determined." +msgstr "Filnavnet kunne ikke afgøres." + +#: fields.py:1070 +msgid "The submitted file is empty." +msgstr "Den medsendte fil er tom." + +#: fields.py:1071 +msgid "" +"Ensure this filename has at most {max_length} characters (it has {length})." +msgstr "Sørg for at filnavnet er højst {max_length} langt (det er {length})." + +#: fields.py:1113 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "Medsend et gyldigt billede. Den medsendte fil var enten ikke et billede eller billedfilen var ødelagt." + +#: fields.py:1188 +msgid "Expected a dictionary of items but got type \"{input_type}\"." +msgstr "" + +#: pagination.py:221 +msgid "Invalid page \"{page_number}\": {message}." +msgstr "Ugyldig side \"{page_number}\": {message}." + +#: pagination.py:442 +msgid "Invalid cursor" +msgstr "" + +#: relations.py:133 +msgid "Invalid pk \"{pk_value}\" - object does not exist." +msgstr "Ugyldig primærnøgle \"{pk_value}\" - objektet findes ikke." + +#: relations.py:134 +msgid "Incorrect type. Expected pk value, received {data_type}." +msgstr "Ugyldig type. Forventet værdi er primærnøgle, fik {data_type}." + +#: relations.py:157 +msgid "Invalid hyperlink - No URL match." +msgstr "Ugyldigt hyperlink - intet URL match." + +#: relations.py:158 +msgid "Invalid hyperlink - Incorrect URL match." +msgstr "Ugyldigt hyperlink - forkert URL match." + +#: relations.py:159 +msgid "Invalid hyperlink - Object does not exist." +msgstr "Ugyldigt hyperlink - objektet findes ikke." + +#: relations.py:160 +msgid "Incorrect type. Expected URL string, received {data_type}." +msgstr "Forkert type. Forventede en URL-streng, fik {data_type}." + +#: relations.py:295 +msgid "Object with {slug_name}={value} does not exist." +msgstr "Object med {slug_name}={value} findes ikke." + +#: relations.py:296 +msgid "Invalid value." +msgstr "Ugyldig værdi." + +#: serializers.py:299 +msgid "Invalid data. Expected a dictionary, but got {datatype}." +msgstr "Ugyldig data. Forventede en dictionary, men fik {datatype}." + +#: validators.py:22 +msgid "This field must be unique." +msgstr "Dette felt skal være unikt." + +#: validators.py:76 +msgid "The fields {field_names} must make a unique set." +msgstr "Felterne {field_names} skal udgøre et unikt sæt." + +#: validators.py:219 +msgid "This field must be unique for the \"{date_field}\" date." +msgstr "Dette felt skal være unikt for \"{date_field}\"-datoen." + +#: validators.py:234 +msgid "This field must be unique for the \"{date_field}\" month." +msgstr "Dette felt skal være unikt for \"{date_field}\"-måneden." + +#: validators.py:247 +msgid "This field must be unique for the \"{date_field}\" year." +msgstr "Dette felt skal være unikt for \"{date_field}\"-året." + +#: versioning.py:39 +msgid "Invalid version in \"Accept\" header." +msgstr "Ugyldig version i \"Accept\" headeren." + +#: versioning.py:70 versioning.py:112 +msgid "Invalid version in URL path." +msgstr "Ugyldig version i URL-stien." + +#: versioning.py:138 +msgid "Invalid version in hostname." +msgstr "Ugyldig version i hostname." + +#: versioning.py:160 +msgid "Invalid version in query parameter." +msgstr "Ugyldig version i forespørgselsparameteren." + +#: authtoken/serializers.py:20 +msgid "User account is disabled." +msgstr "Brugerkontoen er deaktiveret." + +#: authtoken/serializers.py:23 +msgid "Unable to log in with provided credentials." +msgstr "Kunne ikke logge ind med den angivne legitimation." + +#: authtoken/serializers.py:26 +msgid "Must include \"username\" and \"password\"." +msgstr "Skal indeholde \"username\" og \"password\"." diff --git a/rest_framework/locale/de/LC_MESSAGES/django.mo b/rest_framework/locale/de/LC_MESSAGES/django.moBinary files differ new file mode 100644 index 00000000..48245c60 --- /dev/null +++ b/rest_framework/locale/de/LC_MESSAGES/django.mo diff --git a/rest_framework/locale/de/LC_MESSAGES/django.po b/rest_framework/locale/de/LC_MESSAGES/django.po new file mode 100644 index 00000000..74bee416 --- /dev/null +++ b/rest_framework/locale/de/LC_MESSAGES/django.po @@ -0,0 +1,325 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +#  +# Translators: +# Thomas Tanner, 2015 +msgid "" +msgstr "" +"Project-Id-Version: Django REST framework\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-30 16:23+0000\n" +"PO-Revision-Date: 2015-01-30 16:27+0000\n" +"Last-Translator: Thomas Christie <tom@tomchristie.com>\n" +"Language-Team: German (http://www.transifex.com/projects/p/django-rest-framework/language/de/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: de\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: authentication.py:69 +msgid "Invalid basic header. No credentials provided." +msgstr "Ungültiger basic header. Keine Zugangsdaten angegeben." + +#: authentication.py:72 +msgid "Invalid basic header. Credentials string should not contain spaces." +msgstr "Ungültiger basic header. Zugangsdaten sollen keine Leerzeichen enthalten." + +#: authentication.py:78 +msgid "Invalid basic header. Credentials not correctly base64 encoded." +msgstr "Ungültiger basic header. Zugangsdaten sind nicht korrekt mit base64 kodiert." + +#: authentication.py:90 +msgid "Invalid username/password." +msgstr "Ungültiger Benutzername/Passwort" + +#: authentication.py:156 +msgid "Invalid token header. No credentials provided." +msgstr "Ungültiger token header. Keine Zugangsdaten angegeben." + +#: authentication.py:159 +msgid "Invalid token header. Token string should not contain spaces." +msgstr "Ungültiger token header. Zugangsdaten sollen keine Leerzeichen enthalten." + +#: authentication.py:168 +msgid "Invalid token." +msgstr "Ungültiges Token" + +#: authentication.py:171 +msgid "User inactive or deleted." +msgstr "Benutzer inaktiv oder gelöscht." + +#: exceptions.py:38 +msgid "A server error occurred." +msgstr "Ein Serverfehler ist aufgetreten." + +#: exceptions.py:73 +msgid "Malformed request." +msgstr "Fehlerhafte Anfrage." + +#: exceptions.py:78 +msgid "Incorrect authentication credentials." +msgstr "Falsche Anmeldedaten." + +#: exceptions.py:83 +msgid "Authentication credentials were not provided." +msgstr "Anmeldedaten fehlen." + +#: exceptions.py:88 +msgid "You do not have permission to perform this action." +msgstr "Sie sind nicht berechtigt, diese Aktion durchzuführen." + +#: exceptions.py:93 +msgid "Not found." +msgstr "Nicht gefunden." + +#: exceptions.py:98 +msgid "Method \"{method}\" not allowed." +msgstr "Methode \"{method}\" nicht erlaubt." + +#: exceptions.py:109 +msgid "Could not satisfy the request Accept header." +msgstr "Kann den Accept header der Anfrage nicht erfüllen." + +#: exceptions.py:121 +msgid "Unsupported media type \"{media_type}\" in request." +msgstr "Nicht unterstützter Medientyp \"{media_type}\" in der Anfrage." + +#: exceptions.py:134 +msgid "Request was throttled." +msgstr "Die Anfrage wurde gedrosselt." + +#: fields.py:153 relations.py:132 relations.py:156 validators.py:77 +#: validators.py:155 +msgid "This field is required." +msgstr "Dieses Feld ist erforderlich." + +#: fields.py:154 +msgid "This field may not be null." +msgstr "Dieses Feld darf nicht Null sein." + +#: fields.py:487 fields.py:515 +msgid "\"{input}\" is not a valid boolean." +msgstr "\"{input}\" ist kein gültiger Boole'scher Wert." + +#: fields.py:550 +msgid "This field may not be blank." +msgstr "Dieses Feld darf nicht leer sein." + +#: fields.py:551 fields.py:1324 +msgid "Ensure this field has no more than {max_length} characters." +msgstr "Stelle sicher, dass dieses Feld nicht mehr als {max_length} Zeichen lang ist." + +#: fields.py:552 +msgid "Ensure this field has at least {min_length} characters." +msgstr "Stelle sicher, dass dieses Feld mindestens {min_length} Zeichen lang ist." + +#: fields.py:587 +msgid "Enter a valid email address." +msgstr "Gebe eine gültige E-Mail Adresse an." + +#: fields.py:604 +msgid "This value does not match the required pattern." +msgstr "Dieser Wert passt nicht zu dem erforderlichen Muster." + +#: fields.py:615 +msgid "" +"Enter a valid \"slug\" consisting of letters, numbers, underscores or " +"hyphens." +msgstr "Gebe ein gültiges \"slug\" aus Buchstaben, Ziffern, Unterstrichen und Minuszeichen ein." + +#: fields.py:627 +msgid "Enter a valid URL." +msgstr "Gebe eine gültige URL ein." + +#: fields.py:638 +msgid "\"{value}\" is not a valid UUID." +msgstr "" + +#: fields.py:657 +msgid "A valid integer is required." +msgstr "Eine gültige Ganzzahl ist erforderlich." + +#: fields.py:658 fields.py:692 fields.py:725 +msgid "Ensure this value is less than or equal to {max_value}." +msgstr "Stelle sicher, dass dieser Wert kleiner oder gleich {max_value} ist." + +#: fields.py:659 fields.py:693 fields.py:726 +msgid "Ensure this value is greater than or equal to {min_value}." +msgstr "Stelle sicher, dass dieser Wert größer oder gleich {max_value} ist." + +#: fields.py:660 fields.py:694 fields.py:730 +msgid "String value too large." +msgstr "Zeichenkette zu lang." + +#: fields.py:691 fields.py:724 +msgid "A valid number is required." +msgstr "Eine gültige Zahl ist erforderlich." + +#: fields.py:727 +msgid "Ensure that there are no more than {max_digits} digits in total." +msgstr "Stelle sicher, dass es insgesamt nicht mehr als {max_digits} Ziffern lang ist." + +#: fields.py:728 +msgid "" +"Ensure that there are no more than {max_decimal_places} decimal places." +msgstr "Stelle sicher, dass es nicht mehr als {max_decimal_places} Nachkommastellen lang ist." + +#: fields.py:729 +msgid "" +"Ensure that there are no more than {max_whole_digits} digits before the " +"decimal point." +msgstr "Stelle sicher, dass es nicht mehr als {max_whole_places} Stellen vor dem Komma lang ist." + +#: fields.py:813 +msgid "Datetime has wrong format. Use one of these formats instead: {format}." +msgstr "Datum- und Zeitangabe hat das falsche Format. Nutze stattdessen eines dieser Formate: {format}." + +#: fields.py:814 +msgid "Expected a datetime but got a date." +msgstr "Erwarte eine Datum- und Zeitangabe, erhielt aber ein Datum." + +#: fields.py:878 +msgid "Date has wrong format. Use one of these formats instead: {format}." +msgstr "Datum hat das falsche Format. Nutze stattdessen eines dieser Formate: {format}." + +#: fields.py:879 +msgid "Expected a date but got a datetime." +msgstr "Erwarte ein Datum, erhielt aber eine Datum- und Zeitangabe." + +#: fields.py:936 +msgid "Time has wrong format. Use one of these formats instead: {format}." +msgstr "Zeitangabe hat das falsche Format. Nutze stattdessen eines dieser Formate: {format}." + +#: fields.py:992 fields.py:1036 +msgid "\"{input}\" is not a valid choice." +msgstr "\"{input}\" ist keine gültige Option." + +#: fields.py:1037 fields.py:1151 serializers.py:482 +msgid "Expected a list of items but got type \"{input_type}\"." +msgstr "Erwarte eine Liste von Elementen, erhielt aber den Typ \"{input_type}\"." + +#: fields.py:1067 +msgid "No file was submitted." +msgstr "Es wurde keine Datei übermittelt." + +#: fields.py:1068 +msgid "" +"The submitted data was not a file. Check the encoding type on the form." +msgstr "Die übermittelten Daten sind keine Datei. Prüfe den Kodierungstyp im Formular." + +#: fields.py:1069 +msgid "No filename could be determined." +msgstr "Der Dateiname konnte nicht ermittelt werden." + +#: fields.py:1070 +msgid "The submitted file is empty." +msgstr "Die übermittelte Datei ist leer." + +#: fields.py:1071 +msgid "" +"Ensure this filename has at most {max_length} characters (it has {length})." +msgstr "" + +#: fields.py:1113 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "" + +#: fields.py:1188 +msgid "Expected a dictionary of items but got type \"{input_type}\"." +msgstr "" + +#: pagination.py:221 +msgid "Invalid page \"{page_number}\": {message}." +msgstr "" + +#: pagination.py:442 +msgid "Invalid cursor" +msgstr "" + +#: relations.py:133 +msgid "Invalid pk \"{pk_value}\" - object does not exist." +msgstr "" + +#: relations.py:134 +msgid "Incorrect type. Expected pk value, received {data_type}." +msgstr "" + +#: relations.py:157 +msgid "Invalid hyperlink - No URL match." +msgstr "" + +#: relations.py:158 +msgid "Invalid hyperlink - Incorrect URL match." +msgstr "" + +#: relations.py:159 +msgid "Invalid hyperlink - Object does not exist." +msgstr "" + +#: relations.py:160 +msgid "Incorrect type. Expected URL string, received {data_type}." +msgstr "" + +#: relations.py:295 +msgid "Object with {slug_name}={value} does not exist." +msgstr "" + +#: relations.py:296 +msgid "Invalid value." +msgstr "Ungültiger Wert." + +#: serializers.py:299 +msgid "Invalid data. Expected a dictionary, but got {datatype}." +msgstr "Ungültige Daten. Dictionary erwartet, aber {datatype} erhalten." + +#: validators.py:22 +msgid "This field must be unique." +msgstr "Dieses Feld muss eineindeutig sein." + +#: 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 "" + +#: authtoken/serializers.py:20 +msgid "User account is disabled." +msgstr "Benutzerkonto ist gesperrt." + +#: authtoken/serializers.py:23 +msgid "Unable to log in with provided credentials." +msgstr "Kann nicht mit den angegeben Zugangsdaten anmelden." + +#: authtoken/serializers.py:26 +msgid "Must include \"username\" and \"password\"." +msgstr "\"username\" und \"password\" sind erforderlich." diff --git a/rest_framework/locale/en/LC_MESSAGES/django.mo b/rest_framework/locale/en/LC_MESSAGES/django.moBinary files differ new file mode 100644 index 00000000..746915ff --- /dev/null +++ b/rest_framework/locale/en/LC_MESSAGES/django.mo diff --git a/rest_framework/locale/en/LC_MESSAGES/django.po b/rest_framework/locale/en/LC_MESSAGES/django.po new file mode 100644 index 00000000..f3db69e5 --- /dev/null +++ b/rest_framework/locale/en/LC_MESSAGES/django.po @@ -0,0 +1,324 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +#  +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: Django REST framework\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-30 16:23+0000\n" +"PO-Revision-Date: 2015-01-30 16:27+0000\n" +"Last-Translator: Thomas Christie <tom@tomchristie.com>\n" +"Language-Team: English (http://www.transifex.com/projects/p/django-rest-framework/language/en/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: en\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: authentication.py:69 +msgid "Invalid basic header. No credentials provided." +msgstr "Invalid basic header. No credentials provided." + +#: authentication.py:72 +msgid "Invalid basic header. Credentials string should not contain spaces." +msgstr "Invalid basic header. Credentials string should not contain spaces." + +#: authentication.py:78 +msgid "Invalid basic header. Credentials not correctly base64 encoded." +msgstr "Invalid basic header. Credentials not correctly base64 encoded." + +#: authentication.py:90 +msgid "Invalid username/password." +msgstr "Invalid username/password." + +#: authentication.py:156 +msgid "Invalid token header. No credentials provided." +msgstr "Invalid token header. No credentials provided." + +#: authentication.py:159 +msgid "Invalid token header. Token string should not contain spaces." +msgstr "Invalid token header. Token string should not contain spaces." + +#: authentication.py:168 +msgid "Invalid token." +msgstr "Invalid token." + +#: authentication.py:171 +msgid "User inactive or deleted." +msgstr "User inactive or deleted." + +#: exceptions.py:38 +msgid "A server error occurred." +msgstr "A server error occurred." + +#: exceptions.py:73 +msgid "Malformed request." +msgstr "Malformed request." + +#: exceptions.py:78 +msgid "Incorrect authentication credentials." +msgstr "Incorrect authentication credentials." + +#: exceptions.py:83 +msgid "Authentication credentials were not provided." +msgstr "Authentication credentials were not provided." + +#: exceptions.py:88 +msgid "You do not have permission to perform this action." +msgstr "You do not have permission to perform this action." + +#: exceptions.py:93 +msgid "Not found." +msgstr "Not found." + +#: exceptions.py:98 +msgid "Method \"{method}\" not allowed." +msgstr "Method \"{method}\" not allowed." + +#: exceptions.py:109 +msgid "Could not satisfy the request Accept header." +msgstr "Could not satisfy the request Accept header." + +#: exceptions.py:121 +msgid "Unsupported media type \"{media_type}\" in request." +msgstr "Unsupported media type \"{media_type}\" in request." + +#: exceptions.py:134 +msgid "Request was throttled." +msgstr "Request was throttled." + +#: fields.py:153 relations.py:132 relations.py:156 validators.py:77 +#: validators.py:155 +msgid "This field is required." +msgstr "This field is required." + +#: fields.py:154 +msgid "This field may not be null." +msgstr "This field may not be null." + +#: fields.py:487 fields.py:515 +msgid "\"{input}\" is not a valid boolean." +msgstr "\"{input}\" is not a valid boolean." + +#: fields.py:550 +msgid "This field may not be blank." +msgstr "This field may not be blank." + +#: fields.py:551 fields.py:1324 +msgid "Ensure this field has no more than {max_length} characters." +msgstr "Ensure this field has no more than {max_length} characters." + +#: fields.py:552 +msgid "Ensure this field has at least {min_length} characters." +msgstr "Ensure this field has at least {min_length} characters." + +#: fields.py:587 +msgid "Enter a valid email address." +msgstr "Enter a valid email address." + +#: fields.py:604 +msgid "This value does not match the required pattern." +msgstr "This value does not match the required pattern." + +#: fields.py:615 +msgid "" +"Enter a valid \"slug\" consisting of letters, numbers, underscores or " +"hyphens." +msgstr "Enter a valid \"slug\" consisting of letters, numbers, underscores or hyphens." + +#: fields.py:627 +msgid "Enter a valid URL." +msgstr "Enter a valid URL." + +#: fields.py:638 +msgid "\"{value}\" is not a valid UUID." +msgstr "\"{value}\" is not a valid UUID." + +#: fields.py:657 +msgid "A valid integer is required." +msgstr "A valid integer is required." + +#: fields.py:658 fields.py:692 fields.py:725 +msgid "Ensure this value is less than or equal to {max_value}." +msgstr "Ensure this value is less than or equal to {max_value}." + +#: fields.py:659 fields.py:693 fields.py:726 +msgid "Ensure this value is greater than or equal to {min_value}." +msgstr "Ensure this value is greater than or equal to {min_value}." + +#: fields.py:660 fields.py:694 fields.py:730 +msgid "String value too large." +msgstr "String value too large." + +#: fields.py:691 fields.py:724 +msgid "A valid number is required." +msgstr "A valid number is required." + +#: fields.py:727 +msgid "Ensure that there are no more than {max_digits} digits in total." +msgstr "Ensure that there are no more than {max_digits} digits in total." + +#: fields.py:728 +msgid "" +"Ensure that there are no more than {max_decimal_places} decimal places." +msgstr "Ensure that there are no more than {max_decimal_places} decimal places." + +#: fields.py:729 +msgid "" +"Ensure that there are no more than {max_whole_digits} digits before the " +"decimal point." +msgstr "Ensure that there are no more than {max_whole_digits} digits before the decimal point." + +#: fields.py:813 +msgid "Datetime has wrong format. Use one of these formats instead: {format}." +msgstr "Datetime has wrong format. Use one of these formats instead: {format}." + +#: fields.py:814 +msgid "Expected a datetime but got a date." +msgstr "Expected a datetime but got a date." + +#: fields.py:878 +msgid "Date has wrong format. Use one of these formats instead: {format}." +msgstr "Date has wrong format. Use one of these formats instead: {format}." + +#: fields.py:879 +msgid "Expected a date but got a datetime." +msgstr "Expected a date but got a datetime." + +#: fields.py:936 +msgid "Time has wrong format. Use one of these formats instead: {format}." +msgstr "Time has wrong format. Use one of these formats instead: {format}." + +#: fields.py:992 fields.py:1036 +msgid "\"{input}\" is not a valid choice." +msgstr "\"{input}\" is not a valid choice." + +#: fields.py:1037 fields.py:1151 serializers.py:482 +msgid "Expected a list of items but got type \"{input_type}\"." +msgstr "Expected a list of items but got type \"{input_type}\"." + +#: fields.py:1067 +msgid "No file was submitted." +msgstr "No file was submitted." + +#: fields.py:1068 +msgid "" +"The submitted data was not a file. Check the encoding type on the form." +msgstr "The submitted data was not a file. Check the encoding type on the form." + +#: fields.py:1069 +msgid "No filename could be determined." +msgstr "No filename could be determined." + +#: fields.py:1070 +msgid "The submitted file is empty." +msgstr "The submitted file is empty." + +#: fields.py:1071 +msgid "" +"Ensure this filename has at most {max_length} characters (it has {length})." +msgstr "Ensure this filename has at most {max_length} characters (it has {length})." + +#: fields.py:1113 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "Upload a valid image. The file you uploaded was either not an image or a corrupted image." + +#: fields.py:1188 +msgid "Expected a dictionary of items but got type \"{input_type}\"." +msgstr "Expected a dictionary of items but got type \"{input_type}\"." + +#: pagination.py:221 +msgid "Invalid page \"{page_number}\": {message}." +msgstr "Invalid page \"{page_number}\": {message}." + +#: pagination.py:442 +msgid "Invalid cursor" +msgstr "Invalid cursor" + +#: relations.py:133 +msgid "Invalid pk \"{pk_value}\" - object does not exist." +msgstr "Invalid pk \"{pk_value}\" - object does not exist." + +#: relations.py:134 +msgid "Incorrect type. Expected pk value, received {data_type}." +msgstr "Incorrect type. Expected pk value, received {data_type}." + +#: relations.py:157 +msgid "Invalid hyperlink - No URL match." +msgstr "Invalid hyperlink - No URL match." + +#: relations.py:158 +msgid "Invalid hyperlink - Incorrect URL match." +msgstr "Invalid hyperlink - Incorrect URL match." + +#: relations.py:159 +msgid "Invalid hyperlink - Object does not exist." +msgstr "Invalid hyperlink - Object does not exist." + +#: relations.py:160 +msgid "Incorrect type. Expected URL string, received {data_type}." +msgstr "Incorrect type. Expected URL string, received {data_type}." + +#: relations.py:295 +msgid "Object with {slug_name}={value} does not exist." +msgstr "Object with {slug_name}={value} does not exist." + +#: relations.py:296 +msgid "Invalid value." +msgstr "Invalid value." + +#: serializers.py:299 +msgid "Invalid data. Expected a dictionary, but got {datatype}." +msgstr "Invalid data. Expected a dictionary, but got {datatype}." + +#: validators.py:22 +msgid "This field must be unique." +msgstr "This field must be unique." + +#: validators.py:76 +msgid "The fields {field_names} must make a unique set." +msgstr "The fields {field_names} must make a unique set." + +#: validators.py:219 +msgid "This field must be unique for the \"{date_field}\" date." +msgstr "This field must be unique for the \"{date_field}\" date." + +#: validators.py:234 +msgid "This field must be unique for the \"{date_field}\" month." +msgstr "This field must be unique for the \"{date_field}\" month." + +#: validators.py:247 +msgid "This field must be unique for the \"{date_field}\" year." +msgstr "This field must be unique for the \"{date_field}\" year." + +#: versioning.py:39 +msgid "Invalid version in \"Accept\" header." +msgstr "Invalid version in \"Accept\" header." + +#: versioning.py:70 versioning.py:112 +msgid "Invalid version in URL path." +msgstr "Invalid version in URL path." + +#: versioning.py:138 +msgid "Invalid version in hostname." +msgstr "Invalid version in hostname." + +#: versioning.py:160 +msgid "Invalid version in query parameter." +msgstr "Invalid version in query parameter." + +#: authtoken/serializers.py:20 +msgid "User account is disabled." +msgstr "User account is disabled." + +#: authtoken/serializers.py:23 +msgid "Unable to log in with provided credentials." +msgstr "Unable to log in with provided credentials." + +#: authtoken/serializers.py:26 +msgid "Must include \"username\" and \"password\"." +msgstr "Must include \"username\" and \"password\"." diff --git a/rest_framework/locale/en_US/LC_MESSAGES/django.mo b/rest_framework/locale/en_US/LC_MESSAGES/django.moBinary files differ new file mode 100644 index 00000000..eb60d9d7 --- /dev/null +++ b/rest_framework/locale/en_US/LC_MESSAGES/django.mo 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..11d94e9c --- /dev/null +++ b/rest_framework/locale/en_US/LC_MESSAGES/django.po @@ -0,0 +1,326 @@ +# 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-30 16:40+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 "" + +#: 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 views.py:77 +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:153 relations.py:132 relations.py:156 validators.py:77 +#: validators.py:155 +msgid "This field is required." +msgstr "" + +#: fields.py:154 +msgid "This field may not be null." +msgstr "" + +#: fields.py:487 fields.py:515 +msgid "\"{input}\" is not a valid boolean." +msgstr "" + +#: fields.py:550 +msgid "This field may not be blank." +msgstr "" + +#: fields.py:551 fields.py:1324 +msgid "Ensure this field has no more than {max_length} characters." +msgstr "" + +#: fields.py:552 +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:638 +msgid "\"{value}\" is not a valid UUID." +msgstr "" + +#: fields.py:657 +msgid "A valid integer is required." +msgstr "" + +#: fields.py:658 fields.py:692 fields.py:725 +msgid "Ensure this value is less than or equal to {max_value}." +msgstr "" + +#: fields.py:659 fields.py:693 fields.py:726 +msgid "Ensure this value is greater than or equal to {min_value}." +msgstr "" + +#: fields.py:660 fields.py:694 fields.py:730 +msgid "String value too large." +msgstr "" + +#: fields.py:691 fields.py:724 +msgid "A valid number is required." +msgstr "" + +#: fields.py:727 +msgid "Ensure that there are no more than {max_digits} digits in total." +msgstr "" + +#: fields.py:728 +msgid "Ensure that there are no more than {max_decimal_places} decimal places." +msgstr "" + +#: fields.py:729 +msgid "" +"Ensure that there are no more than {max_whole_digits} digits before the " +"decimal point." +msgstr "" + +#: fields.py:813 +msgid "Datetime has wrong format. Use one of these formats instead: {format}." +msgstr "" + +#: fields.py:814 +msgid "Expected a datetime but got a date." +msgstr "" + +#: fields.py:878 +msgid "Date has wrong format. Use one of these formats instead: {format}." +msgstr "" + +#: fields.py:879 +msgid "Expected a date but got a datetime." +msgstr "" + +#: fields.py:936 +msgid "Time has wrong format. Use one of these formats instead: {format}." +msgstr "" + +#: fields.py:992 fields.py:1036 +msgid "\"{input}\" is not a valid choice." +msgstr "" + +#: fields.py:1037 fields.py:1151 serializers.py:482 +msgid "Expected a list of items but got type \"{input_type}\"." +msgstr "" + +#: fields.py:1067 +msgid "No file was submitted." +msgstr "" + +#: fields.py:1068 +msgid "The submitted data was not a file. Check the encoding type on the form." +msgstr "" + +#: fields.py:1069 +msgid "No filename could be determined." +msgstr "" + +#: fields.py:1070 +msgid "The submitted file is empty." +msgstr "" + +#: fields.py:1071 +msgid "" +"Ensure this filename has at most {max_length} characters (it has {length})." +msgstr "" + +#: fields.py:1113 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "" + +#: fields.py:1188 +msgid "Expected a dictionary of items but got type \"{input_type}\"." +msgstr "" + +#: pagination.py:221 +msgid "Invalid page \"{page_number}\": {message}." +msgstr "" + +#: pagination.py:442 +msgid "Invalid cursor" +msgstr "" + +#: relations.py:133 +msgid "Invalid pk \"{pk_value}\" - object does not exist." +msgstr "" + +#: relations.py:134 +msgid "Incorrect type. Expected pk value, received {data_type}." +msgstr "" + +#: relations.py:157 +msgid "Invalid hyperlink - No URL match." +msgstr "" + +#: relations.py:158 +msgid "Invalid hyperlink - Incorrect URL match." +msgstr "" + +#: relations.py:159 +msgid "Invalid hyperlink - Object does not exist." +msgstr "" + +#: relations.py:160 +msgid "Incorrect type. Expected URL string, received {data_type}." +msgstr "" + +#: relations.py:295 +msgid "Object with {slug_name}={value} does not exist." +msgstr "" + +#: relations.py:296 +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 "" + +#: views.py:81 +msgid "Permission denied." +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 "" diff --git a/rest_framework/locale/es/LC_MESSAGES/django.mo b/rest_framework/locale/es/LC_MESSAGES/django.moBinary files differ new file mode 100644 index 00000000..814db7be --- /dev/null +++ b/rest_framework/locale/es/LC_MESSAGES/django.mo diff --git a/rest_framework/locale/es/LC_MESSAGES/django.po b/rest_framework/locale/es/LC_MESSAGES/django.po new file mode 100644 index 00000000..28ef893d --- /dev/null +++ b/rest_framework/locale/es/LC_MESSAGES/django.po @@ -0,0 +1,327 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +#  +# Translators: +# José Padilla <jpadilla@webapplicate.com>, 2015 +# Miguel González <migonzalvar@activitycentral.com>, 2015 +# Sergio Infante <rsinfante@gmail.com>, 2015 +msgid "" +msgstr "" +"Project-Id-Version: Django REST framework\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-30 16:23+0000\n" +"PO-Revision-Date: 2015-01-30 16:27+0000\n" +"Last-Translator: Thomas Christie <tom@tomchristie.com>\n" +"Language-Team: Spanish (http://www.transifex.com/projects/p/django-rest-framework/language/es/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: es\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: authentication.py:69 +msgid "Invalid basic header. No credentials provided." +msgstr "Cabecera básica inválida. Las credenciales no fueron suministradas." + +#: authentication.py:72 +msgid "Invalid basic header. Credentials string should not contain spaces." +msgstr "Cabecera básica inválida. La cadena con las credenciales no debe contener espacios." + +#: authentication.py:78 +msgid "Invalid basic header. Credentials not correctly base64 encoded." +msgstr "Cabecera básica inválida. Las credenciales incorrectamente codificadas en base64." + +#: authentication.py:90 +msgid "Invalid username/password." +msgstr "Nombre de usuario/contraseña inválidos." + +#: authentication.py:156 +msgid "Invalid token header. No credentials provided." +msgstr "Cabecera token inválida. Las credenciales no fueron suministradas." + +#: authentication.py:159 +msgid "Invalid token header. Token string should not contain spaces." +msgstr "Cabecera token inválida. La cadena token no debe contener espacios." + +#: authentication.py:168 +msgid "Invalid token." +msgstr "Token inválido." + +#: authentication.py:171 +msgid "User inactive or deleted." +msgstr "Usuario inactivo o borrado." + +#: exceptions.py:38 +msgid "A server error occurred." +msgstr "Se ha producido un error en el servidor." + +#: exceptions.py:73 +msgid "Malformed request." +msgstr "Solicitud con formato incorrecto." + +#: exceptions.py:78 +msgid "Incorrect authentication credentials." +msgstr "Credenciales de autenticación incorrectas." + +#: exceptions.py:83 +msgid "Authentication credentials were not provided." +msgstr "Las credenciales de autenticación no se proveyeron." + +#: exceptions.py:88 +msgid "You do not have permission to perform this action." +msgstr "Usted no tiene permiso para realizar esta acción." + +#: exceptions.py:93 +msgid "Not found." +msgstr "No encontrado." + +#: exceptions.py:98 +msgid "Method \"{method}\" not allowed." +msgstr "Método \"{method}\" no permitido." + +#: exceptions.py:109 +msgid "Could not satisfy the request Accept header." +msgstr "No se ha podido satisfacer la solicitud de cabecera de Accept." + +#: exceptions.py:121 +msgid "Unsupported media type \"{media_type}\" in request." +msgstr "Tipo de medio \"{media_type}\" incompatible en la solicitud." + +#: exceptions.py:134 +msgid "Request was throttled." +msgstr "Solicitud fue regulada (throttled)." + +#: fields.py:153 relations.py:132 relations.py:156 validators.py:77 +#: validators.py:155 +msgid "This field is required." +msgstr "Este campo es requerido." + +#: fields.py:154 +msgid "This field may not be null." +msgstr "Este campo no puede ser nulo." + +#: fields.py:487 fields.py:515 +msgid "\"{input}\" is not a valid boolean." +msgstr "\"{input}\" no es un booleano válido." + +#: fields.py:550 +msgid "This field may not be blank." +msgstr "Este campo no puede estar en blanco." + +#: fields.py:551 fields.py:1324 +msgid "Ensure this field has no more than {max_length} characters." +msgstr "Asegúrese de que este campo no tenga más de {max_length} caracteres." + +#: fields.py:552 +msgid "Ensure this field has at least {min_length} characters." +msgstr "Asegúrese de que este campo tenga al menos {min_length} caracteres." + +#: fields.py:587 +msgid "Enter a valid email address." +msgstr "Introduzca una dirección de correo electrónico válida." + +#: fields.py:604 +msgid "This value does not match the required pattern." +msgstr "Este valor no coincide con el patrón requerido." + +#: fields.py:615 +msgid "" +"Enter a valid \"slug\" consisting of letters, numbers, underscores or " +"hyphens." +msgstr "Introduzca un \"slug\" válido consistente en letras, números, guiones o guiones bajos." + +#: fields.py:627 +msgid "Enter a valid URL." +msgstr "Introduzca una URL válida." + +#: fields.py:638 +msgid "\"{value}\" is not a valid UUID." +msgstr "" + +#: fields.py:657 +msgid "A valid integer is required." +msgstr "Introduzca un número entero válido." + +#: fields.py:658 fields.py:692 fields.py:725 +msgid "Ensure this value is less than or equal to {max_value}." +msgstr "Asegúrese de que este valor es menor o igual a {max_value}." + +#: fields.py:659 fields.py:693 fields.py:726 +msgid "Ensure this value is greater than or equal to {min_value}." +msgstr "Asegúrese de que este valor es mayor o igual a {min_value}." + +#: fields.py:660 fields.py:694 fields.py:730 +msgid "String value too large." +msgstr "Cadena demasiado larga." + +#: fields.py:691 fields.py:724 +msgid "A valid number is required." +msgstr "Se requiere un número válido." + +#: fields.py:727 +msgid "Ensure that there are no more than {max_digits} digits in total." +msgstr "Asegúrese de que no haya más de {max_digits} dígitos en total." + +#: fields.py:728 +msgid "" +"Ensure that there are no more than {max_decimal_places} decimal places." +msgstr "Asegúrese de que no haya más de {max_decimal_places} decimales." + +#: fields.py:729 +msgid "" +"Ensure that there are no more than {max_whole_digits} digits before the " +"decimal point." +msgstr "Asegúrese de que no haya más de {max_whole_digits} dígitos en la parte entera." + +#: fields.py:813 +msgid "Datetime has wrong format. Use one of these formats instead: {format}." +msgstr "Fecha/hora con formato erróneo. Use uno de los siguientes formatos en su lugar: {format}." + +#: fields.py:814 +msgid "Expected a datetime but got a date." +msgstr "Se esperaba un fecha/hora en vez de una fecha." + +#: fields.py:878 +msgid "Date has wrong format. Use one of these formats instead: {format}." +msgstr "Fecha con formato erróneo. Use uno de los siguientes formatos en su lugar: {format}." + +#: fields.py:879 +msgid "Expected a date but got a datetime." +msgstr "Se esperaba una fecha en vez de una fecha/hora." + +#: fields.py:936 +msgid "Time has wrong format. Use one of these formats instead: {format}." +msgstr "Hora con formato erróneo. Use uno de los siguientes formatos en su lugar: {format}." + +#: fields.py:992 fields.py:1036 +msgid "\"{input}\" is not a valid choice." +msgstr "\"{input}\" no es una elección válida." + +#: fields.py:1037 fields.py:1151 serializers.py:482 +msgid "Expected a list of items but got type \"{input_type}\"." +msgstr "Se esperaba una lista de elementos en vez del tipo \"{input_type}\"." + +#: fields.py:1067 +msgid "No file was submitted." +msgstr "No se envió ningún archivo." + +#: fields.py:1068 +msgid "" +"The submitted data was not a file. Check the encoding type on the form." +msgstr "La información enviada no era un archivo. Compruebe el tipo de codificación del formulario." + +#: fields.py:1069 +msgid "No filename could be determined." +msgstr "No se pudo determinar un nombre de archivo." + +#: fields.py:1070 +msgid "The submitted file is empty." +msgstr "El archivo enviado está vació." + +#: fields.py:1071 +msgid "" +"Ensure this filename has at most {max_length} characters (it has {length})." +msgstr "Asegúrese de que el nombre de archivo no tenga más de {max_length} caracteres (tiene {length})." + +#: fields.py:1113 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "Adjunte una imagen válida. El archivo adjunto o bien no es una imagen o bien está dañado." + +#: fields.py:1188 +msgid "Expected a dictionary of items but got type \"{input_type}\"." +msgstr "" + +#: pagination.py:221 +msgid "Invalid page \"{page_number}\": {message}." +msgstr "Página \"{page_number}\" inválida: {message}." + +#: pagination.py:442 +msgid "Invalid cursor" +msgstr "" + +#: relations.py:133 +msgid "Invalid pk \"{pk_value}\" - object does not exist." +msgstr "Clave primaria \"{pk_value}\" inválida - objeto no existe." + +#: relations.py:134 +msgid "Incorrect type. Expected pk value, received {data_type}." +msgstr "Tipo incorrecto. Se esperaba valor de clave primaria y se recibió {data_type}." + +#: relations.py:157 +msgid "Invalid hyperlink - No URL match." +msgstr "Hiperenlace inválido - No hay URL coincidentes." + +#: relations.py:158 +msgid "Invalid hyperlink - Incorrect URL match." +msgstr "Hiperenlace inválido - Coincidencia incorrecta de la URL." + +#: relations.py:159 +msgid "Invalid hyperlink - Object does not exist." +msgstr "Hiperenlace inválido - Objeto no existe." + +#: relations.py:160 +msgid "Incorrect type. Expected URL string, received {data_type}." +msgstr "Tipo incorrecto. Se esperaba una URL y se recibió {data_type}." + +#: relations.py:295 +msgid "Object with {slug_name}={value} does not exist." +msgstr "Objeto con {slug_name}={value} no existe." + +#: relations.py:296 +msgid "Invalid value." +msgstr "Valor inválido." + +#: serializers.py:299 +msgid "Invalid data. Expected a dictionary, but got {datatype}." +msgstr "Datos inválidos. Se esperaba un diccionario pero es un {datatype}." + +#: validators.py:22 +msgid "This field must be unique." +msgstr "Este campo debe ser único." + +#: validators.py:76 +msgid "The fields {field_names} must make a unique set." +msgstr "Los campos {field_names} deben formar un conjunto único." + +#: validators.py:219 +msgid "This field must be unique for the \"{date_field}\" date." +msgstr "Este campo debe ser único para el día \"{date_field}\"." + +#: validators.py:234 +msgid "This field must be unique for the \"{date_field}\" month." +msgstr "Este campo debe ser único para el mes \"{date_field}\"." + +#: validators.py:247 +msgid "This field must be unique for the \"{date_field}\" year." +msgstr "Este campo debe ser único para el año \"{date_field}\"." + +#: versioning.py:39 +msgid "Invalid version in \"Accept\" header." +msgstr "Versión inválida en la cabecera \"Accept\"." + +#: versioning.py:70 versioning.py:112 +msgid "Invalid version in URL path." +msgstr "Versión inválida en la ruta de la URL." + +#: versioning.py:138 +msgid "Invalid version in hostname." +msgstr "Versión inválida en el nombre de host." + +#: versioning.py:160 +msgid "Invalid version in query parameter." +msgstr "Versión inválida en el parámetro de consulta." + +#: authtoken/serializers.py:20 +msgid "User account is disabled." +msgstr "Cuenta de usuario está deshabilitada." + +#: authtoken/serializers.py:23 +msgid "Unable to log in with provided credentials." +msgstr "No puede iniciar sesión con las credenciales proporcionadas." + +#: authtoken/serializers.py:26 +msgid "Must include \"username\" and \"password\"." +msgstr "Debe incluir \"username\" y \"password\"." diff --git a/rest_framework/locale/et/LC_MESSAGES/django.mo b/rest_framework/locale/et/LC_MESSAGES/django.moBinary files differ new file mode 100644 index 00000000..ca9b6ec4 --- /dev/null +++ b/rest_framework/locale/et/LC_MESSAGES/django.mo diff --git a/rest_framework/locale/et/LC_MESSAGES/django.po b/rest_framework/locale/et/LC_MESSAGES/django.po new file mode 100644 index 00000000..dec03d4d --- /dev/null +++ b/rest_framework/locale/et/LC_MESSAGES/django.po @@ -0,0 +1,325 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +#  +# Translators: +# Tõnis Kärdi <tonis.kardi@gmail.com>, 2015 +msgid "" +msgstr "" +"Project-Id-Version: Django REST framework\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-30 16:23+0000\n" +"PO-Revision-Date: 2015-01-30 16:27+0000\n" +"Last-Translator: Thomas Christie <tom@tomchristie.com>\n" +"Language-Team: Estonian (http://www.transifex.com/projects/p/django-rest-framework/language/et/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: et\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\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 "Vale kasutajatunnus/salasõna." + +#: 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 "Kasutaja on inaktiivne või kustutatud." + +#: 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:153 relations.py:132 relations.py:156 validators.py:77 +#: validators.py:155 +msgid "This field is required." +msgstr "Väli on kohustuslik." + +#: fields.py:154 +msgid "This field may not be null." +msgstr "Väli ei tohi olla tühi." + +#: fields.py:487 fields.py:515 +msgid "\"{input}\" is not a valid boolean." +msgstr "" + +#: fields.py:550 +msgid "This field may not be blank." +msgstr "" + +#: fields.py:551 fields.py:1324 +msgid "Ensure this field has no more than {max_length} characters." +msgstr "" + +#: fields.py:552 +msgid "Ensure this field has at least {min_length} characters." +msgstr "" + +#: fields.py:587 +msgid "Enter a valid email address." +msgstr "Sisesta kehtiv e-posti aadress." + +#: fields.py:604 +msgid "This value does not match the required pattern." +msgstr "Väärtus ei ühti etteantud mustriga." + +#: 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 "Sisesta korrektne URL." + +#: fields.py:638 +msgid "\"{value}\" is not a valid UUID." +msgstr "" + +#: fields.py:657 +msgid "A valid integer is required." +msgstr "" + +#: fields.py:658 fields.py:692 fields.py:725 +msgid "Ensure this value is less than or equal to {max_value}." +msgstr "Veendu, et väärtus on väiksem kui või võrdne väärtusega {max_value}. " + +#: fields.py:659 fields.py:693 fields.py:726 +msgid "Ensure this value is greater than or equal to {min_value}." +msgstr "Veendu, et väärtus on suurem kui või võrdne väärtusega {min_value}." + +#: fields.py:660 fields.py:694 fields.py:730 +msgid "String value too large." +msgstr "Sõne on liiga pikk." + +#: fields.py:691 fields.py:724 +msgid "A valid number is required." +msgstr "" + +#: fields.py:727 +msgid "Ensure that there are no more than {max_digits} digits in total." +msgstr "Veendu, et kokku pole rohkem kui {max_digits}." + +#: fields.py:728 +msgid "" +"Ensure that there are no more than {max_decimal_places} decimal places." +msgstr "Veendu, et komakohti pole rohkem kui {max_decimal_places}. " + +#: fields.py:729 +msgid "" +"Ensure that there are no more than {max_whole_digits} digits before the " +"decimal point." +msgstr "" + +#: fields.py:813 +msgid "Datetime has wrong format. Use one of these formats instead: {format}." +msgstr "" + +#: fields.py:814 +msgid "Expected a datetime but got a date." +msgstr "" + +#: fields.py:878 +msgid "Date has wrong format. Use one of these formats instead: {format}." +msgstr "" + +#: fields.py:879 +msgid "Expected a date but got a datetime." +msgstr "" + +#: fields.py:936 +msgid "Time has wrong format. Use one of these formats instead: {format}." +msgstr "" + +#: fields.py:992 fields.py:1036 +msgid "\"{input}\" is not a valid choice." +msgstr "" + +#: fields.py:1037 fields.py:1151 serializers.py:482 +msgid "Expected a list of items but got type \"{input_type}\"." +msgstr "" + +#: fields.py:1067 +msgid "No file was submitted." +msgstr "" + +#: fields.py:1068 +msgid "" +"The submitted data was not a file. Check the encoding type on the form." +msgstr "" + +#: fields.py:1069 +msgid "No filename could be determined." +msgstr "" + +#: fields.py:1070 +msgid "The submitted file is empty." +msgstr "" + +#: fields.py:1071 +msgid "" +"Ensure this filename has at most {max_length} characters (it has {length})." +msgstr "" + +#: fields.py:1113 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "" + +#: fields.py:1188 +msgid "Expected a dictionary of items but got type \"{input_type}\"." +msgstr "" + +#: pagination.py:221 +msgid "Invalid page \"{page_number}\": {message}." +msgstr "" + +#: pagination.py:442 +msgid "Invalid cursor" +msgstr "" + +#: relations.py:133 +msgid "Invalid pk \"{pk_value}\" - object does not exist." +msgstr "" + +#: relations.py:134 +msgid "Incorrect type. Expected pk value, received {data_type}." +msgstr "" + +#: relations.py:157 +msgid "Invalid hyperlink - No URL match." +msgstr "" + +#: relations.py:158 +msgid "Invalid hyperlink - Incorrect URL match." +msgstr "" + +#: relations.py:159 +msgid "Invalid hyperlink - Object does not exist." +msgstr "" + +#: relations.py:160 +msgid "Incorrect type. Expected URL string, received {data_type}." +msgstr "" + +#: relations.py:295 +msgid "Object with {slug_name}={value} does not exist." +msgstr "" + +#: relations.py:296 +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 "" + +#: authtoken/serializers.py:20 +msgid "User account is disabled." +msgstr "Kasutajakonto on suletud" + +#: authtoken/serializers.py:23 +msgid "Unable to log in with provided credentials." +msgstr "Sisselogimine antud tunnusega ebaõnnestus." + +#: authtoken/serializers.py:26 +msgid "Must include \"username\" and \"password\"." +msgstr "Peab sisaldama \"kasutajatunnust\" ja \"slasõna\"." diff --git a/rest_framework/locale/fr/LC_MESSAGES/django.mo b/rest_framework/locale/fr/LC_MESSAGES/django.moBinary files differ new file mode 100644 index 00000000..68519d45 --- /dev/null +++ b/rest_framework/locale/fr/LC_MESSAGES/django.mo diff --git a/rest_framework/locale/fr/LC_MESSAGES/django.po b/rest_framework/locale/fr/LC_MESSAGES/django.po new file mode 100644 index 00000000..e8597c30 --- /dev/null +++ b/rest_framework/locale/fr/LC_MESSAGES/django.po @@ -0,0 +1,326 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +#  +# Translators: +# Etienne Desgagné <etienne.desgagne@evimbec.ca>, 2015 +# Martin Maillard <martin.maillard@gmail.com>, 2015 +msgid "" +msgstr "" +"Project-Id-Version: Django REST framework\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-30 16:23+0000\n" +"PO-Revision-Date: 2015-01-30 16:27+0000\n" +"Last-Translator: Thomas Christie <tom@tomchristie.com>\n" +"Language-Team: French (http://www.transifex.com/projects/p/django-rest-framework/language/fr/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: fr\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: authentication.py:69 +msgid "Invalid basic header. No credentials provided." +msgstr "En-tête « basic » non valide. Informations d'identification non fournies." + +#: authentication.py:72 +msgid "Invalid basic header. Credentials string should not contain spaces." +msgstr "En-tête « basic » non valide. Les informations d'identification ne doivent pas contenir d'espaces." + +#: authentication.py:78 +msgid "Invalid basic header. Credentials not correctly base64 encoded." +msgstr "En-tête « basic » non valide. Encodage base64 des informations d'identification incorrect." + +#: authentication.py:90 +msgid "Invalid username/password." +msgstr "Nom d'utilisateur et/ou mot de passe non valide(s)." + +#: authentication.py:156 +msgid "Invalid token header. No credentials provided." +msgstr "En-tête « token » non valide. Informations d'identification non fournies." + +#: authentication.py:159 +msgid "Invalid token header. Token string should not contain spaces." +msgstr "En-tête « token » non valide. Un token ne doit pas contenir d'espaces." + +#: authentication.py:168 +msgid "Invalid token." +msgstr "Token non valide." + +#: authentication.py:171 +msgid "User inactive or deleted." +msgstr "Utilisateur inactif ou supprimé." + +#: exceptions.py:38 +msgid "A server error occurred." +msgstr "Une erreur du serveur est survenue." + +#: exceptions.py:73 +msgid "Malformed request." +msgstr "Requête malformée" + +#: exceptions.py:78 +msgid "Incorrect authentication credentials." +msgstr "Informations d'authentification incorrectes." + +#: exceptions.py:83 +msgid "Authentication credentials were not provided." +msgstr "Informations d'authentification non fournies." + +#: exceptions.py:88 +msgid "You do not have permission to perform this action." +msgstr "Vous n'avez pas la permission d'effectuer cette action." + +#: exceptions.py:93 +msgid "Not found." +msgstr "" + +#: exceptions.py:98 +msgid "Method \"{method}\" not allowed." +msgstr "Méthode \"{method}\" non autorisée." + +#: 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:153 relations.py:132 relations.py:156 validators.py:77 +#: validators.py:155 +msgid "This field is required." +msgstr "Ce champ est obligatoire." + +#: fields.py:154 +msgid "This field may not be null." +msgstr "Ce champ ne peut être null." + +#: fields.py:487 fields.py:515 +msgid "\"{input}\" is not a valid boolean." +msgstr "\"{input}\" n'est pas un booléen valide." + +#: fields.py:550 +msgid "This field may not be blank." +msgstr "Ce champ ne peut être vide." + +#: fields.py:551 fields.py:1324 +msgid "Ensure this field has no more than {max_length} characters." +msgstr "Assurez-vous que ce champ comporte au plus {max_length} caractères." + +#: fields.py:552 +msgid "Ensure this field has at least {min_length} characters." +msgstr "Assurez-vous que ce champ comporte au moins {min_length} caractères." + +#: fields.py:587 +msgid "Enter a valid email address." +msgstr "Saisissez une adresse email valable." + +#: fields.py:604 +msgid "This value does not match the required pattern." +msgstr "Cette valeur ne satisfait pas le motif imposé." + +#: fields.py:615 +msgid "" +"Enter a valid \"slug\" consisting of letters, numbers, underscores or " +"hyphens." +msgstr "Ce champ ne doit contenir que des lettres, des nombres, des tirets bas _ et des traits d'union." + +#: fields.py:627 +msgid "Enter a valid URL." +msgstr "Saisissez une URL valide." + +#: fields.py:638 +msgid "\"{value}\" is not a valid UUID." +msgstr "" + +#: fields.py:657 +msgid "A valid integer is required." +msgstr "Saisissez un nombre entier valide." + +#: fields.py:658 fields.py:692 fields.py:725 +msgid "Ensure this value is less than or equal to {max_value}." +msgstr "Assurez-vous que cette valeur est inférieure ou égale à {max_value}." + +#: fields.py:659 fields.py:693 fields.py:726 +msgid "Ensure this value is greater than or equal to {min_value}." +msgstr "Assurez-vous que cette valeur est supérieure ou égale à {min_value}." + +#: fields.py:660 fields.py:694 fields.py:730 +msgid "String value too large." +msgstr "Chaîne de caractères trop longue." + +#: fields.py:691 fields.py:724 +msgid "A valid number is required." +msgstr "Un nombre valide est requis." + +#: fields.py:727 +msgid "Ensure that there are no more than {max_digits} digits in total." +msgstr "Assurez-vous qu'il n'y a pas plus de {max_digits} chiffres au total." + +#: fields.py:728 +msgid "" +"Ensure that there are no more than {max_decimal_places} decimal places." +msgstr "Assurez-vous qu'il n'y a pas plus de {max_decimal_places} chiffres après la virgule." + +#: fields.py:729 +msgid "" +"Ensure that there are no more than {max_whole_digits} digits before the " +"decimal point." +msgstr "Assurez-vous qu'il n'y a pas plus de {max_whole_digits} chiffres avant la virgule." + +#: fields.py:813 +msgid "Datetime has wrong format. Use one of these formats instead: {format}." +msgstr "" + +#: fields.py:814 +msgid "Expected a datetime but got a date." +msgstr "" + +#: fields.py:878 +msgid "Date has wrong format. Use one of these formats instead: {format}." +msgstr "" + +#: fields.py:879 +msgid "Expected a date but got a datetime." +msgstr "" + +#: fields.py:936 +msgid "Time has wrong format. Use one of these formats instead: {format}." +msgstr "" + +#: fields.py:992 fields.py:1036 +msgid "\"{input}\" is not a valid choice." +msgstr "\"{input}\" n'est pas un choix valide." + +#: fields.py:1037 fields.py:1151 serializers.py:482 +msgid "Expected a list of items but got type \"{input_type}\"." +msgstr "" + +#: fields.py:1067 +msgid "No file was submitted." +msgstr "Aucun fichier n'a été soumis." + +#: fields.py:1068 +msgid "" +"The submitted data was not a file. Check the encoding type on the form." +msgstr "La donnée soumise n'est pas un fichier. Vérifiez le type d'encodage du formulaire." + +#: fields.py:1069 +msgid "No filename could be determined." +msgstr "Le nom de fichier n'a pu être déterminé." + +#: fields.py:1070 +msgid "The submitted file is empty." +msgstr "Le fichier soumis est vide." + +#: fields.py:1071 +msgid "" +"Ensure this filename has at most {max_length} characters (it has {length})." +msgstr "Assurez-vous que le nom de fichier comporte au plus {max_length} caractères (il en comporte {length})." + +#: fields.py:1113 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "Transférez une image valide. Le fichier que vous avez transféré n'est pas une image, ou il est corrompu." + +#: fields.py:1188 +msgid "Expected a dictionary of items but got type \"{input_type}\"." +msgstr "" + +#: pagination.py:221 +msgid "Invalid page \"{page_number}\": {message}." +msgstr "Page \"{page_number}\" non valide : {message}." + +#: pagination.py:442 +msgid "Invalid cursor" +msgstr "" + +#: relations.py:133 +msgid "Invalid pk \"{pk_value}\" - object does not exist." +msgstr "Clé primaire \"{pk_value}\" non valide - l'objet n'existe pas." + +#: relations.py:134 +msgid "Incorrect type. Expected pk value, received {data_type}." +msgstr "" + +#: relations.py:157 +msgid "Invalid hyperlink - No URL match." +msgstr "" + +#: relations.py:158 +msgid "Invalid hyperlink - Incorrect URL match." +msgstr "" + +#: relations.py:159 +msgid "Invalid hyperlink - Object does not exist." +msgstr "" + +#: relations.py:160 +msgid "Incorrect type. Expected URL string, received {data_type}." +msgstr "" + +#: relations.py:295 +msgid "Object with {slug_name}={value} does not exist." +msgstr "L'object avec {slug_name}={value} n'existe pas." + +#: relations.py:296 +msgid "Invalid value." +msgstr "Valeur non valide." + +#: serializers.py:299 +msgid "Invalid data. Expected a dictionary, but got {datatype}." +msgstr "" + +#: validators.py:22 +msgid "This field must be unique." +msgstr "Ce champ doit être unique." + +#: validators.py:76 +msgid "The fields {field_names} must make a unique set." +msgstr "Les champs {field_names} doivent former un ensemble unique." + +#: validators.py:219 +msgid "This field must be unique for the \"{date_field}\" date." +msgstr "Ce champ doit être unique pour la date \"{date_field}\"." + +#: validators.py:234 +msgid "This field must be unique for the \"{date_field}\" month." +msgstr "Ce champ doit être unique pour le mois \"{date_field}\"." + +#: validators.py:247 +msgid "This field must be unique for the \"{date_field}\" year." +msgstr "Ce champ doit être unique pour l'année \"{date_field}\"." + +#: versioning.py:39 +msgid "Invalid version in \"Accept\" header." +msgstr "Version non valide dans l'en-tête « Accept »." + +#: versioning.py:70 versioning.py:112 +msgid "Invalid version in URL path." +msgstr "Version non valide dans l'URL." + +#: versioning.py:138 +msgid "Invalid version in hostname." +msgstr "Version non valide dans le nom d'hôte." + +#: versioning.py:160 +msgid "Invalid version in query parameter." +msgstr "Version non valide dans le paramètre de requête." + +#: authtoken/serializers.py:20 +msgid "User account is disabled." +msgstr "Ce compte est désactivé." + +#: authtoken/serializers.py:23 +msgid "Unable to log in with provided credentials." +msgstr "Impossible de se connecter avec les informations d'identification fournies." + +#: authtoken/serializers.py:26 +msgid "Must include \"username\" and \"password\"." +msgstr "\"username\" et \"password\" doivent être inclus." diff --git a/rest_framework/locale/hu/LC_MESSAGES/django.mo b/rest_framework/locale/hu/LC_MESSAGES/django.moBinary files differ new file mode 100644 index 00000000..451b0b9a --- /dev/null +++ b/rest_framework/locale/hu/LC_MESSAGES/django.mo diff --git a/rest_framework/locale/hu/LC_MESSAGES/django.po b/rest_framework/locale/hu/LC_MESSAGES/django.po new file mode 100644 index 00000000..14fb6544 --- /dev/null +++ b/rest_framework/locale/hu/LC_MESSAGES/django.po @@ -0,0 +1,325 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +#  +# Translators: +# Zoltan Szalai <defaultdict@gmail.com>, 2015 +msgid "" +msgstr "" +"Project-Id-Version: Django REST framework\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-30 16:23+0000\n" +"PO-Revision-Date: 2015-01-30 16:27+0000\n" +"Last-Translator: Thomas Christie <tom@tomchristie.com>\n" +"Language-Team: Hungarian (http://www.transifex.com/projects/p/django-rest-framework/language/hu/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: hu\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: authentication.py:69 +msgid "Invalid basic header. No credentials provided." +msgstr "Érvénytelen basic fejlécmező. Nem voltak megadva azonosítók." + +#: authentication.py:72 +msgid "Invalid basic header. Credentials string should not contain spaces." +msgstr "Érvénytelen basic fejlécmező. Az azonosító karakterlánc nem tartalmazhat szóközöket." + +#: authentication.py:78 +msgid "Invalid basic header. Credentials not correctly base64 encoded." +msgstr "Érvénytelen basic fejlécmező. Az azonosítók base64 kódolása nem megfelelő." + +#: authentication.py:90 +msgid "Invalid username/password." +msgstr "Érvénytelen felhasználónév/jelszó." + +#: authentication.py:156 +msgid "Invalid token header. No credentials provided." +msgstr "Érvénytelen token fejlécmező. Nem voltak megadva azonosítók." + +#: authentication.py:159 +msgid "Invalid token header. Token string should not contain spaces." +msgstr "Érvénytelen token fejlécmező. A token karakterlánc nem tartalmazhat szóközöket." + +#: authentication.py:168 +msgid "Invalid token." +msgstr "Érvénytelen token." + +#: authentication.py:171 +msgid "User inactive or deleted." +msgstr "A felhasználó nincs aktiválva vagy törölve lett." + +#: exceptions.py:38 +msgid "A server error occurred." +msgstr "Szerver oldali hiba történt." + +#: exceptions.py:73 +msgid "Malformed request." +msgstr "Hibás kérés." + +#: exceptions.py:78 +msgid "Incorrect authentication credentials." +msgstr "Hibás azonosítók." + +#: exceptions.py:83 +msgid "Authentication credentials were not provided." +msgstr "Nem voltak megadva azonosítók." + +#: exceptions.py:88 +msgid "You do not have permission to perform this action." +msgstr "Nincs jogosultsága a művelet végrehajtásához." + +#: exceptions.py:93 +msgid "Not found." +msgstr "Nem található." + +#: exceptions.py:98 +msgid "Method \"{method}\" not allowed." +msgstr "A \"{method}\" metódus nem megengedett." + +#: exceptions.py:109 +msgid "Could not satisfy the request Accept header." +msgstr "A kérés Accept fejlécmezőjét nem lehetett kiszolgálni." + +#: exceptions.py:121 +msgid "Unsupported media type \"{media_type}\" in request." +msgstr "Nem támogatott média típus \"{media_type}\" a kérésben." + +#: exceptions.py:134 +msgid "Request was throttled." +msgstr "A kérés korlátozva lett." + +#: fields.py:153 relations.py:132 relations.py:156 validators.py:77 +#: validators.py:155 +msgid "This field is required." +msgstr "Ennek a mezőnek a megadása kötelező." + +#: fields.py:154 +msgid "This field may not be null." +msgstr "Ez a mező nem lehet null értékű." + +#: fields.py:487 fields.py:515 +msgid "\"{input}\" is not a valid boolean." +msgstr "Az \"{input}\" nem egy érvényes logikai érték." + +#: fields.py:550 +msgid "This field may not be blank." +msgstr "Ez a mező nem lehet üres." + +#: fields.py:551 fields.py:1324 +msgid "Ensure this field has no more than {max_length} characters." +msgstr "Bizonyosodjon meg arról, hogy ez a mező legfeljebb {max_length} karakterből áll." + +#: fields.py:552 +msgid "Ensure this field has at least {min_length} characters." +msgstr "Bizonyosodjon meg arról, hogy ez a mező legalább {min_length} karakterből áll." + +#: fields.py:587 +msgid "Enter a valid email address." +msgstr "Adjon meg egy érvényes e-mail címet!" + +#: fields.py:604 +msgid "This value does not match the required pattern." +msgstr "Ez az érték nem illeszkedik a szükséges mintázatra." + +#: fields.py:615 +msgid "" +"Enter a valid \"slug\" consisting of letters, numbers, underscores or " +"hyphens." +msgstr "Az URL barát cím csak betűket, számokat, aláhúzásokat és kötőjeleket tartalmazhat." + +#: fields.py:627 +msgid "Enter a valid URL." +msgstr "Adjon meg egy érvényes URL-t!" + +#: fields.py:638 +msgid "\"{value}\" is not a valid UUID." +msgstr "" + +#: fields.py:657 +msgid "A valid integer is required." +msgstr "Egy érvényes egész szám megadása szükséges." + +#: fields.py:658 fields.py:692 fields.py:725 +msgid "Ensure this value is less than or equal to {max_value}." +msgstr "Bizonyosodjon meg arról, hogy ez az érték legfeljebb {max_value}." + +#: fields.py:659 fields.py:693 fields.py:726 +msgid "Ensure this value is greater than or equal to {min_value}." +msgstr "Bizonyosodjon meg arról, hogy ez az érték legalább {min_value}." + +#: fields.py:660 fields.py:694 fields.py:730 +msgid "String value too large." +msgstr "A karakterlánc túl hosszú." + +#: fields.py:691 fields.py:724 +msgid "A valid number is required." +msgstr "Egy érvényes szám megadása szükséges." + +#: fields.py:727 +msgid "Ensure that there are no more than {max_digits} digits in total." +msgstr "Bizonyosodjon meg arról, hogy a számjegyek száma összesen legfeljebb {max_digits}." + +#: fields.py:728 +msgid "" +"Ensure that there are no more than {max_decimal_places} decimal places." +msgstr "Bizonyosodjon meg arról, hogy a tizedes tört törtrészében levő számjegyek száma összesen legfeljebb {max_decimal_places}." + +#: fields.py:729 +msgid "" +"Ensure that there are no more than {max_whole_digits} digits before the " +"decimal point." +msgstr "Bizonyosodjon meg arról, hogy a tizedes tört egész részében levő számjegyek száma összesen legfeljebb {max_whole_digits}." + +#: fields.py:813 +msgid "Datetime has wrong format. Use one of these formats instead: {format}." +msgstr "A dátum formátuma hibás. Használja ezek valamelyikét helyette: {format}." + +#: fields.py:814 +msgid "Expected a datetime but got a date." +msgstr "Időt is tartalmazó dátum helyett egy időt nem tartalmazó dátum lett elküldve." + +#: fields.py:878 +msgid "Date has wrong format. Use one of these formats instead: {format}." +msgstr "A dátum formátuma hibás. Használja ezek valamelyikét helyette: {format}." + +#: fields.py:879 +msgid "Expected a date but got a datetime." +msgstr "Időt nem tartalmazó dátum helyett egy időt is tartalmazó dátum lett elküldve." + +#: fields.py:936 +msgid "Time has wrong format. Use one of these formats instead: {format}." +msgstr "Az idő formátuma hibás. Használja ezek valamelyikét helyette: {format}." + +#: fields.py:992 fields.py:1036 +msgid "\"{input}\" is not a valid choice." +msgstr "Az \"{input}\" nem egy érvényes elem." + +#: fields.py:1037 fields.py:1151 serializers.py:482 +msgid "Expected a list of items but got type \"{input_type}\"." +msgstr "Elemek listája helyett \"{input_type}\" lett elküldve." + +#: fields.py:1067 +msgid "No file was submitted." +msgstr "Semmilyen fájl sem került feltöltésre." + +#: fields.py:1068 +msgid "" +"The submitted data was not a file. Check the encoding type on the form." +msgstr "Az elküldött adat nem egy fájl volt. Ellenőrizze a kódolás típusát az űrlapon!" + +#: fields.py:1069 +msgid "No filename could be determined." +msgstr "A fájlnév nem megállapítható." + +#: fields.py:1070 +msgid "The submitted file is empty." +msgstr "A küldött fájl üres." + +#: fields.py:1071 +msgid "" +"Ensure this filename has at most {max_length} characters (it has {length})." +msgstr "Bizonyosodjon meg arról, hogy a fájlnév legfeljebb {max_length} karakterből áll (jelenlegi hossza: {length})." + +#: fields.py:1113 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "Töltsön fel egy érvényes képfájlt! A feltöltött fájl nem kép volt, vagy megsérült." + +#: fields.py:1188 +msgid "Expected a dictionary of items but got type \"{input_type}\"." +msgstr "" + +#: pagination.py:221 +msgid "Invalid page \"{page_number}\": {message}." +msgstr "Érvénytelen oldal \"{page_number}\": {message}." + +#: pagination.py:442 +msgid "Invalid cursor" +msgstr "" + +#: relations.py:133 +msgid "Invalid pk \"{pk_value}\" - object does not exist." +msgstr "Érvénytelen pk \"{pk_value}\" - az objektum nem létezik." + +#: relations.py:134 +msgid "Incorrect type. Expected pk value, received {data_type}." +msgstr "Helytelen típus. pk érték helyett {data_type} lett elküldve." + +#: relations.py:157 +msgid "Invalid hyperlink - No URL match." +msgstr "Érvénytelen link - Nem illeszkedő URL." + +#: relations.py:158 +msgid "Invalid hyperlink - Incorrect URL match." +msgstr "Érvénytelen link. - Eltérő URL illeszkedés." + +#: relations.py:159 +msgid "Invalid hyperlink - Object does not exist." +msgstr "Érvénytelen link - Az objektum nem létezik." + +#: relations.py:160 +msgid "Incorrect type. Expected URL string, received {data_type}." +msgstr "Helytelen típus. URL karakterlánc helyett {data_type} lett elküldve." + +#: relations.py:295 +msgid "Object with {slug_name}={value} does not exist." +msgstr "Nem létezik olyan objektum, amelynél {slug_name}={value}." + +#: relations.py:296 +msgid "Invalid value." +msgstr "Érvénytelen érték." + +#: serializers.py:299 +msgid "Invalid data. Expected a dictionary, but got {datatype}." +msgstr "Érvénytelen adat. Egy dictionary helyett {datatype} lett elküldve." + +#: validators.py:22 +msgid "This field must be unique." +msgstr "Ennek a mezőnek egyedinek kell lennie." + +#: validators.py:76 +msgid "The fields {field_names} must make a unique set." +msgstr "A {field_names} mezőnevek nem tartalmazhatnak duplikátumot." + +#: validators.py:219 +msgid "This field must be unique for the \"{date_field}\" date." +msgstr "A mezőnek egyedinek kell lennie a \"{date_field}\" dátumra." + +#: validators.py:234 +msgid "This field must be unique for the \"{date_field}\" month." +msgstr "A mezőnek egyedinek kell lennie a \"{date_field}\" hónapra." + +#: validators.py:247 +msgid "This field must be unique for the \"{date_field}\" year." +msgstr "A mezőnek egyedinek kell lennie a \"{date_field}\" évre." + +#: versioning.py:39 +msgid "Invalid version in \"Accept\" header." +msgstr "Érvénytelen verzió az \"Accept\" fejlécmezőben." + +#: versioning.py:70 versioning.py:112 +msgid "Invalid version in URL path." +msgstr "Érvénytelen verzió az URL elérési útban." + +#: versioning.py:138 +msgid "Invalid version in hostname." +msgstr "Érvénytelen verzió a hosztnévben." + +#: versioning.py:160 +msgid "Invalid version in query parameter." +msgstr "Érvénytelen verzió a lekérdezési paraméterben." + +#: authtoken/serializers.py:20 +msgid "User account is disabled." +msgstr "A felhasználó tiltva van." + +#: authtoken/serializers.py:23 +msgid "Unable to log in with provided credentials." +msgstr "A megadott azonosítókkal nem lehet bejelentkezni." + +#: authtoken/serializers.py:26 +msgid "Must include \"username\" and \"password\"." +msgstr "Tartalmaznia kell a \"felhasználónevet\" és a \"jelszót\"." diff --git a/rest_framework/locale/id/LC_MESSAGES/django.mo b/rest_framework/locale/id/LC_MESSAGES/django.moBinary files differ new file mode 100644 index 00000000..7fc98bda --- /dev/null +++ b/rest_framework/locale/id/LC_MESSAGES/django.mo diff --git a/rest_framework/locale/id/LC_MESSAGES/django.po b/rest_framework/locale/id/LC_MESSAGES/django.po new file mode 100644 index 00000000..99b70546 --- /dev/null +++ b/rest_framework/locale/id/LC_MESSAGES/django.po @@ -0,0 +1,324 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +#  +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: Django REST framework\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-30 16:23+0000\n" +"PO-Revision-Date: 2015-01-30 16:27+0000\n" +"Last-Translator: Thomas Christie <tom@tomchristie.com>\n" +"Language-Team: Indonesian (http://www.transifex.com/projects/p/django-rest-framework/language/id/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: id\n" +"Plural-Forms: nplurals=1; plural=0;\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 "" + +#: 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:153 relations.py:132 relations.py:156 validators.py:77 +#: validators.py:155 +msgid "This field is required." +msgstr "" + +#: fields.py:154 +msgid "This field may not be null." +msgstr "" + +#: fields.py:487 fields.py:515 +msgid "\"{input}\" is not a valid boolean." +msgstr "" + +#: fields.py:550 +msgid "This field may not be blank." +msgstr "" + +#: fields.py:551 fields.py:1324 +msgid "Ensure this field has no more than {max_length} characters." +msgstr "" + +#: fields.py:552 +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:638 +msgid "\"{value}\" is not a valid UUID." +msgstr "" + +#: fields.py:657 +msgid "A valid integer is required." +msgstr "" + +#: fields.py:658 fields.py:692 fields.py:725 +msgid "Ensure this value is less than or equal to {max_value}." +msgstr "" + +#: fields.py:659 fields.py:693 fields.py:726 +msgid "Ensure this value is greater than or equal to {min_value}." +msgstr "" + +#: fields.py:660 fields.py:694 fields.py:730 +msgid "String value too large." +msgstr "" + +#: fields.py:691 fields.py:724 +msgid "A valid number is required." +msgstr "" + +#: fields.py:727 +msgid "Ensure that there are no more than {max_digits} digits in total." +msgstr "" + +#: fields.py:728 +msgid "" +"Ensure that there are no more than {max_decimal_places} decimal places." +msgstr "" + +#: fields.py:729 +msgid "" +"Ensure that there are no more than {max_whole_digits} digits before the " +"decimal point." +msgstr "" + +#: fields.py:813 +msgid "Datetime has wrong format. Use one of these formats instead: {format}." +msgstr "" + +#: fields.py:814 +msgid "Expected a datetime but got a date." +msgstr "" + +#: fields.py:878 +msgid "Date has wrong format. Use one of these formats instead: {format}." +msgstr "" + +#: fields.py:879 +msgid "Expected a date but got a datetime." +msgstr "" + +#: fields.py:936 +msgid "Time has wrong format. Use one of these formats instead: {format}." +msgstr "" + +#: fields.py:992 fields.py:1036 +msgid "\"{input}\" is not a valid choice." +msgstr "" + +#: fields.py:1037 fields.py:1151 serializers.py:482 +msgid "Expected a list of items but got type \"{input_type}\"." +msgstr "" + +#: fields.py:1067 +msgid "No file was submitted." +msgstr "" + +#: fields.py:1068 +msgid "" +"The submitted data was not a file. Check the encoding type on the form." +msgstr "" + +#: fields.py:1069 +msgid "No filename could be determined." +msgstr "" + +#: fields.py:1070 +msgid "The submitted file is empty." +msgstr "" + +#: fields.py:1071 +msgid "" +"Ensure this filename has at most {max_length} characters (it has {length})." +msgstr "" + +#: fields.py:1113 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "" + +#: fields.py:1188 +msgid "Expected a dictionary of items but got type \"{input_type}\"." +msgstr "" + +#: pagination.py:221 +msgid "Invalid page \"{page_number}\": {message}." +msgstr "" + +#: pagination.py:442 +msgid "Invalid cursor" +msgstr "" + +#: relations.py:133 +msgid "Invalid pk \"{pk_value}\" - object does not exist." +msgstr "" + +#: relations.py:134 +msgid "Incorrect type. Expected pk value, received {data_type}." +msgstr "" + +#: relations.py:157 +msgid "Invalid hyperlink - No URL match." +msgstr "" + +#: relations.py:158 +msgid "Invalid hyperlink - Incorrect URL match." +msgstr "" + +#: relations.py:159 +msgid "Invalid hyperlink - Object does not exist." +msgstr "" + +#: relations.py:160 +msgid "Incorrect type. Expected URL string, received {data_type}." +msgstr "" + +#: relations.py:295 +msgid "Object with {slug_name}={value} does not exist." +msgstr "" + +#: relations.py:296 +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 "" + +#: 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 "" diff --git a/rest_framework/locale/it/LC_MESSAGES/django.mo b/rest_framework/locale/it/LC_MESSAGES/django.moBinary files differ new file mode 100644 index 00000000..82ceb810 --- /dev/null +++ b/rest_framework/locale/it/LC_MESSAGES/django.mo diff --git a/rest_framework/locale/it/LC_MESSAGES/django.po b/rest_framework/locale/it/LC_MESSAGES/django.po new file mode 100644 index 00000000..2cdfb877 --- /dev/null +++ b/rest_framework/locale/it/LC_MESSAGES/django.po @@ -0,0 +1,325 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +#  +# Translators: +# Mattia Procopio <promat85@gmail.com>, 2015 +msgid "" +msgstr "" +"Project-Id-Version: Django REST framework\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-30 16:23+0000\n" +"PO-Revision-Date: 2015-01-30 16:27+0000\n" +"Last-Translator: Thomas Christie <tom@tomchristie.com>\n" +"Language-Team: Italian (http://www.transifex.com/projects/p/django-rest-framework/language/it/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: it\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\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 "Nome utente/password non validi" + +#: authentication.py:156 +msgid "Invalid token header. No credentials provided." +msgstr "Header del token non valido. Credenziali non fornite." + +#: authentication.py:159 +msgid "Invalid token header. Token string should not contain spaces." +msgstr "Header del token non valido. Il contenuto del token non dovrebbe contenere spazi." + +#: authentication.py:168 +msgid "Invalid token." +msgstr "Token invalido." + +#: authentication.py:171 +msgid "User inactive or deleted." +msgstr "Utente inattivo o eliminato." + +#: exceptions.py:38 +msgid "A server error occurred." +msgstr "Errore del server." + +#: exceptions.py:73 +msgid "Malformed request." +msgstr "Richiesta malformata." + +#: exceptions.py:78 +msgid "Incorrect authentication credentials." +msgstr "Credenziali di autenticazione incorrette." + +#: exceptions.py:83 +msgid "Authentication credentials were not provided." +msgstr "Non sono state immesse le credenziali di autenticazione." + +#: exceptions.py:88 +msgid "You do not have permission to perform this action." +msgstr "Non hai l'autorizzazione per eseguire questa azione." + +#: exceptions.py:93 +msgid "Not found." +msgstr "Non trovato." + +#: exceptions.py:98 +msgid "Method \"{method}\" not allowed." +msgstr "Metodo \"{method}\" non consentito" + +#: exceptions.py:109 +msgid "Could not satisfy the request Accept header." +msgstr "Impossibile soddisfare l'header \"Accept\" presente nella richiesta." + +#: exceptions.py:121 +msgid "Unsupported media type \"{media_type}\" in request." +msgstr "Tipo di media \"{media_type}\"non supportato." + +#: exceptions.py:134 +msgid "Request was throttled." +msgstr "" + +#: fields.py:153 relations.py:132 relations.py:156 validators.py:77 +#: validators.py:155 +msgid "This field is required." +msgstr "Campo obbligatorio." + +#: fields.py:154 +msgid "This field may not be null." +msgstr "Il campo non puà essere nullo." + +#: fields.py:487 fields.py:515 +msgid "\"{input}\" is not a valid boolean." +msgstr "\"{input}\" non è un valido valore booleano." + +#: fields.py:550 +msgid "This field may not be blank." +msgstr "Questo campo non può essere omesso." + +#: fields.py:551 fields.py:1324 +msgid "Ensure this field has no more than {max_length} characters." +msgstr "Assicurati che questo campo non abbia più di {max_length} caratteri." + +#: fields.py:552 +msgid "Ensure this field has at least {min_length} characters." +msgstr "Assicurati che questo campo abbia almeno {max_length} caratteri." + +#: fields.py:587 +msgid "Enter a valid email address." +msgstr "Inserisci un indirizzo email valido." + +#: 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 "Immetti uno \"slug\" valido che consista di lettere, numeri, underscore o trattini." + +#: fields.py:627 +msgid "Enter a valid URL." +msgstr "Inserisci un URL valido" + +#: fields.py:638 +msgid "\"{value}\" is not a valid UUID." +msgstr "" + +#: fields.py:657 +msgid "A valid integer is required." +msgstr "È richiesto un numero intero valido." + +#: fields.py:658 fields.py:692 fields.py:725 +msgid "Ensure this value is less than or equal to {max_value}." +msgstr "Assicurati che il valore sia minore o uguale a {max_value}." + +#: fields.py:659 fields.py:693 fields.py:726 +msgid "Ensure this value is greater than or equal to {min_value}." +msgstr "Assicurati che il valore sia maggiore o uguale a {min_value}." + +#: fields.py:660 fields.py:694 fields.py:730 +msgid "String value too large." +msgstr "" + +#: fields.py:691 fields.py:724 +msgid "A valid number is required." +msgstr "È richiesto un numero valido." + +#: fields.py:727 +msgid "Ensure that there are no more than {max_digits} digits in total." +msgstr "Assicurati che non ci siano più di {max_digits} cifre in totale." + +#: fields.py:728 +msgid "" +"Ensure that there are no more than {max_decimal_places} decimal places." +msgstr "Assicurati che non ci siano più di {max_decimal_places} cifre decimali." + +#: fields.py:729 +msgid "" +"Ensure that there are no more than {max_whole_digits} digits before the " +"decimal point." +msgstr "Assicurati che non ci siano più di {max_whole_digits} cifre prima del separatore decimale." + +#: fields.py:813 +msgid "Datetime has wrong format. Use one of these formats instead: {format}." +msgstr "L'oggetto di tipo datetime è in un formato errato. Usa uno dei seguenti formati: {format}." + +#: fields.py:814 +msgid "Expected a datetime but got a date." +msgstr "Atteso un oggetto di tipo datetime ma l'oggetto ricevuto è di tipo date." + +#: fields.py:878 +msgid "Date has wrong format. Use one of these formats instead: {format}." +msgstr "La data è in un formato errato. Usa uno dei seguenti formati: {format}." + +#: fields.py:879 +msgid "Expected a date but got a datetime." +msgstr "Atteso un oggetto di tipo date ma l'oggetto ricevuto è di tipo datetime." + +#: fields.py:936 +msgid "Time has wrong format. Use one of these formats instead: {format}." +msgstr "" + +#: fields.py:992 fields.py:1036 +msgid "\"{input}\" is not a valid choice." +msgstr "\"{input}\" non è una scelta valida." + +#: fields.py:1037 fields.py:1151 serializers.py:482 +msgid "Expected a list of items but got type \"{input_type}\"." +msgstr "Attesa una lista di oggetti ma l'oggetto ricevuto è di tipo \"{input_type}\"." + +#: fields.py:1067 +msgid "No file was submitted." +msgstr "Non è stato inviato alcun file." + +#: fields.py:1068 +msgid "" +"The submitted data was not a file. Check the encoding type on the form." +msgstr "" + +#: fields.py:1069 +msgid "No filename could be determined." +msgstr "Il nome del file non può essere determinato." + +#: fields.py:1070 +msgid "The submitted file is empty." +msgstr "Il file inviato è vuoto." + +#: fields.py:1071 +msgid "" +"Ensure this filename has at most {max_length} characters (it has {length})." +msgstr "" + +#: fields.py:1113 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "" + +#: fields.py:1188 +msgid "Expected a dictionary of items but got type \"{input_type}\"." +msgstr "" + +#: pagination.py:221 +msgid "Invalid page \"{page_number}\": {message}." +msgstr "" + +#: pagination.py:442 +msgid "Invalid cursor" +msgstr "" + +#: relations.py:133 +msgid "Invalid pk \"{pk_value}\" - object does not exist." +msgstr "" + +#: relations.py:134 +msgid "Incorrect type. Expected pk value, received {data_type}." +msgstr "" + +#: relations.py:157 +msgid "Invalid hyperlink - No URL match." +msgstr "" + +#: relations.py:158 +msgid "Invalid hyperlink - Incorrect URL match." +msgstr "" + +#: relations.py:159 +msgid "Invalid hyperlink - Object does not exist." +msgstr "" + +#: relations.py:160 +msgid "Incorrect type. Expected URL string, received {data_type}." +msgstr "" + +#: relations.py:295 +msgid "Object with {slug_name}={value} does not exist." +msgstr "" + +#: relations.py:296 +msgid "Invalid value." +msgstr "Valore non valido." + +#: serializers.py:299 +msgid "Invalid data. Expected a dictionary, but got {datatype}." +msgstr "" + +#: validators.py:22 +msgid "This field must be unique." +msgstr "Questo campo deve essere unico." + +#: 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 "" + +#: authtoken/serializers.py:20 +msgid "User account is disabled." +msgstr "L'account dell'utente è disabilitato" + +#: authtoken/serializers.py:23 +msgid "Unable to log in with provided credentials." +msgstr "Impossibile eseguire il log in con le credenziali immesse." + +#: authtoken/serializers.py:26 +msgid "Must include \"username\" and \"password\"." +msgstr "Deve includere \"nome utente\" e \"password\"." diff --git a/rest_framework/locale/ko_KR/LC_MESSAGES/django.mo b/rest_framework/locale/ko_KR/LC_MESSAGES/django.moBinary files differ new file mode 100644 index 00000000..457bb53c --- /dev/null +++ b/rest_framework/locale/ko_KR/LC_MESSAGES/django.mo diff --git a/rest_framework/locale/ko_KR/LC_MESSAGES/django.po b/rest_framework/locale/ko_KR/LC_MESSAGES/django.po new file mode 100644 index 00000000..963fe89a --- /dev/null +++ b/rest_framework/locale/ko_KR/LC_MESSAGES/django.po @@ -0,0 +1,325 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +#  +# Translators: +# SUN CHOI <best2378@gmail.com>, 2015 +msgid "" +msgstr "" +"Project-Id-Version: Django REST framework\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-30 16:23+0000\n" +"PO-Revision-Date: 2015-01-30 16:27+0000\n" +"Last-Translator: Thomas Christie <tom@tomchristie.com>\n" +"Language-Team: Korean (Korea) (http://www.transifex.com/projects/p/django-rest-framework/language/ko_KR/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: ko_KR\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: authentication.py:69 +msgid "Invalid basic header. No credentials provided." +msgstr "기본 헤더(basic header)가 유효하지 않습니다. 인증데이터(credentials)가 제공되지 않았습니다." + +#: authentication.py:72 +msgid "Invalid basic header. Credentials string should not contain spaces." +msgstr "기본 헤더(basic header)가 유효하지 않습니다. 인증데이터(credentials) 문자열은 빈칸(spaces)을 포함하지 않아야 합니다." + +#: authentication.py:78 +msgid "Invalid basic header. Credentials not correctly base64 encoded." +msgstr "기본 헤더(basic header)가 유효하지 않습니다. 인증데이터(credentials)가 base64로 적절히 부호화(encode)되지 않았습니다." + +#: authentication.py:90 +msgid "Invalid username/password." +msgstr "아이디/비밀번호가 유효하지 않습니다." + +#: authentication.py:156 +msgid "Invalid token header. No credentials provided." +msgstr "토큰 헤더가 유효하지 않습니다. 인증데이터(credentials)가 제공되지 않았습니다." + +#: authentication.py:159 +msgid "Invalid token header. Token string should not contain spaces." +msgstr "토큰 헤더가 유효하지 않습니다. 토큰 문자열은 빈칸(spaces)를 포함하지 않아야 합니다." + +#: authentication.py:168 +msgid "Invalid token." +msgstr "토큰이 유효하지 않습니다." + +#: authentication.py:171 +msgid "User inactive or deleted." +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 "자격 인증데이터(authentication credentials)가 정확하지 않습니다." + +#: exceptions.py:83 +msgid "Authentication credentials were not provided." +msgstr "자격 인증데이터(authentication credentials)가 제공되지 않았습니다." + +#: 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 "메소드(Method) \"{method}\"는 허용되지 않습니다." + +#: exceptions.py:109 +msgid "Could not satisfy the request Accept header." +msgstr "" + +#: exceptions.py:121 +msgid "Unsupported media type \"{media_type}\" in request." +msgstr "요청된 \"{media_type}\"가 지원되지 않는 미디어 형태입니다." + +#: exceptions.py:134 +msgid "Request was throttled." +msgstr "요청이 지연(throttled)되었습니다." + +#: fields.py:153 relations.py:132 relations.py:156 validators.py:77 +#: validators.py:155 +msgid "This field is required." +msgstr "이 항목을 채워주십시오." + +#: fields.py:154 +msgid "This field may not be null." +msgstr "" + +#: fields.py:487 fields.py:515 +msgid "\"{input}\" is not a valid boolean." +msgstr "\"{input}\"이 유효하지 않은 부울(boolean)입니다." + +#: fields.py:550 +msgid "This field may not be blank." +msgstr "" + +#: fields.py:551 fields.py:1324 +msgid "Ensure this field has no more than {max_length} characters." +msgstr "이 칸이 글자 수가 {max_length} 이하인지 확인하십시오." + +#: fields.py:552 +msgid "Ensure this field has at least {min_length} characters." +msgstr "이 칸이 글자 수가  적어도 {min_length} 이상인지 확인하십시오." + +#: 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 "문자, 숫자, 밑줄( _ ) 또는 하이픈( - )으로 이루어진 유효한 \"slug\"를 입력하십시오." + +#: fields.py:627 +msgid "Enter a valid URL." +msgstr "유효한 URL을 입력하십시오." + +#: fields.py:638 +msgid "\"{value}\" is not a valid UUID." +msgstr "" + +#: fields.py:657 +msgid "A valid integer is required." +msgstr "유효한 정수(integer)를 넣어주세요." + +#: fields.py:658 fields.py:692 fields.py:725 +msgid "Ensure this value is less than or equal to {max_value}." +msgstr "이 값이 {max_value}보다 작거나 같은지 확인하십시오." + +#: fields.py:659 fields.py:693 fields.py:726 +msgid "Ensure this value is greater than or equal to {min_value}." +msgstr "이 값이 {min_value}보다 크거나 같은지 확인하십시오." + +#: fields.py:660 fields.py:694 fields.py:730 +msgid "String value too large." +msgstr "문자열 값이 너무 큽니다." + +#: fields.py:691 fields.py:724 +msgid "A valid number is required." +msgstr "유효한 숫자를 넣어주세요." + +#: fields.py:727 +msgid "Ensure that there are no more than {max_digits} digits in total." +msgstr "전체 숫자(digits)가 {max_digits} 이하인지 확인하십시오." + +#: fields.py:728 +msgid "" +"Ensure that there are no more than {max_decimal_places} decimal places." +msgstr "소수점 자릿수가  {max_decimal_places} 이하인지 확인하십시오." + +#: fields.py:729 +msgid "" +"Ensure that there are no more than {max_whole_digits} digits before the " +"decimal point." +msgstr "소수점 자리 앞에 숫자(digits)가 {max_whole_digits} 이하인지 확인하십시오." + +#: fields.py:813 +msgid "Datetime has wrong format. Use one of these formats instead: {format}." +msgstr "Datetime의 포멧이 잘못되었습니다. 이 형식들 중 한가지를 사용하세요: {format}." + +#: fields.py:814 +msgid "Expected a datetime but got a date." +msgstr "예상된 datatime 대신 date를 받았습니다." + +#: fields.py:878 +msgid "Date has wrong format. Use one of these formats instead: {format}." +msgstr "Date의 포멧이 잘못되었습니다. 이 형식들 중 한가지를 사용하세요: {format}." + +#: fields.py:879 +msgid "Expected a date but got a datetime." +msgstr "예상된 date 대신 datetime을 받았습니다." + +#: fields.py:936 +msgid "Time has wrong format. Use one of these formats instead: {format}." +msgstr "Time의 포멧이 잘못되었습니다. 이 형식들 중 한가지를 사용하세요: {format}." + +#: fields.py:992 fields.py:1036 +msgid "\"{input}\" is not a valid choice." +msgstr "\"{input}\"이 유효하지 않은 선택(choice)입니다." + +#: fields.py:1037 fields.py:1151 serializers.py:482 +msgid "Expected a list of items but got type \"{input_type}\"." +msgstr "아이템 리스트가 예상되었으나 \"{input_type}\"를 받았습니다." + +#: fields.py:1067 +msgid "No file was submitted." +msgstr "파일이 제출되지 않았습니다." + +#: fields.py:1068 +msgid "" +"The submitted data was not a file. Check the encoding type on the form." +msgstr "제출된 데이터는 파일이 아닙니다. 제출된 서식의 인코딩 형식을 확인하세요." + +#: fields.py:1069 +msgid "No filename could be determined." +msgstr "파일명을 알 수 없습니다." + +#: fields.py:1070 +msgid "The submitted file is empty." +msgstr "제출된 파일이 비어있습니다." + +#: fields.py:1071 +msgid "" +"Ensure this filename has at most {max_length} characters (it has {length})." +msgstr "이 파일명의 글자수가 최대 {max_length}를 넘지 않는지 확인하십시오. (이것은 {length}가 있습니다)." + +#: fields.py:1113 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "유효한 이미지 파일을 업로드 하십시오. 업로드 하신 파일은 이미지 파일이 아니거나 손상된 이미지 파일입니다." + +#: fields.py:1188 +msgid "Expected a dictionary of items but got type \"{input_type}\"." +msgstr "" + +#: pagination.py:221 +msgid "Invalid page \"{page_number}\": {message}." +msgstr "유효하지 않은 page \"{page_number}\": {message}." + +#: pagination.py:442 +msgid "Invalid cursor" +msgstr "" + +#: relations.py:133 +msgid "Invalid pk \"{pk_value}\" - object does not exist." +msgstr "유효하지 않은 pk \"{pk_value}\" - 객체가 존재하지 않습니다." + +#: relations.py:134 +msgid "Incorrect type. Expected pk value, received {data_type}." +msgstr "잘못된 형식입니다. pk 값 대신 {data_type}를 받았습니다." + +#: relations.py:157 +msgid "Invalid hyperlink - No URL match." +msgstr "유효하지 않은 하이퍼링크 - 일치하는 URL이 없습니다." + +#: relations.py:158 +msgid "Invalid hyperlink - Incorrect URL match." +msgstr "유효하지 않은 하이퍼링크 - URL이 일치하지 않습니다." + +#: relations.py:159 +msgid "Invalid hyperlink - Object does not exist." +msgstr "유효하지 않은 하이퍼링크 - 객체가 존재하지 않습니다." + +#: relations.py:160 +msgid "Incorrect type. Expected URL string, received {data_type}." +msgstr "잘못된 형식입니다. URL 문자열을 예상했으나 {data_type}을 받았습니다." + +#: relations.py:295 +msgid "Object with {slug_name}={value} does not exist." +msgstr "{slug_name}={value} 객체가 존재하지 않습니다." + +#: relations.py:296 +msgid "Invalid value." +msgstr "값이 유효하지 않습니다." + +#: serializers.py:299 +msgid "Invalid data. Expected a dictionary, but got {datatype}." +msgstr "유효하지 않은 데이터. 딕셔너리(dictionary)대신 {datatype}를 받았습니다." + +#: 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 "" + +#: authtoken/serializers.py:20 +msgid "User account is disabled." +msgstr "사용자 계정을 사용할 수 없습니다." + +#: authtoken/serializers.py:23 +msgid "Unable to log in with provided credentials." +msgstr "제공된 인증데이터(credentials)로는 로그인할 수 없습니다." + +#: authtoken/serializers.py:26 +msgid "Must include \"username\" and \"password\"." +msgstr "\"아이디\"와 \"비밀번호\"를 포함해야 합니다." diff --git a/rest_framework/locale/mk/LC_MESSAGES/django.mo b/rest_framework/locale/mk/LC_MESSAGES/django.moBinary files differ new file mode 100644 index 00000000..fc586626 --- /dev/null +++ b/rest_framework/locale/mk/LC_MESSAGES/django.mo diff --git a/rest_framework/locale/mk/LC_MESSAGES/django.po b/rest_framework/locale/mk/LC_MESSAGES/django.po new file mode 100644 index 00000000..d9a46953 --- /dev/null +++ b/rest_framework/locale/mk/LC_MESSAGES/django.po @@ -0,0 +1,325 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +#  +# Translators: +# Filip Dimitrovski <filipdimitrovski22@gmail.com>, 2015 +msgid "" +msgstr "" +"Project-Id-Version: Django REST framework\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-30 16:23+0000\n" +"PO-Revision-Date: 2015-01-30 16:27+0000\n" +"Last-Translator: Thomas Christie <tom@tomchristie.com>\n" +"Language-Team: Macedonian (http://www.transifex.com/projects/p/django-rest-framework/language/mk/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: mk\n" +"Plural-Forms: nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;\n" + +#: authentication.py:69 +msgid "Invalid basic header. No credentials provided." +msgstr "Невалиден основен header. Не се внесени податоци за автентикација." + +#: authentication.py:72 +msgid "Invalid basic header. Credentials string should not contain spaces." +msgstr "Невалиден основен header. Автентикационата низа не треба да содржи празни места." + +#: authentication.py:78 +msgid "Invalid basic header. Credentials not correctly base64 encoded." +msgstr "Невалиден основен header. Податоците за автентикација не се енкодирани со base64." + +#: authentication.py:90 +msgid "Invalid username/password." +msgstr "Невалидно корисничко име/лозинка." + +#: authentication.py:156 +msgid "Invalid token header. No credentials provided." +msgstr "Невалиден токен header. Не се внесени податоци за најава." + +#: authentication.py:159 +msgid "Invalid token header. Token string should not contain spaces." +msgstr "Невалиден токен во header. Токенот не треба да содржи празни места." + +#: authentication.py:168 +msgid "Invalid token." +msgstr "Невалиден токен." + +#: authentication.py:171 +msgid "User inactive or deleted." +msgstr "Корисникот е деактивиран или избришан." + +#: exceptions.py:38 +msgid "A server error occurred." +msgstr "Настана серверска грешка." + +#: exceptions.py:73 +msgid "Malformed request." +msgstr "Неправилен request." + +#: 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 "Методата \"{method}\" не е дозволена." + +#: exceptions.py:109 +msgid "Could not satisfy the request Accept header." +msgstr "Не може да се исполни барањето на Accept header-от." + +#: exceptions.py:121 +msgid "Unsupported media type \"{media_type}\" in request." +msgstr "Media типот „{media_type}“ не е поддржан." + +#: exceptions.py:134 +msgid "Request was throttled." +msgstr "Request-от е забранет заради ограничувања." + +#: fields.py:153 relations.py:132 relations.py:156 validators.py:77 +#: validators.py:155 +msgid "This field is required." +msgstr "Ова поле е задолжително." + +#: fields.py:154 +msgid "This field may not be null." +msgstr "Ова поле не смее да биде недефинирано." + +#: fields.py:487 fields.py:515 +msgid "\"{input}\" is not a valid boolean." +msgstr "\"{input}\" не е валиден boolean." + +#: fields.py:550 +msgid "This field may not be blank." +msgstr "Ова поле не смее да биде празно." + +#: fields.py:551 fields.py:1324 +msgid "Ensure this field has no more than {max_length} characters." +msgstr "Ова поле не смее да има повеќе од {max_length} знаци." + +#: fields.py:552 +msgid "Ensure this field has at least {min_length} characters." +msgstr "Ова поле мора да има барем {min_length} знаци." + +#: fields.py:587 +msgid "Enter a valid email address." +msgstr "Внесете валидна email адреса." + +#: 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 "Внесете валиден URL." + +#: fields.py:638 +msgid "\"{value}\" is not a valid UUID." +msgstr "" + +#: fields.py:657 +msgid "A valid integer is required." +msgstr "Задолжителен е валиден цел број." + +#: fields.py:658 fields.py:692 fields.py:725 +msgid "Ensure this value is less than or equal to {max_value}." +msgstr "Вредноста треба да биде помала или еднаква на {max_value}." + +#: fields.py:659 fields.py:693 fields.py:726 +msgid "Ensure this value is greater than or equal to {min_value}." +msgstr "Вредноста треба да биде поголема или еднаква на {min_value}." + +#: fields.py:660 fields.py:694 fields.py:730 +msgid "String value too large." +msgstr "Вредноста е преголема." + +#: fields.py:691 fields.py:724 +msgid "A valid number is required." +msgstr "Задолжителен е валиден број." + +#: fields.py:727 +msgid "Ensure that there are no more than {max_digits} digits in total." +msgstr "Не смее да има повеќе од {max_digits} цифри вкупно." + +#: fields.py:728 +msgid "" +"Ensure that there are no more than {max_decimal_places} decimal places." +msgstr "Не смее да има повеќе од {max_decimal_places} децимални места." + +#: fields.py:729 +msgid "" +"Ensure that there are no more than {max_whole_digits} digits before the " +"decimal point." +msgstr "Не смее да има повеќе од {max_whole_digits} цифри пред децималната точка." + +#: fields.py:813 +msgid "Datetime has wrong format. Use one of these formats instead: {format}." +msgstr "Датата и времето се со погрешен формат. Користете го овој формат: {format}." + +#: fields.py:814 +msgid "Expected a datetime but got a date." +msgstr "Очекувано беше дата и време, а внесено беше само дата." + +#: fields.py:878 +msgid "Date has wrong format. Use one of these formats instead: {format}." +msgstr "Датата е со погрешен формат. Користете го овој формат: {format}." + +#: fields.py:879 +msgid "Expected a date but got a datetime." +msgstr "Очекувана беше дата, а внесени беа и дата и време." + +#: fields.py:936 +msgid "Time has wrong format. Use one of these formats instead: {format}." +msgstr "Времето е со погрешен формат. Користете го овој формат: {format}." + +#: fields.py:992 fields.py:1036 +msgid "\"{input}\" is not a valid choice." +msgstr "„{input}“ не е валиден избор." + +#: fields.py:1037 fields.py:1151 serializers.py:482 +msgid "Expected a list of items but got type \"{input_type}\"." +msgstr "Очекувана беше листа, а внесено беше „{input_type}“." + +#: fields.py:1067 +msgid "No file was submitted." +msgstr "Ниеден фајл не е качен (upload-иран)." + +#: fields.py:1068 +msgid "" +"The submitted data was not a file. Check the encoding type on the form." +msgstr "Испратените податоци не се фајл. Проверете го encoding-от на формата." + +#: fields.py:1069 +msgid "No filename could be determined." +msgstr "Не може да се открие име на фајлот." + +#: fields.py:1070 +msgid "The submitted file is empty." +msgstr "Качениот (upload-иран) фајл е празен." + +#: fields.py:1071 +msgid "" +"Ensure this filename has at most {max_length} characters (it has {length})." +msgstr "Името на фајлот треба да има највеќе {max_length} знаци (а има {length})." + +#: fields.py:1113 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "Качете (upload-ирајте) валидна слика. Фајлот што го качивте не е валидна слика или е расипан." + +#: fields.py:1188 +msgid "Expected a dictionary of items but got type \"{input_type}\"." +msgstr "" + +#: pagination.py:221 +msgid "Invalid page \"{page_number}\": {message}." +msgstr "Невалидна страна „{page_number}“: {message}." + +#: pagination.py:442 +msgid "Invalid cursor" +msgstr "" + +#: relations.py:133 +msgid "Invalid pk \"{pk_value}\" - object does not exist." +msgstr "Невалиден pk „{pk_value}“ - објектот не постои." + +#: relations.py:134 +msgid "Incorrect type. Expected pk value, received {data_type}." +msgstr "Неточен тип. Очекувано беше pk, а внесено {data_type}." + +#: relations.py:157 +msgid "Invalid hyperlink - No URL match." +msgstr "Невалиден хиперлинк - не е внесен URL." + +#: relations.py:158 +msgid "Invalid hyperlink - Incorrect URL match." +msgstr "Невалиден хиперлинк - внесен е неправилен URL." + +#: relations.py:159 +msgid "Invalid hyperlink - Object does not exist." +msgstr "Невалиден хиперлинк - Објектот не постои." + +#: relations.py:160 +msgid "Incorrect type. Expected URL string, received {data_type}." +msgstr "Неточен тип. Очекувано беше URL, a внесено {data_type}." + +#: relations.py:295 +msgid "Object with {slug_name}={value} does not exist." +msgstr "Објектот со {slug_name}={value} не постои." + +#: relations.py:296 +msgid "Invalid value." +msgstr "Невалидна вредност." + +#: serializers.py:299 +msgid "Invalid data. Expected a dictionary, but got {datatype}." +msgstr "Невалидни податоци. Очекуван беше dictionary, а внесен {datatype}." + +#: validators.py:22 +msgid "This field must be unique." +msgstr "Ова поле мора да биде уникатно." + +#: validators.py:76 +msgid "The fields {field_names} must make a unique set." +msgstr "Полињата {field_names} заедно мора да формираат уникатен збир." + +#: validators.py:219 +msgid "This field must be unique for the \"{date_field}\" date." +msgstr "Ова поле мора да биде уникатно за „{date_field}“ датата." + +#: validators.py:234 +msgid "This field must be unique for the \"{date_field}\" month." +msgstr "Ова поле мора да биде уникатно за „{date_field}“ месецот." + +#: validators.py:247 +msgid "This field must be unique for the \"{date_field}\" year." +msgstr "Ова поле мора да биде уникатно за „{date_field}“ годината." + +#: versioning.py:39 +msgid "Invalid version in \"Accept\" header." +msgstr "Невалидна верзија во „Accept“ header-от." + +#: versioning.py:70 versioning.py:112 +msgid "Invalid version in URL path." +msgstr "Невалидна верзија во URL патеката." + +#: versioning.py:138 +msgid "Invalid version in hostname." +msgstr "Невалидна верзија во hostname-от." + +#: versioning.py:160 +msgid "Invalid version in query parameter." +msgstr "Невалидна верзија во query параметарот." + +#: 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 "Мора да се внесе „username“ и „password“." diff --git a/rest_framework/locale/nl/LC_MESSAGES/django.mo b/rest_framework/locale/nl/LC_MESSAGES/django.moBinary files differ new file mode 100644 index 00000000..b0e1ad77 --- /dev/null +++ b/rest_framework/locale/nl/LC_MESSAGES/django.mo diff --git a/rest_framework/locale/nl/LC_MESSAGES/django.po b/rest_framework/locale/nl/LC_MESSAGES/django.po new file mode 100644 index 00000000..a1215512 --- /dev/null +++ b/rest_framework/locale/nl/LC_MESSAGES/django.po @@ -0,0 +1,324 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +#  +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: Django REST framework\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-30 16:23+0000\n" +"PO-Revision-Date: 2015-01-30 16:27+0000\n" +"Last-Translator: Thomas Christie <tom@tomchristie.com>\n" +"Language-Team: Dutch (http://www.transifex.com/projects/p/django-rest-framework/language/nl/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: nl\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\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 "" + +#: 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:153 relations.py:132 relations.py:156 validators.py:77 +#: validators.py:155 +msgid "This field is required." +msgstr "" + +#: fields.py:154 +msgid "This field may not be null." +msgstr "" + +#: fields.py:487 fields.py:515 +msgid "\"{input}\" is not a valid boolean." +msgstr "" + +#: fields.py:550 +msgid "This field may not be blank." +msgstr "" + +#: fields.py:551 fields.py:1324 +msgid "Ensure this field has no more than {max_length} characters." +msgstr "" + +#: fields.py:552 +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:638 +msgid "\"{value}\" is not a valid UUID." +msgstr "" + +#: fields.py:657 +msgid "A valid integer is required." +msgstr "" + +#: fields.py:658 fields.py:692 fields.py:725 +msgid "Ensure this value is less than or equal to {max_value}." +msgstr "" + +#: fields.py:659 fields.py:693 fields.py:726 +msgid "Ensure this value is greater than or equal to {min_value}." +msgstr "" + +#: fields.py:660 fields.py:694 fields.py:730 +msgid "String value too large." +msgstr "" + +#: fields.py:691 fields.py:724 +msgid "A valid number is required." +msgstr "" + +#: fields.py:727 +msgid "Ensure that there are no more than {max_digits} digits in total." +msgstr "" + +#: fields.py:728 +msgid "" +"Ensure that there are no more than {max_decimal_places} decimal places." +msgstr "" + +#: fields.py:729 +msgid "" +"Ensure that there are no more than {max_whole_digits} digits before the " +"decimal point." +msgstr "" + +#: fields.py:813 +msgid "Datetime has wrong format. Use one of these formats instead: {format}." +msgstr "" + +#: fields.py:814 +msgid "Expected a datetime but got a date." +msgstr "" + +#: fields.py:878 +msgid "Date has wrong format. Use one of these formats instead: {format}." +msgstr "" + +#: fields.py:879 +msgid "Expected a date but got a datetime." +msgstr "" + +#: fields.py:936 +msgid "Time has wrong format. Use one of these formats instead: {format}." +msgstr "" + +#: fields.py:992 fields.py:1036 +msgid "\"{input}\" is not a valid choice." +msgstr "" + +#: fields.py:1037 fields.py:1151 serializers.py:482 +msgid "Expected a list of items but got type \"{input_type}\"." +msgstr "" + +#: fields.py:1067 +msgid "No file was submitted." +msgstr "" + +#: fields.py:1068 +msgid "" +"The submitted data was not a file. Check the encoding type on the form." +msgstr "" + +#: fields.py:1069 +msgid "No filename could be determined." +msgstr "" + +#: fields.py:1070 +msgid "The submitted file is empty." +msgstr "" + +#: fields.py:1071 +msgid "" +"Ensure this filename has at most {max_length} characters (it has {length})." +msgstr "" + +#: fields.py:1113 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "" + +#: fields.py:1188 +msgid "Expected a dictionary of items but got type \"{input_type}\"." +msgstr "" + +#: pagination.py:221 +msgid "Invalid page \"{page_number}\": {message}." +msgstr "" + +#: pagination.py:442 +msgid "Invalid cursor" +msgstr "" + +#: relations.py:133 +msgid "Invalid pk \"{pk_value}\" - object does not exist." +msgstr "" + +#: relations.py:134 +msgid "Incorrect type. Expected pk value, received {data_type}." +msgstr "" + +#: relations.py:157 +msgid "Invalid hyperlink - No URL match." +msgstr "" + +#: relations.py:158 +msgid "Invalid hyperlink - Incorrect URL match." +msgstr "" + +#: relations.py:159 +msgid "Invalid hyperlink - Object does not exist." +msgstr "" + +#: relations.py:160 +msgid "Incorrect type. Expected URL string, received {data_type}." +msgstr "" + +#: relations.py:295 +msgid "Object with {slug_name}={value} does not exist." +msgstr "" + +#: relations.py:296 +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 "" + +#: 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 "" diff --git a/rest_framework/locale/pl/LC_MESSAGES/django.mo b/rest_framework/locale/pl/LC_MESSAGES/django.moBinary files differ new file mode 100644 index 00000000..9db72cfb --- /dev/null +++ b/rest_framework/locale/pl/LC_MESSAGES/django.mo diff --git a/rest_framework/locale/pl/LC_MESSAGES/django.po b/rest_framework/locale/pl/LC_MESSAGES/django.po new file mode 100644 index 00000000..8e51d754 --- /dev/null +++ b/rest_framework/locale/pl/LC_MESSAGES/django.po @@ -0,0 +1,326 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +#  +# Translators: +# Janusz Harkot <jh@blueice.pl>, 2015 +# Maciek Olko <maciej.olko@gmail.com>, 2015 +msgid "" +msgstr "" +"Project-Id-Version: Django REST framework\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-30 16:23+0000\n" +"PO-Revision-Date: 2015-01-30 16:27+0000\n" +"Last-Translator: Thomas Christie <tom@tomchristie.com>\n" +"Language-Team: Polish (http://www.transifex.com/projects/p/django-rest-framework/language/pl/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: pl\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" + +#: authentication.py:69 +msgid "Invalid basic header. No credentials provided." +msgstr "Niepoprawny podstawowy nagłówek. Brak danych uwierzytelniających." + +#: authentication.py:72 +msgid "Invalid basic header. Credentials string should not contain spaces." +msgstr "Niepoprawny podstawowy nagłówek. Ciąg znaków danych uwierzytelniających nie powinien zawierać spacji." + +#: authentication.py:78 +msgid "Invalid basic header. Credentials not correctly base64 encoded." +msgstr "Niepoprawny podstawowy nagłówek. Niewłaściwe kodowanie base64 danych uwierzytelniających." + +#: authentication.py:90 +msgid "Invalid username/password." +msgstr "Niepoprawna nazwa użytkownika lub hasło." + +#: authentication.py:156 +msgid "Invalid token header. No credentials provided." +msgstr "Niepoprawny nagłówek tokena. Brak danych uwierzytelniających." + +#: authentication.py:159 +msgid "Invalid token header. Token string should not contain spaces." +msgstr "Niepoprawny nagłówek tokena. Token nie może zawierać odstępów." + +#: authentication.py:168 +msgid "Invalid token." +msgstr "Niepoprawny token." + +#: authentication.py:171 +msgid "User inactive or deleted." +msgstr "Użytkownik nieaktywny lub usunięty." + +#: exceptions.py:38 +msgid "A server error occurred." +msgstr "Wystąpił błąd serwera." + +#: exceptions.py:73 +msgid "Malformed request." +msgstr "Zniekształcone żądanie." + +#: exceptions.py:78 +msgid "Incorrect authentication credentials." +msgstr "Błędne dane uwierzytelniające." + +#: exceptions.py:83 +msgid "Authentication credentials were not provided." +msgstr "Nie podano danych uwierzytelniających." + +#: exceptions.py:88 +msgid "You do not have permission to perform this action." +msgstr "Nie masz uprawnień, by wykonać tę czynność." + +#: exceptions.py:93 +msgid "Not found." +msgstr "Nie znaleziono." + +#: exceptions.py:98 +msgid "Method \"{method}\" not allowed." +msgstr "Niedozwolona metoda \"{method}\"." + +#: exceptions.py:109 +msgid "Could not satisfy the request Accept header." +msgstr "Nie można zaspokoić nagłówka Accept żądania." + +#: exceptions.py:121 +msgid "Unsupported media type \"{media_type}\" in request." +msgstr "Brak wsparcia dla żądanego typu danych \"{media_type}\"." + +#: exceptions.py:134 +msgid "Request was throttled." +msgstr "Żądanie zostało zdławione." + +#: fields.py:153 relations.py:132 relations.py:156 validators.py:77 +#: validators.py:155 +msgid "This field is required." +msgstr "To pole jest wymagane." + +#: fields.py:154 +msgid "This field may not be null." +msgstr "Pole nie może mieć wartości null." + +#: fields.py:487 fields.py:515 +msgid "\"{input}\" is not a valid boolean." +msgstr "\"{input}\" nie jest poprawną wartością logiczną." + +#: fields.py:550 +msgid "This field may not be blank." +msgstr "To pole nie może być puste." + +#: fields.py:551 fields.py:1324 +msgid "Ensure this field has no more than {max_length} characters." +msgstr "Upewnij się, że to pole ma nie więcej niż {max_length} znaków." + +#: fields.py:552 +msgid "Ensure this field has at least {min_length} characters." +msgstr "Upewnij się, że pole ma co najmniej {min_length} znaków." + +#: fields.py:587 +msgid "Enter a valid email address." +msgstr "Podaj poprawny adres e-mail." + +#: fields.py:604 +msgid "This value does not match the required pattern." +msgstr "Ta wartość nie pasuje do wymaganego wzorca." + +#: fields.py:615 +msgid "" +"Enter a valid \"slug\" consisting of letters, numbers, underscores or " +"hyphens." +msgstr "Wprowadź poprawną wartość pola typu \"slug\", składającą się ze znaków łacińskich, cyfr, podkreślenia lub myślnika." + +#: fields.py:627 +msgid "Enter a valid URL." +msgstr "Wprowadź poprawny adres URL." + +#: fields.py:638 +msgid "\"{value}\" is not a valid UUID." +msgstr "" + +#: fields.py:657 +msgid "A valid integer is required." +msgstr "Wymagana poprawna liczba całkowita." + +#: fields.py:658 fields.py:692 fields.py:725 +msgid "Ensure this value is less than or equal to {max_value}." +msgstr "Upewnij się, że ta wartość jest mniejsza lub równa {max_value}." + +#: fields.py:659 fields.py:693 fields.py:726 +msgid "Ensure this value is greater than or equal to {min_value}." +msgstr "Upewnij się, że ta wartość jest większa lub równa {min_value}." + +#: fields.py:660 fields.py:694 fields.py:730 +msgid "String value too large." +msgstr "Za długi ciąg znaków." + +#: fields.py:691 fields.py:724 +msgid "A valid number is required." +msgstr "Wymagana poprawna liczba." + +#: fields.py:727 +msgid "Ensure that there are no more than {max_digits} digits in total." +msgstr "Upewnij się, że liczba ma nie więcej niż {max_digits} cyfr." + +#: fields.py:728 +msgid "" +"Ensure that there are no more than {max_decimal_places} decimal places." +msgstr "Upewnij się, że liczba ma nie więcej niż {max_decimal_places} cyfr dziesiętnych." + +#: fields.py:729 +msgid "" +"Ensure that there are no more than {max_whole_digits} digits before the " +"decimal point." +msgstr "Upewnij się, że liczba ma nie więcej niż {max_whole_digits} cyfr całkowitych." + +#: fields.py:813 +msgid "Datetime has wrong format. Use one of these formats instead: {format}." +msgstr "Wartość daty z czasem ma zły format. Użyj jednego z dostępnych formatów: {format}." + +#: fields.py:814 +msgid "Expected a datetime but got a date." +msgstr "Oczekiwano datę z czasem, otrzymano tylko datę." + +#: fields.py:878 +msgid "Date has wrong format. Use one of these formats instead: {format}." +msgstr "Data ma zły format. Użyj jednego z tych formatów: {format}." + +#: fields.py:879 +msgid "Expected a date but got a datetime." +msgstr "Oczekiwano daty a otrzymano datę z czasem." + +#: fields.py:936 +msgid "Time has wrong format. Use one of these formats instead: {format}." +msgstr "Błędny format czasu. Użyj jednego z dostępnych formatów: {format}" + +#: fields.py:992 fields.py:1036 +msgid "\"{input}\" is not a valid choice." +msgstr "\"{input}\" nie jest poprawnym wyborem." + +#: fields.py:1037 fields.py:1151 serializers.py:482 +msgid "Expected a list of items but got type \"{input_type}\"." +msgstr "Oczekiwano listy elementów, a otrzymano dane typu \"{input_type}\"." + +#: fields.py:1067 +msgid "No file was submitted." +msgstr "Nie przesłano pliku." + +#: fields.py:1068 +msgid "" +"The submitted data was not a file. Check the encoding type on the form." +msgstr "Przesłane dane nie były plikiem. Sprawdź typ kodowania formatki." + +#: fields.py:1069 +msgid "No filename could be determined." +msgstr "Nie można określić nazwy pliku." + +#: fields.py:1070 +msgid "The submitted file is empty." +msgstr "Przesłany plik jest pusty." + +#: fields.py:1071 +msgid "" +"Ensure this filename has at most {max_length} characters (it has {length})." +msgstr "Upewnij się, że nazwa pliku ma długość co najwyżej {max_length} znaków (aktualnie ma {length})." + +#: fields.py:1113 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "Prześlij poprawny plik graficzny. Przesłany plik albo nie jest grafiką lub jest uszkodzony." + +#: fields.py:1188 +msgid "Expected a dictionary of items but got type \"{input_type}\"." +msgstr "" + +#: pagination.py:221 +msgid "Invalid page \"{page_number}\": {message}." +msgstr "Niepoprawna strona \"{page_number}\": {message}." + +#: pagination.py:442 +msgid "Invalid cursor" +msgstr "" + +#: relations.py:133 +msgid "Invalid pk \"{pk_value}\" - object does not exist." +msgstr "Błędny klucz główny \"{pk_value}\" - obiekt nie istnieje." + +#: relations.py:134 +msgid "Incorrect type. Expected pk value, received {data_type}." +msgstr "Błędny typ danych. Oczekiwano wartość klucza głównego, otrzymano {data_type}." + +#: relations.py:157 +msgid "Invalid hyperlink - No URL match." +msgstr "Błędny hyperlink - nie znaleziono pasującego adresu URL." + +#: relations.py:158 +msgid "Invalid hyperlink - Incorrect URL match." +msgstr "Błędny hyperlink - błędne dopasowanie adresu URL." + +#: relations.py:159 +msgid "Invalid hyperlink - Object does not exist." +msgstr "Błędny hyperlink - obiekt nie istnieje." + +#: relations.py:160 +msgid "Incorrect type. Expected URL string, received {data_type}." +msgstr "Błędny typ danych. Oczekiwano adresu URL, otrzymano {data_type}" + +#: relations.py:295 +msgid "Object with {slug_name}={value} does not exist." +msgstr "Obiekt z polem {slug_name}={value} nie istnieje" + +#: relations.py:296 +msgid "Invalid value." +msgstr "Niepoprawna wartość." + +#: serializers.py:299 +msgid "Invalid data. Expected a dictionary, but got {datatype}." +msgstr "Niepoprawne dane. Oczekiwano słownika, otrzymano  {datatype}." + +#: validators.py:22 +msgid "This field must be unique." +msgstr "Wartość dla tego pola musi być unikalna." + +#: validators.py:76 +msgid "The fields {field_names} must make a unique set." +msgstr "Pola {field_names} muszą tworzyć unikalny zestaw." + +#: validators.py:219 +msgid "This field must be unique for the \"{date_field}\" date." +msgstr "To pole musi mieć unikalną wartość dla jednej daty z pola \"{date_field}\"." + +#: validators.py:234 +msgid "This field must be unique for the \"{date_field}\" month." +msgstr "To pole musi mieć unikalną wartość dla konkretnego miesiąca z pola \"{date_field}\"." + +#: validators.py:247 +msgid "This field must be unique for the \"{date_field}\" year." +msgstr "To pole musi mieć unikalną wartość dla konkretnego roku z pola \"{date_field}\"." + +#: versioning.py:39 +msgid "Invalid version in \"Accept\" header." +msgstr "Błędna wersja w nagłówku \"Accept\"." + +#: versioning.py:70 versioning.py:112 +msgid "Invalid version in URL path." +msgstr "Błędna wersja w ścieżce URL." + +#: versioning.py:138 +msgid "Invalid version in hostname." +msgstr "Błędna wersja w nazwie hosta." + +#: versioning.py:160 +msgid "Invalid version in query parameter." +msgstr "Błędna wersja w parametrach zapytania." + +#: authtoken/serializers.py:20 +msgid "User account is disabled." +msgstr "Konto użytkownika jest nieaktywne." + +#: authtoken/serializers.py:23 +msgid "Unable to log in with provided credentials." +msgstr "Podane dane uwierzytelniające nie pozwalają na zalogowanie." + +#: authtoken/serializers.py:26 +msgid "Must include \"username\" and \"password\"." +msgstr "Musi zawierać \"username\" i \"password\"." diff --git a/rest_framework/locale/pt_BR/LC_MESSAGES/django.mo b/rest_framework/locale/pt_BR/LC_MESSAGES/django.moBinary files differ new file mode 100644 index 00000000..49f01929 --- /dev/null +++ b/rest_framework/locale/pt_BR/LC_MESSAGES/django.mo diff --git a/rest_framework/locale/pt_BR/LC_MESSAGES/django.po b/rest_framework/locale/pt_BR/LC_MESSAGES/django.po new file mode 100644 index 00000000..3f272f71 --- /dev/null +++ b/rest_framework/locale/pt_BR/LC_MESSAGES/django.po @@ -0,0 +1,326 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +#  +# Translators: +# Craig Blaszczyk <masterjakul@gmail.com>, 2015 +# Filipe Rinaldi <filipe.rinaldi@gmail.com>, 2015 +msgid "" +msgstr "" +"Project-Id-Version: Django REST framework\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-30 16:23+0000\n" +"PO-Revision-Date: 2015-01-30 16:27+0000\n" +"Last-Translator: Thomas Christie <tom@tomchristie.com>\n" +"Language-Team: Portuguese (Brazil) (http://www.transifex.com/projects/p/django-rest-framework/language/pt_BR/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: pt_BR\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: authentication.py:69 +msgid "Invalid basic header. No credentials provided." +msgstr "Cabeçalho básico inválido. Credenciais não fornecidas." + +#: authentication.py:72 +msgid "Invalid basic header. Credentials string should not contain spaces." +msgstr "Cabeçalho básico inválido. String de credenciais não deve incluir espaços." + +#: authentication.py:78 +msgid "Invalid basic header. Credentials not correctly base64 encoded." +msgstr "Cabeçalho básico inválido. Credenciais codificadas em base64 incorretamente." + +#: authentication.py:90 +msgid "Invalid username/password." +msgstr "Usário ou senha inválido." + +#: authentication.py:156 +msgid "Invalid token header. No credentials provided." +msgstr "Cabeçalho de token inválido. Credenciais não fornecidas." + +#: authentication.py:159 +msgid "Invalid token header. Token string should not contain spaces." +msgstr "Cabeçalho de token inválido. String de token não deve incluir espaços." + +#: authentication.py:168 +msgid "Invalid token." +msgstr "Token inválido." + +#: authentication.py:171 +msgid "User inactive or deleted." +msgstr "Usuário inativo ou removido." + +#: exceptions.py:38 +msgid "A server error occurred." +msgstr "Ocorreu um erro de servidor." + +#: exceptions.py:73 +msgid "Malformed request." +msgstr "Pedido malformado." + +#: exceptions.py:78 +msgid "Incorrect authentication credentials." +msgstr "Credenciais de autenticação incorretas." + +#: exceptions.py:83 +msgid "Authentication credentials were not provided." +msgstr "As credenciais de autenticação não foram fornecidas." + +#: exceptions.py:88 +msgid "You do not have permission to perform this action." +msgstr "Você não tem persmissao para executar essa ação." + +#: exceptions.py:93 +msgid "Not found." +msgstr "Não encontrado." + +#: exceptions.py:98 +msgid "Method \"{method}\" not allowed." +msgstr "Método \"{method}\" não é permitido." + +#: exceptions.py:109 +msgid "Could not satisfy the request Accept header." +msgstr "Não foi possível satisfazer a requisição do cabeçalho Accept." + +#: exceptions.py:121 +msgid "Unsupported media type \"{media_type}\" in request." +msgstr "Media type \"{media_type}\" no pedido não é suportado." + +#: exceptions.py:134 +msgid "Request was throttled." +msgstr "Pedido foi limitado." + +#: fields.py:153 relations.py:132 relations.py:156 validators.py:77 +#: validators.py:155 +msgid "This field is required." +msgstr "Este campo é obrigatório." + +#: fields.py:154 +msgid "This field may not be null." +msgstr "Este campo não pode ser nulo." + +#: fields.py:487 fields.py:515 +msgid "\"{input}\" is not a valid boolean." +msgstr "\"{input}\" não é um valor boleano válido." + +#: fields.py:550 +msgid "This field may not be blank." +msgstr "Este campo não pode ser em branco." + +#: fields.py:551 fields.py:1324 +msgid "Ensure this field has no more than {max_length} characters." +msgstr "Certifique-se de que este campo não tenha mais de {max_length} caracteres." + +#: fields.py:552 +msgid "Ensure this field has at least {min_length} characters." +msgstr "Certifique-se de que este campo tenha mais de {min_length} caracteres." + +#: fields.py:587 +msgid "Enter a valid email address." +msgstr "Insira um endereço de email válido." + +#: fields.py:604 +msgid "This value does not match the required pattern." +msgstr "Este valor não corresponde ao padrão exigido." + +#: fields.py:615 +msgid "" +"Enter a valid \"slug\" consisting of letters, numbers, underscores or " +"hyphens." +msgstr "Entrar um \"slug\" válido que consista de letras, números, sublinhados ou hífens." + +#: fields.py:627 +msgid "Enter a valid URL." +msgstr "Entrar um URL válido." + +#: fields.py:638 +msgid "\"{value}\" is not a valid UUID." +msgstr "" + +#: fields.py:657 +msgid "A valid integer is required." +msgstr "Um número inteiro válido é exigido." + +#: fields.py:658 fields.py:692 fields.py:725 +msgid "Ensure this value is less than or equal to {max_value}." +msgstr "Certifique-se de que este valor seja inferior ou igual a {max_value}." + +#: fields.py:659 fields.py:693 fields.py:726 +msgid "Ensure this value is greater than or equal to {min_value}." +msgstr "Certifque-se de que este valor seja maior ou igual a {min_value}." + +#: fields.py:660 fields.py:694 fields.py:730 +msgid "String value too large." +msgstr "Valor da string é muito grande." + +#: fields.py:691 fields.py:724 +msgid "A valid number is required." +msgstr "Um número válido é necessário." + +#: fields.py:727 +msgid "Ensure that there are no more than {max_digits} digits in total." +msgstr "Certifique-se de que não haja mais de {max_digits} dígitos no total." + +#: fields.py:728 +msgid "" +"Ensure that there are no more than {max_decimal_places} decimal places." +msgstr "Certifique-se de que não haja mais de {max_decimal_places} casas decimais." + +#: fields.py:729 +msgid "" +"Ensure that there are no more than {max_whole_digits} digits before the " +"decimal point." +msgstr "Certifique-se de que não haja mais de {max_whole_digits} dígitos antes do ponto decimal." + +#: fields.py:813 +msgid "Datetime has wrong format. Use one of these formats instead: {format}." +msgstr "Formato inválido para data e hora. Use um dos formatos a seguir: {format}." + +#: fields.py:814 +msgid "Expected a datetime but got a date." +msgstr "Data e hora são necessários mas apenas data foi encontrada." + +#: fields.py:878 +msgid "Date has wrong format. Use one of these formats instead: {format}." +msgstr "Formato inválido para data. Use um dos formatos a seguir: {format}." + +#: fields.py:879 +msgid "Expected a date but got a datetime." +msgstr "Necessário uma data mas recebeu uma data e hora." + +#: fields.py:936 +msgid "Time has wrong format. Use one of these formats instead: {format}." +msgstr "Tempo tem formato errado. Usa um desses em vez disso: {format}." + +#: fields.py:992 fields.py:1036 +msgid "\"{input}\" is not a valid choice." +msgstr "\"{input}\" não é um escolha válido." + +#: fields.py:1037 fields.py:1151 serializers.py:482 +msgid "Expected a list of items but got type \"{input_type}\"." +msgstr "Necessário uma lista de itens, mas recebeu tipo \"{input_type}\"." + +#: fields.py:1067 +msgid "No file was submitted." +msgstr "Ficheiro não foi submetido." + +#: fields.py:1068 +msgid "" +"The submitted data was not a file. Check the encoding type on the form." +msgstr "Os dados submetidos nao foram um ficheiro. Certifique-se do tipo de codificação no formulário." + +#: fields.py:1069 +msgid "No filename could be determined." +msgstr "Nome do arquivo não pode ser determinado." + +#: fields.py:1070 +msgid "The submitted file is empty." +msgstr "O arquivo submetido ésta vázio." + +#: fields.py:1071 +msgid "" +"Ensure this filename has at most {max_length} characters (it has {length})." +msgstr "Certifique-se de que o nome do ficheiro tem menos de {max_length} caracteres (tem {length})." + +#: fields.py:1113 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "Fazer upload de um imagem válido. O arquivo mandou não foi um imagem ou foi corrupto." + +#: fields.py:1188 +msgid "Expected a dictionary of items but got type \"{input_type}\"." +msgstr "" + +#: pagination.py:221 +msgid "Invalid page \"{page_number}\": {message}." +msgstr "Página inválido \"{page_number}\": {message}." + +#: pagination.py:442 +msgid "Invalid cursor" +msgstr "" + +#: relations.py:133 +msgid "Invalid pk \"{pk_value}\" - object does not exist." +msgstr "Pk inválido \"{pk_value}\" - objeto não existe." + +#: relations.py:134 +msgid "Incorrect type. Expected pk value, received {data_type}." +msgstr "Tipo incorreto. Necessário valor pk, recebeu {data_type}." + +#: relations.py:157 +msgid "Invalid hyperlink - No URL match." +msgstr "Hyperlink inválido - URL não combinou." + +#: relations.py:158 +msgid "Invalid hyperlink - Incorrect URL match." +msgstr "Hyperlink inválido - URL combinou errado." + +#: relations.py:159 +msgid "Invalid hyperlink - Object does not exist." +msgstr "Hyperlink inválido - objeto não existe." + +#: relations.py:160 +msgid "Incorrect type. Expected URL string, received {data_type}." +msgstr "Tipo incorreto. Necessário string URL, recebeu {data_type}." + +#: relations.py:295 +msgid "Object with {slug_name}={value} does not exist." +msgstr "Objeto com {slug_name}={value} não existe." + +#: relations.py:296 +msgid "Invalid value." +msgstr "Valor inválido." + +#: serializers.py:299 +msgid "Invalid data. Expected a dictionary, but got {datatype}." +msgstr "Data inválido. Necessário um dicionário mas recebeu {datatype}." + +#: validators.py:22 +msgid "This field must be unique." +msgstr "Esse campo deve ser unico." + +#: validators.py:76 +msgid "The fields {field_names} must make a unique set." +msgstr "Os campos {field_names} devem criar um set unico." + +#: validators.py:219 +msgid "This field must be unique for the \"{date_field}\" date." +msgstr "O campo deve ser unico pela data \"{date_field}\"." + +#: validators.py:234 +msgid "This field must be unique for the \"{date_field}\" month." +msgstr "O campo deve ser unico pelo anô \"{date_field}\"." + +#: validators.py:247 +msgid "This field must be unique for the \"{date_field}\" year." +msgstr "O campo deve ser unico pela mês \"{date_field}\"." + +#: versioning.py:39 +msgid "Invalid version in \"Accept\" header." +msgstr "Versão inválido no cabeçalho \"Accept\"." + +#: versioning.py:70 versioning.py:112 +msgid "Invalid version in URL path." +msgstr "Versão inválido no caminho de URL." + +#: versioning.py:138 +msgid "Invalid version in hostname." +msgstr "Versão inválido no hostname." + +#: versioning.py:160 +msgid "Invalid version in query parameter." +msgstr "Versão inválida no parâmetro de query." + +#: authtoken/serializers.py:20 +msgid "User account is disabled." +msgstr "Conta de usário desabilitada." + +#: authtoken/serializers.py:23 +msgid "Unable to log in with provided credentials." +msgstr "Impossível fazer login com as credenciais fornecidas." + +#: authtoken/serializers.py:26 +msgid "Must include \"username\" and \"password\"." +msgstr "Obrigatório incluir \"usuário\" e \"senha\"." diff --git a/rest_framework/locale/ru/LC_MESSAGES/django.mo b/rest_framework/locale/ru/LC_MESSAGES/django.moBinary files differ new file mode 100644 index 00000000..d1555f1f --- /dev/null +++ b/rest_framework/locale/ru/LC_MESSAGES/django.mo diff --git a/rest_framework/locale/ru/LC_MESSAGES/django.po b/rest_framework/locale/ru/LC_MESSAGES/django.po new file mode 100644 index 00000000..38489747 --- /dev/null +++ b/rest_framework/locale/ru/LC_MESSAGES/django.po @@ -0,0 +1,325 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +#  +# Translators: +# Mikhail Dmitriev <mktums@gmail.com>, 2015 +msgid "" +msgstr "" +"Project-Id-Version: Django REST framework\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-30 16:23+0000\n" +"PO-Revision-Date: 2015-01-30 16:27+0000\n" +"Last-Translator: Thomas Christie <tom@tomchristie.com>\n" +"Language-Team: Russian (http://www.transifex.com/projects/p/django-rest-framework/language/ru/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: ru\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\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 "Недопустимый заголовок. Учетные данные некорректно закодированны в base64." + +#: 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 "Пользователь неактивен или удален." + +#: 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 "Метод \"{method}\" не разрешен." + +#: exceptions.py:109 +msgid "Could not satisfy the request Accept header." +msgstr "Невозможно удовлетворить \"Accept\" заголовок запроса." + +#: exceptions.py:121 +msgid "Unsupported media type \"{media_type}\" in request." +msgstr "Неподдерживаемый тип данных \"{media_type}\" в запросе." + +#: exceptions.py:134 +msgid "Request was throttled." +msgstr "Запрос был проигнорирован." + +#: fields.py:153 relations.py:132 relations.py:156 validators.py:77 +#: validators.py:155 +msgid "This field is required." +msgstr "Это поле обязательно." + +#: fields.py:154 +msgid "This field may not be null." +msgstr "Это поле не может быть null." + +#: fields.py:487 fields.py:515 +msgid "\"{input}\" is not a valid boolean." +msgstr "\"{input}\" не является корректным булевым значением." + +#: fields.py:550 +msgid "This field may not be blank." +msgstr "Это поле не может быть пустым." + +#: fields.py:551 fields.py:1324 +msgid "Ensure this field has no more than {max_length} characters." +msgstr "Убедитесь что в этом поле не больше {max_length} символов." + +#: fields.py:552 +msgid "Ensure this field has at least {min_length} characters." +msgstr "Убедитесь что в этом поле как минимум {min_length} символов." + +#: 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 "Введите корректный \"slug\", состоящий из букв, цифр, знаков подчеркивания или дефисов." + +#: fields.py:627 +msgid "Enter a valid URL." +msgstr "Введите корректный URL." + +#: fields.py:638 +msgid "\"{value}\" is not a valid UUID." +msgstr "" + +#: fields.py:657 +msgid "A valid integer is required." +msgstr "Требуется целочисленное значение." + +#: fields.py:658 fields.py:692 fields.py:725 +msgid "Ensure this value is less than or equal to {max_value}." +msgstr "Убедитесь что значение меньше или равно {max_value}." + +#: fields.py:659 fields.py:693 fields.py:726 +msgid "Ensure this value is greater than or equal to {min_value}." +msgstr "Убедитесь что значение больше или равно {min_value}." + +#: fields.py:660 fields.py:694 fields.py:730 +msgid "String value too large." +msgstr "Слишком длинное значение." + +#: fields.py:691 fields.py:724 +msgid "A valid number is required." +msgstr "Требуется численное значение." + +#: fields.py:727 +msgid "Ensure that there are no more than {max_digits} digits in total." +msgstr "Убедитесь что в числе не больше {max_digits} знаков." + +#: fields.py:728 +msgid "" +"Ensure that there are no more than {max_decimal_places} decimal places." +msgstr "Убедитесь что в числе не больше {max_decimal_places} знаков в дробной части." + +#: fields.py:729 +msgid "" +"Ensure that there are no more than {max_whole_digits} digits before the " +"decimal point." +msgstr "Убедитесь что в цисле не больше {max_whole_digits} знаков в целой части." + +#: fields.py:813 +msgid "Datetime has wrong format. Use one of these formats instead: {format}." +msgstr "Неправильный формат datetime. Используйте один из этих форматов:  {format}." + +#: fields.py:814 +msgid "Expected a datetime but got a date." +msgstr "Ожидался datetime, но был получен date." + +#: fields.py:878 +msgid "Date has wrong format. Use one of these formats instead: {format}." +msgstr "Неправильный формат date. Используйте один из этих форматов: {format}." + +#: fields.py:879 +msgid "Expected a date but got a datetime." +msgstr "Ожидался date, но был получен datetime." + +#: fields.py:936 +msgid "Time has wrong format. Use one of these formats instead: {format}." +msgstr "Неправильный формат времени. Используйте один из этих форматов: {format}." + +#: fields.py:992 fields.py:1036 +msgid "\"{input}\" is not a valid choice." +msgstr "\"{input}\" не является корректным значением." + +#: fields.py:1037 fields.py:1151 serializers.py:482 +msgid "Expected a list of items but got type \"{input_type}\"." +msgstr "Ожидался list со значениями, но был получен \"{input_type}\"." + +#: fields.py:1067 +msgid "No file was submitted." +msgstr "Не был загружен файл." + +#: fields.py:1068 +msgid "" +"The submitted data was not a file. Check the encoding type on the form." +msgstr "Загруженный файл не является корректным файлом. " + +#: fields.py:1069 +msgid "No filename could be determined." +msgstr "Невозможно определить имя файла." + +#: fields.py:1070 +msgid "The submitted file is empty." +msgstr "Загруженный файл пуст." + +#: fields.py:1071 +msgid "" +"Ensure this filename has at most {max_length} characters (it has {length})." +msgstr "Убедитесь что имя файла меньше {max_length} символов (сейчас {length})." + +#: fields.py:1113 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "Загрузите корректное изображение. Загруженный файл не является изображением, либо является испорченным." + +#: fields.py:1188 +msgid "Expected a dictionary of items but got type \"{input_type}\"." +msgstr "" + +#: pagination.py:221 +msgid "Invalid page \"{page_number}\": {message}." +msgstr "Недопустимая страница \"{page_number}\": {message}." + +#: pagination.py:442 +msgid "Invalid cursor" +msgstr "" + +#: relations.py:133 +msgid "Invalid pk \"{pk_value}\" - object does not exist." +msgstr "Недопустимый первичный ключ \"{pk_value}\" - объект не существует." + +#: relations.py:134 +msgid "Incorrect type. Expected pk value, received {data_type}." +msgstr "Некорректный тип. Ожилалось значение первичного ключа, получен {data_type}." + +#: relations.py:157 +msgid "Invalid hyperlink - No URL match." +msgstr "Недопустимая ссылка - нет совпадения по URL." + +#: relations.py:158 +msgid "Invalid hyperlink - Incorrect URL match." +msgstr "Недопустимая ссылка - некорректное совпадение по URL," + +#: relations.py:159 +msgid "Invalid hyperlink - Object does not exist." +msgstr "Недопустимая ссылка - объект не существует." + +#: relations.py:160 +msgid "Incorrect type. Expected URL string, received {data_type}." +msgstr "Некорректный тип. Ожидался URL, получен {data_type}." + +#: relations.py:295 +msgid "Object with {slug_name}={value} does not exist." +msgstr "Объект с {slug_name}={value} не существует." + +#: relations.py:296 +msgid "Invalid value." +msgstr "Недопустимое значение." + +#: serializers.py:299 +msgid "Invalid data. Expected a dictionary, but got {datatype}." +msgstr "Недопустимые данные. Ожидался dictionary, но был получен {datatype}." + +#: 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 "" + +#: 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 "Должен включать \"username\" и \"password\"." diff --git a/rest_framework/locale/sk/LC_MESSAGES/django.mo b/rest_framework/locale/sk/LC_MESSAGES/django.moBinary files differ new file mode 100644 index 00000000..53bb95d8 --- /dev/null +++ b/rest_framework/locale/sk/LC_MESSAGES/django.mo diff --git a/rest_framework/locale/sk/LC_MESSAGES/django.po b/rest_framework/locale/sk/LC_MESSAGES/django.po new file mode 100644 index 00000000..9dd378c0 --- /dev/null +++ b/rest_framework/locale/sk/LC_MESSAGES/django.po @@ -0,0 +1,325 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +#  +# Translators: +# Stanislav Komanec <stano@videoflot.com>, 2015 +msgid "" +msgstr "" +"Project-Id-Version: Django REST framework\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-30 16:23+0000\n" +"PO-Revision-Date: 2015-01-30 16:27+0000\n" +"Last-Translator: Thomas Christie <tom@tomchristie.com>\n" +"Language-Team: Slovak (http://www.transifex.com/projects/p/django-rest-framework/language/sk/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: sk\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" + +#: authentication.py:69 +msgid "Invalid basic header. No credentials provided." +msgstr "Nesprávna hlavička. Neboli poskytnuté prihlasovacie údaje." + +#: authentication.py:72 +msgid "Invalid basic header. Credentials string should not contain spaces." +msgstr "Nesprávna hlavička. Prihlasovacie údaje nesmú obsahovať medzery." + +#: authentication.py:78 +msgid "Invalid basic header. Credentials not correctly base64 encoded." +msgstr "Nesprávna hlavička. Prihlasovacie údaje nie sú správne zakódované pomocou metódy base64." + +#: authentication.py:90 +msgid "Invalid username/password." +msgstr "Nesprávne prihlasovacie údaje." + +#: authentication.py:156 +msgid "Invalid token header. No credentials provided." +msgstr "Nesprávna token hlavička. Neboli poskytnuté prihlasovacie údaje." + +#: authentication.py:159 +msgid "Invalid token header. Token string should not contain spaces." +msgstr "Nesprávna token hlavička. Token hlavička nesmie obsahovať medzery." + +#: authentication.py:168 +msgid "Invalid token." +msgstr "Nesprávny token." + +#: authentication.py:171 +msgid "User inactive or deleted." +msgstr "Daný používateľ je neaktívny, alebo zmazaný." + +#: exceptions.py:38 +msgid "A server error occurred." +msgstr "Vyskytla sa chyba na strane servera." + +#: exceptions.py:73 +msgid "Malformed request." +msgstr "Požiadavok má nesprávny formát, alebo je poškodený." + +#: exceptions.py:78 +msgid "Incorrect authentication credentials." +msgstr "Nesprávne prihlasovacie údaje." + +#: exceptions.py:83 +msgid "Authentication credentials were not provided." +msgstr "Prihlasovacie údaje neboli zadané." + +#: exceptions.py:88 +msgid "You do not have permission to perform this action." +msgstr "K danej akcii nemáte oprávnenie." + +#: exceptions.py:93 +msgid "Not found." +msgstr "Nebolo nájdené." + +#: exceptions.py:98 +msgid "Method \"{method}\" not allowed." +msgstr "Metóda \"{method}\" nie je povolená." + +#: exceptions.py:109 +msgid "Could not satisfy the request Accept header." +msgstr "Nie je možné vyhovieť požiadavku v hlavičke \"Accept\"." + +#: exceptions.py:121 +msgid "Unsupported media type \"{media_type}\" in request." +msgstr "Požiadavok obsahuje nepodporovaný media type: \"{media_type}\"." + +#: exceptions.py:134 +msgid "Request was throttled." +msgstr "" + +#: fields.py:153 relations.py:132 relations.py:156 validators.py:77 +#: validators.py:155 +msgid "This field is required." +msgstr "" + +#: fields.py:154 +msgid "This field may not be null." +msgstr "" + +#: fields.py:487 fields.py:515 +msgid "\"{input}\" is not a valid boolean." +msgstr "" + +#: fields.py:550 +msgid "This field may not be blank." +msgstr "" + +#: fields.py:551 fields.py:1324 +msgid "Ensure this field has no more than {max_length} characters." +msgstr "" + +#: fields.py:552 +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:638 +msgid "\"{value}\" is not a valid UUID." +msgstr "" + +#: fields.py:657 +msgid "A valid integer is required." +msgstr "" + +#: fields.py:658 fields.py:692 fields.py:725 +msgid "Ensure this value is less than or equal to {max_value}." +msgstr "" + +#: fields.py:659 fields.py:693 fields.py:726 +msgid "Ensure this value is greater than or equal to {min_value}." +msgstr "" + +#: fields.py:660 fields.py:694 fields.py:730 +msgid "String value too large." +msgstr "" + +#: fields.py:691 fields.py:724 +msgid "A valid number is required." +msgstr "" + +#: fields.py:727 +msgid "Ensure that there are no more than {max_digits} digits in total." +msgstr "" + +#: fields.py:728 +msgid "" +"Ensure that there are no more than {max_decimal_places} decimal places." +msgstr "" + +#: fields.py:729 +msgid "" +"Ensure that there are no more than {max_whole_digits} digits before the " +"decimal point." +msgstr "" + +#: fields.py:813 +msgid "Datetime has wrong format. Use one of these formats instead: {format}." +msgstr "" + +#: fields.py:814 +msgid "Expected a datetime but got a date." +msgstr "" + +#: fields.py:878 +msgid "Date has wrong format. Use one of these formats instead: {format}." +msgstr "" + +#: fields.py:879 +msgid "Expected a date but got a datetime." +msgstr "" + +#: fields.py:936 +msgid "Time has wrong format. Use one of these formats instead: {format}." +msgstr "" + +#: fields.py:992 fields.py:1036 +msgid "\"{input}\" is not a valid choice." +msgstr "" + +#: fields.py:1037 fields.py:1151 serializers.py:482 +msgid "Expected a list of items but got type \"{input_type}\"." +msgstr "" + +#: fields.py:1067 +msgid "No file was submitted." +msgstr "" + +#: fields.py:1068 +msgid "" +"The submitted data was not a file. Check the encoding type on the form." +msgstr "" + +#: fields.py:1069 +msgid "No filename could be determined." +msgstr "" + +#: fields.py:1070 +msgid "The submitted file is empty." +msgstr "" + +#: fields.py:1071 +msgid "" +"Ensure this filename has at most {max_length} characters (it has {length})." +msgstr "" + +#: fields.py:1113 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "" + +#: fields.py:1188 +msgid "Expected a dictionary of items but got type \"{input_type}\"." +msgstr "" + +#: pagination.py:221 +msgid "Invalid page \"{page_number}\": {message}." +msgstr "" + +#: pagination.py:442 +msgid "Invalid cursor" +msgstr "" + +#: relations.py:133 +msgid "Invalid pk \"{pk_value}\" - object does not exist." +msgstr "" + +#: relations.py:134 +msgid "Incorrect type. Expected pk value, received {data_type}." +msgstr "" + +#: relations.py:157 +msgid "Invalid hyperlink - No URL match." +msgstr "" + +#: relations.py:158 +msgid "Invalid hyperlink - Incorrect URL match." +msgstr "" + +#: relations.py:159 +msgid "Invalid hyperlink - Object does not exist." +msgstr "" + +#: relations.py:160 +msgid "Incorrect type. Expected URL string, received {data_type}." +msgstr "" + +#: relations.py:295 +msgid "Object with {slug_name}={value} does not exist." +msgstr "" + +#: relations.py:296 +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 "" + +#: authtoken/serializers.py:20 +msgid "User account is disabled." +msgstr "Daný používateľ je zablokovaný." + +#: authtoken/serializers.py:23 +msgid "Unable to log in with provided credentials." +msgstr "S danými prihlasovacími údajmi nebolo možné sa prihlásiť." + +#: authtoken/serializers.py:26 +msgid "Must include \"username\" and \"password\"." +msgstr "Musí obsahovať parametre \"používateľské meno\" a \"heslo\"." diff --git a/rest_framework/locale/sv/LC_MESSAGES/django.mo b/rest_framework/locale/sv/LC_MESSAGES/django.moBinary files differ new file mode 100644 index 00000000..a33b0cc5 --- /dev/null +++ b/rest_framework/locale/sv/LC_MESSAGES/django.mo diff --git a/rest_framework/locale/sv/LC_MESSAGES/django.po b/rest_framework/locale/sv/LC_MESSAGES/django.po new file mode 100644 index 00000000..1602bf55 --- /dev/null +++ b/rest_framework/locale/sv/LC_MESSAGES/django.po @@ -0,0 +1,325 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +#  +# Translators: +# Joakim Soderlund, 2015 +msgid "" +msgstr "" +"Project-Id-Version: Django REST framework\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-30 16:23+0000\n" +"PO-Revision-Date: 2015-01-30 16:27+0000\n" +"Last-Translator: Thomas Christie <tom@tomchristie.com>\n" +"Language-Team: Swedish (http://www.transifex.com/projects/p/django-rest-framework/language/sv/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: sv\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: authentication.py:69 +msgid "Invalid basic header. No credentials provided." +msgstr "Ogiltig \"basic\"-header. Inga användaruppgifter tillhandahölls." + +#: authentication.py:72 +msgid "Invalid basic header. Credentials string should not contain spaces." +msgstr "Ogiltig \"basic\"-header. Strängen för användaruppgifterna ska inte innehålla mellanslag." + +#: authentication.py:78 +msgid "Invalid basic header. Credentials not correctly base64 encoded." +msgstr "Ogiltig \"basic\"-header. Användaruppgifterna är inte korrekt base64-kodade." + +#: authentication.py:90 +msgid "Invalid username/password." +msgstr "Ogiltigt användarnamn/lösenord." + +#: authentication.py:156 +msgid "Invalid token header. No credentials provided." +msgstr "Ogiltig \"token\"-header. Inga användaruppgifter tillhandahölls." + +#: authentication.py:159 +msgid "Invalid token header. Token string should not contain spaces." +msgstr "Ogiltig \"token\"-header. Strängen för referensen ska inte innehålla mellanslag." + +#: authentication.py:168 +msgid "Invalid token." +msgstr "Ogiltig \"token\"." + +#: authentication.py:171 +msgid "User inactive or deleted." +msgstr "Användaren borttagen eller inaktiv." + +#: exceptions.py:38 +msgid "A server error occurred." +msgstr "Ett serverfel inträffade." + +#: exceptions.py:73 +msgid "Malformed request." +msgstr "Ogiltig förfrågan." + +#: exceptions.py:78 +msgid "Incorrect authentication credentials." +msgstr "Ogiltiga inloggningsuppgifter. " + +#: exceptions.py:83 +msgid "Authentication credentials were not provided." +msgstr "Autentiseringsuppgifter ej tillhandahållna." + +#: exceptions.py:88 +msgid "You do not have permission to perform this action." +msgstr "Du har inte tillåtelse att utföra denna förfrågan." + +#: exceptions.py:93 +msgid "Not found." +msgstr "Hittades inte." + +#: exceptions.py:98 +msgid "Method \"{method}\" not allowed." +msgstr "Metoden \"{method}\" tillåts inte." + +#: exceptions.py:109 +msgid "Could not satisfy the request Accept header." +msgstr "Kunde inte tillfredsställa förfrågans \"Accept\"-header." + +#: exceptions.py:121 +msgid "Unsupported media type \"{media_type}\" in request." +msgstr "Medietypen \"{media_type}\" stöds inte." + +#: exceptions.py:134 +msgid "Request was throttled." +msgstr "Förfrågan stoppades eftersom du har skickat för många." + +#: fields.py:153 relations.py:132 relations.py:156 validators.py:77 +#: validators.py:155 +msgid "This field is required." +msgstr "Det här fältet är obligatoriskt." + +#: fields.py:154 +msgid "This field may not be null." +msgstr "Det här fältet får inte vara null." + +#: fields.py:487 fields.py:515 +msgid "\"{input}\" is not a valid boolean." +msgstr "\"{input}\" är inte ett giltigt booleskt värde." + +#: fields.py:550 +msgid "This field may not be blank." +msgstr "Det här fältet får inte vara blankt." + +#: fields.py:551 fields.py:1324 +msgid "Ensure this field has no more than {max_length} characters." +msgstr "Se till att detta fält inte har fler än {max_length} tecken." + +#: fields.py:552 +msgid "Ensure this field has at least {min_length} characters." +msgstr "Se till att detta fält har minst {min_length} tecken." + +#: fields.py:587 +msgid "Enter a valid email address." +msgstr "Ange en giltig mejladress." + +#: fields.py:604 +msgid "This value does not match the required pattern." +msgstr "Det här värdet matchar inte mallen." + +#: fields.py:615 +msgid "" +"Enter a valid \"slug\" consisting of letters, numbers, underscores or " +"hyphens." +msgstr "Ange en giltig \"slug\" bestående av bokstäver, nummer, understreck eller bindestreck." + +#: fields.py:627 +msgid "Enter a valid URL." +msgstr "Ange en giltig URL." + +#: fields.py:638 +msgid "\"{value}\" is not a valid UUID." +msgstr "" + +#: fields.py:657 +msgid "A valid integer is required." +msgstr "Ett giltigt heltal krävs." + +#: fields.py:658 fields.py:692 fields.py:725 +msgid "Ensure this value is less than or equal to {max_value}." +msgstr "Se till att detta värde är mindre än eller lika med {max_value}." + +#: fields.py:659 fields.py:693 fields.py:726 +msgid "Ensure this value is greater than or equal to {min_value}." +msgstr "Se till att detta värde är större än eller lika med {min_value}." + +#: fields.py:660 fields.py:694 fields.py:730 +msgid "String value too large." +msgstr "Textvärdet är för långt." + +#: fields.py:691 fields.py:724 +msgid "A valid number is required." +msgstr "Ett giltigt nummer krävs." + +#: fields.py:727 +msgid "Ensure that there are no more than {max_digits} digits in total." +msgstr "Se till att det inte finns fler än totalt {max_digits} siffror." + +#: fields.py:728 +msgid "" +"Ensure that there are no more than {max_decimal_places} decimal places." +msgstr "Se till att det inte finns fler än {max_decimal_places} decimaler." + +#: fields.py:729 +msgid "" +"Ensure that there are no more than {max_whole_digits} digits before the " +"decimal point." +msgstr "Se till att det inte finns fler än {max_whole_digits} siffror före decimalpunkten." + +#: fields.py:813 +msgid "Datetime has wrong format. Use one of these formats instead: {format}." +msgstr "Datumtiden har fel format. Använd ett av dessa format istället: {format}." + +#: fields.py:814 +msgid "Expected a datetime but got a date." +msgstr "Förväntade en datumtid men fick ett datum." + +#: fields.py:878 +msgid "Date has wrong format. Use one of these formats instead: {format}." +msgstr "Datumet har fel format. Använde ett av dessa format istället: {format}." + +#: fields.py:879 +msgid "Expected a date but got a datetime." +msgstr "Förväntade ett datum men fick en datumtid." + +#: fields.py:936 +msgid "Time has wrong format. Use one of these formats instead: {format}." +msgstr "Tiden har fel format. Använd ett av dessa format istället: {format}." + +#: fields.py:992 fields.py:1036 +msgid "\"{input}\" is not a valid choice." +msgstr "\"{input}\" är inte ett giltigt val." + +#: fields.py:1037 fields.py:1151 serializers.py:482 +msgid "Expected a list of items but got type \"{input_type}\"." +msgstr "Förväntade en lista med element men fick typen \"{input_type}\"." + +#: fields.py:1067 +msgid "No file was submitted." +msgstr "Ingen fil skickades." + +#: fields.py:1068 +msgid "" +"The submitted data was not a file. Check the encoding type on the form." +msgstr "Den skickade informationen var inte en fil. Kontrollera formulärets kodningstyp." + +#: fields.py:1069 +msgid "No filename could be determined." +msgstr "Inget filnamn kunde bestämmas." + +#: fields.py:1070 +msgid "The submitted file is empty." +msgstr "Den skickade filen var tom." + +#: fields.py:1071 +msgid "" +"Ensure this filename has at most {max_length} characters (it has {length})." +msgstr "Se till att det här filnamnet har högst {max_length} tecken (det har {length})." + +#: fields.py:1113 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "Ladda upp en giltig bild. Filen du laddade upp var antingen inte en bild eller en skadad bild." + +#: fields.py:1188 +msgid "Expected a dictionary of items but got type \"{input_type}\"." +msgstr "" + +#: pagination.py:221 +msgid "Invalid page \"{page_number}\": {message}." +msgstr "Ogiltigt sida \"{page_number}\": {message}." + +#: pagination.py:442 +msgid "Invalid cursor" +msgstr "" + +#: relations.py:133 +msgid "Invalid pk \"{pk_value}\" - object does not exist." +msgstr "Ogiltigt pk \"{pk_value}\" - Objektet finns inte." + +#: relations.py:134 +msgid "Incorrect type. Expected pk value, received {data_type}." +msgstr "Felaktig typ. Förväntade pk-värde, fick {data_type}." + +#: relations.py:157 +msgid "Invalid hyperlink - No URL match." +msgstr "Ogiltig hyperlänk - Ingen URL matchade." + +#: relations.py:158 +msgid "Invalid hyperlink - Incorrect URL match." +msgstr "Ogiltig hyperlänk - Felaktig URL-matching." + +#: relations.py:159 +msgid "Invalid hyperlink - Object does not exist." +msgstr "Ogiltig hyperlänk - Objektet finns inte." + +#: relations.py:160 +msgid "Incorrect type. Expected URL string, received {data_type}." +msgstr "Felaktig typ. Förväntade URL-sträng, fick {data_type}." + +#: relations.py:295 +msgid "Object with {slug_name}={value} does not exist." +msgstr "Objekt med {slug_name}={value} finns inte." + +#: relations.py:296 +msgid "Invalid value." +msgstr "Ogiltigt värde." + +#: serializers.py:299 +msgid "Invalid data. Expected a dictionary, but got {datatype}." +msgstr "Ogiltig data. Förväntade en dictionary, men fick {datatype}." + +#: validators.py:22 +msgid "This field must be unique." +msgstr "Det här fältet måste vara unikt." + +#: validators.py:76 +msgid "The fields {field_names} must make a unique set." +msgstr "Fälten {field_names} måste skapa ett unikt set." + +#: validators.py:219 +msgid "This field must be unique for the \"{date_field}\" date." +msgstr "Det här fältet måste vara unikt för datumet \"{date_field}\"." + +#: validators.py:234 +msgid "This field must be unique for the \"{date_field}\" month." +msgstr "Det här fältet måste vara unikt för månaden \"{date_field}\"." + +#: validators.py:247 +msgid "This field must be unique for the \"{date_field}\" year." +msgstr "Det här fältet måste vara unikt för året \"{date_field}\"." + +#: versioning.py:39 +msgid "Invalid version in \"Accept\" header." +msgstr "Ogiltig version i \"Accept\"-headern." + +#: versioning.py:70 versioning.py:112 +msgid "Invalid version in URL path." +msgstr "Ogiltig version i URL-resursen." + +#: versioning.py:138 +msgid "Invalid version in hostname." +msgstr "Ogiltig version i värdnamnet." + +#: versioning.py:160 +msgid "Invalid version in query parameter." +msgstr "Ogiltig version i förfrågningsparametern." + +#: authtoken/serializers.py:20 +msgid "User account is disabled." +msgstr "Användarkontot är borttaget." + +#: authtoken/serializers.py:23 +msgid "Unable to log in with provided credentials." +msgstr "Kunde inte logga in med de angivna inloggningsuppgifterna." + +#: authtoken/serializers.py:26 +msgid "Must include \"username\" and \"password\"." +msgstr "Användarnamn och lösenord måste anges." diff --git a/rest_framework/locale/tr/LC_MESSAGES/django.mo b/rest_framework/locale/tr/LC_MESSAGES/django.moBinary files differ new file mode 100644 index 00000000..e6b848cf --- /dev/null +++ b/rest_framework/locale/tr/LC_MESSAGES/django.mo diff --git a/rest_framework/locale/tr/LC_MESSAGES/django.po b/rest_framework/locale/tr/LC_MESSAGES/django.po new file mode 100644 index 00000000..5aabbeba --- /dev/null +++ b/rest_framework/locale/tr/LC_MESSAGES/django.po @@ -0,0 +1,328 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +#  +# Translators: +# Ertaç Paprat <epaprat@gmail.com>, 2015 +# Mesut Can Gürle <mesutcang@gmail.com>, 2015 +# Recep KIRMIZI <rkirmizi@gmail.com>, 2015 +# Ülgen Sarıkavak <ulgensrkvk@gmail.com>, 2015 +msgid "" +msgstr "" +"Project-Id-Version: Django REST framework\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-30 16:23+0000\n" +"PO-Revision-Date: 2015-01-30 16:27+0000\n" +"Last-Translator: Thomas Christie <tom@tomchristie.com>\n" +"Language-Team: Turkish (http://www.transifex.com/projects/p/django-rest-framework/language/tr/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: tr\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\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 "Geçersiz kullanıcı adı/parola" + +#: authentication.py:156 +msgid "Invalid token header. No credentials provided." +msgstr "Geçersiz token başlığı. Kimlik bilgileri eksik." + +#: authentication.py:159 +msgid "Invalid token header. Token string should not contain spaces." +msgstr "Geçersiz token başlığı. Token'da boşluk olmamalı." + +#: authentication.py:168 +msgid "Invalid token." +msgstr "Geçersiz token." + +#: authentication.py:171 +msgid "User inactive or deleted." +msgstr "Kullanıcı aktif değil ya da silinmiş." + +#: exceptions.py:38 +msgid "A server error occurred." +msgstr "Sunucu hatası oluştu." + +#: exceptions.py:73 +msgid "Malformed request." +msgstr "Bozuk istek." + +#: exceptions.py:78 +msgid "Incorrect authentication credentials." +msgstr "Giriş bilgileri hatalı." + +#: exceptions.py:83 +msgid "Authentication credentials were not provided." +msgstr "Giriş bilgileri verilmedi." + +#: exceptions.py:88 +msgid "You do not have permission to perform this action." +msgstr "Bu işlemi yapmak için izniniz bulunmuyor." + +#: exceptions.py:93 +msgid "Not found." +msgstr "Bulunamadı." + +#: exceptions.py:98 +msgid "Method \"{method}\" not allowed." +msgstr "\"{method}\" metoduna izin verilmiyor." + +#: exceptions.py:109 +msgid "Could not satisfy the request Accept header." +msgstr "" + +#: exceptions.py:121 +msgid "Unsupported media type \"{media_type}\" in request." +msgstr "İstekte desteklenmeyen medya tipi: \"{media_type}\"." + +#: exceptions.py:134 +msgid "Request was throttled." +msgstr "" + +#: fields.py:153 relations.py:132 relations.py:156 validators.py:77 +#: validators.py:155 +msgid "This field is required." +msgstr "Bu alan zorunlu." + +#: fields.py:154 +msgid "This field may not be null." +msgstr "Bu alan boş bırakılmamalı." + +#: fields.py:487 fields.py:515 +msgid "\"{input}\" is not a valid boolean." +msgstr "\"{input}\" geçerli bir boolean değil." + +#: fields.py:550 +msgid "This field may not be blank." +msgstr "Bu alan boş bırakılmamalı." + +#: fields.py:551 fields.py:1324 +msgid "Ensure this field has no more than {max_length} characters." +msgstr "Bu alanın {max_length} karakterden fazla karakter barındırmadığından emin olun." + +#: fields.py:552 +msgid "Ensure this field has at least {min_length} characters." +msgstr "Bu alanın en az {min_length} karakter barındırdığından emin olun." + +#: fields.py:587 +msgid "Enter a valid email address." +msgstr "Geçerli bir e-posta adresi girin." + +#: fields.py:604 +msgid "This value does not match the required pattern." +msgstr "Bu değer gereken düzenli ifade deseni ile uyuşmuyor." + +#: fields.py:615 +msgid "" +"Enter a valid \"slug\" consisting of letters, numbers, underscores or " +"hyphens." +msgstr "Harf, rakam, altçizgi veya tireden oluşan geçerli bir \"slug\" giriniz." + +#: fields.py:627 +msgid "Enter a valid URL." +msgstr "Geçerli bir URL girin." + +#: fields.py:638 +msgid "\"{value}\" is not a valid UUID." +msgstr "" + +#: fields.py:657 +msgid "A valid integer is required." +msgstr "Geçerli bir tam sayı girin." + +#: fields.py:658 fields.py:692 fields.py:725 +msgid "Ensure this value is less than or equal to {max_value}." +msgstr "Değerin {max_value} değerinden küçük ya da eşit olduğundan emin olun." + +#: fields.py:659 fields.py:693 fields.py:726 +msgid "Ensure this value is greater than or equal to {min_value}." +msgstr "Değerin {min_value} değerinden büyük ya da eşit olduğundan emin olun." + +#: fields.py:660 fields.py:694 fields.py:730 +msgid "String value too large." +msgstr "String değeri çok uzun." + +#: fields.py:691 fields.py:724 +msgid "A valid number is required." +msgstr "Geçerli bir numara gerekiyor." + +#: fields.py:727 +msgid "Ensure that there are no more than {max_digits} digits in total." +msgstr "Toplamda {max_digits} haneden fazla hane olmadığından emin olun." + +#: fields.py:728 +msgid "" +"Ensure that there are no more than {max_decimal_places} decimal places." +msgstr "Ondalık basamak değerinin {max_decimal_places} haneden fazla olmadığından emin olun." + +#: fields.py:729 +msgid "" +"Ensure that there are no more than {max_whole_digits} digits before the " +"decimal point." +msgstr "Ondalık ayracından önce {max_whole_digits} basamaktan fazla olmadığından emin olun." + +#: fields.py:813 +msgid "Datetime has wrong format. Use one of these formats instead: {format}." +msgstr "Datetime alanı yanlış biçimde. {format} biçimlerinden birini kullanın." + +#: fields.py:814 +msgid "Expected a datetime but got a date." +msgstr "Datetime değeri bekleniyor, ama date değeri geldi." + +#: fields.py:878 +msgid "Date has wrong format. Use one of these formats instead: {format}." +msgstr "Tarih biçimi yanlış. {format} biçimlerinden birini kullanın." + +#: fields.py:879 +msgid "Expected a date but got a datetime." +msgstr "Date tipi beklenmekteydi, fakat datetime tipi geldi." + +#: fields.py:936 +msgid "Time has wrong format. Use one of these formats instead: {format}." +msgstr "Time biçimi yanlış. {format} biçimlerinden birini kullanın." + +#: fields.py:992 fields.py:1036 +msgid "\"{input}\" is not a valid choice." +msgstr "\"{input}\" geçerli bir seçim değil." + +#: fields.py:1037 fields.py:1151 serializers.py:482 +msgid "Expected a list of items but got type \"{input_type}\"." +msgstr "Elemanların listesi beklenirken \"{input_type}\" alındı." + +#: fields.py:1067 +msgid "No file was submitted." +msgstr "Hiçbir dosya verilmedi." + +#: fields.py:1068 +msgid "" +"The submitted data was not a file. Check the encoding type on the form." +msgstr "Gönderilen veri dosya değil. Formdaki kodlama tipini kontrol edin." + +#: fields.py:1069 +msgid "No filename could be determined." +msgstr "Hiçbir dosya adı belirlenemedi." + +#: fields.py:1070 +msgid "The submitted file is empty." +msgstr "Gönderilen dosya boş." + +#: fields.py:1071 +msgid "" +"Ensure this filename has at most {max_length} characters (it has {length})." +msgstr "Bu dosya adının en fazla {max_length} karakter uzunluğunda olduğundan emin olun. (şu anda {length} karakter)." + +#: fields.py:1113 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "Geçerli bir resim yükleyin. Yüklediğiniz dosya resim değil ya da bozuk." + +#: fields.py:1188 +msgid "Expected a dictionary of items but got type \"{input_type}\"." +msgstr "" + +#: pagination.py:221 +msgid "Invalid page \"{page_number}\": {message}." +msgstr "Geçersiz sayfa \"{page_number}\":{message}." + +#: pagination.py:442 +msgid "Invalid cursor" +msgstr "" + +#: relations.py:133 +msgid "Invalid pk \"{pk_value}\" - object does not exist." +msgstr "Geçersiz pk \"{pk_value}\" - obje bulunamadı." + +#: relations.py:134 +msgid "Incorrect type. Expected pk value, received {data_type}." +msgstr "Hatalı tip. Pk değeri beklenirken, alınan {data_type}." + +#: relations.py:157 +msgid "Invalid hyperlink - No URL match." +msgstr "Geçersiz bağlantı - Hiçbir URL eşleşmedi." + +#: relations.py:158 +msgid "Invalid hyperlink - Incorrect URL match." +msgstr "Geçersiz bağlantı - Yanlış URL eşleşmesi." + +#: relations.py:159 +msgid "Invalid hyperlink - Object does not exist." +msgstr "Geçersiz bağlantı - Obje bulunamadı." + +#: relations.py:160 +msgid "Incorrect type. Expected URL string, received {data_type}." +msgstr "Hatalı tip. URL metni bekleniyor, {data_type} alındı." + +#: relations.py:295 +msgid "Object with {slug_name}={value} does not exist." +msgstr "{slug_name}={value} değerini taşıyan obje bulunamadı." + +#: relations.py:296 +msgid "Invalid value." +msgstr "Geçersiz değer." + +#: serializers.py:299 +msgid "Invalid data. Expected a dictionary, but got {datatype}." +msgstr "Geçersiz veri. Sözlük bekleniyordu fakat {datatype} geldi. " + +#: validators.py:22 +msgid "This field must be unique." +msgstr "Bu alan eşsiz olmalı." + +#: validators.py:76 +msgid "The fields {field_names} must make a unique set." +msgstr "{field_names} hep birlikte eşsiz bir küme oluşturmalılar." + +#: validators.py:219 +msgid "This field must be unique for the \"{date_field}\" date." +msgstr "Bu alan \"{date_field}\" tarihine göre eşsiz olmalı." + +#: validators.py:234 +msgid "This field must be unique for the \"{date_field}\" month." +msgstr "Bu alan \"{date_field}\" ayına göre eşsiz olmalı." + +#: validators.py:247 +msgid "This field must be unique for the \"{date_field}\" year." +msgstr "Bu alan \"{date_field}\" yılına göre eşsiz olmalı." + +#: versioning.py:39 +msgid "Invalid version in \"Accept\" header." +msgstr "\"Accept\" başlığındaki sürüm geçersiz." + +#: versioning.py:70 versioning.py:112 +msgid "Invalid version in URL path." +msgstr "URL dizininde geçersiz versiyon." + +#: versioning.py:138 +msgid "Invalid version in hostname." +msgstr "Host adında geçersiz versiyon." + +#: versioning.py:160 +msgid "Invalid version in query parameter." +msgstr "Sorgu parametresinde geçersiz versiyon." + +#: authtoken/serializers.py:20 +msgid "User account is disabled." +msgstr "Kullanıcı hesabı devre dışı bırakılmış." + +#: authtoken/serializers.py:23 +msgid "Unable to log in with provided credentials." +msgstr "Verilen bilgiler ile giriş sağlanamadı." + +#: authtoken/serializers.py:26 +msgid "Must include \"username\" and \"password\"." +msgstr "\"Kullanıcı Adı\" ve \"Parola\" eklenmeli." diff --git a/rest_framework/locale/uk/LC_MESSAGES/django.mo b/rest_framework/locale/uk/LC_MESSAGES/django.moBinary files differ new file mode 100644 index 00000000..fc335054 --- /dev/null +++ b/rest_framework/locale/uk/LC_MESSAGES/django.mo diff --git a/rest_framework/locale/uk/LC_MESSAGES/django.po b/rest_framework/locale/uk/LC_MESSAGES/django.po new file mode 100644 index 00000000..93fc2bf9 --- /dev/null +++ b/rest_framework/locale/uk/LC_MESSAGES/django.po @@ -0,0 +1,324 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +#  +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: Django REST framework\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-30 16:23+0000\n" +"PO-Revision-Date: 2015-01-30 16:27+0000\n" +"Last-Translator: Thomas Christie <tom@tomchristie.com>\n" +"Language-Team: Ukrainian (http://www.transifex.com/projects/p/django-rest-framework/language/uk/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: uk\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\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 "" + +#: 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:153 relations.py:132 relations.py:156 validators.py:77 +#: validators.py:155 +msgid "This field is required." +msgstr "" + +#: fields.py:154 +msgid "This field may not be null." +msgstr "" + +#: fields.py:487 fields.py:515 +msgid "\"{input}\" is not a valid boolean." +msgstr "" + +#: fields.py:550 +msgid "This field may not be blank." +msgstr "" + +#: fields.py:551 fields.py:1324 +msgid "Ensure this field has no more than {max_length} characters." +msgstr "" + +#: fields.py:552 +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:638 +msgid "\"{value}\" is not a valid UUID." +msgstr "" + +#: fields.py:657 +msgid "A valid integer is required." +msgstr "" + +#: fields.py:658 fields.py:692 fields.py:725 +msgid "Ensure this value is less than or equal to {max_value}." +msgstr "" + +#: fields.py:659 fields.py:693 fields.py:726 +msgid "Ensure this value is greater than or equal to {min_value}." +msgstr "" + +#: fields.py:660 fields.py:694 fields.py:730 +msgid "String value too large." +msgstr "" + +#: fields.py:691 fields.py:724 +msgid "A valid number is required." +msgstr "" + +#: fields.py:727 +msgid "Ensure that there are no more than {max_digits} digits in total." +msgstr "" + +#: fields.py:728 +msgid "" +"Ensure that there are no more than {max_decimal_places} decimal places." +msgstr "" + +#: fields.py:729 +msgid "" +"Ensure that there are no more than {max_whole_digits} digits before the " +"decimal point." +msgstr "" + +#: fields.py:813 +msgid "Datetime has wrong format. Use one of these formats instead: {format}." +msgstr "" + +#: fields.py:814 +msgid "Expected a datetime but got a date." +msgstr "" + +#: fields.py:878 +msgid "Date has wrong format. Use one of these formats instead: {format}." +msgstr "" + +#: fields.py:879 +msgid "Expected a date but got a datetime." +msgstr "" + +#: fields.py:936 +msgid "Time has wrong format. Use one of these formats instead: {format}." +msgstr "" + +#: fields.py:992 fields.py:1036 +msgid "\"{input}\" is not a valid choice." +msgstr "" + +#: fields.py:1037 fields.py:1151 serializers.py:482 +msgid "Expected a list of items but got type \"{input_type}\"." +msgstr "" + +#: fields.py:1067 +msgid "No file was submitted." +msgstr "" + +#: fields.py:1068 +msgid "" +"The submitted data was not a file. Check the encoding type on the form." +msgstr "" + +#: fields.py:1069 +msgid "No filename could be determined." +msgstr "" + +#: fields.py:1070 +msgid "The submitted file is empty." +msgstr "" + +#: fields.py:1071 +msgid "" +"Ensure this filename has at most {max_length} characters (it has {length})." +msgstr "" + +#: fields.py:1113 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "" + +#: fields.py:1188 +msgid "Expected a dictionary of items but got type \"{input_type}\"." +msgstr "" + +#: pagination.py:221 +msgid "Invalid page \"{page_number}\": {message}." +msgstr "" + +#: pagination.py:442 +msgid "Invalid cursor" +msgstr "" + +#: relations.py:133 +msgid "Invalid pk \"{pk_value}\" - object does not exist." +msgstr "" + +#: relations.py:134 +msgid "Incorrect type. Expected pk value, received {data_type}." +msgstr "" + +#: relations.py:157 +msgid "Invalid hyperlink - No URL match." +msgstr "" + +#: relations.py:158 +msgid "Invalid hyperlink - Incorrect URL match." +msgstr "" + +#: relations.py:159 +msgid "Invalid hyperlink - Object does not exist." +msgstr "" + +#: relations.py:160 +msgid "Incorrect type. Expected URL string, received {data_type}." +msgstr "" + +#: relations.py:295 +msgid "Object with {slug_name}={value} does not exist." +msgstr "" + +#: relations.py:296 +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 "" + +#: 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 "" diff --git a/rest_framework/locale/zh_CN/LC_MESSAGES/django.mo b/rest_framework/locale/zh_CN/LC_MESSAGES/django.moBinary files differ new file mode 100644 index 00000000..6e7073bd --- /dev/null +++ b/rest_framework/locale/zh_CN/LC_MESSAGES/django.mo diff --git a/rest_framework/locale/zh_CN/LC_MESSAGES/django.po b/rest_framework/locale/zh_CN/LC_MESSAGES/django.po new file mode 100644 index 00000000..01128859 --- /dev/null +++ b/rest_framework/locale/zh_CN/LC_MESSAGES/django.po @@ -0,0 +1,325 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +#  +# Translators: +# Lele Long <schemacs@gmail.com>, 2015 +msgid "" +msgstr "" +"Project-Id-Version: Django REST framework\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-30 16:23+0000\n" +"PO-Revision-Date: 2015-01-30 16:27+0000\n" +"Last-Translator: Thomas Christie <tom@tomchristie.com>\n" +"Language-Team: Chinese (China) (http://www.transifex.com/projects/p/django-rest-framework/language/zh_CN/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: zh_CN\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: authentication.py:69 +msgid "Invalid basic header. No credentials provided." +msgstr "没有提供认证信息(基本认证HTTP头无效)。" + +#: authentication.py:72 +msgid "Invalid basic header. Credentials string should not contain spaces." +msgstr "认证字符串不应该包含空格(基本认证HTTP头无效)。" + +#: authentication.py:78 +msgid "Invalid basic header. Credentials not correctly base64 encoded." +msgstr "认证字符串base64编码错误(基本认证HTTP头无效)。" + +#: authentication.py:90 +msgid "Invalid username/password." +msgstr "用户名或者密码错误。" + +#: authentication.py:156 +msgid "Invalid token header. No credentials provided." +msgstr "没有提供认证信息(认证令牌HTTP头无效)。" + +#: authentication.py:159 +msgid "Invalid token header. Token string should not contain spaces." +msgstr "认证令牌字符串不应该包含空格(无效的认证令牌HTTP头)。" + +#: authentication.py:168 +msgid "Invalid token." +msgstr "认证令牌无效。" + +#: authentication.py:171 +msgid "User inactive or deleted." +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 "方法 “{method}” 不被允许。" + +#: exceptions.py:109 +msgid "Could not satisfy the request Accept header." +msgstr "无法满足Accept HTTP头的请求。" + +#: exceptions.py:121 +msgid "Unsupported media type \"{media_type}\" in request." +msgstr "不支持请求中的媒体类型 “{media_type}”。" + +#: exceptions.py:134 +msgid "Request was throttled." +msgstr "请求被限速。" + +#: fields.py:153 relations.py:132 relations.py:156 validators.py:77 +#: validators.py:155 +msgid "This field is required." +msgstr "这个字段是必填项。" + +#: fields.py:154 +msgid "This field may not be null." +msgstr "这个值不能为 null。" + +#: fields.py:487 fields.py:515 +msgid "\"{input}\" is not a valid boolean." +msgstr "“{input}” 不是合法的布尔值。" + +#: fields.py:550 +msgid "This field may not be blank." +msgstr "此字段不能为空。" + +#: fields.py:551 fields.py:1324 +msgid "Ensure this field has no more than {max_length} characters." +msgstr "请确保这个字段不能超过 {max_length} 个字符。" + +#: fields.py:552 +msgid "Ensure this field has at least {min_length} characters." +msgstr "请确保这个字段至少包含 {min_length} 个字符。" + +#: 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 "请输入合法的URL。" + +#: fields.py:638 +msgid "\"{value}\" is not a valid UUID." +msgstr "" + +#: fields.py:657 +msgid "A valid integer is required." +msgstr "请填写合法的整数值。" + +#: fields.py:658 fields.py:692 fields.py:725 +msgid "Ensure this value is less than or equal to {max_value}." +msgstr "请确保该值小于或者等于 {max_value}。" + +#: fields.py:659 fields.py:693 fields.py:726 +msgid "Ensure this value is greater than or equal to {min_value}." +msgstr "请确保该值大于或者等于 {min_value}。" + +#: fields.py:660 fields.py:694 fields.py:730 +msgid "String value too large." +msgstr "字符值太长。" + +#: fields.py:691 fields.py:724 +msgid "A valid number is required." +msgstr "请填写合法的数字。" + +#: fields.py:727 +msgid "Ensure that there are no more than {max_digits} digits in total." +msgstr "请确保总计不超过 {max_digits} 个数字。" + +#: fields.py:728 +msgid "" +"Ensure that there are no more than {max_decimal_places} decimal places." +msgstr "请确保总计不超过 {max_decimal_places} 个小数位。" + +#: fields.py:729 +msgid "" +"Ensure that there are no more than {max_whole_digits} digits before the " +"decimal point." +msgstr "请确保小数点前不超过 {max_whole_digits} 个数字。" + +#: fields.py:813 +msgid "Datetime has wrong format. Use one of these formats instead: {format}." +msgstr "日期时间格式错误。请从这些格式中选择:{format}。" + +#: fields.py:814 +msgid "Expected a datetime but got a date." +msgstr "期望为日期时间,得到的是日期。" + +#: fields.py:878 +msgid "Date has wrong format. Use one of these formats instead: {format}." +msgstr "日期格式错误。请从这些格式中选择:{format}。" + +#: fields.py:879 +msgid "Expected a date but got a datetime." +msgstr "期望为日期,得到的是日期时间。" + +#: fields.py:936 +msgid "Time has wrong format. Use one of these formats instead: {format}." +msgstr "时间格式错误。请从这些格式中选择:{format}。" + +#: fields.py:992 fields.py:1036 +msgid "\"{input}\" is not a valid choice." +msgstr "“{input}” 不是合法选项。" + +#: fields.py:1037 fields.py:1151 serializers.py:482 +msgid "Expected a list of items but got type \"{input_type}\"." +msgstr "期望为一个包含物件的列表,得到的类型是“{input_type}”。" + +#: fields.py:1067 +msgid "No file was submitted." +msgstr "没有提交任何文件。" + +#: fields.py:1068 +msgid "" +"The submitted data was not a file. Check the encoding type on the form." +msgstr "提交的数据不是一个文件。请检查表单的编码类型。" + +#: fields.py:1069 +msgid "No filename could be determined." +msgstr "无法检测到文件名。" + +#: fields.py:1070 +msgid "The submitted file is empty." +msgstr "提交的是空文件。" + +#: fields.py:1071 +msgid "" +"Ensure this filename has at most {max_length} characters (it has {length})." +msgstr "确保该文件名最多包含 {max_length} 个字符 ( 当前长度为{length} ) 。" + +#: fields.py:1113 +msgid "" +"Upload a valid image. The file you uploaded was either not an image or a " +"corrupted image." +msgstr "请上传有效图片。您上传的该文件不是图片或者图片已经损坏。" + +#: fields.py:1188 +msgid "Expected a dictionary of items but got type \"{input_type}\"." +msgstr "" + +#: pagination.py:221 +msgid "Invalid page \"{page_number}\": {message}." +msgstr "无效页面 “{page_number}”:{message}。" + +#: pagination.py:442 +msgid "Invalid cursor" +msgstr "" + +#: relations.py:133 +msgid "Invalid pk \"{pk_value}\" - object does not exist." +msgstr "无效主键 “{pk_value}” - 对象不存在。" + +#: relations.py:134 +msgid "Incorrect type. Expected pk value, received {data_type}." +msgstr "类型错误。期望为主键,得到的类型为 {data_type}。" + +#: relations.py:157 +msgid "Invalid hyperlink - No URL match." +msgstr "无效超链接 -没有匹配的URL。" + +#: relations.py:158 +msgid "Invalid hyperlink - Incorrect URL match." +msgstr "无效超链接 -错误的URL匹配。" + +#: relations.py:159 +msgid "Invalid hyperlink - Object does not exist." +msgstr "无效超链接 -对象不存在。" + +#: relations.py:160 +msgid "Incorrect type. Expected URL string, received {data_type}." +msgstr "类型错误。期望为URL字符串,得到的类型是 {data_type}。" + +#: relations.py:295 +msgid "Object with {slug_name}={value} does not exist." +msgstr "属性 {slug_name} 为 {value} 的对象不存在。" + +#: relations.py:296 +msgid "Invalid value." +msgstr "无效值。" + +#: serializers.py:299 +msgid "Invalid data. Expected a dictionary, but got {datatype}." +msgstr "无效数据。期待为字典类型,得到的是 {datatype} 。" + +#: validators.py:22 +msgid "This field must be unique." +msgstr "该字段必须唯一。" + +#: validators.py:76 +msgid "The fields {field_names} must make a unique set." +msgstr "字段 {field_names} 必须能构成唯一集合。" + +#: validators.py:219 +msgid "This field must be unique for the \"{date_field}\" date." +msgstr "该字段必须在日期 “{date_field}” 唯一。" + +#: validators.py:234 +msgid "This field must be unique for the \"{date_field}\" month." +msgstr "该字段必须在月份 “{date_field}” 唯一。" + +#: validators.py:247 +msgid "This field must be unique for the \"{date_field}\" year." +msgstr "该字段必须在年 “{date_field}” 唯一。" + +#: versioning.py:39 +msgid "Invalid version in \"Accept\" header." +msgstr "“Accept” HTTP头包含无效版本。" + +#: versioning.py:70 versioning.py:112 +msgid "Invalid version in URL path." +msgstr "URl路径包含无效版本。" + +#: versioning.py:138 +msgid "Invalid version in hostname." +msgstr "主机名包含无效版本。" + +#: versioning.py:160 +msgid "Invalid version in query parameter." +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 "必须包含 “用户名” 和 “密码”。" diff --git a/rest_framework/mixins.py b/rest_framework/mixins.py index 2074a107..c34cfcee 100644 --- a/rest_framework/mixins.py +++ b/rest_framework/mixins.py @@ -5,7 +5,6 @@ We don't bind behaviour to http method handlers yet,  which allows mixin classes to be composed in interesting ways.  """  from __future__ import unicode_literals -  from rest_framework import status  from rest_framework.response import Response  from rest_framework.settings import api_settings @@ -37,12 +36,14 @@ class ListModelMixin(object):      List a queryset.      """      def list(self, request, *args, **kwargs): -        instance = self.filter_queryset(self.get_queryset()) -        page = self.paginate_queryset(instance) +        queryset = self.filter_queryset(self.get_queryset()) + +        page = self.paginate_queryset(queryset)          if page is not None: -            serializer = self.get_pagination_serializer(page) -        else: -            serializer = self.get_serializer(instance, many=True) +            serializer = self.get_serializer(page, many=True) +            return self.get_paginated_response(serializer.data) + +        serializer = self.get_serializer(queryset, many=True)          return Response(serializer.data) diff --git a/rest_framework/pagination.py b/rest_framework/pagination.py index 9c8dda8f..496500ba 100644 --- a/rest_framework/pagination.py +++ b/rest_framework/pagination.py @@ -1,85 +1,684 @@ +# coding: utf-8  """  Pagination serializers determine the structure of the output that should  be used for paginated responses.  """  from __future__ import unicode_literals -from rest_framework import serializers -from rest_framework.templatetags.rest_framework import replace_query_param +from base64 import b64encode, b64decode +from collections import namedtuple +from django.core.paginator import InvalidPage, Paginator as DjangoPaginator +from django.template import Context, loader +from django.utils import six +from django.utils.six.moves.urllib import parse as urlparse +from django.utils.translation import ugettext as _ +from rest_framework.compat import OrderedDict +from rest_framework.exceptions import NotFound +from rest_framework.response import Response +from rest_framework.settings import api_settings +from rest_framework.utils.urls import ( +    replace_query_param, remove_query_param +) -class NextPageField(serializers.Field): +def _positive_int(integer_string, strict=False, cutoff=None):      """ -    Field that returns a link to the next page in paginated results. +    Cast a string to a strictly positive integer.      """ -    page_field = 'page' +    ret = int(integer_string) +    if ret < 0 or (ret == 0 and strict): +        raise ValueError() +    if cutoff: +        ret = min(ret, cutoff) +    return ret -    def to_representation(self, value): -        if not value.has_next(): -            return None -        page = value.next_page_number() -        request = self.context.get('request') -        url = request and request.build_absolute_uri() or '' -        return replace_query_param(url, self.page_field, page) +def _divide_with_ceil(a, b): +    """ +    Returns 'a' divded by 'b', with any remainder rounded up. +    """ +    if a % b: +        return (a // b) + 1 +    return a // b -class PreviousPageField(serializers.Field): + +def _get_count(queryset):      """ -    Field that returns a link to the previous page in paginated results. +    Determine an object count, supporting either querysets or regular lists.      """ -    page_field = 'page' +    try: +        return queryset.count() +    except (AttributeError, TypeError): +        return len(queryset) -    def to_representation(self, value): -        if not value.has_previous(): -            return None -        page = value.previous_page_number() -        request = self.context.get('request') -        url = request and request.build_absolute_uri() or '' -        return replace_query_param(url, self.page_field, page) + +def _get_displayed_page_numbers(current, final): +    """ +    This utility function determines a list of page numbers to display. +    This gives us a nice contextually relevant set of page numbers. + +    For example: +    current=14, final=16 -> [1, None, 13, 14, 15, 16] + +    This implementation gives one page to each side of the cursor, +    or two pages to the side when the cursor is at the edge, then +    ensures that any breaks between non-continous page numbers never +    remove only a single page. + +    For an alernativative implementation which gives two pages to each side of +    the cursor, eg. as in GitHub issue list pagination, see: + +    https://gist.github.com/tomchristie/321140cebb1c4a558b15 +    """ +    assert current >= 1 +    assert final >= current + +    if final <= 5: +        return list(range(1, final + 1)) + +    # We always include the first two pages, last two pages, and +    # two pages either side of the current page. +    included = set(( +        1, +        current - 1, current, current + 1, +        final +    )) + +    # If the break would only exclude a single page number then we +    # may as well include the page number instead of the break. +    if current <= 4: +        included.add(2) +        included.add(3) +    if current >= final - 3: +        included.add(final - 1) +        included.add(final - 2) + +    # Now sort the page numbers and drop anything outside the limits. +    included = [ +        idx for idx in sorted(list(included)) +        if idx > 0 and idx <= final +    ] + +    # Finally insert any `...` breaks +    if current > 4: +        included.insert(1, None) +    if current < final - 3: +        included.insert(len(included) - 1, None) +    return included -class DefaultObjectSerializer(serializers.Serializer): +def _get_page_links(page_numbers, current, url_func):      """ -    If no object serializer is specified, then this serializer will be applied -    as the default. +    Given a list of page numbers and `None` page breaks, +    return a list of `PageLink` objects.      """ -    def to_representation(self, value): -        return value +    page_links = [] +    for page_number in page_numbers: +        if page_number is None: +            page_link = PAGE_BREAK +        else: +            page_link = PageLink( +                url=url_func(page_number), +                number=page_number, +                is_active=(page_number == current), +                is_break=False +            ) +        page_links.append(page_link) +    return page_links -class BasePaginationSerializer(serializers.Serializer): +def _decode_cursor(encoded):      """ -    A base class for pagination serializers to inherit from, -    to make implementing custom serializers more easy. +    Given a string representing an encoded cursor, return a `Cursor` instance.      """ -    results_field = 'results' +    try: +        querystring = b64decode(encoded.encode('ascii')).decode('ascii') +        tokens = urlparse.parse_qs(querystring, keep_blank_values=True) + +        offset = tokens.get('o', ['0'])[0] +        offset = _positive_int(offset) + +        reverse = tokens.get('r', ['0'])[0] +        reverse = bool(int(reverse)) + +        position = tokens.get('p', [None])[0] +    except (TypeError, ValueError): +        return None + +    return Cursor(offset=offset, reverse=reverse, position=position) + + +def _encode_cursor(cursor): +    """ +    Given a Cursor instance, return an encoded string representation. +    """ +    tokens = {} +    if cursor.offset != 0: +        tokens['o'] = str(cursor.offset) +    if cursor.reverse: +        tokens['r'] = '1' +    if cursor.position is not None: +        tokens['p'] = cursor.position + +    querystring = urlparse.urlencode(tokens, doseq=True) +    return b64encode(querystring.encode('ascii')).decode('ascii') + + +def _reverse_ordering(ordering_tuple): +    """ +    Given an order_by tuple such as `('-created', 'uuid')` reverse the +    ordering and return a new tuple, eg. `('created', '-uuid')`. +    """ +    def invert(x): +        return x[1:] if (x.startswith('-')) else '-' + x + +    return tuple([invert(item) for item in ordering_tuple]) + + +Cursor = namedtuple('Cursor', ['offset', 'reverse', 'position']) +PageLink = namedtuple('PageLink', ['url', 'number', 'is_active', 'is_break']) -    def __init__(self, *args, **kwargs): +PAGE_BREAK = PageLink(url=None, number=None, is_active=False, is_break=True) + + +class BasePagination(object): +    display_page_controls = False + +    def paginate_queryset(self, queryset, request, view=None):  # pragma: no cover +        raise NotImplementedError('paginate_queryset() must be implemented.') + +    def get_paginated_response(self, data):  # pragma: no cover +        raise NotImplementedError('get_paginated_response() must be implemented.') + +    def to_html(self):  # pragma: no cover +        raise NotImplementedError('to_html() must be implemented to display page controls.') + + +class PageNumberPagination(BasePagination): +    """ +    A simple page number based style that supports page numbers as +    query parameters. For example: + +    http://api.example.org/accounts/?page=4 +    http://api.example.org/accounts/?page=4&page_size=100 +    """ +    # The default page size. +    # Defaults to `None`, meaning pagination is disabled. +    paginate_by = api_settings.PAGINATE_BY + +    # Client can control the page using this query parameter. +    page_query_param = 'page' + +    # Client can control the page size using this query parameter. +    # Default is 'None'. Set to eg 'page_size' to enable usage. +    paginate_by_param = api_settings.PAGINATE_BY_PARAM + +    # Set to an integer to limit the maximum page size the client may request. +    # Only relevant if 'paginate_by_param' has also been set. +    max_paginate_by = api_settings.MAX_PAGINATE_BY + +    last_page_strings = ('last',) + +    template = 'rest_framework/pagination/numbers.html' + +    invalid_page_message = _('Invalid page "{page_number}": {message}.') + +    def _handle_backwards_compat(self, view):          """ -        Override init to add in the object serializer field on-the-fly. +        Prior to version 3.1, pagination was handled in the view, and the +        attributes were set there. The attributes should now be set on +        the pagination class, but the old style is still pending deprecation.          """ -        super(BasePaginationSerializer, self).__init__(*args, **kwargs) -        results_field = self.results_field +        for attr in ( +            'paginate_by', 'page_query_param', +            'paginate_by_param', 'max_paginate_by' +        ): +            if hasattr(view, attr): +                setattr(self, attr, getattr(view, attr)) -        try: -            object_serializer = self.Meta.object_serializer_class -        except AttributeError: -            object_serializer = DefaultObjectSerializer +    def paginate_queryset(self, queryset, request, view=None): +        """ +        Paginate a queryset if required, either returning a +        page object, or `None` if pagination is not configured for this view. +        """ +        self._handle_backwards_compat(view) + +        page_size = self.get_page_size(request) +        if not page_size: +            return None + +        paginator = DjangoPaginator(queryset, page_size) +        page_number = request.query_params.get(self.page_query_param, 1) +        if page_number in self.last_page_strings: +            page_number = paginator.num_pages          try: -            list_serializer_class = object_serializer.Meta.list_serializer_class -        except AttributeError: -            list_serializer_class = serializers.ListSerializer +            self.page = paginator.page(page_number) +        except InvalidPage as exc: +            msg = self.invalid_page_message.format( +                page_number=page_number, message=six.text_type(exc) +            ) +            raise NotFound(msg) -        self.fields[results_field] = list_serializer_class( -            child=object_serializer(*args, **kwargs), -            source='object_list' -        ) +        if paginator.count > 1: +            # The browsable API should display pagination controls. +            self.display_page_controls = True + +        self.request = request +        return self.page + +    def get_paginated_response(self, data): +        return Response(OrderedDict([ +            ('count', self.page.paginator.count), +            ('next', self.get_next_link()), +            ('previous', self.get_previous_link()), +            ('results', data) +        ])) + +    def get_page_size(self, request): +        if self.paginate_by_param: +            try: +                return _positive_int( +                    request.query_params[self.paginate_by_param], +                    strict=True, +                    cutoff=self.max_paginate_by +                ) +            except (KeyError, ValueError): +                pass + +        return self.paginate_by + +    def get_next_link(self): +        if not self.page.has_next(): +            return None +        url = self.request.build_absolute_uri() +        page_number = self.page.next_page_number() +        return replace_query_param(url, self.page_query_param, page_number) + +    def get_previous_link(self): +        if not self.page.has_previous(): +            return None +        url = self.request.build_absolute_uri() +        page_number = self.page.previous_page_number() +        if page_number == 1: +            return remove_query_param(url, self.page_query_param) +        return replace_query_param(url, self.page_query_param, page_number) +    def get_html_context(self): +        base_url = self.request.build_absolute_uri() -class PaginationSerializer(BasePaginationSerializer): +        def page_number_to_url(page_number): +            if page_number == 1: +                return remove_query_param(base_url, self.page_query_param) +            else: +                return replace_query_param(base_url, self.page_query_param, page_number) + +        current = self.page.number +        final = self.page.paginator.num_pages +        page_numbers = _get_displayed_page_numbers(current, final) +        page_links = _get_page_links(page_numbers, current, page_number_to_url) + +        return { +            'previous_url': self.get_previous_link(), +            'next_url': self.get_next_link(), +            'page_links': page_links +        } + +    def to_html(self): +        template = loader.get_template(self.template) +        context = Context(self.get_html_context()) +        return template.render(context) + + +class LimitOffsetPagination(BasePagination):      """ -    A default implementation of a pagination serializer. +    A limit/offset based style. For example: + +    http://api.example.org/accounts/?limit=100 +    http://api.example.org/accounts/?offset=400&limit=100      """ -    count = serializers.ReadOnlyField(source='paginator.count') -    next = NextPageField(source='*') -    previous = PreviousPageField(source='*') +    default_limit = api_settings.PAGINATE_BY +    limit_query_param = 'limit' +    offset_query_param = 'offset' +    max_limit = None +    template = 'rest_framework/pagination/numbers.html' + +    def paginate_queryset(self, queryset, request, view=None): +        self.limit = self.get_limit(request) +        self.offset = self.get_offset(request) +        self.count = _get_count(queryset) +        self.request = request +        if self.count > self.limit: +            self.display_page_controls = True +        return queryset[self.offset:self.offset + self.limit] + +    def get_paginated_response(self, data): +        return Response(OrderedDict([ +            ('count', self.count), +            ('next', self.get_next_link()), +            ('previous', self.get_previous_link()), +            ('results', data) +        ])) + +    def get_limit(self, request): +        if self.limit_query_param: +            try: +                return _positive_int( +                    request.query_params[self.limit_query_param], +                    cutoff=self.max_limit +                ) +            except (KeyError, ValueError): +                pass + +        return self.default_limit + +    def get_offset(self, request): +        try: +            return _positive_int( +                request.query_params[self.offset_query_param], +            ) +        except (KeyError, ValueError): +            return 0 + +    def get_next_link(self): +        if self.offset + self.limit >= self.count: +            return None + +        url = self.request.build_absolute_uri() +        offset = self.offset + self.limit +        return replace_query_param(url, self.offset_query_param, offset) + +    def get_previous_link(self): +        if self.offset <= 0: +            return None + +        url = self.request.build_absolute_uri() + +        if self.offset - self.limit <= 0: +            return remove_query_param(url, self.offset_query_param) + +        offset = self.offset - self.limit +        return replace_query_param(url, self.offset_query_param, offset) + +    def get_html_context(self): +        base_url = self.request.build_absolute_uri() +        current = _divide_with_ceil(self.offset, self.limit) + 1 +        # The number of pages is a little bit fiddly. +        # We need to sum both the number of pages from current offset to end +        # plus the number of pages up to the current offset. +        # When offset is not strictly divisible by the limit then we may +        # end up introducing an extra page as an artifact. +        final = ( +            _divide_with_ceil(self.count - self.offset, self.limit) + +            _divide_with_ceil(self.offset, self.limit) +        ) + +        def page_number_to_url(page_number): +            if page_number == 1: +                return remove_query_param(base_url, self.offset_query_param) +            else: +                offset = self.offset + ((page_number - current) * self.limit) +                return replace_query_param(base_url, self.offset_query_param, offset) + +        page_numbers = _get_displayed_page_numbers(current, final) +        page_links = _get_page_links(page_numbers, current, page_number_to_url) + +        return { +            'previous_url': self.get_previous_link(), +            'next_url': self.get_next_link(), +            'page_links': page_links +        } + +    def to_html(self): +        template = loader.get_template(self.template) +        context = Context(self.get_html_context()) +        return template.render(context) + + +class CursorPagination(BasePagination): +    # Determine how/if True, False and None positions work - do the string +    # encodings work with Django queryset filters? +    # Consider a max offset cap. +    # Tidy up the `get_ordering` API (eg remove queryset from it) +    cursor_query_param = 'cursor' +    page_size = api_settings.PAGINATE_BY +    invalid_cursor_message = _('Invalid cursor') +    ordering = None +    template = 'rest_framework/pagination/previous_and_next.html' + +    def paginate_queryset(self, queryset, request, view=None): +        self.base_url = request.build_absolute_uri() +        self.ordering = self.get_ordering(request, queryset, view) + +        # Determine if we have a cursor, and if so then decode it. +        encoded = request.query_params.get(self.cursor_query_param) +        if encoded is None: +            self.cursor = None +            (offset, reverse, current_position) = (0, False, None) +        else: +            self.cursor = _decode_cursor(encoded) +            if self.cursor is None: +                raise NotFound(self.invalid_cursor_message) +            (offset, reverse, current_position) = self.cursor + +        # Cursor pagination always enforces an ordering. +        if reverse: +            queryset = queryset.order_by(*_reverse_ordering(self.ordering)) +        else: +            queryset = queryset.order_by(*self.ordering) + +        # If we have a cursor with a fixed position then filter by that. +        if current_position is not None: +            order = self.ordering[0] +            is_reversed = order.startswith('-') +            order_attr = order.lstrip('-') + +            # Test for: (cursor reversed) XOR (queryset reversed) +            if self.cursor.reverse != is_reversed: +                kwargs = {order_attr + '__lt': current_position} +            else: +                kwargs = {order_attr + '__gt': current_position} + +            queryset = queryset.filter(**kwargs) + +        # If we have an offset cursor then offset the entire page by that amount. +        # We also always fetch an extra item in order to determine if there is a +        # page following on from this one. +        results = list(queryset[offset:offset + self.page_size + 1]) +        self.page = results[:self.page_size] + +        # Determine the position of the final item following the page. +        if len(results) > len(self.page): +            has_following_postion = True +            following_position = self._get_position_from_instance(results[-1], self.ordering) +        else: +            has_following_postion = False +            following_position = None + +        # If we have a reverse queryset, then the query ordering was in reverse +        # so we need to reverse the items again before returning them to the user. +        if reverse: +            self.page = list(reversed(self.page)) + +        if reverse: +            # Determine next and previous positions for reverse cursors. +            self.has_next = (current_position is not None) or (offset > 0) +            self.has_previous = has_following_postion +            if self.has_next: +                self.next_position = current_position +            if self.has_previous: +                self.previous_position = following_position +        else: +            # Determine next and previous positions for forward cursors. +            self.has_next = has_following_postion +            self.has_previous = (current_position is not None) or (offset > 0) +            if self.has_next: +                self.next_position = following_position +            if self.has_previous: +                self.previous_position = current_position + +        # Display page controls in the browsable API if there is more +        # than one page. +        if self.has_previous or self.has_next: +            self.display_page_controls = True + +        return self.page + +    def get_next_link(self): +        if not self.has_next: +            return None + +        if self.cursor and self.cursor.reverse and self.cursor.offset != 0: +            # If we're reversing direction and we have an offset cursor +            # then we cannot use the first position we find as a marker. +            compare = self._get_position_from_instance(self.page[-1], self.ordering) +        else: +            compare = self.next_position +        offset = 0 + +        for item in reversed(self.page): +            position = self._get_position_from_instance(item, self.ordering) +            if position != compare: +                # The item in this position and the item following it +                # have different positions. We can use this position as +                # our marker. +                break + +            # The item in this postion has the same position as the item +            # following it, we can't use it as a marker position, so increment +            # the offset and keep seeking to the previous item. +            compare = position +            offset += 1 + +        else: +            # There were no unique positions in the page. +            if not self.has_previous: +                # We are on the first page. +                # Our cursor will have an offset equal to the page size, +                # but no position to filter against yet. +                offset = self.page_size +                position = None +            elif self.cursor.reverse: +                # The change in direction will introduce a paging artifact, +                # where we end up skipping forward a few extra items. +                offset = 0 +                position = self.previous_position +            else: +                # Use the position from the existing cursor and increment +                # it's offset by the page size. +                offset = self.cursor.offset + self.page_size +                position = self.previous_position + +        cursor = Cursor(offset=offset, reverse=False, position=position) +        encoded = _encode_cursor(cursor) +        return replace_query_param(self.base_url, self.cursor_query_param, encoded) + +    def get_previous_link(self): +        if not self.has_previous: +            return None + +        if self.cursor and not self.cursor.reverse and self.cursor.offset != 0: +            # If we're reversing direction and we have an offset cursor +            # then we cannot use the first position we find as a marker. +            compare = self._get_position_from_instance(self.page[0], self.ordering) +        else: +            compare = self.previous_position +        offset = 0 + +        for item in self.page: +            position = self._get_position_from_instance(item, self.ordering) +            if position != compare: +                # The item in this position and the item following it +                # have different positions. We can use this position as +                # our marker. +                break + +            # The item in this postion has the same position as the item +            # following it, we can't use it as a marker position, so increment +            # the offset and keep seeking to the previous item. +            compare = position +            offset += 1 + +        else: +            # There were no unique positions in the page. +            if not self.has_next: +                # We are on the final page. +                # Our cursor will have an offset equal to the page size, +                # but no position to filter against yet. +                offset = self.page_size +                position = None +            elif self.cursor.reverse: +                # Use the position from the existing cursor and increment +                # it's offset by the page size. +                offset = self.cursor.offset + self.page_size +                position = self.next_position +            else: +                # The change in direction will introduce a paging artifact, +                # where we end up skipping back a few extra items. +                offset = 0 +                position = self.next_position + +        cursor = Cursor(offset=offset, reverse=True, position=position) +        encoded = _encode_cursor(cursor) +        return replace_query_param(self.base_url, self.cursor_query_param, encoded) + +    def get_ordering(self, request, queryset, view): +        """ +        Return a tuple of strings, that may be used in an `order_by` method. +        """ +        ordering_filters = [ +            filter_cls for filter_cls in getattr(view, 'filter_backends', []) +            if hasattr(filter_cls, 'get_ordering') +        ] + +        if ordering_filters: +            # If a filter exists on the view that implements `get_ordering` +            # then we defer to that filter to determine the ordering. +            filter_cls = ordering_filters[0] +            filter_instance = filter_cls() +            ordering = filter_instance.get_ordering(request, queryset, view) +            assert ordering is not None, ( +                'Using cursor pagination, but filter class {filter_cls} ' +                'returned a `None` ordering.'.format( +                    filter_cls=filter_cls.__name__ +                ) +            ) +        else: +            # The default case is to check for an `ordering` attribute, +            # first on the view instance, and then on this pagination instance. +            ordering = getattr(view, 'ordering', getattr(self, 'ordering', None)) +            assert ordering is not None, ( +                'Using cursor pagination, but no ordering attribute was declared ' +                'on the view or on the pagination class.' +            ) + +        assert isinstance(ordering, (six.string_types, list, tuple)), ( +            'Invalid ordering. Expected string or tuple, but got {type}'.format( +                type=type(ordering).__name__ +            ) +        ) + +        if isinstance(ordering, six.string_types): +            return (ordering,) +        return tuple(ordering) + +    def _get_position_from_instance(self, instance, ordering): +        attr = getattr(instance, ordering[0].lstrip('-')) +        return six.text_type(attr) + +    def get_paginated_response(self, data): +        return Response(OrderedDict([ +            ('next', self.get_next_link()), +            ('previous', self.get_previous_link()), +            ('results', data) +        ])) + +    def get_html_context(self): +        return { +            'previous_url': self.get_previous_link(), +            'next_url': self.get_next_link() +        } + +    def to_html(self): +        template = loader.get_template(self.template) +        context = Context(self.get_html_context()) +        return template.render(context) diff --git a/rest_framework/parsers.py b/rest_framework/parsers.py index 1efab85b..437d1339 100644 --- a/rest_framework/parsers.py +++ b/rest_framework/parsers.py @@ -14,12 +14,9 @@ from django.http.multipartparser import MultiPartParserError, parse_header, Chun  from django.utils import six  from django.utils.six.moves.urllib import parse as urlparse  from django.utils.encoding import force_text -from rest_framework.compat import etree, yaml  from rest_framework.exceptions import ParseError  from rest_framework import renderers  import json -import datetime -import decimal  class DataAndFiles(object): @@ -67,29 +64,6 @@ class JSONParser(BaseParser):              raise ParseError('JSON parse error - %s' % six.text_type(exc)) -class YAMLParser(BaseParser): -    """ -    Parses YAML-serialized data. -    """ - -    media_type = 'application/yaml' - -    def parse(self, stream, media_type=None, parser_context=None): -        """ -        Parses the incoming bytestream as YAML and returns the resulting data. -        """ -        assert yaml, 'YAMLParser requires pyyaml to be installed' - -        parser_context = parser_context or {} -        encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET) - -        try: -            data = stream.read().decode(encoding) -            return yaml.safe_load(data) -        except (ValueError, yaml.parser.ParserError) as exc: -            raise ParseError('YAML parse error - %s' % six.text_type(exc)) - -  class FormParser(BaseParser):      """      Parser for form data. @@ -138,78 +112,6 @@ class MultiPartParser(BaseParser):              raise ParseError('Multipart form parse error - %s' % six.text_type(exc)) -class XMLParser(BaseParser): -    """ -    XML parser. -    """ - -    media_type = 'application/xml' - -    def parse(self, stream, media_type=None, parser_context=None): -        """ -        Parses the incoming bytestream as XML and returns the resulting data. -        """ -        assert etree, 'XMLParser requires defusedxml to be installed' - -        parser_context = parser_context or {} -        encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET) -        parser = etree.DefusedXMLParser(encoding=encoding) -        try: -            tree = etree.parse(stream, parser=parser, forbid_dtd=True) -        except (etree.ParseError, ValueError) as exc: -            raise ParseError('XML parse error - %s' % six.text_type(exc)) -        data = self._xml_convert(tree.getroot()) - -        return data - -    def _xml_convert(self, element): -        """ -        convert the xml `element` into the corresponding python object -        """ - -        children = list(element) - -        if len(children) == 0: -            return self._type_convert(element.text) -        else: -            # if the fist child tag is list-item means all children are list-item -            if children[0].tag == "list-item": -                data = [] -                for child in children: -                    data.append(self._xml_convert(child)) -            else: -                data = {} -                for child in children: -                    data[child.tag] = self._xml_convert(child) - -            return data - -    def _type_convert(self, value): -        """ -        Converts the value returned by the XMl parse into the equivalent -        Python type -        """ -        if value is None: -            return value - -        try: -            return datetime.datetime.strptime(value, '%Y-%m-%d %H:%M:%S') -        except ValueError: -            pass - -        try: -            return int(value) -        except ValueError: -            pass - -        try: -            return decimal.Decimal(value) -        except decimal.InvalidOperation: -            pass - -        return value - -  class FileUploadParser(BaseParser):      """      Parser for file upload data. diff --git a/rest_framework/permissions.py b/rest_framework/permissions.py index 3f6f5961..9069d315 100644 --- a/rest_framework/permissions.py +++ b/rest_framework/permissions.py @@ -3,8 +3,7 @@ Provides a set of pluggable permission policies.  """  from __future__ import unicode_literals  from django.http import Http404 -from rest_framework.compat import (get_model_name, oauth2_provider_scope, -                                   oauth2_constants) +from rest_framework.compat import get_model_name  SAFE_METHODS = ['GET', 'HEAD', 'OPTIONS'] @@ -199,28 +198,3 @@ class DjangoObjectPermissions(DjangoModelPermissions):              return False          return True - - -class TokenHasReadWriteScope(BasePermission): -    """ -    The request is authenticated as a user and the token used has the right scope -    """ - -    def has_permission(self, request, view): -        token = request.auth -        read_only = request.method in SAFE_METHODS - -        if not token: -            return False - -        if hasattr(token, 'resource'):  # OAuth 1 -            return read_only or not request.auth.resource.is_readonly -        elif hasattr(token, 'scope'):  # OAuth 2 -            required = oauth2_constants.READ if read_only else oauth2_constants.WRITE -            return oauth2_provider_scope.check(required, request.auth.scope) - -        assert False, ( -            'TokenHasReadWriteScope requires either the' -            '`OAuthAuthentication` or `OAuth2Authentication` authentication ' -            'class to be used.' -        ) diff --git a/rest_framework/relations.py b/rest_framework/relations.py index 13793f37..0b7c9d86 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -1,7 +1,7 @@  # coding: utf-8  from __future__ import unicode_literals  from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured -from django.core.urlresolvers import resolve, get_script_prefix, NoReverseMatch, Resolver404 +from django.core.urlresolvers import get_script_prefix, resolve, NoReverseMatch, Resolver404  from django.db.models.query import QuerySet  from django.utils import six  from django.utils.encoding import smart_text @@ -130,7 +130,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}.'),      } @@ -154,7 +154,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}.'), @@ -167,11 +167,10 @@ class HyperlinkedRelatedField(RelatedField):          self.lookup_url_kwarg = kwargs.pop('lookup_url_kwarg', self.lookup_field)          self.format = kwargs.pop('format', None) -        # We include these simply for dependency injection in tests. -        # We can't add them as class attributes or they would expect an +        # We include this simply for dependency injection in tests. +        # We can't add it as a class attributes or it would expect an          # implicit `self` argument to be passed.          self.reverse = reverse -        self.resolve = resolve          super(HyperlinkedRelatedField, self).__init__(**kwargs) @@ -205,6 +204,7 @@ class HyperlinkedRelatedField(RelatedField):          return self.reverse(view_name, kwargs=kwargs, request=request, format=format)      def to_internal_value(self, data): +        request = self.context.get('request', None)          try:              http_prefix = data.startswith(('http:', 'https:'))          except AttributeError: @@ -218,11 +218,18 @@ class HyperlinkedRelatedField(RelatedField):                  data = '/' + data[len(prefix):]          try: -            match = self.resolve(data) +            match = resolve(data)          except Resolver404:              self.fail('no_match') -        if match.view_name != self.view_name: +        try: +            expected_viewname = request.versioning_scheme.get_versioned_viewname( +                self.view_name, request +            ) +        except AttributeError: +            expected_viewname = self.view_name + +        if match.view_name != expected_viewname:              self.fail('incorrect_match')          try: @@ -292,7 +299,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/renderers.py b/rest_framework/renderers.py index 584332e6..6256acdd 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -17,11 +17,8 @@ from django.http.multipartparser import parse_header  from django.template import Context, RequestContext, loader, Template  from django.test.client import encode_multipart  from django.utils import six -from django.utils.encoding import smart_text -from django.utils.xmlutils import SimplerXMLGenerator -from django.utils.six.moves import StringIO  from rest_framework import exceptions, serializers, status, VERSION -from rest_framework.compat import SHORT_SEPARATORS, LONG_SEPARATORS, yaml +from rest_framework.compat import SHORT_SEPARATORS, LONG_SEPARATORS, INDENT_SEPARATORS  from rest_framework.exceptions import ParseError  from rest_framework.settings import api_settings  from rest_framework.request import is_form_media_type, override_method @@ -90,7 +87,11 @@ class JSONRenderer(BaseRenderer):          renderer_context = renderer_context or {}          indent = self.get_indent(accepted_media_type, renderer_context) -        separators = SHORT_SEPARATORS if (indent is None and self.compact) else LONG_SEPARATORS + +        if indent is None: +            separators = SHORT_SEPARATORS if self.compact else LONG_SEPARATORS +        else: +            separators = INDENT_SEPARATORS          ret = json.dumps(              data, cls=self.encoder_class, @@ -112,112 +113,6 @@ class JSONRenderer(BaseRenderer):          return ret -class JSONPRenderer(JSONRenderer): -    """ -    Renderer which serializes to json, -    wrapping the json output in a callback function. -    """ - -    media_type = 'application/javascript' -    format = 'jsonp' -    callback_parameter = 'callback' -    default_callback = 'callback' -    charset = 'utf-8' - -    def get_callback(self, renderer_context): -        """ -        Determine the name of the callback to wrap around the json output. -        """ -        request = renderer_context.get('request', None) -        params = request and request.query_params or {} -        return params.get(self.callback_parameter, self.default_callback) - -    def render(self, data, accepted_media_type=None, renderer_context=None): -        """ -        Renders into jsonp, wrapping the json output in a callback function. - -        Clients may set the callback function name using a query parameter -        on the URL, for example: ?callback=exampleCallbackName -        """ -        renderer_context = renderer_context or {} -        callback = self.get_callback(renderer_context) -        json = super(JSONPRenderer, self).render(data, accepted_media_type, -                                                 renderer_context) -        return callback.encode(self.charset) + b'(' + json + b');' - - -class XMLRenderer(BaseRenderer): -    """ -    Renderer which serializes to XML. -    """ - -    media_type = 'application/xml' -    format = 'xml' -    charset = 'utf-8' - -    def render(self, data, accepted_media_type=None, renderer_context=None): -        """ -        Renders `data` into serialized XML. -        """ -        if data is None: -            return '' - -        stream = StringIO() - -        xml = SimplerXMLGenerator(stream, self.charset) -        xml.startDocument() -        xml.startElement("root", {}) - -        self._to_xml(xml, data) - -        xml.endElement("root") -        xml.endDocument() -        return stream.getvalue() - -    def _to_xml(self, xml, data): -        if isinstance(data, (list, tuple)): -            for item in data: -                xml.startElement("list-item", {}) -                self._to_xml(xml, item) -                xml.endElement("list-item") - -        elif isinstance(data, dict): -            for key, value in six.iteritems(data): -                xml.startElement(key, {}) -                self._to_xml(xml, value) -                xml.endElement(key) - -        elif data is None: -            # Don't output any value -            pass - -        else: -            xml.characters(smart_text(data)) - - -class YAMLRenderer(BaseRenderer): -    """ -    Renderer which serializes to YAML. -    """ - -    media_type = 'application/yaml' -    format = 'yaml' -    encoder = encoders.SafeDumper -    charset = 'utf-8' -    ensure_ascii = False - -    def render(self, data, accepted_media_type=None, renderer_context=None): -        """ -        Renders `data` into serialized YAML. -        """ -        assert yaml, 'YAMLRenderer requires pyyaml to be installed' - -        if data is None: -            return '' - -        return yaml.dump(data, stream=None, encoding=self.charset, Dumper=self.encoder, allow_unicode=not self.ensure_ascii) - -  class TemplateHTMLRenderer(BaseRenderer):      """      An HTML renderer for use with templates. @@ -696,6 +591,11 @@ class BrowsableAPIRenderer(BaseRenderer):                  renderer_content_type += ' ;%s' % renderer.charset          response_headers['Content-Type'] = renderer_content_type +        if hasattr(view, 'paginator') and view.paginator.display_page_controls: +            paginator = view.paginator +        else: +            paginator = None +          context = {              'content': self.get_content(renderer, data, accepted_media_type, renderer_context),              'view': view, @@ -704,6 +604,7 @@ class BrowsableAPIRenderer(BaseRenderer):              'description': self.get_description(view),              'name': self.get_name(view),              'version': VERSION, +            'paginator': paginator,              'breadcrumblist': self.get_breadcrumbs(request),              'allowed_methods': view.allowed_methods,              'available_formats': [renderer_cls.format for renderer_cls in view.renderer_classes], diff --git a/rest_framework/request.py b/rest_framework/request.py index c4de9424..081ace23 100644 --- a/rest_framework/request.py +++ b/rest_framework/request.py @@ -108,6 +108,10 @@ def clone_request(request, method):          ret.accepted_renderer = request.accepted_renderer      if hasattr(request, 'accepted_media_type'):          ret.accepted_media_type = request.accepted_media_type +    if hasattr(request, 'version'): +        ret.version = request.version +    if hasattr(request, 'versioning_scheme'): +        ret.versioning_scheme = request.versioning_scheme      return ret @@ -216,8 +220,8 @@ class Request(object):          Synonym for `.query_params`, for backwards compatibility.          """          warnings.warn( -            "`request.QUERY_PARAMS` is pending deprecation. Use `request.query_params` instead.", -            PendingDeprecationWarning, +            "`request.QUERY_PARAMS` is deprecated. Use `request.query_params` instead.", +            DeprecationWarning,              stacklevel=1          )          return self._request.GET @@ -237,8 +241,8 @@ class Request(object):          arbitrary parsers, and also works on methods other than POST (eg PUT).          """          warnings.warn( -            "`request.DATA` is pending deprecation. Use `request.data` instead.", -            PendingDeprecationWarning, +            "`request.DATA` is deprecated. Use `request.data` instead.", +            DeprecationWarning,              stacklevel=1          )          if not _hasattr(self, '_data'): @@ -254,8 +258,8 @@ class Request(object):          arbitrary parsers, and also works on methods other than POST (eg PUT).          """          warnings.warn( -            "`request.FILES` is pending deprecation. Use `request.data` instead.", -            PendingDeprecationWarning, +            "`request.FILES` is deprecated. Use `request.data` instead.", +            DeprecationWarning,              stacklevel=1          )          if not _hasattr(self, '_files'): diff --git a/rest_framework/reverse.py b/rest_framework/reverse.py index a74e8aa2..a251d99d 100644 --- a/rest_framework/reverse.py +++ b/rest_framework/reverse.py @@ -1,5 +1,5 @@  """ -Provide reverse functions that return fully qualified URLs +Provide urlresolver functions that return fully qualified URLs or view names  """  from __future__ import unicode_literals  from django.core.urlresolvers import reverse as django_reverse @@ -9,6 +9,18 @@ from django.utils.functional import lazy  def reverse(viewname, args=None, kwargs=None, request=None, format=None, **extra):      """ +    If versioning is being used then we pass any `reverse` calls through +    to the versioning scheme instance, so that the resulting URL +    can be modified if needed. +    """ +    scheme = getattr(request, 'versioning_scheme', None) +    if scheme is not None: +        return scheme.reverse(viewname, args, kwargs, request, format, **extra) +    return _reverse(viewname, args, kwargs, request, format, **extra) + + +def _reverse(viewname, args=None, kwargs=None, request=None, format=None, **extra): +    """      Same as `django.core.urlresolvers.reverse`, but optionally takes a request      and returns a fully qualified URL, using the request to get the base URL.      """ diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index d76658b0..c60574d4 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -12,7 +12,7 @@ response content is handled by parsers and renderers.  """  from __future__ import unicode_literals  from django.db import models -from django.db.models.fields import FieldDoesNotExist, Field as DjangoField +from django.db.models.fields import FieldDoesNotExist, Field as DjangoModelField  from django.utils.translation import ugettext_lazy as _  from rest_framework.compat import postgres_fields, unicode_to_repr  from rest_framework.utils import model_meta @@ -327,7 +327,9 @@ class Serializer(BaseSerializer):          Returns a list of validator callables.          """          # Used by the lazily-evaluated `validators` property. -        return getattr(getattr(self, 'Meta', None), 'validators', []) +        meta = getattr(self, 'Meta', None) +        validators = getattr(meta, 'validators', None) +        return validators[:] if validators else []      def get_initial(self):          if hasattr(self, 'initial_data'): @@ -477,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): @@ -702,8 +704,7 @@ class ModelSerializer(Serializer):      you need you should either declare the extra/differing fields explicitly on      the serializer class, or simply use a `Serializer` class.      """ - -    _field_mapping = ClassLookupDict({ +    serializer_field_mapping = {          models.AutoField: IntegerField,          models.BigIntegerField: IntegerField,          models.BooleanField: BooleanField, @@ -725,10 +726,13 @@ class ModelSerializer(Serializer):          models.SmallIntegerField: IntegerField,          models.TextField: CharField,          models.TimeField: TimeField, -        models.URLField: URLField -        # Note: Some version-specific mappings also defined below. -    }) -    _related_class = PrimaryKeyRelatedField +        models.URLField: URLField, +    } +    serializer_related_field = PrimaryKeyRelatedField +    serializer_url_field = HyperlinkedIdentityField +    serializer_choice_field = ChoiceField + +    # Default `create` and `update` behavior...      def create(self, validated_data):          """ @@ -799,69 +803,82 @@ class ModelSerializer(Serializer):          return instance -    def get_validators(self): -        # If the validators have been declared explicitly then use that. -        validators = getattr(getattr(self, 'Meta', None), 'validators', None) -        if validators is not None: -            return validators +    # Determine the fields to apply... -        # Determine the default set of validators. -        validators = [] -        model_class = self.Meta.model -        field_names = set([ -            field.source for field in self.fields.values() -            if (field.source != '*') and ('.' not in field.source) -        ]) +    def get_fields(self): +        """ +        Return the dict of field names -> field instances that should be +        used for `self.fields` when instantiating the serializer. +        """ +        assert hasattr(self, 'Meta'), ( +            'Class {serializer_class} missing "Meta" attribute'.format( +                serializer_class=self.__class__.__name__ +            ) +        ) +        assert hasattr(self.Meta, 'model'), ( +            'Class {serializer_class} missing "Meta.model" attribute'.format( +                serializer_class=self.__class__.__name__ +            ) +        ) -        # Note that we make sure to check `unique_together` both on the -        # base model class, but also on any parent classes. -        for parent_class in [model_class] + list(model_class._meta.parents.keys()): -            for unique_together in parent_class._meta.unique_together: -                if field_names.issuperset(set(unique_together)): -                    validator = UniqueTogetherValidator( -                        queryset=parent_class._default_manager, -                        fields=unique_together -                    ) -                    validators.append(validator) +        declared_fields = copy.deepcopy(self._declared_fields) +        model = getattr(self.Meta, 'model') +        depth = getattr(self.Meta, 'depth', 0) -        # Add any unique_for_date/unique_for_month/unique_for_year constraints. -        info = model_meta.get_field_info(model_class) -        for field_name, field in info.fields_and_pk.items(): -            if field.unique_for_date and field_name in field_names: -                validator = UniqueForDateValidator( -                    queryset=model_class._default_manager, -                    field=field_name, -                    date_field=field.unique_for_date -                ) -                validators.append(validator) +        if depth is not None: +            assert depth >= 0, "'depth' may not be negative." +            assert depth <= 10, "'depth' may not be greater than 10." -            if field.unique_for_month and field_name in field_names: -                validator = UniqueForMonthValidator( -                    queryset=model_class._default_manager, -                    field=field_name, -                    date_field=field.unique_for_month -                ) -                validators.append(validator) +        # Retrieve metadata about fields & relationships on the model class. +        info = model_meta.get_field_info(model) +        field_names = self.get_field_names(declared_fields, info) -            if field.unique_for_year and field_name in field_names: -                validator = UniqueForYearValidator( -                    queryset=model_class._default_manager, -                    field=field_name, -                    date_field=field.unique_for_year -                ) -                validators.append(validator) +        # Determine any extra field arguments and hidden fields that +        # should be included +        extra_kwargs = self.get_extra_kwargs() +        extra_kwargs, hidden_fields = self.get_uniqueness_extra_kwargs( +            field_names, declared_fields, extra_kwargs +        ) -        return validators +        # Determine the fields that should be included on the serializer. +        fields = OrderedDict() -    def get_fields(self): -        declared_fields = copy.deepcopy(self._declared_fields) +        for field_name in field_names: +            # If the field is explicitly declared on the class then use that. +            if field_name in declared_fields: +                fields[field_name] = declared_fields[field_name] +                continue -        ret = OrderedDict() -        model = getattr(self.Meta, 'model') +            # Determine the serializer field class and keyword arguments. +            field_class, field_kwargs = self.build_field( +                field_name, info, model, depth +            ) + +            # Include any kwargs defined in `Meta.extra_kwargs` +            extra_field_kwargs = extra_kwargs.get(field_name, {}) +            field_kwargs = self.include_extra_kwargs( +                field_kwargs, extra_field_kwargs +            ) + +            # Create the serializer field. +            fields[field_name] = field_class(**field_kwargs) + +        # Add in any hidden fields. +        fields.update(hidden_fields) + +        return fields + +    # Methods for determining the set of field names to include... + +    def get_field_names(self, declared_fields, info): +        """ +        Returns the list of all field names that should be created when +        instantiating this serializer class. This is based on the default +        set of fields, but also takes into account the `Meta.fields` or +        `Meta.exclude` options if they have been specified. +        """          fields = getattr(self.Meta, 'fields', None)          exclude = getattr(self.Meta, 'exclude', None) -        depth = getattr(self.Meta, 'depth', 0) -        extra_kwargs = getattr(self.Meta, 'extra_kwargs', {})          if fields and not isinstance(fields, (list, tuple)):              raise TypeError( @@ -875,201 +892,208 @@ class ModelSerializer(Serializer):                  type(exclude).__name__              ) -        assert not (fields and exclude), "Cannot set both 'fields' and 'exclude'." - -        extra_kwargs = self._include_additional_options(extra_kwargs) +        assert not (fields and exclude), ( +            "Cannot set both 'fields' and 'exclude' options on " +            "serializer {serializer_class}.".format( +                serializer_class=self.__class__.__name__ +            ) +        ) -        # Retrieve metadata about fields & relationships on the model class. -        info = model_meta.get_field_info(model) +        if fields is not None: +            # Ensure that all declared fields have also been included in the +            # `Meta.fields` option. -        if fields is None: -            # Use the default set of field names if none is supplied explicitly. -            fields = self._get_default_field_names(declared_fields, info) -            exclude = getattr(self.Meta, 'exclude', None) -            if exclude is not None: -                for field_name in exclude: -                    assert field_name in fields, ( -                        'The field in the `exclude` option must be a model field. Got %s.' % -                        field_name +            # Do not require any fields that are declared a parent class, +            # in order to allow serializer subclasses to only include +            # a subset of fields. +            required_field_names = set(declared_fields) +            for cls in self.__class__.__bases__: +                required_field_names -= set(getattr(cls, '_declared_fields', [])) + +            for field_name in required_field_names: +                assert field_name in fields, ( +                    "The field '{field_name}' was declared on serializer " +                    "{serializer_class}, but has not been included in the " +                    "'fields' option.".format( +                        field_name=field_name, +                        serializer_class=self.__class__.__name__                      ) -                    fields.remove(field_name) -        else: -            # Check that any fields declared on the class are -            # also explicitly included in `Meta.fields`. +                ) +            return fields + +        # Use the default set of field names if `Meta.fields` is not specified. +        fields = self.get_default_field_names(declared_fields, info) + +        if exclude is not None: +            # If `Meta.exclude` is included, then remove those fields. +            for field_name in exclude: +                assert field_name in fields, ( +                    "The field '{field_name}' was include on serializer " +                    "{serializer_class} in the 'exclude' option, but does " +                    "not match any model field.".format( +                        field_name=field_name, +                        serializer_class=self.__class__.__name__ +                    ) +                ) +                fields.remove(field_name) -            # Note that we ignore any fields that were declared on a parent -            # class, in order to support only including a subset of fields -            # when subclassing serializers. -            declared_field_names = set(declared_fields.keys()) -            for cls in self.__class__.__bases__: -                declared_field_names -= set(getattr(cls, '_declared_fields', [])) +        return fields -            missing_fields = declared_field_names - set(fields) -            assert not missing_fields, ( -                'Field `%s` has been declared on serializer `%s`, but ' -                'is missing from `Meta.fields`.' % -                (list(missing_fields)[0], self.__class__.__name__) -            ) +    def get_default_field_names(self, declared_fields, model_info): +        """ +        Return the default list of field names that will be used if the +        `Meta.fields` option is not specified. +        """ +        return ( +            [model_info.pk.name] + +            list(declared_fields.keys()) + +            list(model_info.fields.keys()) + +            list(model_info.forward_relations.keys()) +        ) -        # Determine the set of model fields, and the fields that they map to. -        # We actually only need this to deal with the slightly awkward case -        # of supporting `unique_for_date`/`unique_for_month`/`unique_for_year`. -        model_field_mapping = {} -        for field_name in fields: -            if field_name in declared_fields: -                field = declared_fields[field_name] -                source = field.source or field_name +    # Methods for constructing serializer fields... + +    def build_field(self, field_name, info, model_class, nested_depth): +        """ +        Return a two tuple of (cls, kwargs) to build a serializer field with. +        """ +        if field_name in info.fields_and_pk: +            model_field = info.fields_and_pk[field_name] +            return self.build_standard_field(field_name, model_field) + +        elif field_name in info.relations: +            relation_info = info.relations[field_name] +            if not nested_depth: +                return self.build_relational_field(field_name, relation_info)              else: -                try: -                    source = extra_kwargs[field_name]['source'] -                except KeyError: -                    source = field_name -            # Model fields will always have a simple source mapping, -            # they can't be nested attribute lookups. -            if '.' not in source and source != '*': -                model_field_mapping[source] = field_name +                return self.build_nested_field(field_name, relation_info, nested_depth) -        # Determine if we need any additional `HiddenField` or extra keyword -        # arguments to deal with `unique_for` dates that are required to -        # be in the input data in order to validate it. -        hidden_fields = {} -        unique_constraint_names = set() +        elif hasattr(model_class, field_name): +            return self.build_property_field(field_name, model_class) -        for model_field_name, field_name in model_field_mapping.items(): -            try: -                model_field = model._meta.get_field(model_field_name) -            except FieldDoesNotExist: -                continue +        elif field_name == api_settings.URL_FIELD_NAME: +            return self.build_url_field(field_name, model_class) -            if not isinstance(model_field, DjangoField): -                continue +        return self.build_unknown_field(field_name, model_class) -            # Include each of the `unique_for_*` field names. -            unique_constraint_names |= set([ -                model_field.unique_for_date, -                model_field.unique_for_month, -                model_field.unique_for_year -            ]) +    def build_standard_field(self, field_name, model_field): +        """ +        Create regular model fields. +        """ +        field_mapping = ClassLookupDict(self.serializer_field_mapping) + +        field_class = field_mapping[model_field] +        field_kwargs = get_field_kwargs(field_name, model_field) + +        if 'choices' in field_kwargs: +            # Fields with choices get coerced into `ChoiceField` +            # instead of using their regular typed field. +            field_class = self.serializer_choice_field + +        if not issubclass(field_class, ModelField): +            # `model_field` is only valid for the fallback case of +            # `ModelField`, which is used when no other typed field +            # matched to the model field. +            field_kwargs.pop('model_field', None) + +        if not issubclass(field_class, CharField) and not issubclass(field_class, ChoiceField): +            # `allow_blank` is only valid for textual fields. +            field_kwargs.pop('allow_blank', None) + +        if postgres_fields and isinstance(model_field, postgres_fields.ArrayField): +            # Populate the `child` argument on `ListField` instances generated +            # for the PostgrSQL specfic `ArrayField`. +            child_model_field = model_field.base_field +            child_field_class, child_field_kwargs = self.build_standard_field( +                'child', child_model_field +            ) +            field_kwargs['child'] = child_field_class(**child_field_kwargs) -        unique_constraint_names -= set([None]) +        return field_class, field_kwargs -        # Include each of the `unique_together` field names, -        # so long as all the field names are included on the serializer. -        for parent_class in [model] + list(model._meta.parents.keys()): -            for unique_together_list in parent_class._meta.unique_together: -                if set(fields).issuperset(set(unique_together_list)): -                    unique_constraint_names |= set(unique_together_list) +    def build_relational_field(self, field_name, relation_info): +        """ +        Create fields for forward and reverse relationships. +        """ +        field_class = self.serializer_related_field +        field_kwargs = get_relation_kwargs(field_name, relation_info) -        # Now we have all the field names that have uniqueness constraints -        # applied, we can add the extra 'required=...' or 'default=...' -        # arguments that are appropriate to these fields, or add a `HiddenField` for it. -        for unique_constraint_name in unique_constraint_names: -            # Get the model field that is referred too. -            unique_constraint_field = model._meta.get_field(unique_constraint_name) +        # `view_name` is only valid for hyperlinked relationships. +        if not issubclass(field_class, HyperlinkedRelatedField): +            field_kwargs.pop('view_name', None) -            if getattr(unique_constraint_field, 'auto_now_add', None): -                default = CreateOnlyDefault(timezone.now) -            elif getattr(unique_constraint_field, 'auto_now', None): -                default = timezone.now -            elif unique_constraint_field.has_default(): -                default = unique_constraint_field.default -            else: -                default = empty +        return field_class, field_kwargs -            if unique_constraint_name in model_field_mapping: -                # The corresponding field is present in the serializer -                if unique_constraint_name not in extra_kwargs: -                    extra_kwargs[unique_constraint_name] = {} -                if default is empty: -                    if 'required' not in extra_kwargs[unique_constraint_name]: -                        extra_kwargs[unique_constraint_name]['required'] = True -                else: -                    if 'default' not in extra_kwargs[unique_constraint_name]: -                        extra_kwargs[unique_constraint_name]['default'] = default -            elif default is not empty: -                # The corresponding field is not present in the, -                # serializer. We have a default to use for it, so -                # add in a hidden field that populates it. -                hidden_fields[unique_constraint_name] = HiddenField(default=default) +    def build_nested_field(self, field_name, relation_info, nested_depth): +        """ +        Create nested fields for forward and reverse relationships. +        """ +        class NestedSerializer(ModelSerializer): +            class Meta: +                model = relation_info.related_model +                depth = nested_depth -        # Now determine the fields that should be included on the serializer. -        for field_name in fields: -            if field_name in declared_fields: -                # Field is explicitly declared on the class, use that. -                ret[field_name] = declared_fields[field_name] -                continue +        field_class = NestedSerializer +        field_kwargs = get_nested_relation_kwargs(relation_info) -            elif field_name in info.fields_and_pk: -                # Create regular model fields. -                model_field = info.fields_and_pk[field_name] -                field_cls = self._field_mapping[model_field] -                kwargs = get_field_kwargs(field_name, model_field) -                if 'choices' in kwargs: -                    # Fields with choices get coerced into `ChoiceField` -                    # instead of using their regular typed field. -                    field_cls = ChoiceField -                if not issubclass(field_cls, ModelField): -                    # `model_field` is only valid for the fallback case of -                    # `ModelField`, which is used when no other typed field -                    # matched to the model field. -                    kwargs.pop('model_field', None) -                if not issubclass(field_cls, CharField) and not issubclass(field_cls, ChoiceField): -                    # `allow_blank` is only valid for textual fields. -                    kwargs.pop('allow_blank', None) - -            elif field_name in info.relations: -                # Create forward and reverse relationships. -                relation_info = info.relations[field_name] -                if depth: -                    field_cls = self._get_nested_class(depth, relation_info) -                    kwargs = get_nested_relation_kwargs(relation_info) -                else: -                    field_cls = self._related_class -                    kwargs = get_relation_kwargs(field_name, relation_info) -                    # `view_name` is only valid for hyperlinked relationships. -                    if not issubclass(field_cls, HyperlinkedRelatedField): -                        kwargs.pop('view_name', None) - -            elif hasattr(model, field_name): -                # Create a read only field for model methods and properties. -                field_cls = ReadOnlyField -                kwargs = {} - -            elif field_name == api_settings.URL_FIELD_NAME: -                # Create the URL field. -                field_cls = HyperlinkedIdentityField -                kwargs = get_url_kwargs(model) +        return field_class, field_kwargs -            else: -                raise ImproperlyConfigured( -                    'Field name `%s` is not valid for model `%s`.' % -                    (field_name, model.__class__.__name__) -                ) +    def build_property_field(self, field_name, model_class): +        """ +        Create a read only field for model methods and properties. +        """ +        field_class = ReadOnlyField +        field_kwargs = {} -            # Populate any kwargs defined in `Meta.extra_kwargs` -            extras = extra_kwargs.get(field_name, {}) -            if extras.get('read_only', False): -                for attr in [ -                    'required', 'default', 'allow_blank', 'allow_null', -                    'min_length', 'max_length', 'min_value', 'max_value', -                    'validators', 'queryset' -                ]: -                    kwargs.pop(attr, None) +        return field_class, field_kwargs -            if extras.get('default') and kwargs.get('required') is False: -                kwargs.pop('required') +    def build_url_field(self, field_name, model_class): +        """ +        Create a field representing the object's own URL. +        """ +        field_class = self.serializer_url_field +        field_kwargs = get_url_kwargs(model_class) -            kwargs.update(extras) +        return field_class, field_kwargs -            # Create the serializer field. -            ret[field_name] = field_cls(**kwargs) +    def build_unknown_field(self, field_name, model_class): +        """ +        Raise an error on any unknown fields. +        """ +        raise ImproperlyConfigured( +            'Field name `%s` is not valid for model `%s`.' % +            (field_name, model_class.__name__) +        ) -        for field_name, field in hidden_fields.items(): -            ret[field_name] = field +    def include_extra_kwargs(self, kwargs, extra_kwargs): +        """ +        Include any 'extra_kwargs' that have been included for this field, +        possibly removing any incompatible existing keyword arguments. +        """ +        if extra_kwargs.get('read_only', False): +            for attr in [ +                'required', 'default', 'allow_blank', 'allow_null', +                'min_length', 'max_length', 'min_value', 'max_value', +                'validators', 'queryset' +            ]: +                kwargs.pop(attr, None) -        return ret +        if extra_kwargs.get('default') and kwargs.get('required') is False: +            kwargs.pop('required') + +        kwargs.update(extra_kwargs) + +        return kwargs + +    # Methods for determining additional keyword arguments to apply... + +    def get_extra_kwargs(self): +        """ +        Return a dictionary mapping field names to a dictionary of +        additional keyword arguments. +        """ +        extra_kwargs = getattr(self.Meta, 'extra_kwargs', {}) -    def _include_additional_options(self, extra_kwargs):          read_only_fields = getattr(self.Meta, 'read_only_fields', None)          if read_only_fields is not None:              for field_name in read_only_fields: @@ -1081,9 +1105,9 @@ class ModelSerializer(Serializer):          write_only_fields = getattr(self.Meta, 'write_only_fields', None)          if write_only_fields is not None:              warnings.warn( -                "The `Meta.write_only_fields` option is pending deprecation. " +                "The `Meta.write_only_fields` option is deprecated. "                  "Use `Meta.extra_kwargs={<field_name>: {'write_only': True}}` instead.", -                PendingDeprecationWarning, +                DeprecationWarning,                  stacklevel=3              )              for field_name in write_only_fields: @@ -1094,9 +1118,9 @@ class ModelSerializer(Serializer):          view_name = getattr(self.Meta, 'view_name', None)          if view_name is not None:              warnings.warn( -                "The `Meta.view_name` option is pending deprecation. " +                "The `Meta.view_name` option is deprecated. "                  "Use `Meta.extra_kwargs={'url': {'view_name': ...}}` instead.", -                PendingDeprecationWarning, +                DeprecationWarning,                  stacklevel=3              )              kwargs = extra_kwargs.get(api_settings.URL_FIELD_NAME, {}) @@ -1106,9 +1130,9 @@ class ModelSerializer(Serializer):          lookup_field = getattr(self.Meta, 'lookup_field', None)          if lookup_field is not None:              warnings.warn( -                "The `Meta.lookup_field` option is pending deprecation. " +                "The `Meta.lookup_field` option is deprecated. "                  "Use `Meta.extra_kwargs={'url': {'lookup_field': ...}}` instead.", -                PendingDeprecationWarning, +                DeprecationWarning,                  stacklevel=3              )              kwargs = extra_kwargs.get(api_settings.URL_FIELD_NAME, {}) @@ -1117,31 +1141,215 @@ class ModelSerializer(Serializer):          return extra_kwargs -    def _get_default_field_names(self, declared_fields, model_info): +    def get_uniqueness_extra_kwargs(self, field_names, declared_fields, extra_kwargs): +        """ +        Return any additional field options that need to be included as a +        result of uniqueness constraints on the model. This is returned as +        a two-tuple of: + +        ('dict of updated extra kwargs', 'mapping of hidden fields') +        """ +        model = getattr(self.Meta, 'model') +        model_fields = self._get_model_fields( +            field_names, declared_fields, extra_kwargs +        ) + +        # Determine if we need any additional `HiddenField` or extra keyword +        # arguments to deal with `unique_for` dates that are required to +        # be in the input data in order to validate it. +        unique_constraint_names = set() + +        for model_field in model_fields.values(): +            # Include each of the `unique_for_*` field names. +            unique_constraint_names |= set([ +                model_field.unique_for_date, +                model_field.unique_for_month, +                model_field.unique_for_year +            ]) + +        unique_constraint_names -= set([None]) + +        # Include each of the `unique_together` field names, +        # so long as all the field names are included on the serializer. +        for parent_class in [model] + list(model._meta.parents.keys()): +            for unique_together_list in parent_class._meta.unique_together: +                if set(field_names).issuperset(set(unique_together_list)): +                    unique_constraint_names |= set(unique_together_list) + +        # Now we have all the field names that have uniqueness constraints +        # applied, we can add the extra 'required=...' or 'default=...' +        # arguments that are appropriate to these fields, or add a `HiddenField` for it. +        hidden_fields = {} +        uniqueness_extra_kwargs = {} + +        for unique_constraint_name in unique_constraint_names: +            # Get the model field that is referred too. +            unique_constraint_field = model._meta.get_field(unique_constraint_name) + +            if getattr(unique_constraint_field, 'auto_now_add', None): +                default = CreateOnlyDefault(timezone.now) +            elif getattr(unique_constraint_field, 'auto_now', None): +                default = timezone.now +            elif unique_constraint_field.has_default(): +                default = unique_constraint_field.default +            else: +                default = empty + +            if unique_constraint_name in model_fields: +                # The corresponding field is present in the serializer +                if default is empty: +                    uniqueness_extra_kwargs[unique_constraint_name] = {'required': True} +                else: +                    uniqueness_extra_kwargs[unique_constraint_name] = {'default': default} +            elif default is not empty: +                # The corresponding field is not present in the, +                # serializer. We have a default to use for it, so +                # add in a hidden field that populates it. +                hidden_fields[unique_constraint_name] = HiddenField(default=default) + +        # Update `extra_kwargs` with any new options. +        for key, value in uniqueness_extra_kwargs.items(): +            if key in extra_kwargs: +                extra_kwargs[key].update(value) +            else: +                extra_kwargs[key] = value + +        return extra_kwargs, hidden_fields + +    def _get_model_fields(self, field_names, declared_fields, extra_kwargs): +        """ +        Returns all the model fields that are being mapped to by fields +        on the serializer class. +        Returned as a dict of 'model field name' -> 'model field'. +        Used internally by `get_uniqueness_field_options`. +        """ +        model = getattr(self.Meta, 'model') +        model_fields = {} + +        for field_name in field_names: +            if field_name in declared_fields: +                # If the field is declared on the serializer +                field = declared_fields[field_name] +                source = field.source or field_name +            else: +                try: +                    source = extra_kwargs[field_name]['source'] +                except KeyError: +                    source = field_name + +            if '.' in source or source == '*': +                # Model fields will always have a simple source mapping, +                # they can't be nested attribute lookups. +                continue + +            try: +                field = model._meta.get_field(source) +                if isinstance(field, DjangoModelField): +                    model_fields[source] = field +            except FieldDoesNotExist: +                pass + +        return model_fields + +    # Determine the validators to apply... + +    def get_validators(self): +        """ +        Determine the set of validators to use when instantiating serializer. +        """ +        # If the validators have been declared explicitly then use that. +        validators = getattr(getattr(self, 'Meta', None), 'validators', None) +        if validators is not None: +            return validators[:] + +        # Otherwise use the default set of validators.          return ( -            [model_info.pk.name] + -            list(declared_fields.keys()) + -            list(model_info.fields.keys()) + -            list(model_info.forward_relations.keys()) +            self.get_unique_together_validators() + +            self.get_unique_for_date_validators()          ) -    def _get_nested_class(self, nested_depth, relation_info): -        class NestedSerializer(ModelSerializer): -            class Meta: -                model = relation_info.related -                depth = nested_depth - 1 +    def get_unique_together_validators(self): +        """ +        Determine a default set of validators for any unique_together contraints. +        """ +        model_class_inheritance_tree = ( +            [self.Meta.model] + +            list(self.Meta.model._meta.parents.keys()) +        ) + +        # The field names we're passing though here only include fields +        # which may map onto a model field. Any dotted field name lookups +        # cannot map to a field, and must be a traversal, so we're not +        # including those. +        field_names = set([ +            field.source for field in self.fields.values() +            if (field.source != '*') and ('.' not in field.source) +        ]) + +        # Note that we make sure to check `unique_together` both on the +        # base model class, but also on any parent classes. +        validators = [] +        for parent_class in model_class_inheritance_tree: +            for unique_together in parent_class._meta.unique_together: +                if field_names.issuperset(set(unique_together)): +                    validator = UniqueTogetherValidator( +                        queryset=parent_class._default_manager, +                        fields=unique_together +                    ) +                    validators.append(validator) +        return validators + +    def get_unique_for_date_validators(self): +        """ +        Determine a default set of validators for the following contraints: + +        * unique_for_date +        * unique_for_month +        * unique_for_year +        """ +        info = model_meta.get_field_info(self.Meta.model) +        default_manager = self.Meta.model._default_manager +        field_names = [field.source for field in self.fields.values()] + +        validators = [] + +        for field_name, field in info.fields_and_pk.items(): +            if field.unique_for_date and field_name in field_names: +                validator = UniqueForDateValidator( +                    queryset=default_manager, +                    field=field_name, +                    date_field=field.unique_for_date +                ) +                validators.append(validator) -        return NestedSerializer +            if field.unique_for_month and field_name in field_names: +                validator = UniqueForMonthValidator( +                    queryset=default_manager, +                    field=field_name, +                    date_field=field.unique_for_month +                ) +                validators.append(validator) + +            if field.unique_for_year and field_name in field_names: +                validator = UniqueForYearValidator( +                    queryset=default_manager, +                    field=field_name, +                    date_field=field.unique_for_year +                ) +                validators.append(validator) + +        return validators  if hasattr(models, 'UUIDField'): -    ModelSerializer._field_mapping[models.UUIDField] = UUIDField +    ModelSerializer.serializer_field_mapping[models.UUIDField] = UUIDField  if postgres_fields:      class CharMappingField(DictField):          child = CharField() -    ModelSerializer._field_mapping[postgres_fields.HStoreField] = CharMappingField +    ModelSerializer.serializer_field_mapping[postgres_fields.HStoreField] = CharMappingField +    ModelSerializer.serializer_field_mapping[postgres_fields.ArrayField] = ListField  class HyperlinkedModelSerializer(ModelSerializer): @@ -1152,9 +1360,13 @@ class HyperlinkedModelSerializer(ModelSerializer):      * A 'url' field is included instead of the 'id' field.      * Relationships to other instances are hyperlinks, instead of primary keys.      """ -    _related_class = HyperlinkedRelatedField +    serializer_related_field = HyperlinkedRelatedField -    def _get_default_field_names(self, declared_fields, model_info): +    def get_default_field_names(self, declared_fields, model_info): +        """ +        Return the default list of field names that will be used if the +        `Meta.fields` option is not specified. +        """          return (              [api_settings.URL_FIELD_NAME] +              list(declared_fields.keys()) + @@ -1162,10 +1374,16 @@ class HyperlinkedModelSerializer(ModelSerializer):              list(model_info.forward_relations.keys())          ) -    def _get_nested_class(self, nested_depth, relation_info): +    def build_nested_field(self, field_name, relation_info, nested_depth): +        """ +        Create nested fields for forward and reverse relationships. +        """          class NestedSerializer(HyperlinkedModelSerializer):              class Meta: -                model = relation_info.related +                model = relation_info.related_model                  depth = nested_depth - 1 -        return NestedSerializer +        field_class = NestedSerializer +        field_kwargs = get_nested_relation_kwargs(relation_info) + +        return field_class, field_kwargs diff --git a/rest_framework/settings.py b/rest_framework/settings.py index e5e5edaf..7331f265 100644 --- a/rest_framework/settings.py +++ b/rest_framework/settings.py @@ -5,11 +5,11 @@ For example your project's `settings.py` file might look like this:  REST_FRAMEWORK = {      'DEFAULT_RENDERER_CLASSES': (          'rest_framework.renderers.JSONRenderer', -        'rest_framework.renderers.YAMLRenderer', +        'rest_framework.renderers.TemplateHTMLRenderer',      )      'DEFAULT_PARSER_CLASSES': (          'rest_framework.parsers.JSONParser', -        'rest_framework.parsers.YAMLParser', +        'rest_framework.parsers.TemplateHTMLRenderer',      )  } @@ -47,9 +47,10 @@ DEFAULTS = {      'DEFAULT_THROTTLE_CLASSES': (),      'DEFAULT_CONTENT_NEGOTIATION_CLASS': 'rest_framework.negotiation.DefaultContentNegotiation',      'DEFAULT_METADATA_CLASS': 'rest_framework.metadata.SimpleMetadata', +    'DEFAULT_VERSIONING_CLASS': None,      # Generic view behavior -    'DEFAULT_PAGINATION_SERIALIZER_CLASS': 'rest_framework.pagination.PaginationSerializer', +    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',      'DEFAULT_FILTER_BACKENDS': (),      # Throttling @@ -68,6 +69,11 @@ DEFAULTS = {      'SEARCH_PARAM': 'search',      'ORDERING_PARAM': 'ordering', +    # Versioning +    'DEFAULT_VERSION': None, +    'ALLOWED_VERSIONS': None, +    'VERSION_PARAM': 'version', +      # Authentication      'UNAUTHENTICATED_USER': 'django.contrib.auth.models.AnonymousUser',      'UNAUTHENTICATED_TOKEN': None, @@ -124,7 +130,8 @@ IMPORT_STRINGS = (      'DEFAULT_THROTTLE_CLASSES',      'DEFAULT_CONTENT_NEGOTIATION_CLASS',      'DEFAULT_METADATA_CLASS', -    'DEFAULT_PAGINATION_SERIALIZER_CLASS', +    'DEFAULT_VERSIONING_CLASS', +    'DEFAULT_PAGINATION_CLASS',      'DEFAULT_FILTER_BACKENDS',      'EXCEPTION_HANDLER',      'TEST_REQUEST_RENDERER_CLASSES', @@ -140,7 +147,9 @@ def perform_import(val, setting_name):      If the given setting is a string import notation,      then perform the necessary import or imports.      """ -    if isinstance(val, six.string_types): +    if val is None: +        return None +    elif isinstance(val, six.string_types):          return import_from_string(val, setting_name)      elif isinstance(val, (list, tuple)):          return [import_from_string(item, setting_name) for item in val] diff --git a/rest_framework/static/rest_framework/css/bootstrap-tweaks.css b/rest_framework/static/rest_framework/css/bootstrap-tweaks.css index 36c7be48..04f12ed3 100644 --- a/rest_framework/static/rest_framework/css/bootstrap-tweaks.css +++ b/rest_framework/static/rest_framework/css/bootstrap-tweaks.css @@ -60,6 +60,23 @@ a single block in the template.    color: #C20000;  } +.pagination>.disabled>a, +.pagination>.disabled>a:hover, +.pagination>.disabled>a:focus { +  cursor: not-allowed; +  pointer-events: none; +} + +.pager>.disabled>a, +.pager>.disabled>a:hover, +.pager>.disabled>a:focus { +  pointer-events: none; +} + +.pager .next { +  margin-left: 10px; +} +  /*=== dabapps bootstrap styles ====*/  html { @@ -185,10 +202,6 @@ body a:hover {    color: #c20000;  } -#content a span { -  text-decoration: underline; - } -  .request-info {    clear:both;  } diff --git a/rest_framework/templates/rest_framework/base.html b/rest_framework/templates/rest_framework/base.html index e9668193..877387f2 100644 --- a/rest_framework/templates/rest_framework/base.html +++ b/rest_framework/templates/rest_framework/base.html @@ -119,9 +119,18 @@                      <div class="page-header">                          <h1>{{ name }}</h1>                      </div> +                    <div style="float:left">                      {% block description %}                          {{ description }}                      {% endblock %} +                    </div> + +                    {% if paginator %} +                        <nav style="float: right"> +                        {% get_pagination_html paginator %} +                        </nav> +                    {% endif %} +                      <div class="request-info" style="clear: both" >                          <pre class="prettyprint"><b>{{ request.method }}</b> {{ request.get_full_path }}</pre>                      </div> diff --git a/rest_framework/templates/rest_framework/pagination/numbers.html b/rest_framework/templates/rest_framework/pagination/numbers.html new file mode 100644 index 00000000..04045810 --- /dev/null +++ b/rest_framework/templates/rest_framework/pagination/numbers.html @@ -0,0 +1,27 @@ +<ul class="pagination" style="margin: 5px 0 10px 0"> +    {% if previous_url %} +        <li><a href="{{ previous_url }}" aria-label="Previous"><span aria-hidden="true">«</span></a></li> +    {% else %} +        <li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">«</span></a></li> +    {% endif %} + +    {% for page_link in page_links %} +        {% if page_link.is_break %} +            <li class="disabled"> +                <a href="#"><span aria-hidden="true">…</span></a> +            </li> +        {% else %} +            {% if page_link.is_active %} +                <li class="active"><a href="{{ page_link.url }}">{{ page_link.number }}</a></li> +            {% else %} +                <li><a href="{{ page_link.url }}">{{ page_link.number }}</a></li> +            {% endif %} +        {% endif %} +    {% endfor %} + +    {% if next_url %} +        <li><a href="{{ next_url }}" aria-label="Next"><span aria-hidden="true">»</span></a></li> +    {% else %} +        <li class="disabled"><a href="#" aria-label="Next"><span aria-hidden="true">»</span></a></li> +    {% endif %} +</ul> diff --git a/rest_framework/templates/rest_framework/pagination/previous_and_next.html b/rest_framework/templates/rest_framework/pagination/previous_and_next.html new file mode 100644 index 00000000..eacbfff4 --- /dev/null +++ b/rest_framework/templates/rest_framework/pagination/previous_and_next.html @@ -0,0 +1,12 @@ +<ul class="pager"> +{% if previous_url %} +    <li class="previous"><a href="{{ previous_url }}">« Previous</a></li> +{% else %} +    <li class="previous disabled"><a href="#">« Previous</a></li> +{% endif %} +{% if next_url %} +    <li class="next"><a href="{{ next_url }}">Next »</a></li> +{% else %} +    <li class="next disabled"><a href="#">Next »</li> +{% endif %} +</ul> diff --git a/rest_framework/templatetags/rest_framework.py b/rest_framework/templatetags/rest_framework.py index d66ffb33..699ea897 100644 --- a/rest_framework/templatetags/rest_framework.py +++ b/rest_framework/templatetags/rest_framework.py @@ -1,36 +1,25 @@  from __future__ import unicode_literals, absolute_import  from django import template  from django.core.urlresolvers import reverse, NoReverseMatch -from django.http import QueryDict  from django.utils import six -from django.utils.six.moves.urllib import parse as urlparse  from django.utils.encoding import iri_to_uri, force_text  from django.utils.html import escape  from django.utils.safestring import SafeData, mark_safe  from django.utils.html import smart_urlquote  from rest_framework.renderers import HTMLFormRenderer +from rest_framework.utils.urls import replace_query_param  import re  register = template.Library() - -def replace_query_param(url, key, val): -    """ -    Given a URL and a key/val pair, set or replace an item in the query -    parameters of the URL, and return the new URL. -    """ -    (scheme, netloc, path, query, fragment) = urlparse.urlsplit(url) -    query_dict = QueryDict(query).copy() -    query_dict[key] = val -    query = query_dict.urlencode() -    return urlparse.urlunsplit((scheme, netloc, path, query, fragment)) - -  # Regex for adding classes to html snippets  class_re = re.compile(r'(?<=class=["\'])(.*)(?=["\'])') -# And the template tags themselves... +@register.simple_tag +def get_pagination_html(pager): +    return pager.to_html() +  @register.simple_tag  def render_field(field, style=None): diff --git a/rest_framework/utils/encoders.py b/rest_framework/utils/encoders.py index bf753271..2160d18b 100644 --- a/rest_framework/utils/encoders.py +++ b/rest_framework/utils/encoders.py @@ -6,11 +6,9 @@ from django.db.models.query import QuerySet  from django.utils import six, timezone  from django.utils.encoding import force_text  from django.utils.functional import Promise -from rest_framework.compat import OrderedDict, total_seconds -from rest_framework.utils.serializer_helpers import ReturnDict, ReturnList +from rest_framework.compat import total_seconds  import datetime  import decimal -import types  import json  import uuid @@ -61,65 +59,3 @@ class JSONEncoder(json.JSONEncoder):          elif hasattr(obj, '__iter__'):              return tuple(item for item in obj)          return super(JSONEncoder, self).default(obj) - - -try: -    import yaml -except ImportError: -    SafeDumper = None -else: -    # Adapted from http://pyyaml.org/attachment/ticket/161/use_ordered_dict.py -    class SafeDumper(yaml.SafeDumper): -        """ -        Handles decimals as strings. -        Handles OrderedDicts as usual dicts, but preserves field order, rather -        than the usual behaviour of sorting the keys. -        """ -        def represent_decimal(self, data): -            return self.represent_scalar('tag:yaml.org,2002:str', six.text_type(data)) - -        def represent_mapping(self, tag, mapping, flow_style=None): -            value = [] -            node = yaml.MappingNode(tag, value, flow_style=flow_style) -            if self.alias_key is not None: -                self.represented_objects[self.alias_key] = node -            best_style = True -            if hasattr(mapping, 'items'): -                mapping = list(mapping.items()) -                if not isinstance(mapping, OrderedDict): -                    mapping.sort() -            for item_key, item_value in mapping: -                node_key = self.represent_data(item_key) -                node_value = self.represent_data(item_value) -                if not (isinstance(node_key, yaml.ScalarNode) and not node_key.style): -                    best_style = False -                if not (isinstance(node_value, yaml.ScalarNode) and not node_value.style): -                    best_style = False -                value.append((node_key, node_value)) -            if flow_style is None: -                if self.default_flow_style is not None: -                    node.flow_style = self.default_flow_style -                else: -                    node.flow_style = best_style -            return node - -    SafeDumper.add_representer( -        decimal.Decimal, -        SafeDumper.represent_decimal -    ) -    SafeDumper.add_representer( -        OrderedDict, -        yaml.representer.SafeRepresenter.represent_dict -    ) -    SafeDumper.add_representer( -        ReturnDict, -        yaml.representer.SafeRepresenter.represent_dict -    ) -    SafeDumper.add_representer( -        ReturnList, -        yaml.representer.SafeRepresenter.represent_list -    ) -    SafeDumper.add_representer( -        types.GeneratorType, -        yaml.representer.SafeRepresenter.represent_list -    ) diff --git a/rest_framework/utils/formatting.py b/rest_framework/utils/formatting.py index 470af51b..8b6f005e 100644 --- a/rest_framework/utils/formatting.py +++ b/rest_framework/utils/formatting.py @@ -2,12 +2,10 @@  Utility functions to return a formatted name and description for a given view.  """  from __future__ import unicode_literals -import re -  from django.utils.html import escape  from django.utils.safestring import mark_safe -  from rest_framework.compat import apply_markdown, force_text +import re  def remove_trailing_string(content, trailing): @@ -59,4 +57,5 @@ def markup_description(description):          description = apply_markdown(description)      else:          description = escape(description).replace('\n', '<br />') +        description = '<p>' + description + '</p>'      return mark_safe(description) diff --git a/rest_framework/utils/model_meta.py b/rest_framework/utils/model_meta.py index 6a5835f5..dd92f8b6 100644 --- a/rest_framework/utils/model_meta.py +++ b/rest_framework/utils/model_meta.py @@ -24,7 +24,7 @@ FieldInfo = namedtuple('FieldResult', [  RelationInfo = namedtuple('RelationInfo', [      'model_field', -    'related', +    'related_model',      'to_many',      'has_through_model'  ]) @@ -98,7 +98,7 @@ def _get_forward_relationships(opts):      for field in [field for field in opts.fields if field.serialize and field.rel]:          forward_relations[field.name] = RelationInfo(              model_field=field, -            related=_resolve_model(field.rel.to), +            related_model=_resolve_model(field.rel.to),              to_many=False,              has_through_model=False          ) @@ -107,7 +107,7 @@ def _get_forward_relationships(opts):      for field in [field for field in opts.many_to_many if field.serialize]:          forward_relations[field.name] = RelationInfo(              model_field=field, -            related=_resolve_model(field.rel.to), +            related_model=_resolve_model(field.rel.to),              to_many=True,              has_through_model=(                  not field.rel.through._meta.auto_created @@ -131,7 +131,7 @@ def _get_reverse_relationships(opts):          related = getattr(relation, 'related_model', relation.model)          reverse_relations[accessor_name] = RelationInfo(              model_field=None, -            related=related, +            related_model=related,              to_many=relation.field.rel.multiple,              has_through_model=False          ) @@ -142,7 +142,7 @@ def _get_reverse_relationships(opts):          related = getattr(relation, 'related_model', relation.model)          reverse_relations[accessor_name] = RelationInfo(              model_field=None, -            related=related, +            related_model=related,              to_many=True,              has_through_model=(                  (getattr(relation.field.rel, 'through', None) is not None) diff --git a/rest_framework/utils/urls.py b/rest_framework/utils/urls.py new file mode 100644 index 00000000..880ef9ed --- /dev/null +++ b/rest_framework/utils/urls.py @@ -0,0 +1,25 @@ +from django.utils.six.moves.urllib import parse as urlparse + + +def replace_query_param(url, key, val): +    """ +    Given a URL and a key/val pair, set or replace an item in the query +    parameters of the URL, and return the new URL. +    """ +    (scheme, netloc, path, query, fragment) = urlparse.urlsplit(url) +    query_dict = urlparse.parse_qs(query) +    query_dict[key] = [val] +    query = urlparse.urlencode(sorted(list(query_dict.items())), doseq=True) +    return urlparse.urlunsplit((scheme, netloc, path, query, fragment)) + + +def remove_query_param(url, key): +    """ +    Given a URL and a key/val pair, remove an item in the query +    parameters of the URL, and return the new URL. +    """ +    (scheme, netloc, path, query, fragment) = urlparse.urlsplit(url) +    query_dict = urlparse.parse_qs(query) +    query_dict.pop(key, None) +    query = urlparse.urlencode(sorted(list(query_dict.items())), doseq=True) +    return urlparse.urlunsplit((scheme, netloc, path, query, fragment)) diff --git a/rest_framework/versioning.py b/rest_framework/versioning.py new file mode 100644 index 00000000..51b886f3 --- /dev/null +++ b/rest_framework/versioning.py @@ -0,0 +1,177 @@ +# coding: utf-8 +from __future__ import unicode_literals +from django.utils.translation import ugettext_lazy as _ +from rest_framework import exceptions +from rest_framework.compat import unicode_http_header +from rest_framework.reverse import _reverse +from rest_framework.settings import api_settings +from rest_framework.templatetags.rest_framework import replace_query_param +from rest_framework.utils.mediatypes import _MediaType +import re + + +class BaseVersioning(object): +    default_version = api_settings.DEFAULT_VERSION +    allowed_versions = api_settings.ALLOWED_VERSIONS +    version_param = api_settings.VERSION_PARAM + +    def determine_version(self, request, *args, **kwargs): +        msg = '{cls}.determine_version() must be implemented.' +        raise NotImplementedError(msg.format( +            cls=self.__class__.__name__ +        )) + +    def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra): +        return _reverse(viewname, args, kwargs, request, format, **extra) + +    def is_allowed_version(self, version): +        if not self.allowed_versions: +            return True +        return (version == self.default_version) or (version in self.allowed_versions) + + +class AcceptHeaderVersioning(BaseVersioning): +    """ +    GET /something/ HTTP/1.1 +    Host: example.com +    Accept: application/json; version=1.0 +    """ +    invalid_version_message = _('Invalid version in "Accept" header.') + +    def determine_version(self, request, *args, **kwargs): +        media_type = _MediaType(request.accepted_media_type) +        version = media_type.params.get(self.version_param, self.default_version) +        version = unicode_http_header(version) +        if not self.is_allowed_version(version): +            raise exceptions.NotAcceptable(self.invalid_version_message) +        return version + +    # We don't need to implement `reverse`, as the versioning is based +    # on the `Accept` header, not on the request URL. + + +class URLPathVersioning(BaseVersioning): +    """ +    To the client this is the same style as `NamespaceVersioning`. +    The difference is in the backend - this implementation uses +    Django's URL keyword arguments to determine the version. + +    An example URL conf for two views that accept two different versions. + +    urlpatterns = [ +        url(r'^(?P<version>{v1,v2})/users/$', users_list, name='users-list'), +        url(r'^(?P<version>{v1,v2})/users/(?P<pk>[0-9]+)/$', users_detail, name='users-detail') +    ] + +    GET /1.0/something/ HTTP/1.1 +    Host: example.com +    Accept: application/json +    """ +    invalid_version_message = _('Invalid version in URL path.') + +    def determine_version(self, request, *args, **kwargs): +        version = kwargs.get(self.version_param, self.default_version) +        if not self.is_allowed_version(version): +            raise exceptions.NotFound(self.invalid_version_message) +        return version + +    def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra): +        if request.version is not None: +            kwargs = {} if (kwargs is None) else kwargs +            kwargs[self.version_param] = request.version + +        return super(URLPathVersioning, self).reverse( +            viewname, args, kwargs, request, format, **extra +        ) + + +class NamespaceVersioning(BaseVersioning): +    """ +    To the client this is the same style as `URLPathVersioning`. +    The difference is in the backend - this implementation uses +    Django's URL namespaces to determine the version. + +    An example URL conf that is namespaced into two seperate versions + +    # users/urls.py +    urlpatterns = [ +        url(r'^/users/$', users_list, name='users-list'), +        url(r'^/users/(?P<pk>[0-9]+)/$', users_detail, name='users-detail') +    ] + +    # urls.py +    urlpatterns = [ +        url(r'^v1/', include('users.urls', namespace='v1')), +        url(r'^v2/', include('users.urls', namespace='v2')) +    ] + +    GET /1.0/something/ HTTP/1.1 +    Host: example.com +    Accept: application/json +    """ +    invalid_version_message = _('Invalid version in URL path.') + +    def determine_version(self, request, *args, **kwargs): +        resolver_match = getattr(request, 'resolver_match', None) +        if (resolver_match is None or not resolver_match.namespace): +            return self.default_version +        version = resolver_match.namespace +        if not self.is_allowed_version(version): +            raise exceptions.NotFound(self.invalid_version_message) +        return version + +    def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra): +        if request.version is not None: +            viewname = self.get_versioned_viewname(viewname, request) +        return super(NamespaceVersioning, self).reverse( +            viewname, args, kwargs, request, format, **extra +        ) + +    def get_versioned_viewname(self, viewname, request): +        return request.version + ':' + viewname + + +class HostNameVersioning(BaseVersioning): +    """ +    GET /something/ HTTP/1.1 +    Host: v1.example.com +    Accept: application/json +    """ +    hostname_regex = re.compile(r'^([a-zA-Z0-9]+)\.[a-zA-Z0-9]+\.[a-zA-Z0-9]+$') +    invalid_version_message = _('Invalid version in hostname.') + +    def determine_version(self, request, *args, **kwargs): +        hostname, seperator, port = request.get_host().partition(':') +        match = self.hostname_regex.match(hostname) +        if not match: +            return self.default_version +        version = match.group(1) +        if not self.is_allowed_version(version): +            raise exceptions.NotFound(self.invalid_version_message) +        return version + +    # We don't need to implement `reverse`, as the hostname will already be +    # preserved as part of the REST framework `reverse` implementation. + + +class QueryParameterVersioning(BaseVersioning): +    """ +    GET /something/?version=0.1 HTTP/1.1 +    Host: example.com +    Accept: application/json +    """ +    invalid_version_message = _('Invalid version in query parameter.') + +    def determine_version(self, request, *args, **kwargs): +        version = request.query_params.get(self.version_param) +        if not self.is_allowed_version(version): +            raise exceptions.NotFound(self.invalid_version_message) +        return version + +    def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra): +        url = super(QueryParameterVersioning, self).reverse( +            viewname, args, kwargs, request, format, **extra +        ) +        if request.version is not None: +            return replace_query_param(url, self.version_param, request.version) +        return url diff --git a/rest_framework/views.py b/rest_framework/views.py index bc870417..b4abc4d9 100644 --- a/rest_framework/views.py +++ b/rest_framework/views.py @@ -2,10 +2,11 @@  Provides an APIView class that is the base of all views in REST framework.  """  from __future__ import unicode_literals -  from django.core.exceptions import PermissionDenied  from django.http import Http404 +from django.utils import six  from django.utils.encoding import smart_text +from django.utils.translation import ugettext_lazy as _  from django.views.decorators.csrf import csrf_exempt  from rest_framework import status, exceptions  from rest_framework.compat import HttpResponseBase, View @@ -13,6 +14,8 @@ from rest_framework.request import Request  from rest_framework.response import Response  from rest_framework.settings import api_settings  from rest_framework.utils import formatting +import inspect +import warnings  def get_view_name(view_cls, suffix=None): @@ -46,7 +49,7 @@ def get_view_description(view_cls, html=False):      return description -def exception_handler(exc): +def exception_handler(exc, context):      """      Returns the response that should be used for any given exception. @@ -72,11 +75,13 @@ def exception_handler(exc):          return Response(data, status=exc.status_code, headers=headers)      elif isinstance(exc, Http404): -        data = {'detail': 'Not found'} +        msg = _('Not found.') +        data = {'detail': six.text_type(msg)}          return Response(data, status=status.HTTP_404_NOT_FOUND)      elif isinstance(exc, PermissionDenied): -        data = {'detail': 'Permission denied'} +        msg = _('Permission denied.') +        data = {'detail': six.text_type(msg)}          return Response(data, status=status.HTTP_403_FORBIDDEN)      # Note: Unhandled exceptions will raise a 500 error. @@ -93,6 +98,7 @@ class APIView(View):      permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES      content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS      metadata_class = api_settings.DEFAULT_METADATA_CLASS +    versioning_class = api_settings.DEFAULT_VERSIONING_CLASS      # Allow dependency injection of other settings to make testing easier.      settings = api_settings @@ -184,6 +190,18 @@ class APIView(View):              'request': getattr(self, 'request', None)          } +    def get_exception_handler_context(self): +        """ +        Returns a dict that is passed through to EXCEPTION_HANDLER, +        as the `context` argument. +        """ +        return { +            'view': self, +            'args': getattr(self, 'args', ()), +            'kwargs': getattr(self, 'kwargs', {}), +            'request': getattr(self, 'request', None) +        } +      def get_view_name(self):          """          Return the view name, as used in OPTIONS responses and in the @@ -300,6 +318,16 @@ class APIView(View):              if not throttle.allow_request(request, self):                  self.throttled(request, throttle.wait()) +    def determine_version(self, request, *args, **kwargs): +        """ +        If versioning is being used, then determine any API version for the +        incoming request. Returns a two-tuple of (version, versioning_scheme) +        """ +        if self.versioning_class is None: +            return (None, None) +        scheme = self.versioning_class() +        return (scheme.determine_version(request, *args, **kwargs), scheme) +      # Dispatch methods      def initialize_request(self, request, *args, **kwargs): @@ -308,11 +336,13 @@ class APIView(View):          """          parser_context = self.get_parser_context(request) -        return Request(request, -                       parsers=self.get_parsers(), -                       authenticators=self.get_authenticators(), -                       negotiator=self.get_content_negotiator(), -                       parser_context=parser_context) +        return Request( +            request, +            parsers=self.get_parsers(), +            authenticators=self.get_authenticators(), +            negotiator=self.get_content_negotiator(), +            parser_context=parser_context +        )      def initial(self, request, *args, **kwargs):          """ @@ -329,6 +359,10 @@ class APIView(View):          neg = self.perform_content_negotiation(request)          request.accepted_renderer, request.accepted_media_type = neg +        # Determine the API version, if versioning is in use. +        version, scheme = self.determine_version(request, *args, **kwargs) +        request.version, request.versioning_scheme = version, scheme +      def finalize_response(self, request, response, *args, **kwargs):          """          Returns the final response object. @@ -369,7 +403,18 @@ class APIView(View):              else:                  exc.status_code = status.HTTP_403_FORBIDDEN -        response = self.settings.EXCEPTION_HANDLER(exc) +        exception_handler = self.settings.EXCEPTION_HANDLER + +        if len(inspect.getargspec(exception_handler).args) == 1: +            warnings.warn( +                'The `exception_handler(exc)` call signature is deprecated. ' +                'Use `exception_handler(exc, context) instead.', +                DeprecationWarning +            ) +            response = exception_handler(exc) +        else: +            context = self.get_exception_handler_context() +            response = exception_handler(exc, context)          if response is None:              raise | 
