2012-07-11 15 views
18

Używam i18n_patterns do tworzenia prefiksów języka w aplikacji Django.Szablony Django: Pobierz bieżący adres URL w innym języku

Moi URL wyglądać tak:

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

W moim szablonu bazowego, mam pętli na wszystkich dostępnych językach pokazanie powiązań zmienić język.

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

W tym przypadku cofam adres URL "macierzystego". Czy istnieje sposób, aby zamiast tego uzyskać przetłumaczony adres URL bieżącej strony?

Jeśli jestem w niemieckiej wersji strony "kontakt", chcę, aby link "fr" wskazywał na francuską wersję strony "kontakt", a nie na stronę "domową".

Odpowiedz

14

nie używam przedrostków językowe , ale przetłumaczone adresy URL. Jednak ten tag szablonu powinien również pomóc:

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

Powoduje zwrócenie bieżącego adresu URL w żądanym języku. Użyj go tak: {% translate_url de %}

Komentarze i sugestie dotyczące ulepszeń są mile widziane.

+4

Dzięki, twoje rozwiązanie działa dla mnie z niewielką poprawą. Używam prostego znacznika wewnątrz forloop ... '@ register.simple_tag (name = '') translate_url def do_translate_url (language): powrót TranslatedURL (język)' ... Następnie w szablonie ... '{% get_language_info_list dla JĘZYKÓW jako języków%} {% dla języka w językach%} {{ language.name_local }} {% endfor%}' – pista329

+0

Wydaje się to nie działać, jeśli kwargs są zależne od języka - na przykład z zależnym od języka karetką 'Parametr w adresie URL powoduje, że ten sam program działa we wszystkich językach. – Flash

+0

@Flash wymyśliłeś sposób na pracę z parametrami ślimaka? Mam też ten problem :( –

2

Myślę, że dodajesz niepotrzebne komplikacje do problemu. To, czego szukasz, to prosty selektor języka. Django udostępnia tę funkcjonalność po wyjęciu z pudełka i zawsze przekierowuje do bieżącej strony (w innym języku).

To jest udokumentowane tutaj:

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

Jedyną rzeczą jest to, że widok set_language oczekuje parametr POST, więc trzeba użyć elementu <form>; nie można użyć prostego linku <a href="...">. Czasami jednak chcesz, aby selektor języka wyglądał jak link, a nie jak formularz z wybranym widgetem. Moją propozycją jest użycie formularza, ale styl, aby wyglądał jak link.

Szablon może wyglądać następująco:

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

A potem użyć CSS projektować formularze i złożyć przyciski wyglądają jak normalne linki:

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}} 'powinna' {{language.name_local}}'. –

+6

Również to rozwiązanie nie gra dobrze z prefiksami języka. Zdecydowaliśmy, że nie będziemy używać wyłącznie sesji lub plików cookie do ustawiania i zapamiętywania języka, a zamiast tego będziemy szukać unikatowych adresów URL. Dlatego to podejście tak naprawdę nie działa dla mnie ... (Ale dzięki za przyczynienie się.) –

+3

Mam podobny problem i nie jest pomocne użycie formularza do rozwiązania tego problemu. Chcę używać "[alternatywnych metatagów językowych] (http://support.google.com/webmasters/bin/answer.py?hl=pl&answer=189077)", aby dyktować klientowi (lub botowi), że "ten adres URL jest bieżąca strona x wersja językowa ". Wszelkie sugestie na ten temat? –

5

Ten fragment powinien to zrobić:

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

Gdy masz added that as a custom template tag, można zrobić coś takiego:

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

+1

nadal działa idealnie z django 1.8 – soField

+0

Wadą tego rozwiązania jest: nie zachowuje on wybranego języka w przeciwieństwie do 'django. conf.urls.i18n.set_language', dlatego powinieneś zrobić to na własną rękę, na przykład poprzez dodanie dodatkowego oprogramowania pośredniego lub specjalnego widoku, który sobie z tym poradzi. – potar

1

używam formę językową standart z 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> 

i jquery fix do pracy z url lang prefiksów:

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

run gdy strona gotowa.

1

Problem miałem z tagu szablonu niestandardowego jest to, że funkcja oblicza inne podobne sformułowanie w oparciu o aktualny adres URL, jak używam modeltranslation package wtedy ślimak był zawsze taki sam między adresami URL. np .:

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

Aby ustalić, że wziąłem nieco inne podejście, obliczania alternatywnych adresów URL na poziomie widoku i mieć je dostępne w kontekście szablonu.

Aby to działało:

1- Tworzenie utils.py plik o następującej funkcji pomocnika

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- Czy twoje modele określić odwrotny URL: get_absolute_url

3- Dodaj zmienną kontekstową, która będzie przechowywać słownik adresów URL w Twoich views.py

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

4- Generowanie alternatywne adresy URL, meta tagi w sekcji head szablonu

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

Testowane w Django 1.8

1

starałem się zrobić to tak proste, jak to możliwe - korzystać dynamiczny reverse() z dowolną liczbą kwargs, aby przełącznik języka (lub inne podobne elementy) przekierował do bieżącego widoku.

Dodano prosty szablon tag w templatetags dir pliku (na przykład 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) 

które mogłyby być użyte w szablonie zmienić język tak:

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

pracuje dla mnie całkiem dobrze.

1

Wolę komentować zaakceptowaną odpowiedź, ale nie mogę, dlatego publikuję własne. używam dość podobne rozwiązanie w oparciu o: https://djangosnippets.org/snippets/2875/

Istnieje problem, że oba resolve i reverse metody mogą upaść:

  • resolve może podnieść wyjątek Resolver404, zwłaszcza jeśli jesteś już wyświetlania strony 404 (powodując Zamiast tego błąd 500, bardzo denerwujący i trudny do wykrycia, zwłaszcza przy DEBUG = Prawdziwe wyświetlanie nie rzeczywiste 404)
  • reverse może ulec awarii, gdy próbujesz uzyskać stronę z innym językiem, który faktycznie nie ma trans lacja.

Może odwrotnie zależy bardziej od tego, jakiego rodzaju metody tłumaczenia używasz lub cokolwiek, ale rozwiązanie awarii w obrębie strony 404 jest dość oczywiste.

W przypadku wyjątku możesz zwrócić ten sam URL lub URL strony indeksu zamiast podnieść wyjątek w szablonie. Kod może wyglądać następująco:

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

myślę, warto wspomnieć, że jest wbudowana funkcja o nazwie translate_url (url, LANG_CODE)

+1

To jest w najlepszym razie komentarz. – gobrewers14

2

Zastosowanie 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

Dla Django 2.0 (oparty na filtrze Philippa Zedlera answer)

Szablon niestandardowy:

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 

się Szablon:

{% 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> 
Powiązane problemy