Astro i18n 設定ガイド:30分で実装する多言語サイト(言語切り替え機能付き)

はじめに
「よし、素敵なAstroブログができた!次は世界に向けて発信だ!」と意気込んで多言語対応(i18n)を調べ始めたものの、挫折しそうになったことはありませんか?astro.config.mjs の locales だの prefixDefaultLocale だの設定項目は多いし、ディレクトリ構造はどうすればいいか迷うし、言語切り替えボタンの実装方法もよくわからない…。
正直、私も最初は prefixDefaultLocale を true にすべきか false にすべきかで半日悩みました。でも、一度理解してしまえば、Astroのi18n機能は非常にシンプルで強力なことに気づきます。
この記事では、公式ドキュメントよりも噛み砕いて、Astroサイトを多言語化する全手順を解説します。基本設定から、コピペで使える言語切り替えコンポーネント、SEO対策まで、これさえ読めば30分であなたのサイトがグローバル対応になります。
Astro i18n 基本設定(10分で完了)
astro.config.mjs の設定
まずは心臓部である設定ファイルです。Astro v4.0からi18nは標準機能になりました。astro.config.mjs に以下の設定を追加します。
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
i18n: {
// サイトでサポートする全言語リスト
locales: ['en', 'zh-cn', 'ja'],
// デフォルト言語(localesに含まれている必要あり)
defaultLocale: 'ja',
// デフォルト言語のURLにプレフィックス(/ja/)をつけるかどうか
// false にすると、日本語は /about 、英語は /en/about になります(推奨)
prefixDefaultLocale: false,
}
});設定項目の意味は以下の通りです:
locales: サポートする言語の配列です。'en'(英語)、'zh-cn'(簡体字中国語)、'ja'(日本語)のように標準的な言語コードを使います。地域まで指定したい場合は 'en-US' のように書きます。
defaultLocale: ユーザーがルートURL(/)にアクセスしたときに表示される言語(デフォルト言語)です。
prefixDefaultLocale: ここが悩みどころです。
false(推奨): デフォルト言語(例:日本語)のURLは/aboutのようにスッキリします。他の言語は/en/aboutになります。true: 全ての言語にプレフィックスがつきます。日本語は/ja/about、英語は/en/aboutになります。URLの構造を統一したい場合や、SEO上の理由がある場合はこちらを選びます。
3つのルーティング戦略
どのURL構造にするか、プロジェクトに合わせて選びましょう。
| 戦略 | 設定 | URL例 | おすすめシーン | メリット・デメリット |
|---|---|---|---|---|
| 戦略1:デフォルト言語プレフィックスなし | prefixDefaultLocale: false | /about/en/about | 一般的なブログ、公式サイト(推奨) | ✅ デフォルト言語のURLが短い ❌ URL構造が不統一に見えるかも |
| 戦略2:全言語プレフィックスあり | prefixDefaultLocale: true | /ja/about/en/about | SEO要件が厳しい場合 URL構造を統一したい場合 | ✅ 構造が統一されて管理しやすい ✅ 言語切り替えロジックが単純 ❌ デフォルト言語のURLが長くなる |
| 戦略3:マニュアルモード | routing: 'manual' | (完全カスタム) | 複雑な要件がある場合 | ✅ 自由自在 ❌ 設定と実装が大変 |
個人のブログやドキュメントサイトなら、戦略1(false)で十分です。もし中英日3ヶ国語対応のブログにするなら、locales: ['ja', 'en', 'zh-cn']、defaultLocale: 'ja' でOKです。
Astro i18n 多言語設定
Astroサイトを多言語化するための30分ステップバイステップガイド
- 1
Step1: 設定ファイルの編集
astro.config.mjs に i18n オブジェクトを追加:
• locales:対応言語リスト(例:['ja', 'en'])
• defaultLocale:デフォルト言語(例:ja)
• prefixDefaultLocale:URLプレフィックス設定
- false:デフォルト言語はプレフィックスなし(推奨)
- true:全言語にプレフィックス付与 - 2
Step2: コンテンツの構造化
コンテンツ管理方法を選択:
方法1:言語別フォルダ(初心者向け)
• src/pages/以下に ja/ や en/ フォルダを作成
• 直感的で分かりやすい
方法2:動的ルーティング(中級者向け)
• [lang] パラメータを使用
• コード量を削減できる
ブログの場合:
• Content Collections を使用
• Markdownファイルを言語ごとに管理 - 3
Step3: UI翻訳辞書の作成
src/i18n/ui.ts を作成し、ナビゲーションやボタンなどの定型文を定義:
{
'ja': {
nav: { home: 'ホーム', about: '概要' },
button: { submit: '送信' }
},
'en': {
nav: { home: 'Home', about: 'About' },
button: { submit: 'Submit' }
}
} - 4
Step4: 言語切り替え機の実装
getRelativeLocaleUrl と Astro.currentLocale を活用して言語切り替えコンポーネントを作成:
• 現在のパスを維持したまま言語部分だけ置換
• ドロップダウンやボタンリストで表示 - 5
Step5: SEO対策
Layoutファイルに hreflang タグを追加し、sitemap設定を行うことで検索エンジンに多言語対応を通知する
コンテンツの管理方法(2パターン)
設定の次は「ファイルをどう置くか」です。Astroには主に2つのアプローチがあります。
パターン1:言語ごとにフォルダを分ける(初心者向け)
一番わかりやすい方法です。言語ごとに物理的なフォルダを作ります。
src/pages/
├── about.astro # デフォルト言語(日本語)
├── blog.astro
├── index.astro
├── en/ # 英語版
│ ├── about.astro
│ ├── blog.astro
│ └── index.astro
└── zh-cn/ # 中国語版
├── about.astro
├── blog.astro
└── index.astro※ prefixDefaultLocale: false の場合、デフォルト言語のファイルは src/pages/ 直下に置きます。
この方法は構造が単純で、ページごとにレイアウトを大胆に変えたい場合などに便利です。ただし、全言語共通の修正が入った場合、全てのファイルを修正する必要があります。
パターン2:動的ルーティング(中級者向け)
ファイルを1つにまとめたい場合は動的ルーティングを使います。
src/pages/
└── [lang]/
└── [...slug].astro[lang] 部分が言語コード(en, jaなど)になります。
---
// src/pages/[lang]/[...slug].astro
export function getStaticPaths() {
const locales = ['ja', 'en', 'zh-cn'];
const slugs = ['about', 'blog', 'contact'];
return locales.flatMap((lang) =>
slugs.map((slug) => ({
params: { lang, slug },
}))
);
}
const { lang, slug } = Astro.params;
// langとslugに基づいてコンテンツをロード
---コードの重複が減りますが、Astroの動的ルーティングの知識が必要です。最初はパターン1で慣れてから移行するのもありです。
Content Collections を使う(ブログならこれ!)
ブログ記事のようなコンテンツは、Content Collections で管理するのがベストプラクティスです。
ディレクトリ構成:
src/content/
└── blog/
├── en/
│ ├── post-1.md
│ └── post-2.md
├── ja/
│ ├── post-1.md
│ └── post-2.md
└── zh-cn/設定ファイル src/content/config.ts:
import { defineCollection, z } from 'astro:content';
const blogCollection = defineCollection({
schema: z.object({
title: z.string(),
lang: z.enum(['en', 'zh-cn', 'ja']), // 言語フィールドを追加
// ...他のフィールド
}),
});
export const collections = {
blog: blogCollection,
};ページ側での取得:
---
import { getCollection } from 'astro:content';
const currentLang = Astro.currentLocale; // 現在の言語を取得
const posts = await getCollection('blog', ({ data }) => {
return data.lang === currentLang; // 現在の言語の記事だけフィルタリング
});
---Astro公式サイトもこの方式を採用しています。スケーラブルで管理しやすいです。
UI翻訳辞書の管理
記事の中身以外の、ナビゲーションメニューやボタンのテキスト(「ホーム」「次へ」など)の翻訳管理方法です。
シンプルな辞書ファイルを作りましょう。
// src/i18n/ui.ts
export const ui = {
'en': {
'nav.home': 'Home',
'nav.about': 'About',
'btn.readMore': 'Read More',
},
'ja': {
'nav.home': 'ホーム',
'nav.about': '概要',
'btn.readMore': '続きを読む',
},
'zh-cn': {
'nav.home': '首页',
'nav.about': '关于',
'btn.readMore': '阅读更多',
},
} as const;ヘルパー関数を作成:
// src/i18n/utils.ts
import { ui } from './ui';
export function getLangFromUrl(url: URL) {
const [, lang] = url.pathname.split('/');
if (lang in ui) return lang as keyof typeof ui;
return 'ja'; // デフォルト言語
}
export function useTranslations(lang: keyof typeof ui) {
return function t(key: keyof typeof ui[typeof lang]) {
return ui[lang][key] || ui['ja'][key];
}
}コンポーネントでの使用:
---
import { getLangFromUrl, useTranslations } from '@/i18n/utils';
const lang = getLangFromUrl(Astro.url);
const t = useTranslations(lang);
---
<nav>
<a href="/">{t('nav.home')}</a> <!-- "ホーム" or "Home" -->
</nav>言語切り替え機能の実装(完全コード)
ここが最難関だと思われがちですが、Astroのヘルパー関数を使えば簡単です。
便利なヘルパー関数
getRelativeLocaleUrl(locale, path): 指定した言語での相対パスを生成します。
例:getRelativeLocaleUrl('en', 'about') → /en/about
Astro.currentLocale: 現在のページの言語コードを取得します。
言語切り替えコンポーネント
コピペで使えるコンポーネントです。現在見ているページを維持したまま、言語だけ切り替えるリンクを生成します。
---
// src/components/LanguageSwitcher.astro
import { getRelativeLocaleUrl } from 'astro:i18n';
const locales = {
'ja': '日本語',
'en': 'English',
'zh-cn': '简体中文',
};
const currentLang = Astro.currentLocale || 'ja';
// URLから言語プレフィックスを除去して、纯粋なパスを取得
const currentPath = Astro.url.pathname
.replace(new RegExp(`^/${currentLang}/`), '/') // 先頭の言語パスを削除
.replace(/^\//, ''); // 先頭のスラッシュを削除(getRelativeLocaleUrlがよしなに処理するため)
---
<div class="language-switcher">
<button class="lang-button">
{locales[currentLang]} ▼
</button>
<div class="lang-dropdown">
{Object.entries(locales).map(([lang, label]) => {
// 魔法のメソッド:現在のパスを維持したまま、指定言語のURLを生成
const url = getRelativeLocaleUrl(lang, currentPath);
return (
<a
href={url}
class={lang === currentLang ? 'active' : ''}
>
{label}
</a>
);
})}
</div>
</div>
<style>
/* スタイルは適宜調整してください */
.language-switcher { position: relative; display: inline-block; }
.lang-dropdown { display: none; position: absolute; background: white; border: 1px solid #ccc; }
.language-switcher:hover .lang-dropdown { display: block; }
.active { font-weight: bold; color: blue; }
</style>これをヘッダーなどに配置すれば、マルチリンガルサイトの完成です!
ユーザーの使用言語自動検出(オプション)
初めて訪れたユーザーを、ブラウザの言語設定に合わせてリダイレクトさせたい場合、Middlewareを使います。
// src/middleware.ts
import { defineMiddleware } from 'astro:middleware';
export const onRequest = defineMiddleware((context, next) => {
const url = context.url;
const currentLocale = context.currentLocale;
const preferredLocale = context.preferredLocale; // ブラウザの言語設定
// トップページへのアクセスで、かつブラウザ言語が現在の表示言語と異なる場合
if (url.pathname === '/' && preferredLocale && preferredLocale !== currentLocale) {
return context.redirect(`/${preferredLocale}/`);
}
return next();
});※Cookieを使ってユーザーの選択を保存するロジックを追加すると、より親切です(強制リダイレクトループを防ぐため)。
SEO対策(hreflangタグ)
Googleなどの検索エンジンに「このページには英語版があるよ」と伝えるために、hreflang タグの設定は必須です。src/layouts/Layout.astro の <head> に以下を追加します。
---
import { getAbsoluteLocaleUrl } from 'astro:i18n';
const locales = ['ja', 'en', 'zh-cn'];
// パスから言語部分を取り除く処理(簡易版)
const currentPath = Astro.url.pathname
.replace(/^\/(en|zh-cn|ja)\//, '')
.replace(/^\//, '');
---
<head>
<!-- 各言語版のURLを出力 -->
{locales.map((lang) => (
<link
rel="alternate"
hreflang={lang}
href={getAbsoluteLocaleUrl(lang, currentPath)}
/>
))}
<!-- デフォルト言語(x-default)の指定 -->
<link
rel="alternate"
hreflang="x-default"
href={getAbsoluteLocaleUrl('ja', currentPath)}
/>
<link rel="canonical" href={getAbsoluteLocaleUrl(Astro.currentLocale, currentPath)} />
</head>結論
Astroのi18n機能は、設定ファイル、フォルダ構成、ヘルパー関数の3点セットで成り立っています。
- 設定:
astro.config.mjsで言語を定義。 - 構成: 言語別フォルダか Content Collections で管理。
- 実装:
getRelativeLocaleUrlでリンク生成。
これだけで、SEOにも強く、管理しやすい多言語サイトが作れます。もう「多言語対応」のタスクに怯える必要はありません。
ぜひあなたのブログも世界に発信してみてください!
FAQ
設定完了までどのくらいかかりますか?
URLのプレフィックス設定はどうすべき?
翻訳テキストの管理はどうするのがベスト?
3 min read · 公開日: 2025年12月2日 · 更新日: 2026年1月22日
関連記事
Next.js ファイルアップロード完全ガイド:S3/Qiniu Cloud 署名付き URL 直接アップロード実践

Next.js ファイルアップロード完全ガイド:S3/Qiniu Cloud 署名付き URL 直接アップロード実践
Next.js Eコマース実践:カートと Stripe 決済の完全実装ガイド

Next.js Eコマース実践:カートと Stripe 決済の完全実装ガイド
Next.js ユニットテスト実践:Jest + React Testing Library 完全設定ガイド


コメント
GitHubアカウントでログインしてコメントできます