Menu

Using Internationalization

Nexty.dev uses the next-intl library to implement complete multilingual support, providing a flexible internationalization solution that includes route-level language switching, automatic language detection, and other features.

Through this documentation, you will learn the basic usage of next-intl, methods for extending new languages and translation content, and the advanced multilingual features supported by Nexty.dev.

File Structure

i18n/
├── messages/                # Translation files directory
│   ├── en/                  # English translations
│   │   └── common.json
│   ├── zh/                  # Chinese translations
│   │   └── common.json
│   └── ja/                  # Japanese translations
│       └── common.json
├── request.ts               # next-intl request configuration
└── routing.ts               # Route and language configuration
 
components/
├── LocaleSwitcher.tsx       # Language switcher component
└── LanguageDetectionAlert.tsx  # Language detection alert component
 
stores/
└── localeStore.ts           # Language state management
 
middleware.ts                # Middleware configuration
next.config.mjs              # Next.js configuration

Basic Usage

Using Translations in Components

In frontend components, use useLocale to get the current language and useTranslations to get translation content.

import { useLocale, useTranslations } from 'next-intl';
 
export default function MyComponent() {
  const locale = useLocale();
  const t = useTranslations('Home');
  
  return (
    <div>
      <h1>{t('title')}</h1>
      <p>{t('description')}</p>
    </div>
  );
}

Using in Server Components

In server components, use getLocale to get the current language and getTranslations to get translation content.

import { getLocale, getTranslations } from 'next-intl/server';
 
export default async function ServerComponent() {
  const locale = await getLocale();
  const t = await getTranslations('Home');
  
  return (
    <div>
      <h1>{t('title')}</h1>
    </div>
  );
}

Good to know

If server components are not using async, you can also use useLocale and useTranslations, and next-intl will handle this automatically.

Using Translations with Parameters

In JSON file:

{
  "welcome": "Welcome, {name}!",
  "countdown": "Closing in {countdown} seconds"
}

In component:

const message = t('welcome', { name: 'John' });
const timer = t('countdown', { countdown: countdown.toString() });

Using Raw Data

For complex data structures (like arrays, objects), use t.raw():

const headerLinks = t.raw('Header.links') as HeaderLink[];
const features = t.raw('Landing.Features.items');

Use the Link component exposed by @/i18n/routing. You don't need to write language prefixes in href, as next-intl will automatically handle them based on the current language.

import { Link as I18nLink } from '@/i18n/routing';
 
<I18nLink href="/about">
  {t('aboutUs')}
</I18nLink>

Internationalized useRouter

Use the useRouter component exposed by @/i18n/routing. Similarly, you don't need to write language prefixes, as next-intl will automatically handle them based on the current language.

import { useRouter } from '@/i18n/routing';
 
const router = useRouter();
 
const handleClick = () => {
  router.push('/dashboard');
};

Steps to Add New Languages

Step 1. Modify Language Configuration

Add the new language in i18n/routing.ts:

export const LOCALES = ['en', 'zh', 'ja', 'ko'] // Add Korean
export const DEFAULT_LOCALE = 'en'
export const LOCALE_NAMES: Record<string, string> = {
  'en': "English",
  'zh': "中文", 
  'ja': "日本語",
  'ko': "한국어", // Add Korean display name
};

Step 2. Create Translation Files

Create new language directory and translation files:

mkdir i18n/messages/ko
cp i18n/messages/en/common.json i18n/messages/ko/common.json

Step 3. Translate Content

Edit i18n/messages/ko/common.json and translate all English content to Korean.

Step 4. Update Route Redirects (Optional)

If needed, add corresponding redirect rules in next.config.mjs:

{
  source: "/ko/dashboard", 
  destination: "/ko/dashboard/settings",
  permanent: true,
}

Multi-file Translation Architecture

When there's a lot of translation content, it's recommended to split translation files into multiple modules:

Create Modular File Structure

i18n/messages/en/
├── common.json          # Common translations
├── Landing.json         # Authentication related
├── Dashboard.json       # Dashboard
└── Blog.json            # Blog

Modify request.ts Configuration

import { getRequestConfig } from 'next-intl/server';
import { routing } from './routing';
 
export default getRequestConfig(async ({ requestLocale }) => {
  let locale = await requestLocale;
 
  if (!locale || !routing.locales.includes(locale as any)) {
    locale = routing.defaultLocale;
  }
 
  // Dynamically import all translation files
  const common = (await import(`./messages/${locale}/common.json`)).default;
  const Landing = (await import(`./messages/${locale}/Landing.json`)).default;
  const Dashboard = (await import(`./messages/${locale}/Dashboard.json`)).default;
  const Blog = (await import(`./messages/${locale}/Blog.json`)).default;
 
  return {
    locale,
    messages: {
      ...common,
      Landing,
      Dashboard,
      Blog,
    }
  };
});

Using Namespaces

// Use specific namespace
const t = useTranslations('Dashboard.User.Settings');
const tLanding = useTranslations('Landing');
const tBlog = useTranslations('Blog');

File Organization Recommendations

// common.json - Site-wide common
{
  "header": {...},
  "footer": {...},
  "common": {...}
}
 
// Landing.json - Landing page
{
  "login": {...},
  "register": {...},
  "forgotPassword": {...}
}
 
// Dashboard.json - Dashboard module  
{
  "sidebar": {...},
  "settings": {...},
  "profile": {...}
}

Advanced Features of Nexty.dev

Language Detection and Alerts

The system automatically detects the browser language when users first visit. If it doesn't match the current website language, a switching prompt will be displayed:

  • 10-second countdown with automatic close
  • Users can manually close
  • Closed state is saved for 30 days (via Cookie)

Within the Cookie validity period, when visiting the website again, the language will automatically switch.

SEO Optimization

Each language version generates independent URLs and metadata:

import { constructMetadata } from "@/lib/metadata";
 
export async function generateMetadata({ params }: MetadataProps): Promise<Metadata> {
  const { locale } = await params;
  const t = await getTranslations({ locale, namespace: "Home" });
 
  return constructMetadata({
    page: "Home",
    title: t("title"),
    description: t("description"),
    locale: locale as Locale,
    path: `/`,
  });
}