
私のブログへのアクセスを増やすためにどうすればいいか考えて、多言語設定を試してみることにしました。
さまざまな方法を探しましたが、まずは言語ごとに異なるルーティングをすることから始めることに。
next-intlを使って試してみました。
1. インストール
yarn add next-intl2. 適用
適用は少し面倒です。
以下の手順で進めれば大丈夫です。
app内部のフォルダルーティング全体を[locale]フォルダ内に入れます。
i18nフォルダを作成し、その中にconfig.ts、request.ts、ko.json、en.jsonファイルを作成して設定します。
middleware.ts、next.config.tsで設定
layoutでparamsとproviderでchildrenを囲む
コンポーネントでメッセージを呼び出す
3. 実行してみる
1) [locale] フォルダ

私のapp内部フォルダ構造は上記の通りです。
ここでapp以下のapi、uploadsを除くすべてのフォルダを[locale]で囲みます。
.nextがある状態でフォルダを移動すると権限エラーが表示されるので、sudo rm -r .nextで削除後にフォルダを移動します。
注意すべき点は、フォルダ構造が変わったため相対パスで呼び出している箇所を変更する必要があるということです。

2) i18nフォルダを作成する
srcフォルダがある人はsrc以下に、appのみを使用する人はルートフォルダにそのまま作成しても構いません。
私はi18nフォルダにconfig.ts、request.tsを作成し、messageフォルダ内にko.json、en.jsonを作成しました。

そしてconfig.tsを以下のように設定します。
私は何もない基本パス「/」を韓国語に設定しました。
export const locales = ['ko', 'en'] as const;
export type Locale = (typeof locales)[number];
export const defaultLocale: Locale = 'ko'; // 基本パスを韓国語に設定
export const pathnames = {
'/': '/',
'/about': {
ko: '/about',
en: '/about',
},
'/post/[slug]': {
ko: '/post/[slug]',
en: '/post/[slug]',
},
} as const;そしてrequest.tsでは以下のように設定します。
locale情報を呼び出してサーバーに返す方法です。
import { getRequestConfig } from 'next-intl/server';
import { defaultLocale } from './config';
export default getRequestConfig(async ({ requestLocale }: { requestLocale: Promise<string | undefined> }) => {
const locale = await requestLocale || defaultLocale;
return {
locale,
messages: (await import(`./message/${locale}.json`)).default,
};
});3) middleware.ts、next.config.tsを設定する
まずmiddleware.tsは以下のように設定します。
上の行にcreateMiddlewareをエクスポートで追加すると考えると簡単です。
import createMiddleware from 'next-intl/middleware';
import { locales, defaultLocale } from './i18n/config';
export createMiddleware({
locales,
defaultLocale,
localePrefix: 'as-needed', // 基本(ko)はパスにプレフィックスなし
});
//...既存の設定...//
export default withAuth(
function middleware(req) {
//...既存の設定...//
});そしてnext.config.tsにも下記のようにcreateNextIntlPluginを作成し、既存の設定を一度囲みます。
import type { NextConfig } from "next";
import createNextIntlPlugin from 'next-intl/plugin';
const withNextIntl = createNextIntlPlugin()
const withNextIntlConfig: NextConfig = withNextIntl({
既存のnext.config設定...
});
export default withNextIntlConfig;4) レイアウトで囲む
レイアウトでgetMessageでlocaleを受け取り、providerで囲んで下位コンポーネントで利用できるようにします。
import { NextIntlClientProvider } from "next-intl";
import { getMessages, getLocale } from "next-intl/server";
export default async function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const messages = await getMessages();
const locale = await getLocale();
return (
<html
lang={locale}
>
<NextIntlClientProvider locale={locale} messages={messages}>
<body>
{children}
</body>
</NextIntlClientProvider>
</html>
);
}5) メッセージを使ってみる
まずサーバー側でレンダリングする場合とクライアント側でレンダリングする場合の関数名が異なります。
import {useTranslations, useLocale, useFormatter} from 'next-intl'; // 'use client' コンポーネントから呼び出し
import {getTranslations, getLocale, getFormatter} from 'next-intl/server'; // サーバーコンポーネントから呼び出し区分 | クライアントコンポーネント | サーバーコンポーネント / サーバー関数 | 説明 |
|---|---|---|---|
Translations |
|
|
|
Locale |
|
| 現在アクティブなロケール( |
Formatter |
|
| 日付、時間、数値などをロケールに合わせてフォーマッティング |
Messages | — |
| 現在のリクエストの全翻訳メッセージオブジェクト(通常はlayoutでprovider用として使用) |
リクエストLocale設定 | — |
| SSG·SSRキャッシング時にロケール整合性を保証するためにlayoutで使用 |
私はまず/aboutを変更することにしました。
現在、私の/aboutコンポーネントは以下のようにハードコードされているので、変更しやすいと思いました。
import {
HeroSection,
JourneySection,
ProjectsSection,
} from "@/components/about";
const baseUrl = process.env.NEXT_PUBLIC_URL||"";
export default function AboutPage() {
...
const heroData = {
...
};
const journeyData = {
title: "My Journey",
items: [
.....
]
};
const projectsData = {
title: "Featured Projects",
projects: [
{
title: "大学入試統計分析",
...
},
...
],
};
return (
<div className="min-h-screen bg-gray-900 ">
<main className="rounded-lg container relative mx-auto scroll-my-12 overflow-auto">
{/* Language Selector */}
<HeroSection {...heroData} />
<JourneySection {...journeyData} />
<ProjectsSection {...projectsData} />
</main>
</div>
);
}
そしてko.jsonとen.jsonを設定し、コンポーネントはgetTranslationsでテキストを挿入します。

ただし問題はgetTranslationsで呼び出したものが文字列構造でしか出力されないこと。
下記のように変更しようとするとエラーが発生しました。
export default async function AboutPage() {
...
const t = await getTranslations("about");
const heroData = JSON.parse(JSON.stringify(t("hero")));
const journeyData = JSON.parse(JSON.stringify(t("journey")));
const projectsData = JSON.parse(JSON.stringify(t("projects")));
...
}あまりに面倒なので、カスタマイズサポートを受けました。

そのようにして下位コンポーネントにすべてpropsで渡しました。
そしてenでアクセスして確認しました。

うまく適用されていることが見受けられます。
4. 感想
今まで英語のブログを全部手作業でしなければと思っていたけれど、今やAIもあり、自動化されたツールがたくさんあるので簡単にできそうです。
あとはブログの文章をすべて翻訳してdbに入れること。
そしてdbにlocaleを追加し、localeで検索してpostを返せばよいでしょう。
近いうちに試してみます。
댓글을 불러오는 중...