閲覧数 集計中...
ブログ開発ログ 02
Devlog Astro i18n Refactoring
プロジェクト
個人ブログの多言語対応と画像システム改善
- 期間: 2025-10-28
- 役割: ブログ開発者
主なタスク
- Astro の i18n 設定と多言語ルーティングを実装
- ブログコンテンツを言語別に構造化
- 画像パスを
src/assetsからpublic/imagesへ移行 - 型安全性を保ちながらコードをシンプルに再構成
主要作業まとめ
1. Astro i18n 設定 (astro.config.mjs)
i18n: {
defaultLocale: 'ko',
locales: ['ko', 'jp', 'en'],
routing: {
prefixDefaultLocale: false
}
}
- 韓国語:
/(デフォルト、プレフィックスなし) - 日本語:
/jp/ - 英語:
/en/
2. 翻訳システム (src/i18n/ui.ts)
- 3言語 (ko, jp, en) の辞書を定義
useTranslations()で型安全にキーへアクセス- ナビゲーション、ブログ、About のすべての UI テキストを翻訳
主なキー例:
nav: home, blog, aboutblog: all-posts, read-more, no-posts, tags, categoryabout: title, greeting, intro, background, interests, skills, contact
3. LanguagePicker コンポーネント (src/components/LanguagePicker.astro)
- ドロップダウン形式の言語切替
- 現在の言語を 🌐 アイコン + テキストで表示
- ルートは維持したまま言語プレフィックスのみ変更
4. 言語別ページルーティング (src/pages/[lang]/)
src/pages/
├── index.astro (/ → /ko/ リダイレクト)
├── about.astro (/about → /ko/about リダイレクト)
└── [lang]/
├── index.astro
├── about.astro
└── blog/
├── index.astro
└── [...slug].astro
getStaticPaths()で ko / jp / en のパス生成- ‘post.id.startsWith(
${lang}/)‘で言語ごとの記事をフィルタ - 各ページで
useTranslations(lang)を使用
5. ブログコンテンツ構造の再編
src/content/blog/
├── ko/
│ ├── devlog/
│ ├── review/
│ └── contemplation/
├── jp/
│ └── sample.md
└── en/
└── sample.md
6. 画像システム改善
課題:
src/assets/を参照する relative path が崩壊image()ヘルパーと public フォルダの URL が衝突- 複雑な型チェックでメンテが困難
対応:
- すべての画像を
public/images/に移動 content.config.tsからimage()を外しz.string().optional()にBaseHead.astroとBlogPost.astroから Image コンポーネントを削除<img>タグに統一
関連ファイル:
src/content.config.ts: heroImage スキーマ簡素化src/components/BaseHead.astro: 文字列 URL 対応src/layouts/BlogPost.astro: 画像処理ロジック削減src/pages/[lang]/about.astro: 画像 import を廃止し URL を直書き
正しいパス例:
heroImage: '/images/KOSSDA.png'
7. レガシーコード整理
/blogディレクトリを完全削除- 重複していたブログポストを除去
- 未使用の画像 import を削除
技術スタックの変更
追加設定
astro.config.mjs: i18n 設定src/i18n/ui.ts: 翻訳辞書
更新されたコンポーネント
Header.astro: LanguagePicker を統合BaseHead.astro: 画像を文字列 URL として扱うBlogPost.astro: 画像の型チェックを撤廃
削除した依存
astro:assetsImage コンポーネント- ImageMetadata 型
Issue と解決
Issue 1: Content Collection の画像参照エラー
- 症状:
ImageNotFound: Could not find requested image - 原因:
image()ヘルパーが多階層パスを解決できない - 対応: public/images へ移行し、文字列パスに統一
Issue 2: BaseHead と画像型の不一致
- 症状:
Property 'src' does not exist on type 'string' - 原因: ImageMetadata を想定していた
- 対応: prop を string に変更し、fallback を
/images/blog-placeholder-1.jpgに固定
Issue 3: About ページのビルド失敗
- 症状:
Rollup failed to resolve import "/images/my_photo.png" - 原因: public 配下の画像を import しようとした
- 対応: import を削除し
src="/images/my_photo.jpeg"と直接指定
学んだこと
Astro Content Collections の限界
image()ヘルパーは浅い階層向け- 言語別の入れ子構造では public フォルダが安全
- 型安全とシンプルさのトレードオフを常に意識
i18n 実装の戦略
- URL ベースのルーティングは SEO に有利
- 既存リンクを壊さないようデフォルト言語は prefix なしが良い
- 翻訳辞書を一元管理すると運用コストが下がる
リファクタリングの重要性
- 複雑な型チェックよりシンプルな構造が安定する
- ビルドエラーは早期に潰すことで技術的負債を防げる
- 小さく区切って
dev → build → deployで確認するのが安全
作成日: 2025-10-28
댓글