【问题标题】:How to add language code to URL in Pyramid?如何在 Pyramid 中的 URL 中添加语言代码?
【发布时间】:2016-11-05 15:24:20
【问题描述】:

我刚刚创建了基本的 Pyramid “hello world”模板项目并添加了 i18n 支持。我将 Python 3.5 和 Chameleon 模板 (.pt) 与 gettext 一起使用。

我目前可以通过.ini 文件更改语言。

现在我想让它动态化并从 URL 中读取语言代码。因此 URL 更改为 /<language code>/page/{possible params},例如 /fi/home。我不想将{language} 添加到现有路由/视图中,以便隐藏语言代码参数并且视图不知道任何关于它的信息,除非在模板/视图中创建指向其他页面的链接。

编辑:这是我尝试使用 Mikko Ohtamaa 提到的tweens

添加到__init__.py:

config.add_tween('myapp.tweens.LocalizerTween')

tweens.py:

import logging

from pyramid.registry import Registry
from pyramid.request import Request

log = logging.getLogger(__name__)


class LocalizerTween(object):
  """
  Set translator based on URL
  """
  def __init__(self, handler, registry: Registry):
    self.handler = handler
    self.registry = registry

  def __call__(self, request: Request):
    if request.path.count("/") > 1 and len(request.path) > 3:
      request.locale_name = request.path[1:].split("/", 1)[0]
    else:
      # Redirect to default language
      from pyramid.settings import aslist
      import pyramid.httpexceptions as exc
      raise exc.HTTPFound("/" + aslist(request.registry.settings['pyramid.default_locale_name'])[0] + "/")

    newpath = request.path[1:]
    newpath = newpath[newpath.find("/"):]
    log.debug("new path: %s", newpath)

    request.path = newpath

    response = self.handler(request)
    return response

重定向到默认语言会出现异常:

pyramid.httpexceptions.HTTPFound: The resource was found at

尝试设置新路径:

AttributeError: can't set attribute

如果我注释掉 request.path = newpath 并转到 /fi//en/ 我会得到正确语言的 404 页。

【问题讨论】:

    标签: python url-rewriting internationalization pyramid


    【解决方案1】:

    这是一个示例解决方案,严格限于语言感知路径的范围(无本地化绑定等):

    """Self-contained language aware path routing example for Pyramid."""
    
    from urllib.parse import urlunparse
    from urllib.parse import urlparse
    from wsgiref.simple_server import make_server
    
    from pyramid.config import Configurator
    from pyramid.httpexceptions import HTTPFound
    from pyramid.request import Request
    from pyramid.response import Response
    
    
    def redirect_to_default_language(request: Request):
        """A view that redirects path language-free URLs to the default language URLs.
    
        E.g. /greeter/foobar -> /en/greeter/foobar
        """
    
        default_language = request.registry.settings["default_language"]
    
        parts = urlparse(request.url)
        new_path = "/{}{}".format(default_language, parts.path)
        new_parts = [parts[0], parts[1], new_path, parts[3], parts[4], parts[5]]
        language_redirected_url = urlunparse(new_parts)
        return HTTPFound(language_redirected_url)
    
    
    def add_localized_route(config, name, pattern, factory=None, pregenerator=None, **kw):
        """Create path language aware routing paths.
    
        Each route will have /{lang}/ prefix added to them.
    
        Optionally, if default language is set, we'll create redirect from an URL without language path component to the URL with the language path component.
        """
        orig_factory = factory
    
        def wrapper_factory(request):
            lang = request.matchdict['lang']
            # determine if this is a supported lang and convert it to a locale,
            # likely defaulting to your default language if the requested one is
            # not supported by your app
            request.path_lang = lang
    
            if orig_factory:
                return orig_factory(request)
    
        orig_pregenerator = pregenerator
    
        def wrapper_pregenerator(request, elements, kw):
            if 'lang' not in kw:
                # not quite right but figure out how to convert request._LOCALE_ back into a language url
                kw['lang'] = request.path_lang
            if orig_pregenerator:
                return orig_pregenerator(elements, kw)
            return elements, kw
    
        if pattern.startswith('/'):
            new_pattern = pattern[1:]
        else:
            new_pattern = pattern
    
        new_pattern = '/{lang}/' + new_pattern
    
        # Language-aware URL routed
        config.add_route(name, new_pattern, factory=wrapper_factory, pregenerator=wrapper_pregenerator, **kw)
    
        # Add redirect to the default language routes
        if config.registry.settings.get("default_language"):
            # TODO: This works only for the most simplest routes
            fallback_route_name = name + "_language_redirect_fallback"
            config.add_route(fallback_route_name, pattern)
            config.add_view(redirect_to_default_language, route_name=fallback_route_name)
    
    
    def home(request):
        """Example of language aware parameterless routing."""
    
        if request.path_lang == "fi":
            msg = 'Hyvää päivää!'
        else:
            msg = 'Hello sir'
    
        # This will use current language
        # and automatically populate /{lang}/ matchdict
        # as in wrapper_pregenerator()
        another_url = request.route_url("greeter", name="mikko")
    
        text = """{}
    
        Also see {}
        """.format(msg, another_url)
    
        return Response(text)
    
    
    def greeter(request):
        """Example of language aware matchdict routing."""
        name = request.matchdict["name"]
        if request.path_lang == "fi":
            return Response('Mitä kuuluu {}?'.format(name))
        else:
            return Response('How are you {}?'.format(name))
    
    
    if __name__ == '__main__':
        config = Configurator()
    
        # Map all /lang/ free URLs to this language
        config.registry.settings["default_language"] = "en"
    
        # Set up config.add_localized_route
        config.add_directive('add_localized_route', add_localized_route)
    
        # Parameterless routing
        # This will create
        # -  /
        # - /fi/
        # - /en/
        # patterns
        config.add_localized_route('home', '/')
        config.add_view(home, route_name='home')
    
        # Match dict routing
        # This will create
        # - /greet/mikko
        # - /en/greet/mikko
        # - /fi/greet/mikko
        # patterns
        config.add_localized_route('greeter', '/greet/{name}')
        config.add_view(greeter, route_name='greeter')
    
        # Run the web server
        app = config.make_wsgi_app()
        server = make_server('0.0.0.0', 8080, app)
        server.serve_forever()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-21
      • 2018-07-18
      • 2013-07-02
      • 1970-01-01
      • 1970-01-01
      • 2019-11-06
      相关资源
      最近更新 更多