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:
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
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));
  }
}

Using Translations

Client Components

For client-side components, use the useTranslations hook:
"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>
  );
}

Translation Key Format

Use colon-separated namespaces for organization:
{
  "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:

Best Practices for Translation Keys

Translation Key Guidelines

  • 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}}!"

Adding New Languages

Step 1: Create Translation Files

  1. Create language directory in public/locales/:
    mkdir -p public/locales/es  # For Spanish
    
  2. Copy English files as templates:
    cp -r public/locales/en/* public/locales/es/
    
  3. Translate the content in each JSON file:
    // 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:
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'
};

Step 3: Update Language Switcher

The language switcher will automatically include new languages:
// 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

Troubleshooting

Common Issues

Debugging Tools

# 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

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

i18n Contributing Guidelines

  • 📝 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

Next Steps