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.

en · two segments
"items": "# item|# items"
pl · four segments
"items": "# artykuł|# artykuły|# artykułów|# artykułu"
ar · six segments
"items": "لا عناصر|عنصر واحد|عنصران|# عناصر|# عنصرًا|# عنصر"

The dedicated Symfony spelling below sits beside these plain pipes:

explicit counts and intervals
# the full Symfony syntax, with explicit
# counts and intervals
"apples": "{0} no apples|{1} one apple|]1,Inf[ %count% apples"
en
items: "# item|# items"
pl
items: "# artykuł|# artykuły|# artykułów|# artykułu"
en
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

strength

Compact and quotable

One string per key in any file format, no structure needed, no braces to balance.

strength

Explicit special cases

Exact counts and intervals express zero states and cutoffs that pure CLDR categories cannot.

limit

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

Pipes out, when pipes are wanted

Translate with named forms and export pipe joined strings for the Symfony side of your stack.