Django 模板:获取另一种语言的当前 URL

Posted

技术标签:

【中文标题】Django 模板:获取另一种语言的当前 URL【英文标题】:Django templates: Get current URL in another language 【发布时间】:2012-07-11 08:30:23 【问题描述】:

我正在使用 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' %"  title=" lang_name "> lang_code </a></li
            % endlanguage %
        % endfor %
    </ul>
</nav>

在这种情况下,我正在反转“主页”URL。有没有办法获取当前页面的翻译 URL?

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

【问题讨论】:

【参考方案1】:

我没有使用语言前缀,而是使用翻译后的网址。但是,这个模板标签也应该可以帮助你:

# 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)

它以所需语言返回当前 url。像这样使用它:% translate_url de %

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

【讨论】:

谢谢,您的解决方案对我有用,但几乎没有改进。我在 forloop ... @register.simple_tag(name='translate_url') def do_translate_url(language): return TranslatedURL(language) ... 然后在模板中使用简单标签 ... % get_language_info_list for LANGUAGES as languages % % for language in languages % &lt;a href="% translate_url language.code %"&gt; language.name_local &lt;/a&gt; % endfor % 如果 kwarg 依赖于语言,这似乎会失败 - 例如,在 url 中使用依赖于语言的 slug 参数,这会为所有语言呈现相同的 slug。 @Flash 您是否找到了一种使用 slug 参数的方法?我也有这个问题:( @LuisPalacios 作为临时黑客,在translation.activate 之后,我正在使用view.kwargs['slug'] = MyModel.objects.get(pk=view.kwargs['id']).slug 手动修复蛞蝓 - 我相信有更好的方法。 @LuisPalacios,我已经为 translated url patterns 的项目开发了我的解决方案 - 它有效。无论如何,当 URL 与模型相关时,我们可以在模型上定义一个方法,以所需语言返回 URL。【参考方案2】:

这个 sn-p 应该这样做:

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

一旦您拥有added that as a custom template tag,您就可以执行以下操作:

&lt;a href='% change_lang 'fr' %'&gt;View this page in French&lt;/a&gt;

【讨论】:

此解决方案的缺点是:与django.conf.urls.i18n.set_language 相比,它不会保留所选语言,因此您应该自己完成,例如,通过添加额外的中间件或特殊的将处理它的视图。【参考方案3】:

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

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

【讨论】:

这充其量是一条评论。【参考方案4】:

使用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】:

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

这在此处记录:

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

唯一的一点是set_language视图需要一个POST参数,所以你需要使用&lt;form&gt;元素;您不能使用简单的&lt;a href="..."&gt; 链接。但是,有时您希望语言选择器看起来像一个链接,而不是带有选择小部件的表单。我的建议是使用一个表单,但它的样式看起来像一个链接。

您的模板可能如下所示:

<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 */

【讨论】:

language.local_name 应该是 language.name_local 另外,该解决方案与语言前缀并不能很好地配合使用。我们决定不只使用会话或 cookie 来设置和记住语言,而是使用唯一的 URL。因此,这种方法对我来说真的不起作用......(但无论如何感谢您的贡献。) 我也有类似的问题,用表格来解决也没有用。我想使用“alternate language meta tags”向客户端(或机器人)指示“此 url 是当前页面的 x 语言版本”。对此有何建议? 你也可以使用get参数。我有时会这样使用它:&lt;form action="/search/?q=" method="get"&gt;&lt;button&gt;&lt;img src="/static/images/search_20x20.png" alt="Search Symbol"&gt;&lt;/button&gt;&lt;/form&gt;【参考方案6】:

我使用来自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));

页面准备就绪时运行。

【讨论】:

在 Django 3.2 中删除 lang 前缀对我有用。我不得不在window.location.pathname 上使用这个函数***.com/a/14482123/329395,因为我有这样的前缀:es-mx【参考方案7】:

一个简单的解决方案是使用带有模板标签的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 %

希望这会有所帮助。

【讨论】:

【参考方案8】:

对于 Django 2.0(基于 Philipp Zedler 的 answer)

自定义模板:

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

在模板中:

% get_available_languages as LANGUAGES %
<ul>
  % for lang_code, lang_name in LANGUAGES %
    <li><a href="% translate_url lang_code %"> lang_name </a></li>
  % endfor %
</ul>

【讨论】:

【参考方案9】:

自定义模板标签的问题是该函数根据当前 url 计算其他语言等效项,因为我使用的是 modeltranslation package 然后url 之间的 slug 总是相同的。例如:

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

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

为此工作:

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- 让您的模型定义反向 url: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- 在模板的头部生成备用 urls 元标记

<!-- 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 中测试

【讨论】:

【参考方案10】:

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

在 templatetags 目录文件中添加了简单的模板标签(例如,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 %

非常适合我。

【讨论】:

【参考方案11】:

我宁愿评论接受的答案,但不能,所以我发布我自己的。 我正在使用基于以下内容的非常相似的解决方案: 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

【讨论】:

【参考方案12】:

在 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>

【讨论】:

【参考方案13】:

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

文件: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>

【讨论】:

以上是关于Django 模板:获取另一种语言的当前 URL的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Django 模板中获取当前 URL?

如何在 Django 模板中获取当前 URL?

如何在 Django 模板中获取当前 URL?

当前在 Django 模板中获取主页 URL(域)的方法?

Django——有没有办法从模板中引用/获取当前页面 URL? [复制]

有没有一种快速的方法来获取当前页面 url 的结尾?姜戈