|
| 1 | +from django.conf import settings |
| 2 | +from django.conf.urls.i18n import is_language_prefix_patterns_used |
| 3 | +from django.http import HttpResponseRedirect |
| 4 | +from django.urls import get_script_prefix, is_valid_path |
| 5 | +from django.utils import translation |
| 6 | +from django.utils.cache import patch_vary_headers |
| 7 | + |
| 8 | +from django_async_extensions.amiddleware.base import AsyncMiddlewareMixin |
| 9 | + |
| 10 | + |
| 11 | +class AsyncLocaleMiddleware(AsyncMiddlewareMixin): |
| 12 | + """ |
| 13 | + Parse a request and decide what translation object to install in the |
| 14 | + current thread context. This allows pages to be dynamically translated to |
| 15 | + the language the user desires (if the language is available). |
| 16 | + """ |
| 17 | + |
| 18 | + response_redirect_class = HttpResponseRedirect |
| 19 | + |
| 20 | + async def process_request(self, request): |
| 21 | + urlconf = getattr(request, "urlconf", settings.ROOT_URLCONF) |
| 22 | + ( |
| 23 | + i18n_patterns_used, |
| 24 | + prefixed_default_language, |
| 25 | + ) = is_language_prefix_patterns_used(urlconf) |
| 26 | + language = translation.get_language_from_request( |
| 27 | + request, check_path=i18n_patterns_used |
| 28 | + ) |
| 29 | + language_from_path = translation.get_language_from_path(request.path_info) |
| 30 | + if ( |
| 31 | + not language_from_path |
| 32 | + and i18n_patterns_used |
| 33 | + and not prefixed_default_language |
| 34 | + ): |
| 35 | + language = settings.LANGUAGE_CODE |
| 36 | + translation.activate(language) |
| 37 | + request.LANGUAGE_CODE = translation.get_language() |
| 38 | + |
| 39 | + async def process_response(self, request, response): |
| 40 | + language = translation.get_language() |
| 41 | + language_from_path = translation.get_language_from_path(request.path_info) |
| 42 | + urlconf = getattr(request, "urlconf", settings.ROOT_URLCONF) |
| 43 | + ( |
| 44 | + i18n_patterns_used, |
| 45 | + prefixed_default_language, |
| 46 | + ) = is_language_prefix_patterns_used(urlconf) |
| 47 | + |
| 48 | + if ( |
| 49 | + response.status_code == 404 |
| 50 | + and not language_from_path |
| 51 | + and i18n_patterns_used |
| 52 | + and prefixed_default_language |
| 53 | + ): |
| 54 | + # Maybe the language code is missing in the URL? Try adding the |
| 55 | + # language prefix and redirecting to that URL. |
| 56 | + language_path = "/%s%s" % (language, request.path_info) |
| 57 | + path_valid = is_valid_path(language_path, urlconf) |
| 58 | + path_needs_slash = not path_valid and ( |
| 59 | + settings.APPEND_SLASH |
| 60 | + and not language_path.endswith("/") |
| 61 | + and is_valid_path("%s/" % language_path, urlconf) |
| 62 | + ) |
| 63 | + |
| 64 | + if path_valid or path_needs_slash: |
| 65 | + script_prefix = get_script_prefix() |
| 66 | + # Insert language after the script prefix and before the |
| 67 | + # rest of the URL |
| 68 | + language_url = request.get_full_path( |
| 69 | + force_append_slash=path_needs_slash |
| 70 | + ).replace(script_prefix, "%s%s/" % (script_prefix, language), 1) |
| 71 | + # Redirect to the language-specific URL as detected by |
| 72 | + # get_language_from_request(). HTTP caches may cache this |
| 73 | + # redirect, so add the Vary header. |
| 74 | + redirect = self.response_redirect_class(language_url) |
| 75 | + patch_vary_headers(redirect, ("Accept-Language", "Cookie")) |
| 76 | + return redirect |
| 77 | + |
| 78 | + if not (i18n_patterns_used and language_from_path): |
| 79 | + patch_vary_headers(response, ("Accept-Language",)) |
| 80 | + response.headers.setdefault("Content-Language", language) |
| 81 | + return response |
0 commit comments