IntlayerとNext.js 15アプリルーターでの国際化 (i18n) の始め方
Intlayerとは?
Intlayerは、モダンウェブアプリケーションにおける多言語サポートを簡素化するために設計された革新的なオープンソース国際化(i18n)ライブラリです。Intlayerは最新のNext.js 15フレームワークとシームレスに統合され、強力なアプリルーターも含まれています。効率的なレンダリングのためにサーバーコンポーネントでの動作に最適化されており、Turbopackにも完全に対応しています。
Intlayerを使用すると、以下を実現できます:
- 宣言型辞書を使用して翻訳を簡単に管理することができます。
- メタデータ、ルート、およびコンテンツを動的にローカライズすることができます。
- クライアントサイドおよびサーバーサイドコンポーネントで翻訳にアクセスすることができます。
- 自動生成された型を使用してTypeScriptサポートを確保し、オートコンプリートとエラーチェックを向上させます。
- 動的ロケール検出や切り替えなどの高度な機能を利用できます。
IntlayerはNext.js 12、13、14、15に対応しています。Next.js Page Routerを使用している場合は、このガイドを参照してください。Next.js 12、13、14でApp Routerを使っている場合は、このガイドを参照してください。
Next.jsアプリケーションにIntlayerをセットアップする手順ガイド
ステップ1: 依存関係をインストール
npmを使用して必要なパッケージをインストールします:
npm install intlayer next-intlayer
intlayer
設定管理、翻訳、コンテンツ宣言、トランスパイレーション、CLIコマンドのための国際化ツールを提供するコアパッケージです。
next-intlayer
IntlayerとNext.jsを統合するパッケージです。Next.js国際化のためのコンテキストプロバイダーとフックを提供します。さらに、IntlayerをWebpackやTurbopackと統合するNext.jsプラグイン、およびユーザーの好ましいロケールを検出し、クッキーを管理し、URLリダイレクトを処理するためのミドルウェアを含んでいます。
ステップ2: プロジェクトを設定する
アプリケーションの言語を設定するための構成ファイルを作成します:
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のログをコンソールに表示しないようにするなどを設定できます。利用可能なパラメータの完全なリストについては、設定ドキュメントを参照してください。
ステップ3: Next.js設定にIntlayerを統合
Next.jsのセットアップをIntlayerを使用するように設定します:
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の環境変数を定義します。さらに、パフォーマンスを最適化するためのエイリアスを提供し、サーバーコンポーネントとの互換性を確保します。
ステップ4: ロケール検出のためのミドルウェアを設定
ユーザーの好ましいロケールを検出するためのミドルウェアを設定します:
export { intlayerMiddleware as middleware } from "next-intlayer/middleware";export const config = { matcher: "/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\\..*|_next).*)",};
intlayerMiddlewareは、ユーザーの好ましいロケールを検出し、設定で指定された適切なURLにリダイレクトします。また、ユーザーの好ましいロケールをクッキーに保存することを可能にします。
ステップ5: 動的ロケールルートを定義
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 { NextLayoutIntlayer } from "next-intlayer";import { Inter } from "next/font/google";import { getHTMLTextDir } from "intlayer";const inter = Inter({ subsets: ["latin"] });const LocaleLayout: NextLayoutIntlayer = async ({ children, params }) => { const { locale } = await params; return ( <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: NextLayoutIntlayer = async ({ children, params }) => { /*... 後のコード*/};export default LocaleLayout;
generateStaticParamsは、アプリケーションがすべてのロケールの必要なページを事前にビルドすることを保証し、ランタイム計算を減少させ、ユーザーエクスペリエンスを向上させます。詳細については、Next.jsのgenerateStaticParamsに関するドキュメントを参照してください。
ステップ6: コンテンツを宣言する
翻訳を保存するためのコンテンツ宣言を作成して管理します:
import { t, type DeclarationContent } from "intlayer";const pageContent = { key: "page", content: { getStarted: { main: t({ ja: "編集を始めるには", fr: "Commencez par éditer", es: "Comience por editar", }), pageLink: "src/app/page.tsx", }, },} satisfies DeclarationContent;export default pageContent;
コンテンツ宣言は、アプリケーション内の任意の場所で定義できますが、contentDirディレクトリに含まれている必要があります(デフォルトは./src)。また、コンテンツ宣言ファイルの拡張子と一致する必要があります(デフォルトは.content.{ts,tsx,js,jsx,mjs,cjs})。 詳細については、コンテンツ宣言のドキュメントを参照してください。
ステップ7: コード内のコンテンツを利用
アプリケーション全体でコンテンツ辞書にアクセスします:
import type { FC } from "react";import { ClientComponentExample } from "@components/ClientComponentExample";import { ServerComponentExample } from "@components/ServerComponentExample";import { type NextPageIntlayer, IntlayerClientProvider } from "next-intlayer";import { IntlayerServerProvider, useIntlayer } from "next-intlayer/server";const PageContent: FC = () => { const { title, content } = useIntlayer("page"); return ( <> <p>{content.getStarted.main}</p> <code>{content.getStarted.pageLink}</code> </> );};const Page: NextPageIntlayer = async ({ params }) => { const { locale } = await params; return ( <> <IntlayerServerProvider locale={locale}> <PageContent /> <ServerComponentExample /> <IntlayerClientProvider locale={locale}> <ClientComponentExample /> </IntlayerClientProvider> </IntlayerServerProvider> </> );};export default Page;
- IntlayerClientProviderは、クライアントサイドコンポーネントにロケールを提供するために使用されます。親コンポーネントの中であれば、どこにでも配置できますが、レイアウトに配置することが推奨されます。これにより、Next.jsはページ間でレイアウトコードを共有し、効率が向上します。レイアウトでIntlayerClientProviderを使用すると、各ページで再初期化することを避け、パフォーマンスが向上し、アプリケーション全体で一貫したローカライズコンテキストを維持できます。
IntlayerServerProviderは、サーバーの子要素にロケールを提供するために使用されます。レイアウト内で設定することはできません。
レイアウトとページで共通のサーバーコンテキストを共有することはできません。なぜなら、サーバーコンテキストシステムはリクエストごとのデータストア(Reactのキャッシュメカニズム経由)のために基づいているからです。これにより、アプリケーションの異なるセグメントに対して各「コンテキスト」が再作成されます。プロバイダを共有レイアウトに配置すると、この隔離が壊れ、サーバーコンテキストの値がサーバーコンポーネントに正しく伝播されなくなります。
"use client";import type { FC } from "react";import { useIntlayer } from "next-intlayer";export 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";export 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フックの詳細については、ドキュメントを参照してください。
(オプション) ステップ8: メタデータの国際化
ページのタイトルなどのメタデータを国際化したい場合は、Next.jsが提供するgenerateMetadata関数を使用できます。この関数の中でgetTranslationContent関数を使用してメタデータを翻訳します。
import { type IConfigLocales, getTranslationContent, getMultilingualUrls,} from "intlayer";import type { Metadata } from "next";import type { LocalPromiseParams } from "next-intlayer";export const generateMetadata = async ({ params: { locale },}: LocalPromiseParams): Metadata => { const { locale } = await params; const t = <T>(content: IConfigLocales<T>) => getTranslationContent(content, locale); /** * 各ロケールのすべてのURLを含むオブジェクトを生成します。 * * 例: * ```ts * getMultilingualUrls('/about'); * * // 返り値 * // { * // ja: '/about', * // fr: '/fr/about', * // es: '/es/about', * // } * ``` */ const multilingualUrls = getMultilingualUrls("/"); return { title: t<string>({ ja: "私のタイトル", fr: "Mon titre", es: "Mi título", }), description: t({ ja: "私の説明", fr: "Ma description", es: "Mi descripción", }), alternates: { canonical: "/", languages: { ...multilingualUrls, "x-default": "/" }, }, openGraph: { url: multilingualUrls[locale], }, };};// ... 後のコード
メタデータの最適化については、Next.jsの公式ドキュメントを参照してください。
(オプション) ステップ9: sitemap.xmlと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の公式ドキュメントを参照してください。
(オプション) ステップ10: コンテンツの言語を変更
コンテンツの言語を変更するには、useLocaleフックが提供するsetLocale関数を使用できます。この関数を使用すると、アプリケーションのロケールを設定し、それに応じてコンテンツを更新できます。
"use client";import type { FC } from "react";import { Locales, getHTMLTextDir, getLocaleName, getLocalizedUrl,} from "intlayer";import { useLocale } from "next-intlayer";import Link from "next/link";export const LocaleSwitcher: FC = () => { const { locale, pathWithoutLocale, availableLocales, setLocale } = useLocale(); return ( <ol> {availableLocales.map((localeItem) => ( <li key={localeItem}> <Link href={getLocalizedUrl(pathWithoutLocale, localeItem)} hrefLang={localeItem} aria-current={locale === localeItem ? "page" : undefined} onClick={(e) => { e.preventDefault(); setLocale(localeItem); }} > <span> {/* 自国のロケールでの言語名 - 例: 日本語 */} {getLocaleName(localeItem, locale)} </span> <span dir={getHTMLTextDir(localeItem)} lang={localeItem}> {/* 現在のロケールでの言語名 - 例: 日本語がLocales.SPANISHに設定されているときのEspañol */} {getLocaleName(localeItem)} </span> <span dir="ltr" lang={Locales.ENGLISH}> {/* 英語での言語名 - 例: Japanese */} {getLocaleName(localeItem, Locales.ENGLISH)} </span> <span> {/* 自国のロケールでの言語名 - 例: JA */} {localeItem} </span> </Link> </li> ))} </ol> );};
ドキュメント参照:
TypeScriptの設定
Intlayerは、TypeScriptの利点を活用し、コードベースを強化するためにモジュール拡張を使用します。
TypeScript設定に自動生成された型が含まれていることを確認してください。
{ // ... 既存のTypeScript構成 "include": [ // ... 既存のTypeScript構成 "types", // 自動生成された型を含める ],}
Gitの設定
Intlayerによって生成されたファイルを無視することが推奨されます。これにより、それらをGitリポジトリにコミットすることを避けることができます。
これを行うには、.gitignoreファイルに次の指示を追加します:
# Intlayerによって生成されたファイルを無視.intlayer
このドキュメントを改善するアイデアがある場合は、GitHubでプルリクエストを送信することで自由に貢献してください。
ドキュメントへのGitHubリンク