0.1.0 — 2026-11-11
The first packaged version.
Changes
- Every attribute with an
AshGettext.Enumtype gets a public<attribute>_labelfield on resources that useAshGettext.Resource. Load it (load: [:status_label]) to get the translated label on the record. use AshGettext.Enum, backend: MyApp.Gettext, values: [...]makes an Ash enum whose ownlabel/1anddescription/1return the translated text, in Gettext's current locale. It callsuse Ash.Type.Enumfor you. There is no wrapper to call. An empty value (nil) has no label and no description.AshGettext.translate/5andtranslate_plural/7are the pure functions underneath, with the language passed as an argument.- Running an action with
actor:gives loaded_labelfields and error messages in that user's language, using the domain's onelocale_resolver. It gets the actor and returns its language. With no actor, Gettext's current process language is used. No action changes the process language, so a long-lived process never runs the next job in the last user's language. - User-facing text is always written by a person. The library never makes it
from a code name. An enum value without a
label:is a compile error. - A resource's
gettextblock holds written attribute labels (label :delivery_date, "Delivery date").attribute_label/2translates one and raises for an attribute with no written label. Alabelfor an attribute the resource does not have fails the build. - A lookup with no translation sends the telemetry event
[:ash_gettext, :translation, :missing], withbackend,text_domain,msgidandlocale. AshGettext.known_locales/1includes the source locale.- A resolver's answer is cut to a language your catalogs have (
ru_RUbecomesru), ordefault_locale. A resolver must be a pure function of the actor and must not query the database. AshGettext.DomainandAshGettext.Resourceextensions. Agettext doblock on a domain translates the errors of every create, update and destroy action on its resources, in Gettext's current language.text_domaindefaults to"ash": one catalog for Ash's errors, enum labels and attribute names. Text fromtranslate/3uses Gettext's"default".- Gettext's own
mix gettext.extractfinds every text AshGettext translates: enum labels and descriptions, attribute labels, themessages in a resource's DSL and in the validation, change and preparation modules it uses, and Ash's own error sentences. Each goes to its domain's backend andtext_domain. There is no extract task of AshGettext's own. mix ash_gettext.installpreviews, and with--applywrites, the domain and resource extensions and thegettextblock for an existing app.translate_or_missing/5,translate_plural_or_missing/7andattribute_label_or_missing/2never report:missingin the source locale (the backend's default locale). The msgid is the text, so the source language needs no catalog.require_resource_extension?on thegettextblock is an opt-in compile time check that every resource in the domain carriesAshGettext.Resource.- Ash's own errors that have no message (a missing required value, a value
that does not cast, a failed policy) come back with a written sentence in
the user's language, such as "is required", not text built from a field
name. The sentences live in
AshGettext.AshMessages, andmix gettext.extractadds them to the template. AshGettext.Erroris a user-facing error with a requiredcode, a translatablemessage, and an optionalfieldandvars. It renders for JSON:API, with no Englishtitle, when:ash_json_apiis present, which is an optional dependency.