[web] Migrate manual plurals to i18next _plural convention (#33989)

* Add tests on plurals

* Update `collabs_per_proj` and its pluralisations

* Update `n_user` and its pluralisations

* Update `showing_x_results` and its pluralisations

* Update `show_x_more_projects` and its pluralisations

* `bin/run web npm run extract-translations`

* Populate `_plural` keys in non-en locales

For 2-form languages (da, de, es, fi, fr, it, nl, no, pt, sv, tr), copy
the existing bare-key value into the new `_plural` sibling to prevent
i18next from falling back to English for count!=1.

Also remove orphan singular keys (`collabs_per_proj_single`,
`showing_1_result*`) left over from the previous commits.

Bare-key values remain in their original plural form pending translator
review — count=1 will still render the plural form in non-en until
translators flip those to singular. Multi-form (cs, pl, ru) and
single-form (ja, ko, zh-CN, zh-TW) locales are unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Flip non-en bare-key values to singular form

Per review, the i18next v3 plural convention uses the bare key for count=1
(singular) and `_plural` for count!=1. The non-en bare-key values were
left as the original plural form by the previous commit so the `_plural`
siblings could be copied from them; this commit flips the bare values to
the singular form per language.

Languages where singular and plural noun forms coincide (Finnish, Swedish,
Turkish) are unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Apply suggestions from code review

Co-authored-by: Olzhas Askar <olzhas.askar@gmail.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Olzhas Askar <olzhas.askar@gmail.com>
GitOrigin-RevId: 628513ca792c2dcce023247e52b7320e2741cc54
This commit is contained in:
Antoine Clausse
2026-06-02 08:07:17 +00:00
committed by Copybot
co-authored by Claude Opus 4.7 Olzhas Askar
parent 58884231c1
commit 0e4fe4090a
24 changed files with 104 additions and 71 deletions
@@ -144,4 +144,34 @@ describe('i18n', function () {
.should('have.text', "<i>T</i>&<b>e</b>'s<code>t</code>ing")
})
})
describe('plurals', function () {
// See https://www.i18next.com/misc/json-format#i-18-next-json-v3
it('picks singular for count=1', function () {
const Test = () => {
const { t } = useTranslation()
return <div>{t('project_search_file_count', { count: 1 })}</div>
}
cy.mount(<Test />)
cy.findByText('in 1 file')
})
it('picks plural for count>1', function () {
const Test = () => {
const { t } = useTranslation()
return <div>{t('project_search_file_count', { count: 5 })}</div>
}
cy.mount(<Test />)
cy.findByText('in 5 files')
})
it('picks plural for count=0', function () {
const Test = () => {
const { t } = useTranslation()
return <div>{t('project_search_file_count', { count: 0 })}</div>
}
cy.mount(<Test />)
cy.findByText('in 0 files')
})
})
})