解决了!!!感谢 Dmytriy Voloshyn,它让我了解了神奇的i18n_patterns(我不知道它们:P)。
为了获得我想要的,这些是我已经完成的步骤:
[1] 在我的基本 urls.py 中设置 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 以读取用户首选项:
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)
更新:
我简化了我的方法,以便仅依赖自定义 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)