> For AI agents: the complete documentation index is available at https://mfeflow.github.io/mfeflow/llms.txt, the full documentation bundle is available at https://mfeflow.github.io/mfeflow/llms-full.txt.

# i18n

This feature adds translations to a micro-frontend platform without making every team edit one central message file. The shell starts a single i18next instance, and each remote brings its own messages, so a fixed translation ships with the remote that uses it.

## What you get

The shell gets a language list, a boot step and a language picker you own. Each remote gets message files in English and Arabic (a right-to-left language), a loader, and a wrapper that shows a greeting from its own messages.

## Add it

```sh
pnpm mfeflow add i18n
```

What changed in the shell:

```text
src/i18n/
├── config.ts                   # the language list and default
├── init.ts                     # starts the shared instance
├── Languages.tsx               # wraps the app
├── LanguageSwitcher.tsx        # the language picker
├── init.test.ts                # only if you use testing
└── LanguageSwitcher.test.tsx   # only if you use testing
```

What changed in every remote:

```text
src/i18n/
├── config.ts          # the remote's own language list
├── load.ts            # loads messages from the remote's deploy
├── I18n.tsx           # the wrapper with a greeting
├── I18n.test.tsx      # only if you use testing
└── messages/
    ├── en.json        # English messages
    └── ar.json        # Arabic messages
```

The test files need the [testing](https://mfeflow.github.io/mfeflow/features/testing.md) feature.

Existing files are edited too, as listed here:

```text
shell   src/bootstrap.tsx      awaits the boot step before the first render
shell   src/App.tsx            wrapped in Languages
remote  src/exposed/App.tsx    wrapped in I18n
```

The packages i18next and react-i18next are added at pinned versions to the shell and every remote.

## Use it

Inside a remote, ask for translations by the remote's name and pass the loader that was generated for you.

```tsx
import { useMfeTranslation } from '@mfeflow/i18n/react';
import { loadMessages } from './i18n/load';

export function Title() {
  const { t } = useMfeTranslation('cart', loadMessages);
  return <h2>{t('hello')}</h2>;
}
```

The messages are plain JSON next to the loader:

```json title="apps/cart/src/i18n/messages/en.json"
{
  "hello": "Hello from cart"
}
```

To add a language, list it in the shell, then add a file with the same name to each remote.

```ts title="apps/shell/src/i18n/config.ts"
export const languages: LanguageOption[] = [
  { code: 'en', label: 'English' },
  { code: 'ar', label: 'العربية' },
];

export const defaultLanguage = 'en';
```

## Configure it

There are no install options. These are the settings you edit, or pass to `initI18n` in `init.ts`.

| Setting           | Where                          | Default                                    |
| ----------------- | ------------------------------ | ------------------------------------------ |
| `languages`       | `src/i18n/config.ts`           | English and Arabic                         |
| `defaultLanguage` | `src/i18n/config.ts`           | `en`. It must be in the list.              |
| `resources`       | the call in `src/i18n/init.ts` | the shell's own messages, bundled up front |
| `detect`          | the call to `initI18n`         | `true`: use the browser's languages        |
| `storage`, `root` | the call to `initI18n`         | the shell's storage, and `<html>`          |

## How it works

On first load the language is the saved choice if there is one. Next comes the first browser language you support, by exact match or its base, so `pt-BR` falls back to `pt`. After that comes the default.

Changing the language sets `lang` and `dir` on the page and saves the choice under the shell's storage. The direction comes from i18next, so Arabic, Hebrew and the others it knows are right to left.

A remote's messages load when its component mounts and again when the language changes, each language as its own chunk from that remote's deploy. If one language fails to load, the default language's messages are used, so text never goes blank. The same fallback covers a remote that has no file for a language yet.

`i18next` and `react-i18next` are [shared singletons](https://mfeflow.github.io/mfeflow/concepts/shared-singletons.md), so the page has one copy of each. `mfeflow doctor` compares the versions your apps declare.

## Gotchas

- Run a remote on its own with `pnpm dev` and it starts its own instance with its own language list. Inside the shell, the shell's list wins and the remote's `config.ts` is ignored.

- Use CSS logical properties such as `margin-inline-start` in remotes. Then `dir` is all a right-to-left language needs.

- The namespace is the remote's name. Two remotes that pick the same namespace would share messages.

## Reference

- [theming](https://mfeflow.github.io/mfeflow/features/theming.md), another shell-owned page concern
- [Shared singletons](https://mfeflow.github.io/mfeflow/concepts/shared-singletons.md)
- [feature.json reference](https://mfeflow.github.io/mfeflow/reference/feature-json.md)
