著者:
    作成:2026-04-24最終更新:2026-08-30

    Intlayerを使用したAstro + Vueサイトの翻訳 | 国際化 (i18n)

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

    目次

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

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

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

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

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

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

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

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

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

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

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

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

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

      bash
      npx intlayer init --interactive
      
      --interactive フラグはオプションです。AI エージェントの場合は intlayer-cli init を使用してください。
      このコマンドは環境を検出し、必要なパッケージをインストールします。例えば:
      bash
      npm install intlayer astro-intlayer vue vue-intlayer @astrojs/vue
      
      • intlayer 設定管理、翻訳、コンテンツ宣言、トランスパイル、およびCLIコマンドのための国際化ツールを提供するコアパッケージ。

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

      • vue コアVueパッケージ。

      • vue-intlayer IntlayerをVueアプリケーションと統合するパッケージ。Vueにおける国際化のための installIntlayer および useIntlayeruseLocale コンポーザブルを提供します。

      • @astrojs/vue Vueコンポーネントアイランドの使用を可能にする公式のAstro統合。

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

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

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

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

      src/app.content.ts
      import { t, type Dictionary } from "intlayer";
      
      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でのコンテンツの使用

      intlayerからエクスポートされたコアヘルパーを使用して、.astroファイル内で直接辞書を消費できます。また、各ページにhreflangや正規リンクなどのSEOメタデータを追加し、クライアントサイドのインタラクティブなコンテンツのためにVueアイランドを組み込む必要があります。

      src/pages/[...locale]/index.astro
      ---
      import {
        getIntlayer,
        getLocaleFromPath,
        getLocalizedUrl,
        getHTMLTextDir,
        getPrefix,
        localeMap,
        defaultLocale,
        type LocalesValues,
      } from "intlayer";
      import VueIsland from "../../components/vue/VueIsland.vue";
      
      export const getStaticPaths = () => {
        return localeMap(({ locale }) => ({
          params: { locale: getPrefix(locale).localePrefix },
        }));
      };
      
      const locale = getLocaleFromPath(Astro.url.pathname) as LocalesValues;
      const { title } = getIntlayer("app", locale);
      ---
      
      <!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>
      
          <!-- 正規リンク: このページのプライマリバージョンであることを検索エンジンに伝えます -->
          <link
            rel="canonical"
            href={new URL(getLocalizedUrl(Astro.url.pathname, locale), Astro.site)}
          />
      
          <!-- Hreflang: すべてのローカライズされたバージョンについてGoogleに伝えます -->
          {
            localeMap(({ locale: mapLocale }) => (
              <link
                rel="alternate"
                hreflang={mapLocale}
                href={new URL(
                  getLocalizedUrl(Astro.url.pathname, mapLocale),
                  Astro.site
                )}
              />
            ))
          }
      
          <!-- x-default: 言語が一致しないユーザー向けのフォールバックオプション -->
          <link
            rel="alternate"
            hreflang="x-default"
            href={new URL(
              getLocalizedUrl(Astro.url.pathname, defaultLocale),
              Astro.site
            )}
          />
        </head>
        <body>
          <!-- Vueアイランドは言語切り替えを含むすべてのインタラクティブなコンテンツをレンダリングします -->
          <VueIsland locale={locale} client:only="vue" />
        </body>
      </html>
      

      ルーティング設定に関する注意: 使用するディレクトリ構造は、intlayer.config.tsmiddleware.routing 設定によります:

      • prefix-no-default(デフォルト): ルート(プレフィックスなし)にデフォルト言語を保持し、他の言語にはプレフィックスを付けます。すべてのケースをキャッチするために [...locale] を使用します。
      • prefix-all: すべてのURLに言語プレフィックスが付きます。ルートを個別に処理する必要がない場合は、標準の [locale] を使用できます。
      • search-param または no-prefix: ロケールフォルダは不要です。ロケールは検索パラメータまたはクッキーを通じて処理されます。
    6. Vueアイランドコンポーネントの作成

      Vueアプリケーションをラップし、サーバーによって検出されたロケールを受け取るアイランドコンポーネントを作成します。コンポーザブルを使用する前に、VueインスタンスにIntlayerプラグインを登録するために installIntlayer を呼び出す必要があります。

      src/components/vue/VueIsland.vue
      <script setup lang="ts">
      import { ref, getCurrentInstance } from "vue";
      import { useIntlayer, useLocale, installIntlayer } from "vue-intlayer";
      import { getLocalizedUrl, getLocaleName, type LocalesValues } from "intlayer";
      
      const props = defineProps<{ locale: LocalesValues }>();
      
      const app = getCurrentInstance()?.appContext.app;
      if (app) {
        installIntlayer(app, { locale: props.locale });
      }
      
      const {
        locale: currentLocale,
        availableLocales,
        setLocale,
      } = useLocale({
        onLocaleChange: (newLocale: LocalesValues) => {
          window.location.href = getLocalizedUrl(window.location.pathname, newLocale);
        },
      });
      
      const count = ref(0);
      const { title } = useIntlayer("app");
      </script>
      
      <template>
        <div>
          <h1>{{ title }}</h1>
          <!-- 言語切り替え器はアイランドのテンプレートにインラインでレンダリングされます -->
          <div class="locale-switcher">
            <span class="switcher-label">言語を切り替える:</span>
            <div class="locale-buttons">
              <button
                v-for="localeItem in availableLocales"
                :key="localeItem"
                :class="['locale-btn', { active: localeItem === currentLocale }]"
                :disabled="localeItem === currentLocale"
                @click="setLocale(localeItem)"
              >
                <span class="ls-own-name">{{ getLocaleName(localeItem) }}</span>
                <span class="ls-current-name">{{
                  getLocaleName(localeItem, currentLocale)
                }}</span>
                <span class="ls-code">{{ localeItem.toUpperCase() }}</span>
              </button>
            </div>
          </div>
        </div>
      </template>
      
      locale プロップはAstroページ(サーバー検出)から渡され、installIntlayer を初期化するために使用されます。これにより、コンポーネントツリー内のすべてのコンポーザブルのロケールがデフォルト設定されます。
    7. 言語切り替え機能の追加

      言語切り替え機能はVueアイランドのテンプレート(ステップ6参照)に直接組み込まれています。vue-intlayeruseLocale を使用し、ユーザーが新しい言語を選択したときにローカライズされたURLに移動します:

      src/components/vue/VueIsland.vue
      <script setup lang="ts">
      import { useLocale } from "vue-intlayer";
      import { getLocalizedUrl, getLocaleName, type LocalesValues } from "intlayer";
      
      // 前述のステップ6と同じprops/app設定を再利用...
      
      const {
        locale: currentLocale,
        availableLocales,
        setLocale,
      } = useLocale({
        onLocaleChange: (newLocale: LocalesValues) => {
          // 言語変更時にローカライズされたURLに移動
          window.location.href = getLocalizedUrl(window.location.pathname, newLocale);
        },
      });
      </script>
      
      <template>
        <div class="locale-switcher">
          <span class="switcher-label">言語を切り替える:</span>
          <div class="locale-buttons">
            <button
              v-for="localeItem in availableLocales"
              :key="localeItem"
              :class="['locale-btn', { active: localeItem === currentLocale }]"
              :disabled="localeItem === currentLocale"
              @click="setLocale(localeItem)"
            >
              <span class="ls-own-name">{{ getLocaleName(localeItem) }}</span>
              <span class="ls-current-name">{{
                getLocaleName(localeItem, currentLocale)
              }}</span>
              <span class="ls-code">{{ localeItem.toUpperCase() }}</span>
            </button>
          </div>
        </div>
      </template>
      

      固定の維持に関する注意: window.location.href を介したリダイレクトのために onLocaleChange を使用することで、新しい言語のURLが確実に訪問され、Intlayerミドルウェアが言語クッキーを設定して、将来の訪問時にユーザーの好みが記憶されるようになります。

    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 },
      ];
      
      const SITE_URL = import.meta.env.SITE ?? "http://localhost:4321";
      
      export const GET: APIRoute = async ({ site }) => {
        const xmlOutput = generateSitemap(pathList, { siteUrl: SITE_URL });
      
        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. 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
      
      Since v9, the intlayerCompiler is included in the intlayer plugin. So you don't need to add it manually.

      Update your vite.config.ts to include the intlayerCompiler plugin:

      vite.config.ts
      import { defineConfig } from "vite";
      import { intlayer, intlayerCompiler } from "vite-intlayer";
      
      export default defineConfig({
        plugins: [
          intlayer(),
          intlayerCompiler(), // Adds the compiler plugin
        ],
      });
      
      bash
      npm run build # Or npm run dev
      

    TypeScriptの設定

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

    オートコンプリート

    翻訳エラー

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

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

    Gitの設定

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

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

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

    VS Code拡張機能

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

    VS Code Marketplaceからインストール

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

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

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

    さらに詳しく

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

    よくある質問

    Astro の組み込み i18n オプションはロケールプレフィックスとリダイレクトを処理しますが、コンテンツ自体は処理しないため、メッセージレイヤーが依然として必要です。さらに、island は Astro ではなく Vue で動作するという別の問題があります。

    • Astro i18n と手書きの辞書、そして island 内の vue-i18n: 同期を保つべき2つのコンテンツソースがあり、それらの間に共有された型付けはありません。
    • Intlayer: 両方に対応する1つのコンテンツレイヤー。astro-intlayer.astro ページをカバーし、vue-intlayer は Vue island をカバーし、同じ宣言を読み込みます。

    ラベルを一度宣言し、それを静的ページとインタラクティブな island の両方で使用できることが、ここで単一のコンテンツレイヤーを選択する理由です。Intlayer を選ぶ理由をご覧ください。

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

    ほとんど可能です。コンテンツを移行するには、vue-i18n 移行ガイドに従ってください。段階的に移行することもできます。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 コマンドは、ユーザーが関与することでこれら両方を回避します。

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

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