检测语言与Django本地化URL

3 投票
4 回答
14501 浏览
提问于 2025-04-15 14:52

我想要在我的网站上提供英语和西班牙语版本,并且能够检测用户的浏览器语言,然后把他们引导到正确的语言版本的网站。

我的网站是 www.elmalabarista.com

我安装了一个叫 django-localeurl 的工具,但我发现它没有正确检测语言。

这是我的中间件设置:

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware', 
    'django.middleware.locale.LocaleMiddleware',    
    'multilingual.middleware.DefaultLanguageMiddleware',
    'middleware.feedburner.FeedburnerMiddleware',
    'lib.threadlocals.ThreadLocalsMiddleware',
    'middleware.url.UrlMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'maintenancemode.middleware.MaintenanceModeMiddleware',
    'middleware.redirect.RedirectMiddleware',
    'openidconsumer.middleware.OpenIDMiddleware',
    'django.middleware.doc.XViewMiddleware',
    'middleware.ajax_errors.AjaxMiddleware',
    'pingback.middleware.PingbackMiddleware',
    'localeurl.middleware.LocaleURLMiddleware', 
    'multilingual.flatpages.middleware.FlatpageFallbackMiddleware',
    'django.middleware.common.CommonMiddleware',
)

但是无论如何,网站总是显示美国版,尽管我的操作系统和浏览器设置是西班牙语。

LANGUAGES = (
    ('en', ugettext('English')),  
    ('es', ugettext('Spanish')),
)
DEFAULT_LANGUAGE = 1

然后,我对locale-url的中间件进行了修改,做了这个:

def process_request(self, request):
    locale, path = self.split_locale_from_request(request)
    if request.META.has_key('HTTP_ACCEPT_LANGUAGE'):
        locale = utils.supported_language(request.META['HTTP_ACCEPT_LANGUAGE'].split(',')[0])
    locale_path = utils.locale_path(path, locale)
                
    if locale_path != request.path_info:
        if request.META.get("QUERY_STRING", ""):
            locale_path = "%s?%s" % (locale_path,
                    request.META['QUERY_STRING'])
        return HttpResponseRedirect(locale_path)
    request.path_info = path
    if not locale:
        locale = settings.LANGUAGE_CODE
    translation.activate(locale)
    request.LANGUAGE_CODE = translation.get_language()

不过,这样虽然能正确检测语言,但却把“en”(英语)的链接重定向到了“es”(西班牙语)。所以我根本无法用英语浏览网站。

更新:这是最终的代码(根据 Carl Meyer 的建议修改过),修复了“/”的情况:

def process_request(self, request):
    locale, path = self.split_locale_from_request(request)
    if (not locale) or (locale==''):
        if request.META.has_key('HTTP_ACCEPT_LANGUAGE'):
            locale = utils.supported_language(request.META['HTTP_ACCEPT_LANGUAGE'].split(',')[0])
        else:
            locale = settings.LANGUAGE_CODE
    locale_path = utils.locale_path(path, locale)
    if locale_path != request.path_info:
        if request.META.get("QUERY_STRING", ""):
            locale_path = "%s?%s" % (locale_path, request.META['QUERY_STRING'])
        return HttpResponseRedirect(locale_path)
    request.path_info = path
    translation.activate(locale)
    request.LANGUAGE_CODE = translation.get_language()

4 个回答

0

其实应该是这样的:

可以接受多种语言,按照优先级来排序。

def process_request(self, request):
    locale, path = utils.strip_path(request.path_info)
    if (not locale) or (locale==''):
        if request.META.has_key('HTTP_ACCEPT_LANGUAGE'):
        l = [x.strip()[:2] for x in request.META['HTTP_ACCEPT_LANGUAGE'].split(',')]
        for lang_code in l:
                locale = utils.supported_language(lang_code)
                if locale:
          break
        else:
            locale = settings.LANGUAGE_CODE
    locale_path = utils.locale_path(path, locale)
    if locale_path != request.path_info:
        if request.META.get("QUERY_STRING", ""):
            locale_path = "%s?%s" % (locale_path,
                    request.META['QUERY_STRING'])
        return HttpResponseRedirect(locale_path)
    request.path_info = path
    if not locale:
        try:
            locale = request.LANGUAGE_CODE
        except AttributeError:
            locale = settings.LANGUAGE_CODE
    translation.activate(locale)
    request.LANGUAGE_CODE = translation.get_language()
1

我也需要这样的功能。你现在是只用你自己写的中间件来获取语言吗?还是说你还在同时使用LocaleURLMiddleware和LocaleMiddleware,以及上面代码中的中间件呢?

11

(更新: django-localeurl的LocaleURLMiddleware现在直接支持HTTP的Accept-Language作为备用选项,如果设置了LOCALEURL_USE_ACCEPT_LANGUAGE为True。那么,提问者想要的功能现在可以直接实现,不需要自己写中间件了)。

同时启用Django自带的LocaleMiddleware和LocaleURLMiddleware是没有意义的。它们是互相替代的,选择语言的逻辑也不同。Locale-url的意思就是通过URL的一部分来定义语言(而不是通过Accept-Language这个头信息)。Django的LocaleMiddleware会根据会话值、cookie或者Accept-Language头信息来选择语言。如果同时启用这两个中间件,最后一个生效的会覆盖前面的,这就是你看到LocaleURLMiddleware行为的原因。

听起来你可能想要两者的某种结合:在访问网站的根URL时,初始语言是根据Accept-Language来选择的,之后再通过URL来定义?你想要的行为并不是很清楚,所以首先需要明确这一点。然后你可能需要自己写一个LocaleMiddleware来实现这个功能。你第一次尝试修改LocaleURLMiddleware时,总是使用Accept-Language来替代URL中定义的内容。实际上,你想要在“if not locale:”这个部分进一步检查Accept-Language头信息,在那里它会默认使用settings.LANGUAGE_CODE。可以参考下面的代码(未经测试):

def process_request(self, request):
    locale, path = self.split_locale_from_request(request)
    locale_path = utils.locale_path(path, locale)

    if locale_path != request.path_info:
        if request.META.get("QUERY_STRING", ""):
            locale_path = "%s?%s" % (locale_path, request.META['QUERY_STRING'])
        return HttpResponseRedirect(locale_path)
    request.path_info = path
    if not locale:
        if request.META.has_key('HTTP_ACCEPT_LANGUAGE'):
            locale = utils.supported_language(request.META['HTTP_ACCEPT_LANGUAGE'].split(',')[0])
        else:
            locale = settings.LANGUAGE_CODE
    translation.activate(locale)
    request.LANGUAGE_CODE = translation.get_language()

撰写回答