# python: Custom locale detection URL: https://generaltranslation.com/en-US/docs/python/tutorials/custom-locale-detection.mdx --- title: Custom locale detection description: How to customize locale detection with get_locale, and how the default behavior works --- ## Default behavior When no `get_locale` callback is provided to [`initialize_gt`](/docs/python/api/initialize-gt), GT automatically detects the user's locale from the HTTP `Accept-Language` header on every request: 1. Reads the `Accept-Language` header (e.g. `en-US,en;q=0.9,es;q=0.8`) 2. Parses it into a list of locales sorted by quality value (highest first) 3. Matches against your configured `locales` to find the best fit 4. Falls back to `default_locale` if no match is found This means out of the box, users get content in whatever language their browser requests — as long as you have translations for it. ```python from flask import Flask from gt_flask import initialize_gt app = Flask(__name__) # No get_locale — defaults to Accept-Language parsing initialize_gt( app, default_locale="en", locales=["es", "fr"], ) ``` ```python from fastapi import FastAPI from gt_fastapi import initialize_gt app = FastAPI() # No get_locale — defaults to Accept-Language parsing initialize_gt( app, default_locale="en", locales=["es", "fr"], ) ``` --- ## Custom `get_locale` To override the default, pass a `get_locale` callback to `initialize_gt`. It receives the request object and must return a locale string. ```python from flask import Flask from gt_flask import initialize_gt app = Flask(__name__) def get_locale(request) -> str: # Check query parameter first locale = request.args.get("lang") if locale: return locale # Then check a cookie locale = request.cookies.get("locale") if locale: return locale # Fall back to default return "en" initialize_gt( app, default_locale="en", locales=["es", "fr"], get_locale=get_locale, ) ``` ```python from fastapi import FastAPI, Request from gt_fastapi import initialize_gt app = FastAPI() def get_locale(request: Request) -> str: # Check query parameter first locale = request.query_params.get("lang") if locale: return locale # Then check a cookie locale = request.cookies.get("locale") if locale: return locale # Fall back to default return "en" initialize_gt( app, default_locale="en", locales=["es", "fr"], get_locale=get_locale, ) ``` --- ## How it works internally - **FastAPI**: `initialize_gt` registers an HTTP middleware that runs on every request. If `get_locale` is provided, it calls `get_locale(request)`. Otherwise it parses `Accept-Language`. The resolved locale is set on the `I18nManager`, which [`t()`](/docs/python/api/t) reads from. - **Flask**: `initialize_gt` registers a `before_request` hook with the same logic. --- ## Common patterns ### URL path prefix Extract the locale from the URL path (e.g. `/es/about`, `/fr/home`): ```python def get_locale(request) -> str: parts = request.url.path.strip("/").split("/") supported = {"es", "fr", "de"} if parts and parts[0] in supported: return parts[0] return "en" ``` ### User profile Look up the locale from an authenticated user's preferences: ```python def get_locale(request) -> str: user = get_current_user(request) # your auth logic if user and user.preferred_locale: return user.preferred_locale return "en" ``` ### Subdomain Detect locale from a subdomain like `es.example.com`: ```python def get_locale(request) -> str: host = request.headers.get("host", "") subdomain = host.split(".")[0] if subdomain in ("es", "fr", "de"): return subdomain return "en" ``` --- ## Notes - Your `get_locale` function should always return a valid locale string - If it returns a locale you don't have translations for, `t()` will fall back to the original content in `default_locale` - The function receives the raw framework request object — `Request` for FastAPI, Flask's `request` for Flask - You can use [`get_locale()`](/docs/python/api/get-locale) elsewhere in your code to read back the resolved locale