Localization
Introduction
Section titled “Introduction”Almasix’s localization features retrieve strings in various languages so an
application can support more than one locale. Catalogs live under the app’s
lang/ directory. Groups use short keys in Python files; JSON catalogs use the
default English string as the key — the same two approaches Laravel documents.
lang/ en/ messages.py validation.py sw/ messages.py en.json sw.jsonPrism views can call the same helpers: @lang, __, trans, and
trans_choice are injected into every template. See
Control Structures.
Publishing the language files
Section titled “Publishing the language files”Scaffolded apps may ship a thin lang/ tree. To publish the framework’s English
catalogs (validation, auth, passwords, pagination, errors) into the
application:
python smith lang:publishCreate an empty tree for a new locale:
python smith make:lang swReport keys present in the fallback locale but missing from a target:
python smith lang:missing --locale=swConfiguring the locale
Section titled “Configuring the locale”The default and fallback locales come from config/app.py, typically via the
environment:
| Variable | Default | Purpose |
|---|---|---|
APP_LOCALE |
en |
Active locale when none is set on the request |
APP_FALLBACK_LOCALE |
en |
Used when the active locale lacks a key |
from almasix.config import env
config = { "locale": env("APP_LOCALE", "en"), "fallback_locale": env("APP_FALLBACK_LOCALE", "en"), # ...}Change the locale for the current request (ASGI-scoped — not process-global):
from almasix.translation import set_locale, get_locale, is_locale
set_locale("sw")get_locale() # "sw"is_locale("sw") # TrueOr through the Lang façade:
from almasix.translation import Lang
Lang.set_locale("sw")Lang.get_locale()Lang.set_fallback("en")SetLocaleMiddleware negotiates the locale when nothing was set earlier in the
pipeline: session key locale first, then Accept-Language, then the config
default. Alias it (often as locale) after session middleware on web routes:
from almasix.translation import SetLocaleMiddleware
middleware.alias({"locale": SetLocaleMiddleware})Defining translation strings
Section titled “Defining translation strings”Using short keys
Section titled “Using short keys”Place a Python file per group under lang/<locale>/. The module exposes a
translations dict (nested keys are fine):
translations = { "welcome": "Welcome to our application!", "hello": "Hello, :name",}translations = { "welcome": "Karibu kwenye programu yetu!", "hello": "Habari, :name",}For languages that differ by territory, name directories with underscores
(en_GB), matching common locale tags.
Using translation strings as keys
Section titled “Using translation strings as keys”For apps with many UI strings, store the default wording as the JSON key:
{ "I love Almasix.": "Napenda Almasix."}Do not invent short keys that collide with a group filename. Looking up
__("Action") while lang/nl/action.py exists (and no nl.json) can resolve
as the whole group file rather than a JSON line.
Retrieving translation strings
Section titled “Retrieving translation strings”Use __ or trans with dotted file.key for group catalogs, or the literal
string for JSON catalogs:
from almasix.translation import __, trans, Lang
__("messages.welcome")trans("messages.welcome")Lang.get("messages.welcome")
__("I love Almasix.")If the key is missing in the active locale and the fallback, the helpers return the key itself — never blank, never an exception.
In Prism:
@lang("messages.welcome"){{ __("messages.welcome", {"name": name}) }}Replacing parameters
Section titled “Replacing parameters”Placeholders are prefixed with :. Pass replacements as the second argument:
translations = { "welcome": "Welcome, :name",}__("messages.welcome", {"name": "Ada"})# Welcome, AdaPlaceholder case follows Laravel:
| Placeholder | Replacement |
|---|---|
:name |
as given |
:NAME |
uppercased |
:Name |
first letter uppercased |
translations = { "welcome": "Welcome, :NAME", # Welcome, ADA "goodbye": "Goodbye, :Name", # Goodbye, Ada}Pluralization
Section titled “Pluralization”Separate singular and plural (or more forms) with |. Retrieve with
trans_choice / Lang.choice:
translations = { "apples": "There is one apple|There are many apples",}from almasix.translation import trans_choice
trans_choice("messages.apples", 10)Interval forms and explicit counts work the same as Laravel:
translations = { "apples": "{0} There are none|[1,19] There are some|[20,*] There are many", "minutes_ago": "{1} :value minute ago|[2,*] :value minutes ago",}trans_choice("messages.minutes_ago", 5, {"value": 5}):count is injected automatically from the number passed to trans_choice.
When a string has more than two segments without intervals, Almasix selects by
CLDR plural categories for the active locale (via Babel) — zero / one /
two / few / many / other — not English-only one/other pretending to be
universal.
JSON catalogs support pipe plurals as values as well:
{ "There is one apple|There are many apples": "Kuna tofaa moja|Kuna matofaa mengi"}Checking for keys
Section titled “Checking for keys”from almasix.translation import Lang
Lang.has("messages.welcome")Lang.has_for_locale("messages.welcome", "sw") # no fallbackMissing-key hooks
Section titled “Missing-key hooks”Optionally register a callback when a key cannot be resolved (default still returns the key):
from almasix.translation import Lang
Lang.handle_missing_keys_using( lambda key, locale, replace: f"[missing:{key}]")Namespaces and package catalogs
Section titled “Namespaces and package catalogs”Packages register a namespace; look up with package::file.key:
from almasix.translation import Lang, __
Lang.add_namespace("acme", "/path/to/acme/lang")__("acme::messages.welcome")Runtime lines without a file:
Lang.add_lines({"flash": "Saved"}, locale="en", namespace="*")Overriding package language files
Section titled “Overriding package language files”To override a package’s strings without editing the package, place files under
lang/vendor/<package>/<locale>/:
lang/vendor/acme/en/messages.pyOnly define the keys you want to change; everything else still loads from the package catalog.
Locale-aware numbers and dates
Section titled “Locale-aware numbers and dates”almasix.translation.Number formats values with Babel using the active (or
given) locale — the localization counterpart to the support
Helpers Number utilities:
from almasix.translation import Number, localize_date, localize_time, set_localefrom datetime import datetime
set_locale("de")Number.format(1234.5)Number.percentage(10) # "10%"Number.currency(99.9, "EUR")Number.file_size(1_500_000)Number.for_humans(1_500_000)
localize_date(datetime.now(), format="medium")localize_time(datetime.now(), format="short")Related
Section titled “Related”- Validation — published validation catalogs
- Strings —
Str/Stringable(not translation catalogs) - Middleware — registering
SetLocaleMiddleware - Prism Control Structures
- Structure — the
langdirectory