【问题标题】:Django: prefix/postfix language slug in i18n_urlsDjango:i18n_urls 中的前缀/后缀语言 slug
【发布时间】:2021-10-21 07:47:33
【问题描述】:

我有一个 django-cms 站点,在 urls.py 中使用 i18n_patterns。这行得通,网址的构建类似于/lang/here-starts-the-normal/etc/

现在,我想要这样的网址:/prefix-lang/here-starts...。由于将有几个国家特定的域,这将类似于瑞士/.ch 域的/ch-de/here-...,各州的/us-en/here-starts....,等等。因此,当 URL 为 /ch-de/... 时,LANGUAGE 仍将是 de。希望这很清楚吗?

由于内容填充了现有的LANGUAGES=(('de', 'DE'), ('en', 'EN'), ...),我无法为每个域更改LANGUAGES - 在 cms、modeltranslation 中找不到任何内容,仅提及这两个。

如何在 i18n_patterns 中添加语言 slug 前缀?有可能吗?

【问题讨论】:

    标签: django django-cms django-i18n


    【解决方案1】:

    我认为一种不用过多破解 Django 的方法是使用您运行的网络服务器提供的 URL 重写工具,例如,对于 mod_wsgi,您可以使用 mod_rewritesimilar facility 也适用于 uWSGI

    您可能还需要对 Django 的输出进行后处理,以确保所有链接也正确重写以遵循新架构。不是最干净的方法,但似乎可行。

    【讨论】:

    • 是的。看起来很容易。我们忘记的最明显的。不过,SCRIPT_NAMEFORCE_SCRIPT_NAME 等会有一些摆弄……请参阅stackoverflow.com/questions/47941075/host-django-on-subfolder/… 将报告它是否有效!
    • 有一个非常干燥的 i18n_patterns hack 的工作演示...FORCE_SCRIPT_NAME 目前不适用于 django-cms 页面,仅适用于 apphooks...ARF。
    • 以自定义的 LocaleMiddlewarei18n_patterns 结尾 - 如果有兴趣,请查看我自己的答案...
    【解决方案2】:

    工作示例,虽然国家/语言顺序颠倒了(en-ch 而不是ch-en),但在尝试查找语言时,它就像 django 所期望的那样(即,将语言设置为“en-ch”,如果可用,它将找到“en”)。

    此解决方案涉及修改后的LocaleMiddlewarei18n_patternsLocaleRegexResolver。它不支持使用settings.SITE_COUNTRY 设置的国家或2 字符国家代码。它通过将 url 更改为 lang-country 模式来工作,但在中间件中找到的语言代码仍将是仅语言,2 个字符,并且与现有的包含 2 个字符语言代码的 LANGUAGES 完美配合。

    custom_i18n_patterns.py - 这只是使用我们的新解析器,见下文

    from django.conf import settings
    
    from ceco.resolvers import CountryLocaleRegexURLResolver
    
    
    def country_i18n_patterns(*urls, **kwargs):
        """
        Adds the language code prefix to every URL pattern within this
        function. This may only be used in the root URLconf, not in an included
        URLconf.
        """
        if not settings.USE_I18N:
            return list(urls)
        prefix_default_language = kwargs.pop('prefix_default_language', True)
        assert not kwargs, 'Unexpected kwargs for i18n_patterns(): %s' % kwargs
        return [CountryLocaleRegexURLResolver(list(urls), prefix_default_language=prefix_default_language)]
    

    resolvers.py

    import re
    
    from django.conf import settings
    from django.urls import LocaleRegexURLResolver
    from modeltranslation.utils import get_language
    
    
    class CountryLocaleRegexURLResolver(LocaleRegexURLResolver):
        """
        A URL resolver that always matches the active language code as URL prefix.
        extended, to support custom country postfixes as well.
        """
        @property
        def regex(self):
            language_code = get_language() or settings.LANGUAGE_CODE
            if language_code not in self._regex_dict:
                if language_code == settings.LANGUAGE_CODE and not self.prefix_default_language:
                    regex_string = ''
                else:
                    # start country changes
                    country_postfix = ''
                    if getattr(settings, 'SITE_COUNTRY', None):
                        country_postfix = '-{}'.format(settings.SITE_COUNTRY)
                    regex_string = '^%s%s/' % (language_code, country_postfix)
                    # end country changes
                self._regex_dict[language_code] = re.compile(regex_string, re.UNICODE)
            return self._regex_dict[language_code]
    

    middleware.py - 只更改了很少的几行,但必须替换完整的 process_response

    
    from django.middleware.locale import LocaleMiddleware
    from django.conf import settings
    from django.conf.urls.i18n import is_language_prefix_patterns_used
    from django.http import HttpResponseRedirect
    from django.urls import get_script_prefix, is_valid_path
    from django.utils import translation
    from django.utils.cache import patch_vary_headers
    
    class CountryLocaleMiddleware(LocaleMiddleware):
        """
        This is a very simple middleware that parses a request
        and decides what translation object to install in the current
        thread context. This allows pages to be dynamically
        translated to the language the user desires (if the language
        is available, of course).
        """
        response_redirect_class = HttpResponseRedirect
    
        def process_response(self, request, response):
            language = translation.get_language()
            language_from_path = translation.get_language_from_path(request.path_info)
            urlconf = getattr(request, 'urlconf', settings.ROOT_URLCONF)
            i18n_patterns_used, prefixed_default_language = is_language_prefix_patterns_used(urlconf)
    
            if (response.status_code == 404 and not language_from_path and
                    i18n_patterns_used and prefixed_default_language):
                # Maybe the language code is missing in the URL? Try adding the
                # language prefix and redirecting to that URL.
    
                # start country changes
                language_country = language
                if getattr(settings, 'SITE_COUNTRY', None):
                    language_country = '{}-{}'.format(language, settings.SITE_COUNTRY)
                language_path = '/%s%s' % (language_country, request.path_info)
                # end country changes!
    
                path_valid = is_valid_path(language_path, urlconf)
                path_needs_slash = (
                    not path_valid and (
                        settings.APPEND_SLASH and not language_path.endswith('/') and
                        is_valid_path('%s/' % language_path, urlconf)
                    )
                )
    
                if path_valid or path_needs_slash:
                    script_prefix = get_script_prefix()
                    # Insert language after the script prefix and before the
                    # rest of the URL
                    language_url = request.get_full_path(force_append_slash=path_needs_slash).replace(
                        script_prefix,
                        '%s%s/' % (script_prefix, language_country),
                        1
                    )
                    return self.response_redirect_class(language_url)
    
            if not (i18n_patterns_used and language_from_path):
                patch_vary_headers(response, ('Accept-Language',))
            if 'Content-Language' not in response:
                response['Content-Language'] = language
            return response
    
    

    【讨论】:

      猜你喜欢
      • 2020-07-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-28
      • 2011-01-03
      • 2011-02-18
      • 1970-01-01
      相关资源
      最近更新 更多