Specification¶
You can use this library without reading this page — the
tutorial and guide cover everyday use. This page is
for tool authors: the convention the 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. For
the same rules explained with their reasons, and how the reference
implementation carries them out, read How it works first.
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 "spec" field is not a specification version — every case in
v1.json belongs to spec v1. It names the section of SPEC.md the case
exercises, so "2.2" reads as §2.2, the rule for deriving a placeholder token.
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.