Astro&Markdown/Markdocで作ったサイトで、簡単な言語切り替え機能を実装する

個人のポートフォリオサイトを、2023年からAstroで構築しています。 サイトの要件として、「日本語でも英語でも表示すること」があったため、勉強も兼ねてある程度自前で実装してみました。 基本方針 英語をベースとする 日 […]

広告ここから
広告ここまで

目次

    個人のポートフォリオサイトを、2023年からAstroで構築しています。

    サイトの要件として、「日本語でも英語でも表示すること」があったため、勉強も兼ねてある程度自前で実装してみました。

    基本方針

    • 英語をベースとする
    • 日本語の場合、hidetaka.dev/ja-JP/をベースURLにする
    • Markdown / Makdocファイルは、言語ごとに用意する
    • サードパーティの多言語対応ライブラリは、あえて使わない

    言語別に用意したMarkdown/Markdocファイルを、言語別に読み込む

    今回は配置するファイルもあまり多くないため、次のようなシンプルなディレクトリ構成とします。

    src/contents/blog/hello.mdoc
    src/contents/blog/hello-ja.mdoc

    Astroのsrc/component/Hello.astroファイルを作成しましょう。

    Astro.props.langで言語を受け取る形とし、getEntryBySlugのファイルパスを変化させます。

    ---
    import { getEntryBySlug } from 'astro:content';
    
    const { lang = 'en' } = Astro.props;
    const entry = await getEntryBySlug('blog', `hello${/ja/.test(lang) ? '-ja' : ''}`);
    ---
    
    {Content ? (
        <Content />
    ): null}

    URLのパスから言語を判定する

    今回のサイトでは、次のようにURLで言語を判定します。

    • example.com/: English
    • example.com/ja-JP: Japanese

    pathnameから取得するため、ヘルパー関数を用意しましょう。

    export function getLanguageFromURL(pathname: string) {
        // ja,en,es
        //const langCodeMatch = pathname.match(/\/([a-z]{2}-?[a-z]{0,2})/);
        // ja-JP, en-US
        const langCodeMatch = pathname.match(/^\/(\w{2})-([\w-]{2,})/);
        return langCodeMatch ? langCodeMatch[1] : 'en-US';
    }

    あとはsrc/pages以下のファイルで、言語を取得する様に実装します。

    const currentPage = new URL(Astro.request.url).pathname;
    const lang = getLanguageFromURL(currentPage);

    言語ごとのページファイルを作成する

    動的に設定できるのが理想だとは思いますが、2言語だけなので物理で押し通します。

    src/pages以下に言語ごとにファイルを作成し、併せてsrc/containerssrc/componentsにページ用のファイルも用意しましょう。

    src/pages/index.astro
    src/pages/ja-JP/index.astro
    src/containers/pages/IndexPage.astro

    ページで表示するコンテンツ自体は全てページ用ファイルに任せ、src/pagesのファイルは言語の取得とコンポーネントの呼び出しのみを行います。

    ---
    import { getLanguageFromURL } from "../../libs/urlUtils/lang.util"
    import IndexPage from "../../containers/pages/IndexPage.astro";
    
    const currentPage = new URL(Astro.request.url).pathname;
    const lang = getLanguageFromURL(currentPage);
      
    ---
    
    <IndexPage lang={lang} />

    言語切り替え機能を実装する

    最後に言語切り替え方法です。

    こちらもAstro.request.urlから取得したpathnameを元に、URLを書き換える関数を作ります。

    export const changeLanguageURL = (pathname: string, targetLang: 'en-US' | 'ja-JP' = 'en-US'): string => {
        const lang = getLanguageFromURL(pathname)
        if (lang === targetLang) return pathname
        if (lang === 'en-US') {
          return `/${targetLang}${pathname}`
        }
        const replaceTarget = targetLang === 'en-US' ? '' : `/${targetLang}`
        return pathname.replace(/^\/(\w{2})-([\w-]{2,})/, replaceTarget)  
    }

    あとはリンクタグにこの関数の実行結果を渡しましょう。

    ---
    import { changeLanguageURL } from "../../../libs/urlUtils/lang.util";
    
    const { pathname } = new URL(Astro.request.url)
    ---
    
    <nav>
        <ul>
            <a href={changeLanguageURL(pathname, 'ja-JP')}>Japanese</a>
            <a href={changeLanguageURL(pathname, 'en-US')}>English</NavIatem>
        </ul>
    </nav>

    広告ここから
    広告ここまで
    Home
    Search
    Bookmark