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

# Internationalization (i18n)

> Add multi-language support to MetaMCP with Next.js locale routing and client-side translations

MetaMCP uses **Next.js locale-based routing** and **client-side translations** to support multiple languages. This guide explains the i18n system and how to add new languages.

## Current Language Support

MetaMCP currently supports:

* **English (en)** - Default language
* **Chinese Simplified (zh)** - Full translation available

The author maintains both languages for translation accuracy, but contributions for additional languages are welcome.

## Project Structure

The internationalization system is organized as follows:

```bash theme={null}
apps/frontend/
├── app/
│   └── [locale]/                  # Locale-based routing
│       ├── layout.tsx            # Locale layout
│       ├── (sidebar)/            # Sidebar layout group
│       └── ...
├── public/locales/
│   ├── en/                       # English translations
│   │   ├── common.json
│   │   ├── auth.json
│   │   ├── navigation.json
│   │   ├── mcp-servers.json
│   │   ├── namespaces.json
│   │   ├── endpoints.json
│   │   ├── api-keys.json
│   │   ├── settings.json
│   │   ├── search.json
│   │   ├── inspector.json
│   │   ├── logs.json
│   │   └── validation.json
│   └── zh/                       # Chinese translations
│       └── (same structure)
├── lib/
│   └── i18n.ts                  # Client-side i18n utilities
├── hooks/
│   ├── useLocale.ts             # Hook to get current locale
│   └── useTranslations.ts       # Hook for client-side translations
├── components/
│   └── language-switcher.tsx    # Language switching component
└── middleware.ts                # Locale detection and routing
```

## How It Works

### URL Structure

MetaMCP uses locale-based routing:

* **English (default)**: `/mcp-servers`, `/settings`, `/namespaces`
* **Chinese**: `/zh/mcp-servers`, `/zh/settings`, `/zh/namespaces`

### Middleware

The `middleware.ts` file handles:

* **Locale detection** from URL, cookies, and Accept-Language header
* **Automatic redirects** to appropriate locale
* **Authentication checks**

<CodeGroup>
  ```typescript middleware.ts theme={null}
  import { NextRequest } from 'next/server';
  import { getLocale, getLocalizedPath } from '@/lib/i18n';

  export function middleware(request: NextRequest) {
    // Detect locale from URL, cookie, or headers
    const locale = getLocale(request);
    
    // Redirect if needed
    if (!request.nextUrl.pathname.startsWith(`/${locale}`)) {
      const localizedPath = getLocalizedPath(request.nextUrl.pathname, locale);
      return Response.redirect(new URL(localizedPath, request.url));
    }
  }
  ```

  ```typescript lib/i18n.ts theme={null}
  export function getLocalizedPath(path: string, locale: string): string {
    if (locale === 'en') {
      return path; // Default locale doesn't need prefix
    }
    return `/${locale}${path}`;
  }

  export function detectLocale(request: NextRequest): string {
    // Check URL first, then cookies, then Accept-Language
    // Return detected locale or fallback to 'en'
  }
  ```
</CodeGroup>

## Using Translations

### Client Components

For client-side components, use the `useTranslations` hook:

<CodeGroup>
  ```tsx Basic Usage theme={null}
  "use client";

  import { useTranslations } from "@/hooks/useTranslations";

  function ClientComponent() {
    const { t, isLoading, locale } = useTranslations();
    
    if (isLoading) return <div>Loading...</div>;
    
    return (
      <div>
        <h1>{t('common:title')}</h1>
        <button>{t('auth:signIn')}</button>
      </div>
    );
  }
  ```

  ```tsx With Parameters theme={null}
  // In translation file: "welcome": "Welcome, {{name}}!"
  <span>{t('common:welcome', { name: 'John' })}</span>

  // With count: "itemCount": "{{count}} items found"
  <span>{t('search:itemCount', { count: 42 })}</span>
  ```

  ```tsx Conditional Translations theme={null}
  const { t, locale } = useTranslations();

  return (
    <div>
      <p>{t('common:currentLanguage')}: {locale}</p>
      {locale === 'zh' && (
        <p>{t('common:chineseSpecificMessage')}</p>
      )}
    </div>
  );
  ```
</CodeGroup>

### Translation Key Format

Use colon-separated namespaces for organization:

```json theme={null}
{
  "server": {
    "create": "Create Server",
    "edit": "Edit Server",
    "delete": "Delete Server",
    "status": {
      "online": "Online",
      "offline": "Offline",
      "error": "Error"
    },
    "validation": {
      "nameRequired": "Server name is required",
      "commandRequired": "Command is required"
    }
  }
}
```

**Usage**: `t('mcp-servers:server.create')`, `t('mcp-servers:server.status.online')`

## Translation File Organization

### Namespace Structure

Each translation namespace serves a specific purpose:

<AccordionGroup>
  <Accordion icon="globe" title="common.json">
    **Shared UI elements and general terms**

    ```json theme={null}
    {
      "actions": {
        "save": "Save",
        "cancel": "Cancel",
        "delete": "Delete",
        "edit": "Edit",
        "create": "Create",
        "search": "Search"
      },
      "status": {
        "loading": "Loading...",
        "error": "Error",
        "success": "Success"
      },
      "form": {
        "required": "This field is required",
        "invalid": "Invalid input"
      }
    }
    ```
  </Accordion>

  <Accordion icon="lock" title="auth.json">
    **Authentication-related text**

    ```json theme={null}
    {
      "signIn": "Sign In",
      "signOut": "Sign Out",
      "signUp": "Sign Up",
      "email": "Email",
      "password": "Password",
      "forgotPassword": "Forgot Password?",
      "createAccount": "Create Account",
      "loginWithOIDC": "Login with OIDC"
    }
    ```
  </Accordion>

  <Accordion icon="navigation" title="navigation.json">
    **Menu items and navigation text**

    ```json theme={null}
    {
      "dashboard": "Dashboard",
      "mcpServers": "MCP Servers",
      "namespaces": "Namespaces",
      "endpoints": "Endpoints",
      "apiKeys": "API Keys",
      "settings": "Settings",
      "inspector": "MCP Inspector",
      "logs": "Live Logs"
    }
    ```
  </Accordion>

  <Accordion icon="server" title="mcp-servers.json">
    **MCP server-specific translations**

    ```json theme={null}
    {
      "server": {
        "create": "Create Server",
        "edit": "Edit Server",
        "name": "Server Name",
        "type": "Server Type",
        "command": "Command",
        "args": "Arguments",
        "env": "Environment Variables"
      },
      "types": {
        "stdio": "STDIO",
        "http": "HTTP",
        "websocket": "WebSocket"
      }
    }
    ```
  </Accordion>
</AccordionGroup>

### Best Practices for Translation Keys

<Card title="Translation Key Guidelines" icon="key">
  * **Use descriptive, hierarchical keys**: `server.validation.nameRequired`
  * **Use camelCase for consistency**: `signIn`, `mcpServers`
  * **Group related translations**: All server-related terms under `server`
  * **Keep context clear**: `auth:signIn` vs `form:signIn` if different
  * **Use interpolation for dynamic content**: `"welcome": "Welcome, {{name}}!"`
</Card>

## Adding New Languages

### Step 1: Create Translation Files

1. **Create language directory** in `public/locales/`:
   ```bash theme={null}
   mkdir -p public/locales/es  # For Spanish
   ```

2. **Copy English files** as templates:
   ```bash theme={null}
   cp -r public/locales/en/* public/locales/es/
   ```

3. **Translate the content** in each JSON file:
   ```json theme={null}
   // public/locales/es/common.json
   {
     "actions": {
       "save": "Guardar",
       "cancel": "Cancelar",
       "delete": "Eliminar",
       "edit": "Editar",
       "create": "Crear"
     }
   }
   ```

### Step 2: Update Configuration

Add the new locale to your i18n configuration:

<CodeGroup>
  ```typescript lib/i18n.ts theme={null}
  export const SUPPORTED_LOCALES = ['en', 'zh', 'es'] as const;
  export type Locale = typeof SUPPORTED_LOCALES[number];

  export const LOCALE_NAMES: Record<Locale, string> = {
    en: 'English',
    zh: '中文',
    es: 'Español'
  };
  ```

  ```typescript middleware.ts theme={null}
  import { SUPPORTED_LOCALES } from '@/lib/i18n';

  export function middleware(request: NextRequest) {
    // Update locale detection to include new language
    const supportedLocales = SUPPORTED_LOCALES;
    // ... rest of middleware logic
  }
  ```
</CodeGroup>

### Step 3: Update Language Switcher

The language switcher will automatically include new languages:

```tsx theme={null}
// components/language-switcher.tsx
import { LOCALE_NAMES, SUPPORTED_LOCALES } from '@/lib/i18n';

export function LanguageSwitcher() {
  return (
    <select>
      {SUPPORTED_LOCALES.map(locale => (
        <option key={locale} value={locale}>
          {LOCALE_NAMES[locale]}
        </option>
      ))}
    </select>
  );
}
```

### Step 4: Test the Implementation

1. **Add test content** in the new language
2. **Navigate to** `/{locale}/` URLs (e.g., `/es/mcp-servers`)
3. **Verify translations** appear correctly
4. **Test language switching** functionality
5. **Check fallbacks** work for missing translations

## Translation Workflow

### For New Features

When adding new features to MetaMCP:

1. **Add English translations first** in appropriate namespace
2. **Use descriptive keys** that make sense in context
3. **Test with English** to ensure keys work correctly
4. **Add other languages** (or mark for translation)
5. **Test all languages** before deployment

### For Contributors

<AccordionGroup>
  <Accordion icon="translate" title="Translation Contributors">
    **To contribute translations:**

    1. Fork the repository
    2. Create new language files or update existing ones
    3. Follow the existing key structure
    4. Test your translations locally
    5. Submit a Pull Request with your changes

    **Tips:**

    * Keep translations concise but clear
    * Maintain consistent terminology
    * Consider cultural context, not just literal translation
    * Test with longer text to ensure UI still works
  </Accordion>

  <Accordion icon="robot" title="AI-Assisted Translation">
    **Using AI tools like Cursor/Claude:**

    ```prompt theme={null}
    Translate this English JSON file to Spanish, maintaining the same structure and keys:

    {
      "server": {
        "create": "Create Server",
        "edit": "Edit Server"
      }
    }

    Keep technical terms like "MCP" and "API" unchanged.
    ```
  </Accordion>
</AccordionGroup>

## Troubleshooting

### Common Issues

<AccordionGroup>
  <Accordion icon="warning" title="Missing Translations">
    **When translations don't appear:**

    1. Check the translation key exists in the JSON file
    2. Verify the namespace is correct (`common:save` vs `auth:save`)
    3. Ensure the locale file exists and is valid JSON
    4. Check browser console for missing key warnings
    5. Verify the component is using `useTranslations` correctly
  </Accordion>

  <Accordion icon="bug" title="Hydration Errors">
    **Server/client translation mismatches:**

    1. Ensure consistent locale detection between server and client
    2. Use the `isLoading` state from `useTranslations`
    3. Avoid rendering translations during SSR if locale might change
    4. Test with JavaScript disabled to check SSR behavior
  </Accordion>

  <Accordion icon="globe" title="Locale Routing Issues">
    **URL routing problems:**

    1. Check middleware configuration for new locales
    2. Verify `getLocalizedPath` function handles new languages
    3. Test direct navigation to localized URLs
    4. Ensure fallback behavior works correctly
  </Accordion>
</AccordionGroup>

### Debugging Tools

<CodeGroup>
  ```bash Development Debugging theme={null}
  # Check for missing translation keys
  grep -r "t('" apps/frontend/app --include="*.tsx" | \
    grep -v "useTranslations"

  # Validate JSON files
  for file in public/locales/*/*.json; do
    echo "Checking $file"
    cat "$file" | jq . > /dev/null
  done
  ```

  ```typescript Debug Component theme={null}
  "use client";

  import { useTranslations } from "@/hooks/useTranslations";

  export function TranslationDebugger() {
    const { t, locale, isLoading } = useTranslations();
    
    return (
      <div className="debug-panel">
        <p>Current locale: {locale}</p>
        <p>Is loading: {isLoading.toString()}</p>
        <p>Test translation: {t('common:save')}</p>
      </div>
    );
  }
  ```
</CodeGroup>

## Future Enhancements

### Planned Features

* **RTL language support** for Arabic, Hebrew
* **Date/time localization** with proper formatting
* **Number formatting** based on locale
* **Currency formatting** for pricing features
* **Pluralization rules** for complex language requirements

### Contributing Guidelines

<Card title="i18n Contributing Guidelines" icon="checklist">
  * 📝 **Add English first**: Always start with English translations
  * 🔍 **Test thoroughly**: Verify all locales work correctly
  * 📊 **Use consistent terminology**: Maintain glossary for technical terms
  * 🌍 **Consider context**: Adapt to cultural differences, not just language
  * 📱 **Test UI impact**: Ensure longer translations don't break layout
  * 🤝 **Collaborate**: Work with native speakers when possible
</Card>

## Next Steps

<CardGroup cols={2}>
  <Card title="Contributing Guide" icon="handshake" href="/en/development/contributing">
    Learn how to contribute to MetaMCP development
  </Card>

  <Card title="Frontend Development" icon="code" href="/en/development">
    Understand the frontend architecture and development setup
  </Card>

  <Card title="Component Development" icon="component" href="/en/development#frontend-development">
    Learn about UI component development with i18n
  </Card>

  <Card title="Testing Guide" icon="test" href="/en/development#testing">
    Test your internationalization changes
  </Card>
</CardGroup>
