0
votes

Hi I have django internationalization working on my django site. That is if i browse ".../en/foo/bar" and ".../nb/foo/bar" they work fine. But i am trying to get a drop down menu to automatically change the language but i get csrf error.

base.html

<form action="{% url 'set_language' %}" method="post">
   {% csrf_token %}
    <input name="next" type="hidden" value="{{ redirect_to }}"/>
    <select name="language">
     {% get_current_language as LANGUAGE_CODE %}
     {% get_available_languages as LANGUAGES %}
     {% get_language_info_list for LANGUAGES as languages %}
      {% for language in languages %}
      <option value="{{ language.code }}"
      {% if language.code == LANGUAGE_CODE %}                                                                      selected="selected"{% endif %}>
       {{ language.name_local }} ({{ language.code }})
   </option>
    {% endfor %}
     </select>
      <input type="submit" value="Go"/>
 </form>

I however have another form in the same html but I do not but {% csrf_token %} in it. I rather place@csrf_exempt` on the view that handles the form. I dont know whether having both froms on on html is what is causing the problem.

So what id did was that i created my own set_language view just like in django.veiws.i18n and places the @csrf_exempt on it.

@csrf_exempt
def set_language(request):
    """
    Redirect to a given url while setting the chosen language in the
    session or cookie. The url and the language code need to be
    specified in the request parameters.

    Since this view changes how the user will see the rest of the site, it must
    only be accessed as a POST request. If called as a GET request, it will
    redirect to the page in the request (the 'next' parameter) without changing
    any state.
    """
    print 'I am in setlang'
    next = request.POST.get('next', request.GET.get('next'))

    if not is_safe_url(url=next, host=request.get_host()):
        print 'not safe'
        next = request.META.get('HTTP_REFERER')
        if not is_safe_url(url=next, host=request.get_host()):
            next = '/'
    response = http.HttpResponseRedirect(next)
    if request.method == 'POST':
        lang_code = request.POST.get('language', None)
        if lang_code and check_for_language(lang_code):
            if hasattr(request, 'session'):
                request.session[LANGUAGE_SESSION_KEY] = lang_code
            else:
                response.set_cookie(settings.LANGUAGE_COOKIE_NAME, lang_code,
                                    max_age=settings.LANGUAGE_COOKIE_AGE,
                                    path=settings.LANGUAGE_COOKIE_PATH,
                                    domain=settings.LANGUAGE_COOKIE_DOMAIN)
    return response

Though the CSRF validation error is solved the form has no effect when i change the language and submit. it just stays on the same page. it appears that if not is_safe_url(url=next, host=request.get_host()) is always true. I am not sure what i am doing wrong now

I just realised that my form sends a GET request to the view instead of a post so request.method is GET how and why is this so? The form data does not get to the view at all in this case but they submit when i leave the action attribute of the form blank. The the form submits to the view that called the page. Submitting to a specific view is not working as the request somehow becomes a get request

1
{% csrf_token %} must be on every form.itzMEonTV
Quire sure that it's your view that's called and not the one from the library?e4c5
@itzmeontv yeah i have {% csrf_token %} on both formsflexxxit
@e4c5 Yes i know that because the code to print out stuff in the view is in mine print 'I am in setlang and print 'not safe. `not safe' is always printed when i submit the form and next is also always empty (none)flexxxit

1 Answers

0
votes

With first problem - csrf error, there is no simple solution (if you want csrf working, not bypassed) because we can't tell what is happening here - maybe some cookie-related issue.

But second problem is simple to solve. There is bug in django. In simple words, django won't translate url (change prefix in front of URL or translate whole URL) when user is changing language, so user will be redirected to old, not translated URL with old language prefix. That will cause to switch back to old language after redirection.

Solution to that problem is already submitted to django and will be available in django 1.9, but you can get code of that view from github and put it instead of your current language switching view.

Here is full commit for that fix, there is new function called translate_url in urlresolvers that is used in fixed view.