Tổng hợp ví dụ của chính next-intl triển khai với pages, app (ok)
Nghiên cứu dự án mẫu trong next-intl
— 1. example-pages-router

messages\en.json
{
"Index": {
"title": "Home",
"description": "This is the home page."
},
"LocaleSwitcher": {
"switchLocale": "Switch to {locale, select, vi {Vietnam} en {English} other {Unknown}}"
},
"PageLayout": {
"pageTitle": "Next Intl En"
}
}
messages\vi.json
{
"Index": {
"title": "Trang chủ",
"description": "Đây là trang chủ"
},
"LocaleSwitcher": {
"switchLocale": "Chuyển sang {locale, select, vi {Vietnam} en {English} other {Unknown}}"
},
"PageLayout": {
"pageTitle": "Next Intl Vi"
}
}
next.config.ts
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
i18n: {
locales: ['en', 'vi'],
defaultLocale: 'en'
},
reactStrictMode: true
};
export default nextConfig;
src\pages\index.tsx
import {GetStaticPropsContext} from 'next';
import {useTranslations} from 'next-intl';
import LocaleSwitcher from '@/pages/components/LocaleSwitcher';
import PageLayout from '@/pages/components/PageLayout';
export default function Home() {
const t = useTranslations('Index');
return (
<PageLayout title={t('title')}>
<p>{t('description')}</p>
<LocaleSwitcher />
</PageLayout>
);
}
export async function getStaticProps({locale}: GetStaticPropsContext) {
return {
props: {
messages: (await import(`../../messages/${locale}.json`)).default
}
};
}
src\pages\_app.tsx
import "@/styles/globals.css";
import type { AppProps } from "next/app";
import {useRouter} from 'next/router';
import {NextIntlClientProvider} from 'next-intl';
export default function App({ Component, pageProps }: AppProps) {
const router = useRouter();
return (
<NextIntlClientProvider
locale={router.locale}
messages={pageProps.messages}
timeZone="Europe/Vienna"
>
<Component {...pageProps} />;
</NextIntlClientProvider>
)
}
src\pages\components\LocaleSwitcher.tsx
import Link from 'next/link';
import { useRouter } from 'next/router';
import { useTranslations } from 'next-intl';
export default function LocaleSwitcher() {
const t = useTranslations('LocaleSwitcher');
const { locale, locales, route } = useRouter();
const otherLocale = locales?.find((cur) => cur !== locale) as string;
return (
<Link href={route} locale={otherLocale}>
{t('switchLocale', { locale: otherLocale })}
</Link>
)
}
src\pages\components\PageLayout.tsx
import Head from 'next/head';
import { useTranslations } from 'next-intl';
import { ReactNode } from 'react';
type Props = {
children?: ReactNode;
title: string;
};
export default function PageLayout({ children, title }: Props) {
const t = useTranslations('PageLayout')
return (
<>
<Head>
<title>{[title, t('pageTitle')].join(' - ')}</title>
</Head>
<div className="container m-auto">
<h1>{title}</h1>
{children}
</div>
</>
)
}
pages\index.tsx
import messages from '../messages/en.json';
export default function Home() {
console.log(typeof messages);
return (
<div>
Home
</div>
);
}
Kết quả: console.log(typeof messages); object
— 2. example-pages-router-advanced


messages\en.json
{
"Index": {
"title": "Home",
"description": "<p>Only the minimum of <code>{locale}</code> messages are loaded to render this page.</p><p>These namespaces are available:</p>"
},
"LocaleSwitcher": {
"switchLocale": "Switch to {locale, select, vi {Vietnam} en {English} other {Unknown}}"
},
"PageLayout": {
"pageTitle": "Next Intl En"
},
"About": {
"title": "About",
"lastUpdated": "This example was updated {lastUpdatedRelative} ({lastUpdated, date, short})."
},
"Navigation": {
"index": "Home",
"about": "About",
"switchLocale": "Switch to {locale, select, de {German} en {English} other {Unknown}}"
},
"NotFound": {
"title": "Sorry, this page could not be found."
},
"StrictTypes": {
"nested": {
"hello": "Hello",
"another": {
"level": "Level"
}
}
}
}
messages\vi.json
{
"Index": {
"title": "Trang chủ",
"description": "<p>Chỉ có tối thiểu <code>{locale}</code> tin nhắn được tải để hiển thị trang này.</p><p>Các không gian tên sau đây khả dụng:</p>"
},
"LocaleSwitcher": {
"switchLocale": "Chuyển sang {locale, select, vi {Vietnam} en {English} other {Unknown}}"
},
"About": {
"title": "About",
"lastUpdated": "Ví dụ này đã được cập nhật {lastUpdatedRelative} ({lastUpdated, date, short})."
},
"PageLayout": {
"pageTitle": "Next Intl Vi"
},
"Navigation": {
"index": "Trang chủ",
"about": "Chúng tôi",
"switchLocale": "Chuyển đến {locale, select, vi {Việt Nam} en {English} other {Unknown}}"
},
"NotFound": {
"title": "Xin lỗi trang không được tìm thấy"
},
"StrictTypes": {
"nested": {
"hello": "Xin chào",
"another": {
"level": "Cấp độ"
}
}
}
}
src\pages\components\Code.tsx
import {ReactNode} from 'react';
type Props = {
children: ReactNode;
};
export default function Code({children}: Props) {
return (
<code style={{background: 'red', padding: 4, borderRadius: 4}}>
{children}
</code>
);
}
src\pages\components\LocaleSwitcher.tsx
import Link from 'next/link';
import { useRouter } from 'next/router';
import { useTranslations } from 'next-intl';
export default function LocaleSwitcher() {
const t = useTranslations('LocaleSwitcher');
const { locale, locales, route } = useRouter();
const otherLocale = locales?.find((cur) => cur !== locale) as string;
return (
<Link href={route} locale={otherLocale}>
{t('switchLocale', { locale: otherLocale })}
</Link>
)
}
src\pages\components\Navigation.tsx
import Link from 'next/link';
import {useRouter} from 'next/router';
import {useTranslations} from 'next-intl';
export default function Navigation() {
const t = useTranslations('Navigation');
const {locale, locales, route} = useRouter();
const otherLocale = locales?.find((cur) => cur !== locale) as string;
return (
<div style={{display: 'flex', justifyContent: 'space-between'}}>
<div style={{display: 'flex', gap: 10}}>
<Link href="/">{t('index')}</Link>
<Link href="/about">{t('about')}</Link>
</div>
<Link href={route} locale={otherLocale}>
{t('switchLocale', {locale: otherLocale})}
</Link>
</div>
);
}
Navigation.messages = ['Navigation'];
src\pages\components\PageLayout.tsx
import Head from 'next/head';
import { useTranslations } from 'next-intl';
import { ReactNode } from 'react';
import Navigation from './Navigation';
type Props = {
children?: ReactNode;
title: string;
};
export default function PageLayout({ children, title }: Props) {
const t = useTranslations('PageLayout')
return (
<>
<Head>
<title>{[title, t('pageTitle')].join(' - ')}</title>
</Head>
<div className="container m-auto">
<Navigation />
<h1>{title}</h1>
{children}
</div>
</>
)
}
PageLayout.messages = ['PageLayout', ...Navigation.messages];
src\pages\_app.tsx
import "@/styles/globals.css";
import type { AppProps } from "next/app";
import {useRouter} from 'next/router';
import {NextIntlClientProvider} from 'next-intl';
export default function App({ Component, pageProps }: AppProps) {
const router = useRouter();
return (
<NextIntlClientProvider
// To achieve consistent date, time and number formatting
// across the app, you can define a set of global formats.
formats={{
dateTime: {
short: {
day: 'numeric',
month: 'short',
year: 'numeric'
}
}
}}
locale={router.locale}
// Messages can be received from individual pages or configured
// globally in this module (`App.getInitialProps`). Note that in
// the latter case the messages are available as a top-level prop
// and not nested within `pageProps`.
messages={pageProps.messages}
// Providing an explicit value for `now` ensures consistent formatting of
// relative values regardless of the server or client environment.
now={new Date(pageProps.now)}
// Also an explicit time zone is helpful to ensure dates render the
// same way on the client as on the server, which might be located
// in a different time zone.
timeZone="Europe/Vienna"
>
<Component {...pageProps} />
</NextIntlClientProvider>
)
}
src\pages\index.tsx
import {GetStaticPropsContext} from 'next';
import {useTranslations} from 'next-intl';
import PageLayout from '@/pages/components/PageLayout';
import Code from '@/pages/components/Code';
import { useRouter } from 'next/router';
export default function Home() {
const t = useTranslations('Index');
const {locale} = useRouter();
return (
<PageLayout title={t('title')}>
<div>
{t.rich('description', {
locale: locale!,
p: (children) => <p>{children}</p>,
code: (children) => <Code>{children}</Code>
})}
</div>
<ul>
{Home.messages.map((componentName) => (
<li key={componentName} style={{marginBottom: 5}}>
<Code>{componentName}</Code>
</li>
))}
</ul>
</PageLayout>
);
}
export async function getStaticProps({locale}: GetStaticPropsContext) {
return {
props: {
messages: (await import(`../../messages/${locale}.json`)).default
}
};
}
Home.messages = ['Index', ...PageLayout.messages];
src\pages\about.tsx
import {GetServerSidePropsContext} from 'next';
import {useFormatter, useTranslations} from 'next-intl';
import PageLayout from '@/pages/components/PageLayout';
export default function About() {
const t = useTranslations('About');
const format = useFormatter();
const lastUpdated = new Date('2021-12-23T10:04:45.567Z');
return (
<PageLayout title={t('title')}>
<p>
{t('lastUpdated', {
lastUpdated,
lastUpdatedRelative: format.relativeTime(lastUpdated)
})}
</p>
</PageLayout>
);
}
About.messages = ['About', ...PageLayout.messages];
export async function getServerSideProps({locale}: GetServerSidePropsContext) {
return {
props: {
messages: (await import(`../../messages/${locale}.json`)).default,
// Note that when `now` is passed to the app, you need to make sure the
// value is updated from time to time, so relative times are updated. See
// https://next-intl.dev/docs/usage/configuration#global-now-value
now: new Date().getTime()
}
};
}

Last updated
Was this helpful?