Django模板:使用其他语言获取当前URL

时间:2012-07-11 16:46:03

标签: django internationalization django-templates

我正在使用i18n_patterns在Django应用程序中创建语言前缀。

我的网址如下:

/de/contact/
/fr/contact/
/it/contact/

在我的基本模板中,我循环遍历所有可用语言以显示语言切换链接。

{% get_available_languages as languages %}
<nav id="language_chooser">
    <ul>
        {% for lang_code, lang_name in languages %}
            {% language lang_code %}
            <li><a href="{% url 'home' %}" alt="{{ lang_name }}" title="{{ lang_name }}">{{ lang_code }}</a></li
            {% endlanguage %}
        {% endfor %}
    </ul>
</nav>

在这种情况下,我正在撤消“主页”网址。有没有办法获得当前页面的翻译URL?

如果我使用德语版的“联系”页面,我希望“fr”链接指向“联系”页面的法语版本,而不是“主页”页面。

13 个答案:

答案 0 :(得分:15)

我没有使用语言前缀,而是翻译了网址。但是,此模板标记也应该可以帮助您:

# This Python file uses the following encoding: utf-8

from django import template
from django.core.urlresolvers import reverse # from django.urls for Django >= 2.0
from django.core.urlresolvers import resolve # from django.urls for Django >= 2.0
from django.utils import translation

register = template.Library()

class TranslatedURL(template.Node):
    def __init__(self, language):
        self.language = language
    def render(self, context):
        view = resolve(context['request'].path)
        request_language = translation.get_language()
        translation.activate(self.language)
        url = reverse(view.url_name, args=view.args, kwargs=view.kwargs)
        translation.activate(request_language)
        return url

@register.tag(name='translate_url')
def do_translate_url(parser, token):
    language = token.split_contents()[1]
    return TranslatedURL(language)

以当前语言返回当前网址。像这样使用它:{% translate_url de %}

欢迎提出改进意见和建议。

答案 1 :(得分:7)

这段代码应该这样做:

https://djangosnippets.org/snippets/2875/

一旦你added that as a custom template tag,你可以做以下事情:

<a href='{% change_lang 'fr' %}'>View this page in French</a>

答案 2 :(得分:4)

我认为值得一提的是,有一个名为translate_url的内置函数。

from django.urls import translate_url
translate_url(url, lang_code)

答案 3 :(得分:3)

我认为你正在为这个问题添加不必要的复杂功能。您正在寻找的是一个简单的语言选择器。 Django提供开箱即用的功能,它总是重定向到当前页面(用另一种语言)。

这里记录在案:

https://docs.djangoproject.com/en/dev/topics/i18n/translation/#django.conf.urls.i18n.set_language

唯一的问题是set_language视图需要POST参数,因此您需要使用<form>元素;您无法使用简单的<a href="...">链接。但是,有时您希望语言选择器看起来像链接,而不是像带有选择小部件的表单。我的建议是使用表单,但将其设置为看起来像链接。

您的模板可能如下所示:

<nav id="language_chooser">
    <ul>
        {% get_language_info_list for LANGUAGES as languages %}
        {% for language in languages %}
            <form action="{% url 'set_language' %}" method="post">
                {% csrf_token %}
                <input name="next" type="hidden" value="{{ redirect_to }}" />
                <input name="language" type="hidden" value="{{ language.code }}" />
                <button type="submit">{{ language.local_name }}"</button>
            </form>
        {% endfor %}
    </ul>
</nav>

然后你使用CSS来设置表单样式并提交按钮看起来像普通链接:

ul#language_chooser form {
    display: inline; 
    margin: 0;
    padding: 0;
}

ul#language_chooser button {
    margin: 0;
    padding: 0;
    border: none;
    background: none;
    color: blue; /* whatever you like */
    text-decoration: underline; /* if you like */
}

答案 4 :(得分:3)

使用django_hreflang

{% load hreflang %}

<ul>
    <li><a href="{% translate_url 'en' %}" hreflang="en">English</a></li>
    <li><a href="{% translate_url 'ru' %}" hreflang="ru">Russian</a></li>
</ul>

答案 5 :(得分:2)

我使用docs

中的标准语言表单
<form action="{% url 'set_language' %}" method="post" id="lang_changer">
{% csrf_token %}
<input name="next" type="hidden" value="{{ redirect_to }}" />
<select name="language">
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected="selected"{% endif %}>
    {{ language.name_local }} ({{ language.code }})
</option>
{% endfor %}
</select>
<input type="submit" value="Go" />
</form>

和jquery修复了使用url lang前缀:

$('#lang_changer input[name="next"]').attr('value', '/'+window.location.pathname.substring(4));

在页面准备好后运行。

答案 6 :(得分:1)

我对自定义模板标记的问题是该函数根据当前网址计算其他语言等效项,因为我正在使用 modeltranslation package 然后,网址之间的slu is总是相同的。 e.g:

example.com/en/article/english-slug
example.com/es/articulo/english-slug

为了解决这个问题,我采用了稍微不同的方法,在视图级别计算备用网址,并在模板上下文中使用它们。

为此起作用:

1-使用以下帮助函数

创建 utils.py 文件
from django.utils.translation import activate, get_language
from django.conf import settings

def getAlternateUrls(object):
    #iterate through all translated languages and get its url for alt lang meta tag                      
    cur_language = get_language()
    altUrls = {}
    for language in settings.LANGUAGES:
        try:
            code = language[0]
            activate(code)
            url = object.get_absolute_url()
            altUrls[code] = url
        finally:
            activate(cur_language)
    return altUrls;

2-让您的模型定义反向网址:get_absolute_url

3-添加一个上下文变量,该变量将保存 views.py

中的urls字典
from .utils import getAlternateUrls
...
def MyView(DetailView):
    def get_context_data(self, **kwargs):
        context['alt_urls'] = getAlternateUrls(self.object)

4-在模板的head部分生成备用URL元标记

<!-- alternate lang -->
{% for key, value in alt_urls.items %}
<link rel="alternate" hreflang="{{ key }}" href="http://{{ request.get_host }}{{ value}}">
{% endfor %}
{% endblock %}

在Django 1.8中测试

答案 7 :(得分:1)

我尝试尽可能简单 - 使用任意数量reverse()的动态kwargs,以便语言切换(或任何其他类似的东西)将重定向到当前视图。< / p>

在templatetags dir文件中添加了简单的模板标记(例如,templatetags/helpers.py):

from django.core.urlresolvers import reverse

register = template.Library()


@register.simple_tag
def get_url_with_kwargs(request):
    url_name = ''.join([
        request.resolver_match.app_name,
        ':',
        request.resolver_match.url_name,
    ])

    url_kwargs = request.resolver_match.kwargs

    return reverse(url_name, None, None, url_kwargs)

可以在语言切换模板中使用,如下所示:

{% load helpers %}

{% get_available_languages as available_languages %}
{% get_language_info_list for available_languages as language_info_list %}

{% for language in language_info_list %}

    {% language language.code %}

        {% get_url_with_kwargs request as url_with_kwargs %}
        <a href="{{ url_with_kwargs }}">{{ language.code }}</a>

    {% endlanguage %}

{% endfor %}

很适合我。

答案 8 :(得分:1)

我宁愿评论接受的答案,但不能这样,我发布自己的答案。 我使用相当类似的解决方案基于: https://djangosnippets.org/snippets/2875/

resolvereverse方法都可能崩溃:

  • resolve会引发Resolver404异常,尤其是当您已经显示404页面时(导致500错误,非常烦人且难以检测,特别是DEBUG = True无法显示真实的404)
  • 当您尝试使用实际上没有翻译的不同语言的页面时,
  • reverse会崩溃。

也许反向更多地取决于你使用什么样的翻译方法或者其他什么,但是在404页面内解决崩溃是非常明显的。

如果出现异常,您可能希望将相同的url或url返回到索引页面,而不是在模板中引发异常。代码可能如下所示:

from django.core.urlresolvers import resolve, reverse
from django.utils.translation import activate, get_language


@register.simple_tag(takes_context=True, name="change_lang")
def change_lang(context, lang=None, *args, **kwargs):
    url = context['request'].path
    cur_language = get_language()
    try:
        url_parts = resolve(url)
        activate(lang)
        url = reverse(url_parts.view_name, kwargs=url_parts.kwargs)
    except:
        url = reverse("index") #or whatever page you want to link to
        # or just pass if you want to return same url
    finally:
        activate(cur_language)
    return "%s" % url

答案 9 :(得分:1)

对于Django 2.0(基于Philipp Zedler&#39; s answer

自定义模板:

Select

在模板中:

from django import template
from django.urls import reverse
from django.urls import resolve
from django.utils import translation
register = template.Library()

@register.simple_tag(takes_context=True)
def translate_url(context, language):
  view = resolve(context['request'].path)
  request_language = translation.get_language()
  translation.activate(language)
  url = reverse(view.app_name+":"+view.url_name, args=view.args, kwargs=view.kwargs, )
  translation.activate(request_language)
  return url

答案 10 :(得分:1)

一种简单的解决方案是将Django's translate_url function与模板标签一起使用:

# utils/templatetags/utils.py
from django.template import Library
from django.urls import translate_url as django_translate_url

register = Library()

@register.simple_tag(takes_context=True)
def translate_url(context, lang_code):
    path = context.get('request').get_full_path()
    return django_translate_url(path, lang_code)

然后在html中以这种方式使用它进行语言选择:

{% load i18n utils %}
{% get_available_languages as languages %}

<ul>
{% for lang_code, lang_name in languages %}
     <li><a href="{% translate_url lang_code %}">{{ lang_code }}</a></li>
{% endfor %}
</ul>

对于hreflangs:

{% get_available_languages as languages %}
{% for lang_code, lang_name in languages %}
    <link rel="alternate" hreflang="{{lang_code}}" href="{% translate_url lang_code %}" />
{% endfor %}

希望这会有所帮助。

答案 11 :(得分:1)

基于Jonhatan's answer的Django 3解决方案:

文件:App/templatetags.pyApp/templatetags/change_lang.py

from django.template.defaultfilters import register
from django.urls import translate_url


@register.simple_tag(takes_context=True)
def change_lang(context, lang=None, *args, **kwargs):
    path = context['request'].path
    return translate_url(path, lang)

模板:

{% load trans change_lang %}
{% trans 'View page in other languages:' %}
<a href="{% change_lang 'en' %}">English</a>
| <a href="{% change_lang 'de' %}">Deutsch</a>

答案 12 :(得分:0)

在Django 2.2中为我工作

创建自定义模板标签

from django import template
from django.urls import translate_url

register = template.Library()


@register.simple_tag(takes_context=True)
def change_lang(context, lang=None, *args, **kwargs):
    path = context['request'].path
    return translate_url(path, lang)

在模板中

{% load change_lang %}
<a href="{% change_lang 'en' %}">English</a>
<a href="{% change_lang 'es' %}">Español</a>