BabelizeBabelize
SDK

ICU Message Format

Translate ICU MessageFormat messages — plural, select, and selectordinal — while preserving structure and placeholders.

The SDK supports ICU MessageFormat — the standard for complex pluralization, gender selection, and ordinal numbers. Use babelize.icu() for messages that need more than a simple singular/plural split.

Basic Usage

import { babelize } from "@babelize/sdk";

babelize.icu(
  "{count, plural, one {# item} other {# items}}",
  { count: 3 },
);

How It Works

babelize.icu():

  1. Parses the message into an AST — no fragile string splitting.
  2. Translates the leaf text inside each plural/select/selectordinal option through the normal Babelize translation pipeline (cache → /v1/translate).
  3. Preserves the ICU structure exactly: # (pound), {arg} placeholders, number/date/time formatters, and rich-text tags are never touched.
  4. Formats the translated message with your values via Intl.MessageFormat.

If the string isn't valid ICU (or has no ICU syntax), it falls back to a plain t() translation.

Plural

babelize.icu("{count, plural, one {# item} other {# items}}", { count: 1 }); // "1 item"
babelize.icu("{count, plural, one {# item} other {# items}}", { count: 5 }); // "5 items"

Note the # is ICU's placeholder for the plural value — it's resolved automatically.

Select (gender, etc.)

babelize.icu(
  "{gender, select, male {He} female {She} other {They}}",
  { gender: "male" },
);

SelectOrdinal

babelize.icu("{n, selectordinal, one {#st} two {#nd} few {#rd} other {#th}}", { n: 3 }); // "3rd"

Nested Plural + Select

babelize.icu(
  `{gender, select,
    male   {He has {n, plural, one {# apple} other {# apples}}}
    female {She has {n, plural, one {# apple} other {# apples}}}
    other  {They have {n} apples}}`,
  { gender: "female", n: 2 },
);

Arguments and Formatters Are Preserved

babelize.icu(
  "{count, plural, one {# item} other {# items}} — {total, number} in {folder}",
  { count: 2, total: 1234.5, folder: "inbox" },
);

The {total, number} formatter and {folder} placeholder pass through translation untouched and are formatted per the active locale.

In React

import { useBabelize } from "@babelize/sdk/react";

function CartItemCount({ count }: { count: number }) {
  const babelize = useBabelize();

  return (
    <p>
      {babelize.icu(
        "{count, plural, one {# item} other {# items}}",
        { count },
      )}
    </p>
  );
}

Translation Semantics

ICU structure is preserved exactly; only the human-readable text inside options is translated. This means a message authored once in English can be translated and formatted correctly in any locale — including languages whose plural rules differ from English — because the plural/select options are already expanded and the target translation is applied per option.

Last updated: 2026-08-25

How is this guide?

On this page