2012-07-11 12 views
18

Sto usando i18n_patterns per creare prefissi di lingua in un'app Django.Modelli Django: Ottieni l'URL corrente in un'altra lingua

miei URL simile a questa:

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

Nel mio modello di base, sto loop su tutte le lingue disponibili per mostrare i link interruttore lingua.

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

In questo caso, sto invertendo l'URL "casa". C'è un modo per ottenere un URL tradotto della pagina corrente?

Se sono nella versione tedesca della mia pagina "contatto", voglio che il collegamento "fr" rimandi alla versione francese della pagina "contatti", non alla pagina "home".

risposta

14

non sto usando prefissi lingua , ma invece sono gli URL tradotti. Tuttavia, questo tag modello dovrebbe anche aiutarti:

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

Restituisce l'url corrente nella lingua desiderata. Usalo in questo modo: {% translate_url de %}

Commenti e suggerimenti per miglioramenti sono i benvenuti.

+4

Grazie, la tua soluzione funziona per me con pochi miglioramenti. Sto usando semplice tag all'interno forloop ... '@ register.simple_tag (name = 'translate_url') def do_translate_url (lingua): ritorno TranslatedURL (lingua)' ... Poi, nel template ... '{% get_language_info_list per le lingue come lingue%} {% per la lingua in lingue%} {{ language.name_local }} {% endfor%}' – pista329

+0

questo sembra fallire se i kwargs dipendono dalla lingua - per esempio con un linguaggio dipendente dalla 'lumaca 'parametro nell'URL rende lo stesso slug per tutte le lingue. – Flash

+0

@Flash hai trovato un modo per lavorare con i parametri di lumaca? Sto avendo anche questo problema :( –

2

Penso che si aggiunga una complicazione inutile al problema. Quello che stai cercando è un semplice selettore di lingua. Django fornisce questa funzionalità immediatamente e reindirizza sempre alla pagina corrente (in un'altra lingua).

Questo è documentato qui:

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

L'unica cosa è che la vista set_language si aspetta un parametro POST, quindi è necessario utilizzare un elemento <form>; non è possibile utilizzare un semplice collegamento <a href="...">. Tuttavia, a volte si desidera che il selettore della lingua assomigli a un collegamento, non come un modulo con un widget di selezione. La mia proposta è di usare un modulo, ma lo stile per sembrare un collegamento.

Il modello potrebbe essere simile a questo:

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

e quindi si utilizza i CSS per lo stile delle forme e bottoni di invio a guardare come i collegamenti normali:

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

'{{}} language.local_name' 'dovrebbe essere {{}} language.name_local'. –

+6

Inoltre, questa soluzione non funziona molto bene insieme ai prefissi di lingua. Abbiamo deciso di non usare solo la sessione o i cookie per impostare e ricordare la lingua e invece abbiamo scelto URL univoci. Quindi quell'approccio non funziona davvero per me ... (Ma grazie comunque per averlo contribuito.) –

+3

Ho un problema simile e non è utile usare un modulo per risolverlo. Voglio utilizzare "[meta tag di linguaggio alternativo] (http://support.google.com/webmasters/bin/answer.py?hl=it&answer=189077)" per dettare al cliente (o al bot) che "questo URL è versione della lingua x della pagina corrente ". Qualche suggerimento a riguardo? –

5

Questo frammento dovrebbe farlo:

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

Una volta che hai added that as a custom template tag, allora si può fare qualcosa di simile:

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

+1

funziona ancora perfettamente con django 1.8 – soField

+0

Lo svantaggio di questa soluzione è: non conserva una lingua selezionata in contrasto con 'django. conf.urls.i18n.set_language', quindi dovresti farlo da solo, ad esempio aggiungendo un middleware in più o una vista speciale che lo gestirà. – potar

1

Io uso forma lingua standart da 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> 

e jQuery difficoltà a lavorare con url Lang prefissi:

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

corsa quando la pagina pronto.

1

Il problema che ho avuto con il tag modello personalizzato è che la funzione calcola l'altra equivalente linguaggio basato sulla URL corrente, come io sto usando modeltranslation package poi la lumaca era sempre lo stesso tra gli URL. es .:

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

per risolvere questo ho preso un approccio leggermente diverso, calcolando le URL alternativi a livello di vista e li hanno a disposizione nel contesto del modello.

per questo lavoro:

1- Creare un file diutils.py con la seguente funzione di supporto

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- Avere vostri modelli definire l'URL inverso: get_absolute_url

3- Aggiungi una variabile di contesto che manterrà il dizionario url nel tuo views.py

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

4- Generare le alterne meta tag URL alla sezione head del modello

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

testato in Django 1.8

1

ho cercato di rendere il più semplice possibile - per usare dinamica reverse() con qualsiasi numero di kwargs, in modo che lo switch di lingua (o qualsiasi altra roba simile) reindirizzerà alla vista corrente.

aggiunta di tag semplice modello in templatetags di file dir (ad esempio, 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) 

che potrebbe essere utilizzato nel modello di interruttore linguaggio come questo:

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

per me funziona abbastanza bene.

1

Preferisco commentare la risposta accettata, ma non posso pubblicare i miei. Sto usando soluzione abbastanza simile a base di: https://djangosnippets.org/snippets/2875/

C'è problema che sia resolve e reverse metodi possono mandare in crash:

  • resolve può sollevare un'eccezione Resolver404, soprattutto quando si sta già visualizzando pagina 404 (causando Errore 500, molto fastidioso e difficile da rilevare, in particolare con DEBUG = True non visualizza 404 reale)
  • reverse può arrestarsi in modo anomalo quando si tenta di ottenere una pagina con una lingua diversa che in realtà non ha trans mento.

Forse l'inversione dipende più dal tipo di metodo di traduzione che si usa o da qualsiasi altra cosa, ma risolvere il crash all'interno della pagina 404 è piuttosto ovvio.

In caso di eccezione, è possibile che si desideri restituire lo stesso URL o magari l'URL nella pagina di indice anziché generare un'eccezione nel modello. Codice può assomigliare a questo:

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 
2

penso che la pena ricordare che c'è una funzione built-in chiamato translate_url (url, LANG_CODE)

+1

Questo è un commento al meglio. – gobrewers14

2

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

per Django 2.0 (basato su answer di Philipp Zedler)

Modello personalizzato:

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 

In Template:

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