8

我开始在Django 1.4中使用新的i18n_patterns。基本上,我想在我的所有模板标题中为每种支持的语言提供语言链接。我已经实现我的标题作为一个单独的模板,正在包含在其他模板中。Django1.4:通用的方法来设置模板中的语言链接以使用i18n_patterns?

有没有办法让我的头通用,并解决这个问题,而无需在模板上下文中传递当前视图名或当前url?我猜它涉及到一个问题,我如何以通用的方式从模板中检索当前视图或url。

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

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

回答

1

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

首先评论克里斯的两个解决方案选项: 自定义的set_language和javascript都不是好的目的,因为整个网站模式的美丽是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.path作为current_url_path例如和使用而不是在你的templatetag

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

5

基本上,有两种不同的方法来设置语言。您可以使用i18n_patterns自动为您的网址加上语言代码前缀,也可以使用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从一个已经被送达语言前缀的网址重定向,除非您特别的POST数据传递next参数。这是因为set_language将默认重定向到引荐来源,该引荐来源将包含之前的语言前缀,然后LocaleMiddleware将以旧语言看到并提供内容(因为它会在检查django_language会话变量之前查找网址中的语言前缀)。

一个例子,为了清楚:

  1. 你的用户是在/ EN /新闻/条/ 1000,点击其将发布的 '语言= ES' 到set_language的链接。

  2. set_language看到“语言= ES”,检查是否“上课”是可用的,然后设置“django_language”会话变量(或饼干),以“ES”

  3. 既然你有没有设定 '下一个',它重定向到reqeuest.META [ 'HTTP_REFERRER'],这是/ EN /消息/条/ 1000

  4. LocaleMiddlewaresource)的值看到成 'en' 前缀中的URL,并激活'en'语言并将request.LANGUAGE_CODE设置为'en'

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

  1. 写你自己的set_language视图(见原始来源here),这将在引用(使用django.utils.translation.get_language_from_path)检查语言前缀,将其更改为在重新导向它之前,新选择的语言的前缀。

  2. 使用javascript做与客户端相同的操作,并设置next POST参数。真的这很傻,只需使用javascript将用户的首选语言代码动态地添加到所有的url就可能会更简单,并且完全忘记了set_language

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

+0

关于将set_language与i18n_patterns一起使用,我认为您可以添加自定义中间件类,以便在请求上下文中添加不带语言前缀的URL。我试图编写一个简单的Middleware类[在这里](http://machakux.appspot.com/blog/17010/django_using_i18n_patterns_and_locale_switcher)。 – machaku 2012-06-14 18:57:57

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 

概括起来讲,我解决()为下一个视图参数,然后传递数据到反向()激活新语言后。希望这可以帮助。

+1

伟大的解决方案,谢谢,但它缺少一件事 - HTTP_REFERER包含主机名,所以'translation.get_language_from_path'返回'None'在这种情况下。我已经导入了urlparse并在“开始更改部分”的开头添加了这一行'next = urlparse(next).path'。 – bellum 2015-04-22 10:31:33

+0

好点 - 我没有注意到,因为我只使用过?next =(并保持引用只作为默认以防万一);我会相应地更新答案。 – pgcd 2015-04-23 11:03:54

+0

FWIW,'next'是Python中的一个内置函数(至少2.6以上),不应该用作变量名称。 https://docs.python.org/3/library/functions.html#next – 2016-02-17 11:10:08

2

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

+0

真棒解决方案,如果你告诉用户改变语言的方式只是一个链接的地方。 – 2016-02-11 21:47:22

+0

这应该是完美的答案没有templatetags没有额外的代码' {{ language.0|language_name_local|capfirst }}' – 2016-12-12 11:38:47