# Fumadocs (Framework Mode, Next.js): 国際化
URL: /ja/docs/next/internationalization
Source: https://raw.githubusercontent.com/fuma-nama/fumadocs/refs/heads/main/apps/docs/content/docs/(framework)/[framework]/internationalization.ja.mdx

Next.jsのドキュメントを多言語に対応させます。

<Callout title="Fumadocs CLI">
`npx @fumadocs/cli init --i18n` を実行すると、i18n に対応した新しいドキュメントをセットアップできます。手動で設定する場合は、以下の手順に従ってください。
</Callout>

## 概要 [#overview]

Next.js と Fumadocs の両方で i18n ルーティングを設定します。

Fumadocs が担当するのは、ドキュメントのコンテンツとサイドバーの i18n です。アプリのその他の部分は、独自の i18n 設定で国際化してください。

[next-intl](https://github.com/amannn/next-intl) などのライブラリを Fumadocs と組み合わせて使うこともできます。基本については、[Next.js の i18n](https://nextjs.org/docs/app/building-your-application/routing/internationalization) を参照してください。

## セットアップ [#setup]

i18n の設定をファイルに定義します。このガイドでは、`@/lib/i18n` としてインポートします。

```ts title="lib/i18n.ts"
import { defineI18n } from 'fumadocs-core/i18n';

export const i18n = defineI18n({
  defaultLanguage: 'en',
  languages: ['en', 'cn'],
});
```

> i18n の設定で使用できるオプションについては、[こちら](/docs/headless/internationalization/config)を参照してください。

### ミドルウェア [#middleware]

ユーザーを適切なロケールへリダイレクトするミドルウェアを作成します。

```ts title="proxy.ts"
import { createI18nMiddleware } from 'fumadocs-core/i18n/middleware';
import { i18n } from '@/lib/i18n';

export default createI18nMiddleware(i18n);

export const config = {
  // Matcher ignoring `/_next/` and `/api/`
  // You may need to adjust it to ignore static assets in `/public` folder
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};
```

<Callout title="独自のミドルウェアを使う場合">
デフォルトのミドルウェアの使用は任意です。独自のミドルウェアや、i18n ライブラリが提供するミドルウェアを使うこともできます。

その場合は、ミドルウェアの動作が i18n の設定で指定した [`hideLocale`](/docs/headless/internationalization/config#hide-locale-prefix) オプションと整合していることを確認してください。
</Callout>

### ルーティング [#routing]

`/app/[lang]` フォルダーを作成し、ルートハンドラー以外のページとレイアウトをすべてその中に移動してください。

<Files>
<Folder name="app" defaultOpen>
<File name="api/search/route.ts" />

<Folder name="[lang]" defaultOpen>
<File name="layout.tsx" />

<File name="(home)/page.tsx" />

<File name="..." />
</Folder>
</Folder>
</Files>

<Callout title="よくある間違い" type="error">
スタイルが消えてしまっていませんか？`global.css` のインポートパスが正しいままか確認してください。
</Callout>

### 翻訳 [#translations]

翻訳は `lib/layout.shared.tsx` で定義します。公式の言語パックなど、詳しくは[翻訳](/docs/ui/translations)を参照してください。

また、`baseOptions()` に `locale` パラメーターを追加すると、ロケールごとにレイアウトオプションを切り替えられます。

```tsx title="lib/layout.shared.tsx"
// [!code ++:2]
import { i18n } from '@/lib/i18n';
import { uiTranslations } from 'fumadocs-ui/i18n';
import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';

// [!code ++:11]
export const translations = i18n
  .translations()
  .extend(uiTranslations())
  .add({
    en: {
      displayName: 'English',
    },
    cn: {
      displayName: 'Chinese',
    },
  });

export function baseOptions(): BaseLayoutProps { // [!code --]
export function baseOptions(locale: string): BaseLayoutProps { // [!code ++]
  return {
    // `locale` に応じて異なる props を指定
  };
}
```

翻訳を `<RootProvider />` に渡します。

```tsx title="app/[lang]/layout.tsx"
import { RootProvider } from 'fumadocs-ui/provider/next';
// [!code ++:2]
import { i18nProvider } from 'fumadocs-ui/i18n';
import { translations } from '@/lib/layout.shared';

export default function Layout({ children }: LayoutProps<'/'>) { // [!code --]
// [!code ++:2]
export default async function Layout({ params, children }: LayoutProps<'/[lang]'>) {
  const { lang } = await params;

  return (
    // [!code highlight]
    <html lang={lang} suppressHydrationWarning>
      <body className="flex flex-col min-h-screen">
        <RootProvider
          // [!code ++]
          i18n={i18nProvider(translations, lang)}
        >
          {children}
        </RootProvider>
      </body>
    </html>
  );
}
```

### ロケールを渡す [#pass-locale]

ページとレイアウトで、ロケールを Fumadocs に渡します。

```ts tab="lib/source.ts"
import { i18n } from '@/lib/i18n'; // [!code ++]
import { loader } from 'fumadocs-core/source';

export const source = loader({
  i18n, // [!code ++]
  // その他のオプション
});
```

```tsx tab="Home Layout" title="app/[lang]/(home)/layout.tsx"
export default function Layout({ children }: LayoutProps<'/'>) { // [!code --]
// [!code ++:2]
export default async function Layout({ params, children }: LayoutProps<'/[lang]'>) {
  const { lang } = await params;

  return <HomeLayout {...baseOptions(lang)}>{children}</HomeLayout>; // [!code highlight]
}
```

```tsx tab="Docs Layout" title="app/[lang]/docs/layout.tsx"
export default function Layout({ children }: LayoutProps<'/docs'>) { // [!code --]
// [!code ++:2]
export default async function Layout({ params, children }: LayoutProps<'/[lang]/docs'>) {
  const { lang } = await params;

  return (
    // [!code highlight]
    <DocsLayout {...baseOptions(lang)} tree={source.getPageTree(lang)}>
      {children}
    </DocsLayout>
  );
}
```

```tsx tab="Docs Page" title="app/[lang]/docs/[[...slug]]/page.tsx"
export default async function Page(props: PageProps<'/docs/[[...slug]]'>) { // [!code --]
export default async function Page(props: PageProps<'/[lang]/docs/[[...slug]]'>) { // [!code ++]
  const params = await props.params;
  const page = source.getPage(params.slug); // [!code --]
  const page = source.getPage(params.slug, params.lang); // [!code ++]
  if (!page) notFound();

  // ...
}
```

<Callout>
`app/[locale]` のように別の名前を使用している場合は、docs ページの `generateStaticParams()` も更新する必要があります。

```tsx
export function generateStaticParams() {
  return source.generateParams(); // [!code --]
  return source.generateParams('slug', 'locale'); // [!code ++]
}
```
</Callout>

### 検索 [#search]

使用している検索ソリューションで i18n を設定してください。

* **組み込み検索:** [国際化](/docs/headless/search/orama#internationalization)を参照してください。
* **クラウドソリューション(Algolia など):** 多くの場合、多言語対応が公式にサポートされています。

## ドキュメントの作成 [#writing-documents]

特定のロケール向けのページを作成する方法については、[i18n ルーティング](/docs/next/page-conventions#i18n-routing)を参照してください。

### ナビゲーション [#navigation]

Fumadocs がナビゲーションを処理するのは、Fumadocs 自身のレイアウト(サイドバーなど)のみです。

それ以外の場所では、`useParams` フックで URL からロケールを取得し、`href` の先頭に付加してください。

```tsx
import Link from 'next/link';
import { useParams } from 'next/navigation';

const { lang } = useParams();

return <Link href={`/${lang}/another-page`}>This is a link</Link>;
```

[`fumadocs-core/dynamic-link`](/docs/headless/components/link#dynamic-hrefs) コンポーネントは動的な href に対応しているため、Markdown/MDX コンテンツ内でロケールのプレフィックスを付加する際に利用できます。

```mdx title="content.mdx"
import { DynamicLink } from 'fumadocs-core/dynamic-link';

<DynamicLink href="/[lang]/another-page">This is a link</DynamicLink>
```