Documentation

File formats

Eight formats, and how plurals are handled in each.

FormatExtensionUsed by
JSON.jsonWeb, React, Vue, Node.js, i18next
ARB.arbFlutter, Dart
Android XML.xmlAndroid
Apple Strings.stringsiOS, macOS
Strings Dictionary.stringsdictiOS, macOS — plurals
String Catalog.xcstringsiOS 16+, macOS 13+
Gettext PO.poWordPress, Django, PHP
YAML.yaml / .ymlRuby on Rails, i18next

Plurals

Plural forms are not translated as ordinary strings. ParlanceKit extracts them, asks the model for every plural category the target language requires, and writes them back in the shape the format expects.

This matters because languages disagree about how many forms exist. English has two. Russian has four categories in CLDR: one, few, many, and other. Arabic has six. A source file with a singular and a plural will produce all four Russian forms, correctly inflected — not two.

Plural categories are generated for the target language, never assumed from the source. This holds regardless of what language your source file is written in.

Format-specific behaviour

String Catalogs (.xcstrings)

A catalog contains every language in a single file. ParlanceKit updates it in place, adding each target language's localizations alongside your source. Plurals nested inside substitutions or device variations are handled too.

Gettext (.po)

PO files use positional plural slots — msgstr[0], msgstr[1] — and the number of slots comes from the language's gettext rule, which is not always the same as its CLDR category count. ParlanceKit writes the correct number of slots and the correct Plural-Forms header.

ARB (.arb)

ICU plural syntax is parsed, expanded to the target's categories, and rebuilt. Surrounding prose, offsets, and exact matches such as =0 are preserved.

Placeholders

Every common placeholder syntax is protected before the text reaches the model and restored afterwards: {name}, {{count}}, %d, %@, %lld, %1$s, %{name}, %(name)s, %<n>d, and Apple's %#@variable@. A literal %% is preserved as a literal percent.

If a translation comes back with a placeholder missing or altered, ParlanceKit retries that string once. If it is still wrong, the string is left untranslated rather than written broken.