@intlayer/docs 7.5.6 → 7.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/blog/ar/intlayer_with_i18next.md +4 -4
- package/blog/ar/intlayer_with_next-i18next.md +4 -4
- package/blog/ar/intlayer_with_next-intl.md +4 -4
- package/blog/ar/intlayer_with_react-i18next.md +4 -4
- package/blog/ar/intlayer_with_react-intl.md +4 -4
- package/blog/ar/intlayer_with_vue-i18n.md +4 -4
- package/blog/de/intlayer_with_i18next.md +4 -4
- package/blog/de/intlayer_with_next-i18next.md +4 -4
- package/blog/de/intlayer_with_next-intl.md +4 -4
- package/blog/de/intlayer_with_react-i18next.md +4 -4
- package/blog/de/intlayer_with_react-intl.md +4 -4
- package/blog/de/intlayer_with_vue-i18n.md +4 -4
- package/blog/en/intlayer_with_i18next.md +4 -4
- package/blog/en/intlayer_with_next-i18next.md +4 -4
- package/blog/en/intlayer_with_next-intl.md +4 -4
- package/blog/en/intlayer_with_react-i18next.md +4 -4
- package/blog/en/intlayer_with_react-intl.md +4 -4
- package/blog/en/intlayer_with_vue-i18n.md +4 -4
- package/blog/en-GB/intlayer_with_i18next.md +4 -4
- package/blog/en-GB/intlayer_with_next-i18next.md +4 -4
- package/blog/en-GB/intlayer_with_next-intl.md +4 -4
- package/blog/en-GB/intlayer_with_react-i18next.md +4 -4
- package/blog/en-GB/intlayer_with_react-intl.md +4 -4
- package/blog/en-GB/intlayer_with_vue-i18n.md +4 -4
- package/blog/es/intlayer_with_i18next.md +4 -4
- package/blog/es/intlayer_with_next-i18next.md +4 -4
- package/blog/es/intlayer_with_next-intl.md +4 -4
- package/blog/es/intlayer_with_react-i18next.md +4 -4
- package/blog/es/intlayer_with_react-intl.md +4 -4
- package/blog/es/intlayer_with_vue-i18n.md +4 -4
- package/blog/fr/intlayer_with_i18next.md +4 -4
- package/blog/fr/intlayer_with_next-i18next.md +4 -4
- package/blog/fr/intlayer_with_next-intl.md +4 -4
- package/blog/fr/intlayer_with_react-i18next.md +4 -4
- package/blog/fr/intlayer_with_react-intl.md +4 -4
- package/blog/fr/intlayer_with_vue-i18n.md +4 -4
- package/blog/hi/intlayer_with_i18next.md +4 -4
- package/blog/hi/intlayer_with_next-i18next.md +4 -4
- package/blog/hi/intlayer_with_next-intl.md +4 -4
- package/blog/hi/intlayer_with_react-i18next.md +4 -4
- package/blog/hi/intlayer_with_react-intl.md +4 -4
- package/blog/hi/intlayer_with_vue-i18n.md +4 -4
- package/blog/id/intlayer_with_i18next.md +4 -4
- package/blog/id/intlayer_with_next-i18next.md +4 -4
- package/blog/id/intlayer_with_next-intl.md +4 -4
- package/blog/id/intlayer_with_react-i18next.md +4 -4
- package/blog/id/intlayer_with_react-intl.md +4 -4
- package/blog/id/intlayer_with_vue-i18n.md +4 -4
- package/blog/it/intlayer_with_i18next.md +4 -4
- package/blog/it/intlayer_with_next-i18next.md +4 -4
- package/blog/it/intlayer_with_next-intl.md +4 -4
- package/blog/it/intlayer_with_react-i18next.md +4 -4
- package/blog/it/intlayer_with_react-intl.md +4 -4
- package/blog/it/intlayer_with_vue-i18n.md +4 -4
- package/blog/ja/intlayer_with_i18next.md +4 -4
- package/blog/ja/intlayer_with_next-i18next.md +4 -4
- package/blog/ja/intlayer_with_next-intl.md +4 -4
- package/blog/ja/intlayer_with_react-i18next.md +4 -4
- package/blog/ja/intlayer_with_react-intl.md +4 -4
- package/blog/ja/intlayer_with_vue-i18n.md +4 -4
- package/blog/ko/intlayer_with_i18next.md +4 -4
- package/blog/ko/intlayer_with_next-i18next.md +4 -4
- package/blog/ko/intlayer_with_next-intl.md +4 -4
- package/blog/ko/intlayer_with_react-i18next.md +4 -4
- package/blog/ko/intlayer_with_react-intl.md +4 -4
- package/blog/ko/intlayer_with_vue-i18n.md +4 -4
- package/blog/pl/intlayer_with_i18next.md +4 -4
- package/blog/pl/intlayer_with_next-i18next.md +4 -4
- package/blog/pl/intlayer_with_next-intl.md +4 -4
- package/blog/pl/intlayer_with_react-i18next.md +4 -4
- package/blog/pl/intlayer_with_react-intl.md +4 -4
- package/blog/pl/intlayer_with_vue-i18n.md +4 -4
- package/blog/pt/intlayer_with_i18next.md +4 -4
- package/blog/pt/intlayer_with_next-i18next.md +4 -4
- package/blog/pt/intlayer_with_next-intl.md +4 -4
- package/blog/pt/intlayer_with_react-i18next.md +4 -4
- package/blog/pt/intlayer_with_react-intl.md +4 -4
- package/blog/pt/intlayer_with_vue-i18n.md +4 -4
- package/blog/ru/intlayer_with_i18next.md +4 -4
- package/blog/ru/intlayer_with_next-i18next.md +4 -4
- package/blog/ru/intlayer_with_next-intl.md +4 -4
- package/blog/ru/intlayer_with_react-i18next.md +4 -4
- package/blog/ru/intlayer_with_react-intl.md +4 -4
- package/blog/ru/intlayer_with_vue-i18n.md +4 -4
- package/blog/tr/intlayer_with_i18next.md +4 -4
- package/blog/tr/intlayer_with_next-i18next.md +4 -4
- package/blog/tr/intlayer_with_next-intl.md +4 -4
- package/blog/tr/intlayer_with_react-i18next.md +4 -4
- package/blog/tr/intlayer_with_react-intl.md +4 -4
- package/blog/tr/intlayer_with_vue-i18n.md +4 -4
- package/blog/vi/intlayer_with_i18next.md +4 -4
- package/blog/vi/intlayer_with_next-i18next.md +4 -4
- package/blog/vi/intlayer_with_next-intl.md +4 -4
- package/blog/vi/intlayer_with_react-i18next.md +4 -4
- package/blog/vi/intlayer_with_react-intl.md +4 -4
- package/blog/vi/intlayer_with_vue-i18n.md +4 -4
- package/blog/zh/intlayer_with_i18next.md +4 -4
- package/blog/zh/intlayer_with_next-i18next.md +4 -4
- package/blog/zh/intlayer_with_next-intl.md +4 -4
- package/blog/zh/intlayer_with_react-i18next.md +4 -4
- package/blog/zh/intlayer_with_react-intl.md +4 -4
- package/blog/zh/intlayer_with_vue-i18n.md +4 -4
- package/docs/ar/intlayer_with_next-i18next.md +3 -3
- package/docs/ar/intlayer_with_next-intl.md +3 -3
- package/docs/ar/intlayer_with_react_router_v7.md +72 -16
- package/docs/ar/intlayer_with_react_router_v7_fs_routes.md +2 -0
- package/docs/de/intlayer_with_next-i18next.md +3 -3
- package/docs/de/intlayer_with_next-intl.md +3 -3
- package/docs/de/intlayer_with_react_router_v7.md +72 -15
- package/docs/de/intlayer_with_react_router_v7_fs_routes.md +95 -19
- package/docs/en/configuration.md +1 -0
- package/docs/en/intlayer_with_next-i18next.md +3 -3
- package/docs/en/intlayer_with_next-intl.md +3 -3
- package/docs/en/intlayer_with_react_router_v7.md +74 -15
- package/docs/en/intlayer_with_react_router_v7_fs_routes.md +98 -19
- package/docs/en-GB/configuration.md +1 -0
- package/docs/en-GB/intlayer_with_next-i18next.md +3 -3
- package/docs/en-GB/intlayer_with_next-intl.md +3 -3
- package/docs/en-GB/intlayer_with_react_router_v7.md +73 -16
- package/docs/en-GB/intlayer_with_react_router_v7_fs_routes.md +2 -0
- package/docs/es/intlayer_with_next-i18next.md +3 -3
- package/docs/es/intlayer_with_next-intl.md +3 -3
- package/docs/es/intlayer_with_react_router_v7.md +72 -15
- package/docs/es/intlayer_with_react_router_v7_fs_routes.md +95 -19
- package/docs/fr/intlayer_with_next-i18next.md +3 -3
- package/docs/fr/intlayer_with_next-intl.md +3 -3
- package/docs/fr/intlayer_with_react_router_v7.md +72 -15
- package/docs/fr/intlayer_with_react_router_v7_fs_routes.md +95 -19
- package/docs/hi/intlayer_with_next-i18next.md +3 -3
- package/docs/hi/intlayer_with_next-intl.md +3 -3
- package/docs/hi/intlayer_with_react_router_v7.md +72 -16
- package/docs/hi/intlayer_with_react_router_v7_fs_routes.md +2 -0
- package/docs/id/intlayer_with_next-i18next.md +3 -3
- package/docs/id/intlayer_with_next-intl.md +3 -3
- package/docs/id/intlayer_with_react_router_v7.md +72 -15
- package/docs/id/intlayer_with_react_router_v7_fs_routes.md +2 -0
- package/docs/it/intlayer_with_next-i18next.md +3 -3
- package/docs/it/intlayer_with_next-intl.md +3 -3
- package/docs/it/intlayer_with_react_router_v7.md +72 -15
- package/docs/it/intlayer_with_react_router_v7_fs_routes.md +95 -19
- package/docs/ja/intlayer_with_next-i18next.md +3 -3
- package/docs/ja/intlayer_with_next-intl.md +3 -3
- package/docs/ja/intlayer_with_react_router_v7.md +72 -15
- package/docs/ja/intlayer_with_react_router_v7_fs_routes.md +95 -19
- package/docs/ko/intlayer_with_next-i18next.md +3 -3
- package/docs/ko/intlayer_with_next-intl.md +3 -3
- package/docs/ko/intlayer_with_react_router_v7.md +72 -15
- package/docs/ko/intlayer_with_react_router_v7_fs_routes.md +2 -0
- package/docs/pl/intlayer_with_next-i18next.md +3 -3
- package/docs/pl/intlayer_with_next-intl.md +3 -3
- package/docs/pl/intlayer_with_react_router_v7.md +45 -13
- package/docs/pl/intlayer_with_react_router_v7_fs_routes.md +94 -18
- package/docs/pt/intlayer_with_next-i18next.md +3 -3
- package/docs/pt/intlayer_with_next-intl.md +3 -3
- package/docs/pt/intlayer_with_react_router_v7.md +79 -46
- package/docs/pt/intlayer_with_react_router_v7_fs_routes.md +95 -19
- package/docs/ru/intlayer_with_next-i18next.md +3 -3
- package/docs/ru/intlayer_with_next-intl.md +3 -3
- package/docs/ru/intlayer_with_react_router_v7.md +72 -15
- package/docs/ru/intlayer_with_react_router_v7_fs_routes.md +95 -19
- package/docs/tr/intlayer_with_next-i18next.md +3 -3
- package/docs/tr/intlayer_with_next-intl.md +3 -3
- package/docs/tr/intlayer_with_react_router_v7.md +72 -15
- package/docs/tr/intlayer_with_react_router_v7_fs_routes.md +95 -19
- package/docs/vi/intlayer_with_next-i18next.md +3 -3
- package/docs/vi/intlayer_with_next-intl.md +3 -3
- package/docs/vi/intlayer_with_react_router_v7.md +72 -15
- package/docs/vi/intlayer_with_react_router_v7_fs_routes.md +2 -0
- package/docs/zh/intlayer_with_next-i18next.md +3 -3
- package/docs/zh/intlayer_with_next-intl.md +3 -3
- package/docs/zh/intlayer_with_react_router_v7.md +72 -15
- package/docs/zh/intlayer_with_react_router_v7_fs_routes.md +2 -0
- package/package.json +6 -6
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2025-09-04
|
|
3
|
-
updatedAt: 2025-
|
|
3
|
+
updatedAt: 2025-12-27
|
|
4
4
|
title: React Router v7アプリを翻訳する方法 – i18nガイド 2025
|
|
5
5
|
description: Intlayerを使用してReact Router v7アプリケーションに国際化(i18n)を追加する方法を学びます。ロケール対応ルーティングでアプリを多言語化するための包括的なガイドに従ってください。
|
|
6
6
|
keywords:
|
|
@@ -20,6 +20,9 @@ slugs:
|
|
|
20
20
|
applicationTemplate: https://github.com/aymericzip/intlayer-react-router-v7-template
|
|
21
21
|
youtubeVideo: https://www.youtube.com/watch?v=dS9L7uJeak4
|
|
22
22
|
history:
|
|
23
|
+
- version: 7.5.6
|
|
24
|
+
date: 2025-12-27
|
|
25
|
+
changes: レイアウトの更新と404の処理
|
|
23
26
|
- version: 6.1.5
|
|
24
27
|
date: 2025-10-03
|
|
25
28
|
changes: ドキュメント更新
|
|
@@ -172,10 +175,8 @@ export default defineConfig({
|
|
|
172
175
|
import { layout, route, type RouteConfig } from "@react-router/dev/routes";
|
|
173
176
|
|
|
174
177
|
export default [
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
route("/:lang?/about", "routes/about/page.tsx"), // ローカライズされたアバウトページ
|
|
178
|
-
]),
|
|
178
|
+
route("/:lang?", "routes/page.tsx"), // ローカライズされたホームページ
|
|
179
|
+
route("/:lang?/about", "routes/about/page.tsx"), // ローカライズされたアバウトページ
|
|
179
180
|
] satisfies RouteConfig;
|
|
180
181
|
```
|
|
181
182
|
|
|
@@ -185,19 +186,50 @@ export default [
|
|
|
185
186
|
|
|
186
187
|
#### ルートレイアウト
|
|
187
188
|
|
|
188
|
-
```tsx fileName="app/
|
|
189
|
+
```tsx fileName="app/root.tsx"
|
|
190
|
+
import { getLocaleFromPath } from "intlayer";
|
|
189
191
|
import { IntlayerProvider } from "react-intlayer";
|
|
190
|
-
import {
|
|
192
|
+
import {
|
|
193
|
+
data,
|
|
194
|
+
Meta,
|
|
195
|
+
Scripts,
|
|
196
|
+
ScrollRestoration,
|
|
197
|
+
useLoaderData,
|
|
198
|
+
} from "react-router";
|
|
199
|
+
import type { Route } from "./+types/root";
|
|
191
200
|
|
|
192
|
-
|
|
201
|
+
// ... Unchanged App, links and ErrorBoundary code
|
|
193
202
|
|
|
194
|
-
export
|
|
195
|
-
const
|
|
203
|
+
export async function loader({ request }: Route.LoaderArgs) {
|
|
204
|
+
const locale = getLocaleFromPath(request.url);
|
|
205
|
+
|
|
206
|
+
if (!locale) {
|
|
207
|
+
throw data("Language not supported", { status: 404 });
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return { locale };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export function Layout({
|
|
214
|
+
children,
|
|
215
|
+
}: { children: React.ReactNode } & Route.ComponentProps) {
|
|
216
|
+
const data = useLoaderData<typeof loader>();
|
|
217
|
+
const { locale } = data ?? {};
|
|
196
218
|
|
|
197
219
|
return (
|
|
198
|
-
<
|
|
199
|
-
<
|
|
200
|
-
|
|
220
|
+
<html lang={locale}>
|
|
221
|
+
<head>
|
|
222
|
+
<meta charSet="utf-8" />
|
|
223
|
+
<meta content="width=device-width, initial-scale=1" name="viewport" />
|
|
224
|
+
<Meta />
|
|
225
|
+
<Links />
|
|
226
|
+
</head>
|
|
227
|
+
<body>
|
|
228
|
+
<IntlayerProvider locale={locale}>{children}</IntlayerProvider>
|
|
229
|
+
<ScrollRestoration />
|
|
230
|
+
<Scripts />
|
|
231
|
+
</body>
|
|
232
|
+
</html>
|
|
201
233
|
);
|
|
202
234
|
}
|
|
203
235
|
```
|
|
@@ -312,9 +344,34 @@ export const useLocalizedNavigate = () => {
|
|
|
312
344
|
|
|
313
345
|
#### ローカライズされたホームページ
|
|
314
346
|
|
|
315
|
-
```tsx fileName="app/routes/
|
|
347
|
+
```tsx fileName="app/routes/page.tsx"
|
|
348
|
+
import { getIntlayer, validatePrefix } from "intlayer";
|
|
316
349
|
import { useIntlayer } from "react-intlayer";
|
|
317
|
-
import {
|
|
350
|
+
import { data } from "react-router";
|
|
351
|
+
|
|
352
|
+
import { LocaleSwitcher } from "~/components/locale-switcher";
|
|
353
|
+
|
|
354
|
+
import { Navbar } from "~/components/navbar";
|
|
355
|
+
import type { Route } from "./+types/page";
|
|
356
|
+
|
|
357
|
+
export const loader = ({ params }: Route.LoaderArgs) => {
|
|
358
|
+
const { locale } = params;
|
|
359
|
+
|
|
360
|
+
const { isValid } = validatePrefix(locale);
|
|
361
|
+
|
|
362
|
+
if (!isValid) {
|
|
363
|
+
throw data("Locale not supported", { status: 404 });
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
export const meta: Route.MetaFunction = ({ params }) => {
|
|
368
|
+
const content = getIntlayer("page", params.locale);
|
|
369
|
+
|
|
370
|
+
return [
|
|
371
|
+
{ title: content.title },
|
|
372
|
+
{ content: content.description, name: "description" },
|
|
373
|
+
];
|
|
374
|
+
};
|
|
318
375
|
|
|
319
376
|
export default function Page() {
|
|
320
377
|
const { title, description, aboutLink } = useIntlayer("page");
|
|
@@ -31,6 +31,8 @@ history:
|
|
|
31
31
|
|
|
32
32
|
このガイドでは、React Router v7プロジェクトにおいて、**ファイルシステムベースのルーティング**(`@react-router/fs-routes`)を使用して、ロケール対応ルーティング、TypeScriptサポート、最新の開発手法を活用しながら、**Intlayer**を使ったシームレスな国際化の統合方法を説明します。
|
|
33
33
|
|
|
34
|
+
クライアントサイドルーティングについては、[IntlayerとReact Router v7](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ja/intlayer_with_react_router_v7.md)ガイドを参照してください。
|
|
35
|
+
|
|
34
36
|
## Table of Contents
|
|
35
37
|
|
|
36
38
|
<TOC/>
|
|
@@ -196,12 +198,13 @@ export default routes;
|
|
|
196
198
|
#### ファイル構造
|
|
197
199
|
|
|
198
200
|
```bash
|
|
199
|
-
app/
|
|
200
|
-
├──
|
|
201
|
-
|
|
202
|
-
├── ($locale)._index.
|
|
203
|
-
├── ($locale).
|
|
204
|
-
|
|
201
|
+
app/
|
|
202
|
+
├── root.tsx # ロケールルートのレイアウトラッパー
|
|
203
|
+
└──routes/
|
|
204
|
+
├── ($locale)._index.tsx # ホームページ (/, /es, など)
|
|
205
|
+
├── ($locale)._index.content.ts # ホームページのコンテンツ
|
|
206
|
+
├── ($locale).about.tsx # アバウトページ (/about, /es/about, など)
|
|
207
|
+
└── ($locale).about.content.ts # アバウトページのコンテンツ
|
|
205
208
|
```
|
|
206
209
|
|
|
207
210
|
命名規則:
|
|
@@ -213,23 +216,50 @@ app/routes/
|
|
|
213
216
|
|
|
214
217
|
#### レイアウトコンポーネント
|
|
215
218
|
|
|
216
|
-
```tsx fileName="app/
|
|
219
|
+
```tsx fileName="app/root.tsx"
|
|
220
|
+
import { getLocaleFromPath } from "intlayer";
|
|
217
221
|
import { IntlayerProvider } from "react-intlayer";
|
|
218
|
-
import {
|
|
222
|
+
import {
|
|
223
|
+
isRouteErrorResponse,
|
|
224
|
+
Meta,
|
|
225
|
+
Outlet,
|
|
226
|
+
Scripts,
|
|
227
|
+
ScrollRestoration,
|
|
228
|
+
useLoaderData,
|
|
229
|
+
} from "react-router";
|
|
219
230
|
|
|
220
|
-
import {
|
|
231
|
+
import type { Route } from "./+types/root";
|
|
221
232
|
|
|
222
|
-
import
|
|
233
|
+
import "./app.css";
|
|
223
234
|
|
|
224
|
-
|
|
225
|
-
useI18nHTMLAttributes();
|
|
235
|
+
// links and ErrorBoundary code
|
|
226
236
|
|
|
227
|
-
|
|
237
|
+
export async function loader({ request }: Route.LoaderArgs) {
|
|
238
|
+
const locale = getLocaleFromPath(request.url);
|
|
239
|
+
|
|
240
|
+
return { locale };
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export function Layout({
|
|
244
|
+
children,
|
|
245
|
+
}: { children: React.ReactNode } & Route.ComponentProps) {
|
|
246
|
+
const data = useLoaderData<typeof loader>();
|
|
247
|
+
const { locale } = data ?? {};
|
|
228
248
|
|
|
229
249
|
return (
|
|
230
|
-
<
|
|
231
|
-
<
|
|
232
|
-
|
|
250
|
+
<html lang={locale}>
|
|
251
|
+
<head>
|
|
252
|
+
<meta charSet="utf-8" />
|
|
253
|
+
<meta content="width=device-width, initial-scale=1" name="viewport" />
|
|
254
|
+
<Meta />
|
|
255
|
+
<Links />
|
|
256
|
+
</head>
|
|
257
|
+
<body>
|
|
258
|
+
<IntlayerProvider locale={locale}>{children}</IntlayerProvider>
|
|
259
|
+
<ScrollRestoration />
|
|
260
|
+
<Scripts />
|
|
261
|
+
</body>
|
|
262
|
+
</html>
|
|
233
263
|
);
|
|
234
264
|
}
|
|
235
265
|
```
|
|
@@ -237,11 +267,34 @@ export default function RootLayout({ params }: Route.ComponentProps) {
|
|
|
237
267
|
#### インデックスページ
|
|
238
268
|
|
|
239
269
|
```tsx fileName="app/routes/($locale)._index.tsx"
|
|
270
|
+
import { getIntlayer, validatePrefix } from "intlayer";
|
|
240
271
|
import { useIntlayer } from "react-intlayer";
|
|
241
|
-
import {
|
|
272
|
+
import { data } from "react-router";
|
|
273
|
+
|
|
274
|
+
import { LocaleSwitcher } from "~/components/locale-switcher";
|
|
275
|
+
import { Navbar } from "~/components/navbar";
|
|
242
276
|
|
|
243
277
|
import type { Route } from "./+types/($locale)._index";
|
|
244
278
|
|
|
279
|
+
export const loader = ({ params }: Route.LoaderArgs) => {
|
|
280
|
+
const { locale } = params;
|
|
281
|
+
|
|
282
|
+
const { isValid } = validatePrefix(locale);
|
|
283
|
+
|
|
284
|
+
if (!isValid) {
|
|
285
|
+
throw data("Locale not supported", { status: 404 });
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
export const meta: Route.MetaFunction = ({ params }) => {
|
|
290
|
+
const content = getIntlayer("page", params.locale);
|
|
291
|
+
|
|
292
|
+
return [
|
|
293
|
+
{ title: content.title },
|
|
294
|
+
{ content: content.description, name: "description" },
|
|
295
|
+
];
|
|
296
|
+
};
|
|
297
|
+
|
|
245
298
|
export default function Page() {
|
|
246
299
|
const { title, description, aboutLink } = useIntlayer("page");
|
|
247
300
|
|
|
@@ -260,11 +313,34 @@ export default function Page() {
|
|
|
260
313
|
#### アバウトページ
|
|
261
314
|
|
|
262
315
|
```tsx fileName="app/routes/($locale).about.tsx"
|
|
316
|
+
import { getIntlayer, validatePrefix } from "intlayer";
|
|
263
317
|
import { useIntlayer } from "react-intlayer";
|
|
264
|
-
import {
|
|
318
|
+
import { data } from "react-router";
|
|
319
|
+
|
|
320
|
+
import { LocaleSwitcher } from "~/components/locale-switcher";
|
|
321
|
+
import { Navbar } from "~/components/navbar";
|
|
265
322
|
|
|
266
323
|
import type { Route } from "./+types/($locale).about";
|
|
267
324
|
|
|
325
|
+
export const loader = ({ params }: Route.LoaderArgs) => {
|
|
326
|
+
const { locale } = params;
|
|
327
|
+
|
|
328
|
+
const { isValid } = validatePrefix(locale);
|
|
329
|
+
|
|
330
|
+
if (!isValid) {
|
|
331
|
+
throw data("Locale not supported", { status: 404 });
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
export const meta: Route.MetaFunction = ({ params }) => {
|
|
336
|
+
const content = getIntlayer("about", params.locale);
|
|
337
|
+
|
|
338
|
+
return [
|
|
339
|
+
{ title: content.title },
|
|
340
|
+
{ content: content.description, name: "description" },
|
|
341
|
+
];
|
|
342
|
+
};
|
|
343
|
+
|
|
268
344
|
export default function AboutPage() {
|
|
269
345
|
const { title, content, homeLink } = useIntlayer("about");
|
|
270
346
|
|
|
@@ -486,7 +562,7 @@ export const useI18nHTMLAttributes = () => {
|
|
|
486
562
|
};
|
|
487
563
|
```
|
|
488
564
|
|
|
489
|
-
このフックは、ステップ5で示したレイアウトコンポーネント(`
|
|
565
|
+
このフックは、ステップ5で示したレイアウトコンポーネント(`root.tsx`)で既に使用されています。
|
|
490
566
|
|
|
491
567
|
### ステップ10: ミドルウェアを追加する(オプション)
|
|
492
568
|
|
|
@@ -552,15 +552,15 @@ Intlayer는 JSON 번역을 동기화 상태로 유지하고, 누락된 키를
|
|
|
552
552
|
intlayer 의존성을 설치하세요:
|
|
553
553
|
|
|
554
554
|
```bash packageManager="npm"
|
|
555
|
-
npm install intlayer @intlayer/sync-json-plugin
|
|
555
|
+
npm install intlayer @intlayer/sync-json-plugin --save-dev
|
|
556
556
|
```
|
|
557
557
|
|
|
558
558
|
```bash packageManager="pnpm"
|
|
559
|
-
pnpm add intlayer @intlayer/sync-json-plugin
|
|
559
|
+
pnpm add intlayer @intlayer/sync-json-plugin --save-dev
|
|
560
560
|
```
|
|
561
561
|
|
|
562
562
|
```bash packageManager="yarn"
|
|
563
|
-
yarn add intlayer @intlayer/sync-json-plugin
|
|
563
|
+
yarn add intlayer @intlayer/sync-json-plugin --dev
|
|
564
564
|
```
|
|
565
565
|
|
|
566
566
|
```ts fileName="intlayer.config.ts"
|
|
@@ -391,15 +391,15 @@ export const config = {
|
|
|
391
391
|
intlayer 의존성을 설치하세요:
|
|
392
392
|
|
|
393
393
|
```bash packageManager="npm"
|
|
394
|
-
npm install intlayer @intlayer/sync-json-plugin
|
|
394
|
+
npm install intlayer @intlayer/sync-json-plugin --save-dev
|
|
395
395
|
```
|
|
396
396
|
|
|
397
397
|
```bash packageManager="yarn"
|
|
398
|
-
yarn add intlayer @intlayer/sync-json-plugin
|
|
398
|
+
yarn add intlayer @intlayer/sync-json-plugin --dev
|
|
399
399
|
```
|
|
400
400
|
|
|
401
401
|
```bash packageManager="pnpm"
|
|
402
|
-
pnpm add intlayer @intlayer/sync-json-plugin
|
|
402
|
+
pnpm add intlayer @intlayer/sync-json-plugin --save-dev
|
|
403
403
|
```
|
|
404
404
|
|
|
405
405
|
intlayer 구성 파일을 생성하세요:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2025-09-04
|
|
3
|
-
updatedAt: 2025-
|
|
3
|
+
updatedAt: 2025-12-27
|
|
4
4
|
title: React Router v7 앱 번역하는 방법 – i18n 가이드 2025
|
|
5
5
|
description: Intlayer를 사용하여 React Router v7 애플리케이션에 국제화(i18n)를 추가하는 방법을 배우세요. 로케일 인식 라우팅으로 앱을 다국어로 만드는 종합 가이드를 따르세요.
|
|
6
6
|
keywords:
|
|
@@ -20,6 +20,9 @@ slugs:
|
|
|
20
20
|
applicationTemplate: https://github.com/aymericzip/intlayer-react-router-v7-template
|
|
21
21
|
youtubeVideo: https://www.youtube.com/watch?v=dS9L7uJeak4
|
|
22
22
|
history:
|
|
23
|
+
- version: 7.5.6
|
|
24
|
+
date: 2025-12-27
|
|
25
|
+
changes: 레이아웃 업데이트 및 404 처리
|
|
23
26
|
- version: 6.1.5
|
|
24
27
|
date: 2025-10-03
|
|
25
28
|
changes: 문서 업데이트
|
|
@@ -172,10 +175,8 @@ export default defineConfig({
|
|
|
172
175
|
import { layout, route, type RouteConfig } from "@react-router/dev/routes";
|
|
173
176
|
|
|
174
177
|
export default [
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
route("/:lang?/about", "routes/about/page.tsx"), // 지역화된 소개 페이지
|
|
178
|
-
]),
|
|
178
|
+
route("/:lang?", "routes/page.tsx"), // 지역화된 홈 페이지
|
|
179
|
+
route("/:lang?/about", "routes/about/page.tsx"), // 지역화된 소개 페이지
|
|
179
180
|
] satisfies RouteConfig;
|
|
180
181
|
```
|
|
181
182
|
|
|
@@ -185,19 +186,50 @@ export default [
|
|
|
185
186
|
|
|
186
187
|
#### 루트 레이아웃
|
|
187
188
|
|
|
188
|
-
```tsx fileName="app/
|
|
189
|
+
```tsx fileName="app/root.tsx"
|
|
190
|
+
import { getLocaleFromPath } from "intlayer";
|
|
189
191
|
import { IntlayerProvider } from "react-intlayer";
|
|
190
|
-
import {
|
|
192
|
+
import {
|
|
193
|
+
data,
|
|
194
|
+
Meta,
|
|
195
|
+
Scripts,
|
|
196
|
+
ScrollRestoration,
|
|
197
|
+
useLoaderData,
|
|
198
|
+
} from "react-router";
|
|
199
|
+
import type { Route } from "./+types/root";
|
|
191
200
|
|
|
192
|
-
|
|
201
|
+
// ... Unchanged App, links and ErrorBoundary code
|
|
193
202
|
|
|
194
|
-
export
|
|
195
|
-
const
|
|
203
|
+
export async function loader({ request }: Route.LoaderArgs) {
|
|
204
|
+
const locale = getLocaleFromPath(request.url);
|
|
205
|
+
|
|
206
|
+
if (!locale) {
|
|
207
|
+
throw data("Language not supported", { status: 404 });
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return { locale };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export function Layout({
|
|
214
|
+
children,
|
|
215
|
+
}: { children: React.ReactNode } & Route.ComponentProps) {
|
|
216
|
+
const data = useLoaderData<typeof loader>();
|
|
217
|
+
const { locale } = data ?? {};
|
|
196
218
|
|
|
197
219
|
return (
|
|
198
|
-
<
|
|
199
|
-
<
|
|
200
|
-
|
|
220
|
+
<html lang={locale}>
|
|
221
|
+
<head>
|
|
222
|
+
<meta charSet="utf-8" />
|
|
223
|
+
<meta content="width=device-width, initial-scale=1" name="viewport" />
|
|
224
|
+
<Meta />
|
|
225
|
+
<Links />
|
|
226
|
+
</head>
|
|
227
|
+
<body>
|
|
228
|
+
<IntlayerProvider locale={locale}>{children}</IntlayerProvider>
|
|
229
|
+
<ScrollRestoration />
|
|
230
|
+
<Scripts />
|
|
231
|
+
</body>
|
|
232
|
+
</html>
|
|
201
233
|
);
|
|
202
234
|
}
|
|
203
235
|
```
|
|
@@ -310,9 +342,34 @@ export const useLocalizedNavigate = () => {
|
|
|
310
342
|
|
|
311
343
|
#### 현지화된 홈 페이지
|
|
312
344
|
|
|
313
|
-
```tsx fileName="app/routes/
|
|
345
|
+
```tsx fileName="app/routes/page.tsx"
|
|
346
|
+
import { getIntlayer, validatePrefix } from "intlayer";
|
|
314
347
|
import { useIntlayer } from "react-intlayer";
|
|
315
|
-
import {
|
|
348
|
+
import { data } from "react-router";
|
|
349
|
+
|
|
350
|
+
import { LocaleSwitcher } from "~/components/locale-switcher";
|
|
351
|
+
|
|
352
|
+
import { Navbar } from "~/components/navbar";
|
|
353
|
+
import type { Route } from "./+types/page";
|
|
354
|
+
|
|
355
|
+
export const loader = ({ params }: Route.LoaderArgs) => {
|
|
356
|
+
const { locale } = params;
|
|
357
|
+
|
|
358
|
+
const { isValid } = validatePrefix(locale);
|
|
359
|
+
|
|
360
|
+
if (!isValid) {
|
|
361
|
+
throw data("Locale not supported", { status: 404 });
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
export const meta: Route.MetaFunction = ({ params }) => {
|
|
366
|
+
const content = getIntlayer("page", params.locale);
|
|
367
|
+
|
|
368
|
+
return [
|
|
369
|
+
{ title: content.title },
|
|
370
|
+
{ content: content.description, name: "description" },
|
|
371
|
+
];
|
|
372
|
+
};
|
|
316
373
|
|
|
317
374
|
export default function Page() {
|
|
318
375
|
const { title, description, aboutLink } = useIntlayer("page");
|
|
@@ -32,6 +32,8 @@ history:
|
|
|
32
32
|
|
|
33
33
|
이 가이드는 React Router v7 프로젝트에서 로케일 인식 라우팅, TypeScript 지원 및 최신 개발 방식을 활용하여 **Intlayer**를 통합해 원활한 국제화(i18n)를 구현하는 방법을 보여줍니다.
|
|
34
34
|
|
|
35
|
+
클라이언트 사이드 라우팅의 경우 [Intlayer와 React Router v7](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ko/intlayer_with_react_router_v7.md) 가이드를 참조하세요.
|
|
36
|
+
|
|
35
37
|
## Table of Contents
|
|
36
38
|
|
|
37
39
|
<TOC/>
|
|
@@ -553,15 +553,15 @@ Intlayer pomaga utrzymać synchronizację tłumaczeń JSON, testować brakujące
|
|
|
553
553
|
Zainstaluj zależności intlayer:
|
|
554
554
|
|
|
555
555
|
```bash packageManager="npm"
|
|
556
|
-
npm install intlayer @intlayer/sync-json-plugin
|
|
556
|
+
npm install intlayer @intlayer/sync-json-plugin --save-dev
|
|
557
557
|
```
|
|
558
558
|
|
|
559
559
|
```bash packageManager="pnpm"
|
|
560
|
-
pnpm add intlayer @intlayer/sync-json-plugin
|
|
560
|
+
pnpm add intlayer @intlayer/sync-json-plugin --save-dev
|
|
561
561
|
```
|
|
562
562
|
|
|
563
563
|
```bash packageManager="yarn"
|
|
564
|
-
yarn add intlayer @intlayer/sync-json-plugin
|
|
564
|
+
yarn add intlayer @intlayer/sync-json-plugin --dev
|
|
565
565
|
```
|
|
566
566
|
|
|
567
567
|
```ts fileName="intlayer.config.ts"
|
|
@@ -391,15 +391,15 @@ export const config = {
|
|
|
391
391
|
Zainstaluj zależności intlayer:
|
|
392
392
|
|
|
393
393
|
```bash packageManager="npm"
|
|
394
|
-
npm install intlayer @intlayer/sync-json-plugin
|
|
394
|
+
npm install intlayer @intlayer/sync-json-plugin --save-dev
|
|
395
395
|
```
|
|
396
396
|
|
|
397
397
|
```bash packageManager="yarn"
|
|
398
|
-
yarn add intlayer @intlayer/sync-json-plugin
|
|
398
|
+
yarn add intlayer @intlayer/sync-json-plugin --dev
|
|
399
399
|
```
|
|
400
400
|
|
|
401
401
|
```bash packageManager="pnpm"
|
|
402
|
-
pnpm add intlayer @intlayer/sync-json-plugin
|
|
402
|
+
pnpm add intlayer @intlayer/sync-json-plugin --save-dev
|
|
403
403
|
```
|
|
404
404
|
|
|
405
405
|
Utwórz plik konfiguracyjny intlayer:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2025-09-04
|
|
3
|
-
updatedAt: 2025-
|
|
3
|
+
updatedAt: 2025-12-27
|
|
4
4
|
title: Jak przetłumaczyć aplikację React Router v7 – przewodnik i18n 2025
|
|
5
5
|
description: Dowiedz się, jak dodać internacjonalizację (i18n) do swojej aplikacji React Router v7 za pomocą Intlayer. Postępuj zgodnie z tym kompleksowym przewodnikiem, aby uczynić swoją aplikację wielojęzyczną z routingiem uwzględniającym lokalizację.
|
|
6
6
|
keywords:
|
|
@@ -20,6 +20,9 @@ slugs:
|
|
|
20
20
|
applicationTemplate: https://github.com/aymericzip/intlayer-react-router-v7-template
|
|
21
21
|
youtubeVideo: https://www.youtube.com/watch?v=dS9L7uJeak4
|
|
22
22
|
history:
|
|
23
|
+
- version: 7.5.6
|
|
24
|
+
date: 2025-12-27
|
|
25
|
+
changes: Zaktualizuj Layout i obsłuż 404
|
|
23
26
|
- version: 6.1.5
|
|
24
27
|
date: 2025-10-03
|
|
25
28
|
changes: Zaktualizowano dokumentację
|
|
@@ -183,10 +186,8 @@ Skonfiguruj routing z trasami uwzględniającymi lokalizację:
|
|
|
183
186
|
import { layout, route, type RouteConfig } from "@react-router/dev/routes";
|
|
184
187
|
|
|
185
188
|
export default [
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
route("/:lang?/about", "routes/about/page.tsx"), // Lokalizowana strona o nas
|
|
189
|
-
]),
|
|
189
|
+
route("/:lang?", "routes/page.tsx"), // Lokalizowana strona główna
|
|
190
|
+
route("/:lang?/about", "routes/about/page.tsx"), // Lokalizowana strona o nas
|
|
190
191
|
] satisfies RouteConfig;
|
|
191
192
|
```
|
|
192
193
|
|
|
@@ -196,19 +197,50 @@ Skonfiguruj swój główny layout oraz layouty specyficzne dla lokalizacji:
|
|
|
196
197
|
|
|
197
198
|
#### Główny Layout
|
|
198
199
|
|
|
199
|
-
```tsx fileName="app/
|
|
200
|
+
```tsx fileName="app/root.tsx"
|
|
201
|
+
import { getLocaleFromPath } from "intlayer";
|
|
200
202
|
import { IntlayerProvider } from "react-intlayer";
|
|
201
|
-
import {
|
|
203
|
+
import {
|
|
204
|
+
data,
|
|
205
|
+
Meta,
|
|
206
|
+
Scripts,
|
|
207
|
+
ScrollRestoration,
|
|
208
|
+
useLoaderData,
|
|
209
|
+
} from "react-router";
|
|
210
|
+
import type { Route } from "./+types/root";
|
|
211
|
+
|
|
212
|
+
// ... Unchanged App, links and ErrorBoundary code
|
|
213
|
+
|
|
214
|
+
export async function loader({ request }: Route.LoaderArgs) {
|
|
215
|
+
const locale = getLocaleFromPath(request.url);
|
|
202
216
|
|
|
203
|
-
|
|
217
|
+
if (!locale) {
|
|
218
|
+
throw data("Language not supported", { status: 404 });
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return { locale };
|
|
222
|
+
}
|
|
204
223
|
|
|
205
|
-
export
|
|
206
|
-
|
|
224
|
+
export function Layout({
|
|
225
|
+
children,
|
|
226
|
+
}: { children: React.ReactNode } & Route.ComponentProps) {
|
|
227
|
+
const data = useLoaderData<typeof loader>();
|
|
228
|
+
const { locale } = data ?? {};
|
|
207
229
|
|
|
208
230
|
return (
|
|
209
|
-
<
|
|
210
|
-
<
|
|
211
|
-
|
|
231
|
+
<html lang={locale}>
|
|
232
|
+
<head>
|
|
233
|
+
<meta charSet="utf-8" />
|
|
234
|
+
<meta content="width=device-width, initial-scale=1" name="viewport" />
|
|
235
|
+
<Meta />
|
|
236
|
+
<Links />
|
|
237
|
+
</head>
|
|
238
|
+
<body>
|
|
239
|
+
<IntlayerProvider locale={locale}>{children}</IntlayerProvider>
|
|
240
|
+
<ScrollRestoration />
|
|
241
|
+
<Scripts />
|
|
242
|
+
</body>
|
|
243
|
+
</html>
|
|
212
244
|
);
|
|
213
245
|
}
|
|
214
246
|
```
|