Skip to content
Twilight React Playground
ثيم رائدaren

formatSallaPlural

functionBeginnerserverbrowserlive demo

Picks the right plural form out of a Salla translation such as '{1} one item|[2,*] :count items' and fills in the number.

import { formatSallaPlural } from '@salla.sa/twilight-theme-engine/utils';

In plain words

Some texts change with a number: "1 time", "2 times", "11 times", and Arabic has more forms than English. Salla keeps every form in one translation string, in the Laravel format: {1} One time|{2} Two times|[3,10] :count times|[11,*] :count Time. The translate function t does not understand that format and returns the whole string.

formatSallaPlural(t('pages.products.sold_times'), 5) picks the part that matches 5, puts 5 where :count is, and returns plain text: "5 times".

Signature

function formatSallaPlural(template: unknown, count: number): string

Try it live

Some Salla translations hold every plural form in one string. formatSallaPlural() picks the form for a count.Try this: set the count to 0 on sold_times: no segment covers 0, so the whole template comes back. Switch the language pill to en too.
Storefront canvas · ar · RTL
What i18next returns
{1} <span>مرة واحدة</span>|{2} <span>مرتان</span>|[3,10] <span>:count</span> مرات|[11,*] <span>:count</span> مرة
formatSallaPlural(…, 3)
3 مرات
Controls
Used when "your own template" is picked.
What a theme writes
import { useTranslation } from '@salla.sa/twilight-theme-engine/i18n';
import { formatSallaPlural } from '@salla.sa/twilight-theme-engine/utils';

export function Count() {
  const { t } = useTranslation();
  return <span>{formatSallaPlural(t('pages.products.sold_times'), 3)}</span>;
}

Example

app/components/product/ReviewCount.tsx
import { useTranslation } from '@salla.sa/twilight-theme-engine/i18n';
import { formatSallaPlural } from '@salla.sa/twilight-theme-engine/utils';

export function ReviewCount({ count }: { count: number }) {
  const { t } = useTranslation();
  return <span className="review-count">{formatSallaPlural(t('pages.rating.reviews'), count)}</span>;
}

How it behaves

  • The template is split on | and the parts are tried in order. {n} matches exactly n; [a,b] matches a ≤ count ≤ b; * leaves that end open. The first match wins.

  • Parts without a {…} or […] prefix are the Laravel singular|plural fallback, used only when no prefixed part matched: the first when count === 1, the second otherwise.

  • In the chosen text, :count and {{count}} become the number, every HTML tag is removed, and runs of whitespace become one space.

  • A template without | gets the same substitutions and nothing else, so calling it on an ordinary translation is harmless.

  • ProductDetails uses it for pages.products.sold_times. Salla's translations use this format for blocks.header.products_count, blocks.comments.comment and pages.rating.reviews too.

  • A plain function, not a hook: call it anywhere.

Gotchas

  • When no part matches the count, the whole template comes back with only its tags removed. sold_times has no {0}, so formatSallaPlural(t('pages.products.sold_times'), 0) returns {1} One time|{2} Two times|[3,10] 0 times|[11,*] 0 Time; negative and fractional counts do the same. Check the count first, as ProductDetails does with sold_quantity > 0.

  • The result is plain text. Markup in the translation (the <span> around the number) is removed, so it cannot be styled; build that markup yourself.

  • A template that is not a string returns String(template ?? ''): undefined gives an empty string.

Related

Source and docs