Clarify when ngettext is required in agent guidelines - #2476
Open
dsblank wants to merge 2 commits into
Open
Conversation
The existing rule ("Use ngettext(singular, plural, n) for plural
forms") states what to use but not when a string actually needs it,
which let several count-embedding strings ship with a plain _() call
during a recent FamilySearch import PR -- e.g. "%d people" reads as
"1 people" when the count is 1, with no way for translators to fix
it since the English source string is already wrong.
Add a concrete trigger (a formatted count next to a noun whose
English form changes between singular and plural), a code example
matching the codebase's dominant % formatting style, an explicit
counter-example for ordinal/fraction displays that don't need it
(e.g. "generation 3/10"), and a note to also export ngettext
alongside a centralized _ alias in package __init__.py files.
Co-Authored-By: Doug Blank <doug.blank@gmail.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Nick-Hall
reviewed
Jul 18, 2026
| The alias `_(string , context)` is preferred to `pgettext(context, message)`. | ||
| Use `ngettext(singular, plural, n)` for plural forms. | ||
|
|
||
| Use `ngettext(singular, plural, n)` instead of `_()` whenever a formatted |
Member
There was a problem hiding this comment.
We still need to use ngettext even when the English plural form is the same as the singular or the case where n is always greater than 1. Many languages have more complex plural forms than in English.
Member
Author
There was a problem hiding this comment.
Good catch, that framing was itself wrong. Reworded to drop the "English form changes" test entirely — the rule is now "any string that counts a noun" uses ngettext, and I called out explicitly that identical English singular/plural and n-always->1 are not valid reasons to skip it, since other languages have plural rules (2-4 vs 5+, dual forms, etc.) English doesn't. Commit 4485f48.
Nick-Hall pointed out that the previous wording ("whenever a noun's
English form changes between singular and plural") was itself wrong:
ngettext is needed even when English singular and plural read the
same, or when n can never be 1 in a given code path, because other
languages have plural rules English doesn't (e.g. distinct forms for
2-4 vs 5+, or dual forms for exactly 2). Reframe the rule around
"counts a noun" rather than "English form changes," and say
explicitly that neither identical English forms nor n always being
greater than 1 are valid reasons to skip ngettext.
Co-Authored-By: Doug Blank <doug.blank@gmail.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
AGENTS.mdInternationalization section said what to use (ngettext(singular, plural, n)) but not when a string actually needs it. That gap let several count-embedding strings ship with a plain_()call in a recent FamilySearch import PR (FamilySearch: fix 5 bugs, and 3 performance issues #2475) — e.g._("%d people") % 1reads as "1 people" for translators, with no way to fix it downstream since the English source string is already wrong.%formatting style, an explicit counter-example for ordinal/fraction displays that don't need it (e.g."generation %(gen)d/%(total)d"), and a note to also exportngettextalongside a centralized_alias in package__init__.pyfiles.Test plan
🤖 Generated with Claude Code