Aufbau einer mehrsprachigen Flask Website mit Flask- -Babel
Es gibt nicht viele Beispiele für Mehrsprachigkeit Flask. Hier folgen wir den Vorschlägen aus der Flask Dokumentation.
Mit einer einzigen Sprache gibt es nicht wirklich ein Problem, wir vergessen einfach den Rest der Welt und bauen unsere einzige Flask Sprachapplikation. Wir bekommen Kopfschmerzen, wenn die Website mehrere Sprachen unterstützen muss. Was genau ist eine Website, die mehrere Sprachen unterstützt? Wie viele Sprachen werden unterstützt und in welchen Sprachen? Für Englisch gibt es z.B. en-GB und en-US. Welche Teile der Website müssen in allen Sprachen verfügbar sein? Was sind die Teile einer Website überhaupt? Ich werde mich hier auf die Beantwortung der trivialsten Fragen beschränken. Für eine gute Einführung können Sie auch z.B. die Wordpress Polylang Plugin Anleitung lesen, siehe unten.
Wenn Sie eine Website erstellen, ohne mehrere Sprachen zu unterstützen, verwenden Sie URLs für Ihren Inhalt, wenn Sie weitere Sprachen hinzufügen möchten, müssen Sie alle URLs pflegen, d.h. das, was bereits erstellt wurde. Aus Sicht der SEO beginnen Sie besser mit allen mehrsprachigen Komponenten, auch wenn Sie jetzt daran zweifeln, ob Sie jemals eine andere Sprache hinzufügen werden.
Sprachauswahl
Wenn sich die Sprache in einem Cookie (Sitzung) befindet, kann die richtige Sprachanzeige ein Problem darstellen, wenn Cookies deaktiviert sind. Mit der Sprache in der Domain / URL ist dieses Problem beseitigt und auch die Website ist SEO-freundlicher.
Option 1: Sprache in der Domänenerweiterung
example.com
example.es
example.pl
Beispiel: toyota
https://www.toyota.de
https://www.toyota.es
Option 2: Sprache in der Subdomain
en.example.com
es.example.com
pl.example.com
Beispiel: cnn
https://edition.cnn.com
https://cnnespanol.cnn.com
Option 3: Sprache im URL-Pfad
example.com/de
example.com/es /es
example.com/pl
Übersetzte URLs
Übersetzte URLs sind sehr freundlich, bringen aber auch mehr Komplexität mit sich:
https://edition.cnn.com/unterhaltung
https://cnnespanol.cnn.com/seccion/entretenimiento
Einige Websites haben keine übersetzten URLs:
https://www.tesla.com/nl_NL/model3/design#battery
https://www.tesla.com/de_CH/model3/design#battery
Wenn wir übersetzte Sprach-URLs haben wollen, und warum sollten wir das nicht, dann brauchen wir auch mehrere Endpunkte für eine View-Funktion:
@pages.route('/<lang_code>/about-us', methods=['GET', 'POST'])
@pages.route('/<lang_code>/uber-uns', methods=['GET', 'POST'])
def about():
return render_template(...)
Natürlich wollen wir das irgendwie automatisiert.... schwierig.
Entscheidungen treffen
Im Moment konzentriere ich mich auf eine Website mit der "Sprach-ID" im URL-Pfad, siehe oben Option 3, und ich werde mich nicht mit übersetzten URLs befassen. Weil wir verwenden Flask, verwenden Flaskwir -Babel für unsere Übersetzungen. Einige Texte, z.B. Blogs, Kategorien, Tags, befinden sich in der Datenbank. Wir werden uns später damit befassen.
Sie können eine Website mit der Hauptsprache ohne die "Sprach-ID" im URL-Pfad und die anderen Sprachen mit der "Sprach-ID" im URL-Pfad wünschen. Ich weiß nicht wirklich, wie ich das Flask im Moment machen soll und glaube auch, dass dies die Dinge sehr kompliziert und auch an SEO denkt. Nehmen wir an, Sie wollen nach ein paar Jahren eine weitere Sprache hinzufügen, dann können Sie Ihre URLs nicht ändern: Zusammenfassung: Ich denke, es ist keine schlechte Idee, mit der Sprache im URL-Pfad zu beginnen.
In einer ersten Implementierung habe ich ein Cookie für die Sprachauswahl verwendet, jetzt muss ich dieses entfernen und die Sprache in der URL verwenden. Glücklicherweise gibt die Flask Dokumentation gute Hinweise auf die Internationalisierung. Ich schlage vor, dass du das liest (ich habe es viele Male getan). Ich habe viele blueprints, für die Homepage view.py habe ich folgendes zur Ansicht hinzugefügt:
...
home_blueprint = Blueprint('home', __name__)
# lang_code in urls
@home_blueprint.url_defaults
def add_language_code(endpoint, values):
values.setdefault('lang_code', g.lang_code)
@home_blueprint.url_value_preprocessor
def pull_lang_code(endpoint, values):
url_lang_code_items_values = get_url_lang_code_items_values()
url_lang_code_default_item_value = get_url_lang_code_default_item_value()
g.lang_code = url_lang_code_default_item_value
if values:
if 'lang_code' in values:
if values['lang_code'] in url_lang_code_items_values:
g.lang_code = values.pop('lang_code', None)
else:
pass
...
Die Funktion get_url_lang_code_items_values() gibt eine Liste von lang_codes zurück: en, nl, es, und die Funktion get_url_lang_code_default_item_value() gibt en zurück, also ist Englisch die Standardsprache. Dann registriere ich in __init__.py das Haus blueprint:
from .blueprints.home.views import home_blueprint
app.register_blueprint(home_blueprint, url_prefix='/<lang_code>')
Was passiert, wenn wir eine URL ohne Pfad oder eine völlig zufällige URL eingeben? Sie erhalten eine Fehlermeldung:
TypeError: homepage() got an unexpected keyword argument 'lang_code'
Die Flask Dokumente geben keine Lösung, aber nach einigen Kopfschmerzen (wieder) denke ich, dass ich eine Lösung gefunden habe, um dies mit dem before_request Handler zu lösen. In diesem Handler schaue ich mir die Request-URL an. Der Pfad dieser URL ist in Teile gegliedert. Der erste Teil muss unsere Sprache sein. Wenn der erste Teil in unserer Liste der Sprachen ist, dann fahren Sie einfach fort. Wenn die Seite nicht gefunden Flask wird, wird eine 404, Seite nicht gefunden, was in Ordnung ist. Wenn der erste Teil nicht unsere Liste der Sprachen ist, dann gibt der before_request Handler eine Umleitungsurl auf die Startseite der Standardsprache zurück.
Nach der Implementierung wurde die Website ohne Styles angezeigt und ich bekam seltsame Fehlermeldungen in der Developer Tools Konsole. Die Lösung bestand darin, das statische Verzeichnis auszuschließen. Hier ist also, was im before_request Handler vor sich geht:
@app.before_request
def before_request():
# try to handle missing lang_code in url interceptor
url_lang_code_items_values = get_url_lang_code_items_values()
url_lang_code_default_item_value = get_url_lang_code_default_item_value()
# check for a valid url = starts with /lang_code/
request_path = request.path.strip('/')
request_path_parts = urlparse(request_path).path.split('/')
if request.method in ['GET'] and len(request_path_parts) > 0:
request_path_part_0 = request_path_parts[0]
# do nothing with static urls !!!
if request_path_part_0 != 'static' and request_path_part_0 not in url_lang_code_items_values:
# fucked up url
redir_url_parts = []
redir_url_parts.append( request.url_root.strip('/') )
redir_url_parts.append( url_lang_code_default_item_value.strip('/') )
redir_url = '/'.join(redir_url_parts)
return redirect(redir_url)
Das funktioniert, aber wie ändern wir die Sprache?
In der base.html Vorlage habe ich einen Dropdown-Sprachwahlschalter:
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{{ language_selected }}
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="{{ request.path }}?lc=en_US">{{ _('EN') }}</a>
<a class="dropdown-item" href="{{ request.path }}?lc=nl_NL">{{ _('NL') }}</a>
<a class="dropdown-item" href="{{ request.path }}?lc=es_ES">{{ _('ES') }}</a>
</div>
</li>
Als nächstes lösen wir die Babel Sprache localeselector aus, wenn die Sprache geändert wird:
@babel.localeselector
def get_locale():
request_lc = request.args.get('lc')
if not request_lc:
if not 'lang_code' in g:
# use default
g.lang_code = 'en'
request_lc = 'en_US'
else:
if g.lang_code == 'es':
request_lc = 'es_ES'
elif g.lang_code == 'nl':
request_lc = 'nl_NL'
else:
request_lc = 'en_US'
else:
# set g.lang_code to the requested language
if request_lc == 'nl_NL':
g.lang_code = 'nl'
elif request_lc == 'es_ES':
g.lang_code = 'es'
else:
request_lc = 'en_US'
g.lang_code = 'en'
#sys.exit()
session['lc'] = request_lc
return request_lc
Ok, es funktioniert jetzt, muss aber optimiert werden. Außerdem gibt es im Moment noch zwei Probleme:
- Wenn die Sprache geändert wird, wird dies anschließend nicht mehr in der URL angezeigt.
Du musst auf eine neue Seite gehen. Nach dem Ändern der Sprache mit dem Dropdown-Menü zeigt die URL die Sprache in der URL nicht sofort an, sondern erst beim nächsten Klick. Vielleicht sollte ich den Babel Code in den before_request Handler verschieben? - Viele Aufrufe von url_defaults bei jedem Aufruf
, bei dem ich den Code haben möchte:
@home_blueprint.url_defaults
@home_blueprint.url_value_preprocessor
in der __init__.py statt in der blueprint views.py, aber das funktioniert nicht.
Warum ich das will? Weil ich es nicht mag, den gleichen Code zu duplizieren und ich sehe viele Aufrufe von @auth_blueprint.url etc. Ich glaube, sie sollten einmal in __init__.py gemacht werden, aber vielleicht liege ich falsch.
Links / Impressum
Flask Series: Internationalization
https://damyanon.net/post/flask-series-internationalization/
Flask-multilang-demo
https://github.com/DusanMadar/Flask-multilang-demo
How to Easily Create a Multilingual WordPress Site
https://www.wpbeginner.com/beginners-guide/how-to-easily-create-a-multilingual-wordpress-site/
Internationalized Application URLs
https://flask.palletsprojects.com/en/1.1.x/patterns/urlprocessors/
Multilingual flask application
https://stackoverflow.com/questions/3420897/multilingual-flask-application
Set languages and locales
https://docs.microsoft.com/en-us/windows-hardware/customize/mobile/mcsf/set-languages-and-locales
Mehr erfahren
Babel Flask Multilanguage
Einen Kommentar hinterlassen
Kommentieren Sie anonym oder melden Sie sich zum Kommentieren an.
Kommentare (1)
Eine Antwort hinterlassen
Antworten Sie anonym oder melden Sie sich an, um zu antworten.
From where 'get_url_lang_code_items_values()' and 'get_url_lang_code_default_item_value()' come from?
Neueste
- Ausblenden der Primärschlüssel der Datenbank UUID Ihrer Webanwendung
- Don't Repeat Yourself (DRY) mit Jinja2
- SQLAlchemy, PostgreSQL, maximale Anzahl von Zeilen pro user
- Anzeige der Werte in den dynamischen Filtern SQLAlchemy
- Sichere Datenübertragung mit Public Key Verschlüsselung und pyNaCl
- rqlite: eine hochverfügbare und distverteilte SQLite -Alternative
Meistgesehen
- Verwendung von Pythons pyOpenSSL zur Überprüfung von SSL-Zertifikaten, die von einem Host heruntergeladen wurden
- Verwendung von UUIDs anstelle von Integer Autoincrement Primary Keys mit SQLAlchemy und MariaDb
- Verbindung zu einem Dienst auf einem Docker -Host von einem Docker -Container aus
- PyInstaller und Cython verwenden, um eine ausführbare Python-Datei zu erstellen
- SQLAlchemy: Verwendung von Cascade Deletes zum Löschen verwandter Objekte
- Flask RESTful API Validierung von Anfrageparametern mit Marshmallow-Schemas