tutorial test template rutas method example django internationalization django-templates

test - url pk django



Plantillas Django: Obtener URL actual en otro idioma (11)

Estoy usando i18n_patterns para crear prefijos de idioma en una aplicación Django.

Mis URL se ven así:

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

En mi plantilla base, repaso todos los idiomas disponibles para mostrar los enlaces de cambio de idioma.

{% 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>

En este caso, estoy invirtiendo la URL "de inicio". ¿Hay alguna manera de obtener una URL traducida de la página actual?

Si estoy en la versión en alemán de mi página de "contacto", quiero que el enlace "fr" apunte a la versión en francés de la página de "contacto", no a la página de "inicio".


Creo que estás agregando complicaciones innecesarias al problema. Lo que estás buscando es un selector de idioma simple. Django proporciona esa funcionalidad fuera de la caja y siempre redirige a la página actual (en otro idioma).

Esto se documenta aquí:

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

Lo único es que la vista set_language espera un parámetro POST, por lo que necesita usar un elemento <form> ; no puede utilizar un enlace <a href="..."> simple. Sin embargo, a veces desea que el selector de idioma se vea como un enlace, no como un formulario con un widget de selección. Mi propuesta es usar un formulario, pero diseñarlo para que parezca un enlace.

Su plantilla podría verse así:

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

Y luego usas CSS para dar estilo a los formularios y enviar botones para que parezcan enlaces normales:

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


Creo que vale la pena mencionar que hay una función incorporada llamada translate_url .

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


El problema que tuve con la etiqueta de plantilla personalizada es que la función calcula el equivalente en otro idioma según la url actual, ya que estoy usando el paquete modeltranslation, entonces la bala siempre fue la misma entre las urls. p.ej:

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

Para solucionarlo adopté un enfoque ligeramente diferente, calculando las URL alternativas en el nivel de visualización y las tengo disponibles en el contexto de la plantilla.

Para que esto funcione:

1- Crea un archivo utils.py con la siguiente función auxiliar.

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- Haga que sus modelos definan la url inversa: get_absolute_url

3- Agrega una variable de contexto que contendrá el diccionario de urls en tus views.py

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

4- Genere las metaetiquetas de URL alternativas en la sección de encabezado de la plantilla

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

Probado en Django 1.8



No estoy usando prefijos de idioma, sino URL traducidas. Sin embargo, esta etiqueta de plantilla también debería ayudarte a:

# This Python file uses the following encoding: utf-8 from django import template from django.core.urlresolvers import reverse from django.core.urlresolvers import resolve 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)

Devuelve la url actual en el idioma deseado. Úsalo así: {% translate_url de %}

Los comentarios y sugerencias de mejoras son bienvenidos.


Para Django 2.0 (basado en la answer Philipp Zedler)

Plantilla personalizada:

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

En plantilla:

{% 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>


Prefiero hacer un comentario sobre la respuesta aceptada, pero no puedo, así que estoy publicando la mía. Estoy usando una solución bastante similar basada en: https://djangosnippets.org/snippets/2875/

Hay un problema que los métodos de resolve e reverse pueden fallar:

  • resolve puede generar la excepción Resolver404, especialmente cuando ya se muestra la página 404 (en su lugar, se producen 500 errores, muy molestos y difíciles de detectar, especialmente con DEBUG = Verdadero que no se muestra con 404 real)
  • reverse puede bloquearse cuando intenta obtener una página con un idioma diferente que en realidad no tiene traducción.

Tal vez el reverso depende más del tipo de método de traducción que use o lo que sea, pero resolver el fallo dentro de la página 404 es bastante obvio

En caso de excepción, es posible que desee devolver la misma URL o tal vez la URL a la página de índice en lugar de generar una excepción en la plantilla. El código puede verse así:

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


Traté de hacerlo lo más simple posible: usar reverse() dinámico reverse() con cualquier número de kwargs , para que el cambio de idioma (o cualquier otro elemento similar) redirija a la vista actual.

Se agregó una etiqueta de plantilla simple en el archivo dir de templatetags (por ejemplo, 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)

Que se podría utilizar en una plantilla de cambio de idioma como esta:

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

Funciona para mí bastante bien.


Una solución sencilla sería utilizar la función translate_url de Django con una etiqueta de plantilla:

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

Luego úselo de esta manera en su html para la selección de idioma:

{% 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>

Y para 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 %}

Espero que esto ayude.


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


Yo uso la forma de lenguaje estándar de los 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>

y jquery fix para trabajar con los prefijos de lang url:

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

ejecutar cuando la página está lista.