PluralShapeRule class
A count is interpolated into a sentence that has only one grammatical
shape, so some value of that count reads wrong: "{count} people"
renders "1 people".
The plural_categories rule is the other half of this: it checks a plural
is complete once one exists. Nothing checked that a plural should have
existed at all, which is how two English strings shipped saying
"1 people". This rule fires on the source only, because that is where
the defect is born — once the source is a plural expression, translations
are governed by plural_categories, and a fix applied to a translation
alone would leave the source wrong for every other locale.
The heuristic. A warning, not an error, and knowingly approximate:
- Find placeholders that carry a count. A placeholder qualifies by its
declared
@key.placeholders.<name>.type(int,num,double,number) or, when nothing is declared, by a conventional name (count,n,num,total,qty, or anything ending inCount). - Drop the ones already governed by a
plural/selectordinalexpression (IcuMessage.pluralSelectors). - Of what remains, find the noun the count governs (
_wordAfter) and fire only when that noun is already plural (_looksPlural) — which is precisely the disagreement: a count that can be 1 in front of a word that means many. - For a regular
-scandidate, require the placeholder to be in count position (_inCountPosition) — see below.
Why step 4 exists. An English third-person singular verb ends in -s,
so _looksPlural cannot tell "opens" from "people" by shape alone, and
"Goal {goal} opens now" read as "1 opens". The rule shipped asserting
that its misfires were "a verb, an adjective, or a unit … all singular in
form"; that was true of the calibration corpus, which happened to contain
no Label {n} verb-s string, and false of English. The disambiguator has
to be the text before the placeholder, because "steps" is a plural noun
in "{count} steps" and a verb in "Goal {goal} steps" — the word itself
carries no answer.
English counts forward: a number that counts either opens its phrase or
follows a function word ("and {n} others", "in {n} albums"), while a
number that follows a bare noun labels that noun ("Goal 3", "step 7") and
the -s word after it is the sentence's verb. Irregular plurals skip the
gate: "people" and "children" are never verbs, and that is the case the
rule was written for.
Erring quiet here is deliberate. A missed warning costs a re-read; a false
one blocks a --strict push over correct copy.
Saying it outright. type: int covers both "how many" and "which
one". An author can settle it declaratively with
"role": "identifier" (or "ordinal") on the placeholder, which is a
fact about the variable rather than a waiver on one wording — it survives
a rewrite, where an ack does not. Where the rule still misfires on
undeclared copy, the escape hatch is the standard one:
dialect check --ack plural_shape:source:<key>, whose fingerprint retires
the waiver as soon as the copy is edited.
Constructors
- PluralShapeRule()
-
const
Properties
- defaultSeverity → IssueSeverity
-
Default severity. May be overridden per-issue.
no setteroverride
- hashCode → int
-
The hash code for this object.
no setterinherited
- name → String
-
Stable rule identifier (snake_case). Used by the report formatter
to group findings and by users to silence/ack via state file
(post-v1.0).
no setteroverride
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
Methods
-
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
run(
DialectProject project) → List< Issue> -
Inspect
projectand return findings. May return an empty list. Should NOT throw — turn unexpected conditions into Issues so the report surfaces them rather than crashing.override -
toString(
) → String -
A string representation of this object.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited