著者:
    作成:2025-09-09最終更新:2026-08-25

    Intlayerを使用してTanStack Startウェブサイトを翻訳する | 国際化(i18n)

    目次

    このガイドでは、ロケール対応のルーティング、TypeScriptサポート、および最新の開発手法を使用して、TanStack StartプロジェクトにIntlayerをシームレスに統合し、国際化を実現する方法を説明します。

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

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

    TanStack Start を完全にカバー

    Intlayer は TanStack Start 用に完全に最適化されており、多言語ルーティングCookie 管理サイトマップ生成動的コンテンツ読み込み、および国際化 (i18n) の取り組みを拡張するために必要なすべての機能を提供します。

    バンドルサイズ

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

    保守性

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

    AI エージェント

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

    オートメーション

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

    パフォーマンス

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

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

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


    TanStack StartアプリケーションでIntlayerをセットアップするためのステップバイステップガイド

    www.youtube.com
    ide.intlayer.org
    intlayer-tanstack-start-template.vercel.app

    GitHubのアプリケーションテンプレートを参照してください。

    1. プロジェクトの作成

      まず、TanStack Startウェブサイトのプロジェクトの開始ガイドに従って、新しいTanStack Startプロジェクトを作成します。

    2. Intlayerパッケージのインストール

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

      bash
      npx intlayer init --interactive
      
      --interactive フラグはオプションです。AI エージェントの場合は intlayer-cli init を使用してください。
      このコマンドは環境を検出し、必要なパッケージをインストールします。例えば:
      bash
      npm install intlayer react-intlayer
      npm install vite-intlayer --save-dev
      
      • intlayer

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

      • react-intlayer IntlayerをReactアプリケーションと統合するパッケージです。Reactの国際化のためのコンテキストプロバイダーとフックを提供します。

      • vite-intlayer IntlayerをViteバンミラーと統合するためのViteプラグイン、およびユーザーの優先ロケールの検出、クッキーの管理、URLリダイレクトの処理のためのミドルウェアが含まれています。

    3. プロジェクトの構成

      アプリケーションの言語を構成するための設定ファイルを作成します:

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

      構成にintlayerプラグインを追加します:

      vite.config.ts
      import { tanstackStart } from "@tanstack/react-start/plugin/vite";
      import viteReact from "@vitejs/plugin-react";
      import { nitro } from "nitro/vite";
      import { defineConfig } from "vite";
      import { intlayer } from "vite-intlayer";
      
      const config = defineConfig({
        plugins: [
          nitro(),
          intlayer({
            proxy: {
              ignore: (req) => req.url?.startsWith("/api"),
            },
          }),
          tanstackStart({
            router: {
              routeFileIgnorePattern:
                ".content.(ts|tsx|js|mjs|cjs|jsx|json|jsonc|json5|md|mdx|yaml|yml)$",
            },
          }),
          viteReact(),
        ],
      });
      
      export default config;
      
      intlayer() Viteプラグインは、IntlayerをViteと統合するために使用されます。コンテンツ宣言ファイルの構築を確実にし、開発モードでそれらを監視します。Viteアプリケーション内でIntlayer環境変数を定義します。さらに、パフォーマンスを最適化するためのエイリアスを提供します。
    5. ルートレイアウトの作成

      useParamsを使用して現在のロケールを検出し、htmlタグにlangおよびdir属性を設定することで、国際化をサポートするようにルートレイアウトを構成します。

      src/routes/__root.tsx
      import {
        createRootRouteWithContext,
        getRouteApi,
        HeadContent,
        Scripts,
      } from "@tanstack/react-router";
      import { defaultLocale, getHTMLTextDir } from "intlayer";
      import { type ReactNode } from "react";
      import { IntlayerProvider } from "react-intlayer";
      
      const localeRoute = getRouteApi("/{-$locale}");
      
      export const Route = createRootRouteWithContext<{}>()({
        head: () => ({
          meta: [
            {
              charSet: "utf-8",
            },
            {
              content: "width=device-width, initial-scale=1",
              name: "viewport",
            },
            {
              title: "TanStack Start Starter",
            },
          ],
        }),
      
        shellComponent: RootDocument,
      });
      
      function RootDocument({ children }: { children: ReactNode }) {
        const params = localeRoute.useParams();
        const locale = params?.locale ?? defaultLocale;
      
        return (
          <html dir={getHTMLTextDir(locale)} lang={locale}>
            <head>
              <HeadContent />
            </head>
            <body>
              <IntlayerProvider locale={locale}>{children}</IntlayerProvider>
              <Scripts />
            </body>
          </html>
        );
      }
      
    6. ロケールレイアウトの作成

      ロケール接頭辞を処理し、検証を実行するレイアウトを作成します。

      src/routes/{-$locale}/route.tsx
      import { createFileRoute, Outlet, redirect } from "@tanstack/react-router";
      import { validatePrefix } from "intlayer";
      
      export const Route = createFileRoute("/{-$locale}")({
        beforeLoad: ({ params }) => {
          const localeParam = params.locale;
      
          // ロケール接頭辞を検証する
          const { isValid, localePrefix } = validatePrefix(localeParam);
      
          if (!isValid) {
            throw redirect({
              to: "/{-$locale}/404",
              params: { locale: localePrefix },
            });
          }
        },
        component: Outlet,
      });
      
      ここで、{-$locale}は現在のロケールに置き換えられる動的なルートパラメータです。この記法によりスロットがオプションになり、'prefix-no-default'などのルーティングモードで動作できるようになります。

      同じルートで複数の動的セグメントを使用する場合(例:/{-$locale}/other-path/$anotherDynamicPath/...)、このスロットが問題を引き起こす可能性があることに注意してください。 'prefix-all'モードの場合、スロットを$localeに切り替えることをお勧めします。 'no-prefix'または'search-params'モードの場合、スロットを完全に削除できます。

    7. コンテンツの宣言

      翻訳を保存するためのコンテンツ宣言を作成および管理します:

      src/contents/page.content.ts
      import type { Dictionary } from "intlayer";
      
      import { t } from "intlayer";
      
      const appContent = {
        content: {
          links: {
            about: t({
              en: "About",
              es: "Acerca de",
              fr: "À propos",
              ja: "アバウト",
            }),
            home: t({
              en: "Home",
              es: "Inicio",
              fr: "Accueil",
              ja: "ホーム",
            }),
          },
          meta: {
            title: t({
              en: "Welcome to Intlayer + TanStack Router",
              es: "Bienvenido a Intlayer + TanStack Router",
              fr: "Bienvenue à Intlayer + TanStack Router",
              ja: "Intlayer + TanStack Router へようこそ",
            }),
            description: t({
              en: "This is an example of using Intlayer with TanStack Router",
              es: "Este es un ejemplo de uso de Intlayer con TanStack Router",
              fr: "Ceci est un exemple d'utilisation d'Intlayer avec TanStack Router",
              ja: "これは Intlayer と TanStack Router を使用した例です",
            }),
          },
        },
        key: "app",
      } satisfies Dictionary;
      
      export default appContent;
      
      コンテンツ宣言は、contentDirディレクトリ(デフォルトでは./app)に含まれている限り、アプリケーションのどこでも定義できます。また、コンテンツ宣言ファイルの拡張子(デフォルトでは.content.{json,ts,tsx,js,jsx,mjs,cjs,md,mdx,yaml,yml})と一致する必要があります。
      詳細については、コンテンツ宣言ドキュメントを参照してください。
    8. ロケール対応コンポーネントとフックの作成

      ロケール対応のナビゲーションのための LocalizedLink コンポーネントを作成します:

      src/components/localized-link.tsx
      import type { FC } from "react";
      
      import { Link, type LinkComponentProps } from "@tanstack/react-router";
      import { useLocale } from "react-intlayer";
      import { getPrefix } from "intlayer";
      
      export const LOCALE_ROUTE = "{-$locale}" as const;
      
      export type To = StripLocalePrefix<LinkComponentProps["to"]>;
      
      export type StripLocalePrefix<T extends string | undefined> = T extends
        `/${typeof LOCALE_ROUTE}/` | `/${typeof LOCALE_ROUTE}`
        ? "/"
        : T extends `/${typeof LOCALE_ROUTE}/${infer Rest}`
          ? `/${Rest}`
          : T;
      
      type LocalizedLinkProps = {
        to?: To;
      } & Omit<LinkComponentProps, "to">;
      
      export const LocalizedLink: FC<LocalizedLinkProps> = (props) => {
        const { locale } = useLocale();
        const { localePrefix } = getPrefix(locale);
      
        return (
          <Link
            {...props}
            params={{
              locale: localePrefix,
              ...(typeof props?.params === "object" ? props?.params : {}),
            }}
            to={`/${LOCALE_ROUTE}${props.to}` as LinkComponentProps["to"]}
          />
        );
      };
      

      このコンポーネントには2つの目的があります:

      • URLから不要な{-$locale}接頭辞を削除します。
      • ロケールパラメータをURLに挿入して、ユーザーがローカライズされたルートに直接リダイレクトされるようにします。

      次に、プログラムによるナビゲーションのための useLocalizedNavigate フックを作成できます:

      src/hooks/useLocalizedNavigate.tsx
      import { useNavigate } from "@tanstack/react-router";
      import { getPrefix } from "intlayer";
      import { useLocale } from "react-intlayer";
      import type { StripLocalePrefix } from "@/components/localized-link";
      import type { FileRouteTypes } from "@/routeTree.gen";
      
      type NavigateFn = ReturnType<typeof useNavigate>;
      type BaseNavigateOptions = Parameters<NavigateFn>[0];
      
      type LocalizedTo = StripLocalePrefix<FileRouteTypes["to"]>;
      
      export type LocalizedNavigateOptions = Omit<
        BaseNavigateOptions,
        "to" | "params"
      > & {
        to: LocalizedTo;
        params?: Omit<NonNullable<BaseNavigateOptions["params"]>, "locale">;
      };
      
      type LocalizedNavigate = (
        options: LocalizedNavigateOptions
      ) => ReturnType<NavigateFn>;
      
      export const useLocalizedNavigate = () => {
        const navigate = useNavigate();
      
        const { locale } = useLocale();
      
        const localizedNavigate: LocalizedNavigate = (args: any) => {
          const { localePrefix } = getPrefix(locale);
      
          if (typeof args === "string") {
            return navigate({
              to: `/${LOCALE_ROUTE}${args}`,
              params: { locale: localePrefix },
            });
          }
      
          const { to, ...rest } = args;
      
          const localizedTo = `/${LOCALE_ROUTE}${to}` as any;
      
          return navigate({
            to: localizedTo,
            params: { locale: localePrefix, ...rest } as any,
          });
        };
      
        return localizedNavigate;
      };
      
    9. ページでのIntlayerの利用

      コンポーネント内では既定で useIntlayer を使用してください。コンパイラがレンダリング対象のロケールへ解決してくれるため、これが推奨される方法です。getIntlayer / getIntlayerAsync は React ツリーの外側(ルートの head、ローダー、サーバー関数)でのみ使用します。

      アプリケーション全体でコンテンツ辞書にアクセスします:

      ローカライズされたホームページ

      src/routes/{-$locale}/index.tsx
      import { createFileRoute } from "@tanstack/react-router";
      import { useIntlayer } from "react-intlayer";
      
      import LocaleSwitcher from "@/components/locale-switcher";
      import { LocalizedLink } from "@/components/localized-link";
      import { useLocalizedNavigate } from "@/hooks/useLocalizedNavigate";
      
      export const Route = createFileRoute("/{-$locale}/")({
        component: RouteComponent,
      });
      
      function RouteComponent() {
        const content = useIntlayer("app");
        const navigate = useLocalizedNavigate();
      
        return (
          <div>
            <div>
              {content.title}
              <LocaleSwitcher />
              <div>
                <LocalizedLink to="/">{content.links.home}</LocalizedLink>
                <LocalizedLink to="/about">{content.links.about}</LocalizedLink>
              </div>
              <div>
                <button onClick={() => navigate({ to: "/" })}>
                  {content.links.home}
                </button>
                <button onClick={() => navigate({ to: "/about" })}>
                  {content.links.about}
                </button>
              </div>
            </div>
          </div>
        );
      }
      

      alttitlehrefaria-label などの string 属性でコンテンツを使用する場合、関数の値を次のように使用できます:

      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 hook の詳細については、ドキュメントを参照してください。
    10. ロケール切り替えコンポーネントを作成する

      ユーザーが言語を変更できるようにするコンポーネントを作成します:

      src/components/locale-switcher.tsx
      import { useLocation } from "@tanstack/react-router";
      import {
        getHTMLTextDir,
        getLocaleName,
        getPathWithoutLocale,
        getPrefix,
        Locales,
      } from "intlayer";
      import type { FC } from "react";
      import { useLocale } from "react-intlayer";
      
      import { LocalizedLink, type To } from "./localized-link";
      
      export const LocaleSwitcher: FC = () => {
        const { pathname } = useLocation();
      
        const { availableLocales, locale, setLocale } = useLocale();
      
        const pathWithoutLocale = getPathWithoutLocale(pathname);
      
        return (
          <ol>
            {availableLocales.map((localeEl) => (
              <li key={localeEl}>
                <LocalizedLink
                  aria-current={localeEl === locale ? "page" : undefined}
                  onClick={() => setLocale(localeEl)}
                  params={{ locale: getPrefix(localeEl).localePrefix }}
                  to={pathWithoutLocale as To}
                >
                  <span>
                    {/* ロケール - 例: FR */}
                    {localeEl}
                  </span>
                  <span>
                    {/* その言語自体でのロケール - 例: Français */}
                    {getLocaleName(localeEl, locale)}
                  </span>
                  <span dir={getHTMLTextDir(localeEl)} lang={localeEl}>
                    {/* 現在のロケールでの言語 - 例: Locales.SPANISH に設定された現在のロケールでの Francés */}
                    {getLocaleName(localeEl)}
                  </span>
                  <span dir="ltr" lang={Locales.ENGLISH}>
                    {/* 英語での言語 - 例: French */}
                    {getLocaleName(localeEl, Locales.ENGLISH)}
                  </span>
                </LocalizedLink>
              </li>
            ))}
          </ol>
        );
      };
      
      useLocale hook の詳細については、ドキュメントを参照してください。
    11. HTML 属性管理

      ステップ 5 で見たように、ルートコンポーネントで useParams を使用して html タグの langdir 属性を管理できます。これにより、サーバーとクライアントで正しい属性が設定されます。

      src/routes/__root.tsx
      const localeRoute = getRouteApi("/{-$locale}");
      
      function RootDocument({ children }: { children: ReactNode }) {
        const params = localeRoute.useParams();
        const locale = params?.locale ?? defaultLocale;
      
        return (
          <html dir={getHTMLTextDir(locale)} lang={locale}>
            {/* ... */}
          </html>
        );
      }
      

    12. ミドルウェアを追加する

      intlayerProxy を使用して、アプリケーションにサーバー側のルーティングを追加することもできます。このプラグインは URL に基づいて現在のロケールを自動的に検出し、適切なロケール cookie を設定します。ロケールが指定されていない場合、プラグインはユーザーのブラウザ言語設定に基づいて最も適切なロケールを決定します。ロケールが検出されない場合、デフォルトロケールにリダイレクトされます。

      本番環境で intlayerProxy を使用するには、vite-intlayer パッケージを devDependencies から dependencies に切り替える必要があります。
      Intlayer v9 以降では、intlayerProxy()intlayer() プラグインに直接バンドルされ、routing.enableProxy オプション(デフォルトで true)を通じてデフォルトで有効になっています。以下に示すように、別途登録することは今や任意です: これは後方互換性と、プラグイン順序を制御する必要があるセットアップのために保持されています。オプトアウトするには routing.enableProxy: false を設定してください。v9 リリースノートを参照してください。
      vite.config.ts
      import { tanstackStart } from "@tanstack/react-start/plugin/vite";
      import viteReact from "@vitejs/plugin-react";
      import { nitro } from "nitro/vite";
      import { defineConfig } from "vite";
      import { intlayer } from "vite-intlayer";
      
      export default defineConfig({
        plugins: [
          nitro(),
          intlayer({
            proxy: {
              ignore: (req) => req.url?.startsWith("/api"),
            },
          }),
          tanstackStart({
            router: {
              routeFileIgnorePattern:
                ".content.(ts|tsx|js|mjs|cjs|jsx|json|jsonc|json5|md|mdx|yaml|yml)$",
            },
          }),
          viteReact(),
        ],
      });
      

    13. メタデータを国際化する

      getIntlayerマージされたディクショナリに対して同期的に解決します。これはすべての宣言されたロケールを保持しているものです。head は同期のままで何も待機しませんが、多言語ディクショナリ全体がブラウザに送信されるルートチャンクに含まれます。

      src/routes/{-$locale}/index.tsx
      import { createFileRoute } from "@tanstack/react-router";
      import {
        defaultLocale,
        getIntlayer,
        getLocalizedUrl,
        localeMap,
      } from "intlayer";
      
      export const Route = createFileRoute("/{-$locale}/")({
        component: RouteComponent,
        head: ({ params }) => {
          const { locale = defaultLocale } = params;
          const path = "/"; // このルートのパス
      
          const metaContent = getIntlayer("app", locale);
      
          return {
            links: [
              // 正規リンク: 現在のローカライズされたページを指す
              { rel: "canonical", href: getLocalizedUrl(path, locale) },
      
              // Hreflang: すべてのローカライズされたバージョンについて Google に通知
              ...localeMap(({ locale: mapLocale }) => ({
                rel: "alternate",
                hrefLang: mapLocale,
                href: getLocalizedUrl(path, mapLocale),
              })),
      
              // x-default: マッチしない言語のユーザー向け
              // デフォルトのフォールバックロケールを定義(通常、プライマリ言語)
              {
                rel: "alternate",
                hrefLang: "x-default",
                href: getLocalizedUrl(path, defaultLocale),
              },
            ],
            meta: [
              { title: metaContent.title },
              { name: "description", content: metaContent.meta.description },
            ],
          };
        },
      });
      

      小さなメタデータディクショナリ、少数のロケール、またはプロトタイピング中に最適です。

      getIntlayerAsyncv9.4 から利用可能)は getIntlayer のような動作をしますが、ビルドプラグインはマージされたディクショナリではなく、.intlayer/dynamic_dictionaries/ のロケール別チャンクを指します。したがって、ページはそれがレンダリングするロケールのみを配信します。そのチャンクはオンデマンドで読み込まれるため、headasync になります:

      src/routes/{-$locale}/index.tsx
      import { createFileRoute } from "@tanstack/react-router";
      import {
        defaultLocale,
        getIntlayerAsync,
        getLocalizedUrl,
        localeMap,
      } from "intlayer";
      
      export const Route = createFileRoute("/{-$locale}/")({
        component: RouteComponent,
        head: async ({ params }) => {
          const { locale = defaultLocale } = params;
          const path = "/"; // このルートのパス
      
          const metaContent = await getIntlayerAsync("app", locale);
      
          return {
            links: [
              // 正規リンク: 現在のローカライズされたページを指す
              { rel: "canonical", href: getLocalizedUrl(path, locale) },
      
              // Hreflang: すべてのローカライズされたバージョンについて Google に通知
              ...localeMap(({ locale: mapLocale }) => ({
                rel: "alternate",
                hrefLang: mapLocale,
                href: getLocalizedUrl(path, mapLocale),
              })),
      
              // x-default: マッチしない言語のユーザー向け
              // デフォルトのフォールバックロケールを定義(通常、プライマリ言語)
              {
                rel: "alternate",
                hrefLang: "x-default",
                href: getLocalizedUrl(path, defaultLocale),
              },
            ],
            meta: [
              { title: metaContent.title },
              { name: "description", content: metaContent.meta.description },
            ],
          };
        },
      });
      
      head が複数のディクショナリを読む場合、Promise.all で解決してください: 各 getIntlayerAsync を独自の行で待機すると、リクエストが並行実行ではなく直列実行されます。

      トレードオフ: 動的インポートは head が実行されている間に、ドキュメントレンダリングの重大パス上で解決されます。コールドルートでは、これにより head を数ミリ秒遅延させ、LCP をわずかに低下させる可能性があります。

      ルート loader でディクショナリを解決し、headloaderData から読み直してください。マッチされたルートのローダーは並行実行され、staleTime: Infinity は TanStack Router に結果が決してstaleにならないことを伝えるため、ロケール別チャンクは一度解決され、その後ルーターキャッシュから提供されるため、head は同期のままです。

      src/routes/{-$locale}/index.tsx
      import { createFileRoute } from "@tanstack/react-router";
      import {
        defaultLocale,
        getIntlayerAsync,
        getLocalizedUrl,
        localeMap,
      } from "intlayer";
      
      export const Route = createFileRoute("/{-$locale}/")({
        component: RouteComponent,
        // 他のマッチされたルートと並行実行され、head の重大パスから外れる
        loader: async ({ params }) => {
          const { locale = defaultLocale } = params;
      
          return { metaContent: await getIntlayerAsync("app", locale) };
        },
        // 与えられたロケールに対してディクショナリは決して変わらない: チャンクを一度解決
        staleTime: Infinity,
        head: ({ params, loaderData }) => {
          const { locale = defaultLocale } = params;
          const path = "/"; // このルートのパス
      
          return {
            links: [
              // 正規リンク: 現在のローカライズされたページを指す
              { rel: "canonical", href: getLocalizedUrl(path, locale) },
      
              // Hreflang: すべてのローカライズされたバージョンについて Google に通知
              ...localeMap(({ locale: mapLocale }) => ({
                rel: "alternate",
                hrefLang: mapLocale,
                href: getLocalizedUrl(path, mapLocale),
              })),
      
              // x-default: マッチしない言語のユーザー向け
              // デフォルトのフォールバックロケールを定義(通常、プライマリ言語)
              {
                rel: "alternate",
                hrefLang: "x-default",
                href: getLocalizedUrl(path, defaultLocale),
              },
            ],
            meta: [
              { title: loaderData?.metaContent.title },
              {
                name: "description",
                content: loaderData?.metaContent.meta.description,
              },
            ],
          };
        },
      });
      
      head はローダーが確定する前に呼び出される可能性があるため、loaderDataundefined の可能性があるとして型付けされています。オプショナルチェーニングを保持するか、フォールバックタイトルを返してください。

      head の重大パスでその コストを支払うことなく、ロケール別チャンクを保持します。代金は開発者体験です: コンテンツは loaderData を通じてローダーから head に明示的にスレッド処理される必要があります。

      どの解決方法を選ぶべき?

      静的解決 動的解決 キャッシュされた動的解決
      API getIntlayer getIntlayerAsync (v9.4+) getIntlayerAsync in loader (v9.4+)
      head signature synchronous async synchronous, reads loaderData
      Locales shipped every declared locale requested locale only requested locale only
      Client navigations nothing to resolve re-entered on every match served from the router cache
      Developer experience simplest one await content threaded through loaderData

    14. サーバーアクションでロケールを取得する

      サーバーアクションまたはAPIエンドポイント内から現在のロケールにアクセスしたい場合があります。 intlayer から getLocale ヘルパーを使用してこれを実行できます。

      TanStack Start のサーバー関数を使用した例を示します:

      src/routes/{-$locale}/index.tsx
      import { createServerFn } from "@tanstack/react-start";
      import {
        getRequestHeader,
        getRequestHeaders,
      } from "@tanstack/react-start/server";
      import { getCookie, getIntlayer, getLocale } from "intlayer";
      
      export const getLocaleServer = createServerFn().handler(async () => {
        const locale = await getLocale({
          // リクエストからクッキーを取得(デフォルト:'INTLAYER_LOCALE')
          getCookie: (name) => {
            const cookieString = getRequestHeader("cookie");
      
            return getCookie(name, cookieString);
          },
          // リクエストからヘッダーを取得(デフォルト:'x-intlayer-locale')
          // Accept-Language ネゴシエーションを使用したフォールバック
          getHeader: (name) => getRequestHeader(name),
        });
      
        // getIntlayerAsync() を使用してコンテンツを取得
        const content = getIntlayer("app", locale);
      
        return { locale, content };
      });
      

    15. 見つからないページを管理する

      ユーザーが存在しないページにアクセスした場合、カスタム見つからないページを表示できます。ロケールプレフィックスは見つからないページがトリガーされる方法に影響を与える可能性があります。

      ローカライズされたホームページ

      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フックの詳細については、ドキュメントを参照してください。
    16. src/components/locale-switcher.tsx
      import { useLocation } from "@tanstack/react-router";
      import {
        getHTMLTextDir,
        getLocaleName,
        getPathWithoutLocale,
        getPrefix,
        Locales,
      } from "intlayer";
      import type { FC } from "react";
      import { useLocale } from "react-intlayer";
      
      import { LocalizedLink, type To } from "./localized-link";
      
      export const LocaleSwitcher: FC = () => {
        const { pathname } = useLocation();
      
        const { availableLocales, locale, setLocale } = useLocale();
      
        const pathWithoutLocale = getPathWithoutLocale(pathname);
      
        return (
          <ol>
            {availableLocales.map((localeEl) => (
              <li key={localeEl}>
                <LocalizedLink
                  aria-current={localeEl === locale ? "page" : undefined}
                  onClick={() => setLocale(localeEl)}
                  params={{ locale: getPrefix(localeEl).localePrefix }}
                  to={pathWithoutLocale as To}
                >
                  <span>
                    {/* ロケール - 例: FR */}
                    {localeEl}
                  </span>
                  <span>
                    {/* そのロケール自体での言語名 - 例: Français */}
                    {getLocaleName(localeEl, locale)}
                  </span>
                  <span dir={getHTMLTextDir(localeEl)} lang={localeEl}>
                    {/* 現在のロケールでの言語名 - 例: Locales.SPANISH の場合 Francés */}
                    {getLocaleName(localeEl)}
                  </span>
                  <span dir="ltr" lang={Locales.ENGLISH}>
                    {/* 英語での言語名 - 例: French */}
                    {getLocaleName(localeEl, Locales.ENGLISH)}
                  </span>
                </LocalizedLink>
              </li>
            ))}
          </ol>
        );
      };
      
      useLocaleフックの詳細については、ドキュメントを参照してください。

      </Step>

    17. HTML属性の管理

      return ( {/* ... _/} ); } {/_ ... */} </html> ); }

      export const Route = createFileRoute("/{-$locale}/")({ component: RouteComponent, head: async ({ params }) => { const { locale = defaultLocale } = params; const path = "/"; // The path for this route

      plaintext
      const metaContent = await getIntlayerAsync("app", locale);
      plaintext
      
      > `head` はローダーの解決前に呼ばれることがあるため、`loaderData` は `undefined` の可能性がある型になります。オプショナルチェーンを残すか、フォールバックのタイトルを返してください。
      
      ロケール別チャンクの利点を保ちつつ、そのコストを `head` のクリティカルパスで支払わずに済みます。代償は DX です。コンテンツをローダーから `head` へ `loaderData` 経由で明示的に受け渡す必要があります。
      
      </Tab>
      
      </Tabs>
      
      ### どの解決方法を選ぶべきか
      
      |                     | 静的解決                   | 動的解決                    | キャッシュ付き動的解決                    |
      | ------------------- | -------------------------- | --------------------------- | ----------------------------------------- |
      | API                 | `getIntlayer`              | `getIntlayerAsync`(v9.4+) | `loader` 内の `getIntlayerAsync`(v9.4+) |
      | `head` のシグネチャ | 同期                       | `async`                     | 同期、`loaderData` を読む                 |
      | 配信されるロケール  | 宣言されたすべてのロケール | 要求されたロケールのみ      | 要求されたロケールのみ                    |
      | クライアント遷移    | 解決するものなし           | マッチのたびに再実行        | ルーターのキャッシュから提供              |
      | DX                  | 最もシンプル               | `await` が 1 つ             | コンテンツを `loaderData` 経由で受け渡し  |
      
      ---
      
      
    18. サーバーアクションでのロケールの取得

      サーバーアクションやAPIエンドポイント内から現在のロケールにアクセスしたい場合があります。 Intlayerの getLocale ヘルパーを使用してこれを行うことができます。

      以下は、TanStack Startのサーバー関数を使用した例です:

      src/routes/{-$locale}/index.tsx
            return getCookie(name, cookieString);
          },
          // リクエストからヘッダーを取得する(デフォルト:'x-intlayer-locale')
          // Accept-Languageネゴシエーションを使用したフォールバック
          getHeader: (name) => getRequestHeader(name),
        });
      
        // getIntlayer()を使用してコンテンツを取得する
        const content = getIntlayer("app", locale);
      
      

      `


    19. 「見つかりませんでした」ページの管理

      ユーザーが存在しないページにアクセスしたときにカスタムの404ページを表示できます。ロケール接頭辞は、404ページがトリガーされる方法に影響を与える可能性があります。

      ロケール接頭辞を使用したTanStack Routerの404処理の理解

      TanStack Routerでは、ローカライズされたルートでの404ページの処理には多層的なアプローチが必要です:

      1. 専用の404ルート: 404 UIを表示するための特定のルート
      2. ルートレベルの検証: ロケール接頭辞を検証し、無効なものを404にリダイレクトします
      3. キャッチオールルート: ロケールセグメント内の一致しないパスをすべてキャプチャします
      src/routes/{-$locale}/404.tsx
      
      
      src/routes/{-$locale}/route.tsx
      
      
      src/routes/{-$locale}/$.tsx
      
      
    20. コンポーネントのコンテンツを抽出する

      オプション
    21. 既存のコードベースがある場合、数千のファイルを変換するのは時間がかかることがあります。

      このプロセスを容易にするために、Intlayerは、コンポーネントを変換しコンテンツを抽出するための コンパイラ / エクストラクタ を提案しています。

      セットアップするには、intlayer.config.ts ファイルに compiler セクションを追加します。

      intlayer.config.ts
      import { type IntlayerConfig } from "intlayer";
      
      const config: IntlayerConfig = {
        // ... 他の構成
        compiler: {
          /**
           * コンパイラを有効にするかどうかを指定します。
           */
          enabled: true,
      
          /**
           * 出力ファイルのパスを定義します。
           */
          output: ({ fileName, extension }) => `./${fileName}${extension}`,
      
          /**
           * 変換後にコンポーネントを保存するかどうかを指定します。
           *
           * - `true` の場合、コンパイラはディスク上のコンポーネントファイルを書き換えます。変換は永続的になり、次回のプロセスではスキップされます。これにより、アプリの変換後にコンパイラを削除できます。
           *
           * - `false` の場合、コンパイラはビルド出力のコードにのみ `useIntlayer()` 関数呼び出しを注入し、元のコードベースはそのまま維持します。変換はメモリ内でのみ行われます。
           */
          saveComponents: false,
      
      

      コンポーネントを変換してコンテンツを抽出するためにエクストラクタを実行します

      bash
      
      

      bun x intlayer extract import { intlayer, intlayerCompiler } from "vite-intlayer"; import { defineConfig } from "vite"; import { devtools } from "@tanstack/devtools-vite"; import { tanstackStart } from "@tanstack/react-start/plugin/vite"; import viteReact from "@vitejs/plugin-react";

      export default defineConfig({ plugins: [

      plaintext
      devtools(),
      tanstackStart({
        router: {
          routeFileIgnorePattern:
            ".content.(ts|tsx|js|mjs|cjs|jsx|json|jsonc|json5|md|mdx|yaml|yml)$",
        },
      }),
      viteReact(),
      intlayer(),
      intlayerCompiler(), // Adds the compiler plugin

      ], });

      plaintext
      
      

      bash packageManager="npm" npm run build # または npm run dev

      plaintext
      
      

      bash packageManager="pnpm" pnpm run build # または pnpm run dev

      plaintext
      
      

      bash packageManager="yarn" yarn build # Or yarn dev

      plaintext
      
      

      bash packageManager="bun"


      1. BLOCK 2 of 3 - 英語(en)のソース
      2. BLOCK 2 of 3 - 日本語(ja)の現在の翻訳

      その後、監査を実施し、完全に更新された日本語ファイルを返します。---

      bun run build # またはbun run dev import { localeFlatMap } from "intlayer"; // ... その他のインポート

      export default defineConfig({ plugins: [

      plaintext
      // ... その他のプラグイン
      tanstackStart({
        // ... その他の設定
        sitemap: {
          enabled: false,
        },
        prerender: {
          enabled: true,
          crawlLinks: false,
          concurrency: 10,
        },
        pages: localizedPages,
      }),

      ], });

      plaintext
      
      次に、`generateSitemap` 関数を使用する `src/routes/sitemap[.]xml.ts` ルートを作成します。
      
      

      `typescript fileName="src/routes/sitemap[.]xml.ts"


      export const Route = createFileRoute("/sitemap.xml")({ server: {

      plaintext
      handlers: {
        GET: async () => {
          const sitemap = generateSitemap(
            [
              { path: "/", changefreq: "daily", priority: 1.0 },
              { path: "/about", changefreq: "monthly", priority: 0.8 },
            ],
            { siteUrl: SITE_URL }
          );
      
          return new Response(sitemap, {
            headers: { "Content-Type": "application/xml" },
          });
        },
      },

      }, }); { // ... 既存の構成 include: [

      plaintext
      // ... 既存の包含
      ".intlayer/**/*.ts", // 自動生成された型を含める

      ], }

      Git Configuration

      Intlayerによって生成されたファイルを無視することをお勧めします。これにより、Gitリポジトリにコミットするのを避けることができます。

      これを行うには、.gitignoreファイルに以下の指示を追加できます:

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

      `


      VS Code Extension

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

      VS Code Marketplace からインストール

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

      • 翻訳キーの自動補完
      • 欠落している翻訳のリアルタイムエラー検出
      • 翻訳されたコンテンツのインラインプレビュー
      • 翻訳を簡単に作成・更新するクイックアクション

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


      さらに進む

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


      ドキュメント参考資料