メインコンテンツへスキップ
Code & Craft
Web制作 約8分で読めます

Astro i18nで実現する国際化対応とSEO設定の完全ガイド【2026年版】

Astro i18nを使った国際化対応の実装方法とSEO設定を徹底解説。多言語サイトのパフォーマンス最適化とhreflang設定まで実践的に紹介します。

グローバル市場を狙うWebサイトやサービスを運営するなら、多言語対応は避けて通れません。しかし、ただ翻訳するだけでは不十分です。検索エンジンに各言語版を正しく認識させ、ユーザーに最適な言語ページを届けるには、適切なSEO設定が必須です。

AstroはビルドタイムでのSSG(Static Site Generation)により、多言語サイトでも驚異的な速度を実現できるフレームワークです。2026年現在、Astro 4.xでは公式のi18nルーティング機能が標準搭載され、以前よりも圧倒的に簡単に国際化対応が可能になりました。

この記事では、Astro i18nの基本実装から、Google検索で各言語ページを適切にインデックスさせるためのSEO設定、さらにパフォーマンス最適化まで、実践的なコード例とともに解説します。

Astro i18nの基本セットアップ

Astro 4.0以降では、astro.config.mjsi18nオプションを追加するだけで、多言語ルーティングが有効になります。

プロジェクト構造

src/
├── pages/
│   ├── index.astro          # デフォルト言語(日本語)
│   ├── about.astro
│   ├── en/
│   │   ├── index.astro      # 英語版
│   │   └── about.astro
│   └── zh/
│       ├── index.astro      # 中国語版
│       └── about.astro
├── i18n/
│   ├── ja.json
│   ├── en.json
│   └── zh.json
└── components/
    └── LanguageSwitcher.astro

astro.config.mjs の設定

import { defineConfig } from 'astro/config';

export default defineConfig({
  i18n: {
    defaultLocale: 'ja',
    locales: ['ja', 'en', 'zh'],
    routing: {
      prefixDefaultLocale: false, // デフォルト言語に /ja をつけない
      redirectToDefaultLocale: true
    },
    fallback: {
      en: 'ja',
      zh: 'ja'
    }
  },
  site: 'https://example.com'
});

この設定により、以下のURLスキームが自動生成されます:

  • https://example.com/ → 日本語(デフォルト)
  • https://example.com/en/ → 英語
  • https://example.com/zh/ → 中国語

翻訳データの管理

src/i18n/ja.json:

{
  "nav.home": "ホーム",
  "nav.about": "私たちについて",
  "nav.contact": "お問い合わせ",
  "hero.title": "次世代Webフレームワークで構築しよう",
  "hero.description": "Astroで高速かつSEOに強いサイトを実現"
}

src/i18n/en.json:

{
  "nav.home": "Home",
  "nav.about": "About",
  "nav.contact": "Contact",
  "hero.title": "Build with Next-Gen Web Framework",
  "hero.description": "Create fast and SEO-friendly sites with Astro"
}

翻訳を読み込むヘルパー関数を作成:

// src/utils/i18n.ts
import ja from '../i18n/ja.json';
import en from '../i18n/en.json';
import zh from '../i18n/zh.json';

const translations = { ja, en, zh };

export function useTranslation(locale: string = 'ja') {
  return (key: string): string => {
    const keys = key.split('.');
    let value: any = translations[locale as keyof typeof translations];
    
    for (const k of keys) {
      value = value?.[k];
    }
    
    return value || key;
  };
}

Astroページでの使用例:

---
// src/pages/index.astro
import Layout from '../layouts/Layout.astro';
import { useTranslation } from '../utils/i18n';

const t = useTranslation('ja');
---

<Layout title={t('hero.title')}>
  <h1>{t('hero.title')}</h1>
  <p>{t('hero.description')}</p>
</Layout>

多言語サイトのSEO最適化設定

多言語サイトのSEOで最も重要なのは、検索エンジンに「このページの言語版はどこにあるのか」を正確に伝えることです。

hreflangタグの実装

hreflangタグは、各言語・地域版のページURLを検索エンジンに通知します。これがないと、Google検索で間違った言語のページが表示されたり、重複コンテンツとみなされるリスクがあります。

src/components/SEOHead.astro:

---
interface Props {
  title: string;
  description: string;
  locale: string;
  canonicalURL?: string;
  alternateURLs?: Record<string, string>;
}

const { 
  title, 
  description, 
  locale, 
  canonicalURL,
  alternateURLs = {}
} = Astro.props;

const site = import.meta.env.SITE || 'https://example.com';
const currentURL = canonicalURL || new URL(Astro.url.pathname, site).href;

// 言語コードからOGP用のlocale値に変換
const ogLocale = locale === 'ja' ? 'ja_JP' : locale === 'en' ? 'en_US' : 'zh_CN';
---

<!-- 基本メタタグ -->
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{title}</title>
<meta name="description" content={description} />

<!-- 言語宣言 -->
<html lang={locale} />

<!-- Canonical URL -->
<link rel="canonical" href={currentURL} />

<!-- hreflang -->
{Object.entries(alternateURLs).map(([lang, url]) => (
  <link rel="alternate" hreflang={lang} href={url} />
))}
<link rel="alternate" hreflang="x-default" href={alternateURLs['ja'] || currentURL} />

<!-- OGP -->
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:url" content={currentURL} />
<meta property="og:locale" content={ogLocale} />
<meta property="og:type" content="website" />

<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={description} />

使用例:

---
// src/pages/about.astro
import Layout from '../layouts/Layout.astro';
import SEOHead from '../components/SEOHead.astro';

const site = 'https://example.com';
const alternateURLs = {
  'ja': `${site}/about`,
  'en': `${site}/en/about`,
  'zh': `${site}/zh/about`
};
---

<html>
  <head>
    <SEOHead 
      title="私たちについて - Example Inc."
      description="Example Inc.は次世代Web技術で革新的なソリューションを提供します。"
      locale="ja"
      alternateURLs={alternateURLs}
    />
  </head>
  <body>
    <!-- コンテンツ -->
  </body>
</html>

構造化データ(Schema.org)の多言語対応

WebサイトのSEOを強化するには、構造化データも必須です。多言語サイトでは、各言語版で適切に翻訳された構造化データを配置します。

---
// src/components/StructuredData.astro
interface Props {
  type: 'Organization' | 'WebSite' | 'Article';
  locale: string;
  data: Record<string, any>;
}

const { type, locale, data } = Astro.props;

const structuredData = {
  '@context': 'https://schema.org',
  '@type': type,
  inLanguage: locale,
  ...data
};
---

<script type="application/ld+json" set:html={JSON.stringify(structuredData)} />

使用例:

<StructuredData 
  type="Organization"
  locale="ja"
  data={{
    name: "Example Inc.",
    url: "https://example.com",
    logo: "https://example.com/logo.png",
    description: "次世代Web技術のリーディングカンパニー",
    sameAs: [
      "https://twitter.com/example",
      "https://www.linkedin.com/company/example"
    ]
  }}
/>

Sitemapの多言語対応

Astroの公式@astrojs/sitemapを使えば、多言語対応のサイトマップを自動生成できます。

npm install @astrojs/sitemap

astro.config.mjs:

import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';

export default defineConfig({
  site: 'https://example.com',
  i18n: {
    defaultLocale: 'ja',
    locales: ['ja', 'en', 'zh'],
    routing: {
      prefixDefaultLocale: false
    }
  },
  integrations: [
    sitemap({
      i18n: {
        defaultLocale: 'ja',
        locales: {
          ja: 'ja',
          en: 'en',
          zh: 'zh'
        }
      }
    })
  ]
});

これにより、以下のような構造のサイトマップが生成されます:

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
        xmlns:xhtml="http://www.w3.org/1999/xhtml">
  <url>
    <loc>https://example.com/</loc>
    <xhtml:link rel="alternate" hreflang="ja" href="https://example.com/" />
    <xhtml:link rel="alternate" hreflang="en" href="https://example.com/en/" />
    <xhtml:link rel="alternate" hreflang="zh" href="https://example.com/zh/" />
  </url>
  <url>
    <loc>https://example.com/en/</loc>
    <xhtml:link rel="alternate" hreflang="ja" href="https://example.com/" />
    <xhtml:link rel="alternate" hreflang="en" href="https://example.com/en/" />
    <xhtml:link rel="alternate" hreflang="zh" href="https://example.com/zh/" />
  </url>
</urlset>

言語切り替え機能の実装

ユーザーが言語を切り替えられるUIは必須です。現在のページに対応する他言語版にスムーズに遷移できる実装を紹介します。

---
// src/components/LanguageSwitcher.astro
interface Props {
  currentLocale: string;
  currentPath: string;
}

const { currentLocale, currentPath } = Astro.props;

const languages = {
  ja: { name: '日本語', flag: '🇯🇵' },
  en: { name: 'English', flag: '🇺🇸' },
  zh: { name: '中文', flag: '🇨🇳' }
};

// 現在のパスから言語部分を除去
const pathWithoutLocale = currentPath.replace(/^\/(en|zh)/, '') || '/';

// 各言語版のURLを生成
const localeURLs = {
  ja: pathWithoutLocale,
  en: `/en${pathWithoutLocale}`,
  zh: `/zh${pathWithoutLocale}`
};
---

<div class="language-switcher">
  {Object.entries(languages).map(([code, { name, flag }]) => (
    <a 
      href={localeURLs[code as keyof typeof localeURLs]}
      class:list={['lang-option', { active: code === currentLocale }]}
      aria-label={`Switch to ${name}`}
    >
      <span class="flag">{flag}</span>
      <span class="name">{name}</span>
    </a>
  ))}
</div>

<style>
  .language-switcher {
    display: flex;
    gap: 0.5rem;
    padding: 0.5rem;
    background: var(--bg-secondary);
    border-radius: 8px;
  }
  
  .lang-option {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.5rem 1rem;
    text-decoration: none;
    color: var(--text-primary);
    border-radius: 4px;
    transition: background 0.2s;
  }
  
  .lang-option:hover {
    background: var(--bg-hover);
  }
  
  .lang-option.active {
    background: var(--primary-color);
    color: white;
    font-weight: 600;
  }
  
  .flag {
    font-size: 1.2rem;
  }
</style>

使用例:

---
import LanguageSwitcher from '../components/LanguageSwitcher.astro';

const currentLocale = Astro.currentLocale || 'ja';
const currentPath = Astro.url.pathname;
---

<nav>
  <LanguageSwitcher currentLocale={currentLocale} currentPath={currentPath} />
</nav>

パフォーマンス最適化とCore Web Vitals

多言語サイトでは、翻訳データの読み込みがパフォーマンスのボトルネックになりがちです。Astroのビルドタイムレンダリングを活用すれば、この問題を解決できます。

ビルド時の最適化

Astroでは、翻訳データがビルド時に各ページにインライン化されるため、ランタイムでのJSONフェッチが不要です。これにより、以下の効果が得られます:

指標従来のSPA(React i18next等)Astro i18n
初回レンダリング~800ms~150ms
翻訳データ読み込み別途HTTPリクエストビルド時に埋め込み
LCP(Largest Contentful Paint)2.5s〜1.2s〜
CLS(Cumulative Layout Shift)0.1〜0.250.05以下

画像の最適化

多言語サイトでは、言語ごとに異なる画像(テキスト入り画像など)を使うケースがあります。Astroの<Image />コンポーネントを使えば、自動的にWebP変換とレスポンシブ対応が行われます。

---
import { Image } from 'astro:assets';
import heroJa from '../assets/hero-ja.png';
import heroEn from '../assets/hero-en.png';

const currentLocale = Astro.currentLocale || 'ja';
const heroImages = { ja: heroJa, en: heroEn, zh: heroJa };
---

<Image 
  src={heroImages[currentLocale as keyof typeof heroImages]} 
  alt="Hero image"
  width={1200}
  height={630}
  format="webp"
  loading="eager"
/>

フォントの最適化

日本語・中国語のWebフォントは容量が大きいため、サブセット化が必須です。

<!-- 日本語:Noto Sans JP(サブセット版) -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap&text=よく使う文字列のみ" rel="stylesheet">

または、Google Fontsの代わりにセルフホストでサブセットフォントを使用:

# pyftsubsetをインストール
pip install fonttools brotli

# 必要な文字だけ抽出
pyftsubset NotoSansJP-Regular.otf \
  --text-file=characters.txt \
  --output-file=NotoSansJP-Subset.woff2 \
  --flavor=woff2

多言語サイト運用のベストプラクティス

1. デフォルト言語の選択基準

  • ユーザーベースの地域分布:Google Analyticsで訪問者の地域を確認
  • ビジネスの主要市場:売上の50%以上を占める地域の言語
  • ドメイン戦略.jpなら日本語、.comなら英語など

2. 翻訳の品質管理

機械翻訳をそのまま使うのは避けるべきです。2026年のAI翻訳は高精度ですが、以下の点は人間のチェックが必須です:

  • ブランド名・商品名の表記統一
  • 業界特有の専門用語
  • CTAボタンのマイクロコピー
  • 法的文言(利用規約・プライバシーポリシー)

3. 地域ごとのSEOカスタマイズ

同じ言語でも地域によって検索キーワードが異なります:

言語地域
英語アメリカ”truck”(トラック)
英語イギリス”lorry”(トラック)
中国語中国本土”手机”(携帯電話)
中国語台湾”手機”(携帯電話)

hreflangで地域別に指定することで、検索エンジンに最適なページを示せます:

<link rel="alternate" hreflang="en-US" href="https://example.com/en-us/" />
<link rel="alternate" hreflang="en-GB" href="https://example.com/en-gb/" />
<link rel="alternate" hreflang="zh-CN" href="https://example.com/zh-cn/" />
<link rel="alternate" hreflang="zh-TW" href="https://example.com/zh-tw/" />

4. URLスキームの選択

多言語サイトのURLスキームは主に3つあります:

スキームメリットデメリット
サブディレクトリexample.com/en/管理が簡単、SEO評価が分散しない同一ドメイン内で言語を区別
サブドメインen.example.com地域ごとのサーバー配置が可能SEO評価が分散する可能性
ccTLDexample.co.uk地域ターゲティングが明確ドメイン管理コストが高い

推奨:サブディレクトリ方式

Astroのデフォルト設定と相性が良く、Google検索でも推奨されています。

まとめ

Astro i18nを使った国際化対応とSEO設定のポイントをまとめます:

  • Astro 4.xの公式i18n機能を活用すれば、最小限の設定で多言語ルーティングが実現できる
  • hreflangタグとsitemap.xmlにより、検索エンジンに各言語版を正確に伝達
  • ビルドタイムレンダリングで翻訳データをインライン化し、初回表示を高速化
  • 構造化データとOGPを各言語で適切に設定し、検索結果とSNSシェアでの表示を最適化
  • 地域ごとのキーワード最適化とURL設計により、グローバル市場での検索順位を向上

多言語サイトのSEOは技術的な正確性が成否を分けます。hreflangの設定ミスやcanonical URLの誤りは、検索順位の低下や重複コンテンツペナルティにつながります。

Astroの高速性と柔軟性を活かせば、SEOに強く、運用しやすい多言語サイトが構築できます。この記事のコード例をベースに、あなたのプロジェクトでもグローバル展開を加速させてください。

#Astro #i18n #SEO #国際化 #多言語対応
シェア: