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.
How to create scroll animations with Next.js App
admin08/04/2024

How to create scroll animations with Next.js App
A Beginner's Guide to Using AOS Library with Next.js application
Create Cognito User Pool with AWS CDK
admin09/06/2023

Create Cognito User Pool with AWS CDK
In the previous post, I showed you how to create a simple S3 bucket. Next, in this article, I will guide you to create a Cognito User Pool.
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.
Create S3 Bucket with AWS CDK
admin09/06/2023

Create S3 Bucket with AWS CDK
In this article, I introduce Amazon CDK and how to write AWS infrastructure-as-code using TypeScript. We will do it step by step.
Part 1: Build a Chat App with ReactJS + Material UI
admin13/09/2023

Part 1: Build a Chat App with ReactJS + Material UI
In this article, I would like to introduce using ReactJS and material UI to build a Chat App.
Đ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