こんにちは!今回は、Astro を使って多言語サイトを構築した際の経験についてお話ししたいと思います。特に、日本語と英語のサイトを効率的に管理するために行った工夫や、実際に直面した課題について深掘りしていきます。

なぜ Astro で多言語サイト?

Astro は、高速な Web サイト構築に特化したモダンなフレームワークです。サーバーサイドレンダリング(SSR)とアイランドアーキテクチャにより、パフォーマンスと開発体験のバランスが非常に優れています。多言語サイトのようなコンテンツが豊富なサイトでは、これらの特性が大いに役立ちます。

さらに、Astro の大きな魅力は、HTML を記述する感覚でコンポーネントを作成できる点です。HTML の構文をそのまま利用できるため、Web 開発者が長年慣れ親しんだ書き方で直感的にコードを書くことができます。これにより、JSX 特有の記法や、JavaScript フレームワークにありがちな複雑なテンプレート構文を覚える必要がほとんどありません。

また、HTML で記述できるということは、エディターでの開発体験にも直結します。例えば、HTML で普段利用している Tab キーでのコード展開(Emmet 記法など)は、Astro ファイル内でもそのまま機能します。このように、エディターの設定などを意識しなくても、HTML でできていたことはそのまま動くため、新しい環境に慣れるための「無駄な脳のメモリ」を使うことなく、本質的な開発に集中できるという大きなメリットがあります。

工夫した点:効率的な多言語対応への挑戦

多言語サイトを構築する上で、主に以下の点に工夫を凝らしました。

1. オブジェクトを使ったテキストデータの管理

サイト内の各テキストを効率的に管理するため、JavaScript(TypeScript)のオブジェクトを使って多言語データを一元化しました。例えば、以下のような構造でテキストデータを保持しています。

const texts: Texts = {
  ja: {
    title: "サンプルサイト",
    description: "これはサンプルサイトの説明です。",
    // ...その他日本語テキスト
  },
  en: {
    title: "Sample Site",
    description: "This is Sample Site description.",
    // ...その他英語テキスト
  },
};

これにより、現在の言語(lang)を元に const t = texts[lang]; のようにオブジェクトを取得し、{t.title} の形式で各テキストを参照することで、言語を切り替えるだけで表示内容が自動的に変わるように実装しました。

2. 画像パスの動的な切り替え

テキストだけでなく、言語によって異なる画像を表示する必要がある場面も出てきます。今回は、以下のように JavaScript の三項演算子を使用して、言語に応じて画像のパスを動的に切り替える実装を行いました。

<img src={lang === "ja" ? "../logo.png" : "../logo-en.png"} alt={t.title} />

このように、src 属性だけでなく、画像の内容を説明する alt 属性も t.title のように多言語テキストから取得することで、視覚的な情報だけでなく、アクセシビリティも言語に合わせて最適化することができました。

3. CSS における言語ごとの条件分岐

デザイン面では、日本語と英語でテキストの長さやフォントサイズが異なる場合があるため、CSS で言語ごとの条件分岐を活用しました。特に、html[lang="en"] のような属性セレクタを使うことで、HTML の lang 属性に応じてスタイルを切り替えることができました。

html[lang="en"] body {
  font-family: "Bold"; /* 英語の場合に別のフォントを適用 */
  line-height: 1.4; /* 英語の場合に文字の高さを調整 */
}

/* もしくは、特定の要素に限定して */
html[lang="en"] .main-title {
  font-size: 2.5rem; /* 英語の場合に特定のタイトルのフォントサイズを調整 */
}

このアプローチにより、各言語のコンテンツに最適な見た目を維持しつつ、CSS コードを整理することができました。

苦労した点:理想のデータ構造を求めて

今回のプロジェクトで特に「こうすればよかった!」と痛感したのが、テキストデータのオブジェクト構造についてです。

現在の texts.ts の構造は、言語キー(ja, en)の下に各テキストのキー(title, description)がネストされています。

// 現在の構造
const texts: Texts = {
  ja: {
    title: "サンプルサイト",
    // ...
  },
  en: {
    title: "Sample Site",
    // ...
  },
};

この構造の場合、各コンポーネントではまず現在の言語 lang を使って const t = texts[lang]; のように言語ごとのテキストオブジェクトを取得し、その後 {t.title} のように個別のテキストを参照していました。

しかし、開発を進める中で、この構造よりもテキストキー(titleなど)の下に言語キー(ja, en)をネストする構造の方が、より管理しやすく、コンポーネント内での使用も直感的だったと感じています。

// 理想的だった構造
const texts: Texts = {
  title: {
    ja: "サンプルサイト",
    en: "Sample Site",
  },
  description: {
    ja: "これはサンプルサイトの説明です。",
    en: "This is Sample Site description.",
  },
  // ...
};

この理想的な構造であれば、特定のテキスト項目(例: title)の各言語での翻訳を一目で確認できるようになり、管理が非常に楽になります。また、コンポーネント内では直接 texts.title[lang] のようにアクセスできるようになるため、中間変数 t を介する必要がなくなり、テキストごとに翻訳状況を把握しやすくなるため、コードの見通しも格段に向上します。現在の構造では、異なるテキストキーを横断して翻訳状況を把握する際に、やや手間がかかる点が課題でした。

まとめ

Astro を使った多言語サイト構築は、そのパフォーマンスと開発のしやすさから非常に良い経験となりました。特にオブジェクトを使ったテキスト管理や CSS での言語分岐は有効な手段でしたが、テキストデータの構造設計は初期段階での見直しが重要だと改めて認識しました。

今後の多言語サイト開発では、今回得た知見を活かし、より効率的でメンテナンスしやすいデータ構造を意識していきたいと思います。