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, and this page is available as Markdown at https://mfeflow.github.io/mfeflow/features/i18n.md.

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

pnpm mfeflow add i18n

What changed in the shell:

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:

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 feature.

Existing files are edited too, as listed here:

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.

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:

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.

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.

SettingWhereDefault
languagessrc/i18n/config.tsEnglish and Arabic
defaultLanguagesrc/i18n/config.tsen. It must be in the list.
resourcesthe call in src/i18n/init.tsthe shell's own messages, bundled up front
detectthe call to initI18ntrue: use the browser's languages
storage, rootthe call to initI18nthe 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, 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