Internationalization (Translations)

Translations are used to internationalize an application and display content in different languages. In Lila, translations are stored in the app/locales directory and can be dynamically loaded into the application.

️ Localized Routing & Language Detection

Instead of manually creating duplicate routes (like /, /es, and /en) and forcing the language inside each renderer, Lila provides the highly elegant @locales decorator from core.routing. This registers all localized path prefixes for the handler automatically and dynamically sets the active language for the request.

app/routes/routes.py

from core.routing import Router, locales
from core.templates import render

router = Router()

# English: Example rendering HTML file with Jinja2, using the @locales decorator to automatically register localized prefixes.
# Español: Ejemplo de renderizar un archivo HTML con Jinja2, usando el decorador @locales para registrar prefijos localizados de forma automática.
@router.get("/")
@locales(["es", "en"])
async def home(request: Request):
    context = {
        "url": f"http://{HOST}:{PORT}"
    }
    response = render(
        request=request, template="index", context=context
    )
    return response
                                    

Under the hood, decorating your route with @locales(["es", "en"]) will automatically register /, /es, and /en to the same handler. When the user requests a localized URL, Lila dynamically sets the appropriate active language inside the request state, which is then seamlessly picked up by Translate.lang() and the template render() function.

Forcing Language Manually (Fallback)

If you still need to force a specific language manually without using localized route prefixes, the render method also accepts an optional lang_default parameter:

Manual language override

@router.get("/custom-es")
async def custom_home(request: Request):
    response = render(
        request=request,
        template="index",
        lang_default="es"  # Manually forces Spanish translations
    )
    return response
                                    

Translation Files

To load a locale file, use the Translate class from lila.core.translate. You can access translations using:

Example translation file (app/locales/translations.json):

app/locales/translations.json

{
    "Send": {
        "es": "Enviar",
        "en": "Send"
    },
    "Cancel": {
        "es": "Cancelar",
        "en": "Cancel"
    },
    "Accept": {
        "es": "Aceptar",
        "en": "Accept"
    },
    "Email": {
        "es": "Email",
        "en": "Email"
    },
    "Name": {
        "es": "Nombre",
        "en": "Name"
    },
    "Back": {
        "es": "Volver",
        "en": "Back"
    },
    "Hi": {
        "es": "Hola",
        "en": "Hi"
    }
}
                                    

Using Translations

Get a specific translation:

example.py

from lila.core.translate import Translate

msg_error_login = Translate.t(
    key="Incorrect email or password", 
    request=request, 
    file_name="guest"
)
                                    

Helpers and Performance

Lila includes helpers to manage the application state and ensure high performance through caching.

Setting the Language

You can change the user's language dynamically. This stores the preference in an encrypted session cookie.

Option A: Dynamic POST Route (e.g. for fetch/AJAX)


@router.post("/set-language")
async def change_lang(request: Request):
    data = await request.json()
    new_lang = data.get("lang", "en")
    
    response = JSONResponse({"success": True})
    await Translate.set_lang(request, response, new_lang)
    return response
                    

Option B: Automatic Query Parameter Switching (Zero Code/Routes Required)

To completely avoid defining custom routes or controllers, Lila provides a built-in global switcher. Simply append the query parameter ?lang=code (or ?changeLang=code, ?change_lang=code) to any URL in your entire application. Lila will intercept it, update the session language preference automatically, and seamlessly perform an instant, clean redirect to the same URL without the query parameter.

Jinja2 Template / HTML Link

<!-- Dynamically switches the active language to Spanish or English and reloads the current page cleanly -->
<a href="?lang=es">🇪🇸 Español</a>
<a href="?lang=en">🇺🇸 English</a>
                    

Translating Pydantic Errors

If you use Pydantic models for validation, you can translate the error messages into Spanish automatically.


try:
    user = UserModel(**data)
except ValidationError as e:
    # Translates the first error found
    err_msg = Translate.translate_pydantic_error(e.errors()[0], target_lang="es")
    return JSONResponse({"error": err_msg}, status_code=400)
                    

Performance Note: The Translate class uses internal caching to avoid re-reading JSON files and re-processing dictionaries on every request. Language settings are also cached within the request state to minimize session decryption overhead.

Client-Side Instant Translation

To provide a completely instantaneous user experience when switching languages, Lila's SPA navigation engine (spa.js) features an optimistic translation layer. When a user requests a language switch via a query parameter (e.g., ?lang=es), the engine intercepts it and instantly translates the page on the client side before the network request completes.

How it works:

Note: Since translations occur instantly on the client, the user experiences zero lag or layout shifts during language switches, even on slow or latent connections.

Usage in Templates

Translations are automatically available in the translate context variable:

index.html

{{ translate["Send"] }}
    

{{ translate["Hi"] }} {{ user.name }}