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

TanStack Startのドキュメントを多言語に対応させます。

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

## 概要 [#overview]

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

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

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

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

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

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

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

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

`routes` の下に `$lang` ディレクトリを作成し、すべてのページをその中に移動してください。

<Files>
<Folder name="src/routes" defaultOpen>
<Folder name="$lang" defaultOpen>
<File name="index.tsx" />

<File name="docs/$.tsx" />
</Folder>

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

### 翻訳 [#translations]

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

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

```tsx title="src/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="src/routes/__root.tsx"
import { createRootRoute, HeadContent, Outlet, Scripts } from '@tanstack/react-router'; // [!code --]
import { createRootRoute, HeadContent, Outlet, Scripts, useParams } from '@tanstack/react-router'; // [!code ++]
import { RootProvider } from 'fumadocs-ui/provider/tanstack';
// [!code ++:3]
import { i18nProvider } from 'fumadocs-ui/i18n';
import { i18n } from '@/lib/i18n';
import { translations } from '@/lib/layout.shared';

// ...

function RootComponent() {
  const { lang = i18n.defaultLanguage } = useParams({ strict: false }); // [!code ++]

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

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

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

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

export const source = loader({
  source: docs.toFumadocsSource(),
  baseUrl: '/docs',
  i18n, // [!code ++]
});
```

```tsx tab="ホームページ" title="src/routes/$lang/index.tsx"
export const Route = createFileRoute('/')({ // [!code --]
export const Route = createFileRoute('/$lang/')({ // [!code ++]
  component: Home,
});

function Home() {
  const { lang } = Route.useParams(); // [!code ++]

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

```tsx tab="ドキュメントページ" title="src/routes/$lang/docs/$.tsx"
export const Route = createFileRoute('/docs/$')({ // [!code --]
export const Route = createFileRoute('/$lang/docs/$')({ // [!code ++]
  component: Page,
  loader: async ({ params }) => {
    const slugs = params._splat?.split('/') ?? [];
    const data = await serverLoader({ data: slugs }); // [!code --]
    const data = await serverLoader({ data: { slugs, lang: params.lang } }); // [!code ++]
    await docs.getPage(data.path)?.preload();
    return data;
  },
});

const serverLoader = createServerFn({
  method: 'GET',
})
  .validator((slugs: string[]) => slugs) // [!code --]
  .handler(async ({ data: slugs }) => { // [!code --]
  .validator((data: { slugs: string[]; lang: string }) => data) // [!code ++]
  .handler(async ({ data: { slugs, lang } }) => { // [!code ++]
    const page = source.getPage(slugs); // [!code --]
    const page = source.getPage(slugs, lang); // [!code ++]
    if (!page) throw notFound();

    return {
      path: page.path,
      pageTree: await source.serializePageTree(source.getPageTree()), // [!code --]
      pageTree: await source.serializePageTree(source.getPageTree(lang)), // [!code ++]
    };
  });

function Page() {
  const { lang } = Route.useParams(); // [!code ++]
  const data = useFumadocsLoader(Route.useLoaderData());

  return (
    // [!code highlight]
    <DocsLayout {...baseOptions(lang)} tree={data.pageTree}>
      <Suspense>
        <Content path={data.path} />
      </Suspense>
    </DocsLayout>
  );
}
```

### 検索 [#search]

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

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

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

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

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

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

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

```tsx
import { Link, useParams } from '@tanstack/react-router';

const { lang } = useParams({ from: '/$lang/' });

<Link
  to="/$lang/docs/$"
  params={{
    lang,
    _splat: '',
  }}
>
  Open Docs
</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>
```