# How to support multiple languages in Replit apps

- Tool: Replit
- Difficulty: Beginner
- Time required: 25 minutes
- Compatibility: All Replit plans. Works with React (react-i18next), Flask (Flask-Babel), and other frameworks. Install packages via Shell.
- Last updated: March 2026

## TL;DR

Add multi-language support to Replit apps using i18n libraries like react-i18next for React projects or Flask-Babel for Python. Create locale JSON files for each language, wire up a language switcher component, and let users toggle between languages at runtime. All configuration happens in code — no special Replit features are needed beyond the standard workspace.

## Add multi-language support to your Replit application

Internationalization (i18n) lets your app display content in multiple languages, making it accessible to a global audience. On Replit, you implement i18n the same way as any web project — using established libraries like react-i18next for React apps or Flask-Babel for Python Flask apps. This tutorial walks you through setting up translation files, configuring the i18n library, building a language switcher, and organizing locale files so your app scales cleanly as you add more languages.

## Before you start

- A Replit account with a React or Flask project
- Basic understanding of React components or Flask route handlers
- Familiarity with JSON file format (translations are stored as JSON)
- Access to the Shell pane for installing npm/pip packages

## Step-by-step guide

### 1. Install the i18n library for your framework

Open the Shell pane and install the appropriate internationalization library. For React projects, install react-i18next and i18next, which are the most widely used i18n solution in the React ecosystem. For Flask projects, install Flask-Babel. These libraries handle translation loading, language detection, pluralization, and formatting. Install them as regular dependencies since they are needed in production.

```
# For React projects
npm install i18next react-i18next i18next-browser-languagedetector

# For Flask projects
pip install Flask-Babel
```

**Expected result:** The packages install successfully and appear in package.json (React) or can be imported in Python (Flask).

### 2. Create translation files for each language

Create a directory structure to hold your translations. The standard pattern is to create a locales or translations folder with a subfolder or file for each language code (en, es, fr, de, etc.). Each file contains a flat or nested JSON object mapping translation keys to translated strings. Start with English as your base language and add other languages as needed. Keep translation keys descriptive and organized by feature or page.

```
// src/locales/en.json
{
  "common": {
    "welcome": "Welcome to our app",
    "login": "Log In",
    "signup": "Sign Up",
    "logout": "Log Out"
  },
  "home": {
    "title": "Home Page",
    "description": "Build amazing things with our platform",
    "cta": "Get Started"
  },
  "errors": {
    "not_found": "Page not found",
    "generic": "Something went wrong. Please try again."
  }
}

// src/locales/es.json
{
  "common": {
    "welcome": "Bienvenido a nuestra aplicacion",
    "login": "Iniciar sesion",
    "signup": "Registrarse",
    "logout": "Cerrar sesion"
  },
  "home": {
    "title": "Pagina principal",
    "description": "Crea cosas increibles con nuestra plataforma",
    "cta": "Comenzar"
  },
  "errors": {
    "not_found": "Pagina no encontrada",
    "generic": "Algo salio mal. Intentalo de nuevo."
  }
}
```

**Expected result:** You have translation files for each supported language with matching keys and translated values.

### 3. Configure i18next in your React app

Create an i18n configuration file that initializes the library, loads your translation files, and sets the default language. Import this file at the top level of your app (usually in main.jsx or App.jsx) so translations are available everywhere. The browser language detector automatically selects the user's preferred language based on their browser settings, falling back to your default language if their language is not supported.

```
// src/i18n.js
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import en from './locales/en.json';
import es from './locales/es.json';

i18n
  .use(LanguageDetector)
  .use(initReactI18next)
  .init({
    resources: {
      en: { translation: en },
      es: { translation: es }
    },
    fallbackLng: 'en',
    interpolation: {
      escapeValue: false  // React already escapes
    },
    detection: {
      order: ['localStorage', 'navigator'],
      caches: ['localStorage']
    }
  });

export default i18n;
```

**Expected result:** i18next initializes with your translations and auto-detects the user's language. The configuration persists the selected language in localStorage.

### 4. Use translations in React components

Use the useTranslation hook from react-i18next to access translations in any component. The hook returns a t function that takes a translation key and returns the translated string for the current language. Wrap your app with the I18nextProvider (automatically done by initReactI18next) and replace all hardcoded strings with t() calls. This makes every string in your UI translatable.

```
// src/components/HomePage.jsx
import { useTranslation } from 'react-i18next';

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

  return (
    <div>
      <h1>{t('home.title')}</h1>
      <p>{t('home.description')}</p>
      <button>{t('home.cta')}</button>
    </div>
  );
}
```

**Expected result:** The component displays text in the current language. Switching languages updates all t() calls automatically without a page reload.

### 5. Build a language switcher component

Create a dropdown or button group that lets users switch between languages. Use i18next's changeLanguage method to update the active language. When the language changes, all components using the useTranslation hook re-render with the new translations automatically. Store the selection in localStorage so it persists across page reloads. Place the language switcher in your header or navigation bar for easy access.

```
// src/components/LanguageSwitcher.jsx
import { useTranslation } from 'react-i18next';

const languages = [
  { code: 'en', label: 'English' },
  { code: 'es', label: 'Espanol' }
];

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

  return (
    <select
      value={i18n.language}
      onChange={(e) => i18n.changeLanguage(e.target.value)}
      style={{ padding: '4px 8px', borderRadius: '4px' }}
    >
      {languages.map((lang) => (
        <option key={lang.code} value={lang.code}>
          {lang.label}
        </option>
      ))}
    </select>
  );
}
```

**Expected result:** A dropdown appears in your UI. Selecting a language instantly updates all text on the page. The selection persists in localStorage across reloads.

### 6. Set up Flask-Babel for Python backends (optional)

If your Replit project uses Flask for the backend, Flask-Babel handles server-side internationalization including date/number formatting and template translations. Configure the supported languages and default locale, then use the gettext function in Jinja2 templates or Flask route handlers to translate strings. Flask-Babel also supports timezone-aware date formatting, which is useful for international users.

```
# app.py
from flask import Flask, request, render_template
from flask_babel import Babel, gettext as _

app = Flask(__name__)
app.config['BABEL_DEFAULT_LOCALE'] = 'en'
app.config['BABEL_SUPPORTED_LOCALES'] = ['en', 'es', 'fr']

def get_locale():
    return request.accept_languages.best_match(
        app.config['BABEL_SUPPORTED_LOCALES']
    )

babel = Babel(app, locale_selector=get_locale)

@app.route('/')
def home():
    return render_template('index.html',
        title=_('Welcome to our app'),
        description=_('Build amazing things')
    )
```

**Expected result:** Flask automatically selects the best language based on the user's browser preferences and serves translated content.

## Complete code example

File: `src/i18n.js`

```javascript
/**
 * i18n configuration for a React app on Replit.
 * Import this file in main.jsx before rendering the app.
 *
 * Usage: import './i18n';
 * In components: const { t } = useTranslation();
 */
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';

// Import all locale files
import en from './locales/en.json';
import es from './locales/es.json';

i18n
  // Detect user language from browser/localStorage
  .use(LanguageDetector)
  // Connect to React
  .use(initReactI18next)
  .init({
    resources: {
      en: { translation: en },
      es: { translation: es }
    },
    // Default language if detection fails
    fallbackLng: 'en',
    // Allow nested keys: t('common.login')
    keySeparator: '.',
    interpolation: {
      // React handles XSS protection
      escapeValue: false
    },
    detection: {
      // Check localStorage first, then browser language
      order: ['localStorage', 'navigator', 'htmlTag'],
      // Save selection to localStorage
      caches: ['localStorage'],
      lookupLocalStorage: 'i18nextLng'
    },
    // Do not load translations lazily
    partialBundledLanguages: false
  });

export default i18n;
```

## Common mistakes

- **Forgetting to import the i18n config file in main.jsx, causing useTranslation to return raw keys instead of translations** — undefined Fix: Add import './i18n'; at the top of main.jsx or index.jsx, before the React root render call.
- **Using different key structures in translation files (e.g., 'login' in English but 'common.login' in Spanish)** — undefined Fix: All translation files must use identical key structures. Copy the English file as a template for new languages and only change the values.
- **Hardcoding strings in some components while using t() in others, creating a partially translated app** — undefined Fix: Audit all components and replace every user-facing string with a t() call. Use ESLint plugins like eslint-plugin-i18next to catch missed strings.
- **Not handling text expansion — German and Spanish text can be 30-40% longer than English, breaking layouts** — undefined Fix: Test your UI in all supported languages. Use flexible CSS (flexbox, grid) that accommodates varying text lengths without overflow.

## Best practices

- Use descriptive, nested translation keys like 'home.hero.title' instead of generic keys like 'text1' for maintainability
- Always set a fallbackLng so missing translations show the default language instead of raw keys
- Store the user's language preference in localStorage so it persists across sessions and page reloads
- Keep all translation files in a dedicated locales/ directory with one file per language for easy management
- Start with a small number of languages (2-3) and add more once the i18n infrastructure is solid
- Use the browser's Accept-Language header as the initial language guess, but always let users override it manually
- Test your app in each supported language to catch layout issues — some languages produce much longer text than English
- Extract all hardcoded strings at once rather than incrementally to avoid a half-translated app

## Frequently asked questions

### Does Replit have built-in internationalization features?

No. Replit is a development platform and does not provide i18n features. You implement internationalization using standard libraries like react-i18next or Flask-Babel, just as you would in any web project.

### How many languages can I support in a Replit app?

There is no limit from Replit. The constraint is your translation files' total size, which counts against your storage quota. Each language file is typically 1-20 KB, so even 50 languages would use minimal storage.

### Can I use Replit Agent to generate translations?

Yes. You can ask Agent to create translation files based on your English source. However, AI-generated translations may not be perfect — have a native speaker review them before publishing.

### How do I handle right-to-left (RTL) languages like Arabic and Hebrew?

Add a dir attribute to your HTML element based on the current language. In React: document.documentElement.dir = isRTL ? 'rtl' : 'ltr'. You may also need Tailwind CSS RTL plugins or CSS logical properties.

### Where should I store translation files — in the frontend or backend?

For most Replit apps, store translations in the frontend as JSON files. This avoids API calls for every translation. For very large translation sets or dynamic content, consider loading translations from a database or API.

### Can RapidDev help set up internationalization for a Replit project?

Yes. RapidDev can help implement i18n architecture, set up translation workflows, configure RTL support, and integrate with translation management platforms for larger multi-language projects.

### How do I handle dynamic values in translations, like a user's name?

Use interpolation: in your JSON file, write "welcome": "Hello, {{name}}!". In your component, call t('welcome', { name: user.name }). i18next replaces {{name}} with the actual value.

### Will switching languages cause a page reload?

No. react-i18next uses React's reactivity system. When you call i18n.changeLanguage(), all components using useTranslation() re-render with the new language instantly without a page reload.

---

Source: https://www.rapidevelopers.com/replit-tutorial/how-to-enable-multi-language-support-in-replit-for-internationalized-projects
© RapidDev — https://www.rapidevelopers.com/replit-tutorial/how-to-enable-multi-language-support-in-replit-for-internationalized-projects
