@intlayer/docs 7.5.5 → 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 +8 -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
|
@@ -31,6 +31,8 @@ history:
|
|
|
31
31
|
|
|
32
32
|
Ten przewodnik pokazuje, jak zintegrować **Intlayer** dla płynnej internacjonalizacji w projektach React Router v7 używając **routingu opartego na systemie plików** (`@react-router/fs-routes`) z routingiem uwzględniającym lokalizację, wsparciem TypeScript oraz nowoczesnymi praktykami programistycznymi.
|
|
33
33
|
|
|
34
|
+
W przypadku routingu po stronie klienta, zapoznaj się z przewodnikiem [Intlayer z React Router v7](https://github.com/aymericzip/intlayer/blob/main/docs/docs/pl/intlayer_with_react_router_v7.md).
|
|
35
|
+
|
|
34
36
|
## Table of Contents
|
|
35
37
|
|
|
36
38
|
<TOC/>
|
|
@@ -220,12 +222,13 @@ Utwórz następujące pliki w katalogu `app/routes/`:
|
|
|
220
222
|
#### Struktura plików
|
|
221
223
|
|
|
222
224
|
```bash
|
|
223
|
-
app/
|
|
224
|
-
├──
|
|
225
|
-
|
|
226
|
-
├── ($locale)._index.
|
|
227
|
-
├── ($locale).
|
|
228
|
-
|
|
225
|
+
app/
|
|
226
|
+
├── root.tsx # Opakowanie layoutu dla tras lokalizacji
|
|
227
|
+
└──routes/
|
|
228
|
+
├── ($locale)._index.tsx # Strona główna (/, /es, itd.)
|
|
229
|
+
├── ($locale)._index.content.ts # Zawartość strony głównej
|
|
230
|
+
├── ($locale).about.tsx # Strona O nas (/about, /es/about, itd.)
|
|
231
|
+
└── ($locale).about.content.ts # Zawartość strony O nas
|
|
229
232
|
```
|
|
230
233
|
|
|
231
234
|
Konwencje nazewnictwa:
|
|
@@ -237,23 +240,50 @@ Konwencje nazewnictwa:
|
|
|
237
240
|
|
|
238
241
|
#### Komponent Layoutu
|
|
239
242
|
|
|
240
|
-
```tsx fileName="app/
|
|
243
|
+
```tsx fileName="app/root.tsx"
|
|
244
|
+
import { getLocaleFromPath } from "intlayer";
|
|
241
245
|
import { IntlayerProvider } from "react-intlayer";
|
|
242
|
-
import {
|
|
246
|
+
import {
|
|
247
|
+
isRouteErrorResponse,
|
|
248
|
+
Meta,
|
|
249
|
+
Outlet,
|
|
250
|
+
Scripts,
|
|
251
|
+
ScrollRestoration,
|
|
252
|
+
useLoaderData,
|
|
253
|
+
} from "react-router";
|
|
243
254
|
|
|
244
|
-
import {
|
|
255
|
+
import type { Route } from "./+types/root";
|
|
245
256
|
|
|
246
|
-
import
|
|
257
|
+
import "./app.css";
|
|
247
258
|
|
|
248
|
-
|
|
249
|
-
useI18nHTMLAttributes();
|
|
259
|
+
// links and ErrorBoundary code
|
|
250
260
|
|
|
251
|
-
|
|
261
|
+
export async function loader({ request }: Route.LoaderArgs) {
|
|
262
|
+
const locale = getLocaleFromPath(request.url);
|
|
263
|
+
|
|
264
|
+
return { locale };
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export function Layout({
|
|
268
|
+
children,
|
|
269
|
+
}: { children: React.ReactNode } & Route.ComponentProps) {
|
|
270
|
+
const data = useLoaderData<typeof loader>();
|
|
271
|
+
const { locale } = data ?? {};
|
|
252
272
|
|
|
253
273
|
return (
|
|
254
|
-
<
|
|
255
|
-
<
|
|
256
|
-
|
|
274
|
+
<html lang={locale}>
|
|
275
|
+
<head>
|
|
276
|
+
<meta charSet="utf-8" />
|
|
277
|
+
<meta content="width=device-width, initial-scale=1" name="viewport" />
|
|
278
|
+
<Meta />
|
|
279
|
+
<Links />
|
|
280
|
+
</head>
|
|
281
|
+
<body>
|
|
282
|
+
<IntlayerProvider locale={locale}>{children}</IntlayerProvider>
|
|
283
|
+
<ScrollRestoration />
|
|
284
|
+
<Scripts />
|
|
285
|
+
</body>
|
|
286
|
+
</html>
|
|
257
287
|
);
|
|
258
288
|
}
|
|
259
289
|
```
|
|
@@ -261,11 +291,34 @@ export default function RootLayout({ params }: Route.ComponentProps) {
|
|
|
261
291
|
#### Strona indeksowa
|
|
262
292
|
|
|
263
293
|
```tsx fileName="app/routes/($locale)._index.tsx"
|
|
294
|
+
import { getIntlayer, validatePrefix } from "intlayer";
|
|
264
295
|
import { useIntlayer } from "react-intlayer";
|
|
265
|
-
import {
|
|
296
|
+
import { data } from "react-router";
|
|
297
|
+
|
|
298
|
+
import { LocaleSwitcher } from "~/components/locale-switcher";
|
|
299
|
+
import { Navbar } from "~/components/navbar";
|
|
266
300
|
|
|
267
301
|
import type { Route } from "./+types/($locale)._index";
|
|
268
302
|
|
|
303
|
+
export const loader = ({ params }: Route.LoaderArgs) => {
|
|
304
|
+
const { locale } = params;
|
|
305
|
+
|
|
306
|
+
const { isValid } = validatePrefix(locale);
|
|
307
|
+
|
|
308
|
+
if (!isValid) {
|
|
309
|
+
throw data("Locale not supported", { status: 404 });
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
export const meta: Route.MetaFunction = ({ params }) => {
|
|
314
|
+
const content = getIntlayer("page", params.locale);
|
|
315
|
+
|
|
316
|
+
return [
|
|
317
|
+
{ title: content.title },
|
|
318
|
+
{ content: content.description, name: "description" },
|
|
319
|
+
];
|
|
320
|
+
};
|
|
321
|
+
|
|
269
322
|
export default function Page() {
|
|
270
323
|
const { title, description, aboutLink } = useIntlayer("page");
|
|
271
324
|
|
|
@@ -284,11 +337,34 @@ export default function Page() {
|
|
|
284
337
|
#### Strona O nas
|
|
285
338
|
|
|
286
339
|
```tsx fileName="app/routes/($locale).about.tsx"
|
|
340
|
+
import { getIntlayer, validatePrefix } from "intlayer";
|
|
287
341
|
import { useIntlayer } from "react-intlayer";
|
|
288
|
-
import {
|
|
342
|
+
import { data } from "react-router";
|
|
343
|
+
|
|
344
|
+
import { LocaleSwitcher } from "~/components/locale-switcher";
|
|
345
|
+
import { Navbar } from "~/components/navbar";
|
|
289
346
|
|
|
290
347
|
import type { Route } from "./+types/($locale).about";
|
|
291
348
|
|
|
349
|
+
export const loader = ({ params }: Route.LoaderArgs) => {
|
|
350
|
+
const { locale } = params;
|
|
351
|
+
|
|
352
|
+
const { isValid } = validatePrefix(locale);
|
|
353
|
+
|
|
354
|
+
if (!isValid) {
|
|
355
|
+
throw data("Locale not supported", { status: 404 });
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
export const meta: Route.MetaFunction = ({ params }) => {
|
|
360
|
+
const content = getIntlayer("about", params.locale);
|
|
361
|
+
|
|
362
|
+
return [
|
|
363
|
+
{ title: content.title },
|
|
364
|
+
{ content: content.description, name: "description" },
|
|
365
|
+
];
|
|
366
|
+
};
|
|
367
|
+
|
|
292
368
|
export default function AboutPage() {
|
|
293
369
|
const { title, content, homeLink } = useIntlayer("about");
|
|
294
370
|
|
|
@@ -552,15 +552,15 @@ O Intlayer ajuda você a manter as traduções JSON sincronizadas, testar chaves
|
|
|
552
552
|
Instale as dependências do 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
|
Instale as dependências do 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
|
Crie o arquivo de configuração do intlayer:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2025-09-04
|
|
3
|
-
updatedAt: 2025-
|
|
3
|
+
updatedAt: 2025-12-27
|
|
4
4
|
title: Como traduzir seu React Router v7 – guia i18n 2025
|
|
5
5
|
description: Aprenda como adicionar internacionalização (i18n) à sua aplicação React Router v7 usando Intlayer. Siga este guia completo para tornar seu app multilíngue com roteamento sensível à localidade.
|
|
6
6
|
keywords:
|
|
@@ -21,6 +21,9 @@ applicationTemplate: https://github.com/AydinTheFirst/react-router-intlayer
|
|
|
21
21
|
author: AydinTheFirst
|
|
22
22
|
youtubeVideo: https://www.youtube.com/watch?v=dS9L7uJeak4
|
|
23
23
|
history:
|
|
24
|
+
- version: 7.5.6
|
|
25
|
+
date: 2025-12-27
|
|
26
|
+
changes: Atualizar Layout e lidar com 404
|
|
24
27
|
- version: 5.8.2
|
|
25
28
|
date: 2025-09-04
|
|
26
29
|
changes: Adicionado para React Router v7
|
|
@@ -160,15 +163,12 @@ module.exports = config;
|
|
|
160
163
|
|
|
161
164
|
Configure sua configuração de rotas com rotas que reconhecem o idioma:
|
|
162
165
|
|
|
163
|
-
```typescript fileName="app/routes.ts"
|
|
166
|
+
```typescript fileName="app/routes.ts"
|
|
164
167
|
import { layout, route, type RouteConfig } from "@react-router/dev/routes";
|
|
165
168
|
|
|
166
169
|
export default [
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
route("/:lang", "routes/[lang]/page.tsx"), // Página inicial localizada
|
|
170
|
-
route("/:lang?/about", "routes/[lang]/about/page.tsx"), // Página sobre localizada
|
|
171
|
-
]),
|
|
170
|
+
route("/:lang?", "routes/page.tsx"), // Página inicial localizada
|
|
171
|
+
route("/:lang?/about", "routes/about/page.tsx"), // Página sobre localizada
|
|
172
172
|
] satisfies RouteConfig;
|
|
173
173
|
```
|
|
174
174
|
|
|
@@ -195,17 +195,50 @@ Configure seu layout raiz e layouts específicos para cada localidade:
|
|
|
195
195
|
|
|
196
196
|
#### Layout Raiz
|
|
197
197
|
|
|
198
|
-
```tsx fileName="app/
|
|
199
|
-
|
|
200
|
-
// app/routes/layout.tsx
|
|
201
|
-
import { Outlet } from "react-router";
|
|
198
|
+
```tsx fileName="app/root.tsx"
|
|
199
|
+
import { getLocaleFromPath } from "intlayer";
|
|
202
200
|
import { IntlayerProvider } from "react-intlayer";
|
|
201
|
+
import {
|
|
202
|
+
data,
|
|
203
|
+
Meta,
|
|
204
|
+
Scripts,
|
|
205
|
+
ScrollRestoration,
|
|
206
|
+
useLoaderData,
|
|
207
|
+
} from "react-router";
|
|
208
|
+
import type { Route } from "./+types/root";
|
|
209
|
+
|
|
210
|
+
// ... Unchanged App, links and ErrorBoundary code
|
|
211
|
+
|
|
212
|
+
export async function loader({ request }: Route.LoaderArgs) {
|
|
213
|
+
const locale = getLocaleFromPath(request.url);
|
|
214
|
+
|
|
215
|
+
if (!locale) {
|
|
216
|
+
throw data("Language not supported", { status: 404 });
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return { locale };
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export function Layout({
|
|
223
|
+
children,
|
|
224
|
+
}: { children: React.ReactNode } & Route.ComponentProps) {
|
|
225
|
+
const data = useLoaderData<typeof loader>();
|
|
226
|
+
const { locale } = data ?? {};
|
|
203
227
|
|
|
204
|
-
export default function RootLayout() {
|
|
205
228
|
return (
|
|
206
|
-
<
|
|
207
|
-
<
|
|
208
|
-
|
|
229
|
+
<html lang={locale}>
|
|
230
|
+
<head>
|
|
231
|
+
<meta charSet="utf-8" />
|
|
232
|
+
<meta content="width=device-width, initial-scale=1" name="viewport" />
|
|
233
|
+
<Meta />
|
|
234
|
+
<Links />
|
|
235
|
+
</head>
|
|
236
|
+
<body>
|
|
237
|
+
<IntlayerProvider locale={locale}>{children}</IntlayerProvider>
|
|
238
|
+
<ScrollRestoration />
|
|
239
|
+
<Scripts />
|
|
240
|
+
</body>
|
|
241
|
+
</html>
|
|
209
242
|
);
|
|
210
243
|
}
|
|
211
244
|
```
|
|
@@ -299,46 +332,46 @@ export default function LocalizedLink({ to, ...props }: RouterLinkProps) {
|
|
|
299
332
|
|
|
300
333
|
Acesse seus dicionários de conteúdo em toda a sua aplicação:
|
|
301
334
|
|
|
302
|
-
#### Página
|
|
335
|
+
#### Página Inicial Localizada
|
|
303
336
|
|
|
304
|
-
```tsx fileName="app/routes/page.tsx"
|
|
305
|
-
import {
|
|
306
|
-
import {
|
|
337
|
+
```tsx fileName="app/routes/page.tsx"
|
|
338
|
+
import { getIntlayer, validatePrefix } from "intlayer";
|
|
339
|
+
import { useIntlayer } from "react-intlayer";
|
|
340
|
+
import { data } from "react-router";
|
|
307
341
|
|
|
308
|
-
|
|
309
|
-
const { locale } = useLocale();
|
|
342
|
+
import { LocaleSwitcher } from "~/components/locale-switcher";
|
|
310
343
|
|
|
311
|
-
|
|
312
|
-
}
|
|
313
|
-
```
|
|
344
|
+
import { Navbar } from "~/components/navbar";
|
|
345
|
+
import type { Route } from "./+types/page";
|
|
314
346
|
|
|
315
|
-
|
|
347
|
+
export const loader = ({ params }: Route.LoaderArgs) => {
|
|
348
|
+
const { locale } = params;
|
|
316
349
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
350
|
+
const { isValid } = validatePrefix(locale);
|
|
351
|
+
|
|
352
|
+
if (!isValid) {
|
|
353
|
+
throw data("Locale not supported", { status: 404 });
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
export const meta: Route.MetaFunction = ({ params }) => {
|
|
358
|
+
const content = getIntlayer("page", params.locale);
|
|
359
|
+
|
|
360
|
+
return [
|
|
361
|
+
{ title: content.title },
|
|
362
|
+
{ content: content.description, name: "description" },
|
|
363
|
+
];
|
|
364
|
+
};
|
|
320
365
|
|
|
321
366
|
export default function Page() {
|
|
322
|
-
const
|
|
367
|
+
const { title, description, aboutLink } = useIntlayer("page");
|
|
323
368
|
|
|
324
369
|
return (
|
|
325
|
-
<div
|
|
326
|
-
<h1>{
|
|
327
|
-
<p>{
|
|
328
|
-
<nav
|
|
329
|
-
<LocalizedLink
|
|
330
|
-
to="/about"
|
|
331
|
-
style={{
|
|
332
|
-
display: "inline-block",
|
|
333
|
-
padding: "0.5rem 1rem",
|
|
334
|
-
backgroundColor: "#007bff",
|
|
335
|
-
color: "white",
|
|
336
|
-
textDecoration: "none",
|
|
337
|
-
borderRadius: "4px",
|
|
338
|
-
}}
|
|
339
|
-
>
|
|
340
|
-
{content.aboutLink}
|
|
341
|
-
</LocalizedLink>
|
|
370
|
+
<div>
|
|
371
|
+
<h1>{title}</h1>
|
|
372
|
+
<p>{description}</p>
|
|
373
|
+
<nav>
|
|
374
|
+
<LocalizedLink to="/about">{aboutLink}</LocalizedLink>
|
|
342
375
|
</nav>
|
|
343
376
|
</div>
|
|
344
377
|
);
|
|
@@ -31,6 +31,8 @@ history:
|
|
|
31
31
|
|
|
32
32
|
Este guia demonstra como integrar o **Intlayer** para internacionalização perfeita em projetos React Router v7 usando **roteamento baseado em sistema de arquivos** (`@react-router/fs-routes`) com roteamento consciente de localidade, suporte a TypeScript e práticas modernas de desenvolvimento.
|
|
33
33
|
|
|
34
|
+
Para roteamento do lado do cliente, consulte o guia [Intlayer com React Router v7](https://github.com/aymericzip/intlayer/blob/main/docs/docs/pt/intlayer_with_react_router_v7.md).
|
|
35
|
+
|
|
34
36
|
## Índice
|
|
35
37
|
|
|
36
38
|
<TOC/>
|
|
@@ -195,12 +197,13 @@ Crie os seguintes arquivos no seu diretório `app/routes/`:
|
|
|
195
197
|
#### Estrutura de Arquivos
|
|
196
198
|
|
|
197
199
|
```bash
|
|
198
|
-
app/
|
|
199
|
-
├──
|
|
200
|
-
|
|
201
|
-
├── ($locale)._index.
|
|
202
|
-
├── ($locale).
|
|
203
|
-
|
|
200
|
+
app/
|
|
201
|
+
├── root.tsx # Wrapper de layout para rotas de locale
|
|
202
|
+
└──routes/
|
|
203
|
+
├── ($locale)._index.tsx # Página inicial (/, /es, etc.)
|
|
204
|
+
├── ($locale)._index.content.ts # Conteúdo da página inicial
|
|
205
|
+
├── ($locale).about.tsx # Página About (/about, /es/about, etc.)
|
|
206
|
+
└── ($locale).about.content.ts # Conteúdo da página About
|
|
204
207
|
```
|
|
205
208
|
|
|
206
209
|
As convenções de nomenclatura:
|
|
@@ -212,23 +215,50 @@ As convenções de nomenclatura:
|
|
|
212
215
|
|
|
213
216
|
#### Componente de Layout
|
|
214
217
|
|
|
215
|
-
```tsx fileName="app/
|
|
218
|
+
```tsx fileName="app/root.tsx"
|
|
219
|
+
import { getLocaleFromPath } from "intlayer";
|
|
216
220
|
import { IntlayerProvider } from "react-intlayer";
|
|
217
|
-
import {
|
|
221
|
+
import {
|
|
222
|
+
isRouteErrorResponse,
|
|
223
|
+
Meta,
|
|
224
|
+
Outlet,
|
|
225
|
+
Scripts,
|
|
226
|
+
ScrollRestoration,
|
|
227
|
+
useLoaderData,
|
|
228
|
+
} from "react-router";
|
|
218
229
|
|
|
219
|
-
import {
|
|
230
|
+
import type { Route } from "./+types/root";
|
|
220
231
|
|
|
221
|
-
import
|
|
232
|
+
import "./app.css";
|
|
222
233
|
|
|
223
|
-
|
|
224
|
-
useI18nHTMLAttributes();
|
|
234
|
+
// links and ErrorBoundary code
|
|
225
235
|
|
|
226
|
-
|
|
236
|
+
export async function loader({ request }: Route.LoaderArgs) {
|
|
237
|
+
const locale = getLocaleFromPath(request.url);
|
|
238
|
+
|
|
239
|
+
return { locale };
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export function Layout({
|
|
243
|
+
children,
|
|
244
|
+
}: { children: React.ReactNode } & Route.ComponentProps) {
|
|
245
|
+
const data = useLoaderData<typeof loader>();
|
|
246
|
+
const { locale } = data ?? {};
|
|
227
247
|
|
|
228
248
|
return (
|
|
229
|
-
<
|
|
230
|
-
<
|
|
231
|
-
|
|
249
|
+
<html lang={locale}>
|
|
250
|
+
<head>
|
|
251
|
+
<meta charSet="utf-8" />
|
|
252
|
+
<meta content="width=device-width, initial-scale=1" name="viewport" />
|
|
253
|
+
<Meta />
|
|
254
|
+
<Links />
|
|
255
|
+
</head>
|
|
256
|
+
<body>
|
|
257
|
+
<IntlayerProvider locale={locale}>{children}</IntlayerProvider>
|
|
258
|
+
<ScrollRestoration />
|
|
259
|
+
<Scripts />
|
|
260
|
+
</body>
|
|
261
|
+
</html>
|
|
232
262
|
);
|
|
233
263
|
}
|
|
234
264
|
```
|
|
@@ -236,11 +266,34 @@ export default function RootLayout({ params }: Route.ComponentProps) {
|
|
|
236
266
|
#### Página Index
|
|
237
267
|
|
|
238
268
|
```tsx fileName="app/routes/($locale)._index.tsx"
|
|
269
|
+
import { getIntlayer, validatePrefix } from "intlayer";
|
|
239
270
|
import { useIntlayer } from "react-intlayer";
|
|
240
|
-
import {
|
|
271
|
+
import { data } from "react-router";
|
|
272
|
+
|
|
273
|
+
import { LocaleSwitcher } from "~/components/locale-switcher";
|
|
274
|
+
import { Navbar } from "~/components/navbar";
|
|
241
275
|
|
|
242
276
|
import type { Route } from "./+types/($locale)._index";
|
|
243
277
|
|
|
278
|
+
export const loader = ({ params }: Route.LoaderArgs) => {
|
|
279
|
+
const { locale } = params;
|
|
280
|
+
|
|
281
|
+
const { isValid } = validatePrefix(locale);
|
|
282
|
+
|
|
283
|
+
if (!isValid) {
|
|
284
|
+
throw data("Locale not supported", { status: 404 });
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
export const meta: Route.MetaFunction = ({ params }) => {
|
|
289
|
+
const content = getIntlayer("page", params.locale);
|
|
290
|
+
|
|
291
|
+
return [
|
|
292
|
+
{ title: content.title },
|
|
293
|
+
{ content: content.description, name: "description" },
|
|
294
|
+
];
|
|
295
|
+
};
|
|
296
|
+
|
|
244
297
|
export default function Page() {
|
|
245
298
|
const { title, description, aboutLink } = useIntlayer("page");
|
|
246
299
|
|
|
@@ -259,11 +312,34 @@ export default function Page() {
|
|
|
259
312
|
#### Página About
|
|
260
313
|
|
|
261
314
|
```tsx fileName="app/routes/($locale).about.tsx"
|
|
315
|
+
import { getIntlayer, validatePrefix } from "intlayer";
|
|
262
316
|
import { useIntlayer } from "react-intlayer";
|
|
263
|
-
import {
|
|
317
|
+
import { data } from "react-router";
|
|
318
|
+
|
|
319
|
+
import { LocaleSwitcher } from "~/components/locale-switcher";
|
|
320
|
+
import { Navbar } from "~/components/navbar";
|
|
264
321
|
|
|
265
322
|
import type { Route } from "./+types/($locale).about";
|
|
266
323
|
|
|
324
|
+
export const loader = ({ params }: Route.LoaderArgs) => {
|
|
325
|
+
const { locale } = params;
|
|
326
|
+
|
|
327
|
+
const { isValid } = validatePrefix(locale);
|
|
328
|
+
|
|
329
|
+
if (!isValid) {
|
|
330
|
+
throw data("Locale not supported", { status: 404 });
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
export const meta: Route.MetaFunction = ({ params }) => {
|
|
335
|
+
const content = getIntlayer("about", params.locale);
|
|
336
|
+
|
|
337
|
+
return [
|
|
338
|
+
{ title: content.title },
|
|
339
|
+
{ content: content.description, name: "description" },
|
|
340
|
+
];
|
|
341
|
+
};
|
|
342
|
+
|
|
267
343
|
export default function AboutPage() {
|
|
268
344
|
const { title, content, homeLink } = useIntlayer("about");
|
|
269
345
|
|
|
@@ -482,7 +558,7 @@ export const useI18nHTMLAttributes = () => {
|
|
|
482
558
|
};
|
|
483
559
|
```
|
|
484
560
|
|
|
485
|
-
Este hook já é usado no componente de layout (`
|
|
561
|
+
Este hook já é usado no componente de layout (`root.tsx`) mostrado no Passo 5.
|
|
486
562
|
|
|
487
563
|
### Passo 10: Adicionar middleware (Opcional)
|
|
488
564
|
|
|
@@ -554,15 +554,15 @@ Intlayer помогает поддерживать JSON-переводы в си
|
|
|
554
554
|
Установите зависимости intlayer:
|
|
555
555
|
|
|
556
556
|
```bash packageManager="npm"
|
|
557
|
-
npm install intlayer @intlayer/sync-json-plugin
|
|
557
|
+
npm install intlayer @intlayer/sync-json-plugin --save-dev
|
|
558
558
|
```
|
|
559
559
|
|
|
560
560
|
```bash packageManager="pnpm"
|
|
561
|
-
pnpm add intlayer @intlayer/sync-json-plugin
|
|
561
|
+
pnpm add intlayer @intlayer/sync-json-plugin --save-dev
|
|
562
562
|
```
|
|
563
563
|
|
|
564
564
|
```bash packageManager="yarn"
|
|
565
|
-
yarn add intlayer @intlayer/sync-json-plugin
|
|
565
|
+
yarn add intlayer @intlayer/sync-json-plugin --dev
|
|
566
566
|
```
|
|
567
567
|
|
|
568
568
|
```ts fileName="intlayer.config.ts"
|
|
@@ -393,15 +393,15 @@ export const config = {
|
|
|
393
393
|
Установите зависимости intlayer:
|
|
394
394
|
|
|
395
395
|
```bash packageManager="npm"
|
|
396
|
-
npm install intlayer @intlayer/sync-json-plugin
|
|
396
|
+
npm install intlayer @intlayer/sync-json-plugin --save-dev
|
|
397
397
|
```
|
|
398
398
|
|
|
399
399
|
```bash packageManager="yarn"
|
|
400
|
-
yarn add intlayer @intlayer/sync-json-plugin
|
|
400
|
+
yarn add intlayer @intlayer/sync-json-plugin --dev
|
|
401
401
|
```
|
|
402
402
|
|
|
403
403
|
```bash packageManager="pnpm"
|
|
404
|
-
pnpm add intlayer @intlayer/sync-json-plugin
|
|
404
|
+
pnpm add intlayer @intlayer/sync-json-plugin --save-dev
|
|
405
405
|
```
|
|
406
406
|
|
|
407
407
|
Создайте файл конфигурации intlayer:
|