# How to Configure Internationalization (i18n) in OmniRoute with 42 Locales Using next-intl

> Learn to configure internationalization i18n in OmniRoute with 42 locales using next-intl. Discover seamless integration for multi-language support in your application.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: how-to-guide
- Published: 2026-07-05

---

**TLDR:** OmniRoute provides a complete next-intl integration that reads 42 locales from [`config/i18n.json`](https://github.com/diegosouzapw/OmniRoute/blob/main/config/i18n.json), exports them as typed constants in [`src/i18n/config.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/i18n/config.ts), and wires everything together via [`src/i18n/request.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/i18n/request.ts) and [`src/app/layout.tsx`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/layout.tsx) with zero hard-coding.

OmniRoute ships with a production-ready internationalization setup powered by next-intl. This open-source routing solution manages 42 languages through a single JSON catalogue, eliminating the need to hard-code locale lists in TypeScript. By centralizing configuration in [`config/i18n.json`](https://github.com/diegosouzapw/OmniRoute/blob/main/config/i18n.json), the system automatically generates type-safe constants and handles RTL detection, cookie persistence, and message loading.

## Understanding the OmniRoute i18n Architecture

OmniRoute separates concerns between data (the JSON catalogue), types (the TypeScript config), and runtime (the request loader and provider). This separation allows you to add or remove languages without touching application code.

### The Locale Catalogue at config/i18n.json

The source of truth lives in [`config/i18n.json`](https://github.com/diegosouzapw/OmniRoute/blob/main/config/i18n.json). This file defines the `default` locale, an `rtl` array for right-to-left languages, and the full list of 42 supported locales. Each locale object includes metadata fields such as `code`, `label`, `name`, `native`, `english`, and `flag`.

OmniRoute never hard-codes the locale list; it reads this file at build time. When you modify the JSON array, the TypeScript definitions update automatically on the next build.

### Type-Safe Configuration in src/i18n/config.ts

The [`src/i18n/config.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/i18n/config.ts) file transforms the JSON catalogue into typed exports. The `LOCALES` constant is generated by mapping the JSON array (`config.locales.map(l => l.code)`), ensuring the array remains synchronized with the catalogue. This file also exports:

- `DEFAULT_LOCALE` – derived from the JSON default value
- `RTL_LOCALES` – filtered from the rtl array in the JSON
- `LOCALE_COOKIE` – set to `"NEXT_LOCALE"` for cookie-based persistence

Because these values are built from [`config/i18n.json`](https://github.com/diegosouzapw/OmniRoute/blob/main/config/i18n.json), importing `LOCALES` anywhere in the codebase guarantees type safety and completeness.

## Configuring the Server-Side Request Loader

The [`src/i18n/request.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/i18n/request.ts) file implements `getRequestConfig` from `next-intl/server`. This loader determines the active locale by checking the URL, the `NEXT_LOCALE` cookie, or headers, falling back to `DEFAULT_LOCALE` if no match is found.

```typescript
// src/i18n/request.ts
import { getRequestConfig } from "next-intl/server";
import { LOCALES, DEFAULT_LOCALE } from "./config";

export default getRequestConfig({
  locales: LOCALES,
  defaultLocale: DEFAULT_LOCALE,
  // Messages are auto-imported from src/i18n/messages/*-locale.json
});

```

When a request hits the server, this configuration loads the corresponding translation file from `src/i18n/messages/` based on the resolved locale.

## Implementing the Client-Side Provider

In [`src/app/layout.tsx`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/layout.tsx), the root layout wraps the application in `<NextIntlClientProvider>`. This component receives the locale and messages from async server functions, making translations available to all client components.

```tsx
// src/app/layout.tsx
import { NextIntlClientProvider } from "next-intl";
import { getMessages, getLocale } from "next-intl/server";

export default async function RootLayout({ children }: { children: React.ReactNode }) {
  const locale = await getLocale();          // Respects LOCALE_COOKIE
  const messages = await getMessages();      // Loads the JSON for `locale`

  return (
    <html lang={locale}>
      <body>
        <NextIntlClientProvider locale={locale} messages={messages}>
          {children}
        </NextIntlClientProvider>
      </body>
    </html>
  );
}

```

This setup supplies the `useTranslations` and `useLocale` hooks to every component in the tree, including shared components like [`src/shared/components/Header.tsx`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/components/Header.tsx).

## Adding or Removing Locales in the 42-Language Setup

To add a new language—such as Korean—you only need to edit [`config/i18n.json`](https://github.com/diegosouzapw/OmniRoute/blob/main/config/i18n.json). Append the new locale object to the `locales` array:

```json
// config/i18n.json (excerpt)
{
  "default": "en",
  "rtl": [],
  "locales": [
    {
      "code": "ko",
      "label": "Korean",
      "name": "Korean",
      "native": "한국어",
      "english": "Korean",
      "flag": "🇰🇷"
    }
  ]
}

```

After saving the file and running `npm run build`, the new `ko` entry appears in the `LOCALES` array exported by [`src/i18n/config.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/i18n/config.ts) (line 26). No TypeScript changes are required. To remove a locale, simply delete its entry from the JSON file.

## Consuming Translations in Components

Components access the 42-locale catalogue and current translation context through next-intl hooks. Import `LOCALES` from [`src/i18n/config.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/i18n/config.ts) to render language selectors or locale-aware navigation.

```tsx
import { useLocale, useTranslations } from "next-intl";
import { LOCALES } from "@/i18n/config";

export default function LanguageSelector() {
  const t = useTranslations("language-selector");
  const locale = useLocale();

  return (
    <select value={locale}>
      {LOCALES.map((code) => (
        <option key={code} value={code}>
          {t(`locale.${code}`)}
        </option>
      ))}
    </select>
  );
}

```

The `useLocale()` hook returns the active locale code, while `useTranslations()` accesses namespaced message keys from the loaded JSON files.

## Summary

- OmniRoute stores the 42-locale catalogue in [`config/i18n.json`](https://github.com/diegosouzapw/OmniRoute/blob/main/config/i18n.json), making it the single source of truth for all language metadata.
- [`src/i18n/config.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/i18n/config.ts) generates type-safe exports (`LOCALES`, `DEFAULT_LOCALE`, `RTL_LOCALES`) by reading the JSON file at build time.
- The server-side loader in [`src/i18n/request.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/i18n/request.ts) uses `getRequestConfig` to resolve locales and load messages automatically.
- [`src/app/layout.tsx`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/layout.tsx) wraps the app in `<NextIntlClientProvider>` to supply translation hooks to client components.
- Adding or removing languages requires only editing [`config/i18n.json`](https://github.com/diegosouzapw/OmniRoute/blob/main/config/i18n.json); no TypeScript code changes are necessary.

## Frequently Asked Questions

### How many locales does OmniRoute support by default?

OmniRoute ships with 42 locales configured in [`config/i18n.json`](https://github.com/diegosouzapw/OmniRoute/blob/main/config/i18n.json). This includes major world languages and regional variants, all defined with metadata like native names and flag emojis. You can expand or reduce this list by editing the JSON file without modifying TypeScript code.

### Where does OmniRoute store translation messages?

Translation files live in `src/i18n/messages/` as individual JSON files named by locale code (e.g., [`en.json`](https://github.com/diegosouzapw/OmniRoute/blob/main/en.json), [`pt-BR.json`](https://github.com/diegosouzapw/OmniRoute/blob/main/pt-BR.json)). The `getRequestConfig` loader in [`src/i18n/request.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/i18n/request.ts) automatically imports the correct file based on the resolved locale, while `getMessages()` in [`src/app/layout.tsx`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/layout.tsx) makes them available to the provider.

### Do I need to modify TypeScript files when adding a new language?

No. Because [`src/i18n/config.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/i18n/config.ts) generates the `LOCALES` array dynamically from [`config/i18n.json`](https://github.com/diegosouzapw/OmniRoute/blob/main/config/i18n.json) using `config.locales.map(l => l.code)`, adding a new locale to the JSON file automatically updates the typed exports on the next build. This zero-code workflow prevents synchronization errors between configuration and implementation.

### How does OmniRoute handle RTL (Right-to-Left) languages?

The `rtl` array in [`config/i18n.json`](https://github.com/diegosouzapw/OmniRoute/blob/main/config/i18n.json) defines which locales require right-to-left text direction. [`src/i18n/config.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/i18n/config.ts) exports these as `RTL_LOCALES`, which components can use to conditionally apply CSS directionality or layout adjustments. The system supports Arabic, Hebrew, and other RTL languages out of the box when listed in the JSON configuration.