8

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

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

顺便说一句,我发现我之前使用 set_lang 视图使用引用者更改活动语言的方法将被 url_patterns 破坏,因为在更改语言后,它会在重定向到被引用视图时将其改回。

任何帮助找出在模板中设置语言链接以以通用方式与 url_patterns 一起使用的通用方法将不胜感激!

4

4 回答 4

5

基本上,有两种不同的方法来设置语言。您可以使用i18n_patterns语言代码自动为您的 url 添加前缀,或者您可以使用django.views.i18n.set_language视图更改用户会话中语言代码的值(或 cookie,如果您的项目不支持会话)。

值得注意的是该算法LocaleMiddleware用于确定语言:

  • 首先,它在请求的 URL 中查找语言前缀。仅当您在根 URLconf 中使用 i18n_patterns 函数时才会执行此操作。有关语言前缀以及如何国际化 URL 模式的更多信息,请参阅国际化:在 URL 模式中。

  • 否则,它会在当前用户的会话中查找 django_language 键。

  • 否则,它会查找 cookie。使用的 cookie 的名称由 LANGUAGE_COOKIE_NAME 设置设置。(默认名称是 django_language。)

  • 如果做不到这一点,它会查看 Accept-Language HTTP 标头。此标头由您的浏览器发送,并按优先级告诉服务器您喜欢哪种语言。Django 会尝试标题中的每种语言,直到找到具有可用翻译的语言。

  • 否则,它将使用全局 LANGUAGE_CODE 设置。

您可能遇到的问题是您不能使用set_language从已经使用语言前缀提供的 url 重定向,除非您next在 POST 数据中专门传递参数。这是因为set_language将默认重定向到引用者,其中将包括以前的语言前缀,LocaleMiddleware然后它将以旧语言查看和提供内容(因为它会在检查django_language会话变量之前在 url 中查找语言前缀)。

一个例子,为了清楚起见:

  1. 您的用户在 /en/news/article/1000 上,并单击将“language=es”发布到set_language.

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

  3. 由于你没有设置'next',它重定向到reqeuest.META['HTTP_REFERRER']的值,即/en/news/article/1000

  4. LocaleMiddleware( source ) 在 url 中看到 'en' 前缀,并激活 'en' 语言并设置request.LANGUAGE_CODE为 'en'

我看到两种可能的解决方案:

  1. 编写您自己的视图(请参阅此处set_language的原始源代码),它将检查引用者(使用)中的语言前缀,并将其更改为新选择的语言的前缀,然后再重定向回它。django.utils.translation.get_language_from_path

  2. 使用javascript在客户端做同样的操作,并设置nextPOST参数。真的,这有点傻;仅使用 javascript 将所有 url 动态添加到用户的首选语言代码之前可能会更简单,而完全忘记set_language

看来这个新set_language视图应该是 Django 的默认行为了。提出了一张票,其中包括一个提议的实施,但没有真正描述问题,随后被关闭。我建议开一张新票,更好地描述您的用例、现有实现引起的问题set_language以及您提出的解决方案。

于 2012-05-17T16:29:50.410 回答
3

实际上,没有必要摆弄你的观点。Django 有一个方便的切片标签,因此您可以将{{ request.path|slice:'3:' }}其用作链接 URL。这将关闭语言代码前缀,因此语言由 set_lang 函数设置。

于 2015-08-12T01:51:36.827 回答
2

今天在使用 Django 1.7 时遇到了同样的问题,我设计了这个解决方案 - 不是很干燥,但它似乎工作正常(而且我所有的测试都通过了,所以......)。我没有使用内置的 set_language 视图,而是复制了它并做了一个微小的调整——结果如下:

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

总结一下,我 resolve() next 的视图参数,然后在激活新语言后将数据传递给 reverse()。希望这可以帮助。

于 2015-04-08T14:02:05.203 回答
1

我对长时间的延误表示歉意。谢谢大家的答案。

首先评论一下 Chris 的两个解决方案选项:自定义 set_language 和 javascript 都不适合此目的,因为 url 模式的整体美感是 SEO 友好的。

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

对我来说幸运的是,我的项目目前不使用可翻译的 URL,我采用了以下方法。

  1. 添加django.core.context_processors.requestTEMPLATE_CONTEXT_PROCESSORS以便该请求在模板呈现上下文中可用。

  2. RequestContext渲染视图时在视图中使用。这对我来说总是与主题无关。

  3. 编写一个非常简单templatetag的程序,它需要上下文并接受一个语言代码作为参数以返回给定语言的当前 URL。它基本上确保当前 URL 具有有效的语言代码前缀,并简单地返回另一个字符串,该字符串与替换语言代码的当前 URL 相同。

前任:

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

此外,如果一个人不喜欢将完整的请求注入到上下文中,那么编写自己的 context_processor 将非常简单,例如简单地推送request.pathascurrent_url_path并在您的templatetag.

一如既往地欢迎您的意见!

于 2012-08-23T21:15:07.700 回答