Introduction#

Building a React app for global users? This guide walks you through internationalization (i18n) from setup to deployment. We'll use react-i18next, the most popular i18n library for React.

Prerequisites#

  • React 18+ application
  • npm or yarn
  • Basic React knowledge

Step 1: Install Dependencies#

bash
npm install i18next react-i18next i18next-http-backend i18next-browser-languagedetector
PackagePurpose
i18nextCore i18n framework
react-i18nextReact bindings
i18next-http-backendLoad translations from files
i18next-browser-languagedetectorAuto-detect user language

Step 2: Create Translation Files#

Create a folder structure for translations:

text
public/
  locales/
    en/
      translation.json
    de/
      translation.json
    es/
      translation.json

public/locales/en/translation.json:

json
{
  "welcome": "Welcome to our app",
  "nav": {
    "home": "Home",
    "about": "About",
    "contact": "Contact"
  },
  "buttons": {
    "submit": "Submit",
    "cancel": "Cancel",
    "save": "Save Changes"
  }
}

public/locales/de/translation.json:

json
{
  "welcome": "Willkommen in unserer App",
  "nav": {
    "home": "Startseite",
    "about": "Über uns",
    "contact": "Kontakt"
  },
  "buttons": {
    "submit": "Absenden",
    "cancel": "Abbrechen",
    "save": "Änderungen speichern"
  }
}

Step 3: Configure i18next#

Create src/i18n.js:

javascript
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import Backend from 'i18next-http-backend';
import LanguageDetector from 'i18next-browser-languagedetector';

i18n
  .use(Backend)
  .use(LanguageDetector)
  .use(initReactI18next)
  .init({
    fallbackLng: 'en',
    debug: process.env.NODE_ENV === 'development',

    interpolation: {
      escapeValue: false, // React already escapes
    },

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

export default i18n;

Step 4: Initialize in Your App#

src/index.js:

javascript
import React, { Suspense } from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './i18n'; // Import i18n configuration

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Suspense fallback={<div>Loading...</div>}>
      <App />
    </Suspense>
  </React.StrictMode>
);

Step 5: Use Translations in Components#

Using the useTranslation Hook#

jsx
import { useTranslation } from 'react-i18next';

function HomePage() {
  const { t } = useTranslation();

  return (
    <div>
      <h1>{t('welcome')}</h1>
      <nav>
        <a href="/">{t('nav.home')}</a>
        <a href="/about">{t('nav.about')}</a>
        <a href="/contact">{t('nav.contact')}</a>
      </nav>
      <button>{t('buttons.submit')}</button>
    </div>
  );
}

Using the Trans Component#

For complex translations with JSX:

jsx
import { Trans } from 'react-i18next';

function WelcomeMessage({ name }) {
  return (
    <Trans i18nKey="greeting" values={{ name }}>
      Hello <strong>{{ name }}</strong>, welcome back!
    </Trans>
  );
}

Translation file:

json
{
  "greeting": "Hello <1>{{name}}</1>, welcome back!"
}

Step 6: Add Language Switcher#

jsx
import { useTranslation } from 'react-i18next';

function LanguageSwitcher() {
  const { i18n } = useTranslation();

  const languages = [
    { code: 'en', name: 'English' },
    { code: 'de', name: 'Deutsch' },
    { code: 'es', name: 'Español' },
  ];

  return (
    <select
      value={i18n.language}
      onChange={(e) => i18n.changeLanguage(e.target.value)}
    >
      {languages.map((lang) => (
        <option key={lang.code} value={lang.code}>
          {lang.name}
        </option>
      ))}
    </select>
  );
}

Step 7: Handle Pluralization#

Translation file:

json
{
  "items_count": "{{count}} item",
  "items_count_plural": "{{count}} items"
}

Component:

jsx
function CartCount({ count }) {
  const { t } = useTranslation();
  return <span>{t('items_count', { count })}</span>;
}

i18next automatically selects the plural form based on count.

Step 8: Interpolation with Variables#

Translation file:

json
{
  "greeting": "Hello, {{name}}!",
  "order_status": "Your order #{{orderId}} is {{status}}"
}

Component:

jsx
function Greeting({ user, order }) {
  const { t } = useTranslation();

  return (
    <div>
      <h1>{t('greeting', { name: user.name })}</h1>
      <p>{t('order_status', {
        orderId: order.id,
        status: order.status
      })}</p>
    </div>
  );
}

Best Practices#

1. Organize Translation Keys#

Use nested objects for organization:

json
{
  "pages": {
    "home": {
      "title": "Welcome",
      "description": "..."
    },
    "checkout": {
      "title": "Checkout",
      "steps": {
        "shipping": "Shipping",
        "payment": "Payment"
      }
    }
  }
}

2. Extract Strings Early#

Don't hardcode strings. Use translations from the start:

jsx
// Bad
<button>Submit</button>

// Good
<button>{t('buttons.submit')}</button>

3. Use Namespaces for Large Apps#

Split translations into multiple files:

javascript
// i18n.js
i18n.init({
  ns: ['common', 'home', 'checkout'],
  defaultNS: 'common',
});
jsx
// In components
const { t } = useTranslation('checkout');

4. Handle Loading States#

jsx
function App() {
  const { t, ready } = useTranslation();

  if (!ready) return <LoadingSpinner />;

  return <div>{t('welcome')}</div>;
}

Translating Your React App#

Once your app is set up for i18n, you need translations. Here's the workflow:

  1. Export your en/translation.json
  2. Upload to shipglobal.dev
  3. Select target languages (German, Spanish, etc.)
  4. Download translated JSON files
  5. Place in public/locales/{lang}/
  6. Deploy

Your React app now speaks multiple languages!

Conclusion#

Internationalizing a React app with react-i18next is straightforward:

  1. Install dependencies
  2. Create translation files
  3. Configure i18next
  4. Use useTranslation hook
  5. Add language switcher

Start with your primary languages and expand based on user demand. With proper setup, adding new languages takes minutes, not days.