python
46 lines · 8 steps
Per-request localization in Flask with Babel
How Flask-Babel picks a locale per request and localizes both messages and datetimes.
Explained by
highlit
1from flask import Flask, request, g, jsonify
2from flask_babel import Babel, gettext as _, format_datetime
3from datetime import datetime
4
5app = Flask(__name__)
6app.config["BABEL_DEFAULT_LOCALE"] = "en"
7app.config["BABEL_DEFAULT_TIMEZONE"] = "UTC"
8
9SUPPORTED_LOCALES = ["en", "es", "fr", "de", "ja"]
10
11
12def select_locale():
13 requested = request.args.get("lang")
14 if requested in SUPPORTED_LOCALES:
15 return requested
16
17 header = request.headers.get("X-User-Locale")
18 if header in SUPPORTED_LOCALES:
19 return header
20
21 return request.accept_languages.best_match(SUPPORTED_LOCALES) or app.config["BABEL_DEFAULT_LOCALE"]
22
23
24babel = Babel(app, locale_selector=select_locale)
25
26
27@app.before_request
28def store_locale():
29 g.locale = str(select_locale())
30
31
32@app.route("/api/greeting")
33def greeting():
34 name = request.args.get("name", _("friend"))
35 return jsonify(
36 locale=g.locale,
37 message=_("Hello, %(name)s! Welcome back.", name=name),
38 server_time=format_datetime(datetime.utcnow(), format="long"),
39 )
40
41
42@app.after_request
43def expose_locale(response):
44 response.headers["Content-Language"] = g.get("locale", app.config["BABEL_DEFAULT_LOCALE"])
45 response.headers.add("Vary", "Accept-Language")
46 return response
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Locale selection should fall back through explicit choice, custom headers, then the client's Accept-Language.
- 2Storing the resolved locale on g makes it available across the whole request lifecycle without recomputing it.
- 3Advertising Content-Language and Vary lets caches and clients handle localized responses correctly.
Related explainers
typescript
import { registerLocaleData } from '@angular/common'; import localeFr from '@angular/common/locales/fr'; import localeFrExtra from '@angular/common/locales/extra/fr'; import localeDe from '@angular/common/locales/de';
Locale-aware bootstrapping in Angular
i18n
localization
dependency-injection
Intermediate
8 steps
python
from fastapi import FastAPI, WebSocket, WebSocketDisconnect app = FastAPI()
Building a WebSocket chat with FastAPI
websockets
broadcast
connection-management
Intermediate
9 steps
python
import time import uuid from django.utils.deprecation import MiddlewareMixin
Attaching per-request context in Django
middleware
request lifecycle
multi-tenancy
Intermediate
7 steps
python
import random from typing import Iterator, List
How reservoir sampling picks k items
reservoir-sampling
streaming
randomness
Intermediate
5 steps
python
import secrets from django.contrib.auth import authenticate, login from django.core.cache import cache
Two-factor login with OTP in Django
two-factor-auth
one-time-passwords
caching
Intermediate
9 steps
python
import re from functools import total_ordering from typing import Optional
Parsing and comparing semantic versions
regex
operator-overloading
sorting
Intermediate
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/per-request-localization-in-flask-with-babel-explained-python-3cc5/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.