著者:
    作成:2024-03-07最終更新:2026-09-27

    Intlayerを使用したAstroサイトの翻訳

    ide.intlayer.org
    intlayer-astro-template.vercel.app

    目次

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

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

    Intlayer は、多言語ルーティング、サイトマップ、および国際化 (i18n) の拡張に必要なすべての機能を提供することで、Astro と完全に連携するように最適化されています。

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

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

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

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

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

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

    AstroへのIntlayer設定ステップバイステップガイド

    GitHubでアプリケーションテンプレートを表示。

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

      必要なパッケージをパッケージマネージャーを使用してインストールしてください:

      bash
      npx intlayer init --interactive
      
      --interactive フラグはオプションです。AI エージェントの場合は intlayer-cli init を使用してください。

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

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

      • astro-intlayer Intlayer を Vite バンドラー と統合する Astro 統合プラグイン、各リクエストのロケールを Astro.locals.intlayer に解決するミドルウェア、および useIntlayer / useDictionary / useLocale フックが含まれています。同じインポートパスが .astro フロントマターのサーバー実装と <script> ブロック内のクライアント実装(vanilla-intlayer ベース)に解決されます。

    2. プロジェクトの設定

      アーキテクチャ

      このアーキテクチャでは、astro.config.ts に登録された intlayer() 統合が辞書をビルドし、各リクエストのロケールを解決して Astro.locals.intlayer に公開するミドルウェアを追加します。ページは src/pages/[...locale]/ レストセグメントの下に配置されるため、デフォルトロケールはプレフィックスなしで提供され、他のすべてのロケールには専用の URL が割り当てられます。.astro ファイルは astro-intlayer の useIntlayer / useLocale フックを使用してコンテンツを読み取り、コンテンツ宣言は src/ 内のコンポーネントと一緒に配置されます。

      bash
      .
      ├── src
      │   ├── app.content.tsx               # App content declaration
      │   ├── components
      │   │   └── LocaleSwitcher.astro      # Locale switcher component
      │   └── pages
      │       ├── [...locale]
      │       │   └── index.astro           # Localized page (rest param also serves the default locale)
      │       ├── robots.txt.ts             # robots.txt endpoint
      │       └── sitemap.xml.ts            # Localized sitemap endpoint
      ├── astro.config.ts                   # Astro config with the intlayer() integration
      ├── intlayer.config.ts
      ├── package.json
      └── tsconfig.json
      

      設定

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

      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. Astro設定へのIntlayerの統合

      Astroの設定にintlayerプラグインを追加します。

      astro.config.ts
      // @ts-check
      
      import { intlayer } from "astro-intlayer";
      import { defineConfig } from "astro/config";
      
      // https://astro.build/config
      export default defineConfig({
        integrations: [intlayer()],
      });
      
      Astro統合プラグイン intlayer() は、IntlayerをAstroと統合するために使用されます。コンテンツ宣言ファイルの構築を確実にし、開発モードで監視します。Astroアプリケーション内でIntlayerの環境変数を定義し、パフォーマンス最適化のためのエイリアスを提供します。
    4. コンテンツの宣言

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

      src/app.content.tsx
      import { t, type Dictionary } from "intlayer";
      import type { ReactNode } from "react";
      
      const appContent = {
        key: "app",
        content: {
          title: t({
            en: "Hello World",
            fr: "Bonjour le monde",
            es: "Hola mundo",
            ja: "こんにちは世界",
          }),
        },
      } satisfies Dictionary;
      
      export default appContent;
      
      コンテンツ宣言は、contentDir(デフォルトは ./src)に含まれ、コンテンツ宣言ファイルの拡張子(デフォルトは .content.{json,ts,tsx,js,jsx,mjs,cjs,md,mdx,yaml,yml})と一致していれば、アプリケーション内のどこにでも定義できます。
      詳細については、コンテンツ宣言のドキュメントを参照してください。
    5. Astroでのコンテンツの使用

      astro-intlayer がエクスポートするフックを使用して、.astro ファイルで辞書を利用します。これらは react-intlayer と同じシグネチャを共有しており、useIntlayer("key") は辞書の内容を返し、useLocale() は現在のロケールを引数なしで返します。

      ロケールは astro-intlayer ミドルウェアから取得されます。このミドルウェアは独自の src/middleware.ts の前に登録され、各リクエストについて URL プレフィックス、クライアントが保持するロケール(Cookie またはヘッダー)、Accept-Language の順に解決し、Astro.locals.intlayer に保存します。事前レンダリングされたページは訪問者ごとに一度だけレンダリングされるため、URL のみを使用します。

      また、各ページに hreflang や正規リンクなどの SEO メタデータを追加し、ユーザーが言語を切り替えられるように言語スイッチャーを含める必要があります。

      src/pages/index.astro
      ---
      import { useIntlayer, useLocale } from "astro-intlayer";
      import {
        getLocalizedUrl,
        defaultLocale,
        localeMap,
        getHTMLTextDir,
      } from "intlayer";
      import LocaleSwitcher from "../components/LocaleSwitcher.astro";
      
      // ミドルウェアによって解決されたロケール(例: /ja/about -> 'ja')
      const { locale } = useLocale();
      
      // そのロケールの 'app' 辞書の内容
      const { title } = useIntlayer("app");
      ---
      
      <!doctype html>
      <html lang={locale} dir={getHTMLTextDir(locale)}>
        <head>
          <meta charset="utf-8" />
          <meta name="viewport" content="width=device-width" />
          <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
          <title>{title}</title>
      
          <!-- Canonical link: Tells search engines which is the primary version of this page -->
          <link
            rel="canonical"
            href={new URL(getLocalizedUrl(Astro.url.pathname, locale), Astro.site)}
          />
      
          <!-- Hreflang: Tell Google about all localized versions -->
          {
            localeMap(({ locale: mapLocale }) => (
              <link
                rel="alternate"
                hreflang={mapLocale}
                href={new URL(
                  getLocalizedUrl(Astro.url.pathname, mapLocale),
                  Astro.site
                )}
              />
            ))
          }
      
          <!-- x-default: Fallback for users in unmatched languages -->
          <link
            rel="alternate"
            hreflang="x-default"
            href={new URL(
              getLocalizedUrl(Astro.url.pathname, defaultLocale),
              Astro.site
            )}
          />
        </head>
        <body>
          <header>
            <LocaleSwitcher />
          </header>
          <main>
            <h1>{title}</h1>
          </main>
        </body>
      </html>
      
      Astro.locals.intlayer は、独自のミドルウェアやエンドポイントにも locale、defaultLocale、availableLocales を公開します。第2引数としてロケールまたはセレクターを渡すことで(useIntlayer("app", "fr")、useIntlayer("faq", { item: 2 }))、1回の呼び出しに対してリクエストロケールを上書きできます。
    6. ローカライズされたルーティング

      ローカライズされたページを提供するための動的なルートセグメントを作成します(例:src/pages/[locale]/index.astro):

      src/pages/[locale]/index.astro
      <!-- astro -->
      ---
      import { getIntlayer } from "intlayer";
      
      const { title } = getIntlayer('app');
      ---
      
      <h1>{title}</h1>
      

      Astro統合により、開発中に言語認識ルーティングや環境定義を支援するViteミドルウェアが追加されます。独自のロジックや intlayer の getLocalizedUrl などのユーティリティを使用して、言語間のリンクを作成することもできます。

    7. 言語切り替え器の追加

      ユーザーが言語を切り替えられるようにするために、LocaleSwitcherコンポーネントを作成できます。このコンポーネントは、サポートされているすべてのロケールのリストを表示し、各言語の同じページへのリンクを提供する必要があります。

      src/components/LocaleSwitcher.astro
      ---
      import { useLocale } from "astro-intlayer";
      import { getLocaleName, getLocalizedUrl, getPathWithoutLocale } from "intlayer";
      
      const { locale, availableLocales } = useLocale();
      const pathWithoutLocale = getPathWithoutLocale(Astro.url.pathname);
      ---
      
      <nav aria-label="Languages">
        <ul>
          {
            availableLocales.map((localeItem) => (
              <li key={localeItem} class="p-1">
                <a
                  href={getLocalizedUrl(pathWithoutLocale, localeItem)}
                  data-locale={localeItem}
                  aria-current={localeItem === locale ? "page" : undefined}
                >
                  {getLocaleName(localeItem)}
                </a>
              </li>
            ))
          }
        </ul>
      </nav>
      
      <script>
        // ブラウザ内では、同じインポートがクライアント実装に解決されます
        import { useLocale } from "astro-intlayer";
        import { getLocalizedUrl, type LocalesValues } from "intlayer";
      
        // 選択をロケール Cookie に保存し、ローカライズされた URL に移動します
        const { setLocale } = useLocale({
          onLocaleChange: (newLocale) => {
            window.location.href = getLocalizedUrl(window.location.pathname, newLocale);
          },
        });
      
        const localeLinks = document.querySelectorAll("[data-locale]");
      
        localeLinks.forEach((link) => {
          link.addEventListener("click", (event) => {
            const locale = link.getAttribute("data-locale") as LocalesValues;
      
            event.preventDefault();
            setLocale(locale);
          });
        });
      </script>
      
      <style>
        nav {
          display: flex;
          gap: 1rem;
        }
        ul {
          display: flex;
          list-style: none;
          padding: 0;
          margin: 0;
          gap: 0.5rem;
        }
        a[aria-current="page"] {
          font-weight: bold;
          text-decoration: underline;
        }
      </style>
      

      永続化に関する注意: クライアント側の useLocale による setLocale は、ユーザーの言語設定を cookie に保存します。これにより、Intlayer は選択を記憶し、今後のアクセス時にユーザーを希望する言語に自動的にリダイレクトできます。オンデマンドレンダリングされたページ(output: 'server' または prerender = false のアダプター)は HTML が送信される前に Intlayer ミドルウェアによってリダイレクトされ、静的ファイルとして提供される事前レンダリングされたページは、統合機能が各ページに注入する小さなスクリプトによってリダイレクトされます。両方を無効にするには routing.enableProxy を false に設定します。astro dev では、routing.enableProxy が true に設定されていない限り cookie はリダイレクト元として無視されるため、古い cookie が作業中のページをハイジャックすることはありません。

      サーバー / クライアント間の相互互換性: astro-intlayer は、フロントマター内ではサーバーフック(Astro.locals の読み取り)に、<script> ブロックおよびアイランド内では vanilla-intlayer のクライアントフックに解決され、同じ名前とデータ構造を持ちます。setLocale と onChange はクライアント上でのみ動作します。クライアントストアを初期化するために、クライアント側で一度 installIntlayer() を呼び出してください。astro-intlayer/client はクライアントエントリを明示的に公開します。

    8. サイトマップとRobots.txt

      Intlayerは、動的にローカライズされたサイトマップとrobots.txtファイルを生成するためのユーティリティを提供します。

      サイトマップ

      Intlayer には、アプリケーションのサイトマップを簡単に作成できるサイトマップ ジェネレーターが組み込まれています。ローカライズされたルートを処理し、検索エンジンに必要なメタデータを追加します。

      Intlayer によって生成されたサイトマップは、xhtml:link 名前空間 (Hreflang XML Extensions) をサポートしています。生の URL のみを表示するデフォルトのサイトマップ ジェネレーターとは異なり、Intlayer はページのすべての言語バージョン (例: /about、/about?lang=fr、/about?lang=es) 間に必要な双方向リンクを自動的に作成します。これにより、検索エンジンが正しい言語バージョンを正しい対象者に正しくインデックス付けして提供できるようになります。

      すべてのローカライズされたルートを含むサイトマップを生成するために、src/pages/sitemap.xml.ts を作成します。

      src/pages/sitemap.xml.ts
      import type { APIRoute } from "astro";
      import { generateSitemap, type SitemapUrlEntry } from "intlayer";
      
      const pathList: SitemapUrlEntry[] = [
        { path: "/", changefreq: "daily", priority: 1.0 },
        { path: "/about", changefreq: "monthly", priority: 0.7 },
      ];
      
      export const GET: APIRoute = async ({ site }) => {
        const xmlOutput = generateSitemap(pathList, {
          siteUrl: "https://example.com",
        });
      
        return new Response(xmlOutput, {
          headers: { "Content-Type": "application/xml" },
        });
      };
      

      Robots.txt

      検索エンジンのクロールを制御するために src/pages/robots.txt.ts を作成します。

      src/pages/robots.txt.ts
      import type { APIRoute } from "astro";
      import { getMultilingualUrls } from "intlayer";
      
      const getAllMultilingualUrls = (urls: string[]) =>
        urls.flatMap((url) => Object.values(getMultilingualUrls(url)) as string[]);
      
      const disallowedPaths = getAllMultilingualUrls(["/admin", "/private"]);
      
      export const GET: APIRoute = ({ site }) => {
        const robotsTxt = [
          "User-agent: *",
          "Allow: /",
          ...disallowedPaths.map((path) => `Disallow: ${path}`),
          "",
          `Sitemap: ${new URL("/sitemap.xml", site).href}`,
        ].join("\n");
      
        return new Response(robotsTxt, {
          headers: { "Content-Type": "text/plain" },
        });
      };
      
    9. お好みのフレームワークの使用を続ける

      お好みのフレームワークを使用してアプリケーションを構築し続けましょう。

    10. Extract the content of your components

      オプション

      If you have an existing codebase, transforming thousands of files can be time-consuming.

      To ease this process, Intlayer propose a compiler / extractor to transform your components and extract the content.

      To set it up, you can add a compiler section in your intlayer.config.ts file:

      intlayer.config.ts
      import { type IntlayerConfig } from "intlayer";
      
      const config: IntlayerConfig = {
        // ... Rest of your config
        compiler: {
          /**
           * Indicates if the compiler should be enabled.
           */
          enabled: true,
      
          /**
           * Defines the output files path
           */
          output: ({ fileName, extension }) => `./${fileName}${extension}`,
      
          /**
           * Indicates if the components should be saved after being transformed.
           *
           * - If `true`, the compiler will rewrite the component file in the disk. So the transformation will be permanent, and the compiler will skip the transformation for the next process. That way, the compiler can transform the app, and then it can be removed.
           *
           * - If `false`, the compiler will inject the `useIntlayer()` function call into the code in the build output only, and keep the base codebase intact. The transformation will be done only in memory.
           */
          saveComponents: false,
      
          /**
           * Dictionary key prefix
           */
          dictionaryKeyPrefix: "",
        },
      };
      
      export default config;
      

      Run the extractor to transform your components and extract the content

      bash
      npx intlayer extract
      

      アプリケーションをビルドしてコンポーネントを変換し、コンテンツを抽出します。

      bash
      npm run build # Or npm run dev
      

    TypeScriptの設定

    Intlayerはモジュール拡張(module augmentation)を使用してTypeScriptの利点を活かし、コードベースをより堅牢にします。

    オートコンプリート

    翻訳エラー

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

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

    Gitの設定

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

    そのためには、.gitignoreファイルに以下の指示を追加してください:

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

    VS Code拡張機能

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

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

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

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

    さらに詳しく

    さらに詳しく知りたい場合は、ビジュアルエディターを実装したり、CMSを使用してコンテンツを外部化したりすることもできます。

    よくある質問

    Astroはロケールプレフィックスとリダイレクトを処理するルーティングレベルのi18nオプションを提供しますが、コンテンツ自体は管理しないため、メッセージレイヤーが依然として必要です。

    • Astroの組み込みi18nと手書きのJSONまたはTypeScript辞書:依存関係はありませんが、型付け、複数形ルール、ツールはありません。
    • island内のi18nextまたはvue-i18n / svelte-i18n:各islandフレームワークごとに完全なライブラリがあり、それぞれ独自のカタログを持ちます。
    • Intlayer:Astroページとすべてのislandフレームワークで共有される単一のコンテンツレイヤー。ビルド時にコンパイルされ、完全に型付けされ、AI翻訳、ビジュアルエディター、CMSを備えています。

    Astro特有の利点は、islandランタイムごとにi18nライブラリを一つずつ用意する代わりに、同じ辞書が.astroページとReact、Vue、Svelte、Solid、Preact、またはLitのislandにサービスを提供することです。Intlayerの利点をご覧ください。

    名前空間ベースのセットアップよりもはるかに少ないです。なぜなら、ページはレンダリングしないカタログをダウンロードしないからです。Astroページはビルド時にレンダリングされるため、翻訳されたHTMLを配信し、辞書は一切含まれません。islandのみが辞書を受け取ります。ビルド時コンパイラは、コンポーネントが使用する正確なエントリにコンテンツ呼び出しを解決し、動的辞書が残りをロケールごとに分割します。一般的な代替案と比較して、Intlayerはbundleとページサイズを最大50%削減します。bundle最適化とベンチマークをご覧ください。

    大部分は可能です。コンテンツを移行するには、i18next移行ガイドに従ってください。段階的に移行することも可能です。sync JSON pluginは、既存のJSONカタログを信頼できる情報源として保持し、それらからIntlayer辞書を生成するため、コンポーネントを一つずつ移行する間も両方のレイヤーが同期を保ちます。

    はい、可能です。sync JSON pluginは、/messages/{locale}/{namespace}.jsonファイルを信頼できる情報源として保持し、双方向でそれらからIntlayer辞書を生成します。sync PO pluginはgettextカタログに対しても同様の機能を提供し、ロケールごとのファイルを使用すると、ロケールを1つのファイルにまとめるのではなく、言語ごとにコンテンツを分割できます。

    いいえ、必要ありません。npx intlayer extractを実行すると、Intlayerがコンポーネントを読み込み、ユーザー向けの文字列を抽出し、それぞれの隣に.contentファイルを書き込みます。これにより、文字列をカタログに一つずつコピーする代わりに、差分を確認できます。このガイドのステップ15で詳しく説明しています。

    完全に自動化されたパイプラインの場合、Intlayer Compilerがビルド時に同様の処理を行います。変更があるたびにJSX、TSX、Vue、Svelteのソースをスキャンし、辞書を生成し、ホットモジュールリプレイスメントを通じて同期を保つため、手動でキーを管理する必要は一切ありません。

    コンパイラを有効にする前に知っておくべき2つの制限があります。静的解析によって機能するため、APIエラーコードやCMSフィールドなど、実行時にのみ存在する文字列は対象外となります。また、className="active"やステータスコードのようなアプリケーションロジックとユーザー向けのテキストを区別する必要があり、大規模なコードベースではいくつかの注釈が必要になります。extract commandは、ユーザーが関与することでこれら両方を回避します。

    5つのツールがあり、すべてオプションです。

    • VS Code extension: useIntlayerキーからそれを宣言するコンテンツファイルにジャンプしたり、コンポーネントからコンテンツを抽出したり、コマンドパレットまたは専用のIntlayerタブからビルド、フィル、テスト、プッシュ、プルを実行したりできます。
    • LSP server: LSPをサポートするあらゆるエディターで同様の認識機能を提供し、定義へのジャンプ、すべての参照の検索、翻訳された値のホバープレビュー、キーとフィールドのオートコンプリート、およびキーがどこにも宣言されていない場合の警告を表示します。また、i18next、react-i18next、next-intl、use-intlの呼び出しも解決するため、移行中に役立ちます。
    • MCP server: IntlayerのドキュメントとCLIをCursor、VS Code、Claude Desktop、Claude Code、ChatGPTに公開するため、アシスタントは推測ではなく現在のドキュメントから回答し、intlayer fillなどのコマンドを自身で実行できます。
    • Agent skills: intlayer-config、intlayer-cli、intlayer-contentなどの特化されたスキルに加え、フレームワークごとのスキルがあり、エージェントにルーティング設定とコンテンツノードタイプを教えます。
    • ESLint plugin: no-raw-textはハードコードされた文字列を検出し、静的辞書キーや未使用のコンテンツに対する追加ルールも提供します。