Vize

use-plural-rules

Choose and render a message by CLDR plural category (Intl.PluralRules).

Package @vizejs/composable/use-plural-rules
Own the source vize lib pull composable:use-plural-rules
Runtime exports usePluralRules
Gzip budget 2560 B

Minimal setup

Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).

vp install @vizejs/composable

Import the entry directly. Call lifecycle-bound utilities inside <script setup> so cleanup follows the component scope; consult the runtime contract for this entry's SSR and hydration behavior.

import { usePluralRules } from "@vizejs/composable/use-plural-rules";

Try it

Word an unread-message count

Choose the right message for zero, one, and many items, using the locale's plural rules rather than count === 1.

Open the interactive example

What to observe: Zero shows No unread messages from the exact =0 message. Enter 1 for 1 unread message and 2 for 2 unread messages. The plural category below the message shows which rule matched.

Messages are keyed by CLDR category, with optional exact =N overrides; other is required. A function message receives the count and its locale-formatted text. Languages with more categories, such as few or many, need those keys.

Compare the initial and interacted states
Word an unread-message count: initial state
Initial state
Word an unread-message count: state after the verified interactions
After the verified interactions

Copy the example

Save this complete SFC in your Vue project. Its public imports and source are the same ones executed in the preview.

<script setup lang="ts">
import { ref } from "vue";
import { usePluralRules } from "@vizejs/composable/use-plural-rules";

const count = ref(0);
const { message, category } = usePluralRules(
  count,
  {
    "=0": "No unread messages",
    one: (_count, formatted) => `${formatted} unread message`,
    other: (_count, formatted) => `${formatted} unread messages`,
  },
  { locale: "en-US" },
);
</script>

<template>
  <div class="composable-example">
    <p>Pick the right wording for an unread-message count.</p>
    <label>
      Unread messages
      <input v-model.number="count" type="number" min="0" step="1" />
    </label>
    <output aria-live="polite">{{ message }}</output>
    <p>
      Plural category: <code>{{ category }}</code>
    </p>
  </div>
</template>

Runtime contract

Utility Category Stability SSR Hydration Cleanup Targets Host globals Uses
usePluralRules i18n experimental deterministic-fallback caller-managed none web, server, worker, native, desktop, terminal Intl, window useLocale

API

usePluralRules

Choose and render a message by CLDR plural category (Intl.PluralRules). Messages are typed per category with a mandatory other, plus optional exact overrides ("=0": "No items"). Cardinal (1 item) and ordinal (1st, 2nd) rules are supported via type. The count is formatted with the same locale for interpolation. Everything is derived state: no listeners or timers, deterministic during server rendering when the locale is explicit. Invalid options surface as the platform RangeError.

function usePluralRules( count: MaybeRefOrGetter<number>, messages: MaybeRefOrGetter<PluralMessages>, options: MaybeRefOrGetter<UsePluralRulesOptions> = {}, ): PluralRulesControls
const { message } = usePluralRules(count, { "=0": "No files", one: "# file", other: "# files" }, { locale: "en" });

Types

UsePluralRulesOptions

Options for usePluralRules.

Member Type Description
locale? string | Intl.Locale Locale used for plural selection and count formatting. Pass it explicitly for hydration-stable server rendering.

PluralRulesControls

Reactive plural selection returned by usePluralRules.

Member Type Description
locale ComputedRef<string> Canonical locale in use.
rules ComputedRef<Intl.PluralRules> Plural rules for the current locale and options.
category ComputedRef<PluralCategory> Category of the current count.
message ComputedRef<string> Message for the current count with {count} / # interpolated.
select (count: number) => PluralCategory Plural category of any count.
format (count: number) => string Message for any count.