Opened 6 years ago

Closed 6 years ago

Last modified 6 years ago

#29281 closed Bug (wontfix)

In some cases i18n set_language does not change url language

Reported by: Nikita Delyukov Owned by: nobody
Component: Internationalization Version: 1.11
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Nikita Delyukov)

In general POST to /i18n/setlang/ works fine.
Sometimes it fails: if the current link is /es/smth/ (or just /es/, whatever), post to /i18n/setlang/ with 'en' reloads the same link /es/smth/, instead of /en/smth/.
Happens from time to time in our prod, dev servers and locally. Sometimes just closing the browser window and opening the site again solves the issue. At the same time it may be fine in one browser and fail in another. Yesterday I encountered it locally and was able to debug:

#proj.urls.py:
...
urlpatterns += i18n_patterns(
    url(r'^', include('app.urls')),
)
...
# from django.views.i18n, set_language
# current link is '/es/smth/', POST to /i18n/setlang/ with language: en, csrfmiddlewaretoken: xxx
...
if request.method == 'POST':
    lang_code = request.POST.get(LANGUAGE_QUERY_PARAMETER) # ='en'
    if lang_code and check_for_language(lang_code):
        if next:# next = '/es/smth/'
            next_trans = translate_url(next, lang_code)# returns the same '/es/smth/'
            if next_trans != next:# next == next_trans, url is not changed, the same /es/smth/ url is reloaded, language haven't changed
                response = http.HttpResponseRedirect(next_trans)
...
# django.urls.base, translate_url:
...
parsed = urlsplit(url) # SplitResult(scheme='http', netloc='127.0.0.1:8080', path='/es/smth/', query='', fragment='')
try:
    match = resolve(parsed.path)# triggers Resolver404
except Resolver404:
    pass
else:
...
# django.urls.base, resolve
def resolve(path, urlconf=None): # path is the current url, /es/smth/
    if urlconf is None:
        urlconf = get_urlconf() # None
    return get_resolver(urlconf).resolve(path) # <RegexURLResolver 'proj.urls' (None:None) ^/>, resolve(path) triggers Resolver404

Resolver404: {'tried': <RegexURLResolver <RegexURLPattern list> (admin:admin) ^admin/>], [<RegexURLResolver <module 'django.conf.urls.i18n' from 'C:\\Python36\\Scripts\\aliro\\Lib\\site-packages\\django\\conf\\urls\\i18n.py'> (None:None) ^i18n/>], [<LocaleRegexURLResolver <RegexURLResolver list> (None:None) ^en/>, 'path': 'es/smth/'}

So, sometimes get_resolver(None).resolve(path) where path matches a listed i18n_pattern, fails, and in another browser the same path is matched fine.
The variables in both runs are the same until get_resolver(urlconf).resolve(path), where one triggers Resolver404, and the other returns a matched url (ResolverMatch(func=app.views.smth, args=(), kwargs={'template_name': 'app/smth.html'}, url_name=smth, app_names=[], namespaces=[]))

I don't have a setup and\or scenario to reproduce it everytime.
Django 1.11.10

Attachments (1)

29281-regression.patch (619 bytes ) - added by Carlton Gibson 6 years ago.
Failing test case: trying to reverse an en URL when the current language is already nl.

Download all attachments as: .zip

Change History (8)

comment:1 by Nikita Delyukov, 6 years ago

Description: modified (diff)

comment:2 by Nikita Delyukov, 6 years ago

Description: modified (diff)

comment:3 by Tim Graham, 6 years ago

If you don't have a way to reproduce the problem or an explanation of what code is at fault, we'll probably close the report as "needsinfo" until someone can provide that information.

comment:4 by Tim Graham, 6 years ago

Resolution: needsinfo
Status: newclosed

If you have a sample project that reproduces the problem intermittently, that also might be enough to investigate the issue.

comment:5 by Beda Kosata, 6 years ago

Resolution: needsinfo
Status: closednew

Hi,

I have been bitten by the same issue and I think I have found the culprit or at least a way to reproduce the error. The trick is having two windows/tabs open with the same website and then changing the language in one of them.

The page in the active window is properly redirected to the new language version. However, trying to do the same in the other tab no longer works. The reason is that the code that tries to find if the URL should be rewritten (translate_url) uses resolve to try to find the matching URL, but because the language has been already changed in the session, it does not match the original URL and no translation is done.

I hope this is enough information to have the issue reopened. Otherwise I would be happy to provide more info if needed.

Beda

comment:6 by Tim Graham, 6 years ago

A test for tests/view_tests/tests/test_i18n.py that demonstrates the issue would be great.

by Carlton Gibson, 6 years ago

Attachment: 29281-regression.patch added

Failing test case: trying to reverse an en URL when the current language is already nl.

comment:7 by Carlton Gibson, 6 years ago

Resolution: wontfix
Status: newclosed

From Beda's description I recreated the issue: we set a language (once) then try to reverse a URL from the old language when setting the language again. This obviously fails.

Workarounds:

  • keeping track of the old language and falling back to try that if the lookup with the current language fails.
  • Signalling across browser tabs that we already changed the language and adjusting accordingly (???).

Both of these are out of scope for the in-built i18n. (The first would be possible on a project level — reimplementing e.g. set_language — if it was deemed cost effective.)

I'm going to close this on that basis.

If a third option presents itself we could re-open/re-assess.

Last edited 6 years ago by Carlton Gibson (previous) (diff)
Note: See TracTickets for help on using tickets.
Back to Top