LocalePack
ChromeFirefoxEdgeOperaSafariCWS-listaus
Vue.jsReact
Next.jsi18nextReact Native
Oppaat
Home/Guides/i18next JSON format
March 24, 2026

i18next JSON format: namespaces, {{placeholders}}, and _one/_other plurals

i18next is the most popular JavaScript i18n framework. Its JSON locale files support namespaces, double-brace interpolation, CLDR plural suffixes, context variants, and cross-key references. Here is a complete guide to the format — with examples for every feature.

Folder structure

i18next organises locale files by language and namespace. Each namespace is a separate JSON file inside a language folder:

locales/
├── en/
│   ├── common.json        ← default namespace
│   ├── dashboard.json
│   └── validation.json
├── de/
│   ├── common.json
│   ├── dashboard.json
│   └── validation.json
└── ja/
    ├── common.json
    ├── dashboard.json
    └── validation.json

The folder name matches the language code (en, de, ja) and each file name is the namespace (common, dashboard). This path pattern is configured in the i18next backend:

backend: {
  loadPath: '/locales/{{lng}}/{{ns}}.json',
}

Basic JSON format

i18next supports both flat and nested keys. Flat keys use a dot separator by default, while nested keys use standard JSON nesting:

{
  "welcome": "Welcome back!",
  "nav.home": "Home",
  "nav.settings": "Settings"
}

The equivalent nested version:

{
  "welcome": "Welcome back!",
  "nav": {
    "home": "Home",
    "settings": "Settings"
  }
}

Both forms resolve identically with t("nav.home"). The nested version is more common in larger projects because it groups related keys visually.

{{placeholder}} interpolation

Dynamic values are inserted with double curly braces. The variable name inside the braces must match the key you pass to t():

{
  "greeting": "Hello, {{name}}!",
  "itemCount": "You have {{count}} items in your cart."
}

Usage in code:

t('greeting', { name: 'Alice' })
// → "Hello, Alice!"

t('itemCount', { count: 5 })
// → "You have 5 items in your cart."
i18next uses double braces {{}} by default. Single braces {} will be treated as literal text, not interpolation. This is a common mistake when coming from ICU MessageFormat.

Plural keys: _one, _other, _zero, _few, _many

i18next uses CLDR plural categories as key suffixes. When you pass a count option, i18next automatically picks the right suffix for the current language.

English uses two forms — _one and _other:

{
  "message_one": "You have {{count}} message",
  "message_other": "You have {{count}} messages"
}
t('message', { count: 1 })  // → "You have 1 message"
t('message', { count: 5 })  // → "You have 5 messages"
t('message', { count: 0 })  // → "You have 0 messages"

Polish has four forms — _one, _few, _many, and _other:

{
  "message_one": "Masz {{count}} wiadomość",
  "message_few": "Masz {{count}} wiadomości",
  "message_many": "Masz {{count}} wiadomości",
  "message_other": "Masz {{count}} wiadomości"
}
Rule: Every plural key set must include _other. It is the required fallback. Omitting it causes i18next to return the raw key name instead of a translated string.

Namespaces in practice

Namespaces let you split translations into logical groups. You configure them in the i18next init call:

import i18next from 'i18next';

i18next.init({
  lng: 'en',
  ns: ['common', 'dashboard', 'validation'],
  defaultNS: 'common',
  backend: {
    loadPath: '/locales/{{lng}}/{{ns}}.json',
  },
});

To reference a key from a specific namespace, prefix with the namespace name and a colon:

t('dashboard:stats.totalUsers')
t('validation:email.invalid')
t('welcome') // uses defaultNS → common.json

With react-i18next, you can bind a component to a namespace via the useTranslation hook:

import { useTranslation } from 'react-i18next';

function Dashboard() {
  const { t } = useTranslation('dashboard');

  return <h1>{t('stats.totalUsers')}</h1>;
  // reads from locales/en/dashboard.json → stats.totalUsers
}

Context-based keys

Context lets you vary a translation based on a non-numeric dimension — gender, formality, or any custom category. Add a suffix with an underscore:

{
  "friend": "A friend",
  "friend_male": "A boyfriend",
  "friend_female": "A girlfriend"
}
t('friend', { context: 'male' })    // → "A boyfriend"
t('friend', { context: 'female' })  // → "A girlfriend"
t('friend')                         // → "A friend"

You can combine context with plurals. i18next resolves the most specific key first:

{
  "friend_male_one": "{{count}} boyfriend",
  "friend_male_other": "{{count}} boyfriends",
  "friend_female_one": "{{count}} girlfriend",
  "friend_female_other": "{{count}} girlfriends"
}
t('friend', { context: 'female', count: 3 })
// → "3 girlfriends"

Nesting and $t() references

You can reference another translation key inside a value using the $t() syntax. This avoids duplicating shared strings:

{
  "appName": "LocalePack",
  "welcomeBanner": "Welcome to $t(appName)!",
  "footerCopy": "© 2026 $t(appName). All rights reserved."
}
t('welcomeBanner')
// → "Welcome to LocalePack!"

t('footerCopy')
// → "© 2026 LocalePack. All rights reserved."

Nesting works across namespaces too: $t(common:appName) resolves the appName key from the common namespace.

Common mistakes

Missing _other plural key

Defining message_one without message_other. i18next requires _other as the fallback for every plural set. Without it, counts other than 1 return the raw key name.

Single braces instead of double braces

Writing {name} instead of {{name}}. i18next’s default interpolation requires double braces. Single braces are treated as literal text and the variable is never replaced.

Mismatched namespace file names

Naming the file Dashboard.json but configuring the namespace as dashboard. File names are case-sensitive on Linux. The namespace name must exactly match the JSON file name (without extension).

Forgetting to pass count for plurals

Calling t("message") without { count: n }. Without the count option, i18next cannot determine which plural form to use and falls back to the base key — which may not exist in a plural-only set.

Format summary

Featurei18next
File pathlocales/{lng}/{ns}.json
Interpolation{{variable}}
Plurals_one, _other, _zero, _few, _many
Contextkey_{context}
Nesting$t(otherKey)
Namespace separator: (colon)
Key nesting. (dot) or nested JSON objects
Default namespacetranslation (configurable)

Translate your i18next namespace files with LocalePack

Upload your namespace JSON files and LocalePack translates them while preserving every {{placeholder}}, _one/_other plural keys, and $t() nesting references. Download a ready-to-use locales folder in minutes. Pay once, no subscription.

Try LocalePack for i18next →

Related guides

  • Next.js i18n: next-intl vs react-i18next
  • Vue I18n locale files: JSON, YAML, and plurals
← Back to Guides
LocalePack
OppaatTietosuojaKäyttöehdotTuki

© 2025 LocalePack. Kaikki oikeudet pidätetään.

This project was translated with LocalePack logoLocalePack