Gender agreement
Some languages inflect verbs and adjectives for the gender of the person a sentence is about. English mostly doesn’t, so a phrase you write as {username} has been invited is one sentence in English and two or three in Spanish, French, or Russian. Langsys handles that during translation — the same way it generates plural forms — and you pass one argument.
What the pipeline produces
When a target language needs agreement, Langsys rewrites that locale's string into the branches it needs — an ICU select. Your source phrase never changes, and you never write the branches by hand.
// Your source phrase, unchanged:
"{username} has been invited"
// What the Spanish translation becomes — note invitado / invitada:
"{username_gender, select, male {{username} ha sido invitado} \
female {{username} ha sido invitada} \
other {{username} ha sido invitado/a}}" Two consequences worth internalizing. The argument is named after the variable it inflects with _gender appended — {username} gives you username_gender — and the branches are always male, female, other. And it appears only in the locales that need it: this is invisible until someone loads the app in a gendered language.
Passing it
Pass the argument whenever you know it, and the reader gets the correctly-inflected sentence:
// The argument is named after the variable it inflects, + _gender.
// Branches are always male / female / other.
t('{username} has been invited', 'Team', {
username: user.name,
username_gender: user.gender ?? 'other',
}); Don't know the gender? Pass 'other' explicitly — it's the neutral branch. What a missing argument renders varies by SDK; each SDK page says. Every SDK page also shows the call in its own idiom.
Which phrases need it?
You can't tell from your own code, and that's inherent: the argument is added during translation, per target locale, so nothing in the source phrase or your codebase hints at it. Three ways to find out.
Read the catalog. The translations your app fetches are the promoted strings, so the answer is already on the client. Pull the catalog for a locale you support — every SDK exposes it — and look for entries containing , select,. That gives you the exact phrases and argument names, and it's cheap enough to run in CI against each locale you ship.
// The catalog your app fetches IS the promoted strings — grep it.
const wanting = Object.entries(catalog)
.filter(([, translation]) => translation.includes(', select,'))
.map(([phrase]) => phrase);
// → every phrase (and, from the string, every argument) this locale needs Turn on debug (JavaScript SDKs). Pass debug: true in your init config and browse the app in a gendered locale: the SDK logs one Langsys Warning per phrase whose translation wants an argument you didn't supply, naming the argument. Once per phrase per locale, and silent in production. One wrinkle: inside the content-block and phrase components, a defensively-passed _gender is itself reported as an unmatched param, because that check runs against your source text — where the select never appears.
When in doubt, pass it. A value for an argument the string doesn't have is ignored at render time, so sending _gender for every person-shaped variable is safe and covers the locales you haven't looked at yet.
One variable per phrase. Only one variable can drive agreement. A string where two do — a count and a gender — is left unchanged rather than turned into nested ICU, so it translates as a single flat sentence.