Creation:2024-12-07Last update:2026-05-31

    IntlayerでNext.js and Page Routerを翻訳する | 国際化(i18n)

    ide.intlayer.org

    代替手段ではなく Interlayer を使用する理由

    「next-intl」や「i18next」などの主要なソリューションと比較して、Intlayer は次のような統合された最適化を備えたソリューションです。

    Next.js を完全にカバー

    Intlayer は、効率的なレンダリングのために サーバー コンポーネント と連携するように最適化されており、Turbopack と完全に互換性があります。静的レンダリングをブロックせず、ミドルウェアとスケーリング国際化 (i18n) に必要なすべての機能を提供します。

    Intlayer は Next.js 12、13、14、15、および 16 と互換性があります。 Next.js Pages Router を使用している場合は、この ガイド を参照してください。 ロケール ルーティングは、SEO、バンドル サイズ、パフォーマンスに役立ちます。必要ない場合は、このガイドを参照してください。 App Router を使用した Next.js 12、13、14、および 15 については、この ガイド を参照してください。

    バンドルサイズ

    大量の JSON ファイルをページにロードするのではなく、必要なコンテンツのみをロードします。 Intlayer は、バンドルとページのサイズを最大 50% 削減するのに役立ちます。

    保守性

    アプリケーションのコンテンツのスコープを設定すると、大規模なアプリケーションの メンテナンスが容易になります。コンテンツ コードベース全体を確認するという精神的な負担を負うことなく、単一の機能フォルダーを複製または削除できます。さらに、Intlayer は完全に型指定されており、コンテンツの正確性を保証します。

    AI エージェント

    コンテンツを同じ場所に配置すると、大規模言語モデル (LLM) によって 必要なコンテキストが削減されます。 Intlayer には、翻訳の欠落をテストする CLILSPMCP などのツール スイートも付属しています。および エージェント スキル により、AI エージェントの開発者エクスペリエンス (DX) がさらにスムーズになります。

    オートメーション

    AI プロバイダーの費用で、選択した LLM を使用して CI/CD パイプラインで自動化を変換します。 Intlayer は、コンテンツ抽出を自動化する コンパイラー と、バックグラウンドでの翻訳を支援する Web プラットフォーム も提供します。

    パフォーマンス

    大量の JSON ファイルをコンポーネントに接続すると、パフォーマンスと反応性の問題が発生する可能性があります。 Intlayer は、ビルド時のコンテンツの読み込みを最適化します。

    非開発によるスケーリング

    Intlayer は単なる i18n ソリューションではなく、自己ホスト型 ビジュアル エディター完全な CMS を提供します。 リアルタイムで多言語コンテンツを管理できるようになり、翻訳者、コピーライター、その他のチーム メンバーとのコラボレーションがシームレスになります。コンテンツはローカルおよび/またはリモートに保存できます。


    Page Router を使用した Next.js アプリケーションでの Intlayer セットアップ手順

    1. 依存関係のインストール

      お好みのパッケージマネージャーを使って必要なパッケージをインストールします:

      bash
      npm install intlayer next-intlayernpx intlayer init
      • intlayer

        設定管理、翻訳、コンテンツ宣言、トランスパイル、およびCLIコマンドのための国際化ツールを提供するコアパッケージ。

      • next-intlayer

        IntlayerをNext.jsと統合するパッケージです。Next.jsの国際化のためのコンテキストプロバイダーやフックを提供します。さらに、IntlayerをWebpackTurbopackと統合するためのNext.jsプラグインや、ユーザーの優先ロケールの検出、クッキー管理、URLリダイレクト処理のためのミドルウェアも含まれています。

    2. プロジェクトの設定

      アプリケーションでサポートする言語を定義する設定ファイルを作成します:

      intlayer.config.ts
      import { Locales, type IntlayerConfig } from "intlayer";
      
      const config: IntlayerConfig = {
        internationalization: {
          locales: [
            Locales.ENGLISH,
            Locales.FRENCH,
            Locales.SPANISH,
            // 他のロケールをここに追加してください
          ],
          defaultLocale: Locales.ENGLISH,
        },
      };
      
      export default config;
      この設定ファイルを通じて、ローカライズされたURL、ミドルウェアのリダイレクション、クッキー名、コンテンツ宣言の場所と拡張子、Intlayerのコンソールログの無効化などを設定できます。利用可能なパラメータの完全なリストについては、設定ドキュメントを参照してください。
    3. IntlayerをNext.jsの設定に統合する

      Next.jsの設定を修正してIntlayerを組み込みます:

      next.config.mjs
      import { withIntlayer } from "next-intlayer/server";/** @type {import('next').NextConfig} */const nextConfig = {  // 既存のNext.js設定};export default withIntlayer(nextConfig);
      withIntlayer() は Next.js と Intlayer を統合するためのプラグインです。コンテンツ宣言ファイルのビルドを保証し、開発モードでそれらを監視します。また、WebpackTurbopack 環境内で Intlayer の環境変数を定義します。さらに、パフォーマンス最適化のためのエイリアスを提供し、サーバーコンポーネントとの互換性を確保します。
    4. ロケール検出のためのミドルウェア設定

      ユーザーの優先ロケールを自動的に検出し処理するミドルウェアを設定します:

      src/middleware.ts
      export { intlayerProxy as middleware } from "next-intlayer/middleware";
      
      export const config = {
        matcher:
          "/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\\..*|_next).*)",
      };
      matcher パラメータをアプリケーションのルートに合わせて調整してください。詳細については、Next.js の matcher 設定に関するドキュメントを参照してください。
    5. 動的ロケールルートの定義

      ユーザーのロケールに基づいてローカライズされたコンテンツを提供するために動的ルーティングを実装します。

      1. ロケール別ページの作成:

        メインページファイルの名前を [locale] の動的セグメントを含むように変更します。

        bash
        mv src/pages/index.tsx src/pages/[locale]/index.tsx
      2. ローカライズ対応のために _app.tsx を更新:

        plaintext
        `_app.tsx` を修正して Intlayer のプロバイダーを含めます。```tsx fileName="src/pages/_app.tsx" codeFormat="typescript"import type { FC } from "react";import type { AppProps } from "next/app";import { IntlayerClientProvider } from "next-intlayer";const App = FC<AppProps>({ Component, pageProps }) => {  const { locale } = pageProps;  return (    <IntlayerClientProvider locale={locale}>      <Component {...pageProps} />    </IntlayerClientProvider>  );}export default MyApp;``````jsx fileName="src/pages/_app.mjx" codeFormat="esm"import { IntlayerClientProvider } from "next-intlayer";const App = ({ Component, pageProps }) => (  <IntlayerClientProvider locale={locale}>    <Component {...pageProps} />  </IntlayerClientProvider>);export default App;``````jsx fileName="src/pages/_app.csx" codeFormat="commonjs"const { IntlayerClientProvider } = require("next-intlayer");const App = ({ Component, pageProps }) => (  <IntlayerClientProvider locale={locale}>    <Component {...pageProps} />  </IntlayerClientProvider>);module.exports = App;```
      3. getStaticPathsgetStaticProps の設定:

      [locale]/index.tsx ファイル内で、異なるロケールを処理するためのパスとプロパティを定義します。

      src/pages/[locale]/index.tsx
      import type { FC } from "react";
      import type { GetStaticPaths, GetStaticProps } from "next";
      import { type Locales, getConfiguration } from "intlayer";
      
      const HomePage: FC = () => <div>{/* ここにコンテンツを記述 */}</div>;
      
      export const getStaticPaths: GetStaticPaths = () => {
        const { internationalization } = getConfiguration();
        const { locales } = internationalization;
      
        const paths = locales.map((locale) => ({
          params: { locale },
        }));
      
        return { paths, fallback: false };
      };
      
      export const getStaticProps: GetStaticProps = ({ params }) => {
        const locale = params?.locale as string;
      
        return {
          props: {
            locale,
          },
        };
      };
      
      export default HomePage;
      getStaticPathsgetStaticProps は、Next.js のページルーターにおいて、すべてのロケールに対して必要なページを事前にビルドすることを保証します。このアプローチにより、実行時の計算が削減され、ユーザー体験が向上します。詳細については、Next.js のドキュメントの getStaticPaths および getStaticProps を参照してください。
    6. コンテンツを宣言する

      翻訳を格納するためのコンテンツ宣言を作成および管理します。

      src/pages/[locale]/home.content.ts
      import { t, type Dictionary } from "intlayer";
      
      const homeContent = {
        key: "home",
        content: {
          title: t({
            ja: "私のウェブサイトへようこそ",
            en: "Welcome to My Website",
            fr: "Bienvenue sur mon site Web",
            es: "Bienvenido a mi sitio web",
          }),
          description: t({
            ja: "このページを編集して始めましょう。",
            en: "Get started by editing this page.",
            fr: "Commencez par éditer cette page.",
            es: "Comience por editar esta página.",
          }),
        },
      } satisfies Dictionary;
      
      export default homeContent;

      詳細なコンテンツ宣言については、コンテンツ宣言ガイドを参照してください。

    7. コード内でコンテンツを利用する

      アプリケーション全体でコンテンツ辞書にアクセスし、翻訳されたコンテンツを表示します。

      src/pages/[locale]/index.tsx
      import type { FC } from "react";
      import { useIntlayer } from "next-intlayer";
      import { ComponentExample } from "@components/ComponentExample";
      
      const HomePage: FC = () => {
        const content = useIntlayer("home");
      
        return (
          <div>
            <h1>{content.title}</h1>
            <p>{content.description}</p>
            <ComponentExample />
            {/* 追加のコンポーネント */}
          </div>
        );
      };
      
      // ... getStaticPaths と getStaticProps を含むコードの残り
      
      export default HomePage;
      src/components/ComponentExample.tsx
      import type { FC } from "react";
      import { useIntlayer } from "next-intlayer";
      
      export const ComponentExample: FC = () => {
        const content = useIntlayer("component-example"); // 対応するコンテンツ宣言があることを確認してください
      
        return (
          <div>
            <h2>{content.title}</h2>
            <p>{content.content}</p>
          </div>
        );
      };
      string属性(例:alttitlehrefaria-label)で翻訳を使用する場合は、関数の値を次のように呼び出してください:
      html
      <img src="{content.image.src.value}" alt="{content.image.value}" /><img src="{content.image.src.toString()}" alt="{content.image.toString()}" /><img src="{String(content.image.src)}" alt="{String(content.image)}" />
      useIntlayer フックの詳細については、ドキュメントを参照してください。
    8. メタデータの国際化

      ページのタイトルなどのメタデータを国際化したい場合は、Next.js の Page Router が提供する getStaticProps 関数を使用できます。その中で、getIntlayer 関数からコンテンツを取得し、メタデータを翻訳できます。

      src/pages/[locale]/metadata.content.ts
      import { type Dictionary, t } from "intlayer";
      import { type Metadata } from "next";
      
      const metadataContent = {
        key: "page-metadata",
        content: {
          title: t({
            en: "Create Next App",
            fr: "Créer une application Next.js",
            es: "Crear una aplicación Next.js",
          }),
          description: t({
            en: "Generated by create next app",
            fr: "Généré par create next app",
            es: "Generado por create next app",
          }),
        },
      } satisfies Dictionary<Metadata>;
      
      export default metadataContent;
      src/pages/[locale]/index.tsx
      import { GetStaticPaths, GetStaticProps } from "next";
      import { getIntlayer, getMultilingualUrls } from "intlayer";
      import { useIntlayer } from "next-intlayer";
      import Head from "next/head";
      import type { FC } from "react";
      
      interface HomePageProps {
        locale: string;
        metadata: {
          title: string;
          description: string;
        };
        multilingualUrls: Record<string, string>;
      }
      
      const HomePage: FC<HomePageProps> = ({
        metadata,
        multilingualUrls,
        locale,
      }) => {
        const content = useIntlayer("page");
      
        return (
          <div>
            <Head>
              <title>{metadata.title}</title>
              <meta name="description" content={metadata.description} />
              {/* SEOのためのhreflangタグを生成 */}
              {Object.entries(multilingualUrls).map(([lang, url]) => (
                <link key={lang} rel="alternate" hrefLang={lang} href={url} />
              ))}
              <link rel="canonical" href={multilingualUrls[locale]} />
            </Head>
      
            {/* ページコンテンツ */}
            <main>{/* ここにページのコンテンツを記述 */}</main>
          </div>
        );
      };
      
      export const getStaticProps: GetStaticProps<HomePageProps> = async ({
        params,
      }) => {
        const locale = params?.locale as string;
      
        const metadata = getIntlayer("page-metadata", locale);
      
        /**
         * 各ロケールのすべてのURLを含むオブジェクトを生成します。
         *
         * 例:
         * ```ts
         *  getMultilingualUrls('/about');
         *
         *  // 戻り値
         *  // {
         *  //   en: '/about',
         *  //   fr: '/fr/about',
         *  //   es: '/es/about',
         *  // }
         * ```
         */
        const multilingualUrls = getMultilingualUrls("/");
      
        return {
          props: {
            locale,
            metadata,
            multilingualUrls,
          },
        };
      };
      
      export default HomePage;
      
      // ... getStaticPathsを含む残りのコード
      next-intlayer からインポートされる getIntlayer 関数は、コンテンツを IntlayerNode でラップして返すため、ビジュアルエディタとの統合が可能です。対照的に、intlayer からインポートされる getIntlayer 関数は、追加のプロパティなしでコンテンツを直接返します。

      代わりに、getTranslation 関数を使ってメタデータを宣言することもできます。ただし、メタデータの翻訳を自動化し、コンテンツを外部化するためには、コンテンツ宣言ファイルを使用することが推奨されます。

      src/pages/[locale]/index.tsx
      import { GetStaticPaths, GetStaticProps } from "next";
      import {
        type IConfigLocales,
        getTranslation,
        getMultilingualUrls,
      } from "intlayer";
      import { useIntlayer } from "next-intlayer";
      import Head from "next/head";
      import type { FC } from "react";
      
      interface HomePageProps {
        locale: string;
        metadata: {
          title: string;
          description: string;
        };
        multilingualUrls: Record<string, string>;
      }
      
      const HomePage: FC<HomePageProps> = ({ metadata, multilingualUrls, locale }) => {
        const content = useIntlayer("page");
      
        return (
          <div>
            <Head>
              <title>{metadata.title}</title>
              <meta name="description" content={metadata.description} />
              {/* SEOのためのhreflangタグを生成 */}
              {Object.entries(multilingualUrls).map(([lang, url]) => (
                <link
                  key={lang}
                  rel="alternate"
                  hrefLang={lang}
                  href={url}
                />
              ))}
              <link rel="canonical" href={multilingualUrls[locale]} />
            </Head>
      
            {/* ページコンテンツ */}
            <main>
              {/* ここにページコンテンツを記述 */}
            </main>
          </div>
        );
      };
      
      export const getStaticProps: GetStaticProps<HomePageProps> = async ({
        params
      }) => {
        const locale = params?.locale as string;
        const t = <T>(content: IConfigLocales<T>) => getTranslation(content, locale);
      
        const metadata = {
          title: t<string>({
            en: "My title",
            fr: "Mon titre",
            es: "Mi título",
          }),
          description: t({
            en: "My description",
            fr: "Ma description",
            es: "Mi descripción",
          }),
        };
      
        const multilingualUrls = getMultilingualUrls("/");
      
        return {
          props: {
            locale,
            metadata,
            multilingualUrls,
          },
        };
      };
      
      export default HomePage;
      
      // ... getStaticPathsを含む残りのコード
      メタデータの最適化について詳しくは、公式の Next.js ドキュメントをご覧ください。
    9. コンテンツの言語を変更する

      Next.js でコンテンツの言語を変更するには、推奨される方法として Link コンポーネントを使用して、ユーザーを適切なローカライズされたページにリダイレクトする方法があります。Link コンポーネントはページのプリフェッチを可能にし、完全なページリロードを回避するのに役立ちます。

      src/components/LanguageSwitcher.tsx
      import {
        Locales,
        getHTMLTextDir,
        getLocaleName,
        getLocalizedUrl,
      } from "intlayer";
      import { useLocalePageRouter } from "next-intlayer";
      import { type FC } from "react";
      import Link from "next/link";
      
      const LocaleSwitcher: FC = () => {
        const { locale, pathWithoutLocale, availableLocales } = useLocalePageRouter();
      
        return (
          <div>
            <button popoverTarget="localePopover">{getLocaleName(locale)}</button>
            <div id="localePopover" popover="auto">
              {availableLocales.map((localeItem) => (
                <Link
                  href={getLocalizedUrl(pathWithoutLocale, localeItem)}
                  hrefLang={localeItem}
                  key={localeItem}
                  aria-current={locale === localeItem ? "page" : undefined}
                  onClick={() => setLocale(localeItem)}
                >
                  <span>
                    {/* ロケール - 例: FR */}
                    {localeItem}
                  </span>
                  <span>
                    {/* そのロケールでの言語名 - 例: Français */}
                    {getLocaleName(localeItem, locale)}
                  </span>
                  <span dir={getHTMLTextDir(localeItem)} lang={localeItem}>
                    {/* 現在のロケールでの言語 - 例: Locales.SPANISHに設定された現在のロケールでのFrancés */}
                    {getLocaleName(localeItem)}
                  </span>
                  <span dir="ltr" lang={Locales.ENGLISH}>
                    {/* 英語での言語 - 例: French */}
                    {getLocaleName(localeItem, Locales.ENGLISH)}
                  </span>
                </Link>
              ))}
            </div>
          </div>
        );
      };
      もう一つの方法として、useLocale フックが提供する setLocale 関数を使用する方法があります。この関数はページのプリフェッチを許可せず、ページをリロードします。
      この場合、router.push を使ったリダイレクトなしで、サーバーサイドのコードだけがコンテンツのロケールを変更します。
      src/components/LocaleSwitcher.tsx
      "use client";import { useRouter } from "next/navigation";import { useLocale } from "next-intlayer";import { getLocalizedUrl } from "intlayer";// ... 残りのコードconst router = useRouter();const { setLocale } = useLocale({  onLocaleChange: (locale) => {    router.push(getLocalizedUrl(pathWithoutLocale, locale));  },});return (  <button onClick={() => setLocale(Locales.FRENCH)}>フランス語に変更</button>);
      useLocalePageRouter APIはuseLocaleと同じです。useLocaleフックの詳細については、ドキュメントを参照してください。

      ドキュメント参照:

    10. ローカライズされたリンクコンポーネントの作成

      アプリケーションのナビゲーションが現在のロケールを尊重するようにするために、カスタムの Link コンポーネントを作成できます。このコンポーネントは内部URLに自動的に現在の言語のプレフィックスを付けます。例えば、フランス語を話すユーザーが「About」ページへのリンクをクリックすると、/about ではなく /fr/about にリダイレクトされます。

      この動作は以下の理由で有用です:

      • SEOとユーザーエクスペリエンス: ローカライズされたURLは、検索エンジンが言語ごとのページを正しくインデックスし、ユーザーに好みの言語でコンテンツを提供するのに役立ちます。
      • 一貫性: アプリケーション全体でローカライズされたリンクを使用することで、ナビゲーションが現在のロケール内に留まり、予期しない言語の切り替えを防ぎます。
      • 保守性: ローカリゼーションのロジックを単一のコンポーネントに集約することで、URLの管理が簡素化され、アプリケーションの成長に伴いコードベースの保守や拡張が容易になります。

      以下は、TypeScriptで実装したローカライズされたLinkコンポーネントの例です。

      src/components/Link.tsx
      "use client";
      
      import { getLocalizedUrl } from "intlayer";
      import NextLink, { type LinkProps as NextLinkProps } from "next/link";
      import { useLocale } from "next-intlayer";
      import { forwardRef, PropsWithChildren, type ForwardedRef } from "react";
      
      /**
       * 指定されたURLが外部リンクかどうかをチェックするユーティリティ関数。
       * URLが http:// または https:// で始まる場合、外部リンクと見なされます。
       */
      export const checkIsExternalLink = (href?: string): boolean =>
        /^https?:\/\//.test(href ?? "");
      
      /**
       * 現在のロケールに基づいてhref属性を適応させるカスタムLinkコンポーネント。
       * 内部リンクの場合、`getLocalizedUrl`を使用してURLにロケールをプレフィックスします(例: /fr/about)。
       * これにより、ナビゲーションが同じロケールコンテキスト内に留まることを保証します。
       */
      export const Link = forwardRef<
        HTMLAnchorElement,
        PropsWithChildren<NextLinkProps>
      >(({ href, children, ...props }, ref: ForwardedRef<HTMLAnchorElement>) => {
        const { locale } = useLocale();
        const isExternalLink = checkIsExternalLink(href.toString());
      
        // リンクが内部リンクで有効なhrefが提供されている場合、ローカライズされたURLを取得します。
        const hrefI18n: NextLinkProps["href"] =
          href && !isExternalLink ? getLocalizedUrl(href.toString(), locale) : href;
      
        return (
          <NextLink href={hrefI18n} ref={ref} {...props}>
            {children}
          </NextLink>
        );
      });
      
      Link.displayName = "Link";

      動作の仕組み

      • 外部リンクの検出:
        ヘルパー関数 checkIsExternalLink はURLが外部リンクかどうかを判定します。外部リンクはローカライズの必要がないため、そのままにされます。

      • 現在のロケールの取得:
        useLocale フックは現在のロケール(例:フランス語の場合は fr)を提供します。

      • URLのローカライズ:
        内部リンク(つまり外部リンクでない場合)には、getLocalizedUrl が使用され、URLの先頭に現在のロケールが自動的に付加されます。つまり、ユーザーがフランス語環境にいる場合、href/about を渡すと /fr/about に変換されます。

      • リンクの返却:
        コンポーネントはローカライズされたURLを持つ <a> 要素を返し、ナビゲーションがロケールに沿って一貫するようにします。

      この Link コンポーネントをアプリケーション全体に統合することで、一貫性のある言語対応のユーザー体験を維持しつつ、SEOや使いやすさの向上も期待できます。

    11. バンドルサイズの最適化

      next-intlayerを使用すると、辞書はデフォルトですべてのページのバンドルに含まれます。バンドルサイズを最適化するために、Intlayerはマクロを使用してuseIntlayerの呼び出しをインテリジェントに置き換えるオプションのSWCプラグインを提供しています。これにより、辞書は実際に使用されているページのバンドルにのみ含まれるようになります。

      この最適化を有効にするには、@intlayer/swcパッケージをインストールしてください。インストール後、next-intlayerは自動的にプラグインを検出して使用します。

      bash
      npm install @intlayer/swc --save-dev
      注意: この最適化はNext.js 13以降でのみ利用可能です。

      注意: このパッケージは、Next.jsでのSWCプラグインがまだ実験的なため、デフォルトではインストールされていません。将来的に変更される可能性があります。

    TypeScriptの設定

    Intlayerはモジュール拡張を使用して、TypeScriptの利点を活かし、コードベースをより強固にします。

    Autocompletion

    Translation error

    TypeScriptの設定に自動生成された型が含まれていることを確認してください。

    tsconfig.json
    {  // ... 既存のTypeScript設定  "include": [    // ... 既存のTypeScript設定    ".intlayer/**/*.ts", // 自動生成された型を含める  ],}

    Gitの設定

    リポジトリをクリーンに保ち、生成されたファイルのコミットを避けるために、Intlayerによって作成されたファイルを無視することを推奨します。

    以下の行を .gitignore ファイルに追加してください:

    .gitignore
    # Intlayerによって生成されたファイルを無視する.intlayer

    VS Code 拡張機能

    Intlayerでの開発体験を向上させるために、公式の Intlayer VS Code 拡張機能 をインストールできます。

    VS Codeマーケットプレイスからインストール

    この拡張機能は以下を提供します:

    • 翻訳キーの オートコンプリート
    • 欠落している翻訳の リアルタイムエラー検出
    • 翻訳された内容の インラインプレビュー
    • 翻訳を簡単に作成・更新できる クイックアクション

    拡張機能の使用方法の詳細については、Intlayer VS Code 拡張機能のドキュメントを参照してください。

    追加リソース

    このガイドに従うことで、Next.js アプリケーションの Page Router を使用して Intlayer を効果的に統合し、ウェブプロジェクトに対して堅牢でスケーラブルな国際化サポートを実現できます。

    さらに進む

    さらに進めるには、ビジュアルエディターを実装するか、CMSを使用してコンテンツを外部化することができます。