[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
@@ -321,9 +321,9 @@
"collaborator_chat": "",
"collabs_per_proj": "",
"collabs_per_proj_multiple": "",
"collabs_per_proj_plural": "",
"collabs_per_proj_plus": "",
"collabs_per_proj_single": "",
"collabs_per_proj_single_plus": "",
"collabs_per_proj_plus_plural": "",
"collapse": "",
"column_width": "",
"column_width_is_custom_click_to_resize": "",
@@ -1815,13 +1815,14 @@
"show_outline": "",
"show_version_history": "",
"show_x_more_projects": "",
"showing_1_result": "",
"showing_1_result_of_total": "",
"show_x_more_projects_plural": "",
"showing_pdf_preview_with_inverted_colors": "",
"showing_x_out_of_n_projects": "",
"showing_x_out_of_n_users": "",
"showing_x_results": "",
"showing_x_results_of_total": "",
"showing_x_results_of_total_plural": "",
"showing_x_results_plural": "",
"sidebar": "",
"sign_up": "",
"simple_search_mode": "",
@@ -191,9 +191,7 @@ export function CompileTimeoutPaywallModal({
<strong>{t('compile_timeout_modal_intro')}</strong>
</p>
<div className="compile-time-paywall-feature-list">
<ListItem>
{t('collabs_per_proj', { collabcount: 10 })}
</ListItem>
<ListItem>{t('collabs_per_proj', { count: 10 })}</ListItem>
<ListItem>{t('track_changes')}</ListItem>
<ListItem>{t('github_integration')}</ListItem>
<ListItem>{t('and_much_more')}</ListItem>
@@ -21,7 +21,7 @@ export default function LoadMore() {
className="project-list-load-more-button"
onClick={() => loadMoreProjects()}
>
{t('show_x_more_projects', { x: loadMoreCount })}
{t('show_x_more_projects', { count: loadMoreCount })}
</OLButton>
</>
) : null}
@@ -38,13 +38,7 @@ function GroupPlanCollaboratorCount({ planCode }: { planCode: string }) {
const { t } = useTranslation()
if (planCode === 'collaborator') {
return (
<>
{t('collabs_per_proj', {
collabcount: 10,
})}
</>
)
return <>{t('collabs_per_proj', { count: 10 })}</>
} else if (planCode === 'professional') {
return <>{t('unlimited_collabs')}</>
}
@@ -107,7 +107,7 @@ export function UpgradePrompt({
{t('24x_more_compile_time')}
</IconListItem>
<IconListItem icon="group_add">
{t('collabs_per_proj', { collabcount: 10 })}
{t('collabs_per_proj', { count: 10 })}
</IconListItem>
<IconListItem icon="history">
{t('unlimited_document_history')}
@@ -145,7 +145,7 @@ export function UpgradePrompt({
{t('basic_compile_time')}
</IconListItem>
<IconListItem icon="person">
{t('collabs_per_proj_single', { collabcount: 1 })}
{t('collabs_per_proj', { count: 1 })}
</IconListItem>
<IconListItem icon="history_off">
{t('limited_document_history')}