8

Django 1.4 で新しい i18n_patterns を使い始めました。基本的に、すべてのテンプレート ヘッダーに、サポートされている各言語の言語リンクが必要です。他のテンプレートに含まれている別のテンプレートとしてヘッダーを実装しました。

テンプレート コンテキストで現在のビュー名または現在の URL を渡さずに、ヘッダーを汎用的に保ち、これを解決する方法はありますか? テンプレート内から一般的な方法で現在のビューまたは URL を取得するにはどうすればよいかという疑問が生じると思います。

ところで、リファラーを使用してアクティブな言語を変更するset_langビューを使用した以前のアプローチは、言語を変更した後、参照されたビューにリダイレクトされると元に戻るため、url_patternsで壊れることを発見しました。

一般的な方法で url_patterns と共に使用されるテンプレートに言語リンクを設定するための一般的なアプローチを理解するための助けをいただければ幸いです!

4

4 に答える 4

5

基本的に、言語の設定には 2 つの異なるアプローチがあります。を使用i18n_patternsして、URL に言語コードを自動的にプレフィックスとして追加したり、django.views.i18n.set_languageビューを使用して、ユーザーのセッション (プロジェクトがセッションをサポートしていない場合は Cookie) の言語コードの値を変更したりできます。

LocaleMiddlewareアルゴリズムが言語を決定するために使用することは注目に値します。

  • まず、要求された URL で言語プレフィックスを探します。これは、ルート URLconf で i18n_patterns 関数を使用している場合にのみ実行されます。言語プレフィックスと URL パターンを国際化する方法の詳細については、URL パターンの国際化を参照してください。

  • それに失敗すると、現在のユーザーのセッションで django_language キーを探します。

  • 使用される Cookie の名前は、LANGUAGE_COOKIE_NAME 設定によって設定されます。(デフォルト名は django_language です。)

  • それができない場合は、Accept-Language HTTP ヘッダーを調べます。このヘッダーはブラウザから送信され、優先度の高い順に、優先する言語をサーバーに伝えます。Django は、利用可能な翻訳が見つかるまで、ヘッダー内の各言語を試します。

  • これに失敗すると、グローバル LANGUAGE_CODE 設定が使用されます。

あなたが直面している可能性が高い問題は、POST データで具体的にパラメーターをset_language渡さない限り、言語プレフィックスで既に提供されている URL からリダイレクトするために使用できないことです。nextこれはset_language、以前の言語プレフィックスを含むリファラーへのリダイレクトがデフォルトで行われるためです。リファラーは古い言語でコンテンツを表示および提供します (セッション変数LocaleMiddlewareをチェックする前に、URL で言語プレフィックスを検索するため)。django_language

わかりやすくするために例を示します。

  1. あなたのユーザーは /en/news/article/1000 にいて、「language=es」を投稿するリンクをクリックしますset_language

  2. set_language「language=es」を確認し、「es」が使用可能かどうかを確認してから、「django_language」セッション変数 (または Cookie) を「es」に設定します

  3. 「next」を設定していないため、reqeuest.META['HTTP_REFERRER'] の値にリダイレクトされます。これは /en/news/article/1000 です。

  4. LocaleMiddleware( source ) URL に「en」プレフィックスが含まれていることを確認し、「en」言語を有効にして「en」に設定request.LANGUAGE_CODEします

考えられる解決策は 2 つあります。

  1. 独自のset_languageビューを記述し (元のソースはこちらを参照)、リファラー (use ) の言語プレフィックスをチェックし、django.utils.translation.get_language_from_pathリダイレクトする前に新しく選択した言語のプレフィックスに変更します。

  2. JavaScript を使用してクライアント側で同じ操作を行い、nextPOST パラメータを設定します。本当にこれはばかげています。おそらく、javascript を使用してすべての URL にユーザーの優先言語コードを動的に追加し、set_language完全に忘れる方が簡単でしょう。

おそらく、この新しいset_languageビューが Django のデフォルトの動作になるはずです。提案された実装を含むチケットが提起されましたが、実際には問題を説明しておらず、その後クローズされました。set_languageユースケース、既存の実装によって引き起こされた問題、および提案されたソリューションのより良い説明を含む新しいチケットを開くことをお勧めします.

于 2012-05-17T16:29:50.410 に答える
3

実際、ビューをいじる必要はありません。{{ request.path|slice:'3:' }}Django には便利なスライス タグがあるので、そのままリンク URL として使用できます。これにより、言語コードの接頭辞が取り除かれるため、言語は set_lang 関数によって設定されます。

于 2015-08-12T01:51:36.827 に答える
2

今日、Django 1.7 で同じ問題が発生したので、この解決策を考案しました。あまり DRY ではありませんが、問題なく動作するようです (そして、すべてのテストに合格しているので...)。組み込みの set_language ビューを使用するのではなく、それをコピーして小さな調整を行いました。結果は次のとおりです。

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

要約すると、next のビュー パラメーターを resolve() し、新しい言語を有効にした後でデータを reverse() に渡します。お役に立てれば。

于 2015-04-08T14:02:05.203 に答える
1

長い遅れをお詫び申し上げます。回答ありがとうございます。

まず、Chris による 2 つのソリューション オプションについてコメントします。カスタム set_language も JavaScript も、URL パターンの全体的な美しさが SEO フレンドリーであるため、この目的には適していません。

さらに、URL のプレフィックス言語を単に置き換えるだけでは、URL 全体が翻訳可能になる可能性があるため、urlpattern ベースの URL の完全なソリューションとして扱うことはできません。例:/en/profile/英語と/fr/profil/フランス語の場合。このような問題を解決するには、viewfunc と引数をキャプチャして、別の言語で逆にする必要があります。

幸いなことに、私のプロジェクトでは今のところ翻訳可能な URL を使用していないため、次のアプローチを採用しました。

  1. に追加django.core.context_processors.requestTEMPLATE_CONTEXT_PROCESSORSて、テンプレート レンダリング コンテキストでリクエストを使用できるようにします。

  2. RequestContextビューをレンダリングするときにビューで使用します。これは、トピックに関係なく、常に私に当てはまります。

  3. templatetagコンテキストを必要とし、指定された言語で現在の URL を返す言語コードを引数に取る非常に単純なコードを記述します。基本的に、現在の URL に有効な言語コード プレフィックスがあることを確認し、言語コードを置き換えた同じ現在の URL である別の文字列を返すだけです。

元:

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

さらに、完全なリクエストをコンテキストに注入したくない場合は、単にrequest.pathascurrent_url_pathをプッシュする独自の context_processor を作成し、代わりにそれを使用するのは非常に簡単templatetagです。

いつものようにあなたのコメントを歓迎します!

于 2012-08-23T21:15:07.700 に答える