Chameleon

Internationalization

Multi-language support with next-intl

Internationalization

Chameleon supports multiple languages using next-intl for internationalization and localization.

Overview

The internationalization system provides English and Chinese language support with automatic locale detection, dynamic language switching, and comprehensive translation management. The system uses next-intl for message formatting, date/time localization, and number formatting.

Setup

Environment Configuration

# Supported locales
NEXT_PUBLIC_LOCALES="en,zh"

# Default locale
NEXT_PUBLIC_DEFAULT_LOCALE="en"

Locale Configuration

// src/i18n/locale.ts
export const locales = ["en", "zh"] as const;
export const defaultLocale = "en" as const;
export type Locale = (typeof locales)[number];

Usage

Basic Translation

// In components
import { useTranslations } from "next-intl";

export function MyComponent() {
  const t = useTranslations("common");
  
  return (
    <div>
      <h1>{t("title")}</h1>
      <p>{t("description")}</p>
    </div>
  );
}

Server Components

// In server components
import { getTranslations } from "next-intl/server";

export default async function Page() {
  const t = await getTranslations("page");
  
  return (
    <div>
      <h1>{t("title")}</h1>
    </div>
  );
}

Dynamic Messages

// With parameters
const t = useTranslations("user");

return (
  <div>
    <p>{t("welcome", { name: user.name })}</p>
    <p>{t("credits", { count: user.credits })}</p>
  </div>
);

Date and Number Formatting

import { useFormatter } from "next-intl";

export function FormattedContent() {
  const format = useFormatter();
  
  return (
    <div>
      <p>{format.dateTime(new Date(), "short")}</p>
      <p>{format.number(1234.56, "currency")}</p>
    </div>
  );
}

File Structure

Translation Files

src/i18n/
├── messages/
│   ├── en.json          # English translations
│   └── zh.json          # Chinese translations
├── pages/
│   ├── landing/
│   │   ├── en.json      # Landing page translations
│   │   └── zh.json
│   ├── pricing/
│   │   ├── en.json      # Pricing page translations
│   │   └── zh.json
│   └── admin/
│       ├── en.json      # Admin page translations
│       └── zh.json
└── locale.ts            # Locale configuration

Translation File Example

// src/i18n/messages/en.json
{
  "common": {
    "title": "Welcome to Chameleon",
    "description": "AI-powered content generation",
    "loading": "Loading...",
    "error": "An error occurred"
  },
  "navigation": {
    "home": "Home",
    "pricing": "Pricing",
    "dashboard": "Dashboard"
  }
}
// src/i18n/messages/zh.json
{
  "common": {
    "title": "欢迎使用 Chameleon",
    "description": "AI 驱动的内容生成",
    "loading": "加载中...",
    "error": "发生错误"
  },
  "navigation": {
    "home": "首页",
    "pricing": "价格",
    "dashboard": "控制台"
  }
}

Language Switching

Language Switcher Component

// src/components/language-switcher.tsx
import { useLocale } from "next-intl";
import { useRouter, usePathname } from "next/navigation";

export function LanguageSwitcher() {
  const locale = useLocale();
  const router = useRouter();
  const pathname = usePathname();
  
  const switchLanguage = (newLocale: string) => {
    const newPath = pathname.replace(`/${locale}`, `/${newLocale}`);
    router.push(newPath);
  };
  
  return (
    <select value={locale} onChange={(e) => switchLanguage(e.target.value)}>
      <option value="en">English</option>
      <option value="zh">中文</option>
    </select>
  );
}

URL Structure

/en/                    # English homepage
/zh/                    # Chinese homepage
/en/pricing            # English pricing page
/zh/pricing            # Chinese pricing page
/en/admin              # English admin panel
/zh/admin              # Chinese admin panel

File Locations

  • src/i18n/locale.ts - Locale configuration
  • src/i18n/messages/ - Global translation files
  • src/i18n/pages/ - Page-specific translations
  • src/middleware.ts - Locale routing middleware
  • src/app/[locale]/ - Localized app routes

Common Tasks

Add New Translation

  1. Add key to English file (src/i18n/messages/en.json)
  2. Add translation to Chinese file (src/i18n/messages/zh.json)
  3. Use in component with useTranslations

Add New Language

  1. Add locale to src/i18n/locale.ts
  2. Create translation files for new language
  3. Update language switcher component
  4. Test all pages in new language

Page-Specific Translations

// src/i18n/pages/landing/en.json
{
  "hero": {
    "title": "Generate AI Content",
    "subtitle": "Create amazing content with AI"
  }
}

// In landing page component
const t = useTranslations("landing.hero");
return <h1>{t("title")}</h1>;

Dynamic Content Translation

// For database content
const getLocalizedContent = (content: any, locale: string) => {
  return content[locale] || content.en || content;
};

Troubleshooting

Translation not showing

Problem: Text shows translation key instead of translated text

Solution:

  1. Check translation key exists in JSON files
  2. Verify namespace is correct in useTranslations
  3. Check locale is properly set
  4. Clear browser cache

Language not switching

Problem: Language switcher not working

Solution:

  1. Check middleware is properly configured
  2. Verify locale routing is working
  3. Check URL structure matches expected format
  4. Ensure translation files exist for all locales

Missing translations

Problem: Some text not translated

Solution:

  1. Add missing keys to translation files
  2. Check for typos in translation keys
  3. Verify namespace structure
  4. Test with different locales

Next Steps