Why bhasha-js?
i18next and react-intl are excellent, mature, framework-spanning
libraries. If you only swap strings, use them. But the moment your audience is Hindi, Bengali,
Urdu, Tamil, Nepali or any other South Asian language, the defaults are wrong in ways that are
easy to miss and embarrassing to ship. bhasha-js fixes each one by default.
1. Hindi treats 0 as singular. Most tools don't.
CLDR treats both 0 and 1 as the singular ("one") category for Hindi, Bengali, Gujarati, Kannada, Punjabi and Sinhala (and bhasha-js extends the same 0-as-singular rule to Marathi for South-Asian consistency). English treats 0 as plural. A generic setup applies English rules globally:
// generic i18n, default config
t("items", { count: 0 }) // Hindi → "0 आइटमें" ✗ wrong (plural)
// bhasha-js
t("items", { count: 0 }) // Hindi → "0 आइटम" ✓ correct (singular) 2. South Asia groups numbers differently.
The lakh/crore system groups the first three digits, then twos — not threes. bhasha-js does this for every supported currency, including the ones Intl gets wrong (PKR, LKR):
// generic // bhasha-js
1,234,567 formatNumber(1234567) // → 12,34,567
$1,234,567.00 formatCurrency(1234567) // → ₹12,34,567.00
// Urdu/PKR → Rs 12,34,567.00 (lakh-grouped) 3. Code-mixed locales are first-class, not "broken" Hindi.
Over half of young South Asians type in the Latin script — Hinglish, Banglish, Roman Urdu, Roman
Nepali. Generic tools have no concept of these as locales; you'd have to fake them. bhasha-js
ships hi-Latn, bn-Latn, ur-Latn, ne-Latn,
pa-Latn as real locales — with their own translation memory, plural rules, fonts,
and fallback chains. A Roman-Nepali reader falls back to Hinglish before English, because the
script bridges harder than the language family does.
4. One key, multiple registers — chosen at render time.
South Asian languages encode formality grammatically (आप / तुम / तू). The same key can serve a formal banking tone or a Gen-Z casual tone, switched with a prop — no ICU gymnastics, no duplicate key trees:
<I18nProvider register="formal"> // honorific, native-vocabulary
<I18nProvider register="casual"> // "Order करें", "Cart में add करो" 5. RTL, fonts, and fallbacks — handled.
- RTL: switch to Urdu and the layout flips automatically (
dir="rtl"), in the Nastaliq font. - Fonts: the correct Google Font for each script is loaded only when needed — no broken conjuncts.
- Fallbacks: Bengali falls back to Hindi before English; Tamil and the other Dravidian languages skip Hindi entirely (a Tamil speaker isn't more likely to read Hindi than English).
Familiar surface, type-safe keys
The API mirrors react-i18next on purpose — useTranslation(), t(),
<Trans />, <LanguageSwitcher /> — so migration is muscle
memory. Run npx bhasha pull and t() becomes type-safe: autocomplete on
your keys and a compile error on a typo.
When to use something else
bhasha-js is React-first and South-Asia-first. The components are React, but the engine isn't —
Vue, Svelte, vanilla, and React Native can drive the same BhashaStore from
bhasha-js/vanilla. If you need a 600-integration
translation-management platform, or your primary market is outside South Asia, a generic tool may
fit better. We'd rather tell you that than oversell.