Подтвердить что ты не робот

Шаблоны Django: Получить текущий URL на другом языке

Я использую i18n_patterns для создания языковых префиксов в приложении Django.

Мои URL-адреса выглядят следующим образом:

/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. Есть ли способ получить переведенный URL-адрес текущей страницы?

Если я на немецкой версии моей "контактной" страницы, я хочу, чтобы ссылка "fr" указывала на французскую версию "контактной" страницы, а не на "домашнюю страницу".

4b9b3361

Ответ 1

Я не использую языковые префиксы, но перевел URL вместо этого. Однако этот тег шаблона также должен помочь вам:

# 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 %}

Комментарии и предложения по улучшению приветствуются.

Ответ 3

Я думаю, что стоит упомянуть, что есть встроенная функция под названием translate_url.

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

Ответ 4

Я думаю, что вы добавляете ненужное усложнение проблемы. То, что вы ищете, - это простой языковой селектор. 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 */
}

Ответ 5

Используйте 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>

Ответ 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));

запускается при готовности страницы.

Ответ 7

Проблема с пользовательским тегом шаблона заключается в том, что функция вычисляет эквивалент другого языка на основе текущего URL-адреса, поскольку я использую пакет переноса модели, тогда слизь всегда была одинаковой между URL-адресами. например:.

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- Добавьте переменную контекста, которая будет удерживать словарь urls в ваших view.py

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

4- Генерировать метатеги альтернативных 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

Ответ 8

Я попытался сделать это как можно проще - использовать динамический reverse() с любым числом kwargs, чтобы языковой переключатель (или любой другой подобный материал) перенаправлялся на текущий вид.

Добавлен простой тег шаблона в dir файл 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 %}

Хорошо работает для меня.

Ответ 9

Я бы предпочел прокомментировать принятый ответ, но не могу, поэтому я отправляю свой собственный. Я использую довольно похожее решение, основанное на: https://djangosnippets.org/snippets/2875/

Существует проблема, с которой могут столкнуться как методы resolve, так и reverse:

  • 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

Ответ 10

Для Django 2.0 (основано на ответе Филиппа Зедлера 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>

Ответ 11

Простым решением было бы использование функции Django translate_url с тегом шаблона:

# 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 %}

Надеюсь, это поможет.

Ответ 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>