Getting Started internationalizing (i18n) with Intlayer and Next.js 14 with App Router
What is Intlayer?
Intlayer は、最新の Web アプリケーションにおける多言語サポートを簡素化するために設計された革新的なオープンソースの国際化 (i18n) ライブラリです。Intlayer は、最新の Next.js 14 フレームワークにシームレスに統合されており、その強力な App Router を利用しています。効率的なレンダリングのために Server Components での動作に最適化されており、Turbopack(Next.js >= 15 の場合)にも完全に対応しています。
Intlayer を使用すると、次のことが可能です:
- 宣言型の辞書を使用して翻訳を簡単に管理できます。
- メタデータ、ルート、およびコンテンツを動的にローカライズできます。
- クライアント側とサーバー側のコンポーネントの両方で翻訳にアクセスできます。
- 自動生成された型を使用して TypeScript サポートを保証し、オートコンプリートやエラー検出を向上させます。
- 動的ロケール検出や切り替えなどの高度な機能を利用できます。
Intlayer は、Next.js 12、13、14、15 と互換性があります。Next.js Page Router を使用している場合は、このガイドを参照してください。Next.js 15 と turbopack 有無に応じて、このガイドを参照してください。
Step-by-Step Guide to Set Up Intlayer in a Next.js Application
Step 1: Install Dependencies
必要なパッケージを npm を使用してインストールします。
npm install intlayer next-intlayer
intlayer
設定管理、翻訳、コンテンツ宣言、トランスパイレーション、および CLI コマンドのための国際化ツールを提供するコアパッケージです。
next-intlayer
Intlayer を Next.js に統合するパッケージです。Next.js の国際化のためのコンテキストプロバイダとフックを提供します。さらに、Webpack や Turbopack と統合するための Next.js プラグインや、ユーザーの優先ロケールを検出し、クッキーを管理し、URL リダイレクトを処理するためのミドルウェアを含んでいます。
Step 2: Configure Your Project
アプリケーションの言語を設定するための構成ファイルを作成します。
import { Locales, type IntlayerConfig } from "intlayer";const config: IntlayerConfig = { internationalization: { locales: [ Locales.JAPANESE, Locales.FRENCH, Locales.SPANISH, // 他のロケールを追加する ], defaultLocale: Locales.JAPANESE, },};export default config;
この構成ファイルを通じて、ローカライズされた URL、ミドルウェアのリダイレクト、クッキー名、コンテンツ宣言の位置と拡張子、Intlayer のログをコンソールで無効化するなどを設定できます。利用可能なパラメーターの完全なリストについては、構成のドキュメントを参照してください。
Step 3: Integrate Intlayer in Your Next.js Configuration
Intlayer を使用するために、Next.js の設定を構成します。
import { withIntlayer } from "next-intlayer/server";/** @type {import('next').NextConfig} */const nextConfig = {};export default withIntlayer(nextConfig);
withIntlayer() Next.js プラグインは、Intlayer を Next.js に統合するために使用されます。コンテンツ宣言ファイルのビルドを保証し、開発モードでそれらを監視します。さらに、Webpack または Turbopack 環境内での Intlayerの環境変数を定義し、パフォーマンスを最適化するためのエイリアスを提供し、サーバーコンポーネントとの互換性を確保します。
Step 4: Configure Middleware for Locale Detection
ユーザーの優先ロケールを検出するためのミドルウェアをセットアップします。
export { intlayerMiddleware as middleware } from "next-intlayer/middleware";export const config = { matcher: "/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\\..*|_next).*)",};
intlayerMiddleware は、ユーザーの優先ロケールを検出し、構成で指定された適切な URL にリダイレクトします。また、ユーザーの優先ロケールをクッキーに保存することを可能にします。
matcher パラメータをアプリケーションのルートに合わせるように調整してください。詳細については、Next.js のマッチャーの構成に関するドキュメントを参照してください。
Step 5: Define Dynamic Locale Routes
RootLayout からすべてを削除し、以下のコードに置き換えます。
import type { PropsWithChildren, FC } from "react";import "./globals.css";const RootLayout: FC<PropsWithChildren> = ({ children }) => children;export default RootLayout;
RootLayout コンポーネントを空のままにしておくと、<html> タグに lang と dir 属性を設定することができます。
動的ルーティングを実装するには、[locale] ディレクトリに新しいレイアウトを追加してロケールのパスを提供します。
import type { Next14LayoutIntlayer } from "next-intlayer";import { Inter } from "next/font/google";import { getHTMLTextDir } from "intlayer";const inter = Inter({ subsets: ["latin"] });const LocaleLayout: Next14LayoutIntlayer = ({ children, params: { locale },}) => ( <html lang={locale} dir={getHTMLTextDir(locale)}> <body className={inter.className}>{children}</body> </html>);export default LocaleLayout;
[locale] パスセグメントはロケールを定義するために使用されます。例:/en-US/about は en-US を示し、/fr/about は fr を示します。
次に、アプリケーションのレイアウトに generateStaticParams 関数を実装します。
export { generateStaticParams } from "next-intlayer"; // 挿入すべき行const LocaleLayout: Next14LayoutIntlayer = ({ children, params: { locale },}) => { /*... 残りのコード */};export default LocaleLayout;
generateStaticParams は、すべてのロケールに対する必要なページをアプリケーションが事前にビルドすることを保証し、実行時の計算を減らし、ユーザーエクスペリエンスを向上させます。詳細については、Next.js の generateStaticParams に関するドキュメントを参照してください。
Step 6: Declare Your Content
翻訳を格納するためのコンテンツ宣言を作成し、管理します。
import { t, type DeclarationContent } from "intlayer";const pageContent = { key: "page", content: { getStarted: { main: t({ en: "Get started by editing", fr: "Commencez par éditer", es: "Comience por editar", ja: "編集から始める", }), pageLink: "src/app/page.tsx", }, },} satisfies DeclarationContent;export default pageContent;
コンテンツ宣言は、contentDir ディレクトリ(デフォルトでは ./src)に含まれている限り、アプリケーション内のどこにでも定義できます。また、コンテンツ宣言ファイルの拡張子と一致する必要があります(デフォルトでは .content.{ts,tsx,js,jsx,mjs,cjs})。 詳細については、コンテンツ宣言のドキュメントを参照してください。
Step 7: Utilize Content in Your Code
アプリケーション内のどこでも、コンテンツ辞書にアクセスします。
import { ClientComponentExample } from "@components/ClientComponentExample";import { ServerComponentExample } from "@components/ServerComponentExample";import { type Next14PageIntlayer, IntlayerClientProvider } from "next-intlayer";import { IntlayerServerProvider, useIntlayer } from "next-intlayer/server";const Page: Next14PageIntlayer = ({ params: { locale } }) => { const content = useIntlayer("page", locale); return ( <> <p> {content.getStarted.main} <code>{content.getStarted.pageLink}</code> </p> <IntlayerServerProvider locale={locale}> <IntlayerClientProvider locale={locale}> <ServerComponentExample /> <ClientComponentExample /> </IntlayerClientProvider> </IntlayerServerProvider> </> );};export default Page;
- IntlayerClientProvider は、クライアントサイドコンポーネントにロケールを提供するために使用されます。これは、レイアウトを含む任意の親コンポーネントに配置できますが、性能を向上させ、一貫したローカリゼーションコンテキストをアプリケーション全体に維持するために、レイアウトに配置することをお勧めします。
IntlayerServerProvider は、サーバーの子コンポーネントにロケールを提供するために使用されます。レイアウト内で設定することはできません。
レイアウトとページは、共通のサーバーコンテキストを共有できません。なぜなら、サーバーコンテキストシステムはリクエストごとのデータストアに基づいているため、アプリケーションの異なるセグメントでそれぞれの「コンテキスト」が再作成されてしまいます。共有レイアウト内でプロバイダーを配置すると、この分離が崩れ、サーバーコンポーネントへのサーバーコンテキスト値の正しい伝播を防ぐことになります。
"use client";import type { FC } from "react";import { useIntlayer } from "next-intlayer";const ClientComponentExample: FC = () => { const content = useIntlayer("client-component-example"); // 関連するコンテンツ宣言を作成する return ( <div> <h2>{content.title} </h2> <p>{content.content}</p> </div> );};
import type { FC } from "react";import { useIntlayer } from "next-intlayer/server";const ServerComponentExample: FC = () => { const content = useIntlayer("server-component-example"); // 関連するコンテンツ宣言を作成する return ( <div> <h2>{content.title} </h2> <p>{content.content}</p> </div> );};
コンテンツを alt、title、href、aria-label などの string 属性で使用したい場合は、関数の値を呼び出す必要があります。例えば:
jsx<img src={content.image.src.value} alt={content.image.value} />
useIntlayer フックの詳細については、ドキュメントを参照してください。
(Optional) Step 8: Internationalization of your metadata
メタデータ、たとえばページのタイトルを国際化したい場合は、Next.js が提供する generateMetadata 関数を使用できます。関数内で、getTranslationContent 関数を使用してメタデータを翻訳します。
import { type IConfigLocales, getTranslationContent, getMultilingualUrls,} from "intlayer";import type { Metadata } from "next";import type { LocalParams } from "next-intlayer";export const generateMetadata = ({ params: { locale },}: LocalParams): Metadata => { const t = <T>(content: IConfigLocales<T>) => getTranslationContent(content, locale); /** * 各ロケールの URL を含むオブジェクトを生成します。 * * 例: * ```ts * getMultilingualUrls('/about'); * * // 返す値 * // { * // en: '/about', * // fr: '/fr/about', * // es: '/es/about', * // } * ``` */ const multilingualUrls = getMultilingualUrls("/"); return { title: t<string>({ en: "My title", fr: "Mon titre", es: "Mi título", ja: "私のタイトル", }), description: t({ en: "My description", fr: "Ma description", es: "Mi descripción", ja: "私の説明", }), alternates: { canonical: "/", languages: { ...multilingualUrls, "x-default": "/" }, }, openGraph: { url: multilingualUrls[locale], }, };};// ... 残りのコード
メタデータ最適化に関する詳細は、公式 Next.js ドキュメントを参照してください。
(Optional) Step 9: Internationalization of your sitemap.xml and robots.txt
sitemap.xml と robots.txt を国際化するには、Intlayer によって提供される getMultilingualUrls 関数を使用できます。この関数を使用すると、サイトマップ用の多言語 URL を生成することができます。
import { getMultilingualUrls } from "intlayer";import type { MetadataRoute } from "next";const sitemap = (): MetadataRoute.Sitemap => [ { url: "https://example.com", alternates: { languages: getMultilingualUrls("https://example.com"), }, }, { url: "https://example.com/login", alternates: { languages: getMultilingualUrls("https://example.com/login"), }, }, { url: "https://example.com/register", alternates: { languages: getMultilingualUrls("https://example.com/register"), }, },];export default sitemap;
import type { MetadataRoute } from "next";import { getMultilingualUrls } from "intlayer";const getAllMultilingualUrls = (urls: string[]) => urls.flatMap((url) => Object.values(getMultilingualUrls(url)) as string[]);const robots = (): MetadataRoute.Robots => ({ rules: { userAgent: "*", allow: ["/"], disallow: getAllMultilingualUrls(["/login", "/register"]), }, host: "https://example.com", sitemap: `https://example.com/sitemap.xml`,});export default robots;
サイトマップ最適化の詳細は、公式 Next.js ドキュメントを参照してください。robots.txt の最適化に関する詳細は、公式 Next.js ドキュメントを参照してください。
(Optional) Step 10: Change the language of your content
コンテンツの言語を変更するには、useLocale フックが提供する setLocale 関数を使用できます。この関数を使用すると、アプリケーションのロケールを設定し、コンテンツを更新できます。
"use client";import { Locales, getHTMLTextDir, getLocaleName, getLocalizedUrl,} from "intlayer";import { useLocale } from "next-intlayer";import { type FC } from "react";const LocaleSwitcher: FC = () => { const { locale, pathWithoutLocale, availableLocales, setLocale } = useLocale(); return ( <ol> {availableLocales.map((localeItem) => ( <li key={localeItem}> <a href={getLocalizedUrl(pathWithoutLocale, localeItem)} hrefLang={localeItem} aria-current={locale === localeItem ? "page" : undefined} onClick={(e) => { e.preventDefault(); setLocale(localeItem); }} > <span> {/* 自分のロケールの言語 - 例:Français */} {getLocaleName(localeItem, locale)} </span> <span dir={getHTMLTextDir(localeItem)} lang={localeItem}> {/* 現在のロケールにおける言語 - 例:Francés */} {getLocaleName(localeItem)} </span> <span dir="ltr" lang={Locales.ENGLISH}> {/* 英語での言語 - 例:French */} {getLocaleName(localeItem, Locales.ENGLISH)} </span> <span> {/* 自分のロケールの言語コード - 例:FR */} {localeItem} </span> </a> </li> ))} </ol> );};
ドキュメントの参照:
Configure TypeScript
Intlayer は TypeScript のモジュール拡張を使用して、TypeScript の利点を生かし、コードベースを強化します。
TypeScript の設定には、自動生成された型が含まれていることを確認してください。
{ // ... 既存の TypeScript 設定 "include": [ // ... 既存の TypeScript 設定 "types", // 自動生成された型を含む ],}
Git Configuration
Intlayer によって生成されたファイルを無視することをお勧めします。これにより、Git リポジトリにそれらをコミットしないようにできます。
これを行うには、.gitignore ファイルに次の指示を追加できます。
# Intlayer によって生成されたファイルを無視する.intlayer
このドキュメントを改善するアイデアがある場合は、GitHubでプルリクエストを送信することで自由に貢献してください。
ドキュメントへのGitHubリンク