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.mjsにi18nオプションを追加するだけで、多言語ルーティングが有効になります。
プロジェクト構造
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.25 | 0.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評価が分散する可能性 |
| ccTLD | example.co.uk | 地域ターゲティングが明確 | ドメイン管理コストが高い |
推奨:サブディレクトリ方式
Astroのデフォルト設定と相性が良く、Google検索でも推奨されています。
まとめ
Astro i18nを使った国際化対応とSEO設定のポイントをまとめます:
- Astro 4.xの公式i18n機能を活用すれば、最小限の設定で多言語ルーティングが実現できる
- hreflangタグとsitemap.xmlにより、検索エンジンに各言語版を正確に伝達
- ビルドタイムレンダリングで翻訳データをインライン化し、初回表示を高速化
- 構造化データとOGPを各言語で適切に設定し、検索結果とSNSシェアでの表示を最適化
- 地域ごとのキーワード最適化とURL設計により、グローバル市場での検索順位を向上
多言語サイトのSEOは技術的な正確性が成否を分けます。hreflangの設定ミスやcanonical URLの誤りは、検索順位の低下や重複コンテンツペナルティにつながります。
Astroの高速性と柔軟性を活かせば、SEOに強く、運用しやすい多言語サイトが構築できます。この記事のコード例をベースに、あなたのプロジェクトでもグローバル展開を加速させてください。