Symfony pipes
The Symfony plural format
Symfony’s Translation component writes plurals as
one string with pipe separated forms. In its simplest shape the
forms simply follow CLDR order; the full syntax adds explicit counts like
{0} and intervals like ]1,Inf[ for messages
that need special cases, with %count% carrying the number.
This page covers both shapes, the component’s history, and the same plural in JSON, YAML and properties.
Examples
The same plural, three languages
The pipe count grows with the language, and position maps to CLDR order: two segments for English, four for Polish, six for Arabic.
"items": "# item|# items" "items": "# artykuł|# artykuły|# artykułów|# artykułu" "items": "لا عناصر|عنصر واحد|عنصران|# عناصر|# عنصرًا|# عنصر" The dedicated Symfony spelling below sits beside these plain pipes:
# the full Symfony syntax, with explicit
# counts and intervals
"apples": "{0} no apples|{1} one apple|]1,Inf[ %count% apples" items: "# item|# items" items: "# artykuł|# artykuły|# artykułów|# artykułu" cart.items=# item|# items How it works
Position by default, rules when you ask
With plain pipes, the translator supplies the forms in order and the component
maps the count to a position through the locale’s plural rule. The
explicit syntax overrides that: {0} matches exactly
zero, ]1,Inf[ matches everything above one, and the first matching
segment wins. It is a pragmatic middle ground: readable pairs for simple
languages, escape hatches when a message needs them.
Origin
Where it came from
The pipe syntax arrived with Symfony 2’s Translation component in 2011,
in the era of transChoice(). It has carried Symfony applications
since; Symfony 4.2 added ICU MessageFormat support alongside it in 2018, and
both conventions now coexist in the framework’s translation files, pipes
for the classic domains and ICU for the +intl-icu ones.
Trade offs
Strengths and limits
Compact and quotable
One string per key in any file format, no structure needed, no braces to balance.
Explicit special cases
Exact counts and intervals express zero states and cutoffs that pure CLDR categories cannot.
Pipes are load bearing
A pipe inside a translation must not exist; positional segments inherit the same shifting risks arrays have.
In locamorph
How locamorph treats Symfony pipes
The symfony plural format joins translated forms with pipes in CLDR order on export, the shape Symfony’s plain convention reads. Imported pipe strings arrive as the single values they are; a Symfony project that wants decomposed plural editing can round trip through the XLIFF files Symfony also speaks, or the ICU domain files.
Further reading
- Symfony message formats, pipes and ICU side by side
- Symfony Translation component
Related
Keep going
Pipes out, when pipes are wanted
Translate with named forms and export pipe joined strings for the Symfony side of your stack.