Back to Blog
Tutorial

How to Localize a React App: Step-by-Step Guide

Learn how to add localization to your React application with react-i18next. Complete step-by-step tutorial with code examples.

IntlPull Team
IntlPull Team
Engineering
December 3, 202410 min read

Quick Answer

To localize a React app:

  • Install react-i18next: npm install react-i18next i18next
  • Create translation JSON files for each language
  • Configure i18next with your translations
  • Use the useTranslation hook in components
  • Add a language switcher
  • Prerequisites

  • React 16.8+ (for hooks)
  • Node.js 14+
  • Basic React knowledge
  • Step 1: Install Dependencies

    npm install react-i18next i18next i18next-browser-languagedetector
    PackagePurpose
    react-i18nextReact bindings for i18next
    i18nextCore internationalization framework
    i18next-browser-languagedetectorAuto-detect user's language
    react-i18nextReact bindings for i18next
    i18nextCore internationalization framework
    i18next-browser-languagedetectorAuto-detect user's language
    react-i18nextReact bindings for i18next
    i18nextCore internationalization framework
    i18next-browser-languagedetectorAuto-detect user's language
    i18nextCore internationalization framework
    i18next-browser-languagedetectorAuto-detect user's language
    i18next-browser-languagedetectorAuto-detect user's language

    Step 2: Create Translation Files

    Create a locales folder with JSON files for each language:

    src/
      locales/
        en/
          translation.json
        es/
          translation.json
        fr/
          translation.json

    src/locales/en/translation.json:

    {
      "welcome": {
        "title": "Welcome to Our App",
        "subtitle": "The best solution for your needs"
      },
      "nav": {
        "home": "Home",
        "about": "About",
        "contact": "Contact"
      },
      "auth": {
        "login": "Log In",
        "signup": "Sign Up",
        "logout": "Log Out"
      }
    }

    src/locales/es/translation.json:

    {
      "welcome": {
        "title": "Bienvenido a Nuestra App",
        "subtitle": "La mejor solucion para tus necesidades"
      },
      "nav": {
        "home": "Inicio",
        "about": "Acerca de",
        "contact": "Contacto"
      },
      "auth": {
        "login": "Iniciar Sesion",
        "signup": "Registrarse",
        "logout": "Cerrar Sesion"
      }
    }

    Step 3: Configure i18next

    Create src/i18n.js:

    import i18n from 'i18next';
    import { initReactI18next } from 'react-i18next';
    import LanguageDetector from 'i18next-browser-languagedetector';
    
    import enTranslation from './locales/en/translation.json';
    import esTranslation from './locales/es/translation.json';
    import frTranslation from './locales/fr/translation.json';
    
    i18n
      .use(LanguageDetector)
      .use(initReactI18next)
      .init({
        resources: {
          en: { translation: enTranslation },
          es: { translation: esTranslation },
          fr: { translation: frTranslation },
        },
        fallbackLng: 'en',
        interpolation: {
          escapeValue: false, // React already escapes
        },
      });
    
    export default i18n;

    Step 4: Import in App Entry

    src/index.js:

    import React from 'react';
    import ReactDOM from 'react-dom/client';
    import './i18n'; // Import i18n configuration
    import App from './App';
    
    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(
      <React.StrictMode>
        <App />
      </React.StrictMode>
    );

    Step 5: Use Translations in Components

    src/App.js:

    import { useTranslation } from 'react-i18next';
    
    function App() {
      const { t } = useTranslation();
    
      return (
        <div>
          <nav>
            <a href="/">{t('nav.home')}</a>
            <a href="/about">{t('nav.about')}</a>
            <a href="/contact">{t('nav.contact')}</a>
          </nav>
    
          <main>
            <h1>{t('welcome.title')}</h1>
            <p>{t('welcome.subtitle')}</p>
          </main>
    
          <button>{t('auth.login')}</button>
        </div>
      );
    }
    
    export default App;

    Step 6: Add Language Switcher

    import { useTranslation } from 'react-i18next';
    
    function LanguageSwitcher() {
      const { i18n } = useTranslation();
    
      const changeLanguage = (lng) => {
        i18n.changeLanguage(lng);
      };
    
      return (
        <div>
          <button onClick={() => changeLanguage('en')}>English</button>
          <button onClick={() => changeLanguage('es')}>Espanol</button>
          <button onClick={() => changeLanguage('fr')}>Francais</button>
        </div>
      );
    }
    
    export default LanguageSwitcher;

    Advanced Features

    Variables/Interpolation

    Translation:

    {
      "greeting": "Hello, {{name}}!"
    }

    Component:

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

    Pluralization

    Translation:

    {
      "items": "{{count}} item",
      "items_plural": "{{count}} items"
    }

    Component:

    t('items', { count: 1 }) // "1 item"
    t('items', { count: 5 }) // "5 items"

    Nested Keys

    // Access nested keys with dot notation
    t('welcome.title')
    t('nav.home')

    Trans Component (JSX in translations)

    Translation:

    {
      "terms": "I agree to the <link>Terms of Service</link>"
    }

    Component:

    import { Trans } from 'react-i18next';
    
    <Trans i18nKey="terms">
      I agree to the <a href="/terms">Terms of Service</a>
    </Trans>

    Managing Translations at Scale

    As your app grows, managing JSON files becomes difficult:

  • Multiple developers editing same files
  • No translation memory
  • Hard to track missing translations
  • Manual export/import with translators
  • Solution: Use a Translation Management System

    IntlPull automates React localization:

    # Scan your code for hardcoded strings
    npx intlpull scan
    
    # Pull latest translations
    npx intlpull pull --output ./src/locales
    
    # Push new strings
    npx intlpull push

    Benefits:

  • AI-powered translation
  • Collaboration with translators
  • Translation memory
  • Automatic sync with your repo
  • Common Issues and Solutions

    Issue: Translations not updating

    Solution: Make sure you imported i18n before App:

    import './i18n';
    import App from './App';

    Issue: Blank content on first load

    Solution: Add Suspense fallback:

    import { Suspense } from 'react';
    
    <Suspense fallback="Loading...">
      <App />
    </Suspense>

    Issue: TypeScript errors

    Solution: Install types and configure:

    npm install --save-dev @types/react-i18next

    Best Practices

  • Use namespaces for large apps to organize translations
  • Keep keys semantic (e.g., auth.login not button1)
  • Don't concatenate strings - use interpolation
  • Test with pseudo-localization before real translations
  • Use a TMS like IntlPull for collaboration
  • Frequently Asked Questions

    How do I add a new language?

  • Create a new JSON file (e.g., locales/de/translation.json)
  • Add it to i18n config resources
  • Add button to language switcher
  • How do I handle RTL languages?

    Add dir attribute based on language:

    <html dir={i18n.language === 'ar' ? 'rtl' : 'ltr'}>

    How do I lazy-load translations?

    Use i18next-http-backend:

    import Backend from 'i18next-http-backend';
    
    i18n.use(Backend).init({
      backend: {
        loadPath: '/locales/{{lng}}/{{ns}}.json',
      },
    });

    Summary

    To localize a React app:

  • Install react-i18next and i18next
  • Create translation JSON files
  • Configure i18next
  • Use useTranslation hook
  • Add language switcher
  • Use a TMS for scale
  • Ready to scale your localization? IntlPull automates React i18n with AI translation and seamless CLI integration.

    react
    localization
    tutorial
    react-i18next
    how-to
    Share:

    Ready to simplify your i18n workflow?

    Start managing translations with IntlPull. Free tier included.