@intlayer/docs 6.1.5 → 6.1.6
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/next-i18next_vs_next-intl_vs_intlayer.md +404 -173
- package/blog/de/next-i18next_vs_next-intl_vs_intlayer.md +262 -113
- package/blog/en/intlayer_with_next-i18next.mdx +431 -0
- package/blog/en/intlayer_with_next-intl.mdx +335 -0
- package/blog/en/next-i18next_vs_next-intl_vs_intlayer.md +463 -209
- package/blog/en-GB/next-i18next_vs_next-intl_vs_intlayer.md +38 -28
- package/blog/es/next-i18next_vs_next-intl_vs_intlayer.md +185 -71
- package/blog/fr/next-i18next_vs_next-intl_vs_intlayer.md +38 -28
- package/blog/it/next-i18next_vs_next-intl_vs_intlayer.md +38 -28
- package/blog/ja/next-i18next_vs_next-intl_vs_intlayer.md +38 -28
- package/blog/ko/next-i18next_vs_next-intl_vs_intlayer.md +38 -28
- package/blog/pt/next-i18next_vs_next-intl_vs_intlayer.md +38 -28
- package/blog/ru/next-i18next_vs_next-intl_vs_intlayer.md +36 -28
- package/blog/tr/next-i18next_vs_next-intl_vs_intlayer.md +2 -0
- package/blog/zh/next-i18next_vs_next-intl_vs_intlayer.md +38 -28
- package/dist/cjs/generated/docs.entry.cjs +32 -0
- package/dist/cjs/generated/docs.entry.cjs.map +1 -1
- package/dist/esm/generated/docs.entry.mjs +32 -0
- package/dist/esm/generated/docs.entry.mjs.map +1 -1
- package/dist/types/generated/docs.entry.d.ts +2 -0
- package/dist/types/generated/docs.entry.d.ts.map +1 -1
- package/docs/ar/component_i18n.md +186 -0
- package/docs/ar/intlayer_with_angular.md +2 -2
- package/docs/ar/intlayer_with_astro.md +246 -0
- package/docs/ar/intlayer_with_create_react_app.md +3 -2
- package/docs/ar/intlayer_with_express.md +2 -2
- package/docs/ar/intlayer_with_nestjs.md +2 -2
- package/docs/ar/intlayer_with_nextjs_14.md +2 -2
- package/docs/ar/intlayer_with_nextjs_15.md +2 -2
- package/docs/ar/intlayer_with_nextjs_page_router.md +2 -2
- package/docs/ar/intlayer_with_nuxt.md +2 -2
- package/docs/ar/intlayer_with_react_native+expo.md +11 -20
- package/docs/ar/intlayer_with_react_router_v7.md +195 -241
- package/docs/ar/intlayer_with_tanstack.md +198 -272
- package/docs/ar/intlayer_with_vite+preact.md +9 -9
- package/docs/ar/intlayer_with_vite+react.md +7 -7
- package/docs/ar/intlayer_with_vite+vue.md +9 -9
- package/docs/ar/vs_code_extension.md +48 -109
- package/docs/de/component_i18n.md +186 -0
- package/docs/de/intlayer_with_angular.md +2 -2
- package/docs/de/intlayer_with_astro.md +246 -0
- package/docs/de/intlayer_with_create_react_app.md +2 -2
- package/docs/de/intlayer_with_express.md +2 -2
- package/docs/de/intlayer_with_nestjs.md +2 -2
- package/docs/de/intlayer_with_nextjs_14.md +2 -2
- package/docs/de/intlayer_with_nextjs_15.md +2 -2
- package/docs/de/intlayer_with_nextjs_page_router.md +2 -2
- package/docs/de/intlayer_with_nuxt.md +2 -2
- package/docs/de/intlayer_with_react_native+expo.md +11 -20
- package/docs/de/intlayer_with_react_router_v7.md +193 -242
- package/docs/de/intlayer_with_tanstack.md +194 -266
- package/docs/de/intlayer_with_vite+preact.md +9 -9
- package/docs/de/intlayer_with_vite+react.md +9 -9
- package/docs/de/intlayer_with_vite+vue.md +11 -11
- package/docs/de/packages/vite-intlayer/index.md +3 -3
- package/docs/de/vs_code_extension.md +46 -107
- package/docs/en/component_i18n.md +186 -0
- package/docs/en/how_works_intlayer.md +1 -1
- package/docs/en/index.md +1 -1
- package/docs/en/intlayer_cli.md +1 -1
- package/docs/en/intlayer_with_angular.md +4 -4
- package/docs/en/intlayer_with_astro.md +246 -0
- package/docs/en/intlayer_with_create_react_app.md +4 -4
- package/docs/en/intlayer_with_express.md +3 -3
- package/docs/en/intlayer_with_lynx+react.md +1 -1
- package/docs/en/intlayer_with_nestjs.md +2 -2
- package/docs/en/intlayer_with_nextjs_14.md +31 -5
- package/docs/en/intlayer_with_nextjs_15.md +31 -5
- package/docs/en/intlayer_with_nextjs_page_router.md +5 -5
- package/docs/en/intlayer_with_nuxt.md +4 -4
- package/docs/en/intlayer_with_react_native+expo.md +46 -24
- package/docs/en/intlayer_with_react_router_v7.md +164 -211
- package/docs/en/intlayer_with_tanstack.md +166 -241
- package/docs/en/intlayer_with_vite+preact.md +12 -12
- package/docs/en/intlayer_with_vite+react.md +12 -12
- package/docs/en/intlayer_with_vite+solid.md +2 -2
- package/docs/en/intlayer_with_vite+svelte.md +2 -2
- package/docs/en/intlayer_with_vite+vue.md +12 -12
- package/docs/en/introduction.md +1 -1
- package/docs/en/packages/next-intlayer/useDictionary.md +1 -1
- package/docs/en/packages/next-intlayer/useIntlayer.md +1 -1
- package/docs/en/packages/react-intlayer/useDictionary.md +1 -1
- package/docs/en/packages/react-intlayer/useI18n.md +1 -1
- package/docs/en/packages/react-intlayer/useIntlayer.md +1 -1
- package/docs/en/releases/v6.md +1 -0
- package/docs/en/roadmap.md +1 -1
- package/docs/en/vs_code_extension.md +24 -114
- package/docs/en-GB/component_i18n.md +186 -0
- package/docs/en-GB/intlayer_with_angular.md +3 -3
- package/docs/en-GB/intlayer_with_astro.md +246 -0
- package/docs/en-GB/intlayer_with_create_react_app.md +5 -4
- package/docs/en-GB/intlayer_with_express.md +2 -2
- package/docs/en-GB/intlayer_with_nestjs.md +2 -2
- package/docs/en-GB/intlayer_with_nextjs_14.md +4 -4
- package/docs/en-GB/intlayer_with_nextjs_15.md +2 -2
- package/docs/en-GB/intlayer_with_nextjs_page_router.md +2 -2
- package/docs/en-GB/intlayer_with_nuxt.md +2 -2
- package/docs/en-GB/intlayer_with_react_native+expo.md +11 -20
- package/docs/en-GB/intlayer_with_react_router_v7.md +171 -220
- package/docs/en-GB/intlayer_with_tanstack.md +174 -248
- package/docs/en-GB/intlayer_with_vite+preact.md +9 -9
- package/docs/en-GB/intlayer_with_vite+react.md +9 -9
- package/docs/en-GB/intlayer_with_vite+vue.md +11 -11
- package/docs/en-GB/packages/next-intlayer/useIntlayer.md +1 -1
- package/docs/en-GB/packages/react-intlayer/useIntlayer.md +1 -1
- package/docs/en-GB/vs_code_extension.md +42 -103
- package/docs/es/component_i18n.md +182 -0
- package/docs/es/intlayer_with_angular.md +2 -2
- package/docs/es/intlayer_with_astro.md +246 -0
- package/docs/es/intlayer_with_create_react_app.md +3 -2
- package/docs/es/intlayer_with_express.md +2 -2
- package/docs/es/intlayer_with_nextjs_14.md +2 -2
- package/docs/es/intlayer_with_nextjs_15.md +2 -2
- package/docs/es/intlayer_with_react_native+expo.md +11 -20
- package/docs/es/intlayer_with_react_router_v7.md +188 -232
- package/docs/es/intlayer_with_tanstack.md +203 -273
- package/docs/es/intlayer_with_vite+preact.md +7 -7
- package/docs/es/intlayer_with_vite+react.md +7 -7
- package/docs/es/intlayer_with_vite+vue.md +9 -9
- package/docs/es/vs_code_extension.md +53 -114
- package/docs/fr/component_i18n.md +186 -0
- package/docs/fr/intlayer_with_angular.md +2 -2
- package/docs/fr/intlayer_with_astro.md +246 -0
- package/docs/fr/intlayer_with_create_react_app.md +3 -2
- package/docs/fr/intlayer_with_express.md +2 -2
- package/docs/fr/intlayer_with_nestjs.md +2 -2
- package/docs/fr/intlayer_with_nextjs_14.md +2 -2
- package/docs/fr/intlayer_with_react_native+expo.md +11 -20
- package/docs/fr/intlayer_with_react_router_v7.md +188 -248
- package/docs/fr/intlayer_with_tanstack.md +192 -265
- package/docs/fr/intlayer_with_vite+preact.md +7 -7
- package/docs/fr/intlayer_with_vite+react.md +7 -7
- package/docs/fr/intlayer_with_vite+vue.md +9 -9
- package/docs/fr/vs_code_extension.md +50 -111
- package/docs/hi/component_i18n.md +186 -0
- package/docs/hi/intlayer_cli.md +1 -4
- package/docs/hi/intlayer_with_angular.md +2 -2
- package/docs/hi/intlayer_with_astro.md +246 -0
- package/docs/hi/intlayer_with_create_react_app.md +2 -2
- package/docs/hi/intlayer_with_express.md +2 -2
- package/docs/hi/intlayer_with_nestjs.md +2 -2
- package/docs/hi/intlayer_with_nextjs_14.md +2 -2
- package/docs/hi/intlayer_with_nextjs_15.md +2 -2
- package/docs/hi/intlayer_with_nextjs_page_router.md +2 -2
- package/docs/hi/intlayer_with_nuxt.md +2 -2
- package/docs/hi/intlayer_with_react_native+expo.md +11 -20
- package/docs/hi/intlayer_with_react_router_v7.md +199 -243
- package/docs/hi/intlayer_with_tanstack.md +210 -285
- package/docs/hi/intlayer_with_vite+preact.md +9 -9
- package/docs/hi/intlayer_with_vite+react.md +9 -9
- package/docs/hi/intlayer_with_vite+solid.md +1 -1
- package/docs/hi/intlayer_with_vite+vue.md +11 -11
- package/docs/hi/vs_code_extension.md +49 -110
- package/docs/it/component_i18n.md +186 -0
- package/docs/it/intlayer_with_angular.md +2 -2
- package/docs/it/intlayer_with_astro.md +246 -0
- package/docs/it/intlayer_with_create_react_app.md +3 -2
- package/docs/it/intlayer_with_express.md +2 -2
- package/docs/it/intlayer_with_nestjs.md +2 -2
- package/docs/it/intlayer_with_nextjs_14.md +2 -2
- package/docs/it/intlayer_with_nextjs_15.md +2 -2
- package/docs/it/intlayer_with_nextjs_page_router.md +2 -2
- package/docs/it/intlayer_with_nuxt.md +2 -2
- package/docs/it/intlayer_with_react_native+expo.md +11 -21
- package/docs/it/intlayer_with_react_router_v7.md +195 -242
- package/docs/it/intlayer_with_tanstack.md +203 -267
- package/docs/it/intlayer_with_vite+preact.md +9 -9
- package/docs/it/intlayer_with_vite+react.md +13 -11
- package/docs/it/intlayer_with_vite+vue.md +11 -11
- package/docs/it/vs_code_extension.md +50 -111
- package/docs/ja/component_i18n.md +186 -0
- package/docs/ja/intlayer_with_angular.md +2 -2
- package/docs/ja/intlayer_with_astro.md +246 -0
- package/docs/ja/intlayer_with_create_react_app.md +3 -2
- package/docs/ja/intlayer_with_express.md +2 -2
- package/docs/ja/intlayer_with_nestjs.md +2 -2
- package/docs/ja/intlayer_with_nextjs_14.md +2 -2
- package/docs/ja/intlayer_with_nextjs_15.md +2 -2
- package/docs/ja/intlayer_with_nextjs_page_router.md +2 -2
- package/docs/ja/intlayer_with_nuxt.md +2 -2
- package/docs/ja/intlayer_with_react_native+expo.md +18 -29
- package/docs/ja/intlayer_with_react_router_v7.md +204 -250
- package/docs/ja/intlayer_with_tanstack.md +218 -286
- package/docs/ja/intlayer_with_vite+preact.md +9 -9
- package/docs/ja/intlayer_with_vite+react.md +11 -11
- package/docs/ja/intlayer_with_vite+vue.md +11 -11
- package/docs/ja/vs_code_extension.md +50 -111
- package/docs/ko/component_i18n.md +186 -0
- package/docs/ko/intlayer_with_angular.md +2 -2
- package/docs/ko/intlayer_with_astro.md +246 -0
- package/docs/ko/intlayer_with_create_react_app.md +3 -2
- package/docs/ko/intlayer_with_express.md +2 -2
- package/docs/ko/intlayer_with_nestjs.md +2 -2
- package/docs/ko/intlayer_with_nextjs_14.md +2 -2
- package/docs/ko/intlayer_with_nextjs_15.md +2 -2
- package/docs/ko/intlayer_with_nextjs_page_router.md +2 -2
- package/docs/ko/intlayer_with_nuxt.md +2 -2
- package/docs/ko/intlayer_with_react_native+expo.md +19 -28
- package/docs/ko/intlayer_with_react_router_v7.md +190 -244
- package/docs/ko/intlayer_with_tanstack.md +200 -270
- package/docs/ko/intlayer_with_vite+preact.md +9 -9
- package/docs/ko/intlayer_with_vite+react.md +9 -9
- package/docs/ko/intlayer_with_vite+vue.md +11 -11
- package/docs/ko/vs_code_extension.md +48 -109
- package/docs/pt/component_i18n.md +186 -0
- package/docs/pt/intlayer_with_angular.md +2 -2
- package/docs/pt/intlayer_with_astro.md +246 -0
- package/docs/pt/intlayer_with_create_react_app.md +3 -2
- package/docs/pt/intlayer_with_express.md +2 -2
- package/docs/pt/intlayer_with_nestjs.md +2 -2
- package/docs/pt/intlayer_with_nextjs_14.md +2 -2
- package/docs/pt/intlayer_with_nextjs_15.md +2 -2
- package/docs/pt/intlayer_with_nextjs_page_router.md +2 -2
- package/docs/pt/intlayer_with_nuxt.md +2 -2
- package/docs/pt/intlayer_with_react_native+expo.md +11 -20
- package/docs/pt/intlayer_with_react_router_v7.md +7 -13
- package/docs/pt/intlayer_with_tanstack.md +183 -258
- package/docs/pt/intlayer_with_vite+preact.md +9 -9
- package/docs/pt/intlayer_with_vite+react.md +9 -9
- package/docs/pt/intlayer_with_vite+vue.md +9 -9
- package/docs/pt/vs_code_extension.md +46 -107
- package/docs/ru/component_i18n.md +186 -0
- package/docs/ru/intlayer_with_angular.md +2 -2
- package/docs/ru/intlayer_with_astro.md +246 -0
- package/docs/ru/intlayer_with_create_react_app.md +3 -2
- package/docs/ru/intlayer_with_express.md +2 -2
- package/docs/ru/intlayer_with_nestjs.md +2 -2
- package/docs/ru/intlayer_with_nextjs_14.md +2 -2
- package/docs/ru/intlayer_with_nextjs_15.md +2 -2
- package/docs/ru/intlayer_with_nextjs_page_router.md +2 -2
- package/docs/ru/intlayer_with_nuxt.md +2 -2
- package/docs/ru/intlayer_with_react_native+expo.md +11 -20
- package/docs/ru/intlayer_with_react_router_v7.md +192 -238
- package/docs/ru/intlayer_with_tanstack.md +197 -269
- package/docs/ru/intlayer_with_vite+preact.md +9 -9
- package/docs/ru/intlayer_with_vite+react.md +9 -9
- package/docs/ru/intlayer_with_vite+vue.md +11 -11
- package/docs/ru/vs_code_extension.md +48 -109
- package/docs/tr/component_i18n.md +186 -0
- package/docs/tr/how_works_intlayer.md +1 -1
- package/docs/tr/index.md +1 -1
- package/docs/tr/intlayer_cli.md +1 -1
- package/docs/tr/intlayer_with_angular.md +4 -4
- package/docs/tr/intlayer_with_astro.md +246 -0
- package/docs/tr/intlayer_with_create_react_app.md +4 -4
- package/docs/tr/intlayer_with_express.md +3 -3
- package/docs/tr/intlayer_with_lynx+react.md +1 -1
- package/docs/tr/intlayer_with_nestjs.md +2 -2
- package/docs/tr/intlayer_with_nextjs_14.md +2 -2
- package/docs/tr/intlayer_with_nextjs_15.md +4 -4
- package/docs/tr/intlayer_with_nextjs_page_router.md +5 -5
- package/docs/tr/intlayer_with_nuxt.md +4 -4
- package/docs/tr/intlayer_with_react_native+expo.md +12 -21
- package/docs/tr/intlayer_with_react_router_v7.md +222 -267
- package/docs/tr/intlayer_with_tanstack.md +400 -303
- package/docs/tr/intlayer_with_vite+preact.md +12 -12
- package/docs/tr/intlayer_with_vite+react.md +12 -12
- package/docs/tr/intlayer_with_vite+solid.md +2 -2
- package/docs/tr/intlayer_with_vite+svelte.md +2 -2
- package/docs/tr/intlayer_with_vite+vue.md +12 -12
- package/docs/tr/introduction.md +1 -1
- package/docs/tr/packages/react-intlayer/useDictionary.md +1 -1
- package/docs/tr/packages/react-intlayer/useI18n.md +1 -1
- package/docs/tr/roadmap.md +1 -1
- package/docs/tr/vs_code_extension.md +54 -115
- package/docs/zh/component_i18n.md +186 -0
- package/docs/zh/intlayer_with_angular.md +2 -2
- package/docs/zh/intlayer_with_astro.md +246 -0
- package/docs/zh/intlayer_with_create_react_app.md +3 -2
- package/docs/zh/intlayer_with_express.md +2 -2
- package/docs/zh/intlayer_with_nestjs.md +2 -2
- package/docs/zh/intlayer_with_nextjs_14.md +2 -2
- package/docs/zh/intlayer_with_nextjs_15.md +2 -2
- package/docs/zh/intlayer_with_nextjs_page_router.md +2 -2
- package/docs/zh/intlayer_with_nuxt.md +2 -2
- package/docs/zh/intlayer_with_react_native+expo.md +19 -28
- package/docs/zh/intlayer_with_react_router_v7.md +200 -248
- package/docs/zh/intlayer_with_tanstack.md +208 -283
- package/docs/zh/intlayer_with_vite+preact.md +9 -9
- package/docs/zh/intlayer_with_vite+react.md +9 -9
- package/docs/zh/intlayer_with_vite+vue.md +9 -9
- package/docs/zh/vs_code_extension.md +51 -105
- package/package.json +10 -10
- package/src/generated/docs.entry.ts +32 -0
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
```bash
|
|
2
|
+
.
|
|
3
|
+
├── locales
|
|
4
|
+
│ ├── en
|
|
5
|
+
│ │ ├── common.json
|
|
6
|
+
│ │ └── about.json
|
|
7
|
+
│ ├── fr
|
|
8
|
+
│ │ ├── common.json
|
|
9
|
+
│ │ └── about.json
|
|
10
|
+
│ └── es
|
|
11
|
+
│ ├── common.json
|
|
12
|
+
│ └── about.json
|
|
13
|
+
└── src
|
|
14
|
+
├── i18n.ts
|
|
15
|
+
├── middleware.ts
|
|
16
|
+
├── app
|
|
17
|
+
│ └── [locale]
|
|
18
|
+
│ ├── layout.tsx
|
|
19
|
+
│ └── about
|
|
20
|
+
│ └── page.tsx
|
|
21
|
+
└── components
|
|
22
|
+
├── ClientComponentExample.tsx
|
|
23
|
+
└── ServerComponent.tsx
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
#### Setup and Loading Content
|
|
27
|
+
|
|
28
|
+
As mentioned previously, you must optimize how each JSON file is imported into your code.
|
|
29
|
+
How the library handles content loading is important.
|
|
30
|
+
|
|
31
|
+
```tsx fileName="src/i18n.ts"
|
|
32
|
+
import { getRequestConfig } from 'next-intl/server';
|
|
33
|
+
import { notFound } from 'next/navigation';
|
|
34
|
+
|
|
35
|
+
export const locales = ['en', 'fr', 'es'] as const;
|
|
36
|
+
export const defaultLocale = 'en' as const;
|
|
37
|
+
|
|
38
|
+
async function loadMessages(locale: string) {
|
|
39
|
+
// Load only the namespaces your layout/pages need
|
|
40
|
+
const [common, about] = await Promise.all([
|
|
41
|
+
import(`../locales/${locale}/common.json`).then((m) => m.default),
|
|
42
|
+
import(`../locales/${locale}/about.json`).then((m) => m.default),
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
return { common, about } as const;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export default getRequestConfig(async ({ locale }) => {
|
|
49
|
+
if (!locales.includes(locale as any)) notFound();
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
messages: await loadMessages(locale),
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```tsx fileName="src/app/[locale]/layout.tsx"
|
|
58
|
+
import type { ReactNode } from 'react';
|
|
59
|
+
import { locales } from '@/i18n';
|
|
60
|
+
import {
|
|
61
|
+
getLocaleDirection,
|
|
62
|
+
unstable_setRequestLocale,
|
|
63
|
+
} from 'next-intl/server';
|
|
64
|
+
|
|
65
|
+
export const dynamic = 'force-static';
|
|
66
|
+
|
|
67
|
+
export function generateStaticParams() {
|
|
68
|
+
return locales.map((locale) => ({ locale }));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export default function LocaleLayout({
|
|
72
|
+
children,
|
|
73
|
+
params,
|
|
74
|
+
}: {
|
|
75
|
+
children: ReactNode;
|
|
76
|
+
params: Promise<{ locale: string }>;
|
|
77
|
+
}) {
|
|
78
|
+
const { locale } = await params;
|
|
79
|
+
|
|
80
|
+
// Set the active request locale for this server render (RSC)
|
|
81
|
+
unstable_setRequestLocale(locale);
|
|
82
|
+
|
|
83
|
+
const dir = getLocaleDirection(locale);
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<html lang={locale} dir={dir}>
|
|
87
|
+
<body>{children}</body>
|
|
88
|
+
</html>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
```tsx fileName="src/app/[locale]/about/page.tsx"
|
|
94
|
+
import { getTranslations, getMessages, getFormatter } from 'next-intl/server';
|
|
95
|
+
import { NextIntlClientProvider } from 'next-intl';
|
|
96
|
+
import pick from 'lodash/pick';
|
|
97
|
+
import ServerComponent from '@/components/ServerComponent';
|
|
98
|
+
import ClientComponentExample from '@/components/ClientComponentExample';
|
|
99
|
+
|
|
100
|
+
export const dynamic = 'force-static';
|
|
101
|
+
|
|
102
|
+
export default async function AboutPage({
|
|
103
|
+
params,
|
|
104
|
+
}: {
|
|
105
|
+
params: Promise<{ locale: string }>;
|
|
106
|
+
}) {
|
|
107
|
+
const { locale } = await params;
|
|
108
|
+
|
|
109
|
+
// Messages are loaded server-side. Push only what's needed to the client.
|
|
110
|
+
const messages = await getMessages();
|
|
111
|
+
const clientMessages = pick(messages, ['common', 'about']);
|
|
112
|
+
|
|
113
|
+
// Strictly server-side translations/formatting
|
|
114
|
+
const tAbout = await getTranslations('about');
|
|
115
|
+
const tCounter = await getTranslations('about.counter');
|
|
116
|
+
const format = await getFormatter();
|
|
117
|
+
|
|
118
|
+
const initialFormattedCount = format.number(0);
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<NextIntlClientProvider locale={locale} messages={clientMessages}>
|
|
122
|
+
<main>
|
|
123
|
+
<h1>{tAbout('title')}</h1>
|
|
124
|
+
<ClientComponentExample />
|
|
125
|
+
<ServerComponent
|
|
126
|
+
formattedCount={initialFormattedCount}
|
|
127
|
+
label={tCounter('label')}
|
|
128
|
+
increment={tCounter('increment')}
|
|
129
|
+
/>
|
|
130
|
+
</main>
|
|
131
|
+
</NextIntlClientProvider>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Usage in a client component
|
|
137
|
+
|
|
138
|
+
Let's take an example of a client component rendering a counter.
|
|
139
|
+
|
|
140
|
+
**Translations (shape reused; load them into next-intl messages as you prefer)**
|
|
141
|
+
|
|
142
|
+
```json fileName="locales/en/about.json"
|
|
143
|
+
{
|
|
144
|
+
"counter": {
|
|
145
|
+
"label": "Counter",
|
|
146
|
+
"increment": "Increment"
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
```json fileName="locales/fr/about.json"
|
|
152
|
+
{
|
|
153
|
+
"counter": {
|
|
154
|
+
"label": "Compteur",
|
|
155
|
+
"increment": "Incrémenter"
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**Client component**
|
|
161
|
+
|
|
162
|
+
```tsx fileName="src/components/ClientComponentExample.tsx"
|
|
163
|
+
'use client';
|
|
164
|
+
|
|
165
|
+
import React, { useState } from 'react';
|
|
166
|
+
import { useTranslations, useFormatter } from 'next-intl';
|
|
167
|
+
|
|
168
|
+
const ClientComponentExample = () => {
|
|
169
|
+
// Scope directly to the nested object
|
|
170
|
+
const t = useTranslations('about.counter');
|
|
171
|
+
const format = useFormatter();
|
|
172
|
+
const [count, setCount] = useState(0);
|
|
173
|
+
|
|
174
|
+
return (
|
|
175
|
+
<div>
|
|
176
|
+
<p>{format.number(count)}</p>
|
|
177
|
+
<button
|
|
178
|
+
aria-label={t('label')}
|
|
179
|
+
onClick={() => setCount((count) => count + 1)}
|
|
180
|
+
>
|
|
181
|
+
{t('increment')}
|
|
182
|
+
</button>
|
|
183
|
+
</div>
|
|
184
|
+
);
|
|
185
|
+
};
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
> Don't forget to add "about" message on the page client message
|
|
189
|
+
> (only include the namespaces your client actually needs).
|
|
190
|
+
|
|
191
|
+
### Usage in a server component
|
|
192
|
+
|
|
193
|
+
We will take the case of a UI component. This component is a server component, and should be able to be inserted as a child of a client component. (page (server component) -> client component -> server component). As this component can be inserted as a child of a client component, it cannot be async.
|
|
194
|
+
|
|
195
|
+
```tsx fileName="src/components/ServerComponent.tsx"
|
|
196
|
+
type ServerComponentProps = {
|
|
197
|
+
count: number;
|
|
198
|
+
t: (key: string) => string;
|
|
199
|
+
formatter: Intl.NumberFormat;
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const ServerComponent = ({ t, count, formatter }: ServerComponentProps) => {
|
|
203
|
+
const formatted = formatter.format(count);
|
|
204
|
+
|
|
205
|
+
return (
|
|
206
|
+
<div>
|
|
207
|
+
<p>{formatted}</p>
|
|
208
|
+
<button aria-label={t('label')}>{t('increment')}</button>
|
|
209
|
+
</div>
|
|
210
|
+
);
|
|
211
|
+
};
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
> As the server component cannot be async, you need to pass the translations and formatter function as props.
|
|
215
|
+
>
|
|
216
|
+
> In your page / layout:
|
|
217
|
+
>
|
|
218
|
+
> - `import { getTranslations, getFormatter } from "next-intl/server";`
|
|
219
|
+
> - `const t = await getTranslations("about.counter");`
|
|
220
|
+
> - `const formatter = await getFormatter().then((formatter) => formatter.number());`
|
|
221
|
+
|
|
222
|
+
```tsx fileName="src/app/[locale]/about/layout.tsx"
|
|
223
|
+
import type { Metadata } from 'next';
|
|
224
|
+
import { locales, defaultLocale } from '@/i18n';
|
|
225
|
+
import { getTranslations } from 'next-intl/server';
|
|
226
|
+
|
|
227
|
+
function localizedPath(locale: string, path: string) {
|
|
228
|
+
return locale === defaultLocale ? path : '/' + locale + path;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export async function generateMetadata({
|
|
232
|
+
params,
|
|
233
|
+
}: {
|
|
234
|
+
params: { locale: string };
|
|
235
|
+
}): Promise<Metadata> {
|
|
236
|
+
const { locale } = params;
|
|
237
|
+
const t = await getTranslations({ locale, namespace: 'about' });
|
|
238
|
+
|
|
239
|
+
const url = '/about';
|
|
240
|
+
const languages = Object.fromEntries(
|
|
241
|
+
locales.map((locale) => [locale, localizedPath(locale, url)])
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
return {
|
|
245
|
+
title: t('title'),
|
|
246
|
+
description: t('description'),
|
|
247
|
+
alternates: {
|
|
248
|
+
canonical: localizedPath(locale, url),
|
|
249
|
+
languages: { ...languages, 'x-default': url },
|
|
250
|
+
},
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// ... Rest of the page code
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
```tsx fileName="src/app/sitemap.ts"
|
|
258
|
+
import type { MetadataRoute } from 'next';
|
|
259
|
+
import { locales, defaultLocale } from '@/i18n';
|
|
260
|
+
|
|
261
|
+
const origin = 'https://example.com';
|
|
262
|
+
|
|
263
|
+
const formatterLocalizedPath = (locale: string, path: string) =>
|
|
264
|
+
locale === defaultLocale ? origin + path : origin + '/' + locale + path;
|
|
265
|
+
|
|
266
|
+
export default function sitemap(): MetadataRoute.Sitemap {
|
|
267
|
+
const aboutLanguages = Object.fromEntries(
|
|
268
|
+
locales.map((l) => [l, formatterLocalizedPath(l, '/about')])
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
return [
|
|
272
|
+
{
|
|
273
|
+
url: formatterLocalizedPath(defaultLocale, '/about'),
|
|
274
|
+
lastModified: new Date(),
|
|
275
|
+
changeFrequency: 'monthly',
|
|
276
|
+
priority: 0.7,
|
|
277
|
+
alternates: { languages: aboutLanguages },
|
|
278
|
+
},
|
|
279
|
+
];
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
```tsx fileName="src/app/robots.ts"
|
|
284
|
+
import type { MetadataRoute } from 'next';
|
|
285
|
+
import { locales, defaultLocale } from '@/i18n';
|
|
286
|
+
|
|
287
|
+
const origin = 'https://example.com';
|
|
288
|
+
const withAllLocales = (path: string) => [
|
|
289
|
+
path,
|
|
290
|
+
...locales
|
|
291
|
+
.filter((locale) => locale !== defaultLocale)
|
|
292
|
+
.map((locale) => '/' + locale + path),
|
|
293
|
+
];
|
|
294
|
+
|
|
295
|
+
export default function robots(): MetadataRoute.Robots {
|
|
296
|
+
const disallow = [
|
|
297
|
+
...withAllLocales('/dashboard'),
|
|
298
|
+
...withAllLocales('/admin'),
|
|
299
|
+
];
|
|
300
|
+
|
|
301
|
+
return {
|
|
302
|
+
rules: { userAgent: '*', allow: ['/'], disallow },
|
|
303
|
+
host: origin,
|
|
304
|
+
sitemap: origin + '/sitemap.xml',
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### Middleware for locale routing
|
|
310
|
+
|
|
311
|
+
Add a middleware to handle locale detection and routing:
|
|
312
|
+
|
|
313
|
+
```ts fileName="src/middleware.ts"
|
|
314
|
+
import createMiddleware from 'next-intl/middleware';
|
|
315
|
+
import { locales, defaultLocale } from '@/i18n';
|
|
316
|
+
|
|
317
|
+
export default createMiddleware({
|
|
318
|
+
locales: [...locales],
|
|
319
|
+
defaultLocale,
|
|
320
|
+
localeDetection: true,
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
export const config = {
|
|
324
|
+
// Skip API, Next internals and static assets
|
|
325
|
+
matcher: ['/((?!api|_next|.*\\..*).*)'],
|
|
326
|
+
};
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Best practices
|
|
330
|
+
|
|
331
|
+
- **Set html `lang` and `dir`**: In `src/app/[locale]/layout.tsx`, compute `dir` via `getLocaleDirection(locale)` and set `<html lang={locale} dir={dir}>`.
|
|
332
|
+
- **Split messages by namespace**: Organize JSON per locale and namespace (e.g., `common.json`, `about.json`).
|
|
333
|
+
- **Minimize client payload**: On pages, send only required namespaces to `NextIntlClientProvider` (e.g., `pick(messages, ['common', 'about'])`).
|
|
334
|
+
- **Prefer static pages**: Export `export const dynamic = 'force-static'` and generate static params for all `locales`.
|
|
335
|
+
- **Synchronous server components**: Keep server components sync by passing precomputed strings (translated labels, formatted numbers) rather than async calls or non-serializable functions.
|