@intlayer/docs 7.0.4-canary.0 → 7.0.4

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 (107) hide show
  1. package/blog/ar/intlayer_with_i18next.md +68 -106
  2. package/blog/ar/intlayer_with_next-i18next.md +84 -288
  3. package/blog/ar/intlayer_with_next-intl.md +58 -337
  4. package/blog/ar/intlayer_with_react-i18next.md +68 -290
  5. package/blog/ar/intlayer_with_react-intl.md +63 -266
  6. package/blog/de/intlayer_with_i18next.md +77 -97
  7. package/blog/de/intlayer_with_next-i18next.md +69 -296
  8. package/blog/de/intlayer_with_next-intl.md +59 -340
  9. package/blog/de/intlayer_with_react-i18next.md +68 -290
  10. package/blog/de/intlayer_with_react-intl.md +62 -264
  11. package/blog/en/intlayer_with_i18next.md +36 -1638
  12. package/blog/en/intlayer_with_next-i18next.md +22 -847
  13. package/blog/en/intlayer_with_next-intl.md +32 -1053
  14. package/blog/en/intlayer_with_react-i18next.md +38 -764
  15. package/blog/en/intlayer_with_react-intl.md +42 -1018
  16. package/blog/en-GB/intlayer_with_i18next.md +67 -103
  17. package/blog/en-GB/intlayer_with_next-i18next.md +71 -292
  18. package/blog/en-GB/intlayer_with_next-intl.md +58 -337
  19. package/blog/en-GB/intlayer_with_react-i18next.md +67 -289
  20. package/blog/en-GB/intlayer_with_react-intl.md +61 -264
  21. package/blog/es/intlayer_with_i18next.md +67 -103
  22. package/blog/es/intlayer_with_next-i18next.md +71 -296
  23. package/blog/es/intlayer_with_next-intl.md +57 -338
  24. package/blog/es/intlayer_with_react-i18next.md +68 -290
  25. package/blog/es/intlayer_with_react-intl.md +62 -265
  26. package/blog/fr/intlayer_with_i18next.md +66 -104
  27. package/blog/fr/intlayer_with_next-i18next.md +82 -285
  28. package/blog/fr/intlayer_with_next-intl.md +57 -338
  29. package/blog/fr/intlayer_with_react-i18next.md +67 -289
  30. package/blog/fr/intlayer_with_react-intl.md +61 -264
  31. package/blog/hi/intlayer_with_i18next.md +68 -104
  32. package/blog/hi/intlayer_with_next-i18next.md +74 -299
  33. package/blog/hi/intlayer_with_next-intl.md +57 -239
  34. package/blog/hi/intlayer_with_react-i18next.md +69 -291
  35. package/blog/hi/intlayer_with_react-intl.md +65 -268
  36. package/blog/id/intlayer_with_i18next.md +126 -0
  37. package/blog/id/intlayer_with_next-i18next.md +142 -0
  38. package/blog/id/intlayer_with_next-intl.md +113 -0
  39. package/blog/id/intlayer_with_react-i18next.md +124 -0
  40. package/blog/id/intlayer_with_react-intl.md +122 -0
  41. package/blog/it/intlayer_with_i18next.md +67 -103
  42. package/blog/it/intlayer_with_next-i18next.md +71 -296
  43. package/blog/it/intlayer_with_next-intl.md +57 -338
  44. package/blog/it/intlayer_with_react-i18next.md +68 -290
  45. package/blog/it/intlayer_with_react-intl.md +62 -265
  46. package/blog/ja/intlayer_with_i18next.md +68 -103
  47. package/blog/ja/intlayer_with_next-i18next.md +85 -283
  48. package/blog/ja/intlayer_with_next-intl.md +58 -336
  49. package/blog/ja/intlayer_with_react-i18next.md +68 -290
  50. package/blog/ja/intlayer_with_react-intl.md +62 -264
  51. package/blog/ko/intlayer_with_i18next.md +80 -96
  52. package/blog/ko/intlayer_with_next-i18next.md +85 -287
  53. package/blog/ko/intlayer_with_next-intl.md +68 -327
  54. package/blog/ko/intlayer_with_react-i18next.md +68 -290
  55. package/blog/ko/intlayer_with_react-intl.md +64 -266
  56. package/blog/pl/intlayer_with_i18next.md +126 -0
  57. package/blog/pl/intlayer_with_next-i18next.md +142 -0
  58. package/blog/pl/intlayer_with_next-intl.md +111 -0
  59. package/blog/pl/intlayer_with_react-i18next.md +124 -0
  60. package/blog/pl/intlayer_with_react-intl.md +122 -0
  61. package/blog/pt/intlayer_with_i18next.md +67 -103
  62. package/blog/pt/intlayer_with_next-i18next.md +72 -293
  63. package/blog/pt/intlayer_with_next-intl.md +57 -256
  64. package/blog/pt/intlayer_with_react-i18next.md +104 -78
  65. package/blog/pt/intlayer_with_react-intl.md +62 -266
  66. package/blog/ru/intlayer_with_i18next.md +66 -104
  67. package/blog/ru/intlayer_with_next-i18next.md +71 -296
  68. package/blog/ru/intlayer_with_next-intl.md +58 -337
  69. package/blog/ru/intlayer_with_react-i18next.md +68 -290
  70. package/blog/ru/intlayer_with_react-intl.md +62 -265
  71. package/blog/tr/intlayer_with_i18next.md +71 -107
  72. package/blog/tr/intlayer_with_next-i18next.md +72 -297
  73. package/blog/tr/intlayer_with_next-intl.md +58 -339
  74. package/blog/tr/intlayer_with_react-i18next.md +69 -291
  75. package/blog/tr/intlayer_with_react-intl.md +63 -285
  76. package/blog/vi/intlayer_with_i18next.md +126 -0
  77. package/blog/vi/intlayer_with_next-i18next.md +142 -0
  78. package/blog/vi/intlayer_with_next-intl.md +111 -0
  79. package/blog/vi/intlayer_with_react-i18next.md +124 -0
  80. package/blog/vi/intlayer_with_react-intl.md +122 -0
  81. package/blog/zh/intlayer_with_i18next.md +67 -102
  82. package/blog/zh/intlayer_with_next-i18next.md +72 -296
  83. package/blog/zh/intlayer_with_next-intl.md +58 -336
  84. package/blog/zh/intlayer_with_react-i18next.md +68 -290
  85. package/blog/zh/intlayer_with_react-intl.md +63 -106
  86. package/docs/ar/plugins/sync-json.md +244 -0
  87. package/docs/de/plugins/sync-json.md +244 -0
  88. package/docs/en/intlayer_cli.md +25 -0
  89. package/docs/en/intlayer_with_nextjs_14.md +2 -0
  90. package/docs/en/intlayer_with_nextjs_15.md +2 -0
  91. package/docs/en/intlayer_with_nextjs_16.md +2 -0
  92. package/docs/en/plugins/sync-json.md +1 -1
  93. package/docs/en-GB/plugins/sync-json.md +244 -0
  94. package/docs/es/plugins/sync-json.md +244 -0
  95. package/docs/fr/plugins/sync-json.md +244 -0
  96. package/docs/hi/plugins/sync-json.md +244 -0
  97. package/docs/id/plugins/sync-json.md +244 -0
  98. package/docs/it/plugins/sync-json.md +244 -0
  99. package/docs/ja/plugins/sync-json.md +244 -0
  100. package/docs/ko/plugins/sync-json.md +244 -0
  101. package/docs/pl/plugins/sync-json.md +244 -0
  102. package/docs/pt/plugins/sync-json.md +244 -0
  103. package/docs/ru/plugins/sync-json.md +244 -0
  104. package/docs/tr/plugins/sync-json.md +245 -0
  105. package/docs/vi/plugins/sync-json.md +244 -0
  106. package/docs/zh/plugins/sync-json.md +244 -0
  107. package/package.json +14 -14
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  createdAt: 2024-12-24
3
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.
4
+ title: How to automate your i18next JSON translations using Intlayer
5
+ description: Automate your JSON translations with Intlayer and i18next for enhanced internationalization in JavaScript applications.
6
6
  keywords:
7
7
  - Intlayer
8
8
  - i18next
@@ -22,342 +22,63 @@ slugs:
22
22
  history:
23
23
  - version: 7.0.0
24
24
  date: 2025-10-29
25
- changes: Complete rewrite with step-by-step guide and code examples
25
+ changes: Change to syncJSON plugin
26
26
  ---
27
27
 
28
- # Migrate from i18next to Intlayer: Complete Integration Guide
29
-
30
- ## Table of Contents
31
-
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.
28
+ # How to automate your i18next JSON translations using Intlayer
37
29
 
38
30
  ## What is Intlayer?
39
31
 
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.
41
-
42
- ## Intlayer vs. i18next: Key Differences
43
-
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
- ```
85
-
86
- **Advantages:**
87
-
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
91
-
92
- ### 2. Configuration Complexity
93
-
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:**
32
+ **Intlayer** is an innovative, open-source internationalization library designed to address the shortcomings of traditional i18n solutions. It offers a modern approach to content management in JavaScript applications.
216
33
 
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
34
+ See a concrete comparison with i18next in our [next-i18next vs. next-intl vs. Intlayer](https://github.com/aymericzip/intlayer/blob/main/docs/blog/en/next-i18next_vs_next-intl_vs_intlayer.md) blog post.
221
35
 
222
- **Intlayer:**
36
+ ## Why Combine Intlayer with i18next?
223
37
 
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
38
+ While Intlayer provides an excellent standalone i18n solution (see our [Next.js integration guide](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_with_nextjs_16.md)), you might want to combine it with i18next for several reasons:
228
39
 
229
- ## When to Use i18next vs. Intlayer
40
+ 1. **Existing codebase**: You have an established i18next implementation and want to gradually migrate to Intlayer's improved developer experience.
41
+ 2. **Legacy requirements**: Your project requires compatibility with existing i18next plugins or workflows.
42
+ 3. **Team familiarity**: Your team is comfortable with i18next but wants better content management.
230
43
 
231
- ### Use i18next if:
44
+ **For that, Intlayer can be implemented as an adapter for i18next to help automating your JSON translations in CLI or CI/CD pipelines, testing your translations, and more.**
232
45
 
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
46
+ This guide shows you how to leverage Intlayer's superior content declaration system while maintaining compatibility with i18next.
237
47
 
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
- ---
48
+ ## Table of Contents
254
49
 
255
- ## Step-by-Step Guide: Using Intlayer with i18next
50
+ <TOC/>
256
51
 
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.
52
+ ## Step-by-Step Guide to Set Up Intlayer with i18next
258
53
 
259
54
  ### Step 1: Install Dependencies
260
55
 
261
- Install the necessary packages for Intlayer:
56
+ Install the necessary packages:
262
57
 
263
58
  ```bash packageManager="npm"
264
- npm install intlayer next-intlayer
59
+ npm install intlayer @intlayer/sync-json-plugin
265
60
  ```
266
61
 
267
62
  ```bash packageManager="pnpm"
268
- pnpm add intlayer next-intlayer
63
+ pnpm add intlayer @intlayer/sync-json-plugin
269
64
  ```
270
65
 
271
66
  ```bash packageManager="yarn"
272
- yarn add intlayer next-intlayer
273
- ```
274
-
275
- If you plan to use i18next alongside Intlayer (for migration or compatibility):
276
-
277
- ```bash packageManager="npm"
278
- npm install i18next react-i18next i18next-resources-to-backend @intlayer/sync-json-plugin
279
- ```
280
-
281
- ```bash packageManager="pnpm"
282
- pnpm add i18next react-i18next i18next-resources-to-backend @intlayer/sync-json-plugin
67
+ yarn add intlayer @intlayer/sync-json-plugin
283
68
  ```
284
69
 
285
- ```bash packageManager="yarn"
286
- yarn add i18next react-i18next i18next-resources-to-backend @intlayer/sync-json-plugin
287
- ```
70
+ **Package descriptions:**
288
71
 
289
- **What each package does:**
72
+ - **intlayer**: Core library for internationalization management, content declaration, and building
73
+ - **@intlayer/sync-json-plugin**: Plugin to export Intlayer content declarations to i18next compatible JSON format
290
74
 
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.
297
-
298
- ### Step 2: Configure Your Project
75
+ ### Step 2: Implement the Intlayer plugin to wrap the JSON
299
76
 
300
77
  Create an Intlayer configuration file to define your supported locales:
301
78
 
302
- ```typescript fileName="intlayer.config.ts" codeFormat="typescript"
303
- import { Locales, type IntlayerConfig } from "intlayer";
304
-
305
- const config: IntlayerConfig = {
306
- internationalization: {
307
- locales: [
308
- Locales.ENGLISH,
309
- Locales.FRENCH,
310
- Locales.SPANISH,
311
- // Add your other locales
312
- ],
313
- defaultLocale: Locales.ENGLISH,
314
- },
315
- };
316
-
317
- export default config;
318
- ```
319
-
320
- ```javascript fileName="intlayer.config.mjs" codeFormat="esm"
321
- import { Locales } from "intlayer";
322
-
323
- /** @type {import('intlayer').IntlayerConfig} */
324
- const config = {
325
- internationalization: {
326
- locales: [
327
- Locales.ENGLISH,
328
- Locales.FRENCH,
329
- Locales.SPANISH,
330
- // Add your other locales
331
- ],
332
- defaultLocale: Locales.ENGLISH,
333
- },
334
- };
335
-
336
- export default config;
337
- ```
338
-
339
- ```javascript fileName="intlayer.config.cjs" codeFormat="commonjs"
340
- const { Locales } = require("intlayer");
341
-
342
- /** @type {import('intlayer').IntlayerConfig} */
343
- const config = {
344
- internationalization: {
345
- locales: [
346
- Locales.ENGLISH,
347
- Locales.FRENCH,
348
- Locales.SPANISH,
349
- // Add your other locales
350
- ],
351
- defaultLocale: Locales.ENGLISH,
352
- },
353
- };
354
-
355
- module.exports = config;
356
- ```
357
-
358
79
  **If you want to also export JSON dictionaries for i18next**, add the `syncJSON` plugin:
359
80
 
360
- ```typescript fileName="intlayer.config.ts" codeFormat="typescript"
81
+ ```typescript fileName="intlayer.config.ts"
361
82
  import { Locales, type IntlayerConfig } from "intlayer";
362
83
  import { syncJSON } from "@intlayer/sync-json-plugin";
363
84
 
@@ -376,1353 +97,30 @@ const config: IntlayerConfig = {
376
97
  export default config;
377
98
  ```
378
99
 
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;
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[]);
100
+ The `syncJSON` plugin will automatically wrap the JSON. It will read and write the JSON files without changing the content architecture.
1303
101
 
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
- });
102
+ If you want to make coexist that JSON with intlayer content declaration files (`.content` files), Intlayer will proceed this way:
1313
103
 
1314
- export default robots;
1315
- ```
104
+ 1. load both JSON and content declaration files and transform them into a intlayer dictionary.
105
+ 2. if there is conflicts between the JSON and the content declaration files, Intlayer will process to the merge of that all dictionaries. Depending of the priority of the plugins, and the one of the content declaration file (all are configurable).
1316
106
 
1317
- ```jsx fileName="src/app/robots.mjx" codeFormat="esm"
1318
- import { getMultilingualUrls } from "intlayer";
107
+ If changes are made using the CLI to translate the JSON, or using the CMS, Intlayer will update the JSON file with the new translations.
1319
108
 
1320
- const getAllMultilingualUrls = (urls) =>
1321
- urls.flatMap((url) => Object.values(getMultilingualUrls(url)));
109
+ To see more details about the `syncJSON` plugin, please refer to the [syncJSON plugin documentation](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/plugins/sync-json.md).
1322
110
 
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
- ```
111
+ ## Git Configuration
1503
112
 
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"
1518
- import i18next from "i18next";
1519
- import { initReactI18next } from "react-i18next";
1520
- import resourcesToBackend from "i18next-resources-to-backend";
1521
-
1522
- i18next
1523
- .use(initReactI18next)
1524
- .use(
1525
- resourcesToBackend(
1526
- (language: string, namespace: string) =>
1527
- import(`../intl/messages/${language}/${namespace}.json`)
1528
- )
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;
1539
- ```
1540
-
1541
- ```javascript fileName="i18n/client.mjs" codeFormat="esm"
1542
- import i18next from "i18next";
1543
- import { initReactI18next } from "react-i18next";
1544
- import resourcesToBackend from "i18next-resources-to-backend";
1545
-
1546
- i18next
1547
- .use(initReactI18next)
1548
- .use(
1549
- resourcesToBackend(
1550
- (language, namespace) =>
1551
- import(`../intl/messages/${language}/${namespace}.json`)
1552
- )
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;
1563
- ```
1564
-
1565
- ```javascript fileName="i18n/client.cjs" codeFormat="commonjs"
1566
- const i18next = require("i18next");
1567
- const { initReactI18next } = require("react-i18next");
1568
- const resourcesToBackend = require("i18next-resources-to-backend");
1569
-
1570
- i18next
1571
- .use(initReactI18next)
1572
- .use(
1573
- resourcesToBackend(
1574
- (language, namespace) =>
1575
- import(`../intl/messages/${language}/${namespace}.json`)
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>
1604
- );
1605
- };
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:
113
+ It's recommended to ignore auto-generated Intlayer files:
1677
114
 
1678
115
  ```plaintext fileName=".gitignore"
1679
- # Ignore the files generated by Intlayer
116
+ # Ignore files generated by Intlayer
1680
117
  .intlayer
1681
118
  ```
1682
119
 
120
+ These files can be regenerated during your build process and don't need to be committed to version control.
121
+
1683
122
  ### VS Code Extension
1684
123
 
1685
124
  For improved developer experience, install the official **Intlayer VS Code Extension**:
1686
125
 
1687
126
  [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