home / skills / sergiodxa / agent-skills / frontend-internationalization-best-practices

frontend-internationalization-best-practices skill

/skills/frontend-internationalization-best-practices

This skill guides you through implementing internationalization for React Router apps with remix-i18next, improving localization accuracy and performance.

npx playbooks add skill sergiodxa/agent-skills --skill frontend-internationalization-best-practices

Review the files below or copy the command above to add this skill to your agents.

Files (12)
SKILL.md
3.4 KB
---
name: frontend-internationalization-best-practices
description: Internationalization best practices for React Router framework mode using remix-i18next. Use when setting up locales, middleware, resource routes, or language switching.
---

# Internationalization Best Practices

Guidelines for building a React Router i18n setup with `remix-i18next`. Focuses on middleware detection, locale storage, type safety, and client/server synchronization.

## When to Apply

- Adding i18n to a React Router app
- Wiring `remix-i18next` middleware
- Implementing language switching or locale detection
- Serving locale resources from `/api/locales`

## Rules Summary

### Setup & Middleware (CRITICAL)

#### setup-middleware - @rules/setup-middleware.md

Configure `createI18nextMiddleware` and type-safe resources.

```ts
export const [i18nextMiddleware, getLocale, getInstance] =
  createI18nextMiddleware({
    detection: {
      supportedLanguages: ["es", "en"],
      fallbackLanguage: "en",
      cookie: localeCookie,
    },
    i18next: { resources },
    plugins: [initReactI18next],
  });
```

#### locales-structure - @rules/locales-structure.md

Define locale resources per language and re-export.

```ts
// app/locales/en/translation.ts
export default { title: "Example" };
```

### Namespaces (HIGH)

#### namespaces-strategy - @rules/namespaces-strategy.md

Use a single namespace for small apps; multiple namespaces for large apps.

```ts
// Large app: common + route namespaces
export default { common, home, notFound };
```

### Locale Detection & Persistence (CRITICAL)

#### locale-detection - @rules/locale-detection.md

Prefer cookie/session for speed, with DB as source of truth.

```ts
export const [i18nextMiddleware, getLocale] = createI18nextMiddleware({
  detection: { cookie: localeCookie, fallbackLanguage: "en" },
});
```

#### language-switcher - @rules/language-switcher.md

Store locale in cookie/session and keep it in sync.

```ts
return data(
  { locale },
  { headers: { "Set-Cookie": await localeCookie.serialize(locale) } },
);
```

### Client & Server Integration (CRITICAL)

#### root-locale-sync - @rules/root-locale-sync.md

Send locale to the UI and sync `<html lang dir>`.

```tsx
export async function loader({ context }: Route.LoaderArgs) {
  let locale = getLocale(context);
  return data(
    { locale },
    { headers: { "Set-Cookie": await localeCookie.serialize(locale) } },
  );
}
```

#### entry-client-init - @rules/entry-client-init.md

Initialize i18next client with `htmlTag` detection.

```ts
i18next.init({ detection: { order: ["htmlTag"], caches: [] } });
```

#### entry-server-provider - @rules/entry-server-provider.md

Reuse the middleware instance in SSR with `I18nextProvider`.

```tsx
<I18nextProvider i18n={getInstance(routerContext)}>
  <ServerRouter context={entryContext} url={request.url} />
</I18nextProvider>
```

### Resource Routes & Caching (HIGH)

#### locales-resource-route - @rules/locales-resource-route.md

Serve `/api/locales/:lng/:ns` with validation and cache headers.

```ts
return data(namespaces[ns.data], { headers });
```

### UI Usage (MEDIUM)

#### use-bound-t-in-loader - @rules/use-bound-t-in-loader.md

Use the bound `t()` in loaders and `useTranslation` in components.

```ts
let t = getInstance(context).getFixedT(locale);
```

### Not Found (MEDIUM)

#### not-found-i18n - @rules/not-found-i18n.md

Provide a 404 route so middleware runs and translations load.

Overview

This skill provides concise best practices for implementing internationalization in React Router apps using remix-i18next. It focuses on middleware setup, locale detection and persistence, client/server synchronization, and serving locale resources. Follow these guidelines to build a predictable, type-safe, and performant i18n layer.

How this skill works

The guidance shows how to configure createI18nextMiddleware with detection, resources, and plugins, and how to re-use the middleware instance on server and client. It covers storing locale in cookies or session, syncing the root loader to set HTML lang/dir, exposing locale resource routes with caching, and using bound t() in loaders and components. It also recommends a namespace strategy based on app size.

When to use it

  • Adding i18n to a new or existing React Router app
  • Wiring remix-i18next middleware and SSR integration
  • Implementing language switching, detection, or persistence
  • Serving locale JSON from /api/locales with cache headers
  • Ensuring UI and server share the same locale and translations

Best practices

  • Initialize createI18nextMiddleware with supportedLanguages, fallbackLanguage, cookie, resources, and initReactI18next
  • Store locale in a cookie or session for fast detection; use DB as source of truth when needed
  • Export per-language resource files and re-export them to maintain type safety
  • Sync root loader to return locale and set Set-Cookie, and keep <html lang dir> in sync
  • Reuse middleware instance on server with I18nextProvider for SSR hydration
  • Serve /api/locales/:lng/:ns with validation and cache-control for client fetching

Example use cases

  • Add i18n to a Remix-based site and detect user language via cookie
  • Build a language switcher that writes locale to a cookie and redirects
  • Expose namespaces as /api/locales/en/common to let the client load resources lazily
  • Render server-side with the same i18n instance to avoid mismatch flashes
  • Organize translations into a single namespace for small apps or multiple namespaces for large apps

FAQ

Should I store locale in a cookie or the database?

Use a cookie or session for fast detection; treat the database as the authoritative setting when syncing user preferences across devices.

How do I avoid hydration mismatches for language?

Return locale from the root loader, set the cookie header, and initialize the client i18next with htmlTag detection or reuse the server instance via I18nextProvider.