8

Ich fing an, mit neuen i18n_patterns in Django 1.4 zu spielen. Grundsätzlich möchte ich Sprachlinks für jede meiner unterstützten Sprachen in allen Vorlagenheadern haben. Ich habe meinen Header als separate Vorlage implementiert, die in anderen Vorlagen enthalten ist.Django1.4: Generische Möglichkeit, Sprachlinks in der Vorlage so einzustellen, dass sie mit i18n_patterns funktionieren?

Gibt es eine Möglichkeit, meinen Header generisch zu halten und dies zu lösen, ohne den aktuellen View-Namen oder die aktuelle URL im Template-Kontext zu übergeben? Ich denke, es kommt zu einer Frage, wie ich die aktuelle Ansicht oder URL aus der Vorlage in generischer Weise abrufen kann.

BTW, ich entdeckte, dass mein früherer Ansatz mit set_lang view, um die aktive Sprache mit dem Referrer zu ändern, mit url_patterns gebrochen wird, wie nach der Änderung der Sprache wird es zurück, wenn auf die verwiesene Ansicht umgeleitet.

Jede Hilfe, die den allgemeinen Ansatz zum Festlegen von Sprachlinks in Vorlagen zur allgemeinen Verwendung mit url_patterns ermittelt, wäre willkommen!

Antwort

1

Ich entschuldige mich für die lange Verzögerung. Vielen Dank für Ihre Antworten.

Als erstes zu den beiden Lösungsoptionen von Chris kommentieren: Weder benutzerdefinierte set_language noch Javascript sind gut für den Zweck, da die ganze Schönheit der URL-Muster SEO freundlich ist.

Darüber hinaus kann das einfache Ersetzen der Präfixsprache in URL nicht als vollständige Lösung für Urlpattern-basierte URLs behandelt werden, da auch die gesamte URL übersetzbar ist. Bsp .: /en/profile/ für Englisch und /fr/profil/ für Französisch. Um ein solches Problem zu lösen, muss man die Viewfunc und die Argumente erfassen, um sie für verschiedene Sprachen umzukehren.

Zum Glück für mich verwendet mein Projekt keine übersetzbaren URLs für jetzt und ich nahm den folgenden Ansatz.

  1. hinzufügen django.core.context_processors.request zu TEMPLATE_CONTEXT_PROCESSORS so dass Anforderung in Vorlage Rendering-Kontext zur Verfügung steht.

  2. Verwenden Sie RequestContext in Ansichten beim Rendern Ihrer Ansichten. Das ist für mich unabhängig vom Thema immer der Fall.

  3. Schreiben Sie eine ziemlich einfache templatetag, die den Kontext erfordert und ein Argument einen Sprachcode verwendet, um die aktuelle URL in der angegebenen Sprache zurückzugeben. Es stellt im Grunde sicher, dass die aktuelle URL ein gültiges Sprachcode-Präfix hat und gibt einfach eine andere Zeichenfolge zurück, die die gleiche aktuelle URL mit ersetztem Sprachcode ist.

ex:

from django import template 
register = template.Library() 

@register.simple_tag(takes_context=True) 
def get_current_url_for_lang(context, lang_code): 
    request=context.get('request',False) 
    if not request: 
     return None 

    request=context['request'] 
    curr_url=request.path 
    if len(curr_url) < 4 or curr_url[0] != '/' or curr_url[3] != '/': 
     return curr_url 

    if context.get('LANGUAGES',False): 
     codes = [] 
     for code,name in context['LANGUAGES']: 
      codes.append(code) 

     curr_langcode = curr_url[1:3] 
     if lang_code not in codes or curr_langcode not in codes: 
      return curr_url 

    changed_url = '/'+lang_code+curr_url[3:] 
    return changed_url 

Außerdem, wenn man nicht die volle Anfrage in einem Kontext injizieren mag wird es ganz einfach sein, Ihre eigene context_processor zu schreiben, die einfach die request.path als current_url_path zum Beispiel drückt und Verwendung das stattdessen in Ihrem templatetag.

Ihre Kommentare sind wie immer willkommen!

5

Grundsätzlich gibt es zwei verschiedene Ansätze zum Einstellen der Sprache. Sie können i18n_patterns verwenden, um Ihre URLs automatisch mit einem Sprachcode zu versehen, oder Sie können die django.views.i18n.set_language Ansicht verwenden, um den Wert des Sprachcodes in der Benutzersitzung zu ändern (oder ein Cookie, wenn Ihr Projekt keine Sitzungsunterstützung hat) .

Es ist erwähnenswert, der Algorithmus LocaleMiddleware Sprache verwendet, um zu bestimmen:

  • Zuerst sieht es für die Sprache Präfix in der gewünschten URL. Dies wird nur durchgeführt, wenn Sie die i18n_patterns-Funktion in Ihrer root URLconf verwenden. Weitere Informationen zum Sprachenpräfix und zur Internationalisierung von URL-Mustern finden Sie unter Internationalisierung: in URL-Mustern.

  • Wenn das nicht funktioniert, sucht es in der Sitzung des aktuellen Benutzers nach einem Schlüssel Django_language.

  • Andernfalls wird nach einem Cookie gesucht. Der Name des verwendeten Cookies wird in der Einstellung LANGUAGE_COOKIE_NAME festgelegt. (Der Standardname ist django_language.)

  • Wenn das nicht klappt, wird der Accept-Language-HTTP-Header betrachtet. Dieser Header wird von Ihrem Browser gesendet und teilt dem Server die von Ihnen bevorzugten Sprachen in der Reihenfolge ihrer Priorität mit. Django versucht jede Sprache in der Kopfzeile, bis sie eine mit den verfügbaren Übersetzungen findet.

  • Wenn dies nicht der Fall ist, wird die globale Einstellung LANGUAGE_CODE verwendet.

Das Problem, das Sie in wahrscheinlich ausgeführt sind, ist, dass Sie nicht set_language verwenden können, von einer URL zu umleiten, die bereits mit einer Sprache Präfix serviert werden, wenn Sie speziell einen next Parameter in den POST-Daten übergeben. Dies liegt daran, dass set_language standardmäßig zum Referrer umleitet, der das vorherige Sprachpräfix enthält. LocaleMiddleware wird dann den Inhalt in der alten Sprache anzeigen und bereitstellen (weil er vor der Überprüfung der Sitzungsvariablen django_language nach einem Sprachenpräfix in der URL sucht)).

Ein Beispiel zur Verdeutlichung:

  1. Ihre Benutzer auf/en/news/article/1000 und auf den Link klickt, die 'Sprache = es' zu set_language veröffentlichen wird.

  2. set_language sieht 'language = es', überprüft, ob 'es' zur Verfügung steht, und setzt dann das 'django_language' Session-Variable (oder Cookie) auf 'es'

  3. Da Sie nicht haben set 'weiter', leitet es auf den Wert von reqeuest.META [ 'HTTP_REFERRER'], die/en/news/article/1000

  4. LocaleMiddleware (source) sieht den 'en' Präfix in der uRL, und aktiviert die Sprache 'en' und setzt request.LANGUAGE_CODE auf 'en'

Ich sehe zwei mögliche Lösungen:

  1. Schreiben Sie Ihre eigene set_language Ansicht (die ursprüngliche Quelle here sehen), die für eine Sprache Präfix in den Referrer überprüfen wird (verwenden django.utils.translation.get_language_from_path), und es auf die Änderung Präfix für die neu ausgewählte Sprache vor dem Weiterleiten an sie.

  2. Verwenden Sie Javascript, um die gleiche Operation clientseitig auszuführen, und legen Sie den POST-Parameter next fest. Wirklich, das ist irgendwie dumm; es wäre wahrscheinlich einfacher, nur Javascript zu verwenden, um alle URLs mit dem bevorzugten Sprachcode des Benutzers dynamisch voranzukommen und ungefähr set_language zusammen zu vergessen.

Es scheint, dass diese neue set_language Ansicht wahrscheinlich Djangos Standard-Verhalten sein sollte. There was a ticket raised, die eine vorgeschlagene Implementierung beinhaltete, aber das Problem nicht wirklich beschrieb und anschließend geschlossen wurde. Ich schlage vor, ein neues Ticket mit einer besseren Beschreibung Ihres Anwendungsfalls, dem Problem, das durch die vorhandene set_language Implementierung verursacht wurde, und Ihrer vorgeschlagenen Lösung zu öffnen.

+0

Über die Verwendung von set_language mit i18n_pattern denke ich, dass Sie benutzerdefinierte Middleware-Klasse hinzufügen können, die URL ohne Sprachpräfix in Ihrem Anfragekontext hinzufügen. Ich habe versucht, eine einfache Middleware-Klasse [hier] zu schreiben (http://machakux.appspot.com/blog/17010/django_using_i18n_patterns_and_locale_switcher). – machaku

2

Hatte das gleiche Problem heute mit Django 1.7, ich habe diese Lösung - nicht sehr trocken, aber es scheint zu funktionieren OK (und alle meine Tests sind vorbei, so ...). Anstatt die builtin set_language Ansicht mit, ich habe es kopiert und machte eine kleine Anpassung - hier ist das Ergebnis:

def set_language(request): 
""" 
Redirect to a given url while setting the chosen language in the 
session or cookie. The url and the language code need to be 
specified in the request parameters. 

Since this view changes how the user will see the rest of the site, it must 
only be accessed as a POST request. If called as a GET request, it will 
redirect to the page in the request (the 'next' parameter) without changing 
any state. 
""" 
next = request.POST.get('next', request.GET.get('next')) 
if not is_safe_url(url=next, host=request.get_host()): 
    next = request.META.get('HTTP_REFERER') 
    if not is_safe_url(url=next, host=request.get_host()): 
     next = '/' 
lang_code = request.POST.get('language', None) 
# Start changed part 
next = urlparse(next).path # Failsafe when next is take from HTTP_REFERER 
# We need to be able to filter out the language prefix from the next URL 
current_language = translation.get_language_from_path(next) 
translation.activate(current_language) 
next_data = resolve(next) 
translation.activate(lang_code) # this should ensure we get the right URL for the next page 
next = reverse(next_data.view_name, args=next_data.args, kwargs=next_data.kwargs) 
# End changed part 
response = http.HttpResponseRedirect(next) 
if request.method == 'POST': 
    if lang_code and check_for_language(lang_code): 
     if hasattr(request, 'session'): 
      request.session[LANGUAGE_SESSION_KEY] = lang_code 
     else: 
      response.set_cookie(settings.LANGUAGE_COOKIE_NAME, lang_code, 
           max_age=settings.LANGUAGE_COOKIE_AGE, 
           path=settings.LANGUAGE_COOKIE_PATH, 
           domain=settings.LANGUAGE_COOKIE_DOMAIN) 
return response 

Um es zusammenzufassen, ich lösen() die Ansicht Parameter für den nächsten, dann die Daten passieren zu umkehren() nach dem Aktivieren der neuen Sprache. Hoffe das hilft.

+1

großartige Lösung, danke, aber es fehlt eine Sache - HTTP_REFERER enthält Hostname, so dass 'Übersetzung.get_language_from_path' in diesem Fall' None' zurückgibt. Ich habe URL-Parser importiert und diese Zeile "next = urlparse (next) .path" am Anfang von "Start changed part" hinzugefügt. – bellum

+0

Guter Punkt - habe ich nicht bemerkt, da ich immer nur verwende? Next = (und halte den Referrer nur als Standard, nur für den Fall); Ich werde die Antwort entsprechend aktualisieren. – pgcd

+0

FWIW, 'next' ist eine eingebaute Funktion in Python (mindestens seit 2.6) und sollte nicht als Variablenname verwendet werden. https://docs.python.org/3/library/functions.html#next –

2

Eigentlich ist es nicht nötig, mit Ihrer Sichtweise herumzuspielen. Django hat ein praktisches Slice-Tag, so dass Sie einfach {{ request.path|slice:'3:' }} als Ihre Link-URL verwenden können. Dadurch wird das Sprachencode-Präfix deaktiviert, sodass die Sprache von der Funktion set_lang festgelegt wird.

+0

Ehrfürchtige Lösung, wenn die Art, wie Sie dem Benutzer sagen, die Sprache zu ändern, nur ein Link irgendwo ist. –

+0

Dies ist die perfekte Antwort ohne Templatetags ohne Zusatzcodes ' {{ language.0|language_name_local|capfirst }}' –