Flask meertalige verwerking, overschakeling en de 404 pagina Niet gevonden uitzondering
In dit artikel bespreken we een aantal voorwaarden bij het verwerken van de taal in de url, het gebruik van een standaardtaal en het gebruik van een lijst van beschikbare talen.
Hoe Flask meertalig te implementeren wordt uitgelegd in de Flask docs, zie onderstaande links. Maar dit is slechts een beginpunt. U moet het proces beter begrijpen om speciale gevallen te kunnen behandelen, zoals terugvallen op een standaardtaal, taalwisseling en de uitzondering 404 Page Not Found.
Veronderstellingen
In de rest van dit bericht gebruiken we een taalcode, 'lang_code', die beschikbaar is in de url, het is het eerste deel van de url, bijvoorbeeld:
https://www.example.com/en
https://www.example.com/en/login
We gebruiken ook Flask-Babel voor de vertalingen. Ik gebruik blueprints en registreer ze als volgt in create_app():
# 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>')
We gebruiken g.lang_code als de waarde van de geselecteerde taal. Ik gebruik geen sessievariabele om de taal te onthouden, maar vertrouw op de beschikbaarheid van de taal bij elk verzoek.
Flask meertalige verwerking
De manier waarop Flask omgaat met meertaligheid bij een aanvraag is als volgt:
Eerst wordt url_value_preprocessor() aangeroepen om de taal uit het url. voorbeeld te halen:
@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')
Vervolgens wordt Babels locale_selector() aangeroepen om de vertalingen voor de pagina te leveren, bijvoorbeeld:
@babel.localeselector
def get_locale():
return g.get('lang_code')
Tenslotte wordt url_defaults() aangeroepen voordat de pagina wordt gebouwd om <lang_code> te vervangen door lang_code in de urls, bijvoorbeeld:
@pages_blueprint.url_defaults
def add_language_code(endpoint, values):
# stuff g.lang_code in urls
...
values.setdefault('lang_code', g.lang_code)
Dit is vrij eenvoudig, maar zoals je kunt zien, kunnen er omstandigheden optreden waarbij de taalcode wordt gewijzigd, niet beschikbaar of zelfs niet geldig is. Het belangrijkste is om ervoor te zorgen dat g.lang_code altijd op een geldige taal is ingesteld voordat localeselector() en url_defaults() worden aangeroepen. Hieronder wordt een aantal voorwaarden besproken.
Flask meertalige verwerking: bezoekers schakelen over naar een andere taal
Om over te schakelen naar een andere taal kunnen we een GET gebruiken om de huidige aanvraag met een extra lang_code parameter te wijzigen:
<a href="{{ request.script_root + request.path }}?lc=en">English</a>
<a href="{{ request.script_root + request.path }}?lc=de">Deutsch</a>
We moeten de functionaliteit van de url_value_preprocessor() uitbreiden om de taalswitch te ondersteunen. Vereenvoudigd, deze extra code lijkt op deze extra code:
@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 meertalige verwerking: taal ontbreekt in url en standaardtaal.
Dit kan geen fout zijn omdat u misschien wilt dat de bezoeker uw domeinnaam url intypt en naar de standaard taalpagina's wordt 'omgeleid'. Maar dit kan ook gebeuren als een bezoeker een verkeerde url intypt, een (zoek)bot belt een verkeerde url. Ook dit kunnen we in de url_value_preprocessor() verwerken. In dit geval stellen we de lang_code in op de lang_code van de standaardtaal:
@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 meertalige verwerking: taal is geen ondersteunde taal.
Onze applicatie ondersteunt slechts een beperkt aantal talen, bijv:
available_lang_codes = ['en', 'de']
Ook hier kunnen we het ongeldige taalgeval in de url_value_preprocessor() behandelen. Als de taal niet geldig is, stellen we de lang_code in op de lang_code van de standaardtaal:
@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 meertalige verwerking: Pagina niet gevonden (404) fout (404)
Deze gaf me wat hoofdpijn, het kostte me wat debugging om te zien dat de stroom in dit geval anders is. Wat hier gebeurt is dat als geen van de blueprints 's overeenkomt met de aanvraag url, url_value_preprocessor() NOOIT wordt aangeroepen. Bijvoorbeeld, met de blueprints eerder getoond, is dit een geldige url:
http://127.0.0.1:8000/en/auth/login
maar deze url geeft een 404 uitzondering:
http://127.0.0.1:8000/en/auth/login/something
Wat te doen hier? Het antwoord is om deze voorwaarde te verwerken in de Flask @before_request. Op een normale flow before_request() wordt url_value_preprocessor (!) genoemd:
@pages_blueprint.url_value_preprocessor
def pull_lang_code(endpoint, values):
....
@app.before_request
def before_request():
....
In het geval van een 404 uitzondering wordt url_value_preprocessor() NIET aangeroepen maar before_request() wordt nog steeds aangeroepen:
@app.before_request
def before_request():
....
Normaal gesproken zal url_value_preprocessor() g.lang_code instellen op een waarde, een taalcode. Maar op een 404 wordt url_value_preprocessor() niet aangeroepen en is g.lang_code niet ingesteld. In before_request() controleren we de waarde van g.lang_code. Als het niet is ingesteld kunnen we het verzoek zelf in behandeling nemen. Als het eerste deel een geldige taalcode is, gaan we ervan uit dat we deze nodig hebben en stellen we g.lang_code in. Anders stellen we g.lang_code in op de standaard taal. Wanneer vervolgens de 404 handler wordt aangeroepen, kan de pagina in de juiste taal worden weergegeven.
Samenvatting
Ik heb geen sessievariabele gebruikt om de geselecteerde taal op te slaan, maar in plaats daarvan vertrouw ik op de taal in de url. Dit werkt prima als we met allerlei omstandigheden omgaan, zoals een ontbrekende taal. Het belangrijkste is om de taal in g in te stellen alvorens alle andere bewerkingen uit te voeren.
Links / credits
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/
Lees meer
Babel Flask Multilanguage
Recent
- Database UUID primaire sleutels van je webapplicatie verbergen
- Don't Repeat Yourself (DRY) met Jinja2
- SQLAlchemy, PostgreSQL, maximum aantal rijen per user
- Toon de waarden in SQLAlchemy dynamische filters
- Veilige gegevensoverdracht met Public Key versleuteling en pyNaCl
- rqlite: een alternatief voor SQLite met hoge beschikbaarheid en distributed
Meest bekeken
- Met behulp van Python's pyOpenSSL om SSL-certificaten die van een host zijn gedownload te controleren
- Gebruik van UUIDs in plaats van Integer Autoincrement Primary Keys met SQLAlchemy en MariaDb
- Maak verbinding met een dienst op een Docker host vanaf een Docker container
- PyInstaller en Cython gebruiken om een Python executable te maken
- SQLAlchemy: Gebruik van Cascade Deletes om verwante objecten te verwijderen
- Flask RESTful API verzoekparametervalidatie met Marshmallow-schema's