A simple Python library for internationalization (i18n) that uses ContextVar to manage the current language (locale). This makes it thread-safe and suitable for concurrent applications like web servers.
- Simple API:
set_locale()and_()are all you need. - Thread-safe: Uses
ContextVarfor safe use in concurrent environments. - Flexible: Works with any web framework (Flask, FastAPI, etc.) or in simple scripts.
- YAML-based translations.
pip install ctx-i18nYou will also need to install PyYAML:
pip install PyYAMLCreate a locales directory in your project and add your YAML translation files.
locales/en.yml:
greeting: "Hello, {name}!"
farewell: "Goodbye."locales/tr.yml:
greeting: "Merhaba, {name}!"
farewell: "Hoşçakal."You can tell ctx-i18n where to find your locales folder in two ways:
Option A: Environment Variable (Recommended for applications)
Set the APP_PATH environment variable to the absolute path of the directory that contains your locales folder.
export APP_PATH=/path/to/your/projectOption B: base_path Parameter (Recommended for scripts or specific contexts)
Pass the base_path argument directly to the set_locale function (which internally calls load_translations). The base_path should be the absolute path of the directory that contains your locales folder.
from pathlib import Path
from ctx_i18n import set_locale, _
# Assuming 'locales' is a subdirectory of your script's current working directory
project_root = Path.cwd()
set_locale("en", base_path=project_root)import os
from pathlib import Path
from ctx_i18n import set_locale, _
# --- Option A: Using APP_PATH environment variable ---
# Set the APP_PATH to the directory containing the 'locales' folder.
# This is typically done once at application startup.
os.environ["APP_PATH"] = str(Path.cwd()) # Example: current working directory
# Set the locale to Turkish
set_locale("tr")
print(_("greeting", name="World")) # Output: Merhaba, World!
# --- Option B: Passing base_path directly to set_locale ---
# This overrides APP_PATH for this specific call.
# Assuming 'locales' is a subdirectory of your script's current working directory
project_root = Path.cwd()
set_locale("en", base_path=project_root)
print(_("greeting", name="World")) # Output: Hello, World!
# If a translation is not found, the key is returned
print(_("non.existent.key")) # Output: non.existent.keyctx-i18n is ideal for web apps. Here's how to use it with Flask.
from flask import Flask, request
from pathlib import Path
import os
from ctx_i18n import set_locale, _
app = Flask(__name__)
# Set APP_PATH to the directory containing the 'locales' folder.
os.environ["APP_PATH"] = str(Path(__file__).parent)
@app.before_request
def set_language_from_request():
# Set locale from a query param (e.g., /?lang=tr) or header
lang = request.args.get("lang") or request.headers.get("Accept-Language", "en")
set_locale(lang.split(',')[0].split('-')[0])
@app.route("/")
def home():
# The `_` function will automatically use the locale set in the middleware.
return f"<h1>{_('greeting', name='User')}</h1>"
if __name__ == "__main__":
app.run(debug=True)ctx-i18n also works seamlessly with FastAPI.
NOTE: This example might not run on Python 3.14 due to dependency incompatibilities (pydantic-core, watchfiles) with PyO3. It is provided for reference.
from fastapi import FastAPI, Request
from typing import Optional
from pathlib import Path
import os
from ctx_i18n import set_locale, _
app = FastAPI()
# Set APP_PATH to the directory containing the 'locales' folder.
os.environ["APP_PATH"] = str(Path(__file__).parent)
@app.middleware("http")
async def set_language_middleware(request: Request, call_next):
lang = request.query_params.get("lang") or request.headers.get("Accept-Language", "en").split(',')[0].split('-')[0]
set_locale(lang)
response = await call_next(request)
return response
@app.get("/")
async def home(name: Optional[str] = "User"):
return {
"app_name": _("app_name"),
"welcome_message": _("welcome_message", name=name),
"current_language": _("current_language"),
}
# To run this FastAPI example (on a compatible Python version):
# 1. Save it as `app_fastapi.py`.
# 2. Make sure you have a `locales` directory next to it.
# 3. Run `uvicorn app_fastapi:app --reload`.
# 4. Visit http://127.0.0.1:8000/?lang=tr and http://127.0.0.1:8000/?lang=enTo run the tests, first install the development dependencies:
poetry install --with devThen run pytest:
poetry run pytestThis project is licensed under the MIT License.