Hun-Bot's Devlog

閲覧数 集計中...

ブログ開発ログ 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, about
  • blog: all-posts, read-more, no-posts, tags, category
  • about: 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 が衝突
  • 複雑な型チェックでメンテが困難

対応:

  1. すべての画像を public/images/ に移動
  2. content.config.ts から image() を外し z.string().optional()
  3. BaseHead.astroBlogPost.astro から Image コンポーネントを削除
  4. <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:assets Image コンポーネント
  • 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

目次

댓글