Skip to content
better-i18n.com
Bu sayfada

useTranslations Hook #

Access namespaced translations in any component:

TSX
import { useTranslations } from '@better-i18n/use-intl'

function HomePage() {
  const t = useTranslations('home')

  return (
    <div>
      <h1>{t('title')}</h1>
      <p>{t('description')}</p>
    </div>
  )
}

API Reference #

ParameterTypeRequiredDescription
namespacestringThe namespace to scope translations to

Return Methods #

MethodDescription
t(key, values?)Get translated string with optional interpolation
t.rich(key, values)Get translated string with React components
t.raw(key)Get raw translation string
t.has(key)Check if translation exists

Namespaces #

Namespaces help organize translations into logical groups, making large translation files manageable.

What Are Namespaces? #

A namespace is a top-level key in your translation file:

en.json
{
  "home": {
    "title": "Welcome",
    "description": "The best app ever"
  },
  "about": {
    "title": "About Us",
    "mission": "Our mission is..."
  },
  "common": {
    "save": "Save",
    "cancel": "Cancel",
    "loading": "Loading..."
  }
}

Namespace Patterns #

By Page:

TSX
// app/routes/about.tsx
const t = useTranslations('about')

By Feature:

TSX
// components/LoginForm.tsx
const t = useTranslations('auth')
t('login.title')

Shared Namespace:

TSX
const t = useTranslations('common')
<button>{t('actions.save')}</button>

Nested Keys #

Access nested keys with dot notation:

JSON
{
  "settings": {
    "profile": {
      "title": "Profile Settings",
      "fields": {
        "name": "Full Name",
        "email": "Email Address"
      }
    }
  }
}
TSX
const t = useTranslations('settings')

t('profile.title')           // "Profile Settings"
t('profile.fields.name')     // "Full Name"

Multiple Namespaces #

Use multiple namespaces in one component:

TSX
function CheckoutPage() {
  const tCheckout = useTranslations('checkout')
  const tCommon = useTranslations('common')

  return (
    <div>
      <h1>{tCheckout('title')}</h1>
      <button>{tCommon('actions.save')}</button>
      <button>{tCommon('actions.cancel')}</button>
    </div>
  )
}

Interpolation #

Interpolation lets you insert dynamic values into translations using ICU Message Format.

Basic Interpolation #

Insert variables with curly braces:

en.json
{
  "greeting": {
    "hello": "Hello, {name}!",
    "welcome": "Welcome back, {firstName} {lastName}"
  }
}
TSX
const t = useTranslations('greeting')

t('hello', { name: 'John' })
// "Hello, John!"

t('welcome', { firstName: 'John', lastName: 'Doe' })
// "Welcome back, John Doe"

Pluralization #

Handle plural forms with plural:

JSON
{
  "cart": {
    "items": "{count, plural, =0 {No items} one {# item} other {# items}}"
  }
}
TSX
t('items', { count: 0 })   // "No items"
t('items', { count: 1 })   // "1 item"
t('items', { count: 5 })   // "5 items"

Plural Categories

CategoryDescriptionExample
=0, =1, =NExact match=0 {Empty}
zeroZero form (some languages)zero {No items}
oneSingularone {# item}
twoDual (some languages)two {# items}
fewFew (some languages)few {# items}
manyMany (some languages)many {# items}
otherDefault/pluralother {# items}

Select (Gender/Variants) #

Choose based on a string value:

JSON
{
  "notifications": {
    "liked": "{gender, select, male {He} female {She} other {They}} liked your post"
  }
}
TSX
t('liked', { gender: 'male' })    // "He liked your post"
t('liked', { gender: 'female' })  // "She liked your post"
t('liked', { gender: 'other' })   // "They liked your post"

SelectOrdinal #

Handle ordinal numbers (1st, 2nd, 3rd):

JSON
{
  "ranking": {
    "place": "You finished in {position, selectordinal, one {#st} two {#nd} few {#rd} other {#th}} place"
  }
}
TSX
t('place', { position: 1 })   // "You finished in 1st place"
t('place', { position: 2 })   // "You finished in 2nd place"
t('place', { position: 3 })   // "You finished in 3rd place"

Rich Text #

Insert React components with .rich():

JSON
{
  "legal": {
    "terms": "By signing up, you agree to our <link>Terms of Service</link> and <bold>Privacy Policy</bold>."
  }
}
TSX
const t = useTranslations('legal')

t.rich('terms', {
  link: (chunks) => <a href="/terms">{chunks}</a>,
  bold: (chunks) => <strong>{chunks}</strong>,
})

Self-Closing Tags

For elements without children:

JSON
{
  "message": "Loading<spinner/> Please wait..."
}
TSX
t.rich('message', {
  spinner: () => <Spinner />,
})

Number & Date Formatting #

Format numbers and dates inline:

JSON
{
  "stats": {
    "users": "{count, number} active users",
    "created": "Created on {date, date, medium}"
  }
}
TSX
t('users', { count: 1234567 })
// "1,234,567 active users"

t('created', { date: new Date() })
// "Created on Jan 18, 2026"

Escaping #

Use single quotes to escape:

JSON
{
  "code": "Use '{name}' to insert the user''s name"
}
TSX
t('code')
// "Use {name} to insert the user's name"

TypeScript Support #

Enable type-safe translation keys:

src/types/i18n.d.ts
import en from '../locales/en.json'

type Messages = typeof en

declare global {
  interface IntlMessages extends Messages {}
}

Now you get autocomplete for translation keys:

TSX
const t = useTranslations('home')
t('title')       // ✅ Valid
t('typoTitle')   // ❌ TypeScript error

Best Practices #

Keep Namespaces Focused #

JSON
// ✅ Good - focused namespaces (~20-30 keys each)
{
  "home": { ... },
  "dashboard": { ... },
  "settings": { ... }
}

// ❌ Bad - giant namespace
{
  "app": { /* 500+ nested keys */ }
}

Use Consistent Naming #

JSON
// ✅ Good - consistent camelCase
{
  "home": {
    "meta": { "title": "..." },
    "hero": { "title": "...", "cta": "..." }
  }
}

// ❌ Bad - inconsistent
{
  "home": {
    "pageTitle": "...",
    "HeroTitle": "...",
    "button_text": "..."
  }
}

Avoid Deep Nesting #

JSON
// ✅ Good - reasonable depth (2-3 levels)
{
  "settings": {
    "profile": {
      "name": "Name",
      "email": "Email"
    }
  }
}

// ❌ Bad - too deep
{
  "settings": {
    "user": {
      "profile": {
        "personal": {
          "details": {
            "name": "Name"
          }
        }
      }
    }
  }
}