> ## Documentation Index
> Fetch the complete documentation index at: https://docs.weaverse.io/llms.txt
> Use this file to discover all available pages before exploring further.

# i18next Integration

> Learn how to set up i18next for advanced localization and pluralization support in Weaverse.

# How to Integrate i18next with Weaverse Hydrogen

This guide explains how to integrate **i18next** as the primary translation engine in your Weaverse Hydrogen project.

While Weaverse provides a built-in `useThemeText()` hook for simple `{ {variable} }` substitution, integrating `i18next` enables advanced localization features like **plurals**, **context-based formatting**, and **ordinals**—without breaking Weaverse's visual translation workflow!

## How It Works

Weaverse's resolution chain allows you to inject an `externalT` function into the `withWeaverse` configuration. When provided, Weaverse evaluates translations in the following priority:

1. **External t (i18next)** ← Highest priority
2. **Merchant Overrides** (from Weaverse Studio)
3. **Static Content** (`schema.i18n.staticContent`)
4. **Translation Key** ← Fallback

By routing translations through `i18next` first and gracefully falling back to Weaverse if strings aren't matched, your components enjoy full i18next capabilities while giving non-technical merchants complete control inside the Weaverse builder.

***

## Step 1: Install Dependencies

You only need the core `i18next` package. React bindings (`react-i18next`) are fully optional unless you strictly prefer using them in your components over `useThemeText`.

```bash theme={null}
npm install i18next
```

***

## Step 2: Create the i18n Bridge

Create an initialization and bridge file (e.g., `app/utils/i18n.ts`) that holds your `i18next` singleton and the adapter function (`weaverseT`) expected by Weaverse.

```typescript theme={null}
import i18next from 'i18next';
import type { TranslateFunction } from '@weaverse/hydrogen';

// 1. Singleton initialization
let initPromise: Promise<void> | null = null;
function ensureInit() {
  if (initPromise) return initPromise;
  
  initPromise = i18next.init({
    fallbackLng: 'en',
    interpolation: { escapeValue: false }, // React already safeguards against XSS
    compatibilityJSON: 'v4', // Required for advanced pluralizations (_one, _other)
    saveMissing: false,
  }).then(() => undefined);
  
  return initPromise;
}

// 2. Safely initialize translation state per-request (Server / Client)
export async function initI18n(locale: string, translations: Record<string, any>) {
  const lang = locale.toLowerCase().split('_')[0]; // Map 'EN_US' -> 'en'
  await ensureInit();

  if (!i18next.hasResourceBundle(lang, 'translation')) {
    i18next.addResourceBundle(lang, 'translation', translations, true, false);
  }

  if (i18next.language !== lang) {
    await i18next.changeLanguage(lang);
  }
}

// 3. The `externalT` adapter for Weaverse
export const weaverseT: TranslateFunction = (key, variables) => {
  if (!i18next.isInitialized) return key;
  
  const result = i18next.t(key, variables as object | undefined);
  
  // If no translation is found, return the raw key so Weaverse can handle fallbacks gracefully!
  return typeof result === 'string' ? result : key;
};
```

***

## Step 3: Configure Weaverse at the Root level

You now need to inject `weaverseT` into Weaverse and guarantee `initI18n` runs before your app renders the React tree. Open your `app/root.tsx` (or equivalent layout file).

### Add the `externalT` injection:

Pass the `weaverseT` instance to your `withWeaverse` wrapper configuration.

```typescript theme={null}
// app/root.tsx
import { weaverseT } from '~/utils/i18n';
// ...
export const Layout = withWeaverse(RootLayout, { t: weaverseT });
```

### Initialize the language on the Server:

Inside your route `loader`, extract the storefront locale and explicitly trigger `initI18n` using your base JSON bundle.

```typescript theme={null}
// app/root.tsx
import { initI18n } from '~/utils/i18n';
import baseTranslations from '~/i18n/en.json';

export async function loader(args: LoaderFunctionArgs) {
  const data = await loadData(args);
  
  // E.g., data.locale is the Hydrogen active locale prefix
  await initI18n(data.locale, baseTranslations); 

  return data;
}
```

### Sync Client Hydration:

If the user transitions languages seamlessly via client-side routing, add a `useEffect` within the `RootLayout` implementation to sync `i18next` on the browser.

```tsx theme={null}
export function RootLayout() {
  const { locale } = useRouteLoaderData<typeof loader>('root');
  
  useEffect(() => {
    if (locale) initI18n(locale, baseTranslations);
  }, [locale]);
  
  return (/* Your Layout UI */);
}
```

***

## Step 4: Write Components

Your components don't need any updates. Standard keys simply fall back to Weaverse, but keys mapped in your `i18next` bundles using advanced interpolations now resolve correctly!

**Theme JSON Example:**

```json theme={null}
{
  "cart": {
    "itemCount_one": "{{count}} item",
    "itemCount_other": "{{count}} items"
  }
}
```

**React Component Example:**

```tsx theme={null}
import { useThemeText } from "@weaverse/hydrogen";

export function CartItemCount({ count }: { count: number }) {
  const { t } = useThemeText();
  
  // Will output "1 item" or "3 items" depending on the count!
  return <span>{t('cart.itemCount', { count })}</span>;
}
```

## Summary Checklist

* Install `i18next`.
* Create an i18n bridge script containing a secure async init method and the `weaverseT` proxy.
* Pass the localized locale variable to `initI18n` in `root.tsx` loader.
* Wrap `RootLayout` via `withWeaverse(RootLayout, { t: weaverseT })`.
* Enjoy full i18next pluralization combined with Weaverse's visual translation integration!
