DB Internationalization¶
Internationalize SQLModel string attributes with the I18nMixin
mixin. The mixin lets you declare localized variants of a string field (for example name_en
, name_fr
) and resolves the appropriate locale at runtime.
Register localized fields¶
Define localized attributes and register them in __localized_fields__
. The fallback language must always be available. Use the Lang
enum to define the available languages at the model level.
Example model¶
from typing import Optional
from sqlmodel import SQLModel
from sqlmodel import Field
from ecodev_core import I18nMixin
from ecodev_core import Lang
class LocalizedModel(I18nMixin, SQLModel, table=True): # type: ignore[misc]
"""Localized entity storing translated names."""
__tablename__ = 'localized_model'
__localized_fields__ = {'name': [Lang.EN, Lang.FR]}
__fallback_lang__ = Lang.EN
id: Optional[int] = Field(default=None, primary_key=True)
name_en: str = Field(description='English display name')
name_fr: Optional[str] = Field(default=None, description='French display name')
Here the field name
is declared as localized with English and French variants. The fallback language (Lang.EN
) is required (non nullable).
Runtime locale resolution¶
from sqlmodel import Session, select
from ecodev_core import engine
from ecodev_core import set_lang
from ecodev_core import Lang
from ecodev_core import localized_col
with Session(engine) as session:
english_only = LocalizedModel(name_en='Hello')
translated = LocalizedModel(name_en='Hello', name_fr='Bonjour')
session.add(english_only)
session.add(translated)
session.commit()
set_lang(Lang.FR)
print(translated.name) # Bonjour
set_lang(Lang.EN)
print(translated.name) # Hello
set_lang(Lang.EN)
print(english_only.name) # Hello
set_lang(Lang.FR)
print(english_only.name) # Hello
set_lang
uses a contextvars
context variable so the active language flows through any functions executed within the same request/task.
import contextvars
DB_LANG = 'db_lang'
CONTEXT_DB_LANG = contextvars.ContextVar(DB_LANG, default=Lang.EN)
def set_lang(lang: Lang) -> None:
CONTEXT_DB_LANG.set(lang)
def get_lang() -> Lang:
return Lang(CONTEXT_DB_LANG.get())
Querying localized data¶
localized_col
helps you build queries that use the active language (or an explicit override):
set_lang(Lang.FR)
with Session(engine) as session:
localized_query = select(
localized_col('name', LocalizedModel),
LocalizedModel.id,
)
print(session.exec(localized_query).all())
localized_query = select(
localized_col('name', LocalizedModel, Lang.EN),
LocalizedModel.id,
)
print(session.exec(localized_query).all())
filtered = select(LocalizedModel).where(
localized_col('name', LocalizedModel) == 'Bonjour'
)
print(session.exec(filtered).all())
The first query yields localized values in French as defined using set_lang
while the second yields localized values in english. The last query filters on the localized value. See the db_i18n
functional tests in ecodev-core
for more usage examples.