Specification¶
The convention this library implements is written down as a small, stable
contract so that another implementation — an extractor, an IDE, a type checker,
or a future pygettext — can target it and interoperate.
Read spec v1 :material-arrow-right:
The rules in one screen¶
A msgid is the concatenation, in source order, of the literal segments and
one {name} token per interpolation. Literal braces are escaped ({ becomes
{{). A name must be a simple placeholder name — str.isidentifier() is true
and it is not a Python keyword. Conversions and format specs are not part of
the msgid; they stay under application control.
| t-string | msgid |
|---|---|
t"Hello {name}" |
Hello {name} |
t"Total: {amount:,.2f}" |
Total: {amount} |
t"Config {{raw}} is {value}" |
Config {{raw}} is {value} |
t"Hello {user.name}" |
rejected — not a simple name |
A translation is valid when it contains only bare {name} placeholders,
every required name appears at least once, and no name outside the allowed set
appears. Reordering and repetition are deliberately unconstrained: both can be
grammatically necessary in a target language.
For plurals, allowed is the union of the branches' names and required is
their intersection — so t"One file" against t"{n} files" leaves n available
to a translator of either form but required of neither, and a target language's
plural rules can differ from the source's.
An empty msgid is never looked up, because gettext reserves it for a catalog's metadata header.
Conformance¶
conformance/v1.json
is the same document in machine-readable form: cases mapping a t-string's static
structure to a msgid, and a msgid plus a catalog pattern to a rendered string or
a rejection.
An implementation conforms to spec v1 when it reproduces every case. The cases name only what the specification defines — derived msgids, accepted and rejected patterns, rendered output — and never an error message or an exception type, so an implementation in another language can run them unchanged.
Interpolations are described structurally, never as Python source:
{
"spec": "2.2",
"name": "format spec stays out of the msgid",
"source": ["Total: ", {"expression": "amount", "value": 1234.5, "format_spec": ",.2f"}],
"msgid": "Total: {amount}"
}
The reference implementation runs the suite as part of its own test suite, so the prose and the code cannot drift apart in silence.
Versioning¶
This is spec v1. A backwards-incompatible change to msgid derivation or to
translation validation increments the version and ships a new
conformance/vN.json beside the existing one. Additive clarifications that
change neither derived msgids nor accepted patterns do not.