Danh mụcThẻBài viết

admin

I'm a Full-stack developer

Thẻ

Linked List
Data Structure
Chat GPT
Design Pattern
Microservices
API
AWS CDK
ReactJS
AWS Lightsail
Flutter Mobile
Next.js 14 App Router Localization with next-intl
Ngày đăng: 07/07/2024

In this article, I will illustrate how to implement next-intl localization in a Next.js 14 application. 

Localization is a crucial feature for any application aiming to cater to a global audience, ensuring that users can interact with content in their preferred language.


Overview

  • Packages
  • How to install and configure next-intl?
  • Step 1: Create a fresh Next.js project.
  • Step 2: Install the next-intl package:
  • Step 3: Adding the locale route segment
  • Step 4: Adding the translation message files
  • Step 5: Setting up configuration files
  • Step 6: Create a localization middleware
  • Step 7: How to retrieve translated contents
  • Demo
  • Conclusion


Packages

  • typescript -> ver 5 -> Our programming language
  • next -> ver 14.2.4 -> The full-stack react framework
  • react -> ver 18 -> For building UI
  • next-intl -> ver 3.15.3 -> i18n lib
  • rtl-detect -> ver 1.1.2 -> For detecting right-to-left language
  • tailwindcss -> ver 3.4.1 -> For styling
  • mui/material -> ver 5.15.20 -> For building components


How to install and configure next-intl?

Step 1: Create a fresh Next.js project.

npx create-next-app i18n-next-app
cd i18n-next-app
yarn add next@latest


Step 2: Install the next-intl package:

yarn add next-intl


Step 3: Adding the locale route segment

*** First, we need to follow the documents about locale codes and dynamic route segments.

Next, the subdirectory called [locale] is created under src/app.

*** Note, the module import should be updated if needed.


Step 4: Adding the translation message files

First, create a new directory called locales under src

In this tutorial, we are supporting en-us (English USA) and vi (Vietnamese).



Continue, add the content for translation files

// src/locales/en-us/about.ts

export default {
  title: 'Title',
  description: 'Description',
} as const;


// src/locales/vi/about.ts

export default {
  title: 'Tiêu đề',
  description: 'Miêu tả',
} as const;


// src/locales/vi/index.ts
// src/locales/vi/index.ts

import about from './about';
export default { about };


Step 5: Setting up configuration files

// next.config.mjs

import createNextIntlPlugin from "next-intl/plugin";
const withNextIntl = createNextIntlPlugin();

/** @type {import('next').NextConfig} */
const nextConfig = {};

export default withNextIntl(nextConfig);


Create a new file called i18n.config.ts

import { createSharedPathnamesNavigation } from 'next-intl/navigation';

export const locales = ['en-us', 'vi'] as const;
export type Locale = (typeof locales)[number];

export const localeNames: Record<Locale, string> = {
  'en-us': 'Tiếng anh',
  vi: 'Vietnamese',
};

export const { Link, usePathname, useRouter } = createSharedPathnamesNavigation({ locales });


The next-intl uses the i18n.ts file to load translations.

// src/global.d.ts

type Messages = (typeof import('./locales/en-us'))['default'];

declare interface IntlMessages extends Messages {}


// src/i18n.ts

import { getRequestConfig } from 'next-intl/server';
import { notFound } from 'next/navigation';

import { type Locale, locales } from ' ./i18n.config';

export default getRequestConfig(async ({ locale }) => {
  if (!locales.includes(locale as Locale)) {
    return notFound();
  }

  const messages = await import(`./locales/${locale}/index.ts`);

  return {
    messages: messages.default,
  };
});


Step 6: Create a localization middleware

// src/middlewares/with-localization.ts

import createMiddleware from 'next-intl/middleware';
import { NextMiddleware } from 'next/server';

import { locales } from '../i18n.config';
import { MiddlewareFactory } from './types';

export const withLocalization: MiddlewareFactory = (next: NextMiddleware) =>
  createMiddleware({
    defaultLocale: 'vi',
    locales,
    localeDetection: false,
  });


// src/middleware.ts

import { stackMiddlewares } from './middlewares/stack-middlewares';
import { withLocalization } from './middlewares/with-localization';

export default stackMiddlewares([
  withLocalization,
]);

export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};


Step 7: How to retrieve translated contents

// src/hooks/useTextDirection.ts

import { useLocale } from 'next-intl';
import { isRtlLang } from 'rtl-detect';

export type TextDirection = 'ltr' | 'rtl';

export default function useTextDirection(): TextDirection {
  const locale = useLocale();

  return isRtlLang(locale) ? 'rtl' : 'ltr';
}


// src/[locale]/layout.tsx

import { Metadata, Viewport } from 'next';
import { NextIntlClientProvider, useMessages } from 'next-intl';
import { unstable_setRequestLocale } from 'next-intl/server';

import { locales } from './src/i18n.config';

import useTextDirection from '@/hooks/useTextDirection';
import './globals.css';

export async function generateMetadata(): Promise<Metadata> {
  return {
    title: {
      default: site.header,
      template: `${site.header} | %s`,
    },
  };
}

export function generateStaticParams() {
  return locales.map((locale) => ({ locale }));
}

export default function RootLayout({
  children,
  params: { locale },
}: Readonly<{
  children: React.ReactNode;
  params: { locale: string };
}>) {
  unstable_setRequestLocale(locale);
  const dir = useTextDirection();
  const messages = useMessages();

  return (
    <html lang={locale} dir={dir} className={combineClasses([roboto.className])}>
      <head></head>
      <body>
        <NextIntlClientProvider messages={messages}>
          {children}
        </NextIntlClientProvider>
      </body>
    </html>
  );
}


// src/app/[locale]/about.page.tsx

import { getTranslations } from 'next-intl/server';

export async function generateMetadata({
  params: { locale },
}: {
  params: { locale: string };
}): Promise<Metadata> {
  const t = await getTranslations({
    locale,
  });

  return {
    title: t('about.title'),
  };
}

export default async function About({ params: { locale } }: { params: { locale: string } }) {
  const t = useTranslations('about');

  return (
    <Layout>
      {t('description')}
    </Layout>
  );
}


Demo

Vietnamese: https://www.dinhthanhcong.info/vi/about




English: https://dinhthanhcong.info/en-us/about



Conclusion

By following these guidelines, you can build a Next.js 14 application that meets the technical requirements of localization and delivers a superior user experience for a diverse audience. 


Good luck to you, I hope this post is of value to you!!!!


Reference Documents:

  1. https://saimana.com/list-of-country-locale-code/
  2. https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes
  3. https://next-intl-docs.vercel.app/docs/getting-started/app-router/without-i18n-routing
Đề xuất

TypeScript Design Pattern - Prototype
admin07/08/2023

TypeScript Design Pattern - Prototype
The prototype pattern is one of the Creational pattern groups. The responsibility is to create a new object through clone the existing object instead of using the new key. The new object is the same as the original object, and we can change its property does not impact the original object.
TypeScript Design Pattern - Builder
admin07/08/2023

TypeScript Design Pattern - Builder
TypeScript Design Pattern - Builder
Data structure: Doubly Linked List
admin07/04/2024

Data structure: Doubly Linked List
In this article, I would like to show you about Data structure - Doubly Linked List
Mới nhất

TypeScript Design Pattern - Proxy
admin11/08/2023

TypeScript Design Pattern - Proxy
Provide a surrogate or placeholder for another object to control access to it.
TypeScript Design Pattern - Adapter
admin08/08/2023

TypeScript Design Pattern - Adapter
This design pattern acts as a bridge between two different interfaces.
Create Project with Express + TypeScript + ESLint + Auto Reload
admin12/06/2023

Create Project with Express + TypeScript + ESLint + Auto Reload
In this article, I introduce to you how to initialize an Express + TypeScript project.
Đinh Thành Công Blog

My website, where I write blogs on a variety of topics and where I have some experiments with new technologies.

hotlinelinkedinskypezalofacebook
DMCA.com Protection Status
Góp ý
Họ & Tên
Số điện thoại
Email
Nội dung
Tải ứng dụng
hotline

copyright © 2023 - AGAPIFA

Privacy
Term
About