【问题标题】:Django templates: Get current URL in another languageDjango 模板:获取另一种语言的当前 URL
【发布时间】:2012-07-11 08:30:23
【问题描述】:

我正在使用 i18n_patterns 在 Django 应用程序中创建语言前缀。

我的网址如下所示:

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

在我的基本模板中,我循环遍历所有可用的语言以显示语言切换链接。

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

在这种情况下,我正在反转“主页”URL。有没有办法获取当前页面的翻译 URL?

如果我在“联系人”页面的德语版本,我希望“fr”链接指向“联系人”页面的法语版本,而不是“主页”页面。

【问题讨论】:

    标签: django internationalization django-templates


    【解决方案1】:

    我没有使用语言前缀,而是使用翻译后的网址。但是,这个模板标签也应该可以帮助你:

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

    它以所需语言返回当前 url。像这样使用它:{% translate_url de %}

    欢迎提出改进意见和建议。

    【讨论】:

    • 谢谢,您的解决方案对我有用,但几乎没有改进。我在 forloop ... @register.simple_tag(name='translate_url') def do_translate_url(language): return TranslatedURL(language) ... 然后在模板中使用简单标签 ... {% get_language_info_list for LANGUAGES as languages %} {% for language in languages %} &lt;a href="{% translate_url language.code %}"&gt;{{ language.name_local }}&lt;/a&gt; {% endfor %}
    • 如果 kwarg 依赖于语言,这似乎会失败 - 例如,在 url 中使用依赖于语言的 slug 参数,这会为所有语言呈现相同的 slug。
    • @Flash 您是否找到了一种使用 slug 参数的方法?我也有这个问题:(
    • @LuisPalacios 作为临时黑客,在translation.activate 之后,我正在使用view.kwargs['slug'] = MyModel.objects.get(pk=view.kwargs['id']).slug 手动修复蛞蝓 - 我相信有更好的方法。
    • @LuisPalacios,我已经为 translated url patterns 的项目开发了我的解决方案 - 它有效。无论如何,当 URL 与模型相关时,我们可以在模型上定义一个方法,以所需语言返回 URL。
    【解决方案2】:

    这个 sn-p 应该这样做:

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

    一旦您拥有added that as a custom template tag,您就可以执行以下操作:

    &lt;a href='{% change_lang 'fr' %}'&gt;View this page in French&lt;/a&gt;

    【讨论】:

    • 此解决方案的缺点是:与django.conf.urls.i18n.set_language 相比,它不会保留所选语言,因此您应该自己完成,例如,通过添加额外的中间件或特殊的将处理它的视图。
    【解决方案3】:

    我认为值得一提的是,有一个内置函数叫做translate_url

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

    【讨论】:

    • 这充其量是一条评论。
    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

      我认为你给问题增加了不必要的复杂性。您正在寻找的是一个简单的语言选择器。 Django 提供了开箱即用的功能,它总是重定向到当前页面(以另一种语言)。

      这在此处记录:

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

      唯一的一点是set_language视图需要一个POST参数,所以你需要使用&lt;form&gt;元素;您不能使用简单的&lt;a href="..."&gt; 链接。但是,有时您希望语言选择器看起来像一个链接,而不是带有选择小部件的表单。我的建议是使用一个表单,但它的样式看起来像一个链接。

      您的模板可能如下所示:

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

      然后您使用 CSS 设置表单样式并提交按钮,使其看起来像普通链接:

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

      【讨论】:

      • {{ language.local_name }} 应该是{{ language.name_local }}
      • 另外,该解决方案与语言前缀并不能很好地配合使用。我们决定不只使用会话或 cookie 来设置和记住语言,而是使用唯一的 URL。因此,这种方法对我来说真的不起作用......(但无论如何感谢您的贡献。)
      • 我也有类似的问题,用表格来解决也没有用。我想使用“alternate language meta tags”向客户端(或机器人)指示“此 url 是当前页面的 x 语言版本”。对此有何建议?
      • 你也可以使用get参数。我有时会这样使用它:&lt;form action="/search/?q=" method="get"&gt;&lt;button&gt;&lt;img src="/static/images/search_20x20.png" alt="Search Symbol"&gt;&lt;/button&gt;&lt;/form&gt;
      【解决方案6】:

      我使用来自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>
      

      和 jquery 修复以使用 url lang 前缀:

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

      页面准备就绪时运行。

      【讨论】:

      • 在 Django 3.2 中删除 lang 前缀对我有用。我不得不在window.location.pathname 上使用这个函数stackoverflow.com/a/14482123/329395,因为我有这样的前缀:es-mx
      【解决方案7】:

      一个简单的解决方案是使用带有模板标签的Django's translate_url function

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

      然后在您的 html 中以这种方式使用它来选择语言:

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

      对于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 %}
      

      希望这会有所帮助。

      【讨论】:

        【解决方案8】:

        对于 Django 2.0(基于 Philipp Zedler 的 answer

        自定义模板:

        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
        

        在模板中:

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

        【讨论】:

          【解决方案9】:

          自定义模板标签的问题是该函数根据当前 url 计算其他语言等效项,因为我使用的是 modeltranslation package 然后url 之间的 slug 总是相同的。例如:

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

          为了解决这个问题,我采取了一种稍微不同的方法,在视图级别计算备用 url 并让它们在模板上下文中可用。

          为此工作:

          1- 使用以下辅助函数创建一个 utils.py 文件

          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- 让您的模型定义反向 url:get_absolute_url

          3- 在你的 views.py

          中添加一个包含 urls 字典的上下文变量
          from .utils import getAlternateUrls
          ...
          def MyView(DetailView):
              def get_context_data(self, **kwargs):
                  context['alt_urls'] = getAlternateUrls(self.object)
          

          4- 在模板的头部生成备用 urls 元标记

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

          在 Django 1.8 中测试

          【讨论】:

            【解决方案10】:

            我试图让它尽可能简单 - 将动态 reverse() 与任意数量的 kwargs 一起使用,以便语言切换(或任何其他类似的东西)将重定向到当前视图。

            在 templatetags 目录文件中添加了简单的模板标签(例如,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)
            

            可以在这样的语言切换模板中使用:

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

            非常适合我。

            【讨论】:

              【解决方案11】:

              我宁愿评论接受的答案,但不能,所以我发布我自己的。 我正在使用基于以下内容的非常相似的解决方案: https://djangosnippets.org/snippets/2875/

              存在resolvereverse 方法都可能崩溃的问题:

              • resolve 会引发 Resolver404 异常,尤其是当您已经显示 404 页面时(反而会导致 500 错误,非常烦人且难以检测,尤其是在 DEBUG=True 不显示真正的 404 时)
              • reverse 可能会在您尝试使用不同语言但实际上没有翻译的页面时崩溃。

              也许反向更多地取决于您使用哪种翻译方法或其他什么,但解决 404 页面内的崩溃非常明显。

              如果出现异常,您可能希望返回相同的 url 或返回索引页面的 url,而不是在模板中引发异常。代码可能如下所示:

              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
              

              【讨论】:

                【解决方案12】:

                在 Django 2.2 中为我工作

                创建自定义模板标签

                from django import template
                from django.urls import translate_url
                
                register = template.Library()
                
                
                @register.simple_tag(takes_context=True)
                def change_lang(context, lang=None, *args, **kwargs):
                    path = context['request'].path
                    return translate_url(path, lang)
                

                在模板中

                {% load change_lang %}
                <a href="{% change_lang 'en' %}">English</a>
                <a href="{% change_lang 'es' %}">Español</a>
                

                【讨论】:

                  【解决方案13】:

                  Django 3 解决方案,基于Jonhatan's answer:

                  文件:App/templatetags.pyApp/templatetags/change_lang.py

                  from django.template.defaultfilters import register
                  from django.urls import translate_url
                  
                  
                  @register.simple_tag(takes_context=True)
                  def change_lang(context, lang=None, *args, **kwargs):
                      path = context['request'].path
                      return translate_url(path, lang)
                  

                  模板:

                  {% load trans change_lang %}
                  {% trans 'View page in other languages:' %}
                  <a href="{% change_lang 'en' %}">English</a>
                  | <a href="{% change_lang 'de' %}">Deutsch</a>
                  

                  【讨论】:

                    猜你喜欢
                    • 2018-01-05
                    • 1970-01-01
                    • 2011-02-22
                    • 1970-01-01
                    • 2011-09-15
                    • 2011-03-22
                    相关资源
                    最近更新 更多