[wp-trac] [WordPress Trac] #63642: Passing stringy number to _n() can result in a plural when singular is intended

WordPress Trac noreply at wordpress.org
Tue Jul 1 04:44:35 UTC 2025


#63642: Passing stringy number to _n() can result in a plural when singular is
intended
--------------------------------------+------------------------------
 Reporter:  dd32                      |       Owner:  (none)
     Type:  defect (bug)              |      Status:  new
 Priority:  normal                    |   Milestone:  Awaiting Review
Component:  I18N                      |     Version:  6.5
 Severity:  normal                    |  Resolution:
 Keywords:  has-patch has-unit-tests  |     Focuses:
--------------------------------------+------------------------------
Changes (by dd32):

 * keywords:  needs-unit-tests has-patch => has-patch has-unit-tests


Old description:

> Through #59656 a new translation layer was added that replaced the less-
> performant pomo class, for ''some operations''.
>
> WordPress passes numeric strings around quite often when they come from
> database queries, for example, as the return value of `wp_count_posts()`.
>
> This when used with `_n()` can result in an stringy numeric value being
> passed to the `$count` parameter.
>
> Long story short, POMO's [https://github.com/WordPress/wordpress-
> develop/blob/fb4ec6f5b4499208fef7032eb1db63fde8f70a77/src/wp-
> includes/pomo/translations.php#L213-L215
> Translations::translate_plural()] casts `$count` to an integer before
> strict comparisons to `1`, where as [https://github.com/WordPress
> /wordpress-develop/blob/fb4ec6f5b4499208fef7032eb1db63fde8f70a77/src/wp-
> includes/l10n/class-wp-translations.php#L127
> WP_Translations::translate_plural()]'s fallback pluralisation expects
> that it'll only ever be passed an integer and strictly compares that.
>
> This can cause `_n( 'Singular', 'Plural', '1' )` to return `Plural` as `1
> !== '1'` but it depends upon which translation handler the translation
> hits, as it will return `Singular` with a POMO handler, and likely return
> `Singular` if a translation exists via `WP_Translations`.
>
> PR incoming, which casts at the deepest point. Potentially these casts
> should live at a higher level, but this is the status-quo.

New description:

 Through #59656 a new translation layer was added that replaced the less-
 performant pomo class, for ''some operations''.

 WordPress passes numeric strings around quite often when they come from
 database queries, for example, as the return value of `wp_count_posts()`.

 This when used with `_n()` can result in an stringy numeric value being
 passed to the `$count` parameter.

 Long story short, POMO's [https://github.com/WordPress/wordpress-
 develop/blob/fb4ec6f5b4499208fef7032eb1db63fde8f70a77/src/wp-
 includes/pomo/translations.php#L213-L215 Translations::translate_plural()]
 casts `$count` to an integer before strict comparisons to `1`, where as
 [https://github.com/WordPress/wordpress-
 develop/blob/fb4ec6f5b4499208fef7032eb1db63fde8f70a77/src/wp-includes/l10n
 /class-wp-translations.php#L127 WP_Translations::translate_plural()]'s
 fallback pluralisation expects that it'll only ever be passed an integer
 and strictly compares that.

 '''This is strictly about the Fallback pluralisation, if the string is
 present in the translation file, it works as expected, this is only an
 issue if the string is not in the file.'''

 This can cause `_n( 'Singular', 'Plural', '1' )` to return `Plural` as `1
 !== '1'` but it depends upon which translation handler the translation
 hits, as it will return `Singular` with a POMO handler, and likely return
 `Singular` if a translation exists via `WP_Translations`.

 PR incoming, which casts at the deepest point. Potentially these casts
 should live at a higher level, but this is the status-quo.

--

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/63642#comment:2>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list