@intlayer/docs 7.0.3-canary.1 → 7.0.4-canary.0

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.
Files changed (62) hide show
  1. package/blog/en/intlayer_with_i18next.md +1620 -54
  2. package/blog/en/intlayer_with_next-i18next.md +763 -163
  3. package/blog/en/intlayer_with_next-intl.md +986 -217
  4. package/blog/en/intlayer_with_react-i18next.md +645 -147
  5. package/blog/en/intlayer_with_react-intl.md +900 -147
  6. package/blog/en/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
  7. package/dist/cjs/generated/blog.entry.cjs +13 -1
  8. package/dist/cjs/generated/blog.entry.cjs.map +1 -1
  9. package/dist/cjs/generated/docs.entry.cjs +13 -1
  10. package/dist/cjs/generated/docs.entry.cjs.map +1 -1
  11. package/dist/cjs/generated/frequentQuestions.entry.cjs +13 -1
  12. package/dist/cjs/generated/frequentQuestions.entry.cjs.map +1 -1
  13. package/dist/cjs/generated/legal.entry.cjs +13 -1
  14. package/dist/cjs/generated/legal.entry.cjs.map +1 -1
  15. package/dist/esm/generated/blog.entry.mjs +14 -3
  16. package/dist/esm/generated/blog.entry.mjs.map +1 -1
  17. package/dist/esm/generated/docs.entry.mjs +14 -3
  18. package/dist/esm/generated/docs.entry.mjs.map +1 -1
  19. package/dist/esm/generated/frequentQuestions.entry.mjs +14 -3
  20. package/dist/esm/generated/frequentQuestions.entry.mjs.map +1 -1
  21. package/dist/esm/generated/legal.entry.mjs +14 -3
  22. package/dist/esm/generated/legal.entry.mjs.map +1 -1
  23. package/dist/types/generated/blog.entry.d.ts.map +1 -1
  24. package/dist/types/generated/docs.entry.d.ts.map +1 -1
  25. package/dist/types/generated/frequentQuestions.entry.d.ts.map +1 -1
  26. package/dist/types/generated/legal.entry.d.ts.map +1 -1
  27. package/docs/de/releases/v7.md +1 -18
  28. package/docs/en/CI_CD.md +1 -1
  29. package/docs/en/configuration.md +1 -1
  30. package/docs/en/formatters.md +1 -1
  31. package/docs/en/how_works_intlayer.md +1 -1
  32. package/docs/en/intlayer_CMS.md +1 -1
  33. package/docs/en/intlayer_cli.md +1 -1
  34. package/docs/en/intlayer_with_nextjs_14.md +1 -1
  35. package/docs/en/intlayer_with_nextjs_15.md +1 -1
  36. package/docs/en/intlayer_with_nextjs_16.md +1 -1
  37. package/docs/en/intlayer_with_nextjs_page_router.md +1 -1
  38. package/docs/en/intlayer_with_nuxt.md +1 -1
  39. package/docs/en/intlayer_with_react_native+expo.md +1 -1
  40. package/docs/en/intlayer_with_react_router_v7.md +1 -1
  41. package/docs/en/intlayer_with_tanstack.md +1 -1
  42. package/docs/en/intlayer_with_vite+preact.md +1 -1
  43. package/docs/en/intlayer_with_vite+react.md +1 -1
  44. package/docs/en/intlayer_with_vite+solid.md +1 -1
  45. package/docs/en/intlayer_with_vite+svelte.md +1 -1
  46. package/docs/en/intlayer_with_vite+vue.md +1 -1
  47. package/docs/en/roadmap.md +1 -1
  48. package/docs/es/releases/v7.md +1 -18
  49. package/docs/fr/intlayer_with_nextjs_16.md +2 -51
  50. package/docs/fr/releases/v7.md +1 -18
  51. package/docs/hi/intlayer_with_nextjs_16.md +3 -2
  52. package/docs/id/releases/v7.md +1 -18
  53. package/docs/it/releases/v7.md +1 -18
  54. package/docs/ja/intlayer_with_nextjs_16.md +44 -205
  55. package/docs/ja/releases/v7.md +1 -18
  56. package/docs/ko/releases/v7.md +1 -18
  57. package/docs/pt/intlayer_with_nextjs_16.md +1 -52
  58. package/package.json +17 -17
  59. package/src/generated/blog.entry.ts +27 -4
  60. package/src/generated/docs.entry.ts +27 -4
  61. package/src/generated/frequentQuestions.entry.ts +27 -4
  62. package/src/generated/legal.entry.ts +27 -4
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  createdAt: 2024-12-24
3
- updatedAt: 2025-06-29
4
- title: Intlayer and i18next
5
- description: Integrate Intlayer with i18next for optimal internationalisation. Compare the two frameworks and learn how to configure them together.
3
+ updatedAt: 2025-10-29
4
+ title: Migrate from i18next to Intlayer - Complete Integration Guide
5
+ description: Comprehensive guide to migrating from i18next to Intlayer or using them together. Learn the differences, configuration, and best practices for optimal internationalization in Next.js applications.
6
6
  keywords:
7
7
  - Intlayer
8
8
  - i18next
@@ -14,61 +14,303 @@ keywords:
14
14
  - Next.js
15
15
  - JavaScript
16
16
  - TypeScript
17
+ - Migration
18
+ - Integration
17
19
  slugs:
18
20
  - blog
19
21
  - intlayer-with-i18next
22
+ history:
23
+ - version: 7.0.0
24
+ date: 2025-10-29
25
+ changes: Complete rewrite with step-by-step guide and code examples
20
26
  ---
21
27
 
22
- # Internationalization with Intlayer and i18next
28
+ # Migrate from i18next to Intlayer: Complete Integration Guide
23
29
 
24
- i18next is an open-source internationalization (i18n) framework designed for JavaScript applications. It is widely used for managing translations, localization, and language switching in software projects. However, it has some limitations that can complicate scalability and development.
30
+ ## Table of Contents
25
31
 
26
- Intlayer is another internationalization framework that addresses these limitations, offering a more flexible approach to content declaration and management. Let's explore some key differences between i18next and Intlayer, and how to configure both for optimal internationalization.
32
+ <TOC/>
33
+
34
+ ## What is i18next?
35
+
36
+ **i18next** is an open-source internationalization (i18n) framework designed for JavaScript applications. It has been widely used for managing translations, localization, and language switching in software projects for many years. While powerful and mature, i18next has some limitations that can complicate scalability and modern development workflows.
37
+
38
+ ## What is Intlayer?
39
+
40
+ **Intlayer** is a modern, open-source internationalization framework designed to simplify multilingual support in web applications. Intlayer addresses many of the limitations found in traditional i18n solutions like i18next, offering a more flexible and developer-friendly approach to content declaration and management.
27
41
 
28
42
  ## Intlayer vs. i18next: Key Differences
29
43
 
30
- ### 1. Dictionary
44
+ Before diving into the integration, let's understand the key differences between these two frameworks:
45
+
46
+ ### 1. Content Declaration & Dictionary Management
47
+
48
+ **i18next:**
49
+
50
+ - Requires translation dictionaries to be declared in specific folders (typically `public/locales/` or `locales/`)
51
+ - Separate JSON files for each namespace and locale
52
+ - Difficult to track which translations belong to which components
53
+ - Can complicate application scalability as the project grows
54
+
55
+ ```plaintext
56
+ # i18next typical structure
57
+ locales/
58
+ ├── en/
59
+ │ ├── common.json
60
+ │ ├── home.json
61
+ │ └── about.json
62
+ └── fr/
63
+ ├── common.json
64
+ ├── home.json
65
+ └── about.json
66
+ ```
67
+
68
+ **Intlayer:**
69
+
70
+ - Allows content to be declared right next to your components
71
+ - Co-location of content with components
72
+ - Automatic detection and adaptation when components move or are removed
73
+ - Better maintainability and developer experience
74
+
75
+ ```plaintext
76
+ # Intlayer structure
77
+ components/
78
+ ├── Header/
79
+ │ ├── Header.tsx
80
+ │ └── Header.content.ts # Translations live with the component
81
+ └── Footer/
82
+ ├── Footer.tsx
83
+ └── Footer.content.ts
84
+ ```
31
85
 
32
- With i18next, translation dictionaries must be declared in a specific folder, which can complicate application scalability. In contrast, Intlayer allows content to be declared within the same directory as your component. This has several advantages:
86
+ **Advantages:**
33
87
 
34
- - **Simplified Content Editing**: Users don't have to search for the correct dictionary to edit, reducing the chance of errors.
35
- - **Automatic Adaptation**: If a component changes location or is removed, Intlayer detects and adapts automatically.
88
+ - **Simplified Content Editing**: Developers don't have to search through multiple folders to find the correct dictionary
89
+ - **Automatic Adaptation**: If a component changes location or is removed, Intlayer detects and adapts automatically
90
+ - **Better Code Organization**: Keeps related code together, improving maintainability
36
91
 
37
92
  ### 2. Configuration Complexity
38
93
 
39
- Configuring i18next can be complex, especially when integrating with server-side components or configuring middleware for frameworks like Next.js. Intlayer simplifies this process, offering more straightforward configuration.
94
+ **i18next:**
95
+
96
+ - Complex configuration, especially with server-side rendering
97
+ - Requires manual setup for Next.js middleware
98
+ - Separate configuration for client and server
99
+ - Multiple plugins needed for full functionality
100
+
101
+ ```typescript
102
+ // i18next configuration can get complex
103
+ import i18n from "i18next";
104
+ import { initReactI18next } from "react-i18next";
105
+ import Backend from "i18next-http-backend";
106
+ import LanguageDetector from "i18next-browser-languagedetector";
107
+
108
+ i18n
109
+ .use(Backend)
110
+ .use(LanguageDetector)
111
+ .use(initReactI18next)
112
+ .init({
113
+ fallbackLng: "en",
114
+ debug: true,
115
+ interpolation: {
116
+ escapeValue: false,
117
+ },
118
+ // ... many more options
119
+ });
120
+ ```
121
+
122
+ **Intlayer:**
123
+
124
+ - Streamlined configuration process
125
+ - Built-in support for Next.js with simple setup
126
+ - Unified configuration for client and server
127
+ - Minimal configuration required to get started
128
+
129
+ ```typescript
130
+ // Intlayer configuration is straightforward
131
+ import { Locales, type IntlayerConfig } from "intlayer";
132
+
133
+ const config: IntlayerConfig = {
134
+ internationalization: {
135
+ locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
136
+ defaultLocale: Locales.ENGLISH,
137
+ },
138
+ };
139
+
140
+ export default config;
141
+ ```
142
+
143
+ ### 3. TypeScript Integration
144
+
145
+ **i18next:**
146
+
147
+ - TypeScript support requires additional setup
148
+ - Type safety for translation keys is limited
149
+ - Requires manual type definitions
150
+ - Auto-completion is basic
151
+
152
+ **Intlayer:**
153
+
154
+ - First-class TypeScript support out of the box
155
+ - Fully typed content declarations
156
+ - Auto-generated types for all translations
157
+ - Excellent IDE auto-completion and error detection
158
+
159
+ ```typescript
160
+ // Intlayer provides full type safety
161
+ import { t, type Dictionary } from "intlayer";
162
+
163
+ const content = {
164
+ key: "homepage",
165
+ content: {
166
+ title: t({
167
+ en: "Welcome to our site",
168
+ fr: "Bienvenue sur notre site",
169
+ es: "Bienvenido a nuestro sitio",
170
+ }),
171
+ description: t({
172
+ en: "Get started by exploring our features",
173
+ fr: "Commencez par explorer nos fonctionnalités",
174
+ es: "Comience explorando nuestras características",
175
+ }),
176
+ },
177
+ } satisfies Dictionary;
178
+
179
+ // TypeScript knows exactly what keys and values are available
180
+ ```
181
+
182
+ ### 4. Consistency & Validation
183
+
184
+ **i18next:**
185
+
186
+ - Easy to miss translations for specific locales
187
+ - No built-in validation for translation completeness
188
+ - Can lead to runtime errors with missing keys
189
+ - Requires manual checking for consistency
190
+
191
+ **Intlayer:**
192
+
193
+ - Enforces translation completeness at build time
194
+ - Ensures all locales have all required keys
195
+ - TypeScript errors for missing translations
196
+ - Prevents runtime errors from missing content
197
+
198
+ ### 5. Content Sharing Across Applications
199
+
200
+ **i18next:**
201
+
202
+ - Difficult to share translations across multiple apps
203
+ - Requires custom solutions for shared translations
204
+ - No standard approach for monorepo setups
205
+
206
+ **Intlayer:**
207
+
208
+ - Built-in support for sharing content declarations
209
+ - Works seamlessly in monorepo architectures
210
+ - Easy to share translations across multiple applications and libraries
211
+ - Promotes consistency across your entire codebase
212
+
213
+ ### 6. Server Components & Next.js App Router
214
+
215
+ **i18next:**
216
+
217
+ - Limited support for Next.js App Router
218
+ - Complex setup for Server Components
219
+ - Requires workarounds for async components
220
+ - Documentation not always up-to-date with latest Next.js features
221
+
222
+ **Intlayer:**
223
+
224
+ - Native support for Next.js App Router
225
+ - First-class support for Server Components
226
+ - Optimized for Next.js 14, 15, and 16
227
+ - Works seamlessly with Turbopack and React Server Components
228
+
229
+ ## When to Use i18next vs. Intlayer
230
+
231
+ ### Use i18next if:
232
+
233
+ - You have an existing large application already using i18next
234
+ - You need specific i18next plugins or ecosystem tools
235
+ - You're working on a non-React application
236
+ - You need interpolation patterns that i18next handles uniquely
237
+
238
+ ### Use Intlayer if:
239
+
240
+ - You're starting a new project
241
+ - You want better TypeScript integration
242
+ - You're building a modern Next.js application
243
+ - You want co-located translations with components
244
+ - You want better developer experience and maintainability
245
+ - You're working in a monorepo or multi-app architecture
246
+
247
+ ### Use Both Together if:
248
+
249
+ - You're migrating a large existing codebase gradually
250
+ - You want to leverage Intlayer's content management while maintaining i18next compatibility
251
+ - You need to support legacy code while adopting modern patterns
252
+
253
+ ---
254
+
255
+ ## Step-by-Step Guide: Using Intlayer with i18next
256
+
257
+ This guide will show you how to set up a Next.js application with Intlayer, with optional i18next integration for backward compatibility or gradual migration.
258
+
259
+ ### Step 1: Install Dependencies
40
260
 
41
- ### 3. Consistency of Translation Dictionaries
261
+ Install the necessary packages for Intlayer:
42
262
 
43
- Ensuring that translation dictionaries are consistent across different languages can be challenging with i18next. This inconsistency can lead to application crashes if not handled properly. Intlayer addresses this by enforcing constraints on translated content, ensuring no translation is missed and that the translated content is accurate.
263
+ ```bash packageManager="npm"
264
+ npm install intlayer next-intlayer
265
+ ```
266
+
267
+ ```bash packageManager="pnpm"
268
+ pnpm add intlayer next-intlayer
269
+ ```
44
270
 
45
- ### 4. TypeScript Integration
271
+ ```bash packageManager="yarn"
272
+ yarn add intlayer next-intlayer
273
+ ```
46
274
 
47
- Intlayer offers better integration with TypeScript, allowing for auto-suggestions of content in your code, thereby enhancing development efficiency.
275
+ If you plan to use i18next alongside Intlayer (for migration or compatibility):
48
276
 
49
- ### 5. Sharing Content Across Applications
277
+ ```bash packageManager="npm"
278
+ npm install i18next react-i18next i18next-resources-to-backend @intlayer/sync-json-plugin
279
+ ```
50
280
 
51
- Intlayer facilitates the sharing of content declaration files across multiple applications and shared libraries. This feature makes it easier to maintain consistent translations across a larger codebase.
281
+ ```bash packageManager="pnpm"
282
+ pnpm add i18next react-i18next i18next-resources-to-backend @intlayer/sync-json-plugin
283
+ ```
52
284
 
53
- ## How to Generate i18next Dictionaries with Intlayer
285
+ ```bash packageManager="yarn"
286
+ yarn add i18next react-i18next i18next-resources-to-backend @intlayer/sync-json-plugin
287
+ ```
54
288
 
55
- ### Configuring Intlayer to Export i18next Dictionaries
289
+ **What each package does:**
56
290
 
57
- > Important Notes
291
+ - **intlayer**: Core package providing internationalization tools for configuration management, translation, content declaration, transpilation, and CLI commands.
292
+ - **next-intlayer**: Integration package for Next.js with context providers, hooks, and plugins for Webpack/Turbopack.
293
+ - **i18next** (optional): The core i18next internationalization framework.
294
+ - **react-i18next** (optional): React bindings for i18next.
295
+ - **i18next-resources-to-backend** (optional): Dynamically imports i18next resources.
296
+ - **@intlayer/sync-json-plugin** (optional): Plugin to export Intlayer dictionaries as JSON files compatible with i18next.
58
297
 
59
- > The exportation of i18next dictionaries is currently in beta and does not ensure a 1: 1 compatibility with other frameworks. It is recommended to stick to a configuration based on Intlayer to minimise issues.
298
+ ### Step 2: Configure Your Project
60
299
 
61
- To export i18next dictionaries, you need to configure Intlayer appropriately. Below is an example of how to set up Intlayer to export both Intlayer and i18next dictionaries.
300
+ Create an Intlayer configuration file to define your supported locales:
62
301
 
63
302
  ```typescript fileName="intlayer.config.ts" codeFormat="typescript"
64
303
  import { Locales, type IntlayerConfig } from "intlayer";
65
304
 
66
305
  const config: IntlayerConfig = {
67
- content: {
68
- // Indicate that Intlayer will export both Intlayer and i18next dictionaries
69
- dictionaryOutput: ["intlayer", "i18next"],
70
- // Relative path from the project root to the directory where i18n dictionaries will be exported
71
- i18nextResourcesDir: "./i18next/dictionaries",
306
+ internationalization: {
307
+ locales: [
308
+ Locales.ENGLISH,
309
+ Locales.FRENCH,
310
+ Locales.SPANISH,
311
+ // Add your other locales
312
+ ],
313
+ defaultLocale: Locales.ENGLISH,
72
314
  },
73
315
  };
74
316
 
@@ -80,11 +322,14 @@ import { Locales } from "intlayer";
80
322
 
81
323
  /** @type {import('intlayer').IntlayerConfig} */
82
324
  const config = {
83
- content: {
84
- // Indicate that Intlayer will export both Intlayer and i18next dictionaries
85
- dictionaryOutput: ["intlayer", "i18next"],
86
- // Relative path from the project root to the directory where i18n dictionaries will be exported
87
- i18nextResourcesDir: "./i18next/dictionaries",
325
+ internationalization: {
326
+ locales: [
327
+ Locales.ENGLISH,
328
+ Locales.FRENCH,
329
+ Locales.SPANISH,
330
+ // Add your other locales
331
+ ],
332
+ defaultLocale: Locales.ENGLISH,
88
333
  },
89
334
  };
90
335
 
@@ -96,67 +341,1388 @@ const { Locales } = require("intlayer");
96
341
 
97
342
  /** @type {import('intlayer').IntlayerConfig} */
98
343
  const config = {
99
- content: {
100
- // Indicate that Intlayer will export both Intlayer and i18next dictionaries
101
- dictionaryOutput: ["intlayer", "i18next"],
102
- // Relative path from the project root to the directory where i18n dictionaries will be exported
103
- i18nextResourcesDir: "./i18next/dictionaries",
344
+ internationalization: {
345
+ locales: [
346
+ Locales.ENGLISH,
347
+ Locales.FRENCH,
348
+ Locales.SPANISH,
349
+ // Add your other locales
350
+ ],
351
+ defaultLocale: Locales.ENGLISH,
104
352
  },
105
353
  };
106
354
 
107
355
  module.exports = config;
108
356
  ```
109
357
 
110
- By including 'i18next' in the configuration, Intlayer generates dedicated i18next dictionaries in addition to the Intlayer dictionaries. Note that removing 'intlayer' from the configuration may break compatibility with React-Intlayer or Next-Intlayer.
358
+ **If you want to also export JSON dictionaries for i18next**, add the `syncJSON` plugin:
111
359
 
112
- ### Importing Dictionaries into Your i18next Configuration
360
+ ```typescript fileName="intlayer.config.ts" codeFormat="typescript"
361
+ import { Locales, type IntlayerConfig } from "intlayer";
362
+ import { syncJSON } from "@intlayer/sync-json-plugin";
113
363
 
114
- To import the generated dictionaries into your i18next configuration, you can use 'i18next-resources-to-backend'. Here is an example of how to import your i18next dictionaries:
364
+ const config: IntlayerConfig = {
365
+ internationalization: {
366
+ locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
367
+ defaultLocale: Locales.ENGLISH,
368
+ },
369
+ plugins: [
370
+ syncJSON({
371
+ source: ({ key, locale }) => `./intl/messages/${locale}/${key}.json`,
372
+ }),
373
+ ],
374
+ };
115
375
 
116
- ```typescript fileName="i18n/client.ts" codeFormat="typescript"
117
- // i18n/client.ts
376
+ export default config;
377
+ ```
378
+
379
+ ```javascript fileName="intlayer.config.mjs" codeFormat="esm"
380
+ import { Locales } from "intlayer";
381
+ import { syncJSON } from "@intlayer/sync-json-plugin";
382
+
383
+ /** @type {import('intlayer').IntlayerConfig} */
384
+ const config = {
385
+ internationalization: {
386
+ locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
387
+ defaultLocale: Locales.ENGLISH,
388
+ },
389
+ plugins: [
390
+ syncJSON({
391
+ source: ({ key, locale }) => `./intl/messages/${locale}/${key}.json`,
392
+ }),
393
+ ],
394
+ };
395
+
396
+ export default config;
397
+ ```
398
+
399
+ ```javascript fileName="intlayer.config.cjs" codeFormat="commonjs"
400
+ const { Locales } = require("intlayer");
401
+ const { syncJSON } = require("@intlayer/sync-json-plugin");
402
+
403
+ /** @type {import('intlayer').IntlayerConfig} */
404
+ const config = {
405
+ internationalization: {
406
+ locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
407
+ defaultLocale: Locales.ENGLISH,
408
+ },
409
+ plugins: [
410
+ syncJSON({
411
+ source: ({ key, locale }) => `./intl/messages/${locale}/${key}.json`,
412
+ }),
413
+ ],
414
+ };
415
+
416
+ module.exports = config;
417
+ ```
418
+
419
+ > The `syncJSON` plugin will automatically generate JSON files compatible with i18next whenever you build your Intlayer dictionaries.
420
+
421
+ > **Important Note**: The exportation of i18next dictionaries is currently in beta and does not ensure a 1:1 compatibility with all i18next features. It is recommended to use Intlayer natively for the best experience, using i18next export only for gradual migration scenarios.
422
+
423
+ For a complete list of available configuration parameters, refer to the [configuration documentation](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/configuration.md).
424
+
425
+ ### Step 3: Integrate Intlayer in Your Next.js Configuration
426
+
427
+ Configure your Next.js setup to use Intlayer:
428
+
429
+ ```typescript fileName="next.config.ts" codeFormat="typescript"
430
+ import type { NextConfig } from "next";
431
+ import { withIntlayer } from "next-intlayer/server";
432
+
433
+ const nextConfig: NextConfig = {
434
+ /* your config options here */
435
+ };
436
+
437
+ export default withIntlayer(nextConfig);
438
+ ```
439
+
440
+ ```typescript fileName="next.config.mjs" codeFormat="esm"
441
+ import { withIntlayer } from "next-intlayer/server";
442
+
443
+ /** @type {import('next').NextConfig} */
444
+ const nextConfig = {
445
+ /* your config options here */
446
+ };
447
+
448
+ export default withIntlayer(nextConfig);
449
+ ```
450
+
451
+ ```typescript fileName="next.config.cjs" codeFormat="commonjs"
452
+ const { withIntlayer } = require("next-intlayer/server");
453
+
454
+ /** @type {import('next').NextConfig} */
455
+ const nextConfig = {
456
+ /* your config options here */
457
+ };
458
+
459
+ module.exports = withIntlayer(nextConfig);
460
+ ```
461
+
462
+ > The `withIntlayer()` plugin integrates Intlayer with Next.js, building content declaration files, monitoring them in development mode, and providing optimizations for Webpack or Turbopack. It's compatible with both Server and Client Components.
463
+
464
+ ### Step 4: Define Dynamic Locale Routes
465
+
466
+ Set up your Next.js application to handle dynamic locale routing.
467
+
468
+ First, update your root layout to remove the `<html>` and `<body>` tags:
469
+
470
+ ```tsx fileName="src/app/layout.tsx" codeFormat="typescript"
471
+ import type { PropsWithChildren, FC } from "react";
472
+ import "./globals.css";
473
+
474
+ const RootLayout: FC<PropsWithChildren> = ({ children }) => (
475
+ // You can still wrap the children with other providers
476
+ <>{children}</>
477
+ );
478
+
479
+ export default RootLayout;
480
+ ```
481
+
482
+ ```jsx fileName="src/app/layout.mjx" codeFormat="esm"
483
+ import "./globals.css";
484
+
485
+ const RootLayout = ({ children }) => (
486
+ // You can still wrap the children with other providers
487
+ <>{children}</>
488
+ );
489
+
490
+ export default RootLayout;
491
+ ```
492
+
493
+ ```jsx fileName="src/app/layout.csx" codeFormat="commonjs"
494
+ require("./globals.css");
495
+
496
+ const RootLayout = ({ children }) => (
497
+ // You can still wrap the children with other providers
498
+ <>{children}</>
499
+ );
500
+
501
+ module.exports = {
502
+ default: RootLayout,
503
+ };
504
+ ```
505
+
506
+ > Keeping the `RootLayout` component empty allows you to set the [`lang`](https://developer.mozilla.org/fr/docs/Web/HTML/Global_attributes/lang) and [`dir`](https://developer.mozilla.org/fr/docs/Web/HTML/Global_attributes/dir) attributes on the `<html>` tag in the locale-specific layout.
507
+
508
+ Next, create a locale-specific layout in `[locale]` directory:
509
+
510
+ ```tsx fileName="src/app/[locale]/layout.tsx" codeFormat="typescript"
511
+ import type { NextLayoutIntlayer } from "next-intlayer";
512
+ import { Inter } from "next/font/google";
513
+ import { getHTMLTextDir } from "intlayer";
514
+
515
+ const inter = Inter({ subsets: ["latin"] });
516
+
517
+ const LocaleLayout: NextLayoutIntlayer = async ({ children, params }) => {
518
+ const { locale } = await params;
519
+ return (
520
+ <html lang={locale} dir={getHTMLTextDir(locale)}>
521
+ <body className={inter.className}>{children}</body>
522
+ </html>
523
+ );
524
+ };
525
+
526
+ export default LocaleLayout;
527
+ ```
528
+
529
+ ```jsx fileName="src/app/[locale]/layout.mjx" codeFormat="esm"
530
+ import { Inter } from "next/font/google";
531
+ import { getHTMLTextDir } from "intlayer";
532
+
533
+ const inter = Inter({ subsets: ["latin"] });
534
+
535
+ const LocaleLayout = async ({ children, params }) => {
536
+ const { locale } = await params;
537
+ return (
538
+ <html lang={locale} dir={getHTMLTextDir(locale)}>
539
+ <body className={inter.className}>{children}</body>
540
+ </html>
541
+ );
542
+ };
543
+
544
+ export default LocaleLayout;
545
+ ```
546
+
547
+ ```jsx fileName="src/app/[locale]/layout.csx" codeFormat="commonjs"
548
+ const { Inter } = require("next/font/google");
549
+ const { getHTMLTextDir } = require("intlayer");
550
+
551
+ const inter = Inter({ subsets: ["latin"] });
552
+
553
+ const LocaleLayout = async ({ children, params }) => {
554
+ const { locale } = await params;
555
+ return (
556
+ <html lang={locale} dir={getHTMLTextDir(locale)}>
557
+ <body className={inter.className}>{children}</body>
558
+ </html>
559
+ );
560
+ };
561
+
562
+ module.exports = LocaleLayout;
563
+ ```
564
+
565
+ Then, add the `generateStaticParams` function to pre-generate pages for all locales:
566
+
567
+ ```tsx fileName="src/app/[locale]/layout.tsx" codeFormat="typescript"
568
+ export { generateStaticParams } from "next-intlayer"; // Line to insert
569
+
570
+ const LocaleLayout: NextLayoutIntlayer = async ({ children, params }) => {
571
+ /* ... Rest of the code */
572
+ };
573
+
574
+ export default LocaleLayout;
575
+ ```
576
+
577
+ ```jsx fileName="src/app/[locale]/layout.mjx" codeFormat="esm"
578
+ export { generateStaticParams } from "next-intlayer"; // Line to insert
579
+
580
+ const LocaleLayout = async ({ children, params }) => {
581
+ /* ... Rest of the code */
582
+ };
583
+
584
+ export default LocaleLayout;
585
+ ```
586
+
587
+ ```jsx fileName="src/app/[locale]/layout.csx" codeFormat="commonjs"
588
+ const { generateStaticParams } = require("next-intlayer"); // Line to insert
589
+
590
+ const LocaleLayout = async ({ children, params }) => {
591
+ /* ... Rest of the code */
592
+ };
593
+
594
+ module.exports = { default: LocaleLayout, generateStaticParams };
595
+ ```
596
+
597
+ > The `[locale]` path segment is used to define the locale. Example: `/en/about` refers to `en` and `/fr/about` refers to `fr`.
598
+
599
+ > The `generateStaticParams` function ensures your application pre-builds the necessary pages for all locales, reducing runtime computation and improving user experience.
600
+
601
+ ### Step 5: Declare Your Content
602
+
603
+ Create and manage your content declarations. This is where Intlayer truly shines compared to i18next.
604
+
605
+ Create content files next to your components:
606
+
607
+ ```tsx fileName="src/app/[locale]/page.content.ts" contentDeclarationFormat="typescript"
608
+ import { t, type Dictionary } from "intlayer";
609
+
610
+ const pageContent = {
611
+ key: "page",
612
+ content: {
613
+ getStarted: {
614
+ main: t({
615
+ en: "Get started by editing",
616
+ fr: "Commencez par éditer",
617
+ es: "Comience por editar",
618
+ }),
619
+ pageLink: "src/app/page.tsx",
620
+ },
621
+ docs: {
622
+ title: t({
623
+ en: "Documentation",
624
+ fr: "Documentation",
625
+ es: "Documentación",
626
+ }),
627
+ description: t({
628
+ en: "Find in-depth information about Next.js features and API.",
629
+ fr: "Trouvez des informations détaillées sur les fonctionnalités et l'API de Next.js.",
630
+ es: "Encuentre información detallada sobre las características y la API de Next.js.",
631
+ }),
632
+ },
633
+ },
634
+ } satisfies Dictionary;
635
+
636
+ export default pageContent;
637
+ ```
638
+
639
+ ```javascript fileName="src/app/[locale]/page.content.mjs" contentDeclarationFormat="esm"
640
+ import { t } from "intlayer";
641
+
642
+ /** @type {import('intlayer').Dictionary} */
643
+ const pageContent = {
644
+ key: "page",
645
+ content: {
646
+ getStarted: {
647
+ main: t({
648
+ en: "Get started by editing",
649
+ fr: "Commencez par éditer",
650
+ es: "Comience por editar",
651
+ }),
652
+ pageLink: "src/app/page.tsx",
653
+ },
654
+ docs: {
655
+ title: t({
656
+ en: "Documentation",
657
+ fr: "Documentation",
658
+ es: "Documentación",
659
+ }),
660
+ description: t({
661
+ en: "Find in-depth information about Next.js features and API.",
662
+ fr: "Trouvez des informations détaillées sur les fonctionnalités et l'API de Next.js.",
663
+ es: "Encuentre información detallada sobre las características y la API de Next.js.",
664
+ }),
665
+ },
666
+ },
667
+ };
668
+
669
+ export default pageContent;
670
+ ```
671
+
672
+ ```javascript fileName="src/app/[locale]/page.content.cjs" contentDeclarationFormat="commonjs"
673
+ const { t } = require("intlayer");
674
+
675
+ /** @type {import('intlayer').Dictionary} */
676
+ const pageContent = {
677
+ key: "page",
678
+ content: {
679
+ getStarted: {
680
+ main: t({
681
+ en: "Get started by editing",
682
+ fr: "Commencez par éditer",
683
+ es: "Comience por editar",
684
+ }),
685
+ pageLink: "src/app/page.tsx",
686
+ },
687
+ docs: {
688
+ title: t({
689
+ en: "Documentation",
690
+ fr: "Documentation",
691
+ es: "Documentación",
692
+ }),
693
+ description: t({
694
+ en: "Find in-depth information about Next.js features and API.",
695
+ fr: "Trouvez des informations détaillées sur les fonctionnalités et l'API de Next.js.",
696
+ es: "Encuentre información detallada sobre las características y la API de Next.js.",
697
+ }),
698
+ },
699
+ },
700
+ };
701
+
702
+ module.exports = pageContent;
703
+ ```
704
+
705
+ ```json fileName="src/app/[locale]/page.content.json" contentDeclarationFormat="json"
706
+ {
707
+ "$schema": "https://intlayer.org/schema.json",
708
+ "key": "page",
709
+ "content": {
710
+ "getStarted": {
711
+ "main": {
712
+ "nodeType": "translation",
713
+ "translation": {
714
+ "en": "Get started by editing",
715
+ "fr": "Commencez par éditer",
716
+ "es": "Comience por editar"
717
+ }
718
+ },
719
+ "pageLink": "src/app/page.tsx"
720
+ },
721
+ "docs": {
722
+ "title": {
723
+ "nodeType": "translation",
724
+ "translation": {
725
+ "en": "Documentation",
726
+ "fr": "Documentation",
727
+ "es": "Documentación"
728
+ }
729
+ },
730
+ "description": {
731
+ "nodeType": "translation",
732
+ "translation": {
733
+ "en": "Find in-depth information about Next.js features and API.",
734
+ "fr": "Trouvez des informations détaillées sur les fonctionnalités et l'API de Next.js.",
735
+ "es": "Encuentre información detallada sobre las características y la API de Next.js."
736
+ }
737
+ }
738
+ }
739
+ }
740
+ }
741
+ ```
742
+
743
+ > **Intlayer vs. i18next**: With i18next, you would need to create separate JSON files in a `locales/` folder. With Intlayer, content lives right next to your component, making it easier to maintain and refactor.
744
+
745
+ > Content declarations can be defined anywhere in your application as long as they are included in the `contentDir` directory (by default, `./src`). And match the content declaration file extension (by default, `.content.{json,ts,tsx,js,jsx,mjs,mjx,cjs,cjx}`).
746
+
747
+ For more details, refer to the [content declaration documentation](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/dictionary/content_file.md).
748
+
749
+ ### Step 6: Utilize Content in Your Code
750
+
751
+ Access your content dictionaries throughout your application using the `useIntlayer` hook:
752
+
753
+ ```tsx fileName="src/app/[locale]/page.tsx" codeFormat="typescript"
754
+ import type { FC } from "react";
755
+ import { ClientComponentExample } from "@components/ClientComponentExample";
756
+ import { ServerComponentExample } from "@components/ServerComponentExample";
757
+ import { type NextPageIntlayer, IntlayerClientProvider } from "next-intlayer";
758
+ import { IntlayerServerProvider, useIntlayer } from "next-intlayer/server";
759
+
760
+ const PageContent: FC = () => {
761
+ const content = useIntlayer("page");
762
+
763
+ return (
764
+ <>
765
+ <h1>{content.getStarted.main}</h1>
766
+ <code>{content.getStarted.pageLink}</code>
767
+
768
+ <h2>{content.docs.title}</h2>
769
+ <p>{content.docs.description}</p>
770
+ </>
771
+ );
772
+ };
773
+
774
+ const Page: NextPageIntlayer = async ({ params }) => {
775
+ const { locale } = await params;
776
+
777
+ return (
778
+ <IntlayerServerProvider locale={locale}>
779
+ <PageContent />
780
+ <ServerComponentExample />
781
+
782
+ <IntlayerClientProvider locale={locale}>
783
+ <ClientComponentExample />
784
+ </IntlayerClientProvider>
785
+ </IntlayerServerProvider>
786
+ );
787
+ };
788
+
789
+ export default Page;
790
+ ```
791
+
792
+ ```jsx fileName="src/app/[locale]/page.mjx" codeFormat="esm"
793
+ import { ClientComponentExample } from "@components/ClientComponentExample";
794
+ import { ServerComponentExample } from "@components/ServerComponentExample";
795
+ import { IntlayerClientProvider } from "next-intlayer";
796
+ import { IntlayerServerProvider, useIntlayer } from "next-intlayer/server";
797
+
798
+ const PageContent = () => {
799
+ const content = useIntlayer("page");
800
+
801
+ return (
802
+ <>
803
+ <h1>{content.getStarted.main}</h1>
804
+ <code>{content.getStarted.pageLink}</code>
805
+
806
+ <h2>{content.docs.title}</h2>
807
+ <p>{content.docs.description}</p>
808
+ </>
809
+ );
810
+ };
811
+
812
+ const Page = async ({ params }) => {
813
+ const { locale } = await params;
814
+
815
+ return (
816
+ <IntlayerServerProvider locale={locale}>
817
+ <PageContent />
818
+ <ServerComponentExample />
819
+
820
+ <IntlayerClientProvider locale={locale}>
821
+ <ClientComponentExample />
822
+ </IntlayerClientProvider>
823
+ </IntlayerServerProvider>
824
+ );
825
+ };
826
+
827
+ export default Page;
828
+ ```
829
+
830
+ ```jsx fileName="src/app/[locale]/page.csx" codeFormat="commonjs"
831
+ const {
832
+ ClientComponentExample,
833
+ } = require("@components/ClientComponentExample");
834
+ const {
835
+ ServerComponentExample,
836
+ } = require("@components/ServerComponentExample");
837
+ const { IntlayerClientProvider } = require("next-intlayer");
838
+ const { IntlayerServerProvider, useIntlayer } = require("next-intlayer/server");
839
+
840
+ const PageContent = () => {
841
+ const content = useIntlayer("page");
842
+
843
+ return (
844
+ <>
845
+ <h1>{content.getStarted.main}</h1>
846
+ <code>{content.getStarted.pageLink}</code>
847
+
848
+ <h2>{content.docs.title}</h2>
849
+ <p>{content.docs.description}</p>
850
+ </>
851
+ );
852
+ };
853
+
854
+ const Page = async ({ params }) => {
855
+ const { locale } = await params;
118
856
 
857
+ return (
858
+ <IntlayerServerProvider locale={locale}>
859
+ <PageContent />
860
+ <ServerComponentExample />
861
+
862
+ <IntlayerClientProvider locale={locale}>
863
+ <ClientComponentExample />
864
+ </IntlayerClientProvider>
865
+ </IntlayerServerProvider>
866
+ );
867
+ };
868
+
869
+ module.exports = Page;
870
+ ```
871
+
872
+ **Key points:**
873
+
874
+ - **`IntlayerClientProvider`**: Provides the locale to client-side components. Can be placed in any parent component, but recommended in layouts for efficiency.
875
+ - **`IntlayerServerProvider`**: Provides the locale to server children. Cannot be set in the layout due to React's cache mechanism.
876
+ - **`useIntlayer("page")`**: Retrieves the content for the `page` dictionary key with full TypeScript support.
877
+
878
+ **Client Component Example:**
879
+
880
+ ```tsx fileName="src/components/ClientComponentExample.tsx" codeFormat="typescript"
881
+ "use client";
882
+
883
+ import type { FC } from "react";
884
+ import { useIntlayer } from "next-intlayer";
885
+
886
+ export const ClientComponentExample: FC = () => {
887
+ const content = useIntlayer("client-component-example");
888
+
889
+ return (
890
+ <div>
891
+ <h2>{content.title}</h2>
892
+ <p>{content.description}</p>
893
+ </div>
894
+ );
895
+ };
896
+ ```
897
+
898
+ ```jsx fileName="src/components/ClientComponentExample.mjx" codeFormat="esm"
899
+ "use client";
900
+
901
+ import { useIntlayer } from "next-intlayer";
902
+
903
+ export const ClientComponentExample = () => {
904
+ const content = useIntlayer("client-component-example");
905
+
906
+ return (
907
+ <div>
908
+ <h2>{content.title}</h2>
909
+ <p>{content.description}</p>
910
+ </div>
911
+ );
912
+ };
913
+ ```
914
+
915
+ ```jsx fileName="src/components/ClientComponentExample.csx" codeFormat="commonjs"
916
+ "use client";
917
+
918
+ const { useIntlayer } = require("next-intlayer");
919
+
920
+ const ClientComponentExample = () => {
921
+ const content = useIntlayer("client-component-example");
922
+
923
+ return (
924
+ <div>
925
+ <h2>{content.title}</h2>
926
+ <p>{content.description}</p>
927
+ </div>
928
+ );
929
+ };
930
+
931
+ exports.ClientComponentExample = ClientComponentExample;
932
+ ```
933
+
934
+ **Server Component Example:**
935
+
936
+ ```tsx fileName="src/components/ServerComponentExample.tsx" codeFormat="typescript"
937
+ import type { FC } from "react";
938
+ import { useIntlayer } from "next-intlayer/server";
939
+
940
+ export const ServerComponentExample: FC = () => {
941
+ const content = useIntlayer("server-component-example");
942
+
943
+ return (
944
+ <div>
945
+ <h2>{content.title}</h2>
946
+ <p>{content.description}</p>
947
+ </div>
948
+ );
949
+ };
950
+ ```
951
+
952
+ ```jsx fileName="src/components/ServerComponentExample.mjx" codeFormat="esm"
953
+ import { useIntlayer } from "next-intlayer/server";
954
+
955
+ export const ServerComponentExample = () => {
956
+ const content = useIntlayer("server-component-example");
957
+
958
+ return (
959
+ <div>
960
+ <h2>{content.title}</h2>
961
+ <p>{content.description}</p>
962
+ </div>
963
+ );
964
+ };
965
+ ```
966
+
967
+ ```jsx fileName="src/components/ServerComponentExample.csx" codeFormat="commonjs"
968
+ const { useIntlayer } = require("next-intlayer/server");
969
+
970
+ const ServerComponentExample = () => {
971
+ const content = useIntlayer("server-component-example");
972
+
973
+ return (
974
+ <div>
975
+ <h2>{content.title}</h2>
976
+ <p>{content.description}</p>
977
+ </div>
978
+ );
979
+ };
980
+
981
+ exports.ServerComponentExample = ServerComponentExample;
982
+ ```
983
+
984
+ > If you want to use your content in a `string` attribute, such as `alt`, `title`, `href`, `aria-label`, etc., you must call the value of the function:
985
+ >
986
+ > ```jsx
987
+ > <img src={content.image.src.value} alt={content.image.alt.value} />
988
+ > ```
989
+
990
+ > To learn more about the `useIntlayer` hook, refer to the [documentation](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/next-intlayer/useIntlayer.md).
991
+
992
+ ### (Optional) Step 7: Configure Proxy for Locale Detection
993
+
994
+ Set up proxy to automatically detect and redirect users to their preferred locale:
995
+
996
+ ```typescript fileName="src/proxy.ts" codeFormat="typescript"
997
+ export { intlayerProxy as proxy } from "next-intlayer/proxy";
998
+
999
+ export const config = {
1000
+ matcher:
1001
+ "/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\\..*|_next).*)",
1002
+ };
1003
+ ```
1004
+
1005
+ ```javascript fileName="src/proxy.mjs" codeFormat="esm"
1006
+ export { intlayerProxy as proxy } from "next-intlayer/proxy";
1007
+
1008
+ export const config = {
1009
+ matcher:
1010
+ "/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\\..*|_next).*)",
1011
+ };
1012
+ ```
1013
+
1014
+ ```javascript fileName="src/proxy.cjs" codeFormat="commonjs"
1015
+ const { intlayerProxy } = require("next-intlayer/proxy");
1016
+
1017
+ const config = {
1018
+ matcher:
1019
+ "/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\\..*|_next).*)",
1020
+ };
1021
+
1022
+ module.exports = { proxy: intlayerProxy, config };
1023
+ ```
1024
+
1025
+ > The `intlayerProxy` detects the user's preferred locale from browser headers and cookies, then redirects them to the appropriate URL. It also saves the preference in a cookie for future visits.
1026
+
1027
+ ### (Optional) Step 8: Internationalization of Your Metadata
1028
+
1029
+ To internationalize metadata (page titles, descriptions, etc.), use the `generateMetadata` function with `getIntlayer`:
1030
+
1031
+ ```typescript fileName="src/app/[locale]/metadata.content.ts" contentDeclarationFormat="typescript"
1032
+ import { type Dictionary, t } from "intlayer";
1033
+ import type { Metadata } from "next";
1034
+
1035
+ const metadataContent = {
1036
+ key: "page-metadata",
1037
+ content: {
1038
+ title: t({
1039
+ en: "My Website - Home",
1040
+ fr: "Mon Site Web - Accueil",
1041
+ es: "Mi Sitio Web - Inicio",
1042
+ }),
1043
+ description: t({
1044
+ en: "Welcome to my multilingual website built with Intlayer and Next.js",
1045
+ fr: "Bienvenue sur mon site web multilingue construit avec Intlayer et Next.js",
1046
+ es: "Bienvenido a mi sitio web multilingüe construido con Intlayer y Next.js",
1047
+ }),
1048
+ },
1049
+ } satisfies Dictionary<Metadata>;
1050
+
1051
+ export default metadataContent;
1052
+ ```
1053
+
1054
+ ```javascript fileName="src/app/[locale]/metadata.content.mjs" contentDeclarationFormat="esm"
1055
+ import { t } from "intlayer";
1056
+
1057
+ /** @type {import('intlayer').Dictionary<import('next').Metadata>} */
1058
+ const metadataContent = {
1059
+ key: "page-metadata",
1060
+ content: {
1061
+ title: t({
1062
+ en: "My Website - Home",
1063
+ fr: "Mon Site Web - Accueil",
1064
+ es: "Mi Sitio Web - Inicio",
1065
+ }),
1066
+ description: t({
1067
+ en: "Welcome to my multilingual website built with Intlayer and Next.js",
1068
+ fr: "Bienvenue sur mon site web multilingue construit avec Intlayer et Next.js",
1069
+ es: "Bienvenido a mi sitio web multilingüe construido con Intlayer y Next.js",
1070
+ }),
1071
+ },
1072
+ };
1073
+
1074
+ export default metadataContent;
1075
+ ```
1076
+
1077
+ ```javascript fileName="src/app/[locale]/metadata.content.cjs" contentDeclarationFormat="commonjs"
1078
+ const { t } = require("intlayer");
1079
+
1080
+ /** @type {import('intlayer').Dictionary<import('next').Metadata>} */
1081
+ const metadataContent = {
1082
+ key: "page-metadata",
1083
+ content: {
1084
+ title: t({
1085
+ en: "My Website - Home",
1086
+ fr: "Mon Site Web - Accueil",
1087
+ es: "Mi Sitio Web - Inicio",
1088
+ }),
1089
+ description: t({
1090
+ en: "Welcome to my multilingual website built with Intlayer and Next.js",
1091
+ fr: "Bienvenue sur mon site web multilingue construit avec Intlayer et Next.js",
1092
+ es: "Bienvenido a mi sitio web multilingüe construido con Intlayer y Next.js",
1093
+ }),
1094
+ },
1095
+ };
1096
+
1097
+ module.exports = metadataContent;
1098
+ ```
1099
+
1100
+ ```json fileName="src/app/[locale]/metadata.content.json" contentDeclarationFormat="json"
1101
+ {
1102
+ "$schema": "https://intlayer.org/schema.json",
1103
+ "key": "page-metadata",
1104
+ "content": {
1105
+ "title": {
1106
+ "nodeType": "translation",
1107
+ "translation": {
1108
+ "en": "My Website - Home",
1109
+ "fr": "Mon Site Web - Accueil",
1110
+ "es": "Mi Sitio Web - Inicio"
1111
+ }
1112
+ },
1113
+ "description": {
1114
+ "nodeType": "translation",
1115
+ "translation": {
1116
+ "en": "Welcome to my multilingual website built with Intlayer and Next.js",
1117
+ "fr": "Bienvenue sur mon site web multilingue construit avec Intlayer et Next.js",
1118
+ "es": "Bienvenido a mi sitio web multilingüe construido con Intlayer y Next.js"
1119
+ }
1120
+ }
1121
+ }
1122
+ }
1123
+ ```
1124
+
1125
+ Then use it in your layout or page:
1126
+
1127
+ ```typescript fileName="src/app/[locale]/layout.tsx or src/app/[locale]/page.tsx" codeFormat="typescript"
1128
+ import { getIntlayer, getMultilingualUrls } from "intlayer";
1129
+ import type { Metadata } from "next";
1130
+ import type { LocalPromiseParams } from "next-intlayer";
1131
+
1132
+ export const generateMetadata = async ({
1133
+ params,
1134
+ }: LocalPromiseParams): Promise<Metadata> => {
1135
+ const { locale } = await params;
1136
+ const metadata = getIntlayer("page-metadata", locale);
1137
+
1138
+ const multilingualUrls = getMultilingualUrls("/");
1139
+ const localizedUrl =
1140
+ multilingualUrls[locale as keyof typeof multilingualUrls];
1141
+
1142
+ return {
1143
+ ...metadata,
1144
+ alternates: {
1145
+ canonical: localizedUrl,
1146
+ languages: { ...multilingualUrls, "x-default": "/" },
1147
+ },
1148
+ openGraph: {
1149
+ url: localizedUrl,
1150
+ },
1151
+ };
1152
+ };
1153
+
1154
+ // ... Rest of your layout or page code
1155
+ ```
1156
+
1157
+ ```javascript fileName="src/app/[locale]/layout.mjs or src/app/[locale]/page.mjs" codeFormat="esm"
1158
+ import { getIntlayer, getMultilingualUrls } from "intlayer";
1159
+
1160
+ export const generateMetadata = async ({ params }) => {
1161
+ const { locale } = await params;
1162
+ const metadata = getIntlayer("page-metadata", locale);
1163
+
1164
+ const multilingualUrls = getMultilingualUrls("/");
1165
+ const localizedUrl = multilingualUrls[locale];
1166
+
1167
+ return {
1168
+ ...metadata,
1169
+ alternates: {
1170
+ canonical: localizedUrl,
1171
+ languages: { ...multilingualUrls, "x-default": "/" },
1172
+ },
1173
+ openGraph: {
1174
+ url: localizedUrl,
1175
+ },
1176
+ };
1177
+ };
1178
+
1179
+ // ... Rest of your layout or page code
1180
+ ```
1181
+
1182
+ ```javascript fileName="src/app/[locale]/layout.cjs or src/app/[locale]/page.cjs" codeFormat="commonjs"
1183
+ const { getIntlayer, getMultilingualUrls } = require("intlayer");
1184
+
1185
+ const generateMetadata = async ({ params }) => {
1186
+ const { locale } = await params;
1187
+ const metadata = getIntlayer("page-metadata", locale);
1188
+
1189
+ const multilingualUrls = getMultilingualUrls("/");
1190
+ const localizedUrl = multilingualUrls[locale];
1191
+
1192
+ return {
1193
+ ...metadata,
1194
+ alternates: {
1195
+ canonical: localizedUrl,
1196
+ languages: { ...multilingualUrls, "x-default": "/" },
1197
+ },
1198
+ openGraph: {
1199
+ url: localizedUrl,
1200
+ },
1201
+ };
1202
+ };
1203
+
1204
+ module.exports = { generateMetadata };
1205
+
1206
+ // ... Rest of your layout or page code
1207
+ ```
1208
+
1209
+ > Learn more about Next.js metadata optimization in the [official Next.js documentation](https://nextjs.org/docs/app/building-your-application/optimizing/metadata).
1210
+
1211
+ ### (Optional) Step 9: Internationalization of sitemap.xml and robots.txt
1212
+
1213
+ Internationalize your `sitemap.xml` and `robots.txt` files:
1214
+
1215
+ ```tsx fileName="src/app/sitemap.ts" codeFormat="typescript"
1216
+ import { getMultilingualUrls } from "intlayer";
1217
+ import type { MetadataRoute } from "next";
1218
+
1219
+ const sitemap = (): MetadataRoute.Sitemap => [
1220
+ {
1221
+ url: "https://example.com",
1222
+ alternates: {
1223
+ languages: { ...getMultilingualUrls("https://example.com") },
1224
+ },
1225
+ },
1226
+ {
1227
+ url: "https://example.com/about",
1228
+ alternates: {
1229
+ languages: { ...getMultilingualUrls("https://example.com/about") },
1230
+ },
1231
+ },
1232
+ {
1233
+ url: "https://example.com/contact",
1234
+ alternates: {
1235
+ languages: { ...getMultilingualUrls("https://example.com/contact") },
1236
+ },
1237
+ },
1238
+ ];
1239
+
1240
+ export default sitemap;
1241
+ ```
1242
+
1243
+ ```jsx fileName="src/app/sitemap.mjx" codeFormat="esm"
1244
+ import { getMultilingualUrls } from "intlayer";
1245
+
1246
+ const sitemap = () => [
1247
+ {
1248
+ url: "https://example.com",
1249
+ alternates: {
1250
+ languages: { ...getMultilingualUrls("https://example.com") },
1251
+ },
1252
+ },
1253
+ {
1254
+ url: "https://example.com/about",
1255
+ alternates: {
1256
+ languages: { ...getMultilingualUrls("https://example.com/about") },
1257
+ },
1258
+ },
1259
+ {
1260
+ url: "https://example.com/contact",
1261
+ alternates: {
1262
+ languages: { ...getMultilingualUrls("https://example.com/contact") },
1263
+ },
1264
+ },
1265
+ ];
1266
+
1267
+ export default sitemap;
1268
+ ```
1269
+
1270
+ ```jsx fileName="src/app/sitemap.csx" codeFormat="commonjs"
1271
+ const { getMultilingualUrls } = require("intlayer");
1272
+
1273
+ const sitemap = () => [
1274
+ {
1275
+ url: "https://example.com",
1276
+ alternates: {
1277
+ languages: { ...getMultilingualUrls("https://example.com") },
1278
+ },
1279
+ },
1280
+ {
1281
+ url: "https://example.com/about",
1282
+ alternates: {
1283
+ languages: { ...getMultilingualUrls("https://example.com/about") },
1284
+ },
1285
+ },
1286
+ {
1287
+ url: "https://example.com/contact",
1288
+ alternates: {
1289
+ languages: { ...getMultilingualUrls("https://example.com/contact") },
1290
+ },
1291
+ },
1292
+ ];
1293
+
1294
+ module.exports = sitemap;
1295
+ ```
1296
+
1297
+ ```tsx fileName="src/app/robots.ts" codeFormat="typescript"
1298
+ import type { MetadataRoute } from "next";
1299
+ import { getMultilingualUrls } from "intlayer";
1300
+
1301
+ const getAllMultilingualUrls = (urls: string[]) =>
1302
+ urls.flatMap((url) => Object.values(getMultilingualUrls(url)) as string[]);
1303
+
1304
+ const robots = (): MetadataRoute.Robots => ({
1305
+ rules: {
1306
+ userAgent: "*",
1307
+ allow: ["/"],
1308
+ disallow: getAllMultilingualUrls(["/admin", "/private"]),
1309
+ },
1310
+ host: "https://example.com",
1311
+ sitemap: `https://example.com/sitemap.xml`,
1312
+ });
1313
+
1314
+ export default robots;
1315
+ ```
1316
+
1317
+ ```jsx fileName="src/app/robots.mjx" codeFormat="esm"
1318
+ import { getMultilingualUrls } from "intlayer";
1319
+
1320
+ const getAllMultilingualUrls = (urls) =>
1321
+ urls.flatMap((url) => Object.values(getMultilingualUrls(url)));
1322
+
1323
+ const robots = () => ({
1324
+ rules: {
1325
+ userAgent: "*",
1326
+ allow: ["/"],
1327
+ disallow: getAllMultilingualUrls(["/admin", "/private"]),
1328
+ },
1329
+ host: "https://example.com",
1330
+ sitemap: `https://example.com/sitemap.xml`,
1331
+ });
1332
+
1333
+ export default robots;
1334
+ ```
1335
+
1336
+ ```jsx fileName="src/app/robots.csx" codeFormat="commonjs"
1337
+ const { getMultilingualUrls } = require("intlayer");
1338
+
1339
+ const getAllMultilingualUrls = (urls) =>
1340
+ urls.flatMap((url) => Object.values(getMultilingualUrls(url)));
1341
+
1342
+ const robots = () => ({
1343
+ rules: {
1344
+ userAgent: "*",
1345
+ allow: ["/"],
1346
+ disallow: getAllMultilingualUrls(["/admin", "/private"]),
1347
+ },
1348
+ host: "https://example.com",
1349
+ sitemap: `https://example.com/sitemap.xml`,
1350
+ });
1351
+
1352
+ module.exports = robots;
1353
+ ```
1354
+
1355
+ > Learn more about sitemap optimization in the [Next.js sitemap documentation](https://nextjs.org/docs/app/api-reference/file-conventions/metadata/sitemap) and about robots.txt in the [Next.js robots.txt documentation](https://nextjs.org/docs/app/api-reference/file-conventions/metadata/robots).
1356
+
1357
+ ### (Optional) Step 10: Change the Language of Your Content
1358
+
1359
+ To allow users to switch languages, use the `useLocale` hook and Next.js's `Link` component:
1360
+
1361
+ ```tsx fileName="src/components/LocaleSwitcher.tsx" codeFormat="typescript"
1362
+ "use client";
1363
+
1364
+ import type { FC } from "react";
1365
+ import {
1366
+ Locales,
1367
+ getHTMLTextDir,
1368
+ getLocaleName,
1369
+ getLocalizedUrl,
1370
+ } from "intlayer";
1371
+ import { useLocale } from "next-intlayer";
1372
+ import Link from "next/link";
1373
+
1374
+ export const LocaleSwitcher: FC = () => {
1375
+ const { locale, pathWithoutLocale, availableLocales, setLocale } =
1376
+ useLocale();
1377
+
1378
+ return (
1379
+ <div>
1380
+ <button popoverTarget="localePopover">{getLocaleName(locale)}</button>
1381
+ <div id="localePopover" popover="auto">
1382
+ {availableLocales.map((localeItem) => (
1383
+ <Link
1384
+ href={getLocalizedUrl(pathWithoutLocale, localeItem)}
1385
+ key={localeItem}
1386
+ aria-current={locale === localeItem ? "page" : undefined}
1387
+ onClick={() => setLocale(localeItem)}
1388
+ replace // Ensures that "go back" browser button redirects to previous page
1389
+ >
1390
+ <span>
1391
+ {/* Locale - e.g. FR */}
1392
+ {localeItem}
1393
+ </span>
1394
+ <span>
1395
+ {/* Language in its own Locale - e.g. Français */}
1396
+ {getLocaleName(localeItem, locale)}
1397
+ </span>
1398
+ <span dir={getHTMLTextDir(localeItem)} lang={localeItem}>
1399
+ {/* Language in current Locale - e.g. Francés with current locale set to Locales.SPANISH */}
1400
+ {getLocaleName(localeItem)}
1401
+ </span>
1402
+ <span dir="ltr" lang={Locales.ENGLISH}>
1403
+ {/* Language in English - e.g. French */}
1404
+ {getLocaleName(localeItem, Locales.ENGLISH)}
1405
+ </span>
1406
+ </Link>
1407
+ ))}
1408
+ </div>
1409
+ </div>
1410
+ );
1411
+ };
1412
+ ```
1413
+
1414
+ ```jsx fileName="src/components/LocaleSwitcher.mjx" codeFormat="esm"
1415
+ "use client";
1416
+
1417
+ import {
1418
+ Locales,
1419
+ getHTMLTextDir,
1420
+ getLocaleName,
1421
+ getLocalizedUrl,
1422
+ } from "intlayer";
1423
+ import { useLocale } from "next-intlayer";
1424
+ import Link from "next/link";
1425
+
1426
+ export const LocaleSwitcher = () => {
1427
+ const { locale, pathWithoutLocale, availableLocales, setLocale } =
1428
+ useLocale();
1429
+
1430
+ return (
1431
+ <div>
1432
+ <button popoverTarget="localePopover">{getLocaleName(locale)}</button>
1433
+ <div id="localePopover" popover="auto">
1434
+ {availableLocales.map((localeItem) => (
1435
+ <Link
1436
+ href={getLocalizedUrl(pathWithoutLocale, localeItem)}
1437
+ key={localeItem}
1438
+ aria-current={locale === localeItem ? "page" : undefined}
1439
+ onClick={() => setLocale(localeItem)}
1440
+ replace
1441
+ >
1442
+ <span>{localeItem}</span>
1443
+ <span>{getLocaleName(localeItem, locale)}</span>
1444
+ <span dir={getHTMLTextDir(localeItem)} lang={localeItem}>
1445
+ {getLocaleName(localeItem)}
1446
+ </span>
1447
+ <span dir="ltr" lang={Locales.ENGLISH}>
1448
+ {getLocaleName(localeItem, Locales.ENGLISH)}
1449
+ </span>
1450
+ </Link>
1451
+ ))}
1452
+ </div>
1453
+ </div>
1454
+ );
1455
+ };
1456
+ ```
1457
+
1458
+ ```jsx fileName="src/components/LocaleSwitcher.csx" codeFormat="commonjs"
1459
+ "use client";
1460
+
1461
+ const {
1462
+ Locales,
1463
+ getHTMLTextDir,
1464
+ getLocaleName,
1465
+ getLocalizedUrl,
1466
+ } = require("intlayer");
1467
+ const { useLocale } = require("next-intlayer");
1468
+ const Link = require("next/link");
1469
+
1470
+ const LocaleSwitcher = () => {
1471
+ const { locale, pathWithoutLocale, availableLocales, setLocale } =
1472
+ useLocale();
1473
+
1474
+ return (
1475
+ <div>
1476
+ <button popoverTarget="localePopover">{getLocaleName(locale)}</button>
1477
+ <div id="localePopover" popover="auto">
1478
+ {availableLocales.map((localeItem) => (
1479
+ <Link
1480
+ href={getLocalizedUrl(pathWithoutLocale, localeItem)}
1481
+ key={localeItem}
1482
+ aria-current={locale === localeItem ? "page" : undefined}
1483
+ onClick={() => setLocale(localeItem)}
1484
+ replace
1485
+ >
1486
+ <span>{localeItem}</span>
1487
+ <span>{getLocaleName(localeItem, locale)}</span>
1488
+ <span dir={getHTMLTextDir(localeItem)} lang={localeItem}>
1489
+ {getLocaleName(localeItem)}
1490
+ </span>
1491
+ <span dir="ltr" lang={Locales.ENGLISH}>
1492
+ {getLocaleName(localeItem, Locales.ENGLISH)}
1493
+ </span>
1494
+ </Link>
1495
+ ))}
1496
+ </div>
1497
+ </div>
1498
+ );
1499
+ };
1500
+
1501
+ exports.LocaleSwitcher = LocaleSwitcher;
1502
+ ```
1503
+
1504
+ > **Comparison with i18next**: With i18next, you would typically use the `useTranslation` hook and manually manage language switching. Intlayer's `useLocale` hook provides a more integrated experience with Next.js routing and automatic URL management.
1505
+
1506
+ > Documentation references:
1507
+ >
1508
+ > - [`useLocale` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/next-intlayer/useLocale.md)
1509
+ > - [`getLocaleName` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/intlayer/getLocaleName.md)
1510
+ > - [`getLocalizedUrl` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/intlayer/getLocalizedUrl.md)
1511
+ > - [`getHTMLTextDir` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/packages/intlayer/getHTMLTextDir.md)
1512
+
1513
+ ### (Optional) Step 11: Using i18next Alongside Intlayer
1514
+
1515
+ If you need to maintain i18next compatibility during a gradual migration, you can configure i18next to load dictionaries exported by Intlayer:
1516
+
1517
+ ```typescript fileName="i18n/client.ts" codeFormat="typescript"
119
1518
  import i18next from "i18next";
1519
+ import { initReactI18next } from "react-i18next";
120
1520
  import resourcesToBackend from "i18next-resources-to-backend";
121
1521
 
122
1522
  i18next
123
- // Your i18next configuration
1523
+ .use(initReactI18next)
124
1524
  .use(
125
1525
  resourcesToBackend(
126
1526
  (language: string, namespace: string) =>
127
- import(`../i18next/dictionaries/${language}/${namespace}.json`)
1527
+ import(`../intl/messages/${language}/${namespace}.json`)
128
1528
  )
129
- );
1529
+ )
1530
+ .init({
1531
+ fallbackLng: "en",
1532
+ debug: process.env.NODE_ENV === "development",
1533
+ interpolation: {
1534
+ escapeValue: false,
1535
+ },
1536
+ });
1537
+
1538
+ export default i18next;
130
1539
  ```
131
1540
 
132
1541
  ```javascript fileName="i18n/client.mjs" codeFormat="esm"
133
- // i18n/client.mjs
134
-
135
1542
  import i18next from "i18next";
1543
+ import { initReactI18next } from "react-i18next";
136
1544
  import resourcesToBackend from "i18next-resources-to-backend";
137
1545
 
138
1546
  i18next
139
- // Your i18next configuration
1547
+ .use(initReactI18next)
140
1548
  .use(
141
1549
  resourcesToBackend(
142
1550
  (language, namespace) =>
143
- import(`../i18next/dictionaries/${language}/${namespace}.json`)
1551
+ import(`../intl/messages/${language}/${namespace}.json`)
144
1552
  )
145
- );
1553
+ )
1554
+ .init({
1555
+ fallbackLng: "en",
1556
+ debug: process.env.NODE_ENV === "development",
1557
+ interpolation: {
1558
+ escapeValue: false,
1559
+ },
1560
+ });
1561
+
1562
+ export default i18next;
146
1563
  ```
147
1564
 
148
1565
  ```javascript fileName="i18n/client.cjs" codeFormat="commonjs"
149
- // i18n/client.cjs
150
-
151
1566
  const i18next = require("i18next");
1567
+ const { initReactI18next } = require("react-i18next");
152
1568
  const resourcesToBackend = require("i18next-resources-to-backend");
153
1569
 
154
1570
  i18next
155
- // Your i18next configuration
1571
+ .use(initReactI18next)
156
1572
  .use(
157
1573
  resourcesToBackend(
158
1574
  (language, namespace) =>
159
- import(`../i18next/dictionaries/${language}/${namespace}.json`)
1575
+ import(`../intl/messages/${language}/${namespace}.json`)
160
1576
  )
1577
+ )
1578
+ .init({
1579
+ fallbackLng: "en",
1580
+ debug: process.env.NODE_ENV === "development",
1581
+ interpolation: {
1582
+ escapeValue: false,
1583
+ },
1584
+ });
1585
+
1586
+ module.exports = i18next;
1587
+ ```
1588
+
1589
+ **Usage in a component:**
1590
+
1591
+ ```tsx fileName="src/components/LegacyComponent.tsx"
1592
+ "use client";
1593
+
1594
+ import { useTranslation } from "react-i18next";
1595
+
1596
+ export const LegacyComponent = () => {
1597
+ const { t } = useTranslation();
1598
+
1599
+ return (
1600
+ <div>
1601
+ <h2>{t("page:docs.title")}</h2>
1602
+ <p>{t("page:docs.description")}</p>
1603
+ </div>
161
1604
  );
1605
+ };
162
1606
  ```
1607
+
1608
+ This approach allows you to:
1609
+
1610
+ - Use Intlayer's modern content declaration system
1611
+ - Gradually migrate components from i18next to Intlayer
1612
+ - Maintain compatibility with existing i18next code
1613
+ - Export dictionaries in both formats during the transition
1614
+
1615
+ ---
1616
+
1617
+ ## Migration Strategy: From i18next to Intlayer
1618
+
1619
+ If you're migrating an existing application from i18next to Intlayer, follow this strategy:
1620
+
1621
+ ### Phase 1: Setup (Week 1)
1622
+
1623
+ 1. **Install Intlayer** alongside your existing i18next setup
1624
+ 2. **Configure Intlayer** with the `syncJSON` plugin to export dictionaries
1625
+ 3. **Test** that both systems work in parallel
1626
+
1627
+ ### Phase 2: Gradual Migration (Weeks 2-N)
1628
+
1629
+ 1. **Create Intlayer content files** for new features
1630
+ 2. **Migrate existing components** one at a time:
1631
+ - Create corresponding `.content.ts` files
1632
+ - Replace `useTranslation()` with `useIntlayer()`
1633
+ - Test thoroughly before moving to the next component
1634
+ 3. **Focus on high-value components** first (frequently edited, complex translations)
1635
+
1636
+ ### Phase 3: Cleanup (Final Week)
1637
+
1638
+ 1. **Remove i18next dependencies** once all components are migrated
1639
+ 2. **Delete old locale JSON files**
1640
+ 3. **Remove the `syncJSON` plugin** from your Intlayer config
1641
+ 4. **Update documentation** for your team
1642
+
1643
+ ### Migration Checklist
1644
+
1645
+ - [ ] Intlayer installed and configured
1646
+ - [ ] `syncJSON` plugin configured for i18next compatibility
1647
+ - [ ] First component migrated and tested
1648
+ - [ ] Team trained on Intlayer patterns
1649
+ - [ ] 25% of components migrated
1650
+ - [ ] 50% of components migrated
1651
+ - [ ] 75% of components migrated
1652
+ - [ ] 100% of components migrated
1653
+ - [ ] i18next removed
1654
+ - [ ] Documentation updated
1655
+
1656
+ ---
1657
+
1658
+ ## Advanced Configuration
1659
+
1660
+ ### TypeScript Configuration
1661
+
1662
+ Ensure your TypeScript configuration includes the auto-generated types:
1663
+
1664
+ ```json5 fileName="tsconfig.json"
1665
+ {
1666
+ // ... Your existing TypeScript configurations
1667
+ "include": [
1668
+ // ... Your existing TypeScript configurations
1669
+ ".intlayer/**/*.ts", // Include the auto-generated types
1670
+ ],
1671
+ }
1672
+ ```
1673
+
1674
+ ### Git Configuration
1675
+
1676
+ Ignore the generated files:
1677
+
1678
+ ```plaintext fileName=".gitignore"
1679
+ # Ignore the files generated by Intlayer
1680
+ .intlayer
1681
+ ```
1682
+
1683
+ ### VS Code Extension
1684
+
1685
+ For improved developer experience, install the official **Intlayer VS Code Extension**:
1686
+
1687
+ [Install from the VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=intlayer.intlayer-vs-code-extension)
1688
+
1689
+ This extension provides:
1690
+
1691
+ - **Autocompletion** for translation keys
1692
+ - **Real-time error detection** for missing translations
1693
+ - **Inline previews** of translated content
1694
+ - **Quick actions** for creating and updating translations
1695
+
1696
+ > **Comparison with i18next**: While i18next has some IDE extensions, Intlayer's extension provides deeper integration with TypeScript and better auto-completion thanks to co-located content declarations.
1697
+
1698
+ ---
1699
+
1700
+ ## Conclusion
1701
+
1702
+ By following this comprehensive guide, you now have a fully internationalized Next.js application using Intlayer, with optional i18next compatibility for gradual migration.
1703
+
1704
+ **Key Takeaways:**
1705
+
1706
+ 1. **Intlayer** offers a modern, developer-friendly approach to i18n that addresses many limitations of traditional solutions like i18next
1707
+ 2. **Co-located content** declarations improve maintainability and reduce errors
1708
+ 3. **First-class TypeScript support** provides excellent IDE integration and catches errors at build time
1709
+ 4. **Flexible migration** path allows gradual adoption without disrupting existing applications
1710
+ 5. **Built-in Next.js support** makes it the ideal choice for modern React applications
1711
+
1712
+ Whether you're starting a new project or migrating from i18next, Intlayer provides the tools and flexibility you need for a scalable, maintainable internationalization solution.
1713
+
1714
+ ---
1715
+
1716
+ ## Further Resources
1717
+
1718
+ - [Intlayer Documentation](https://intlayer.org)
1719
+ - [Intlayer GitHub Repository](https://github.com/aymericzip/intlayer)
1720
+ - [Next.js Internationalization Guide](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_with_nextjs_14.md)
1721
+ - [Intlayer Visual Editor](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_visual_editor.md)
1722
+ - [Intlayer CMS](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_CMS.md)
1723
+ - [i18next Documentation](https://www.i18next.com/)
1724
+ - [react-i18next Documentation](https://react.i18next.com/)
1725
+
1726
+ <function_calls>
1727
+ <invoke name="read_file">
1728
+ <parameter name="target_file">docs/docs/en/intlayer_with_nextjs_16.md