} */
const metadataContent = {
key: "metadata",
content: {
title: t({
ja: "私のプロジェクトのタイトル",
en: "My Project Title",
fr: "Le Titre de mon Projet",
es: "El Título de mi Proyecto",
}),
description: t({
ja: "ワークフローを合理化し、生産性を向上させるために設計された革新的なプラットフォームをぜひご確認ください。",
en: "Discover our innovative platform designed to streamline your workflow and boost productivity.",
fr: "Découvrez notre plateforme innovante conçue pour simplifier votre flux de travail et booster votre productivité.",
es: "Descubra nuestra plataforma innovadora diseñada para simplificar su flujo de trabajo y aumentar su productividad.",
}),
keywords: t({
ja: ["イノベーション", "生産性", "ワークフロー", "SaaS"],
en: ["innovation", "productivity", "workflow", "SaaS"],
fr: ["innovation", "productivité", "flux de travail", "SaaS"],
es: ["innovación", "productividad", "flujo de trabajo", "SaaS"],
}),
},
};
module.exports = metadataContent;
```
```json fileName="src/app/metadata.content.json" contentDeclarationFormat="json"
{
"key": "metadata",
"content": {
"title": {
"nodeType": "translation",
"translation": {
"ja": "私のプロジェクトのタイトル",
"en": "My Project Title",
"fr": "Le Titre de mon Projet",
"es": "El Título de mi Proyecto"
}
},
"description": {
"nodeType": "translation",
"translation": {
"ja": "ワークフローを合理化し、生産性を向上させるよう設計された革新的なプラットフォームです。",
"en": "Discover our innovative platform designed to streamline your workflow and boost productivity.",
"ja": "ワークフローを簡素化し、生産性を向上させるために設計された革新的なプラットフォームをご覧ください。",
"fr": "Découvrez notre plateforme innovante conçue pour simplifier votre flux de travail et booster votre productivité.",
"es": "Descubra nuestra plataforma innovadora diseñada para simplificar su flujo de trabajo y aumentar su productividad."
}
},
"keywords": {
"nodeType": "translation",
"translation": {
"ja": ["イノベーション", "生産性", "ワークフロー", "SaaS"],
"en": ["innovation", "productivity", "workflow", "SaaS"],
"fr": ["innovation", "productivité", "flux de travail", "SaaS"],
"es": ["innovación", "productividad", "flujo de trabajo", "SaaS"]
}
}
}
}
```
```tsx fileName="src/app/page.content.ts" contentDeclarationFormat="typescript"
import { t, type Dictionary } from "intlayer";
const pageContent = {
key: "page",
content: {
getStarted: {
main: t({
ja: "編集して始めましょう",
en: "Get started by editing",
fr: "Commencez par éditer",
es: "Comience por editar",
}),
pageLink: "src/app/page.tsx",
},
},
} satisfies Dictionary;
export default pageContent;
```
```javascript fileName="src/app/page.content.mjs" contentDeclarationFormat="esm"
import { t } from "intlayer";
/** @type {import('intlayer').Dictionary} */
const pageContent = {
key: "page",
content: {
getStarted: {
main: t({
ja: "編集して始めましょう",
en: "Get started by editing",
fr: "Commencez par éditer",
es: "Comience por editar",
}),
pageLink: "src/app/page.tsx",
},
},
};
export default pageContent;
```
```javascript fileName="src/app/page.content.cjs" contentDeclarationFormat="commonjs"
const { t } = require("intlayer");
/** @type {import('intlayer').Dictionary} */
const pageContent = {
key: "page",
content: {
getStarted: {
main: t({
ja: "編集して始めましょう",
en: "Get started by editing",
fr: "Commencez par éditer",
es: "Comience por editar",
}),
pageLink: "src/app/page.tsx",
},
},
};
module.exports = pageContent;
```
```json fileName="src/app/page.content.json" contentDeclarationFormat="json"
{
"$schema": "https://intlayer.org/schema.json",
"key": "page",
"content": {
"getStarted": {
"nodeType": "translation",
"translation": {
"ja": "編集して始めましょう",
"en": "Get started by editing",
"fr": "Commencez par éditer",
"es": "Comience por editar"
}
},
"pageLink": "src/app/page.tsx"
}
}
```
> コンテンツの宣言は、アプリケーション内の任意の場所に定義できます。ただし、それらが `contentDir` ディレクトリ(デフォルトは `./src`)に含まれており、コンテンツ宣言ファイルの拡張子が一致している必要があります(デフォルト: `.content.{json,ts,tsx,js,jsx,mjs,mjx,cjs,cjx}`)。
> 詳細は、[コンテンツ宣言のドキュメント](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ja/dictionary/content_file.md) を参照してください。
### ステップ6: コード内でコンテンツを利用する
アプリケーション全体からコンテンツ辞書にアクセスします:
```tsx fileName="src/app/page.tsx" codeFormat="typescript"
import type { FC } from "react";
import { ClientComponentExample } from "@components/clientComponentExample/ClientComponentExample";
import { ServerComponentExample } from "@components/serverComponentExample/ServerComponentExample";
import {
IntlayerServerProvider,
useIntlayer,
getLocale,
} from "next-intlayer/server";
import { NextPage } from "next";
import { headers, cookies } from "next/headers";
const PageContent: FC = () => {
const content = useIntlayer("page");
return (
<>
{content.getStarted.main}
{content.getStarted.pageLink}
>
);
};
const Page: NextPage = async () => {
// Next.js 15+ では headers と cookies を await してください
const headerList = await headers();
const cookieList = await cookies();
const locale = await getLocale({
// まず intlayer のクッキーを確認します(デフォルト: 'INTLAYER_LOCALE')
getCookie: (name) => cookieList.get(name)?.value,
// 次に intlayer ヘッダーを確認します(デフォルト: 'x-intlayer-locale')
// 最後に accept-language ヘッダーを確認します('accept-language')
getHeader: (name) => headerList.get(name),
});
return (
);
};
export default Page;
```
```jsx fileName="src/app/page.mjx" codeFormat="esm"
import { ClientComponentExample } from "@components/clientComponentExample/ClientComponentExample";
import { ServerComponentExample } from "@components/serverComponentExample/ServerComponentExample";
import { IntlayerServerProvider, useIntlayer, getLocale } from "next-intlayer/server";
import { headers, cookies } from "next/headers";
import { NextPage } from "next";
const Page: NextPage = async () => {
const content = useIntlayer("page");
return (
<>
{content.getStarted.main}
{content.getStarted.pageLink}
>
);
};
const Page = async () => {
// Next.js 15+ では headers と cookies を await します
const headerList = await headers();
const cookieList = await cookies();
const locale = await getLocale({
// まず intlayer のクッキーを確認します(デフォルト: 'INTLAYER_LOCALE')
getCookie: (name) => cookieList.get(name)?.value,
// 次に intlayer のヘッダーを確認します(デフォルト: 'x-intlayer-locale')
// 最後に accept-language ヘッダーを確認します('accept-language')
getHeader: (name) => headerList.get(name),
});
return (
);
};
export default Page;
```
````jsx fileName="src/app/page.csx" codeFormat="commonjs"
import { ClientComponentExample } from "@components/clientComponentExample/ClientComponentExample";
import { ServerComponentExample } from "@components/serverComponentExample/ServerComponentExample";
import { IntlayerServerProvider, useIntlayer, getLocale } from "next-intlayer/server";
import { NextPage } from "next";
import { headers, cookies } from "next/headers";
const Page: NextPage = async () => {
const content = useIntlayer("page");
return (
<>
{content.getStarted.main}
{content.getStarted.pageLink}
>
);
};
const Page: NextPage = async () => {
// Next.js 15+ では headers と cookies を await する必要があります
const headerList = await headers();
const cookieList = await cookies();
const locale = await getLocale({
// まず intlayer の cookie をチェックします(デフォルト: 'INTLAYER_LOCALE')
getCookie: (name) => cookieList.get(name)?.value,
// 次に intlayer のヘッダーをチェックします(デフォルト: 'x-intlayer-locale')
// 最後に accept-language ヘッダー('accept-language')をチェックします
getHeader: (name) => headerList.get(name),
});
return (
);
};
- **`IntlayerClientProvider`** はクライアント側コンポーネントにロケールを提供するために使用されます。レイアウトを含む任意の親コンポーネントに配置できます。ただし、Next.js がページ間でレイアウトコードを共有するため、レイアウトに配置することが推奨されます。レイアウトで `IntlayerClientProvider` を使用することで、各ページごとに再初期化されることを避け、パフォーマンスを向上させ、アプリケーション全体で一貫したローカリゼーションコンテキストを維持できます。
- **`IntlayerServerProvider`** はサーバー側の子にロケールを提供するために使用されます。レイアウトに設定することはできません。
> Layout と page は共通の server context を共有できません。server context システムはリクエスト単位のデータストア([React の cache](https://react.dev/reference/react/cache) 機構)に基づいており、アプリケーションの異なるセグメントごとに各 "context" が再作成されます。provider を共有 layout に配置するとこの分離が壊れ、server component に対する server context 値の正しい伝播が妨げられます。
```tsx {4,7} fileName="src/components/clientComponentExample/ClientComponentExample.tsx" codeFormat="typescript"
"use client";
import type { FC } from "react";
import { useIntlayer } from "next-intlayer";
export const ClientComponentExample: FC = () => {
const content = useIntlayer("client-component-example"); // 関連コンテンツの宣言を作成します
return (
{content.title}
{content.content}
);
};
```jsx {3,6} fileName="src/components/clientComponentExample/ClientComponentExample.mjx" codeFormat="esm"
"use client";
import { useIntlayer } from "next-intlayer";
const ClientComponentExample = () => {
const content = useIntlayer("client-component-example"); // 関連コンテンツの宣言を作成
return (
{content.title}
{content.content}
);
};
````
```jsx {3,6} fileName="src/components/clientComponentExample/ClientComponentExample.csx" codeFormat="commonjs"
"use client";
const { useIntlayer } = require("next-intlayer");
const ClientComponentExample = () => {
const content = useIntlayer("client-component-example"); // 関連コンテンツの宣言を作成
return (
{content.title}
{content.content}
);
};
```
```tsx {2} fileName="src/components/serverComponentExample/ServerComponentExample.tsx" codeFormat="typescript"
import type { FC } from "react";
import { useIntlayer } from "next-intlayer/server";
export const ServerComponentExample: FC = () => {
const content = useIntlayer("server-component-example"); // 関連コンテンツの宣言を作成
return (
{content.title}
{content.content}
);
};
```
```jsx {1} fileName="src/components/serverComponentExample/ServerComponentExample.mjx" codeFormat="esm"
import { useIntlayer } from "next-intlayer/server";
const ServerComponentExample = () => {
const content = useIntlayer("server-component-example"); // 関連コンテンツの宣言を作成
return (
{content.title}
{content.content}
);
};
```
```jsx {1} fileName="src/components/serverComponentExample/ServerComponentExample.csx" codeFormat="commonjs"
const { useIntlayer } = require("next-intlayer/server");
const ServerComponentExample = () => {
const content = useIntlayer("server-component-example"); // 関連コンテンツの宣言を作成
return (
{content.title}
{content.content}
);
};
```
> `alt`、`title`、`href`、`aria-label` などの `string` 属性でコンテンツを使用する場合は、関数の値を呼び出す必要があります。例えば:
> ```jsx
>
> ```
> `useIntlayer` フックの詳細は[ドキュメント](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ja/packages/next-intlayer/useIntlayer.md)を参照してください。
### (オプション)ステップ7: ロケール検出のためにプロキシを設定
ユーザーの優先ロケールを検出するようにプロキシを設定します:
```typescript fileName="src/proxy.ts" codeFormat="typescript"
export { intlayerProxy as proxy } from "next-intlayer/proxy";
export const config = {
matcher:
"/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\\..*|_next).*)",
};
```
```javascript fileName="src/proxy.mjs" codeFormat="esm"
export { intlayerProxy as proxy } from "next-intlayer/proxy";
export const config = {
matcher:
"/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\\..*|_next).*)",
};
```
```javascript fileName="src/proxy.cjs" codeFormat="commonjs"
const { intlayerProxy } = require("next-intlayer/proxy");
const config = {
matcher:
"/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\\..*|_next).*)",
};
module.exports = { proxy: intlayerProxy, config };
```
> `intlayerProxy` はユーザーの優先ロケールを検出し、[設定](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ja/configuration.md)に記載された適切な URL へリダイレクトするために使用されます。さらに、ユーザーの優先ロケールをクッキーに保存することも可能にします。
> 複数のプロキシを連結する必要がある場合(例えば、認証やカスタムプロキシと `intlayerProxy` を組み合わせる場合)、Intlayer は `multipleProxies` というヘルパーを提供しています。
```ts
import { multipleProxies, intlayerProxy } from "next-intlayer/proxy";
import { customProxy } from "@utils/customProxy";
export const proxy = multipleProxies([intlayerProxy, customProxy]);
```
### (オプション)ステップ 8: コンテンツの言語を変更する
Next.jsでコンテンツの言語を切り替えるには、推奨される方法は`Link`コンポーネントを使用してユーザーを適切なローカライズされたページにリダイレクトすることです。`Link`コンポーネントはページのプリフェッチを可能にし、フルページのリロードを回避するのに役立ちます。
```tsx fileName="src/components/localeSwitcher/LocaleSwitcher.tsx" codeFormat="typescript"
"use client";
import type { FC } from "react";
import { Locales, getHTMLTextDir, getLocaleName } from "intlayer";
import { useLocale } from "next-intlayer";
export const LocaleSwitcher: FC = () => {
const { locale, availableLocales, setLocale } = useLocale({
onChange: () => window.location.reload(),
});
return (
{availableLocales.map((localeItem) => (
);
};
```
```jsx fileName="src/components/localeSwitcher/LocaleSwitcher.msx" codeFormat="esm"
"use client";
import { Locales, getHTMLTextDir, getLocaleName } from "intlayer";
import { useLocale } from "next-intlayer";
export const LocaleSwitcher = () => {
const { locale, availableLocales, setLocale } = useLocale({
onChange: () => window.location.reload(),
});
return (
{getLocaleName(locale)}
{availableLocales.map((localeItem) => (
setLocale(localeItem)}
>
{/* ロケール - 例: FR */}
{localeItem}
{/* 該当ロケールでの言語名 - 例: Français */}
{getLocaleName(localeItem, locale)}
{/* 現在のロケールで表示した言語名 - 例: ロケールが Locales.SPANISH に設定されている場合: Francés */}
{getLocaleName(localeItem)}
{/* 英語での言語名 - 例: French */}
{getLocaleName(localeItem, Locales.ENGLISH)}
))}
);
};
```
```jsx fileName="src/components/localeSwitcher/LocaleSwitcher.csx" codeFormat="commonjs"
"use client";
const { Locales, getHTMLTextDir, getLocaleName } = require("intlayer");
const { useLocale } = require("next-intlayer");
export const LocaleSwitcher = () => {
const path
const { locale availableLocales, setLocale } = useLocale({
onChange: ()=> window.location.reload(),
});
return (
{getLocaleName(locale)}
{availableLocales.map((localeItem) => (
setLocale(localeItem)}
>
{/* ロケール(例: FR) */}
{localeItem}
{/* そのロケールでの言語名(例: Français) */}
{getLocaleName(localeItem, locale)}
{/* 現在のロケールでの言語名(例: 現在のロケールが Locales.SPANISH の場合: Francés) */}
{getLocaleName(localeItem)}
{/* 英語での言語名(例: French) */}
{getLocaleName(localeItem, Locales.ENGLISH)}
))}
);
};
```
> 代替方法として、`useLocale` フックが提供する `setLocale` 関数を使用できます。この関数はページのプリフェッチを許可しません。詳細は [`useLocale` フックのドキュメント](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ja/packages/next-intlayer/useLocale.md) を参照してください。
> ドキュメント参照:
>
> - [`useLocale` フック](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ja/packages/next-intlayer/useLocale.md)
> - [`getLocaleName` フック](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ja/packages/intlayer/getLocaleName.md)
> - [`getLocalizedUrl` フック](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ja/packages/intlayer/getLocalizedUrl.md)
- [`getHTMLTextDir` フック](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ja/packages/intlayer/getHTMLTextDir.md)
- [`hrefLang` 属性](https://developers.google.com/search/docs/specialty/international/localized-versions?hl=fr)
- [`lang` 属性](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang)
- [`dir` 属性](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/dir)
- [`aria-current` 属性](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-current)
### (任意)ステップ 9: Server Actions で現在のロケールを取得する
Server Action の内部でアクティブなロケールが必要な場合(例: メールのローカライズやロケール対応のロジックを実行する場合)、`next-intlayer/server` から `getLocale` を呼び出してください:
```tsx fileName="src/app/actions/getLocale.ts" codeFormat="typescript"
"use server";
import { getLocale } from "next-intlayer/server";
export const myServerAction = async () => {
const locale = await getLocale();
// ロケールを使って処理を行います
};
```
> `getLocale` 関数はユーザーのロケールを決定するためにカスケード戦略を採用します:
>
> 1. まず、プロキシによって設定されている可能性のあるロケール値についてリクエストヘッダーを確認します
> 2. ヘッダーにロケールが見つからない場合、クッキーに保存されたロケールを探します
> 3. クッキーが見つからない場合、ブラウザ設定からユーザーの優先言語を検出しようとします
> 4. 最後の手段として、アプリケーションで設定されたデフォルトロケールにフォールバックします
>
> これにより、利用可能なコンテキストに基づいて最も適切なロケールが選択されます。
### (任意)ステップ10:バンドルサイズを最適化する
`next-intlayer` を使用すると、辞書はデフォルトで各ページのバンドルに含まれます。バンドルサイズを最適化するために、Intlayer はマクロを使用して `useIntlayer` の呼び出しをインテリジェントに置き換えるオプションの SWC プラグインを提供しています。これにより、辞書は実際にそれらを使用するページのバンドルにのみ含まれるようになります。
この最適化を有効にするには、`@intlayer/swc` パッケージをインストールしてください。インストール後、`next-intlayer` は自動的にプラグインを検出して使用します:
```bash packageManager="npm"
npm install @intlayer/swc --save-dev
npx intlayer init
```
```bash packageManager="pnpm"
pnpm add @intlayer/swc --save-dev
pnpm intlayer init
```
```bash packageManager="yarn"
yarn add @intlayer/swc --save-dev
yarn intlayer init
```
```bash packageManager="bun"
bun add @intlayer/swc --dev
bunx intlayer init
```
> 注意: この最適化は Next.js 13 以降でのみ利用可能です。
> 注意: SWCプラグインは Next.js 上でまだ実験的なため、このパッケージはデフォルトでインストールされません。将来的に変更される可能性があります。
> 注意: オプションを `importMode: 'dynamic'` または `importMode: 'live'` に設定すると、Suspense に依存するため、`useIntlayer` の呼び出しを `Suspense` 境界でラップする必要があります。つまり、Page / Layout コンポーネントのトップレベルで `useIntlayer` を直接使用することはできません。
### Turbopackで辞書の変更を監視する
Turbopackを開発サーバーとして`next dev`コマンドで使用している場合、辞書の変更はデフォルトでは自動的に検出されません。
この制限は、Turbopackがコンテンツファイルの変更を監視するためのwebpackプラグインを並列で実行できないために発生します。回避するには、`intlayer watch`コマンドを使用して、開発サーバーとIntlayerのビルドウォッチャーを同時に実行する必要があります。
```json5 fileName="package.json"
{
// ... 既存の package.json 設定
"scripts": {
// ... 既存の scripts 設定
"dev": "intlayer watch --with 'next dev'",
},
}
```
> next-intlayer@<=6.x.x を使用している場合、Next.js 16 アプリケーションを Turbopack と正しく動作させるために `--turbopack` フラグを維持する必要があります。この制約を回避するには next-intlayer@>=7.x.x の使用を推奨します。
### TypeScript の設定
Intlayer は TypeScript の利点を活かすためにモジュール拡張 (module augmentation) を使用し、コードベースをより堅牢にします。


TypeScript の設定に自動生成された型が含まれていることを確認してください。
````json5 fileName="tsconfig.json"
{
// ... 既存の TypeScript 設定
"include": [
// ... 既存の TypeScript 設定
".intlayer/**/*.ts", // 自動生成された型を含める
],
}
### Git 設定
Intlayer によって生成されたファイルは無視することを推奨します。これにより、これらのファイルを Git リポジトリにコミットすることを避けられます。
これを行うには、次の内容を `.gitignore` ファイルに追加してください:
```plaintext fileName=".gitignore"
# Intlayer によって生成されたファイルを無視する
.intlayer
````
### VS Code 拡張機能
Intlayer の開発体験を向上させるために、公式の **Intlayer VS Code Extension** をインストールできます。
[VS Code Marketplace からインストール](https://marketplace.visualstudio.com/items?itemName=intlayer.intlayer-vs-code-extension)
この拡張機能は次の機能を提供します:
- **Autocompletion**: 翻訳キーの補完。
- **リアルタイムのエラーチェック**: 翻訳が欠落している箇所の検出。
- **翻訳されたコンテンツのインラインプレビュー**
- **翻訳を簡単に作成・更新するためのクイックアクション**
拡張機能の使用方法の詳細については、[Intlayer VS Code 拡張機能のドキュメント](https://intlayer.org/doc/vs-code-extension) を参照してください。
### さらに進む
さらに進むには、[ビジュアルエディタ](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ja/intlayer_visual_editor.md) を実装するか、[CMS](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ja/intlayer_CMS.md) を使用してコンテンツを外部化できます。