# i18n Migration Guide

This document describes the i18n configuration changes that enable **both** flat and namespaced translation usage. Users with the older single-namespace setup can migrate using the instructions below.

## Summary of Changes

The i18n setup now supports two usage patterns interchangeably:

| Pattern | Example | Use case |
|---------|---------|----------|
| **Flat (no namespace)** | `useTranslation()` + `t('namespace.section.key')` | Quick access, explicit full path |
| **Namespaced** | `useTranslation('namespace')` + `t('section.key')` | Modular components, shorter keys |

Previously, only the flat pattern worked because all translations lived under a single `translation` namespace. The namespaced pattern failed because i18next couldn't find the individual namespaces (the top-level keys in your merged translation object).

---

## Patch: `src/lib/i18n.ts`

### Before (old configuration)

```typescript
if (!i18n.isInitialized) {
  const lng = getStoredLanguage();
  i18n.use(initReactI18next).init({
    resources: {
      en: { translation: mergeTranslations('en') },
      ja: { translation: mergeTranslations('ja') },
    },
    supportedLngs: supportedLanguages,
    lng,
    fallbackLng: defaultLanguage,
    interpolation: {
      escapeValue: false,
    },
  });
  setLanguageHooks(lng);
}
```

### After (new configuration)

```typescript
if (!i18n.isInitialized) {
  const lng = getStoredLanguage();
  const enResources = mergeTranslations('en');
  const jaResources = mergeTranslations('ja');
  i18n.use(initReactI18next).init({
    resources: {
      en: {
        translation: enResources,
        ...enResources,
      },
      ja: {
        translation: jaResources,
        ...jaResources,
      },
    },
    defaultNS: 'translation',
    ns: ['translation', ...Object.keys(enResources)],
    supportedLngs: supportedLanguages,
    lng,
    fallbackLng: defaultLanguage,
    interpolation: {
      escapeValue: false,
    },
  });
  setLanguageHooks(lng);
}
```

### What changed

1. **Resources structure**: Each language now exposes both:
   - `translation` – the full merged object for flat keys, e.g. `t('namespace.section.key')`
   - Individual namespaces – one per top-level key in the merged object, for `useTranslation('namespace')` + `t('section.key')`

2. **`defaultNS: 'translation'`**: Ensures `useTranslation()` without arguments uses the flat namespace.

3. **`ns` array**: Must list `'translation'` plus every top-level key returned by `mergeTranslations()` (e.g. `['translation', ...Object.keys(enResources)]`) so i18next can load and resolve them correctly.

---

## Migration Steps

### 1. Update `src/lib/i18n.ts`

Replace the `if (!i18n.isInitialized)` block with the new configuration above. The rest of the file (imports, `getLanguage`, `changeLanguage`, etc.) stays the same.

### 2. Verify translation key paths (flat usage)

With the default `translation` namespace, keys must include the full path from the root of your merged translations. The format is the namespace (top-level key) followed by the path inside it:

- **Format**: `t('<namespace>.<path.to.key>')`
- **Example**: If your merged object has a top-level key `auth` with `login.title` inside it, use `t('auth.login.title')`.

If a key used to work as `t('someKey')` and now fails, it likely lives under a namespace in your structure—update it to `t('<namespace>.<someKey>')` (or the full path that matches your locale JSON).

### 3. Optional: Use namespaced pattern in components

You can migrate components to the namespaced pattern for shorter keys:

```tsx
// Before (flat)
const { t } = useTranslation();
return <h1>{t('namespace.section.title')}</h1>;

// After (namespaced) – optional
const { t } = useTranslation('namespace');
return <h1>{t('section.title')}</h1>;
```

Both forms work. Choose what fits your component structure.

---

## Available Namespaces

Namespaces in your project are determined by **the top-level keys of the object returned by `mergeTranslations(lng)`**.

- **`translation`** – Always present. Contains the full merged tree so flat keys like `t('namespace.section.key')` work.
- **Other namespaces** – One for each top-level key in that merged object (e.g. if your merge yields `{ auth, app, common }`, you get namespaces `auth`, `app`, and `common`). Their contents match whatever structure your locale files and `mergeTranslations` produce.

To see which namespaces you have, inspect the keys of the result of `mergeTranslations('en')` (or your default language) and use that same list in the `ns` option in `i18n.ts`.

---

## No Changes Required

- **`src/locales/index.ts`** – `mergeTranslations` is unchanged
- **Locale JSON files** – No structure changes
- **Components using flat keys** – Existing `t('namespace.path.to.key')` calls continue to work
- **`LanguageSwitcher`** – Uses `i18n` only; no translation keys
