Skip to content

Internationalization (i18n)

Setup

  • Library: i18next + react-i18next + i18next-http-backend
  • Languages: id (Indonesian, default) + en (English)
  • Namespace: common
  • Translation files: public/locales/{lang}/common.json

Using Translations

tsx
import { useI18n } from '@/hooks';

const { t, lang, setLang } = useI18n();

t('nav.dashboard')             // → 'Dasbor' (id) | 'Dashboard' (en)
t('auth.login.title')          // → 'Masuk ke Hermina 360' (id)
t('validation.required', { field: 'Email' })  // → 'Email wajib diisi'

Translation File Structure

public/locales/id/common.json:

json
{
  "app": { "name": "Hermina 360" },
  "nav": { "dashboard": "Dasbor", "logout": "Keluar" },
  "auth": {
    "login": {
      "title": "Masuk ke Hermina 360",
      "email": "Email"
    }
  },
  "validation": { "required": "{{field}} wajib diisi" },
  "dashboard": {
    "executive": { "title": "Ringkasan Eksekutif" }
  }
}

Adding a New Key

  1. Add to public/locales/id/common.json
  2. Add to public/locales/en/common.json
  3. Use in component: t('your.new.key')

Switching Language

tsx
const { setLang } = useI18n();
setLang('en');  // persists to localStorage, syncs i18next

Ant Design Locale

The Ant Design locale is synced to the active language in src/main.tsx:

ts
const antdLocaleMap = { id: idID, en: enUS };
<ConfigProvider locale={antdLocaleMap[lang]}>

Language Store

Language is persisted in useLanguageStore (key: hermina360-lang). On hydration, it automatically syncs with i18next.