Frontend
15 min read

Migrate from Next-Intl to Clocale: A Complete Guide with Import Feature

Learn how to seamlessly migrate your Next.js application from next-intl to Clocale, including how to import your existing next-intl JSON files and leverage Clocale's powerful localization management features.

Next.jsLocalizationClocalenext-intlMigrationi18n
Suzuki Ren
1/27/2025

Migrate from Next-Intl to Clocale: A Complete Guide

If you're currently using next-intl in your Next.js application and want to migrate to Clocale for better localization management, this guide will walk you through the entire process. Clocale offers a powerful import feature that allows you to seamlessly import your existing next-intl JSON files, making the migration process smooth and efficient.

Why Migrate to Clocale?

Before diving into the migration process, let's understand why Clocale might be a better choice for your localization needs:

  • Centralized Management: All translations are managed in one place with a user-friendly interface
  • Real-time Updates: Changes to translations are reflected immediately without redeployment
  • Team Collaboration: Non-technical team members can manage translations without touching code
  • Import Feature: Seamlessly import existing next-intl JSON files
  • Advanced Features: Namespace management, translation progress tracking, and more

Prerequisites

Before starting the migration, ensure you have:

  • An existing Next.js project with next-intl
  • Your current translation JSON files
  • A Clocale account (sign up at clocale.com)

Step 1: Understanding Your Current Setup

Let's first examine a typical next-intl setup. Your current project likely has a structure like this:

src/
├── i18n/
│   ├── locales/
│   │   ├── en/
│   │   │   └── common.json
│   │   ├── np/
│   │   │   └── common.json
│   │   └── ja/
│   │       └── common.json
│   ├── config.ts
│   └── request.ts
├── app/
│   └── layout.tsx
└── next.config.ts

Example: Current next-intl Configuration

next.config.ts:

import { NextConfig } from "next/types";

import createNextIntlPlugin from "next-intl/plugin";

const withNextIntl = createNextIntlPlugin();

const nextConfig: NextConfig = {
  // your config
};

export default withNextIntl(nextConfig);

src/i18n/request.ts:

import { getRequestConfig } from "next-intl/server";

import { getCookie } from "@/actions/cookies";

export default getRequestConfig(async () => {
  let locale = await getCookie("language");
  if (!locale) {
    locale = "en";
  }
  const messages = {
    ...(await import(`./locales/${locale}/common.json`)).default,
  };

  return {
    locale,
    messages,
  };
});

src/app/layout.tsx:

import { NextIntlClientProvider } from "next-intl";
import { getLocale, getMessages } from "next-intl/server";

export default async function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  const locale = await getLocale();
  const messages = await getMessages();

  return (
    <html lang={locale}>
      <body>
        <NextIntlClientProvider messages={messages}>
          {children}
        </NextIntlClientProvider>
      </body>
    </html>
  );
}

Step 2: Setting Up Clocale

2.1 Install Clocale Dependencies

First, install Clocale:

# Install Clocale
npm install @clocale/react

2.2 Create Your Clocale Project

  1. Sign up/login to your Clocale account
  2. Create a new project
  3. Add the languages you want to support (e.g., English, Japanese, Nepali)
  4. Note down your project's integration URL from the developer settings

2.3 Environment Configuration

Create or update your .env.local file:

CLOCALE_API_URL=https://api.clocale.com/YOUR-PROJECT-ID

Replace YOUR-PROJECT-ID with your actual Clocale project ID.

Step 3: Import Your Existing Translations

This is where Clocale's powerful import feature comes into play. You can import your existing next-intl JSON files directly into Clocale.

3.1 Prepare Your JSON Files

Your current next-intl JSON files should look something like this:

src/i18n/locales/en/common.json:

{
  "home_page": {
    "title": "Home",
    "hero_main": "Making Translation Effortless and Accessible",
    "description": "Make your website or app available in multiple languages without the technical hassle.",
    "get_started": "Get Started"
  },
  "login_page": {
    "title": "Welcome back",
    "email": "Email",
    "password": "Password",
    "login": "Sign in",
    "forgot_password": "Forgot password?"
  },
  "navbar": {
    "feature": "Features",
    "pricing": "Pricing",
    "blog": "Blog",
    "login": "Login",
    "signup": "Signup"
  }
}

src/i18n/locales/ja/common.json:

{
  "home_page": {
    "title": "ホーム",
    "hero_main": "翻訳をもっと簡単で身近に",
    "description": "技術的な手間なく、あなたのウェブサイトやアプリを複数の言語で利用可能にしましょう。私たちのサービスは翻訳を保存・管理し、開発者の時間を無駄にせず、あなたのコンテンツを世界中に届けます。",
    "get_started": "始める"
  },
  "login_page": {
    "title": "おかえり",
    "email": "メール",
    "password": "パスワード",
    "login": "サインイン",
    "forgot_password": "パスワードを忘れましたか?"
  },
  "navbar": {
    "feature": "特徴",
    "pricing": "価格設定",
    "blog": "ブログ",
    "login": "サインイン",
    "signup": "サインアップ"
  }
}

3.2 Import via Clocale Dashboard

  1. Go to your Clocale project dashboard
  2. Navigate to the "Import" section
  3. Click "Select Files" and choose your JSON files
  4. For each file, select:
    • Language: The language of the file (e.g., English, Japanese, Nepali)
    • Namespace: The namespace (e.g., "common")
  5. Click "Import" to upload your translations

The import interface allows you to easily upload your existing next-intl JSON files:

Step 4: Configure Clocale in Your Next.js App

4.1 Update Next.js Configuration

Remove the next-intl plugin from your next.config.ts:

import { NextConfig } from "next/types";

const nextConfig: NextConfig = {
  // your config without next-intl plugin
};

export default nextConfig;

4.2 Create Clocale Provider

Create a new file src/lib/clocale-provider.tsx:

'use client';

import { ClocaleProvider, SSRTranslations } from '@clocale/react';

interface ClocaleTranslationProviderProps {
  locale: string;
  children: React.ReactNode;
  ssrTranslations: SSRTranslations;
  isDev: boolean;
}

export const ClocaleTranslationProvider = ({
  children,
  locale,
  ssrTranslations,
  isDev,
}: ClocaleTranslationProviderProps) => {
  return (
    <ClocaleProvider
      type="server"
      locale={locale}
      ssrTranslations={ssrTranslations}
      isDev={isDev}
    >
      {children}
    </ClocaleProvider>
  );
};

4.3 Create Locale Management Utilities

Create src/lib/locale.ts:

"use server";

import { cookies } from "next/headers";

const COOKIE_NAME = "language";

export const getLocale = async () => {
  const cookieStore = await cookies();
  return cookieStore.get(COOKIE_NAME)?.value ?? "en";
};

export const setLocale = async (locale: string) => {
  const cookieStore = await cookies();
  cookieStore.set(COOKIE_NAME, locale);
};

4.4 Create Clocale Client Configuration

Create src/lib/clocale-client.ts:

import { ClocaleNext, createServerClient } from "@clocale/react/next";

import { getLocale } from "./locale";

export const { getTranslation, getClocaleClient } = createServerClient({
  getLocale,
  builder: async (locale) =>
    ClocaleNext().init({
      locale,
      baseUrl: process.env.Clocale_API_URL!,
    }),
});

4.5 Update Root Layout

Replace your src/app/layout.tsx:

import type { Metadata } from "next";
import { Roboto, Roboto_Slab } from "next/font/google";
import { NuqsAdapter } from "nuqs/adapters/next/app";
import { Toaster } from "sonner";

import { ClocaleTranslationProvider } from "@/lib/clocale-provider";
import { getLocale } from "@/lib/locale";
import { getClocaleClient } from "@/lib/clocale-client";
import LanguageFloat from "@/components/language-float";
import QueryProvider from "@/lib/tanstack-query/provider";

import "./globals.css";

const robotoSlab = Roboto_Slab({
  weight: ["100", "200", "300", "400", "500", "600", "700", "800", "900"],
  subsets: ["latin"],
  variable: "--font-roboto-slab",
});

const roboto = Roboto({
  weight: ["100", "200", "300", "400", "500", "600", "700", "800", "900"],
  subsets: ["latin"],
  variable: "--font-roboto",
});

export const metadata: Metadata = {
  title: "Clocale",
  description: "Generated by create next app",
};

export default async function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  const locale = await getLocale();
  const clocale = await getClocaleClient();

  // Fetch translations for all namespaces used in your project
  const translations = await clocale.fetchTranslations(['common']);

  return (
    <html
      translate="no"
      lang={locale}
      className={`${roboto.variable} ${robotoSlab.variable} antialiased`}
      suppressHydrationWarning
    >
      <body>
        <ClocaleTranslationProvider
          locale={locale}
          ssrTranslations={translations}
          isDev={process.env.NODE_ENV === 'development'}
        >
          <NuqsAdapter>
            <QueryProvider>
              {children}
              <LanguageFloat />
            </QueryProvider>
          </NuqsAdapter>
        </ClocaleTranslationProvider>
        <Toaster richColors />
      </body>
    </html>
  );
}

Step 5: Update Your Components

5.1 Server Components

Replace getTranslations from next-intl with Clocale's getTranslation:

// Before (next-intl)
import { getTranslations } from "next-intl/server";

export default async function Home() {
  const t = await getTranslations("common.home_page");

  return (
    <div>
      <h1>{t("title")}</h1>
      <p>{t("description")}</p>
    </div>
  );
}

// After (Clocale)
import { getTranslation } from "@/lib/clocale-client";

export default async function Home() {
  const t = await getTranslation("common.home_page");

  return (
    <div>
      <h1>{t("title")}</h1>
      <p>{t("description")}</p>
    </div>
  );
}

5.2 Client Components

Replace useTranslations from next-intl with Clocale's useTranslation:

// Before (next-intl)
"use client";
import { useTranslations } from "next-intl";

export default function Navbar() {
  const t = useTranslations("common.navbar");

  return (
    <nav>
      <a href="/features">{t("feature")}</a>
      <a href="/pricing">{t("pricing")}</a>
      <a href="/blog">{t("blog")}</a>
    </nav>
  );
}

// After (Clocale)
"use client";
import { useTranslation } from "@clocale/react";

export default function Navbar() {
  const t = useTranslation("common.navbar");

  return (
    <nav>
      <a href="/features">{t("feature")}</a>
      <a href="/pricing">{t("pricing")}</a>
      <a href="/blog">{t("blog")}</a>
    </nav>
  );
}

Step 6: Language Switching

Update your language switcher component:

"use client";
import { useTranslation } from "@clocale/react";
import { setLocale } from "@/lib/locale";

export default function LanguageSwitcher() {
  const { locale, setLocale: setLocaleClient } = useTranslation();

  const handleLanguageChange = async (newLocale: string) => {
    await setLocale(newLocale); // Update server-side cookie
    setLocaleClient(newLocale); // Update client-side state
    window.location.reload(); // Reload to apply new locale
  };

  return (
    <div>
      <button onClick={() => handleLanguageChange("en")}>English</button>
      <button onClick={() => handleLanguageChange("ja")}>日本語</button>
      <button onClick={() => handleLanguageChange("np")}>नेपाली</button>
    </div>
  );
}

Step 7: Clean Up

After successful migration, you can remove the old next-intl files:

# Remove old i18n directory
rm -rf src/i18n

Step 8: Verify the Migration

  1. Test all pages to ensure translations are working correctly
  2. Check language switching functionality
  3. Verify that new translations can be added through the Clocale dashboard
  4. Test the import feature by adding new translations

Advanced Features

Namespace Management

Clocale supports multiple namespaces for better organization:

// Create different namespaces for different features
const translations = await clocale.fetchTranslations([
  "common",
  "auth",
  "dashboard",
]);

// Use in components
const t = useTranslation("auth.login_page");
const dashboardT = useTranslation("dashboard.overview");

Translation Progress Tracking

Monitor your translation completion in the Clocale dashboard:

  • View completion percentages by language
  • Identify missing translations
  • Track translation updates

Real-time Updates

With Clocale, you can update translations without redeploying your application:

  1. Make changes in the Clocale dashboard
  2. Changes are immediately available to your users
  3. No need to rebuild and redeploy

Troubleshooting

Common Issues

  1. Translations not loading: Check your CLOCALE_API_URL environment variable
  2. Language switching not working: Ensure both server and client locale updates are implemented
  3. Import failures: Verify JSON structure matches Clocale's expected format

Debug Mode

Enable debug mode during development:

<ClocaleTranslationProvider
  locale={locale}
  ssrTranslations={translations}
  isDev={true} // Enable debug mode
>

Conclusion

Migrating from next-intl to Clocale opens up a world of possibilities for managing your application's localization. The import feature makes the transition seamless, allowing you to preserve all your existing translations while gaining access to powerful new features.

Key benefits of the migration:

  • Seamless import of existing next-intl JSON files
  • Centralized translation management through web interface
  • Real-time updates In-Context editing
  • Advanced features like namespace management and progress tracking

The migration process is straightforward and the import feature ensures you don't lose any of your existing work. Once migrated, you'll have a much more powerful and user-friendly localization system that scales with your application's needs.

Start your migration today and experience the difference that Clocale can make in your localization workflow!