@intlayer/docs 7.0.4-canary.0 → 7.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/blog/ar/intlayer_with_i18next.md +68 -106
- package/blog/ar/intlayer_with_next-i18next.md +84 -288
- package/blog/ar/intlayer_with_next-intl.md +58 -337
- package/blog/ar/intlayer_with_react-i18next.md +68 -290
- package/blog/ar/intlayer_with_react-intl.md +63 -266
- package/blog/de/intlayer_with_i18next.md +77 -97
- package/blog/de/intlayer_with_next-i18next.md +69 -296
- package/blog/de/intlayer_with_next-intl.md +59 -340
- package/blog/de/intlayer_with_react-i18next.md +68 -290
- package/blog/de/intlayer_with_react-intl.md +62 -264
- package/blog/en/intlayer_with_i18next.md +36 -1638
- package/blog/en/intlayer_with_next-i18next.md +22 -847
- package/blog/en/intlayer_with_next-intl.md +32 -1053
- package/blog/en/intlayer_with_react-i18next.md +38 -764
- package/blog/en/intlayer_with_react-intl.md +42 -1018
- package/blog/en-GB/intlayer_with_i18next.md +67 -103
- package/blog/en-GB/intlayer_with_next-i18next.md +71 -292
- package/blog/en-GB/intlayer_with_next-intl.md +58 -337
- package/blog/en-GB/intlayer_with_react-i18next.md +67 -289
- package/blog/en-GB/intlayer_with_react-intl.md +61 -264
- package/blog/es/intlayer_with_i18next.md +67 -103
- package/blog/es/intlayer_with_next-i18next.md +71 -296
- package/blog/es/intlayer_with_next-intl.md +57 -338
- package/blog/es/intlayer_with_react-i18next.md +68 -290
- package/blog/es/intlayer_with_react-intl.md +62 -265
- package/blog/fr/intlayer_with_i18next.md +66 -104
- package/blog/fr/intlayer_with_next-i18next.md +82 -285
- package/blog/fr/intlayer_with_next-intl.md +57 -338
- package/blog/fr/intlayer_with_react-i18next.md +67 -289
- package/blog/fr/intlayer_with_react-intl.md +61 -264
- package/blog/hi/intlayer_with_i18next.md +68 -104
- package/blog/hi/intlayer_with_next-i18next.md +74 -299
- package/blog/hi/intlayer_with_next-intl.md +57 -239
- package/blog/hi/intlayer_with_react-i18next.md +69 -291
- package/blog/hi/intlayer_with_react-intl.md +65 -268
- package/blog/id/intlayer_with_i18next.md +126 -0
- package/blog/id/intlayer_with_next-i18next.md +142 -0
- package/blog/id/intlayer_with_next-intl.md +113 -0
- package/blog/id/intlayer_with_react-i18next.md +124 -0
- package/blog/id/intlayer_with_react-intl.md +122 -0
- package/blog/it/intlayer_with_i18next.md +67 -103
- package/blog/it/intlayer_with_next-i18next.md +71 -296
- package/blog/it/intlayer_with_next-intl.md +57 -338
- package/blog/it/intlayer_with_react-i18next.md +68 -290
- package/blog/it/intlayer_with_react-intl.md +62 -265
- package/blog/ja/intlayer_with_i18next.md +68 -103
- package/blog/ja/intlayer_with_next-i18next.md +85 -283
- package/blog/ja/intlayer_with_next-intl.md +58 -336
- package/blog/ja/intlayer_with_react-i18next.md +68 -290
- package/blog/ja/intlayer_with_react-intl.md +62 -264
- package/blog/ko/intlayer_with_i18next.md +80 -96
- package/blog/ko/intlayer_with_next-i18next.md +85 -287
- package/blog/ko/intlayer_with_next-intl.md +68 -327
- package/blog/ko/intlayer_with_react-i18next.md +68 -290
- package/blog/ko/intlayer_with_react-intl.md +64 -266
- package/blog/pl/intlayer_with_i18next.md +126 -0
- package/blog/pl/intlayer_with_next-i18next.md +142 -0
- package/blog/pl/intlayer_with_next-intl.md +111 -0
- package/blog/pl/intlayer_with_react-i18next.md +124 -0
- package/blog/pl/intlayer_with_react-intl.md +122 -0
- package/blog/pt/intlayer_with_i18next.md +67 -103
- package/blog/pt/intlayer_with_next-i18next.md +72 -293
- package/blog/pt/intlayer_with_next-intl.md +57 -256
- package/blog/pt/intlayer_with_react-i18next.md +104 -78
- package/blog/pt/intlayer_with_react-intl.md +62 -266
- package/blog/ru/intlayer_with_i18next.md +66 -104
- package/blog/ru/intlayer_with_next-i18next.md +71 -296
- package/blog/ru/intlayer_with_next-intl.md +58 -337
- package/blog/ru/intlayer_with_react-i18next.md +68 -290
- package/blog/ru/intlayer_with_react-intl.md +62 -265
- package/blog/tr/intlayer_with_i18next.md +71 -107
- package/blog/tr/intlayer_with_next-i18next.md +72 -297
- package/blog/tr/intlayer_with_next-intl.md +58 -339
- package/blog/tr/intlayer_with_react-i18next.md +69 -291
- package/blog/tr/intlayer_with_react-intl.md +63 -285
- package/blog/vi/intlayer_with_i18next.md +126 -0
- package/blog/vi/intlayer_with_next-i18next.md +142 -0
- package/blog/vi/intlayer_with_next-intl.md +111 -0
- package/blog/vi/intlayer_with_react-i18next.md +124 -0
- package/blog/vi/intlayer_with_react-intl.md +122 -0
- package/blog/zh/intlayer_with_i18next.md +67 -102
- package/blog/zh/intlayer_with_next-i18next.md +72 -296
- package/blog/zh/intlayer_with_next-intl.md +58 -336
- package/blog/zh/intlayer_with_react-i18next.md +68 -290
- package/blog/zh/intlayer_with_react-intl.md +63 -106
- package/docs/ar/plugins/sync-json.md +244 -0
- package/docs/de/plugins/sync-json.md +244 -0
- package/docs/en/intlayer_cli.md +25 -0
- package/docs/en/intlayer_with_nextjs_14.md +2 -0
- package/docs/en/intlayer_with_nextjs_15.md +2 -0
- package/docs/en/intlayer_with_nextjs_16.md +2 -0
- package/docs/en/plugins/sync-json.md +1 -1
- package/docs/en-GB/plugins/sync-json.md +244 -0
- package/docs/es/plugins/sync-json.md +244 -0
- package/docs/fr/plugins/sync-json.md +244 -0
- package/docs/hi/plugins/sync-json.md +244 -0
- package/docs/id/plugins/sync-json.md +244 -0
- package/docs/it/plugins/sync-json.md +244 -0
- package/docs/ja/plugins/sync-json.md +244 -0
- package/docs/ko/plugins/sync-json.md +244 -0
- package/docs/pl/plugins/sync-json.md +244 -0
- package/docs/pt/plugins/sync-json.md +244 -0
- package/docs/ru/plugins/sync-json.md +244 -0
- package/docs/tr/plugins/sync-json.md +245 -0
- package/docs/vi/plugins/sync-json.md +244 -0
- package/docs/zh/plugins/sync-json.md +244 -0
- package/package.json +14 -14
|
@@ -42,13 +42,7 @@ However, next-i18next comes with some challenges:
|
|
|
42
42
|
|
|
43
43
|
**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 Next.js applications.
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
- **Declarative content management**: Translations are defined alongside components, improving maintainability.
|
|
48
|
-
- **Type-safe by design**: Auto-generated TypeScript types ensure type safety and autocompletion.
|
|
49
|
-
- **Flexible content structure**: Supports complex content structures beyond simple key-value pairs.
|
|
50
|
-
- **Built-in Visual Editor**: Optional visual editing capabilities for non-technical team members.
|
|
51
|
-
- **Framework optimization**: Deep integration with Next.js for optimal performance.
|
|
45
|
+
See a concrete comparison with next-intl 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.
|
|
52
46
|
|
|
53
47
|
## Why Combine Intlayer with next-i18next?
|
|
54
48
|
|
|
@@ -58,21 +52,9 @@ While Intlayer provides an excellent standalone i18n solution (see our [Next.js
|
|
|
58
52
|
2. **Legacy requirements**: Your project requires compatibility with existing i18next plugins or workflows.
|
|
59
53
|
3. **Team familiarity**: Your team is comfortable with next-i18next but wants better content management.
|
|
60
54
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
## Intlayer vs. next-i18next: Key Differences
|
|
64
|
-
|
|
65
|
-
For a detailed comparison of different i18n solutions including next-i18next and Intlayer, check out 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.
|
|
55
|
+
**For that, Intlayer can be implemented as an adapter for next-i18next to help automating your JSON translations in CLI or CI/CD pipelines, testing your translations, and more.**
|
|
66
56
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
| Feature | next-i18next | Intlayer with next-i18next |
|
|
70
|
-
| ----------------- | ---------------------------- | -------------------------- |
|
|
71
|
-
| Content Location | Separate translation folders | Co-located with components |
|
|
72
|
-
| Type Safety | Manual setup required | Auto-generated types |
|
|
73
|
-
| Content Structure | Flat key-value pairs | Nested, structured objects |
|
|
74
|
-
| Visual Editor | Not included | Built-in optional editor |
|
|
75
|
-
| Setup Complexity | Multiple config files | Minimal configuration |
|
|
57
|
+
This guide shows you how to leverage Intlayer's superior content declaration system while maintaining compatibility with next-i18next.
|
|
76
58
|
|
|
77
59
|
---
|
|
78
60
|
|
|
@@ -83,15 +65,15 @@ Key differences:
|
|
|
83
65
|
Install the necessary packages using your preferred package manager:
|
|
84
66
|
|
|
85
67
|
```bash packageManager="npm"
|
|
86
|
-
npm install intlayer
|
|
68
|
+
npm install intlayer @intlayer/sync-json-plugin
|
|
87
69
|
```
|
|
88
70
|
|
|
89
71
|
```bash packageManager="pnpm"
|
|
90
|
-
pnpm add intlayer
|
|
72
|
+
pnpm add intlayer @intlayer/sync-json-plugin
|
|
91
73
|
```
|
|
92
74
|
|
|
93
75
|
```bash packageManager="yarn"
|
|
94
|
-
yarn add intlayer
|
|
76
|
+
yarn add intlayer @intlayer/sync-json-plugin
|
|
95
77
|
```
|
|
96
78
|
|
|
97
79
|
**Package explanations:**
|
|
@@ -103,28 +85,24 @@ yarn add intlayer next-intlayer i18next next-i18next i18next-resources-to-backen
|
|
|
103
85
|
- **i18next-resources-to-backend**: Dynamic resource loading for i18next
|
|
104
86
|
- **@intlayer/sync-json-plugin**: Plugin to sync Intlayer content declarations to i18next JSON format
|
|
105
87
|
|
|
106
|
-
### Step 2:
|
|
88
|
+
### Step 2: Implement the Intlayer plugin to wrap the JSON
|
|
89
|
+
|
|
90
|
+
Create an Intlayer configuration file to define your supported locales:
|
|
107
91
|
|
|
108
|
-
|
|
92
|
+
**If you want to also export JSON dictionaries for i18next**, add the `syncJSON` plugin:
|
|
109
93
|
|
|
110
|
-
```typescript fileName="intlayer.config.ts"
|
|
94
|
+
```typescript fileName="intlayer.config.ts"
|
|
111
95
|
import { Locales, type IntlayerConfig } from "intlayer";
|
|
112
96
|
import { syncJSON } from "@intlayer/sync-json-plugin";
|
|
113
97
|
|
|
114
98
|
const config: IntlayerConfig = {
|
|
115
99
|
internationalization: {
|
|
116
|
-
locales: [
|
|
117
|
-
Locales.ENGLISH,
|
|
118
|
-
Locales.FRENCH,
|
|
119
|
-
Locales.SPANISH,
|
|
120
|
-
// Add your other locales
|
|
121
|
-
],
|
|
100
|
+
locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
|
|
122
101
|
defaultLocale: Locales.ENGLISH,
|
|
123
102
|
},
|
|
124
103
|
plugins: [
|
|
125
104
|
syncJSON({
|
|
126
|
-
|
|
127
|
-
source: ({ key, locale }) => `./intl/messages/${locale}/${key}.json`,
|
|
105
|
+
source: ({ key, locale }) => `./messages/${locale}/${key}.json`,
|
|
128
106
|
}),
|
|
129
107
|
],
|
|
130
108
|
};
|
|
@@ -132,775 +110,16 @@ const config: IntlayerConfig = {
|
|
|
132
110
|
export default config;
|
|
133
111
|
```
|
|
134
112
|
|
|
135
|
-
|
|
136
|
-
import { Locales } from "intlayer";
|
|
137
|
-
import { syncJSON } from "@intlayer/sync-json-plugin";
|
|
113
|
+
The `syncJSON` plugin will automatically wrap the JSON. It will read and write the JSON files without changing the content architecture.
|
|
138
114
|
|
|
139
|
-
|
|
140
|
-
const config = {
|
|
141
|
-
internationalization: {
|
|
142
|
-
locales: [
|
|
143
|
-
Locales.ENGLISH,
|
|
144
|
-
Locales.FRENCH,
|
|
145
|
-
Locales.SPANISH,
|
|
146
|
-
// Add your other locales
|
|
147
|
-
],
|
|
148
|
-
defaultLocale: Locales.ENGLISH,
|
|
149
|
-
},
|
|
150
|
-
plugins: [
|
|
151
|
-
syncJSON({
|
|
152
|
-
source: ({ key, locale }) => `./intl/messages/${locale}/${key}.json`,
|
|
153
|
-
}),
|
|
154
|
-
],
|
|
155
|
-
};
|
|
115
|
+
If you want to make coexist that JSON with intlayer content declaration files (`.content` files), Intlayer will proceed this way:
|
|
156
116
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
```javascript fileName="intlayer.config.cjs" codeFormat="commonjs"
|
|
161
|
-
const { Locales } = require("intlayer");
|
|
162
|
-
const { syncJSON } = require("@intlayer/sync-json-plugin");
|
|
163
|
-
|
|
164
|
-
/** @type {import('intlayer').IntlayerConfig} */
|
|
165
|
-
const config = {
|
|
166
|
-
internationalization: {
|
|
167
|
-
locales: [
|
|
168
|
-
Locales.ENGLISH,
|
|
169
|
-
Locales.FRENCH,
|
|
170
|
-
Locales.SPANISH,
|
|
171
|
-
// Add your other locales
|
|
172
|
-
],
|
|
173
|
-
defaultLocale: Locales.ENGLISH,
|
|
174
|
-
},
|
|
175
|
-
plugins: [
|
|
176
|
-
syncJSON({
|
|
177
|
-
source: ({ key, locale }) => `./intl/messages/${locale}/${key}.json`,
|
|
178
|
-
}),
|
|
179
|
-
],
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
module.exports = config;
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
> The `syncJSON` plugin automatically converts Intlayer content declarations to i18next-compatible JSON files. For more configuration options, refer to the [configuration documentation](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/configuration.md).
|
|
186
|
-
|
|
187
|
-
### Step 3: Integrate Intlayer in Your Next.js Configuration
|
|
188
|
-
|
|
189
|
-
Configure your Next.js setup to use Intlayer's build plugin:
|
|
190
|
-
|
|
191
|
-
```typescript fileName="next.config.ts" codeFormat="typescript"
|
|
192
|
-
import type { NextConfig } from "next";
|
|
193
|
-
import { withIntlayer } from "next-intlayer/server";
|
|
194
|
-
|
|
195
|
-
const nextConfig: NextConfig = {
|
|
196
|
-
/* your Next.js config options */
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
export default withIntlayer(nextConfig);
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
```javascript fileName="next.config.mjs" codeFormat="esm"
|
|
203
|
-
import { withIntlayer } from "next-intlayer/server";
|
|
204
|
-
|
|
205
|
-
/** @type {import('next').NextConfig} */
|
|
206
|
-
const nextConfig = {
|
|
207
|
-
/* your Next.js config options */
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
export default withIntlayer(nextConfig);
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
```javascript fileName="next.config.cjs" codeFormat="commonjs"
|
|
214
|
-
const { withIntlayer } = require("next-intlayer/server");
|
|
215
|
-
|
|
216
|
-
/** @type {import('next').NextConfig} */
|
|
217
|
-
const nextConfig = {
|
|
218
|
-
/* your Next.js config options */
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
module.exports = withIntlayer(nextConfig);
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
> The `withIntlayer()` plugin ensures that Intlayer content declarations are built and monitored during development. It automatically regenerates i18next JSON files when you modify content declarations.
|
|
225
|
-
|
|
226
|
-
### Step 4: Set Up next-i18next Configuration
|
|
227
|
-
|
|
228
|
-
Create the standard next-i18next configuration file:
|
|
229
|
-
|
|
230
|
-
```javascript fileName="next-i18next.config.js"
|
|
231
|
-
module.exports = {
|
|
232
|
-
i18n: {
|
|
233
|
-
defaultLocale: "en",
|
|
234
|
-
locales: ["en", "fr", "es"],
|
|
235
|
-
},
|
|
236
|
-
};
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
Update your Next.js config to use next-i18next:
|
|
240
|
-
|
|
241
|
-
```typescript fileName="next.config.ts" codeFormat="typescript"
|
|
242
|
-
import type { NextConfig } from "next";
|
|
243
|
-
import { withIntlayer } from "next-intlayer/server";
|
|
244
|
-
|
|
245
|
-
const nextConfig: NextConfig = {
|
|
246
|
-
/* your Next.js config options */
|
|
247
|
-
i18n: {
|
|
248
|
-
defaultLocale: "en",
|
|
249
|
-
locales: ["en", "fr", "es"],
|
|
250
|
-
},
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
export default withIntlayer(nextConfig);
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
```javascript fileName="next.config.mjs" codeFormat="esm"
|
|
257
|
-
import { withIntlayer } from "next-intlayer/server";
|
|
258
|
-
|
|
259
|
-
/** @type {import('next').NextConfig} */
|
|
260
|
-
const nextConfig = {
|
|
261
|
-
/* your Next.js config options */
|
|
262
|
-
i18n: {
|
|
263
|
-
defaultLocale: "en",
|
|
264
|
-
locales: ["en", "fr", "es"],
|
|
265
|
-
},
|
|
266
|
-
};
|
|
267
|
-
|
|
268
|
-
export default withIntlayer(nextConfig);
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
```javascript fileName="next.config.cjs" codeFormat="commonjs"
|
|
272
|
-
const { withIntlayer } = require("next-intlayer/server");
|
|
273
|
-
|
|
274
|
-
/** @type {import('next').NextConfig} */
|
|
275
|
-
const nextConfig = {
|
|
276
|
-
/* your Next.js config options */
|
|
277
|
-
i18n: {
|
|
278
|
-
defaultLocale: "en",
|
|
279
|
-
locales: ["en", "fr", "es"],
|
|
280
|
-
},
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
module.exports = withIntlayer(nextConfig);
|
|
284
|
-
```
|
|
285
|
-
|
|
286
|
-
### Step 5: Set Up i18next Client Configuration
|
|
287
|
-
|
|
288
|
-
Create an i18next configuration file to load the generated resources:
|
|
289
|
-
|
|
290
|
-
```typescript fileName="i18n/client.ts" codeFormat="typescript"
|
|
291
|
-
import i18next from "i18next";
|
|
292
|
-
import { initReactI18next } from "react-i18next";
|
|
293
|
-
import resourcesToBackend from "i18next-resources-to-backend";
|
|
294
|
-
|
|
295
|
-
i18next
|
|
296
|
-
.use(initReactI18next)
|
|
297
|
-
.use(
|
|
298
|
-
resourcesToBackend(
|
|
299
|
-
(language: string, namespace: string) =>
|
|
300
|
-
import(`../intl/messages/${language}/${namespace}.json`)
|
|
301
|
-
)
|
|
302
|
-
)
|
|
303
|
-
.init({
|
|
304
|
-
fallbackLng: "en",
|
|
305
|
-
// Add other i18next configuration options as needed
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
export default i18next;
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
```javascript fileName="i18n/client.mjs" codeFormat="esm"
|
|
312
|
-
import i18next from "i18next";
|
|
313
|
-
import { initReactI18next } from "react-i18next";
|
|
314
|
-
import resourcesToBackend from "i18next-resources-to-backend";
|
|
315
|
-
|
|
316
|
-
i18next
|
|
317
|
-
.use(initReactI18next)
|
|
318
|
-
.use(
|
|
319
|
-
resourcesToBackend(
|
|
320
|
-
(language, namespace) =>
|
|
321
|
-
import(`../intl/messages/${language}/${namespace}.json`)
|
|
322
|
-
)
|
|
323
|
-
)
|
|
324
|
-
.init({
|
|
325
|
-
fallbackLng: "en",
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
export default i18next;
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
```javascript fileName="i18n/client.cjs" codeFormat="commonjs"
|
|
332
|
-
const i18next = require("i18next");
|
|
333
|
-
const { initReactI18next } = require("react-i18next");
|
|
334
|
-
const resourcesToBackend = require("i18next-resources-to-backend");
|
|
335
|
-
|
|
336
|
-
i18next
|
|
337
|
-
.use(initReactI18next)
|
|
338
|
-
.use(
|
|
339
|
-
resourcesToBackend(
|
|
340
|
-
(language, namespace) =>
|
|
341
|
-
import(`../intl/messages/${language}/${namespace}.json`)
|
|
342
|
-
)
|
|
343
|
-
)
|
|
344
|
-
.init({
|
|
345
|
-
fallbackLng: "en",
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
module.exports = i18next;
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
### Step 6: Declare Your Content
|
|
352
|
-
|
|
353
|
-
Create content declaration files alongside your components:
|
|
354
|
-
|
|
355
|
-
```typescript fileName="src/components/Hero/Hero.content.ts" contentDeclarationFormat="typescript"
|
|
356
|
-
import { t, type Dictionary } from "intlayer";
|
|
357
|
-
|
|
358
|
-
const heroContent = {
|
|
359
|
-
key: "hero",
|
|
360
|
-
content: {
|
|
361
|
-
title: t({
|
|
362
|
-
en: "Welcome to Our Platform",
|
|
363
|
-
fr: "Bienvenue sur notre plateforme",
|
|
364
|
-
es: "Bienvenido a nuestra plataforma",
|
|
365
|
-
}),
|
|
366
|
-
description: t({
|
|
367
|
-
en: "Discover amazing features and possibilities",
|
|
368
|
-
fr: "Découvrez des fonctionnalités et possibilités incroyables",
|
|
369
|
-
es: "Descubre características y posibilidades increíbles",
|
|
370
|
-
}),
|
|
371
|
-
cta: {
|
|
372
|
-
primary: t({
|
|
373
|
-
en: "Get Started",
|
|
374
|
-
fr: "Commencer",
|
|
375
|
-
es: "Empezar",
|
|
376
|
-
}),
|
|
377
|
-
secondary: t({
|
|
378
|
-
en: "Learn More",
|
|
379
|
-
fr: "En savoir plus",
|
|
380
|
-
es: "Saber más",
|
|
381
|
-
}),
|
|
382
|
-
},
|
|
383
|
-
},
|
|
384
|
-
} satisfies Dictionary;
|
|
385
|
-
|
|
386
|
-
export default heroContent;
|
|
387
|
-
```
|
|
388
|
-
|
|
389
|
-
```javascript fileName="src/components/Hero/Hero.content.mjs" contentDeclarationFormat="esm"
|
|
390
|
-
import { t } from "intlayer";
|
|
391
|
-
|
|
392
|
-
/** @type {import('intlayer').Dictionary} */
|
|
393
|
-
const heroContent = {
|
|
394
|
-
key: "hero",
|
|
395
|
-
content: {
|
|
396
|
-
title: t({
|
|
397
|
-
en: "Welcome to Our Platform",
|
|
398
|
-
fr: "Bienvenue sur notre plateforme",
|
|
399
|
-
es: "Bienvenido a nuestra plataforma",
|
|
400
|
-
}),
|
|
401
|
-
description: t({
|
|
402
|
-
en: "Discover amazing features and possibilities",
|
|
403
|
-
fr: "Découvrez des fonctionnalités et possibilités incroyables",
|
|
404
|
-
es: "Descubre características y posibilidades increíbles",
|
|
405
|
-
}),
|
|
406
|
-
cta: {
|
|
407
|
-
primary: t({
|
|
408
|
-
en: "Get Started",
|
|
409
|
-
fr: "Commencer",
|
|
410
|
-
es: "Empezar",
|
|
411
|
-
}),
|
|
412
|
-
secondary: t({
|
|
413
|
-
en: "Learn More",
|
|
414
|
-
fr: "En savoir plus",
|
|
415
|
-
es: "Saber más",
|
|
416
|
-
}),
|
|
417
|
-
},
|
|
418
|
-
},
|
|
419
|
-
};
|
|
420
|
-
|
|
421
|
-
export default heroContent;
|
|
422
|
-
```
|
|
423
|
-
|
|
424
|
-
```javascript fileName="src/components/Hero/Hero.content.cjs" contentDeclarationFormat="commonjs"
|
|
425
|
-
const { t } = require("intlayer");
|
|
426
|
-
|
|
427
|
-
/** @type {import('intlayer').Dictionary} */
|
|
428
|
-
const heroContent = {
|
|
429
|
-
key: "hero",
|
|
430
|
-
content: {
|
|
431
|
-
title: t({
|
|
432
|
-
en: "Welcome to Our Platform",
|
|
433
|
-
fr: "Bienvenue sur notre plateforme",
|
|
434
|
-
es: "Bienvenido a nuestra plataforma",
|
|
435
|
-
}),
|
|
436
|
-
description: t({
|
|
437
|
-
en: "Discover amazing features and possibilities",
|
|
438
|
-
fr: "Découvrez des fonctionnalités et possibilités incroyables",
|
|
439
|
-
es: "Descubre características y posibilidades increíbles",
|
|
440
|
-
}),
|
|
441
|
-
cta: {
|
|
442
|
-
primary: t({
|
|
443
|
-
en: "Get Started",
|
|
444
|
-
fr: "Commencer",
|
|
445
|
-
es: "Empezar",
|
|
446
|
-
}),
|
|
447
|
-
secondary: t({
|
|
448
|
-
en: "Learn More",
|
|
449
|
-
fr: "En savoir plus",
|
|
450
|
-
es: "Saber más",
|
|
451
|
-
}),
|
|
452
|
-
},
|
|
453
|
-
},
|
|
454
|
-
};
|
|
455
|
-
|
|
456
|
-
module.exports = heroContent;
|
|
457
|
-
```
|
|
458
|
-
|
|
459
|
-
```json fileName="src/components/Hero/Hero.content.json" contentDeclarationFormat="json"
|
|
460
|
-
{
|
|
461
|
-
"$schema": "https://intlayer.org/schema.json",
|
|
462
|
-
"key": "hero",
|
|
463
|
-
"content": {
|
|
464
|
-
"title": {
|
|
465
|
-
"nodeType": "translation",
|
|
466
|
-
"translation": {
|
|
467
|
-
"en": "Welcome to Our Platform",
|
|
468
|
-
"fr": "Bienvenue sur notre plateforme",
|
|
469
|
-
"es": "Bienvenido a nuestra plataforma"
|
|
470
|
-
}
|
|
471
|
-
},
|
|
472
|
-
"description": {
|
|
473
|
-
"nodeType": "translation",
|
|
474
|
-
"translation": {
|
|
475
|
-
"en": "Discover amazing features and possibilities",
|
|
476
|
-
"fr": "Découvrez des fonctionnalités et possibilités incroyables",
|
|
477
|
-
"es": "Descubre características y posibilidades increíbles"
|
|
478
|
-
}
|
|
479
|
-
},
|
|
480
|
-
"cta": {
|
|
481
|
-
"primary": {
|
|
482
|
-
"nodeType": "translation",
|
|
483
|
-
"translation": {
|
|
484
|
-
"en": "Get Started",
|
|
485
|
-
"fr": "Commencer",
|
|
486
|
-
"es": "Empezar"
|
|
487
|
-
}
|
|
488
|
-
},
|
|
489
|
-
"secondary": {
|
|
490
|
-
"nodeType": "translation",
|
|
491
|
-
"translation": {
|
|
492
|
-
"en": "Learn More",
|
|
493
|
-
"fr": "En savoir plus",
|
|
494
|
-
"es": "Saber más"
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
```
|
|
117
|
+
1. load both JSON and content declaration files and transform them into a intlayer dictionary.
|
|
118
|
+
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).
|
|
501
119
|
|
|
502
|
-
|
|
120
|
+
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.
|
|
503
121
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
Generate the i18next JSON files from your Intlayer content declarations:
|
|
507
|
-
|
|
508
|
-
```bash packageManager="npm"
|
|
509
|
-
npx intlayer build
|
|
510
|
-
```
|
|
511
|
-
|
|
512
|
-
```bash packageManager="yarn"
|
|
513
|
-
yarn intlayer build
|
|
514
|
-
```
|
|
515
|
-
|
|
516
|
-
```bash packageManager="pnpm"
|
|
517
|
-
pnpm intlayer build
|
|
518
|
-
```
|
|
519
|
-
|
|
520
|
-
This will generate files in the `./intl/messages` directory:
|
|
521
|
-
|
|
522
|
-
```bash
|
|
523
|
-
intl
|
|
524
|
-
└── messages
|
|
525
|
-
├── en
|
|
526
|
-
│ └── hero.json
|
|
527
|
-
├── fr
|
|
528
|
-
│ └── hero.json
|
|
529
|
-
└── es
|
|
530
|
-
└── hero.json
|
|
531
|
-
```
|
|
532
|
-
|
|
533
|
-
Each JSON file contains translations extracted from the corresponding Intlayer content declarations.
|
|
534
|
-
|
|
535
|
-
### Step 8: Utilize Content in Your Code
|
|
536
|
-
|
|
537
|
-
Access your translations using next-i18next's hooks:
|
|
538
|
-
|
|
539
|
-
```typescript fileName="src/components/Hero/Hero.tsx" codeFormat="typescript"
|
|
540
|
-
import type { FC } from "react";
|
|
541
|
-
import { useTranslation } from "next-i18next";
|
|
542
|
-
|
|
543
|
-
const Hero: FC = () => {
|
|
544
|
-
const { t } = useTranslation("hero");
|
|
545
|
-
|
|
546
|
-
return (
|
|
547
|
-
<section>
|
|
548
|
-
<h1>{t("title")}</h1>
|
|
549
|
-
<p>{t("description")}</p>
|
|
550
|
-
<div>
|
|
551
|
-
<button>{t("cta.primary")}</button>
|
|
552
|
-
<button>{t("cta.secondary")}</button>
|
|
553
|
-
</div>
|
|
554
|
-
</section>
|
|
555
|
-
);
|
|
556
|
-
};
|
|
557
|
-
|
|
558
|
-
export default Hero;
|
|
559
|
-
```
|
|
560
|
-
|
|
561
|
-
```jsx fileName="src/components/Hero/Hero.mjx" codeFormat="esm"
|
|
562
|
-
import { useTranslation } from "next-i18next";
|
|
563
|
-
|
|
564
|
-
const Hero = () => {
|
|
565
|
-
const { t } = useTranslation("hero");
|
|
566
|
-
|
|
567
|
-
return (
|
|
568
|
-
<section>
|
|
569
|
-
<h1>{t("title")}</h1>
|
|
570
|
-
<p>{t("description")}</p>
|
|
571
|
-
<div>
|
|
572
|
-
<button>{t("cta.primary")}</button>
|
|
573
|
-
<button>{t("cta.secondary")}</button>
|
|
574
|
-
</div>
|
|
575
|
-
</section>
|
|
576
|
-
);
|
|
577
|
-
};
|
|
578
|
-
|
|
579
|
-
export default Hero;
|
|
580
|
-
```
|
|
581
|
-
|
|
582
|
-
```jsx fileName="src/components/Hero/Hero.csx" codeFormat="commonjs"
|
|
583
|
-
const { useTranslation } = require("next-i18next");
|
|
584
|
-
|
|
585
|
-
const Hero = () => {
|
|
586
|
-
const { t } = useTranslation("hero");
|
|
587
|
-
|
|
588
|
-
return (
|
|
589
|
-
<section>
|
|
590
|
-
<h1>{t("title")}</h1>
|
|
591
|
-
<p>{t("description")}</p>
|
|
592
|
-
<div>
|
|
593
|
-
<button>{t("cta.primary")}</button>
|
|
594
|
-
<button>{t("cta.secondary")}</button>
|
|
595
|
-
</div>
|
|
596
|
-
</section>
|
|
597
|
-
);
|
|
598
|
-
};
|
|
599
|
-
|
|
600
|
-
module.exports = Hero;
|
|
601
|
-
```
|
|
602
|
-
|
|
603
|
-
> The namespace in `useTranslation("hero")` corresponds to the `key` field in your Intlayer content declaration.
|
|
604
|
-
|
|
605
|
-
### (Optional) Step 9: Internationalization of Metadata
|
|
606
|
-
|
|
607
|
-
For page metadata, use next-i18next's `serverSideTranslations`:
|
|
608
|
-
|
|
609
|
-
```typescript fileName="src/pages/index.tsx" codeFormat="typescript"
|
|
610
|
-
import { GetStaticProps } from "next";
|
|
611
|
-
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
|
|
612
|
-
import { useTranslation } from "next-i18next";
|
|
613
|
-
import Head from "next/head";
|
|
614
|
-
|
|
615
|
-
export default function Home() {
|
|
616
|
-
const { t } = useTranslation("common");
|
|
617
|
-
|
|
618
|
-
return (
|
|
619
|
-
<>
|
|
620
|
-
<Head>
|
|
621
|
-
<title>{t("meta.title")}</title>
|
|
622
|
-
<meta name="description" content={t("meta.description")} />
|
|
623
|
-
</Head>
|
|
624
|
-
{/* Page content */}
|
|
625
|
-
</>
|
|
626
|
-
);
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
export const getStaticProps: GetStaticProps = async ({ locale }) => {
|
|
630
|
-
return {
|
|
631
|
-
props: {
|
|
632
|
-
...(await serverSideTranslations(locale ?? "en", ["common"])),
|
|
633
|
-
},
|
|
634
|
-
};
|
|
635
|
-
};
|
|
636
|
-
```
|
|
637
|
-
|
|
638
|
-
Create a corresponding metadata content declaration:
|
|
639
|
-
|
|
640
|
-
```typescript fileName="src/content/metadata.content.ts" contentDeclarationFormat="typescript"
|
|
641
|
-
import { t, type Dictionary } from "intlayer";
|
|
642
|
-
|
|
643
|
-
const metadataContent = {
|
|
644
|
-
key: "common",
|
|
645
|
-
content: {
|
|
646
|
-
meta: {
|
|
647
|
-
title: t({
|
|
648
|
-
en: "My Amazing App",
|
|
649
|
-
fr: "Mon Application Incroyable",
|
|
650
|
-
es: "Mi Aplicación Increíble",
|
|
651
|
-
}),
|
|
652
|
-
description: t({
|
|
653
|
-
en: "Discover the best features of our platform",
|
|
654
|
-
fr: "Découvrez les meilleures fonctionnalités de notre plateforme",
|
|
655
|
-
es: "Descubre las mejores características de nuestra plataforma",
|
|
656
|
-
}),
|
|
657
|
-
},
|
|
658
|
-
},
|
|
659
|
-
} satisfies Dictionary;
|
|
660
|
-
|
|
661
|
-
export default metadataContent;
|
|
662
|
-
```
|
|
663
|
-
|
|
664
|
-
### (Optional) Step 10: Internationalization of sitemap.xml and robots.txt
|
|
665
|
-
|
|
666
|
-
For sitemap and robots.txt internationalization, you can use next-i18next's locale information:
|
|
667
|
-
|
|
668
|
-
```typescript fileName="src/pages/sitemap.xml.ts" codeFormat="typescript"
|
|
669
|
-
import { GetServerSideProps } from "next";
|
|
670
|
-
|
|
671
|
-
const SITE_URL = "https://example.com";
|
|
672
|
-
|
|
673
|
-
function generateSiteMap(locales: string[]) {
|
|
674
|
-
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
675
|
-
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
|
676
|
-
xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
|
677
|
-
${locales
|
|
678
|
-
.map((locale) => {
|
|
679
|
-
return `
|
|
680
|
-
<url>
|
|
681
|
-
<loc>${SITE_URL}/${locale}</loc>
|
|
682
|
-
${locales
|
|
683
|
-
.map((altLocale) => {
|
|
684
|
-
return `
|
|
685
|
-
<xhtml:link
|
|
686
|
-
rel="alternate"
|
|
687
|
-
hreflang="${altLocale}"
|
|
688
|
-
href="${SITE_URL}/${altLocale}"/>
|
|
689
|
-
`;
|
|
690
|
-
})
|
|
691
|
-
.join("")}
|
|
692
|
-
</url>
|
|
693
|
-
`;
|
|
694
|
-
})
|
|
695
|
-
.join("")}
|
|
696
|
-
</urlset>
|
|
697
|
-
`;
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
export const getServerSideProps: GetServerSideProps = async ({ res }) => {
|
|
701
|
-
const locales = ["en", "fr", "es"];
|
|
702
|
-
const sitemap = generateSiteMap(locales);
|
|
703
|
-
|
|
704
|
-
res.setHeader("Content-Type", "text/xml");
|
|
705
|
-
res.write(sitemap);
|
|
706
|
-
res.end();
|
|
707
|
-
|
|
708
|
-
return {
|
|
709
|
-
props: {},
|
|
710
|
-
};
|
|
711
|
-
};
|
|
712
|
-
|
|
713
|
-
export default function SiteMap() {
|
|
714
|
-
return null;
|
|
715
|
-
}
|
|
716
|
-
```
|
|
717
|
-
|
|
718
|
-
### (Optional) Step 11: Change the Language of Your Content
|
|
719
|
-
|
|
720
|
-
Implement a language switcher using next-i18next:
|
|
721
|
-
|
|
722
|
-
```typescript fileName="src/components/LanguageSwitcher.tsx" codeFormat="typescript"
|
|
723
|
-
import { useRouter } from "next/router";
|
|
724
|
-
import Link from "next/link";
|
|
725
|
-
import type { FC } from "react";
|
|
726
|
-
|
|
727
|
-
const LanguageSwitcher: FC = () => {
|
|
728
|
-
const router = useRouter();
|
|
729
|
-
const { locales, locale: currentLocale, asPath } = router;
|
|
730
|
-
|
|
731
|
-
return (
|
|
732
|
-
<div>
|
|
733
|
-
<p>Current Language: {currentLocale}</p>
|
|
734
|
-
<ul>
|
|
735
|
-
{locales?.map((locale) => (
|
|
736
|
-
<li key={locale}>
|
|
737
|
-
<Link href={asPath} locale={locale}>
|
|
738
|
-
<a style={{ fontWeight: locale === currentLocale ? "bold" : "normal" }}>
|
|
739
|
-
{locale.toUpperCase()}
|
|
740
|
-
</a>
|
|
741
|
-
</Link>
|
|
742
|
-
</li>
|
|
743
|
-
))}
|
|
744
|
-
</ul>
|
|
745
|
-
</div>
|
|
746
|
-
);
|
|
747
|
-
};
|
|
748
|
-
|
|
749
|
-
export default LanguageSwitcher;
|
|
750
|
-
```
|
|
751
|
-
|
|
752
|
-
```jsx fileName="src/components/LanguageSwitcher.mjx" codeFormat="esm"
|
|
753
|
-
import { useRouter } from "next/router";
|
|
754
|
-
import Link from "next/link";
|
|
755
|
-
|
|
756
|
-
const LanguageSwitcher = () => {
|
|
757
|
-
const router = useRouter();
|
|
758
|
-
const { locales, locale: currentLocale, asPath } = router;
|
|
759
|
-
|
|
760
|
-
return (
|
|
761
|
-
<div>
|
|
762
|
-
<p>Current Language: {currentLocale}</p>
|
|
763
|
-
<ul>
|
|
764
|
-
{locales?.map((locale) => (
|
|
765
|
-
<li key={locale}>
|
|
766
|
-
<Link href={asPath} locale={locale}>
|
|
767
|
-
<a
|
|
768
|
-
style={{
|
|
769
|
-
fontWeight: locale === currentLocale ? "bold" : "normal",
|
|
770
|
-
}}
|
|
771
|
-
>
|
|
772
|
-
{locale.toUpperCase()}
|
|
773
|
-
</a>
|
|
774
|
-
</Link>
|
|
775
|
-
</li>
|
|
776
|
-
))}
|
|
777
|
-
</ul>
|
|
778
|
-
</div>
|
|
779
|
-
);
|
|
780
|
-
};
|
|
781
|
-
|
|
782
|
-
export default LanguageSwitcher;
|
|
783
|
-
```
|
|
784
|
-
|
|
785
|
-
```jsx fileName="src/components/LanguageSwitcher.csx" codeFormat="commonjs"
|
|
786
|
-
const { useRouter } = require("next/router");
|
|
787
|
-
const Link = require("next/link");
|
|
788
|
-
|
|
789
|
-
const LanguageSwitcher = () => {
|
|
790
|
-
const router = useRouter();
|
|
791
|
-
const { locales, locale: currentLocale, asPath } = router;
|
|
792
|
-
|
|
793
|
-
return (
|
|
794
|
-
<div>
|
|
795
|
-
<p>Current Language: {currentLocale}</p>
|
|
796
|
-
<ul>
|
|
797
|
-
{locales?.map((locale) => (
|
|
798
|
-
<li key={locale}>
|
|
799
|
-
<Link href={asPath} locale={locale}>
|
|
800
|
-
<a
|
|
801
|
-
style={{
|
|
802
|
-
fontWeight: locale === currentLocale ? "bold" : "normal",
|
|
803
|
-
}}
|
|
804
|
-
>
|
|
805
|
-
{locale.toUpperCase()}
|
|
806
|
-
</a>
|
|
807
|
-
</Link>
|
|
808
|
-
</li>
|
|
809
|
-
))}
|
|
810
|
-
</ul>
|
|
811
|
-
</div>
|
|
812
|
-
);
|
|
813
|
-
};
|
|
814
|
-
|
|
815
|
-
module.exports = LanguageSwitcher;
|
|
816
|
-
```
|
|
817
|
-
|
|
818
|
-
### (Optional) Step 12: Creating a Localized Link Component
|
|
819
|
-
|
|
820
|
-
Create a custom Link component that preserves locale context:
|
|
821
|
-
|
|
822
|
-
```typescript fileName="src/components/LocalizedLink.tsx" codeFormat="typescript"
|
|
823
|
-
import Link, { LinkProps } from "next/link";
|
|
824
|
-
import { useRouter } from "next/router";
|
|
825
|
-
import type { FC, PropsWithChildren } from "react";
|
|
826
|
-
|
|
827
|
-
const LocalizedLink: FC<PropsWithChildren<LinkProps>> = ({
|
|
828
|
-
children,
|
|
829
|
-
href,
|
|
830
|
-
...props
|
|
831
|
-
}) => {
|
|
832
|
-
const router = useRouter();
|
|
833
|
-
const { locale } = router;
|
|
834
|
-
|
|
835
|
-
return (
|
|
836
|
-
<Link href={href} locale={locale} {...props}>
|
|
837
|
-
{children}
|
|
838
|
-
</Link>
|
|
839
|
-
);
|
|
840
|
-
};
|
|
841
|
-
|
|
842
|
-
export default LocalizedLink;
|
|
843
|
-
```
|
|
844
|
-
|
|
845
|
-
```jsx fileName="src/components/LocalizedLink.mjx" codeFormat="esm"
|
|
846
|
-
import Link from "next/link";
|
|
847
|
-
import { useRouter } from "next/router";
|
|
848
|
-
|
|
849
|
-
const LocalizedLink = ({ children, href, ...props }) => {
|
|
850
|
-
const router = useRouter();
|
|
851
|
-
const { locale } = router;
|
|
852
|
-
|
|
853
|
-
return (
|
|
854
|
-
<Link href={href} locale={locale} {...props}>
|
|
855
|
-
{children}
|
|
856
|
-
</Link>
|
|
857
|
-
);
|
|
858
|
-
};
|
|
859
|
-
|
|
860
|
-
export default LocalizedLink;
|
|
861
|
-
```
|
|
862
|
-
|
|
863
|
-
```jsx fileName="src/components/LocalizedLink.csx" codeFormat="commonjs"
|
|
864
|
-
const Link = require("next/link");
|
|
865
|
-
const { useRouter } = require("next/router");
|
|
866
|
-
|
|
867
|
-
const LocalizedLink = ({ children, href, ...props }) => {
|
|
868
|
-
const router = useRouter();
|
|
869
|
-
const { locale } = router;
|
|
870
|
-
|
|
871
|
-
return (
|
|
872
|
-
<Link href={href} locale={locale} {...props}>
|
|
873
|
-
{children}
|
|
874
|
-
</Link>
|
|
875
|
-
);
|
|
876
|
-
};
|
|
877
|
-
|
|
878
|
-
module.exports = LocalizedLink;
|
|
879
|
-
```
|
|
880
|
-
|
|
881
|
-
---
|
|
882
|
-
|
|
883
|
-
## TypeScript Configuration
|
|
884
|
-
|
|
885
|
-
Intlayer generates TypeScript type definitions for your content. To enable these types:
|
|
886
|
-
|
|
887
|
-
```json5 fileName="tsconfig.json"
|
|
888
|
-
{
|
|
889
|
-
"compilerOptions": {
|
|
890
|
-
// Your existing TypeScript config
|
|
891
|
-
},
|
|
892
|
-
"include": [
|
|
893
|
-
"src",
|
|
894
|
-
".intlayer/**/*.ts", // Include Intlayer auto-generated types
|
|
895
|
-
],
|
|
896
|
-
}
|
|
897
|
-
```
|
|
898
|
-
|
|
899
|
-
This provides:
|
|
900
|
-
|
|
901
|
-
- **Autocompletion** for translation keys
|
|
902
|
-
- **Type checking** to catch missing translations
|
|
903
|
-
- **IntelliSense** support in your IDE
|
|
122
|
+
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).
|
|
904
123
|
|
|
905
124
|
---
|
|
906
125
|
|
|
@@ -916,52 +135,8 @@ intl
|
|
|
916
135
|
|
|
917
136
|
These files are automatically regenerated during the build process and don't need to be committed to your repository.
|
|
918
137
|
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
## VS Code Extension
|
|
922
|
-
|
|
923
|
-
Intlayer provides a VS Code extension to enhance your development experience:
|
|
924
|
-
|
|
925
|
-
[Install from VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=intlayer.intlayer-vs-code-extension)
|
|
926
|
-
|
|
927
|
-
Features:
|
|
928
|
-
|
|
929
|
-
- **Autocompletion** for content keys
|
|
930
|
-
- **Inline previews** of translations
|
|
931
|
-
- **Error detection** for missing translations
|
|
932
|
-
- **Quick actions** for managing content
|
|
933
|
-
|
|
934
|
-
For more details, see the [VS Code Extension documentation](https://intlayer.org/doc/vs-code-extension).
|
|
935
|
-
|
|
936
|
-
---
|
|
937
|
-
|
|
938
|
-
## Development Workflow
|
|
939
|
-
|
|
940
|
-
When working with this setup:
|
|
941
|
-
|
|
942
|
-
1. **Declare content** in `*.content.*` files alongside your components
|
|
943
|
-
2. **Build translations** with `intlayer build` (or let Next.js plugin auto-rebuild in dev mode)
|
|
944
|
-
3. **Use translations** in components via `useTranslation` from next-i18next
|
|
945
|
-
4. **Benefit from TypeScript** autocompletion and type checking
|
|
946
|
-
|
|
947
|
-
---
|
|
948
|
-
|
|
949
|
-
## Going Further
|
|
950
|
-
|
|
951
|
-
- **Visual Editor**: Consider implementing the [Intlayer Visual Editor](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_visual_editor.md) for non-technical team members
|
|
952
|
-
- **CMS Integration**: Externalize your content using the [Intlayer CMS](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_CMS.md)
|
|
953
|
-
- **Full Intlayer Migration**: For new projects or major refactors, consider using [pure Intlayer](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/intlayer_with_nextjs_16.md) for the best developer experience
|
|
954
|
-
|
|
955
|
-
---
|
|
956
|
-
|
|
957
|
-
## Conclusion
|
|
958
|
-
|
|
959
|
-
By combining Intlayer's superior content declaration system with next-i18next's mature i18n infrastructure, you get:
|
|
138
|
+
### VS Code Extension
|
|
960
139
|
|
|
961
|
-
|
|
962
|
-
✅ **Type safety** - Auto-generated TypeScript types
|
|
963
|
-
✅ **Easier maintenance** - Single source of truth for translations
|
|
964
|
-
✅ **Compatibility** - Works with existing i18next ecosystem
|
|
965
|
-
✅ **Flexibility** - Gradual migration path from pure next-i18next
|
|
140
|
+
For improved developer experience, install the official **Intlayer VS Code Extension**:
|
|
966
141
|
|
|
967
|
-
|
|
142
|
+
[Install from the VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=intlayer.intlayer-vs-code-extension)
|