Skip to content

Internationalization and Timezones

Phase 4 starts with request-scoped locale and timezone context so responses can stay user-aware while storage remains normalized.


Locale Resolution

Use LocaleMiddleware to resolve the active locale from Accept-Language and store it in request state and a context variable.

from aksara import Aksara
from aksara.middleware import LocaleMiddleware

app = Aksara(
    database_url="postgresql://localhost/myapp",
    middlewares=[
        (LocaleMiddleware, {
            "supported_locales": ["en", "fr", "de"],
            "default_locale": "en",
        }),
    ],
)

Inside request handlers you can access the resolved locale from either request.state.locale or aksara.middleware.locale_var.


Lazy Translations

_() returns a lazy string wrapper that resolves when coerced to str() or when it flows through Aksara's serializer/model export helpers.

from aksara import _

headline = _("Welcome back, {name}", name="Ada")
str(headline)  # "Welcome back, Ada"

Translation lookup uses Python's built-in gettext catalogs from Settings.locale_paths.


Timezone Resolution

Use TimezoneMiddleware to resolve a request timezone from X-Timezone.

from aksara.middleware import TimezoneMiddleware

app = Aksara(
    database_url="postgresql://localhost/myapp",
    middlewares=[
        (TimezoneMiddleware, {"default_timezone": "UTC"}),
    ],
)

The resolved timezone is available through request.state.timezone and aksara.middleware.timezone_var.


Datetime Storage and Serialization

When use_tz=True, DateTime fields behave as follows:

  • naive datetimes are interpreted in the active request timezone (or TIME_ZONE when no request timezone is active)
  • persisted values are normalized to UTC
  • model and API serialization convert datetimes into the active request timezone
from datetime import datetime
from aksara import Model, fields


class Event(Model):
    starts_at = fields.DateTime()


event = Event(starts_at=datetime(2026, 1, 15, 9, 30, 0))
await event.save()

If the active request timezone is America/New_York, the naive input above is treated as local New York time and stored in UTC.


Settings

from aksara.conf import Settings, configure

configure(Settings(
    supported_locales=["en", "fr", "de"],
    default_locale="en",
    locale_paths=["locale"],
    use_tz=True,
    time_zone="UTC",
))

See Settings Reference for the full list of related settings.