Issue #23 resolved

Using Django session for storing default locale

Sylvain Fourmanoit
created an issue

Enclosed is a patch making django-localurl able to use Django sessions to store the user-selected locale, via a new LOCALEURL_USE_SESSION setting (turned off by default).

With it, Django serving "unlocalized" urls is able to pick up the last user choice, and serves the content in the previously user-selected language.

Rationale is that it's not always practical to rewrite a large number of templates to invoke locale_url everywhere, and it's handy to have a way to keep the preference around, even if it goes against django-localurl statelessness.

Comments (15)

  1. Alex Marandon

    This looks like a problem we've bumped into as well. There should be a way to set a default locale that localeurl would pick for "unlocalized" urls and that would have a higher priority than the Accept-Language HTTP header.

    Our real-world use case is that we allow users to choose their preferred language in their profile edit screen. With the current localeurl middleware, if they visit an "unlocalized" URL, it will redirect them to a localized URL corresponding to their browser settings (Accept-Language HTTP header), which might be different from their profile settings (people traveling, borrowing someone else's computer, etc.)

    To solve this we override process_request so that it tries to get the correct locale from the user's profile: https://github.com/alex-marandon/imaginationforpeople/blob/0ad6163af6cd125383a9f69c40a3dbdfce009565/apps/member/middleware.py#L12

    The approach suggested by Sylvain here in his patch is more generic and would probably work for us too.

    The ideal approach might actually be to simply use the value of request.LANGUAGE_CODE, which can be set by app developers either by setting a session key or a cookie, as documented at https://docs.djangoproject.com/en/1.0/topics/i18n/#how-django-discovers-language-preference Django's algorithm for setting request.LANGUAGE_CODE also takes into account the Accept-Language HTTP header so the middleware wouldn't need to be much more complicated than it is now and it would preserve Django's expected behaviour regarding language preference discovery. App developpers like us who wants to allow users to choose a preferred language via profile settings could set a cookie or a session key when users sign in.

  2. scrapper

    concerning Sylvains patch it is not clear what is the exact order regarding:

    • 'django.contrib.sessions.middleware.SessionMiddleware',
    • 'localeurl.middleware.LocaleURLMiddleware',

    in the documentation its written oppositional.

    greetings sc

  3. Carl Meyer repo owner

    I'm open to this patch, since the stateful behavior is optional. The patch requires tests before it can be integrated. Also, if I'm not mistaken the feature as implemented only works if the "change_locale" view is used, which is not required; it's also possible to never use "change_locale" and simply use "chlocale" template filter to switch languages via links. I don't think it's really possible to make this feature work with "chlocale" because "switching the language" is not an explicit action, it's just a link like any other. You'd have to store the language in the session on every URL access, and even then you'd risk mistakenly storing a language preference when a user was just following a pasted link to the wrong language or something. So the patch also needs documentation to clarify that point.

  4. scrapper

    I have implemented the patch and after some fiddling around it seems to work fine! Thank you very much!

    I have done some little changes:

    adjusted LOCALE_URL_MIDDLEWARE to work with settings.LANGUAGE_COOKIE_NAME instead of the cookie name "locale" as this is the default setting - and other apps work with this cookie name by default. By default this cookie name is set to: "django_language" in django.conf settings.py. This will help you if you are running other apps which do work with cookie name "django_language" as well. In i18n.py def set_language by example sets the cookie with the name django_language.

    Best way is to use settings.LANGUAGE_COOKIE_NAME and do not hard code it in your apps like "django_language" or "locale".

    Form to change language:

    <form action="{{ set_language_url }}" method="post">{% csrf_token %}
    <p> {% trans "Change language" %} </p>
        <select name="language">
            {% for lang in languages %}
                <option {% ifequal django_language lang.0 %}selected {% endifequal %}value="{{ lang.0 }}">{{ lang.1 }}</option>
            {% endfor %}
        </select>
    <input type="submit" value="{% trans 'Change' %}" />
    </form>
    

    set_language_url has to set the proper url which than calls i18n.py set_language. this will set the language + cookies and redirect to the proper url.

    set_language.py

    you can see the modifications I have made to def set_language in i18n.py when you open the attachment.

    hope it helps.

  5. Carl Meyer repo owner

    Thanks scrapper. If you'd like this applied to django-localeurl trunk, I'll need it in proper patch or pull request format, including necessary changes/additions to tests and docs.

  6. Sylvain Fourmanoit reporter

    Updated version of my patch. It applies cleanly against the latest trunk, and updates the doc, trying to address the various comments by scrapper, Alex Marandon and Carl Meyer.

    I am not on a machine I can test on right now, so tests are still missing, but I will be back with them on Monday.

  7. Anonymous

    great Sylvain

    thank you! I am on delay with some important projects right now.

    greetings sc

  8. Sylvain Fourmanoit reporter
    • changed status to new

    @alexmarandon I did not write the tests yet -- I cannot believe I missed my self-imposed deadline by that long already. So, If you have the time and the inclination, by all means, I would definitively appreciate the help.

  9. Log in to comment