angle-uparrow-clockwisearrow-counterclockwisearrow-down-uparrow-leftatcalendarcard-listchatcheckenvelopefolderhouseinfo-circlepencilpeoplepersonperson-fillperson-plusphoneplusquestion-circlesearchtagtrashx

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.

7 August 2019
In Babel
post main image
Original photo unsplash.com/@jantined.

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

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.

avatar

From where 'get_url_lang_code_items_values()' and 'get_url_lang_code_default_item_value()' come from?