Решенный !!! Благодаря Дмитрию Волошину, который сообщил мне о волшебстве i18n_patterns (я не знал их: P).
Для того, чтобы получить то, что я хочу, это те шаги, которые я сделал:
[1] Настройка i18n_patterns в моих базовых адресов.ру:
from django.conf.urls import include, url
from django.conf.urls.i18n import i18n_patterns
urlpatterns = i18n_patterns(
'',
url(r'^', include('mysite.core.urls')),
url(r'^foo/', include('mysite.foo.urls')),
# ...
)
[2] Напишите служебный класс, чтобы изменить префикс пути:
import re
from django.utils.encoding import force_text
from django.utils.translation import check_for_language
class PathUtils(object):
LANGUAGE_PREFIX_REGEX = re.compile('^/[a-z]{2}/')
@classmethod
def __pathHasValidPrefix(cls, path):
matches = cls.LANGUAGE_PREFIX_REGEX.findall(path)
if not matches:
return False
return check_for_language(matches[0].strip('/'))
@classmethod
def replaceLanguagePrefix(cls, path, newPrefix):
"""
Returns the original path string with the language prefix replaced by the given one.
Returns the unmodified path if language prefix is not found or is invalid (the language is not
available for the application).
:param path: (str) url path
:param newPrefix: (str) 2 chars language code (ie: "IT", "DE", "ES"...)
:return: (str) Path with new prefix
"""
path, newPrefix = force_text(path), force_text(newPrefix)
if not check_for_language(newPrefix) or not cls.__pathHasValidPrefix(path):
return path
return cls.LANGUAGE_PREFIX_REGEX.sub('/{0}/'.format(newPrefix), path)
[3] Используйте этот класс на мой взгляд, после того, как пользовательские предпочтения формируют представление:
def form_valid(self, form):
form.save()
self.success_url = PathUtils.replaceLanguagePrefix(self.success_url, form.cleaned_data['locale'])
return super(UserSettingsUpdateView, self).form_valid(form)
[4] Отменить стандартную утилиту LocaleMiddleware в o rder читать пользовательские предпочтения:
from django.middleware.locale import LocaleMiddleware as BaseLocaleMiddleware
from django.utils.translation import activate
class LocaleMiddleware(BaseLocaleMiddleware):
"""
Override Django LocaleMiddleware in order to read user preferences.
"""
def __userHasLanguagePreference(self, request):
return request.user.is_authenticated() and request.user.locale
def __activateUserFavoriteLanguage(self, request):
activate(request.user.locale)
request.LANGUAGE_CODE = request.user.locale
def process_request(self, request):
if self.__userHasLanguagePreference(request):
self.__activateUserFavoriteLanguage(request)
else:
super(LocaleMiddleware, self).process_request(request)
Важно импортировать промежуточное программное обеспечение в правильном порядке для реализации этого, AuthenticationMiddleware должны быть импортированы до того LocaleMiddleware, в противном случае пользователь будет отсутствовать в запросе (и доступ к request.user будет расти исключение!).
удовлетворение ++ (опс ... в Python: удовлетворение + = 1)
UPDATE:
Я упростил свой подход, чтобы полагаться только на обычае LocaleMiddleware, это обновленный класс:
from django.middleware.locale import LocaleMiddleware as BaseLocaleMiddleware
from django.utils.translation import get_language_from_path
from myapp.PathUtils import PathUtils
class LocaleMiddleware(BaseLocaleMiddleware):
"""
Override Django LocaleMiddleware in order to read user preferences.
"""
def __userHasLanguagePreference(self, request):
return request.user.is_authenticated() and request.user.locale
def __honorUserLanguagePreference(self, request):
preferred = request.user.locale
language = get_language_from_path(request.path_info, supported=self._supported_languages)
if language != preferred:
request.path_info = PathUtils.replaceLanguagePrefix(request.path_info, preferred)
def process_request(self, request):
if self.__userHasLanguagePreference(request):
self.__honorUserLanguagePreference(request)
super(LocaleMiddleware, self).process_request(request)
Вы пытались установить новый язык явно: request.LANGUAGE_CODE = translation.get_language()? –
Да, это бесполезно ... и в любом случае мне нужно постоянно устанавливать язык не только для текущего вида:/ – daveoncode
Вы используете ** i18n_patterns **? –