Search code examples
pythonflaskroutespython-babelflask-babel

Flask-Babel Multiple Language URL Routing


I am creating a multi-language site (EN and FR) and I need it to toggle back and forth on click if the user so chooses. I am using Flask-Babel and the translations and toggle are working correctly on click, however, I need the URLs to be translated as well. I have currently wrapped my URL routes like so, with both the English and French URLs:

@main.route('/accueil')
@main.route('/home')
def index():
    return render('index.html', {})

@main.route('/a-propos-de-nous')
@main.route('/about-us')
def about():
    return render('about.html', {})

The rest of the code that is grabbing the language and toggling is as follows:

app = Flask(__name__, static_folder=settings.STATIC_ROOT)
main = Blueprint('main', __name__, url_prefix='/language/<lang_code>')

@app.url_defaults
def set_language_code(endpoint, values):
    if 'lang_code' in values or not session['lang_code']:
        return
    if app.url_map.is_endpoint_expecting(endpoint, 'lang_code'):
        values['lang_code'] = session['lang_code']

@app.url_value_preprocessor
def get_lang_code(endpoint, values):
    if values is not None:
        session['lang_code'] = values.pop('lang_code', None)

@app.before_request
def ensure_lang_support():
    lang_code = session['lang_code']
    if lang_code and lang_code not in app.config['SUPPORTED_LANGUAGES'].keys():
        return abort(404)

@babel.localeselector
def get_locale():
    if session.get('lang_code') is None:
       session['lang_code'] = request.accept_languages.best_match(app.config['SUPPORTED_LANGUAGES'].keys())
    return session['lang_code']

The template looks like this where the user clicks on the link to change languages:

{% if session['lang_code']=='en' %}
    {% set new_lang_code='fr' %}
{% else %}
    {% set new_lang_code='en' %}
{% endif %}
<li><a href="{{ request.path|replace("/"+session['lang_code']+"/", "/"+new_lang_code+"/") }}">{{ _('Fr') }}</a></li>

As I have little experience with Python/Flask...I am struggling with the best way to switch to the translated URL. How would I go about doing this? Any information would be appreciated. Thanks in advance.


Solution

  • I have found a solution! I had to add endpoints to the URL routes like so:

    @main.route('accueil', endpoint="index_fr")
    @main.route('home', endpoint="index_en")
    def index():
        return render('index.html', {})
    
    @main.route('a-propos-de-nous', endpoint="about_fr")
    @main.route('about-us', endpoint="about_en")
    def about():
        return render('about.html', {})
    

    This allowed me to use Babel to translate the URL endpoints like it did for the rest of the text, and grab the correct URL ending along with the language code from the session. The toggle works like this now:

    {% if session['lang_code']=='en' %}
        {% set new_lang_code='fr' %}
    {% else %}
        {% set new_lang_code='en' %}
    {% endif %}
    
    <li><a href="{{ url_for(request.endpoint|replace("_"+session['lang_code'], "_"+new_lang_code))|replace("/"+session['lang_code']+"/", "/"+new_lang_code+"/") }}">{{ _('Fr') }}</a></li>