Docs / fastkit-i18n / Overview

fastkit-i18n

Laravel-style i18n for FastAPI. JSON translation files, automatic locale detection, and translatable SQLAlchemy/SQLModel models — without touching a framework. The standalone extraction of the i18n module from fastkit-core.

Open Source MIT License Python 3.10+ 139 tests 95% coverage
$ pip install fastkit-i18n

Introduction

Most FastAPI apps eventually need more than one language — validation messages, API responses, or content that comes straight from the database. fastkit-i18n covers all three with a single, small library built around three independent pieces:

_() / TranslationManager

JSON translation files with dot-notation keys, variable interpolation, and locale fallback. Zero dependencies.

LocaleMiddleware

A pure ASGI middleware — detects locale from headers, query params, or cookies. Works with FastAPI, Starlette, or Litestar. Zero dependencies.

TranslatableMixin

Multi-language fields on SQLAlchemy or SQLModel models — a field reads and writes like a plain string, backed by JSON per-locale storage. Needs [sqlalchemy].

Each piece works completely on its own. Use just _() for a single-language app that wants centralized strings, or all three together for a fully multi-language API.

Quick Example

json
{
  "messages": {
    "welcome": "Welcome to the API!",
    "hello":   "Hello, {name}!"
  }
}
json
{
  "messages": {
    "welcome": "¡Bienvenido a la API!",
    "hello":   "¡Hola, {name}!"
  }
}
python
from fastapi import FastAPI
from fastkit_i18n import LocaleMiddleware, _

app = FastAPI()
app.add_middleware(LocaleMiddleware)  # Accept-Language / ?lang= / cookie

@app.get("/")
def root():
    return {"message": _("messages.welcome")}

@app.get("/hello/{name}")
def hello(name: str):
    return {"message": _("messages.hello", name=name)}
bash
curl http://localhost:8000/ -H "Accept-Language: es"
# {"message": "¡Bienvenido a la API!"}

Features

Zero mandatory dependencies

_() and LocaleMiddleware need nothing beyond the standard library. SQLAlchemy is an optional extra, only for TranslatableMixin.

Any ASGI framework

LocaleMiddleware speaks raw ASGI — works identically on FastAPI, Starlette, and Litestar.

SQLAlchemy and SQLModel

TranslatableMixin works with either — a SQLModel table class is a real SQLAlchemy mapped class underneath.

Fails loud, not silent

Combine TranslatableMixin with another base class in the wrong order and it raises a clear TypeError at class-definition time — never a silently empty field.

Graceful fallback

Missing keys and missing locales fall back automatically — partial translations never break your app.

Fully typed

Ships a py.typed marker — inline type hints throughout, no stub packages needed.

Use Cases

Multi-language APIs

Return API responses in the caller's language, detected automatically from the request.

Translatable content

Blog posts, product catalogs, or CMS content stored once per model, in as many languages as you need.

Validation messages

Provide the translation primitive that fastkit-core's validation-error formatting builds on.

Single-language apps

Centralize every user-facing string in JSON — change a label in one place instead of hunting through the codebase.

How it works

All three pieces share the same locale context. LocaleMiddleware reads the request once per call and sets the locale for that request only; _() and TranslatableMixin both read from that same shared context, so nothing needs to be wired together manually.

Request
Accept-Language: es
LocaleMiddleware
sets context locale
Your route
_() / model.title
Response
Spanish content

The context resets automatically once the request finishes, so a locale set for one request can never leak into another — even under concurrent requests.