4

I have a problem with translating custom exception in Django rest, the problem is when I change the LANGUAGE_CODE in the settings, every things work fine and i get correct translation for both of my languages, but when I tried to use Accept-Language in the header to change the translation, it does not work as it should! my settings is:

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.locale.LocaleMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'core.middleware.auth_middleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'core.middleware.dates_middleware',
    'core.middleware.translation_middleware',
]
#LANGUAGE_CODE = 'fa-ir'
LANGUAGE_CODE = 'en-us'

LANGUAGES = [
    ('fa', _('Farsi')),
    ('en', _('English')),
]

TIME_ZONE = 'UTC'


USE_I18N = True

USE_L10N = True

my exception:

from rest_framework.exceptions import APIException
from django.utils.translation import ugettext as _
class WrongUsernamePassword(APIException):
    status_code = 401
    default_detail = _('username or password is wrong')
    default_code = '401'

my view:

class UserViewSet(viewsets.ModelViewSet):
    ...

    @list_route(methods=['POST'], permission_classes=[AllowAny])
    def app_login(self, request):
        lang = translation.get_language() # here the value is fa
        raise WrongUsernamePassword

when I send the request with this header (Accept-Language=fa-ir) I can see that the lang variable value is fa so framework know that I change the language but the response is still in english:

{
    "detail": "username or password is wrong"
}

any idea?

nim4n
  • 1,813
  • 3
  • 21
  • 36

1 Answers1

2

Today I dealt with the same problem. I found this post and saw that it was not solved.

It occurs because those error messages are defined in a class variable, therefore, they are defined when the server is loaded. So, at that moment, there is not an Accept-Language in a header because there is not a request.

To solve that problem, I used gettext_lazy instead of gettext because that function translates the string in a lazy fashion. You should use gettext_lazy. In ugettext() vs. ugettext_lazy() there is a very good explanation about ugettext vs ugettext_lazy which made me understand the problem:

For your code sample:

from rest_framework.exceptions import APIException
from django.utils.translation import ugettext_lazy as _
class WrongUsernamePassword(APIException):
    status_code = 401
    default_detail = _('username or password is wrong')
    default_code = '401'
R3mmurd
  • 46
  • 4
  • The answer can be improved for other users of the forum if you could describe under which circumstances "gettext_lazy" should be used instead of "gettext". Would it be possible to add some cases in which "gettext" still needs to be used? Are there any limitations when using "gettext_lazy"? – nsx Feb 11 '20 at 21:30