# General Translation Knowledge Base: 如何在 React 中处理复数形式？
URL: https://generaltranslation.com/zh/kb/how-to-handle-plurals-in-react.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: 在 React 中处理复数形式时，应为每种语言的每个复数形式各准备一个句子，并按该语言的复数规则选出对应句子——英语有 2 种形式，俄语有 4 种，阿拉伯语有 6 种。gt-react 和 gt-next 提供的 General Translation `<Plural>` 组件只需接收你的源语言形式，General Translation 便会生成每种目标语言所需的形式。
Category: 按区域设置格式化
Last updated: 2026-10-21
Authors: Archie McKenzie
Published: 2025-02-17

要在 React 中处理复数形式，需要为每种语言的每个复数形式各准备一个句子，再根据该语言的复数规则，为每个数量选出对应的句子。这一选择可交由 JavaScript 内置的 [`Intl.PluralRules`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/PluralRules) 完成：它会将数字映射到 Unicode CLDR (Common Locale Data Repository) 中定义的复数类别。英语有 2 个类别，俄语和波兰语有 4 个，阿拉伯语有 6 个，日语则只有 1 个。

`count === 1` 这种判断只适用于英语。俄语的整数有三种形式：“1 файл”、“2 файла”和“5 файлов” (1 个文件、2 个文件、5 个文件) ，而且 21 与 1 使用相同的形式。如果判断逻辑在数量为 1 时显示“файл”，其余数量一律显示“файлов”，就会渲染出“2 файлов”和“21 файлов”，两者都是错的。

## Video

The video is narrated in English, with English captions.

[How do I handle plurals in React?](https://caxecubb9c64cezv.public.blob.vercel-storage.com/films/kb-how-to-handle-plurals-in-react.mp4) (48秒)

General Translation handles plurals in React with the `Plural` component. Run `npx gt init` and sign in, give `Plural` the count and an English sentence for each form, wrap it in a `T` component with the count in `Num`, then run `npx gt translate` to write the forms each language needs.

## 各语言有哪些复数类别？

CLDR 定义了六种复数类别：`zero`、`one`、`two`、`few`、`many` 和 `other`。每种语言只使用其中的一个子集，并按照各自的规则将每个数字归入该子集中的某一类别。

| 语言    | 类别                                      | 各类别对应的数量                                                                                 |
| ----- | --------------------------------------- | ---------------------------------------------------------------------------------------- |
| 英语    | `one`、`other`                           | 1 属于 `one`；0、2、5 和 1.5 属于 `other`                                                        |
| 日语、中文 | `other`                                 | 所有数量均属于 `other`                                                                          |
| 俄语    | `one`、`few`、`many`、`other`              | 1、21 和 101 属于 `one`；2 至 4 及 22 属于 `few`；0、5 至 20 及 100 属于 `many`；1.5 属于 `other`          |
| 波兰语   | `one`、`few`、`many`、`other`              | 1 属于 `one`；2 至 4 及 22 属于 `few`；0、5 至 21 及 100 属于 `many`；1.5 属于 `other`                   |
| 阿拉伯语  | `zero`、`one`、`two`、`few`、`many`、`other` | 0 属于 `zero`；1 属于 `one`；2 属于 `two`；3 至 10 属于 `few`；11 至 99 属于 `many`；100 至 102 属于 `other` |

如需查看某种语言的复数类别，可在浏览器控制台中运行 `new Intl.PluralRules('ru').resolvedOptions().pluralCategories`。以俄语为例，返回结果为 `one`、`few`、`many` 和 `other`。

## 如何在多语言 React 应用中处理复数形式？

在 React 中，General Translation 通过 `gt-react` (Next.js 中为 `gt-next`) 提供的 [`<Plural>`](/docs/react/reference/components/plural) 组件处理复数形式。你只需编写源语言用到的形式，General Translation 会为每种目标语言生成所需的形式。

1. 将数量通过 `n` 传给 [`<Plural>`](/docs/react/reference/components/plural)，并为每种源语言形式分别传入一个属性，例如英语的 `one` 和 `other`。
2. 用 [`<Num>`](/docs/react/reference/components/num) 包裹数量，再用 [`<T>`](/docs/react/reference/components/t) 包裹整个 [`<Plural>`](/docs/react/reference/components/plural)。这样，每种形式都会作为完整的句子翻译，数字则作为变量处理。
3. 在执行生产环境构建之前运行 [`npx gt translate`](/docs/cli/reference/commands/translate)。General Translation 会翻译每种形式，并补全每种目标语言所需的复数类别，例如阿拉伯语会有六种形式，俄语会有四种。

```tsx
import { T, Plural, Num } from 'gt-react';

export function InboxCount({ count }: { count: number }) {
  return (
    <T>
      <Plural
        n={count}
        one={<>You have <Num>{count}</Num> message.</>}
        other={<>You have <Num>{count}</Num> messages.</>}
      />
    </T>
  );
}
```

渲染时，General Translation 的 [`<Plural>`](/docs/react/reference/components/plural) 会根据当前区域设置的 [CLDR 复数规则](https://cldr.unicode.org/index/cldr-spec/plural-rules)，为 `count` 选择对应的形式。如果缺少该类别，则依次回退到 `plural`、`other`，最后使用其子元素。[`<Num>`](/docs/react/reference/components/num) 通过 `Intl.NumberFormat` 在本地格式化数值，因此 1000000 在英语中渲染为 1,000,000，在德语中为 1.000.000，在印地语中为 10,00,000，并且该值不会发送到 General Translation API。

为了让复数消息的译文随文案变更保持同步，可以在 CI 中运行 [`npx gt translate`](/docs/cli/reference/commands/translate)，或[配置 Locadex](/docs/platform/locadex/guides/configuring-automations) (General Translation 的 AI 智能体) ，使其在拉取请求发生变更或有新提交推送时翻译新的源内容。审阅者可以在 General Translation 仪表板的[翻译编辑器](/docs/platform/dashboard/guides/reviewing-translations)中修正任何生成的形式。[处理复数形式和分支](/docs/react/guides/handling-plurals-and-branches)介绍了 React、Next.js 以及实验性的 `gt-tanstack-start` 和 `gt-react-native` 的具体操作步骤。

## 如何在仅支持英语的 React 应用中实现字符串复数化？

仅支持英语的应用只需要 `one` 和 `other` 两种形式，因此一个简单的辅助函数就够用了。请传入完整的短语，这样不规则名词 (&quot;person&quot; 和 &quot;people&quot;) 和动词 (&quot;is&quot; 和 &quot;are&quot;) 都会随数量正确变化。

```ts title="pluralize.ts"
const englishPlurals = new Intl.PluralRules('en-US');

export function pluralize(count: number, one: string, other: string): string {
  return englishPlurals.select(count) === 'one' ? one : other;
}
```

```tsx
import { pluralize } from './pluralize';

export function CartSummary({ items, viewers }: { items: number; viewers: number }) {
  return (
    <>
      {/* 1 件商品、5 件商品 */}
      <p>{pluralize(items, `${items} item`, `${items} items`)}</p>
      {/* 1 人正在查看、3 人正在查看 */}
      <p>{pluralize(viewers, '1 person is watching', `${viewers} people are watching`)}</p>
    </>
  );
}
```

英语的复数规则将 0 归入 `other`，因此该辅助函数会渲染出 &quot;0 items&quot;。该辅助函数硬编码了英语规则，且只接受两种短语形式，而俄语需要三种。因此，当应用需要支持第二种语言时，请改用 [`<Plural>`](/docs/react/reference/components/plural) 或其他国际化 (i18n) 库。

## 如何在 JSX 之外实现字符串的复数形式？

对于只能使用普通字符串的文本 (例如 `placeholder` 或 `aria-label`) ，可以使用 General Translation 的 [`useGT`](/docs/react/reference/hooks/use-gt) 钩子。它会返回一个函数，该函数接受 ICU (International Components for Unicode) 复数消息。在消息中，`#` 会输出计数值。

```tsx
import { useGT } from 'gt-react';

export function ProductSearch({ count }: { count: number }) {
  const gt = useGT();
  return (
    <input
      type="search"
      placeholder={gt(
        'Search {count, plural, one {# product} other {# products}}',
        { count }
      )}
    />
  );
}
```

在异步 App Router 组件中，请改用 `gt-next/server` 提供的 [`getGT`](/docs/react/nextjs/reference/functions/get-gt)。字符串 API 的其他用法请参阅[翻译字符串](/docs/react/guides/translating-strings)。

## react-i18next 和 react-intl 如何处理复数形式？

这两个库都根据 CLDR 复数规则选择类别，并从目录文件中读取各语言的句子，因此每条消息在每种语言中的每种形式，都需要由你的团队或译者亲自编写。两个库都不会自动生成译文。

[react-i18next](https://react.i18next.com/) 为每个类别存储一个键，以类别作为键的后缀，并根据 `count` 选项选取对应的键。

```json title="locales/en/translation.json"
{
  "messages_one": "You have {{count}} message.",
  "messages_other": "You have {{count}} messages."
}
```

```tsx
import { useTranslation } from 'react-i18next';

export function InboxCount({ count }: { count: number }) {
  const { t } = useTranslation();
  return <p>{t('messages', { count })}</p>;
}
```

阿拉伯语文件需要六个键，从 `messages_zero` 到 `messages_other`。[i18next 复数形式文档](https://www.i18next.com/translation-function/plurals)列出了全部后缀。

[react-intl](https://formatjs.github.io/docs/react-intl/) 是 FormatJS 的 React 库，它会把所有类别写进同一个 ICU MessageFormat 字符串，其中 `#` 代表按区域设置格式化后的数量。

```tsx
import { FormattedMessage } from 'react-intl';

export function InboxCount({ count }: { count: number }) {
  return (
    <FormattedMessage
      id="inbox.count"
      defaultMessage="{count, plural, one {You have # message.} other {You have # messages.}}"
      values={{ count }}
    />
  );
}
```

阿拉伯语目录中，同一条消息需要分别以 `zero`、`one`、`two`、`few`、`many` 和 `other` 分支重复编写。[FormatJS 的 ICU 语法指南](https://formatjs.github.io/docs/core-concepts/icu-syntax/)介绍了复数分支以及 `=0` 等精确匹配。

## 在 React 中处理复数形式应采用哪种方式？

| 方式                                                                          | 各形式存放位置                | 由谁编写每种目标语言的形式                                                                             |
| --------------------------------------------------------------------------- | ---------------------- | ----------------------------------------------------------------------------------------- |
| `Intl.PluralRules` 辅助函数                                                     | 你的代码中，仅限英语             | 无需编写，因为应用只以一种语言发布                                                                         |
| react-i18next                                                               | 每种语言一个 JSON 文件，使用带后缀的键 | 你的团队或译者                                                                                   |
| react-intl                                                                  | 每种语言一个目录，使用 ICU 消息     | 你的团队或译者                                                                                   |
| General Translation 的 [`<Plural>`](/docs/react/reference/components/plural) | 你在 JSX 中编写的源语言形式       | 运行 [`npx gt translate`](/docs/cli/reference/commands/translate) 时由 General Translation 生成 |

如果应用只以英语发布，请使用辅助函数。如果你的团队已经在维护目录文件，且由译者手动编写每种形式，只用 react-i18next 或 react-intl 即可。如果应用以多种语言发布，且文案每次发布都会变动，请使用 General Translation 的 [`<Plural>`](/docs/react/reference/components/plural)，因为 General Translation 会为每条新增的复数消息生成所有目标语言的形式。

## 常见问题

### 当数量为 0 时，如何显示 &quot;No items&quot;？

英语的复数规则将 0 归入 `other` 类别，因此只包含 `one` 和 `other` 的消息会显示为 &quot;0 items&quot;。如果是字符串，请在传给 [`useGT`](/docs/react/reference/hooks/use-gt) 的 ICU 消息中添加一个针对 0 的精确匹配：

```tsx
gt('{count, plural, =0 {No items} one {# item} other {# items}}', { count });
```

在 JSX 中判断 `count === 0`，并将空状态单独放在一个 [`<T>`](/docs/react/reference/components/t) 块中渲染。

### Plural 组件能在 Next.js 中使用吗？

可以。从 `gt-next` 导入 [`<Plural>`](/docs/react/reference/components/plural)、[`<T>`](/docs/react/reference/components/t) 和 [`<Num>`](/docs/react/reference/components/num) 即可，属性与 `gt-react` 中的完全相同。此外，General Translation 在实验性的 `gt-tanstack-start` 和 `gt-react-native` 中也提供了这些组件。

### 应该用哪些数量来测试复数形式？

在每个目标区域设置中，分别用 0、1、2、5、11、21 和 100 渲染每条复数消息。这些数量可以覆盖英语、俄语、波兰语和阿拉伯语中的所有整数类别。再加上 1.5，即可覆盖俄语和波兰语中的 `other` 类别。

## Related questions

- [如何翻译 JSX 中的条件文本？](https://generaltranslation.com/zh/kb/translate-conditional-jsx.mdx): 保持句子完整，并翻译它的每个版本。三元表达式会把句子拆成碎片，使其失去含义，也无法适应各语言的语序。General Translation 通过在 `<T>` 中使用 `<Branch>` 解决这一问题，将整个句子作为一个整体进行翻译。
- [不使用翻译文件能实现 i18n 吗？](https://generaltranslation.com/zh/kb/i18n-without-translation-files.mdx): 可以。借助 General Translation 的 gt-react 和 gt-next 库，你可以为 React 和 Next.js 实现 i18n，既无需翻译键，也不用为每种语言维护 JSON 文件。文案以内联方式写在 JSX 的 `<T>` 组件中，gt translate 命令会在构建时结合代码中的上下文，为每种语言生成译文。Locadex 还能通过拉取请求让译文保持最新。
- [React 应用最适合使用哪个国际化库？](https://generaltranslation.com/zh/kb/best-react-i18n-library.mdx): 主流的 React 国际化库有四个：General Translation 的 gt-react、react-i18next、Lingui 和 React Intl。四者都能渲染和格式化译文，但只有 gt-react 还能根据你在 JSX 中内联编写的文案直接生成译文。如果想继续沿用 i18next 的消息目录和插件，请选择 react-i18next；如果需要将文案提取为编译后的消息目录，请选择 Lingui；如果需要 FormatJS 和 ICU MessageFormat，请选择 React Intl。

## Previous and next questions

- Next question: [如何翻译 JSX 中的条件文本？](https://generaltranslation.com/zh/kb/translate-conditional-jsx.mdx)

## Sitemap

See the [Knowledge Base sitemap](https://generaltranslation.com/zh/kb/sitemap.md) for every article.
