Django1.4:在模板中设置语言链接以使用i18n_模式的通用方法?

Django1.4:在模板中设置语言链接以使用i18n_模式的通用方法?,django,localization,internationalization,url-pattern,django-1.4,Django,Localization,Internationalization,Url Pattern,Django 1.4,我开始在Django 1.4中使用新的i18n_模式。基本上,我希望在所有模板标题上都有我支持的每种语言的语言链接。我已经将我的头实现为一个单独的模板,该模板包含在其他模板中 有没有一种方法可以使我的标题保持通用性并解决此问题,而无需在模板上下文中传递当前视图名称或当前url?我想这是一个问题,如何以通用的方式从模板内部检索当前视图或url 顺便说一句,我发现我以前使用set_lang view使用referer更改活动语言的方法将被url_模式打破,因为在更改语言后,它将在重定向到refere

我开始在Django 1.4中使用新的i18n_模式。基本上,我希望在所有模板标题上都有我支持的每种语言的语言链接。我已经将我的头实现为一个单独的模板,该模板包含在其他模板中

有没有一种方法可以使我的标题保持通用性并解决此问题,而无需在模板上下文中传递当前视图名称或当前url?我想这是一个问题,如何以通用的方式从模板内部检索当前视图或url

顺便说一句,我发现我以前使用set_lang view使用referer更改活动语言的方法将被url_模式打破,因为在更改语言后,它将在重定向到refered view时将其更改回来


如果您能帮助我们找到在模板中设置语言链接的通用方法,并以通用方式与url_模式一起使用,我们将不胜感激

基本上,设置语言有两种不同的方法。您可以使用
i18n\u patterns
自动神奇地为URL添加语言代码前缀,也可以使用
django.views.i18n.set\u language
视图更改用户会话(或cookie,如果您的项目没有会话支持)中语言代码的值

值得注意的是,
localemidware
用于确定语言的算法:

  • 首先,它在请求的URL中查找语言前缀。这仅在根URLconf中使用i18n_patterns函数时执行。有关语言前缀和如何国际化URL模式的更多信息,请参见国际化:在URL模式中

  • 否则,它将在当前用户的会话中查找django_语言密钥

  • 否则,它将查找cookie。使用的cookie的名称由语言\u cookie\u name设置设置。(默认名称为django_语言。)

  • 否则,它将查看Accept Language HTTP头。此标题由浏览器发送,并按优先级顺序告知服务器您喜欢哪种语言。Django尝试标头中的每种语言,直到找到一种具有可用翻译的语言

  • 否则,它将使用全局语言代码设置

您可能遇到的问题是,您无法使用
set\u language
从已提供语言前缀的url重定向,除非您在POST数据中特别传递
next
参数。这是因为
set_language
将默认重定向到推荐人,其中将包括以前的语言前缀,然后
localemidware
将以旧语言查看和提供内容(因为它在检查
django_language
会话变量之前在url中查找语言前缀)

为清楚起见,举例如下:

  • 您的用户在/en/news/article/1000上,单击链接将“language=es”发布到
    set\u language

  • set_language
    查看'language=es',检查'es'是否可用,然后将'django_language'会话变量(或cookie)设置为'es'

  • 由于没有设置“next”,它会重定向到requeest.META['HTTP_referer']的值,即/en/news/article/1000

  • localemidware
    ()在url中看到“en”前缀,并激活“en”语言并将
    request.language\u code
    设置为“en”

  • 我认为有两种可能的解决办法:

  • 编写您自己的
    set\u language
    视图(参见原始源代码),该视图将检查引用中的语言前缀(使用
    django.utils.translation.get\u language\u from\u path
    ),并将其更改为新选定语言的前缀,然后再重定向回该语言

  • 使用javascript在客户端执行相同的操作,并设置
    next
    POST参数。真的有点傻;使用javascript动态地在所有URL前面加上用户首选的语言代码可能会更简单,而完全忘记
    set\u language


  • 似乎这个新的
    set\u语言
    视图应该是Django的默认行为,其中包括一个提议的实现,但没有真正描述问题,随后被关闭。我建议打开一张新的记录单,更好地描述您的用例、现有的
    set\u语言实施所导致的问题以及您提出的解决方案。

    对于长期延迟,我深表歉意。谢谢大家的回答

    首先对Chris的两个解决方案选项进行评论: 无论是定制的set_语言还是javascript都不适合这一目的,因为url模式的整体美是对SEO友好的

    此外,简单地替换URL中的前缀语言不能被视为基于URL模式的URL的完整解决方案,因为整个URL也可能是可翻译的。例如:英语为
    /en/profile/
    ,法语为
    /fr/profil/
    。 要解决这样的问题,需要捕获viewfunc和参数,以便针对不同的语言反转它

    幸运的是,我的项目目前没有使用可翻译的URL,我采用了以下方法

  • django.core.context\u processors.request
    添加到
    TEMPLATE\u context\u processors
    中,使请求在模板呈现上下文中可用

  • 渲染视图时,在视图中使用
    RequestContext
    。这对我来说永远是独立于主题的情况

  • 编写一个非常简单的
    templatetag
    ,它需要上下文并使用语言代码作为参数来返回给定语言中的当前URL。它基本上确保当前URL具有有效的语言代码前缀和simp
    from django import template
    register = template.Library()
    
    @register.simple_tag(takes_context=True)
    def get_current_url_for_lang(context, lang_code):
        request=context.get('request',False)
        if not request:
            return None
    
        request=context['request']
        curr_url=request.path
        if len(curr_url) < 4 or curr_url[0] != '/' or curr_url[3] != '/':
            return curr_url
    
        if context.get('LANGUAGES',False):
            codes = []
            for code,name in context['LANGUAGES']:
                codes.append(code)
    
            curr_langcode = curr_url[1:3]
            if lang_code not in codes or curr_langcode not in codes:
                return curr_url
    
        changed_url = '/'+lang_code+curr_url[3:]
        return changed_url
    
    def set_language(request):
    """
    Redirect to a given url while setting the chosen language in the
    session or cookie. The url and the language code need to be
    specified in the request parameters.
    
    Since this view changes how the user will see the rest of the site, it must
    only be accessed as a POST request. If called as a GET request, it will
    redirect to the page in the request (the 'next' parameter) without changing
    any state.
    """
    next = request.POST.get('next', request.GET.get('next'))
    if not is_safe_url(url=next, host=request.get_host()):
        next = request.META.get('HTTP_REFERER')
        if not is_safe_url(url=next, host=request.get_host()):
            next = '/'
    lang_code = request.POST.get('language', None)
    # Start changed part
    next = urlparse(next).path  # Failsafe when next is take from HTTP_REFERER
    # We need to be able to filter out the language prefix from the next URL
    current_language = translation.get_language_from_path(next)
    translation.activate(current_language)
    next_data = resolve(next)
    translation.activate(lang_code)  # this should ensure we get the right URL for the next page
    next = reverse(next_data.view_name, args=next_data.args, kwargs=next_data.kwargs)
    # End changed part
    response = http.HttpResponseRedirect(next)
    if request.method == 'POST':
        if lang_code and check_for_language(lang_code):
            if hasattr(request, 'session'):
                request.session[LANGUAGE_SESSION_KEY] = lang_code
            else:
                response.set_cookie(settings.LANGUAGE_COOKIE_NAME, lang_code,
                                    max_age=settings.LANGUAGE_COOKIE_AGE,
                                    path=settings.LANGUAGE_COOKIE_PATH,
                                    domain=settings.LANGUAGE_COOKIE_DOMAIN)
    return response