Astroの多言語対応にNano Storesを使う
Astro を使った多言語対応の方法は、いくつかあると思いますが
今回は状態管理のライブラリの Nano Stores を使った方法を紹介します!
Nano Stores とは??という方は、こちらの記事や公式 GitHub も確認してみてください。
この記事を書こうと思った理由
- 知見の共有
 - 自分自身の忘備録、理解を深めるため
 
ゴール
- Nano Stores を使い、Astro を使ったサイト制作で言語対応を行う
 
Astro のインストール
まずは Astro をインストールしましょう!
公式サイトの手順に沿ってインストールします。
下記コマンドを実行
npm create astro@latest
recommended を選択します。


http://localhost:4321/にアクセスし
この画面が表示されたら、Astro のインストールは完了です!

この状態で、ディレクトリ構成は下記になっていると思います。
astro-multilang-nanostores/
├── .astro/
├── .vscode/
├── node_modules/
├── public/
├── src/
│   ├── assets/
│   ├── components/
│   ├── layouts/
│   └── pages/
│       └── index.astro
├── .gitignore
├── astro.config.mjs
├── package-lock.json
├── package.json
├── README.md
└── tsconfig.json
Astro ファイルのセットアップ
不要なファルがあるため、ファイルをセットアップします!
今回は、例としてheader作成します。
下記を削除し、
/src/components/Welcome.astro
/src/assets/background.svg
下記を作成。
/src/components/Header.astro
<header>
  <nav>
    <ul>
      <li><a href="/about">私たちについて</a></li>
      <li><a href="/company">会社概要</li>
      <li><a href="/contact">お問い合わせ</li>
    </ul>
  </nav>
</header>
<style>
  header {
    background-color: #f2f2f2;
    padding: 16px;
  }
  nav ul {
    list-style: none;
    display: flex;
    gap: 16px;
  }
  nav a {
    text-decoration: none;
    color: #007bff;
  }
  nav a:hover {
    text-decoration: underline;
  }
</style>
Layout.astroのWelcome.astroをHeader.astroに置き換えます。
Layout.astro
---
import Header from '../components/Header.astro';
import Layout from '../layouts/Layout.astro';
---
<Layout>
  <Header />
</Layout>
header が表示されたら完了です!

Nano Stores を使った多言語対応の実装
多言語対応の設定
多言語対応のため、Nano Stores をインストールします。
npm i nanostores
ストアの作成
言語の状態を管理するため、ストアを作成します。
/src/stores/store.ts を作成し下記を追加します。
import { atom } from 'nanostores';
// 言語 (デフォルトをjaに設定)
// 現在の言語に応じてHTMLのlang属性を動的に変更したい場面等で、このストアから現在の値を取得する
export const storeLang = atom<'ja' | 'en'>('ja');
// 取得した言語をstoreLangにセット
// そのページの言語を初期設定する際に呼び出す
export const setLang = (newLang: 'ja' | 'en'): void => {
  storeLang.set(newLang);
};
/src/pages/index.astro で store.tsで設定した内容を反映します
---
import { setLang } from '../stores/store';
import Header from '../components/Header.astro';
import Layout from '../layouts/Layout.astro';
const lang = 'ja';
setLang(lang);
---
<Layout lang="{lang}">
  <Header />
</Layout>
言語設定はLayout.astroで行われています。
htmlタグを確認すると、まだlang='en'が設定されていると思います。
先ほどsetLang(lang);で設定した、言語を/src/layouts/Layout.astroに反映します。
Layout.astro
---
import { storeLang } from '../stores/store';
const lang = storeLang.get();
---
<!DOCTYPE html>
<html lang="{lang}">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <meta name="generator" content="{Astro.generator}" />
    <title>astro-multiLang-nanoStores</title>
  </head>
  <body>
    <slot />
  </body>
</html>
html 要素の lang 属性が ja に変わっていれば成功です!

英語ページの作成
英語ページの作成にあたり
/src/pages/en/index.astro を作成します。
/src/pages/index.astroをコピペし
英語ページのため、const lang = 'en';のみ変更します。
/en/index.astro
---
import { setLang } from '../../stores/store';
import Header from '../../components/Header.astro';
import Layout from '../../layouts/Layout.astro';
const lang = 'en';
setLang(lang);
---
<Layout lang="{lang}">
  <Header />
</Layout>
http://localhost:4321/en/にアクセスし、
dev ツールで、lang を確認します。
html 要素の lang 属性が en に変わっていれば成功です!

これで、ja ページ(デフォルトのトップページ)と
en ページ(英語ページ)の実装が完了しました。
headerのテキストがまだ日本語のままなので、対応します。
英語テキストの反映
反映させるテキストデータを作成します。
/src/data/header-list.tsを作成し、下記のようにheaderに対応するデータを作成します。
ここでは、a タグのhrefに入る値と、リストのテキストを定義します。
header-list.ts
// リンクの型定義
type THeaderLink = {
  href: string;
  text: string;
};
// 言語の型定義
type TLang = 'ja' | 'en';
// ヘッダーリストの型定義
type THeaderList = Record<TLang, THeaderLink>;
const headerList: THeaderList[] = [
  {
    ja: {
      href: '/about',
      text: '私たちについて',
    },
    en: {
      href: '/en/about',
      text: 'About Us',
    },
  },
  {
    ja: {
      href: '/company',
      text: '会社概要',
    },
    en: {
      href: '/en/company',
      text: 'Company',
    },
  },
  {
    ja: {
      href: '/contact',
      text: 'お問い合わせ',
    },
    en: {
      href: '/en/contact',
      text: 'Contact',
    },
  },
];
export { headerList };
Header.astro に反映
storeLang.get();で言語を取得します。
先ほど作成した、headerListをインポートしmapを使ってaタグに反映させます。
Header.astro
---
import { storeLang } from '../stores/store';
import { headerList } from '../data/header-list';
// 言語を取得
const lang = storeLang.get();
---
<header>
  <nav>
    <ul>
      {headerList.map((item) => (
      <li>
        <a href="{item[lang].href}">{item[lang].text}</a>
      </li>
      ))}
    </ul>
  </nav>
</header>
日本語ページと英語ページを確認します!
http://localhost:4321/とhttp://localhost:4321/en/を切り替えて
日本語と英語が切り替わっている事を確認します。

多言語対応が完了しました!
まとめ
Nano Stores を活用することで、Astro を使ったサイト制作の多言語対応が簡単に実装できることをご紹介しました!
少しでも Astro を使った多言語対応や、Nano Stores の使い方の参考になれば幸いです。
Discussion