angle-up arrow-clockwise arrow-counterclockwise arrow-down-up arrow-left at calendar card-list chat check envelope folder house info-circle pencil people person person-plus phone plus question-circle search tag trash x

Flask traitement multilingue, commutation et l'exception 404 Page Not Found

13 novembre 2019 Mise à jour 15 novembre 2019 à côté de Peter

Dans ce billet, nous discutons de plusieurs conditions lors du traitement de la langue dans l'url, en utilisant une langue par défaut et en utilisant une liste des langues disponibles.

post main image
https://unsplash.com/@sadswim

Comment implémenter Flask multilangue est expliqué dans la documentation Flask , voir liens ci-dessous. Mais ce n'est qu'un point de départ. Vous avez besoin d'une compréhension plus approfondie du processus pour traiter des cas particuliers comme le retour à une langue par défaut, le changement de langue et l'exception 404 Page Not Found.

Hypothèses

Dans le reste de ce post, nous utilisons un code de langue,'lang_code', qui est disponible dans l'url, c'est la première partie de l'url, par exemple :

https://www.example.com/en

https://www.example.com/en/login

Nous utilisons également Flask-Babel pour les traductions. J'utilise blueprints et je les enregistre dans create_app() comme suit :

    # authentication (shared)
    from shared.blueprints.auth.views import auth_blueprint
    app.register_blueprint(auth_blueprint, url_prefix='/<lang_code>/auth')

    # pages (shared)
    from shared.blueprints.pages.views import pages_blueprint
    app.register_blueprint(pages_blueprint, url_prefix='/<lang_code>')

Nous utilisons g.lang_code comme valeur de la langue sélectionnée. Je n'utilise pas de variable de session pour mémoriser la langue, mais je compte plutôt sur la disponibilité de la langue dans chaque requête.

Flask traitement multilingue

La façon dont Flask gère le multilangage sur une requête est la suivante :

Tout d'abord, url_value_preprocessor() est appelé pour extraire la langue de l'exemple url :

@pages_blueprint.url_value_preprocessor
def pull_lang_code(endpoint, values):
    # pop lang_code from url and set g.lang_code
    ...
    if 'lang_code' in values:
        g.lang_code = values.pop('lang_code')

Ensuite, Babels locale_selector() est appelé pour fournir les traductions de la page, exemple :

@babel.localeselector
def get_locale():
    return g.get('lang_code')

Enfin url_defaults() est appelé avant que la page soit construite pour remplacer <lang_code> par lang_code dans les urls, exemple :

@pages_blueprint.url_defaults
def add_language_code(endpoint, values):
    # stuff g.lang_code in urls
    ...
    values.setdefault('lang_code', g.lang_code)

C'est assez simple, mais comme vous pouvez le constater, des conditions peuvent se produire lorsque le code de langue est modifié, non disponible ou même non valide. La chose la plus importante est de s'assurer que g.lang_code est toujours mis à une langue valide avant que localeselector() et url_defaults() soient appelés. Un certain nombre de conditions sont examinées ci-dessous.

Flask traitement multilingue : le visiteur passe à une autre langue

Pour passer à une autre langue, nous pouvons utiliser un GET à la requête courante avec un paramètre lang_code supplémentaire :

<a href="{{ request.script_root  +  request.path }}?lc=en">English</a>
<a href="{{ request.script_root  +  request.path }}?lc=de">Deutsch</a>

Nous devons étendre la fonctionnalité url_value_preprocessor() pour supporter le changement de langue. Simplifiée, cette option ressemble à :

@pages_blueprint.url_value_preprocessor
def pull_lang_code(endpoint, values):
    ...
    request_lang_code = request.args.get('lc')
    if request_lang_code:
        g.lang_code = request_lang_code
    ...

Flask traitement multilingue : langue manquante dans l'url et langue par défaut

Ceci peut ne pas être une erreur parce que vous pouvez vouloir que le vistor tape l'url de votre domaine et soit"redirigé" vers les pages de langue par défaut. Mais cela peut aussi arriver si un visiteur tape une mauvaise url, un bot (de recherche) appelle une mauvaise url. Encore une fois, nous pouvons gérer cela dans le préprocesseur url_value_preprocessor(). Dans ce cas, nous réglons le lang_code au lang_code de la langue par défaut :

@pages_blueprint.url_value_preprocessor
def pull_lang_code(endpoint, values):
    ...
    if g.get('lang_code') is  None:
        g.lang_code = default_lang_code

Flask traitement multilingue : langue non supportée

Notre application ne supporte qu'un nombre limité de langues, par exemple :

    available_lang_codes = ['en', 'de']

Encore une fois, nous pouvons gérer le cas de langage invalide dans le préprocesseur url_value_preprocessor(). Si la langue n'est pas valide, nous réglons le lang_code au lang_code de la langue par défaut :

@pages_blueprint.url_value_preprocessor
def pull_lang_code(endpoint, values):
    ...
    if 'lang_code' in values:
        lang_code = values.pop('lang_code')
        if lang_code not in available_lang_codes:
            g.lang_code = default_lang_code

Flask traitement multilingue : Page introuvable (erreur 404)

Celui-ci m'a donné des maux de tête, il m'a fallu du débogage pour voir que le flux est différent dans ce cas. Ce qui se passe ici est que si aucun des blueprints ne correspond à l'url de requête, url_value_preprocessor() n'est jamais appelé. Par exemple, avec le blueprints montré précédemment, c'est une url valide :

http://127.0.0.1:8000/en/auth/login

mais cette url donne une exception 404 :

http://127.0.0.1:8000/en/auth/login/something

Que faire ici ? La réponse est de traiter cette condition dans Flask @before_request. Sur un flux normal, la fonction before_request() est appelée après ( !) url_value_preprocessor() :

    @pages_blueprint.url_value_preprocessor
    def pull_lang_code(endpoint, values):
        ....

    @app.before_request
    def before_request():
        ....

Dans le cas d'une exception 404, url_value_preprocessor() n'est PAS appelé mais before_request() est toujours appelé :

    @app.before_request
    def before_request():
        ....

Normalement url_value_preprocessor() mettra g.lang_code à une valeur, un code de langue. Mais sur un 404, url_value_preprocessor() n'est pas appelé et g.lang_code n'est pas défini. Dans la fonction before_request() nous vérifions la valeur de g.lang_code. Si ce n'est pas le cas, nous pouvons traiter l'url de la requête nous-mêmes. Si la première partie est un code de langue valide, nous supposons que c'est ce dont nous avons besoin et mettons g.lang_code. Sinon, nous mettons g.lang_code à la langue par défaut. Ensuite, lorsque le gestionnaire 404 est appelé, la page peut être affichée dans la langue appropriée.

Résumé

Je n'ai pas utilisé une variable de session pour stocker la langue sélectionnée, mais plutôt compter sur la langue dans l'url. Cela fonctionne bien si nous gérons toutes sortes de conditions comme une langue manquante. Le plus important est de régler la langue en g avant d'effectuer tout autre traitement.

Liens / crédits

Flask Series: Internationalization
https://damyanon.net/post/flask-series-internationalization/

Flask-Babel
https://pythonhosted.org/Flask-Babel/

Using URL Processors
https://flask.palletsprojects.com/en/1.1.x/patterns/urlprocessors/

Laissez un commentaire

Commentez anonymement ou connectez-vous pour commenter.

Commentaires

Laissez une réponse

Répondez de manière anonyme ou connectez-vous pour répondre.