@intlayer/docs 7.0.3 → 7.0.4-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/blog/en/intlayer_with_i18next.md +1620 -54
  2. package/blog/en/intlayer_with_next-i18next.md +763 -163
  3. package/blog/en/intlayer_with_next-intl.md +986 -217
  4. package/blog/en/intlayer_with_react-i18next.md +645 -147
  5. package/blog/en/intlayer_with_react-intl.md +900 -147
  6. package/blog/en/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
  7. package/dist/cjs/generated/blog.entry.cjs +13 -1
  8. package/dist/cjs/generated/blog.entry.cjs.map +1 -1
  9. package/dist/cjs/generated/docs.entry.cjs +13 -1
  10. package/dist/cjs/generated/docs.entry.cjs.map +1 -1
  11. package/dist/cjs/generated/frequentQuestions.entry.cjs +13 -1
  12. package/dist/cjs/generated/frequentQuestions.entry.cjs.map +1 -1
  13. package/dist/cjs/generated/legal.entry.cjs +13 -1
  14. package/dist/cjs/generated/legal.entry.cjs.map +1 -1
  15. package/dist/esm/generated/blog.entry.mjs +13 -2
  16. package/dist/esm/generated/blog.entry.mjs.map +1 -1
  17. package/dist/esm/generated/docs.entry.mjs +13 -2
  18. package/dist/esm/generated/docs.entry.mjs.map +1 -1
  19. package/dist/esm/generated/frequentQuestions.entry.mjs +13 -2
  20. package/dist/esm/generated/frequentQuestions.entry.mjs.map +1 -1
  21. package/dist/esm/generated/legal.entry.mjs +13 -2
  22. package/dist/esm/generated/legal.entry.mjs.map +1 -1
  23. package/dist/types/generated/blog.entry.d.ts.map +1 -1
  24. package/dist/types/generated/docs.entry.d.ts.map +1 -1
  25. package/dist/types/generated/frequentQuestions.entry.d.ts.map +1 -1
  26. package/dist/types/generated/legal.entry.d.ts.map +1 -1
  27. package/docs/de/releases/v7.md +1 -18
  28. package/docs/en/CI_CD.md +1 -1
  29. package/docs/en/configuration.md +1 -1
  30. package/docs/en/formatters.md +1 -1
  31. package/docs/en/how_works_intlayer.md +1 -1
  32. package/docs/en/intlayer_CMS.md +1 -1
  33. package/docs/en/intlayer_cli.md +1 -1
  34. package/docs/en/intlayer_with_nextjs_14.md +1 -1
  35. package/docs/en/intlayer_with_nextjs_15.md +1 -1
  36. package/docs/en/intlayer_with_nextjs_16.md +1 -1
  37. package/docs/en/intlayer_with_nextjs_page_router.md +1 -1
  38. package/docs/en/intlayer_with_nuxt.md +1 -1
  39. package/docs/en/intlayer_with_react_native+expo.md +1 -1
  40. package/docs/en/intlayer_with_react_router_v7.md +1 -1
  41. package/docs/en/intlayer_with_tanstack.md +1 -1
  42. package/docs/en/intlayer_with_vite+preact.md +1 -1
  43. package/docs/en/intlayer_with_vite+react.md +1 -1
  44. package/docs/en/intlayer_with_vite+solid.md +1 -1
  45. package/docs/en/intlayer_with_vite+svelte.md +1 -1
  46. package/docs/en/intlayer_with_vite+vue.md +1 -1
  47. package/docs/en/roadmap.md +1 -1
  48. package/docs/es/releases/v7.md +1 -18
  49. package/docs/fr/intlayer_with_nextjs_16.md +2 -51
  50. package/docs/fr/releases/v7.md +1 -18
  51. package/docs/hi/intlayer_with_nextjs_16.md +3 -2
  52. package/docs/id/releases/v7.md +1 -18
  53. package/docs/it/releases/v7.md +1 -18
  54. package/docs/ja/intlayer_with_nextjs_16.md +44 -205
  55. package/docs/ja/releases/v7.md +1 -18
  56. package/docs/ko/releases/v7.md +1 -18
  57. package/docs/pt/intlayer_with_nextjs_16.md +1 -52
  58. package/package.json +14 -14
  59. package/src/generated/blog.entry.ts +26 -3
  60. package/src/generated/docs.entry.ts +26 -3
  61. package/src/generated/frequentQuestions.entry.ts +26 -3
  62. package/src/generated/legal.entry.ts +26 -3
@@ -1,345 +1,1098 @@
1
1
  ---
2
2
  createdAt: 2025-01-02
3
- updatedAt: 2025-06-29
4
- title: Intlayer and react-intl
5
- description: Integrate Intlayer with react-intl for a React app
3
+ updatedAt: 2025-10-29
4
+ title: How to Integrate Intlayer with react-intl – Complete i18n Guide
5
+ description: Learn how to integrate Intlayer with react-intl for a React app. Comprehensive guide with code examples for managing translations efficiently.
6
6
  keywords:
7
7
  - react-intl
8
8
  - Intlayer
9
9
  - Internationalization
10
10
  - Blog
11
- - Next.js
11
+ - i18n
12
12
  - JavaScript
13
13
  - React
14
+ - FormatJS
14
15
  slugs:
15
16
  - blog
16
17
  - intlayer-with-react-intl
18
+ history:
19
+ - version: 7.0.0
20
+ date: 2025-10-29
21
+ changes: Change to syncJSON plugin
17
22
  ---
18
23
 
19
24
  # React Internationalization (i18n) with **react-intl** and Intlayer
20
25
 
21
- This guide shows how to integrate **Intlayer** with **react-intl** to manage translations in a React application. Youll declare your translatable content with Intlayer and then consume those messages with **react-intl**, a popular library from the [FormatJS](https://formatjs.io/docs/react-intl) ecosystem.
26
+ This comprehensive guide demonstrates how to integrate **Intlayer** with **react-intl** to manage translations in a React application efficiently. You'll learn to declare your translatable content with Intlayer and consume those messages with **react-intl**, a popular library from the [FormatJS](https://formatjs.io/docs/react-intl) ecosystem.
22
27
 
23
- ## Overview
28
+ ## Table of Contents
24
29
 
25
- - **Intlayer** allows you to store translations in **component-level** content declaration files (JSON, JS, TS, etc.) within your project.
26
- - **react-intl** provides React components and hooks (like `<FormattedMessage>` and `useIntl()`) to display localized strings.
30
+ <TOC/>
27
31
 
28
- By configuring Intlayer to **export** translations in a **react-intl–compatible** format, you can automatically **generate** and **update** the message files that `<IntlProvider>` (from react-intl) requires.
32
+ ## What is Intlayer?
33
+
34
+ **Intlayer** is an innovative, open-source internationalization (i18n) library designed to simplify multilingual support in modern web applications. Intlayer seamlessly integrates with popular React frameworks, including **react-intl**.
35
+
36
+ With Intlayer, you can:
37
+
38
+ - **Easily manage translations** using declarative dictionaries at the component level.
39
+ - **Dynamically localize content** throughout your application.
40
+ - **Access translations in both client-side and server-side components**.
41
+ - **Ensure TypeScript support** with autogenerated types, improving autocompletion and error detection.
42
+ - **Benefit from advanced features**, like dynamic locale detection and switching.
43
+ - **Maintain component-level translations** to prevent orphaned translations when components are moved or deleted.
44
+
45
+ > Intlayer also integrates with Next.js, Express, React, and other popular frameworks. Check out our documentation for framework-specific guides.
29
46
 
30
47
  ---
31
48
 
32
- ## Why Use Intlayer with react-intl?
49
+ ## Intlayer vs. react-intl: Key Differences
50
+
51
+ For a deeper analysis of how Intlayer compares to other i18n libraries for React (such as react-intl), check out the [react-i18next vs. react-intl vs. Intlayer blog post](https://github.com/aymericzip/intlayer/blob/main/docs/blog/en/react-i18next_vs_react-intl_vs_intlayer.md).
33
52
 
34
- 1. **Per-Component Dictionarys**
35
- Intlayer content declaration files can live alongside your React components, preventing “orphaned” translations if components are moved or removed. For example:
53
+ **Key advantages of using Intlayer with react-intl:**
36
54
 
37
- ```bash
38
- .
39
- └── src
40
- └── components
41
- └── MyComponent
42
- ├── index.content.ts # Intlayer content declaration
43
- └── index.tsx # React component
44
- ```
55
+ 1. **Component-Level Dictionaries**
56
+ Intlayer content declaration files can live alongside your React components, preventing "orphaned" translations if components are moved or removed.
45
57
 
46
58
  2. **Centralized Translations**
47
- Each content declaration file collects all translations needed by a component. This is particularly helpful in TypeScript projects: missing translations can be caught at **compile time**.
59
+ Each content declaration file collects all translations needed by a component. This is particularly helpful in TypeScript projects where missing translations can be caught at compile time.
48
60
 
49
61
  3. **Automatic Build and Regeneration**
50
- Whenever you add or update translations, Intlayer regenerates message JSON files. You can then pass these into react-intl’s `<IntlProvider>`.
62
+ Whenever you add or update translations, Intlayer regenerates message JSON files automatically.
63
+
64
+ 4. **Type Safety**
65
+ TypeScript integration ensures that missing or incorrect translation keys are caught during development.
51
66
 
52
67
  ---
53
68
 
54
- ## Installation
69
+ ## Step-by-Step Guide to Set Up Intlayer in a React Application with react-intl
55
70
 
56
- In a typical React project, install the following:
71
+ ### Step 1: Install Dependencies
57
72
 
58
- ```bash
59
- # with npm
60
- npm install intlayer react-intl
73
+ Install the necessary packages using your preferred package manager:
74
+
75
+ ```bash packageManager="npm"
76
+ npm install intlayer react-intl @intlayer/sync-json-plugin
77
+ ```
61
78
 
62
- # with yarn
63
- yarn add intlayer react-intl
79
+ ```bash packageManager="pnpm"
80
+ pnpm add intlayer react-intl @intlayer/sync-json-plugin
81
+ ```
64
82
 
65
- # with pnpm
66
- pnpm add intlayer react-intl
83
+ ```bash packageManager="yarn"
84
+ yarn add intlayer react-intl @intlayer/sync-json-plugin
67
85
  ```
68
86
 
69
- ### Why These Packages?
87
+ #### Why These Packages?
70
88
 
71
89
  - **intlayer**: Core CLI and library that scans for content declarations, merges them, and builds dictionary outputs.
72
- - **react-intl**: The main library from FormatJS that provides `<IntlProvider>`, `<FormattedMessage>`, `useIntl()` and other internationalization primitives.
90
+ - **react-intl**: The main library from FormatJS that provides `<IntlProvider>`, `<FormattedMessage>`, `useIntl()`, and other internationalization primitives.
91
+ - **@intlayer/sync-json-plugin**: Plugin to automatically sync Intlayer dictionaries to react-intl compatible JSON files.
73
92
 
74
- > If you dont already have React itself installed, youll need it, too (`react` and `react-dom`).
93
+ > If you don't already have React installed, you'll also need `react` and `react-dom`.
75
94
 
76
- ## Configuring Intlayer to Export react-intl Messages
95
+ ### Step 2: Configure Your Project
77
96
 
78
- In your project’s root, create **`intlayer.config.ts`** (or `.js`, `.mjs`, `.cjs`) like so:
97
+ Create a configuration file to define the languages and output settings for your application:
79
98
 
80
- ```typescript title="intlayer.config.ts"
99
+ ```typescript fileName="intlayer.config.ts" codeFormat="typescript"
81
100
  import { Locales, type IntlayerConfig } from "intlayer";
101
+ import { syncJSON } from "@intlayer/sync-json-plugin";
82
102
 
83
103
  const config: IntlayerConfig = {
84
104
  internationalization: {
85
- // Add as many locales as you wish
86
- locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
105
+ locales: [
106
+ Locales.ENGLISH,
107
+ Locales.FRENCH,
108
+ Locales.SPANISH,
109
+ // Add your other locales here
110
+ ],
87
111
  defaultLocale: Locales.ENGLISH,
88
112
  },
89
- content: {
90
- // Tells Intlayer to generate message files for react-intl
91
- dictionaryOutput: ["react-intl"],
113
+ plugins: [
114
+ syncJSON({
115
+ // Define the output directory for react-intl message files
116
+ source: ({ key, locale }) => `./intl/messages/${locale}/${key}.json`,
117
+ }),
118
+ ],
119
+ };
120
+
121
+ export default config;
122
+ ```
123
+
124
+ ```javascript fileName="intlayer.config.mjs" codeFormat="esm"
125
+ import { Locales } from "intlayer";
126
+ import { syncJSON } from "@intlayer/sync-json-plugin";
92
127
 
93
- // The directory where Intlayer will write your message JSON files
94
- reactIntlMessagesDir: "./react-intl/messages",
128
+ /** @type {import('intlayer').IntlayerConfig} */
129
+ const config = {
130
+ internationalization: {
131
+ locales: [
132
+ Locales.ENGLISH,
133
+ Locales.FRENCH,
134
+ Locales.SPANISH,
135
+ // Add your other locales here
136
+ ],
137
+ defaultLocale: Locales.ENGLISH,
95
138
  },
139
+ plugins: [
140
+ syncJSON({
141
+ // Define the output directory for react-intl message files
142
+ source: ({ key, locale }) => `./intl/messages/${locale}/${key}.json`,
143
+ }),
144
+ ],
96
145
  };
97
146
 
98
147
  export default config;
99
148
  ```
100
149
 
101
- > **Note**: For other file extensions (`.mjs`, `.cjs`, `.js`), see the [Intlayer docs](https://intlayer.org/en/doc/concept/configuration) for usage details.
150
+ ```javascript fileName="intlayer.config.cjs" codeFormat="commonjs"
151
+ const { Locales } = require("intlayer");
152
+ const { syncJSON } = require("@intlayer/sync-json-plugin");
102
153
 
103
- ---
154
+ /** @type {import('intlayer').IntlayerConfig} */
155
+ const config = {
156
+ internationalization: {
157
+ locales: [
158
+ Locales.ENGLISH,
159
+ Locales.FRENCH,
160
+ Locales.SPANISH,
161
+ // Add your other locales here
162
+ ],
163
+ defaultLocale: Locales.ENGLISH,
164
+ },
165
+ plugins: [
166
+ syncJSON({
167
+ // Define the output directory for react-intl message files
168
+ source: ({ key, locale }) => `./intl/messages/${locale}/${key}.json`,
169
+ }),
170
+ ],
171
+ };
172
+
173
+ module.exports = config;
174
+ ```
175
+
176
+ > Through this configuration file, you can set up locales, output directories, content file patterns, and more. For a complete list of available parameters, refer to the [configuration documentation](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/configuration.md).
104
177
 
105
- ## Creating Your Intlayer Dictionarys
178
+ ### Step 3: Integrate Intlayer in Your Build Process
179
+
180
+ Configure your build scripts to run Intlayer when building your application. Add the Intlayer build command to your `package.json`:
181
+
182
+ ```json fileName="package.json"
183
+ {
184
+ "scripts": {
185
+ "build": "intlayer build && vite build",
186
+ "dev": "intlayer build && vite dev"
187
+ }
188
+ }
189
+ ```
106
190
 
107
- Intlayer scans your codebase (by default, under `./src`) for files matching `*.content.{ts,tsx,js,jsx,mjs,mjx,cjs,cjx,json}`.
108
- Here’s a **TypeScript** example:
191
+ > The `intlayer build` command scans your content declaration files, compiles them, and generates the JSON message files that react-intl will consume.
109
192
 
110
- ```typescript title="src/components/MyComponent/index.content.ts"
193
+ ### Step 4: Declare Your Content
194
+
195
+ Create and manage your content declarations to store translations. Intlayer scans your codebase (by default, under `./src`) for files matching `*.content.{ts,tsx,js,jsx,mjs,mjx,cjs,cjx,json}`.
196
+
197
+ Here's a **TypeScript** example:
198
+
199
+ ```typescript fileName="src/components/MyComponent/index.content.ts" contentDeclarationFormat="typescript"
111
200
  import { t, type Dictionary } from "intlayer";
112
201
 
113
202
  const content = {
114
- // "key" becomes the top-level message key in your react-intl JSON file
203
+ // "key" becomes the namespace in your react-intl JSON files
115
204
  key: "my-component",
116
205
 
117
206
  content: {
118
207
  // Each call to t() declares a translatable field
119
208
  helloWorld: t({
120
209
  en: "Hello World",
121
- es: "Hola Mundo",
122
210
  fr: "Bonjour le monde",
211
+ es: "Hola Mundo",
123
212
  }),
124
213
  description: t({
125
214
  en: "This is a description",
126
215
  fr: "Ceci est une description",
127
216
  es: "Esta es una descripción",
128
217
  }),
218
+ welcomeMessage: t({
219
+ en: "Welcome to our application",
220
+ fr: "Bienvenue dans notre application",
221
+ es: "Bienvenido a nuestra aplicación",
222
+ }),
129
223
  },
130
224
  } satisfies Dictionary;
131
225
 
132
226
  export default content;
133
227
  ```
134
228
 
135
- If you prefer JSON or different JS flavors (`.cjs`, `.mjs`), the structure is largely the same see [Intlayer docs on content declaration](https://intlayer.org/en/doc/concept/content).
229
+ ```javascript fileName="src/components/MyComponent/index.content.mjs" contentDeclarationFormat="esm"
230
+ import { t } from "intlayer";
136
231
 
137
- ---
232
+ /** @type {import('intlayer').Dictionary} */
233
+ const content = {
234
+ key: "my-component",
138
235
 
139
- ## Building the react-intl Messages
236
+ content: {
237
+ helloWorld: t({
238
+ en: "Hello World",
239
+ fr: "Bonjour le monde",
240
+ es: "Hola Mundo",
241
+ }),
242
+ description: t({
243
+ en: "This is a description",
244
+ fr: "Ceci est une description",
245
+ es: "Esta es una descripción",
246
+ }),
247
+ welcomeMessage: t({
248
+ en: "Welcome to our application",
249
+ fr: "Bienvenue dans notre application",
250
+ es: "Bienvenido a nuestra aplicación",
251
+ }),
252
+ },
253
+ };
140
254
 
141
- To generate the actual message JSON files for **react-intl**, run:
255
+ export default content;
256
+ ```
142
257
 
143
- ```bash
144
- # with npm
145
- npx intlayer dictionaries build
258
+ ```javascript fileName="src/components/MyComponent/index.content.cjs" contentDeclarationFormat="commonjs"
259
+ const { t } = require("intlayer");
146
260
 
147
- # with yarn
148
- yarn intlayer build
261
+ /** @type {import('intlayer').Dictionary} */
262
+ const content = {
263
+ key: "my-component",
149
264
 
150
- # with pnpm
265
+ content: {
266
+ helloWorld: t({
267
+ en: "Hello World",
268
+ fr: "Bonjour le monde",
269
+ es: "Hola Mundo",
270
+ }),
271
+ description: t({
272
+ en: "This is a description",
273
+ fr: "Ceci est une description",
274
+ es: "Esta es una descripción",
275
+ }),
276
+ welcomeMessage: t({
277
+ en: "Welcome to our application",
278
+ fr: "Bienvenue dans notre application",
279
+ es: "Bienvenido a nuestra aplicación",
280
+ }),
281
+ },
282
+ };
283
+
284
+ module.exports = content;
285
+ ```
286
+
287
+ ```json fileName="src/components/MyComponent/index.content.json" contentDeclarationFormat="json"
288
+ {
289
+ "$schema": "https://intlayer.org/schema.json",
290
+ "key": "my-component",
291
+ "content": {
292
+ "helloWorld": {
293
+ "nodeType": "translation",
294
+ "translation": {
295
+ "en": "Hello World",
296
+ "fr": "Bonjour le monde",
297
+ "es": "Hola Mundo"
298
+ }
299
+ },
300
+ "description": {
301
+ "nodeType": "translation",
302
+ "translation": {
303
+ "en": "This is a description",
304
+ "fr": "Ceci est une description",
305
+ "es": "Esta es una descripción"
306
+ }
307
+ },
308
+ "welcomeMessage": {
309
+ "nodeType": "translation",
310
+ "translation": {
311
+ "en": "Welcome to our application",
312
+ "fr": "Bienvenue dans notre application",
313
+ "es": "Bienvenido a nuestra aplicación"
314
+ }
315
+ }
316
+ }
317
+ }
318
+ ```
319
+
320
+ > Your 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 pattern.
321
+
322
+ > For more details, refer to the [content declaration documentation](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/dictionary/content_file.md).
323
+
324
+ ### Step 5: Build the react-intl Messages
325
+
326
+ To generate the actual message JSON files for **react-intl**, run:
327
+
328
+ ```bash packageManager="npm"
329
+ npx intlayer build
330
+ ```
331
+
332
+ ```bash packageManager="pnpm"
151
333
  pnpm intlayer build
152
334
  ```
153
335
 
154
- This scans all `*.content.*` files, compiles them, and writes the results to the directory specified in your **`intlayer.config.ts`** in this example, `./react-intl/messages`.
155
- A typical output might look like:
336
+ ```bash packageManager="yarn"
337
+ yarn intlayer build
338
+ ```
339
+
340
+ This command scans all `*.content.*` files, compiles them, and writes the results to the directory specified in your **`intlayer.config.ts`**—in this example, `./intl/messages`.
341
+
342
+ A typical output structure might look like:
156
343
 
157
344
  ```bash
158
345
  .
159
- └── react-intl
346
+ └── intl
160
347
  └── messages
161
- ├── en.json
162
- ├── fr.json
163
- └── es.json
348
+ ├── en
349
+ │ └── my-component.json
350
+ ├── fr
351
+ │ └── my-component.json
352
+ └── es
353
+ └── my-component.json
164
354
  ```
165
355
 
166
- Each file is a JSON object whose **top-level keys** correspond to each **`content.key`** from your declarations. The **sub-keys** (like `helloWorld`) reflect the translations declared within that content item.
167
-
168
- For example, the **en.json** might look like:
356
+ Each file is a JSON object with keys corresponding to the `content` properties defined in your Intlayer dictionaries. For example, **en/my-component.json** might look like:
169
357
 
170
- ```json fileName="react-intl/messages/en/my-component.json"
358
+ ```json fileName="intl/messages/en/my-component.json"
171
359
  {
172
360
  "helloWorld": "Hello World",
173
- "description": "This is a description"
361
+ "description": "This is a description",
362
+ "welcomeMessage": "Welcome to our application"
174
363
  }
175
364
  ```
176
365
 
177
- ---
178
-
179
- ## Initializing react-intl in Your React App
366
+ ### Step 6: Initialize react-intl in Your React App
180
367
 
181
- ### 1. Load the Generated Messages
368
+ #### 6.1. Load the Generated Messages
182
369
 
183
- Where you configure your app’s root component (e.g., `src/main.tsx` or `src/index.tsx`), you’ll need to:
370
+ In your application's entry point (e.g., `src/main.tsx` or `src/index.tsx`), you need to:
184
371
 
185
372
  1. **Import** the generated message files (either statically or dynamically).
186
373
  2. **Provide** them to `<IntlProvider>` from `react-intl`.
187
374
 
188
- A simple approach is to import them **statically**:
375
+ Here's an example using **Vite's** `import.meta.glob`:
189
376
 
190
- ```typescript title="src/index.tsx"
377
+ ```typescript fileName="src/main.tsx" codeFormat="typescript"
191
378
  import React from "react";
192
379
  import ReactDOM from "react-dom/client";
193
380
  import { IntlProvider } from "react-intl";
194
381
  import App from "./App";
195
382
 
196
- // Import the JSON files from the build output.
197
- // Alternatively, you can import dynamically based on the user's chosen locale.
198
- import en from "../react-intl/messages/en.json";
199
- import fr from "../react-intl/messages/fr.json";
200
- import es from "../react-intl/messages/es.json";
383
+ // Dynamically import all JSON message files
384
+ const messages = import.meta.glob<Record<string, string>>(
385
+ "../intl/messages/**/*.json",
386
+ {
387
+ eager: true,
388
+ }
389
+ );
201
390
 
391
+ // Structure messages by locale
392
+ const messagesRecord: Record<string, Record<string, string>> = {};
202
393
 
394
+ Object.entries(messages).forEach(([path, module]) => {
395
+ // Extract locale and namespace from file path
396
+ // Example path: "../intl/messages/en/my-component.json"
397
+ const match = path.match(/messages\/(\w+)\/(.+?)\.json$/);
398
+ if (match) {
399
+ const [, locale, namespace] = match;
400
+ if (!messagesRecord[locale]) {
401
+ messagesRecord[locale] = {};
402
+ }
403
+ // Flatten all messages for the locale
404
+ Object.assign(messagesRecord[locale], module.default || module);
405
+ }
406
+ });
407
+
408
+ // Detect user locale (you can implement more sophisticated logic)
409
+ const userLocale = navigator.language.split("-")[0] || "en";
410
+ const locale = messagesRecord[userLocale] ? userLocale : "en";
411
+
412
+ ReactDOM.createRoot(document.getElementById("root")!).render(
413
+ <React.StrictMode>
414
+ <IntlProvider locale={locale} messages={messagesRecord[locale]}>
415
+ <App />
416
+ </IntlProvider>
417
+ </React.StrictMode>
418
+ );
419
+ ```
203
420
 
204
- // Dynamically import all JSON files using Vite's import.meta.glob
205
- const messages = import.meta.glob("../react-intl/messages/**/*.json", {
421
+ ```javascript fileName="src/main.mjs" codeFormat="esm"
422
+ import React from "react";
423
+ import ReactDOM from "react-dom/client";
424
+ import { IntlProvider } from "react-intl";
425
+ import App from "./App";
426
+
427
+ // Dynamically import all JSON message files
428
+ const messages = import.meta.glob("../intl/messages/**/*.json", {
206
429
  eager: true,
207
430
  });
208
431
 
209
- // Collate messages into a structured record
210
- const messagesRecord: Record<string, Record<string, any>> = {};
432
+ // Structure messages by locale
433
+ const messagesRecord = {};
211
434
 
212
435
  Object.entries(messages).forEach(([path, module]) => {
213
- // Extract locale and namespace from the file path
214
- const [, locale, namespace] = path.match(/messages\/(\w+)\/(.+?)\.json$/) ?? [];
215
- if (locale && namespace) {
216
- messagesRecord[locale] = messagesRecord[locale] ?? {};
217
- messagesRecord[locale][namespace] = module.default; // Assign JSON content
436
+ const match = path.match(/messages\/(\w+)\/(.+?)\.json$/);
437
+ if (match) {
438
+ const [, locale, namespace] = match;
439
+ if (!messagesRecord[locale]) {
440
+ messagesRecord[locale] = {};
441
+ }
442
+ Object.assign(messagesRecord[locale], module.default || module);
218
443
  }
219
444
  });
220
445
 
221
- // Merge namespaces for each locale
222
- const mergeMessages = (locale: string) =>
223
- Object.values(messagesRecord[locale] ?? {}).reduce(
224
- (acc, namespaceMessages) => ({ ...acc, ...namespaceMessages }),
225
- {}
226
- );
446
+ // Detect user locale
447
+ const userLocale = navigator.language.split("-")[0] || "en";
448
+ const locale = messagesRecord[userLocale] ? userLocale : "en";
227
449
 
228
- // If you have a mechanism to detect the user's language, set it here.
229
- // For simplicity, let's pick English.
230
- const locale = "en";
231
-
232
-
233
- ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
450
+ ReactDOM.createRoot(document.getElementById("root")).render(
234
451
  <React.StrictMode>
235
- <IntlProvider locale={locale} messages={mergeMessages(locale)}>
452
+ <IntlProvider locale={locale} messages={messagesRecord[locale]}>
236
453
  <App />
237
454
  </IntlProvider>
238
455
  </React.StrictMode>
239
456
  );
240
457
  ```
241
458
 
242
- > **Tip**: For real projects, you might:
459
+ ```javascript fileName="src/main.cjs" codeFormat="commonjs"
460
+ const React = require("react");
461
+ const ReactDOM = require("react-dom/client");
462
+ const { IntlProvider } = require("react-intl");
463
+ const App = require("./App");
464
+
465
+ // For CommonJS, you'll need to load messages differently
466
+ // This example assumes you have a way to import JSON files
467
+ const enMessages = require("../intl/messages/en/my-component.json");
468
+ const frMessages = require("../intl/messages/fr/my-component.json");
469
+ const esMessages = require("../intl/messages/es/my-component.json");
470
+
471
+ const messagesRecord = {
472
+ en: enMessages,
473
+ fr: frMessages,
474
+ es: esMessages,
475
+ };
476
+
477
+ // Detect user locale
478
+ const userLocale = navigator.language.split("-")[0] || "en";
479
+ const locale = messagesRecord[userLocale] ? userLocale : "en";
480
+
481
+ ReactDOM.createRoot(document.getElementById("root")).render(
482
+ React.createElement(
483
+ React.StrictMode,
484
+ null,
485
+ React.createElement(
486
+ IntlProvider,
487
+ { locale: locale, messages: messagesRecord[locale] },
488
+ React.createElement(App)
489
+ )
490
+ )
491
+ );
492
+ ```
493
+
494
+ > **Tip**: For production applications, consider:
243
495
  >
244
- > - Dynamically load the JSON messages at runtime.
245
- > - Use environment-based, browser-based, or user account–based locale detection.
496
+ > - Implementing proper locale detection based on user preferences, browser settings, or user accounts
497
+ > - Loading messages dynamically to reduce initial bundle size
498
+ > - Using a locale switcher component to allow users to change languages
499
+
500
+ #### 6.2. Create a Locale Context (Optional but Recommended)
501
+
502
+ For better locale management, create a context that allows components to access and change the current locale:
503
+
504
+ ```typescript fileName="src/context/LocaleContext.tsx" codeFormat="typescript"
505
+ import React, {
506
+ createContext,
507
+ useContext,
508
+ useState,
509
+ ReactNode,
510
+ useEffect,
511
+ } from "react";
512
+ import { IntlProvider } from "react-intl";
246
513
 
247
- ### 2. Use `<FormattedMessage>` or `useIntl()`
514
+ interface LocaleContextType {
515
+ locale: string;
516
+ setLocale: (locale: string) => void;
517
+ availableLocales: string[];
518
+ }
248
519
 
249
- Once your messages are loaded into `<IntlProvider>`, any child component can use react-intl to access localized strings. There are two main approaches:
520
+ const LocaleContext = createContext<LocaleContextType | undefined>(undefined);
250
521
 
251
- - **`<FormattedMessage>`** component
252
- - **`useIntl()`** hook
522
+ // Load messages
523
+ const messages = import.meta.glob<Record<string, string>>(
524
+ "../../intl/messages/**/*.json",
525
+ {
526
+ eager: true,
527
+ }
528
+ );
253
529
 
254
- ---
530
+ const messagesRecord: Record<string, Record<string, string>> = {};
531
+
532
+ Object.entries(messages).forEach(([path, module]) => {
533
+ const match = path.match(/messages\/(\w+)\/(.+?)\.json$/);
534
+ if (match) {
535
+ const [, locale] = match;
536
+ if (!messagesRecord[locale]) {
537
+ messagesRecord[locale] = {};
538
+ }
539
+ Object.assign(messagesRecord[locale], module.default || module);
540
+ }
541
+ });
255
542
 
256
- ## Using Translations in React Components
543
+ const availableLocales = Object.keys(messagesRecord);
544
+
545
+ export const LocaleProvider: React.FC<{ children: ReactNode }> = ({
546
+ children,
547
+ }) => {
548
+ const [locale, setLocaleState] = useState<string>(() => {
549
+ // Get locale from localStorage or browser
550
+ const saved = localStorage.getItem("locale");
551
+ if (saved && availableLocales.includes(saved)) {
552
+ return saved;
553
+ }
554
+ const browserLocale = navigator.language.split("-")[0];
555
+ return availableLocales.includes(browserLocale) ? browserLocale : "en";
556
+ });
557
+
558
+ const setLocale = (newLocale: string) => {
559
+ if (availableLocales.includes(newLocale)) {
560
+ setLocaleState(newLocale);
561
+ localStorage.setItem("locale", newLocale);
562
+ }
563
+ };
257
564
 
258
- ### Approach A: `<FormattedMessage>`
565
+ return (
566
+ <LocaleContext.Provider value={{ locale, setLocale, availableLocales }}>
567
+ <IntlProvider locale={locale} messages={messagesRecord[locale]}>
568
+ {children}
569
+ </IntlProvider>
570
+ </LocaleContext.Provider>
571
+ );
572
+ };
573
+
574
+ export const useLocale = () => {
575
+ const context = useContext(LocaleContext);
576
+ if (!context) {
577
+ throw new Error("useLocale must be used within LocaleProvider");
578
+ }
579
+ return context;
580
+ };
581
+ ```
582
+
583
+ ```javascript fileName="src/context/LocaleContext.mjs" codeFormat="esm"
584
+ import React, { createContext, useContext, useState } from "react";
585
+ import { IntlProvider } from "react-intl";
586
+
587
+ const LocaleContext = createContext(undefined);
588
+
589
+ // Load messages
590
+ const messages = import.meta.glob("../../intl/messages/**/*.json", {
591
+ eager: true,
592
+ });
593
+
594
+ const messagesRecord = {};
595
+
596
+ Object.entries(messages).forEach(([path, module]) => {
597
+ const match = path.match(/messages\/(\w+)\/(.+?)\.json$/);
598
+ if (match) {
599
+ const [, locale] = match;
600
+ if (!messagesRecord[locale]) {
601
+ messagesRecord[locale] = {};
602
+ }
603
+ Object.assign(messagesRecord[locale], module.default || module);
604
+ }
605
+ });
606
+
607
+ const availableLocales = Object.keys(messagesRecord);
608
+
609
+ export const LocaleProvider = ({ children }) => {
610
+ const [locale, setLocaleState] = useState(() => {
611
+ const saved = localStorage.getItem("locale");
612
+ if (saved && availableLocales.includes(saved)) {
613
+ return saved;
614
+ }
615
+ const browserLocale = navigator.language.split("-")[0];
616
+ return availableLocales.includes(browserLocale) ? browserLocale : "en";
617
+ });
618
+
619
+ const setLocale = (newLocale) => {
620
+ if (availableLocales.includes(newLocale)) {
621
+ setLocaleState(newLocale);
622
+ localStorage.setItem("locale", newLocale);
623
+ }
624
+ };
625
+
626
+ return (
627
+ <LocaleContext.Provider value={{ locale, setLocale, availableLocales }}>
628
+ <IntlProvider locale={locale} messages={messagesRecord[locale]}>
629
+ {children}
630
+ </IntlProvider>
631
+ </LocaleContext.Provider>
632
+ );
633
+ };
634
+
635
+ export const useLocale = () => {
636
+ const context = useContext(LocaleContext);
637
+ if (!context) {
638
+ throw new Error("useLocale must be used within LocaleProvider");
639
+ }
640
+ return context;
641
+ };
642
+ ```
643
+
644
+ Now update your main entry file to use the `LocaleProvider`:
645
+
646
+ ```typescript fileName="src/main.tsx" codeFormat="typescript"
647
+ import React from "react";
648
+ import ReactDOM from "react-dom/client";
649
+ import { LocaleProvider } from "./context/LocaleContext";
650
+ import App from "./App";
651
+
652
+ ReactDOM.createRoot(document.getElementById("root")!).render(
653
+ <React.StrictMode>
654
+ <LocaleProvider>
655
+ <App />
656
+ </LocaleProvider>
657
+ </React.StrictMode>
658
+ );
659
+ ```
660
+
661
+ ### Step 7: Utilize Content in Your Code
662
+
663
+ Access your translations throughout your application using react-intl's components and hooks.
664
+
665
+ #### Approach A: Using `<FormattedMessage>`
259
666
 
260
667
  For quick inline usage:
261
668
 
262
- ```tsx title="src/components/MyComponent/index.tsx"
669
+ ```tsx fileName="src/components/MyComponent/index.tsx" codeFormat="typescript"
263
670
  import React from "react";
264
671
  import { FormattedMessage } from "react-intl";
265
672
 
266
- export default function MyComponent() {
673
+ const MyComponent: React.FC = () => {
267
674
  return (
268
675
  <div>
269
676
  <h1>
270
- {/* “my-component.helloWorld” references the key from en.json, fr.json, etc. */}
271
677
  <FormattedMessage id="my-component.helloWorld" />
272
678
  </h1>
679
+ <p>
680
+ <FormattedMessage id="my-component.description" />
681
+ </p>
682
+ <p>
683
+ <FormattedMessage id="my-component.welcomeMessage" />
684
+ </p>
685
+ </div>
686
+ );
687
+ };
688
+
689
+ export default MyComponent;
690
+ ```
273
691
 
692
+ ```jsx fileName="src/components/MyComponent/index.mjx" codeFormat="esm"
693
+ import React from "react";
694
+ import { FormattedMessage } from "react-intl";
695
+
696
+ const MyComponent = () => {
697
+ return (
698
+ <div>
699
+ <h1>
700
+ <FormattedMessage id="my-component.helloWorld" />
701
+ </h1>
274
702
  <p>
275
703
  <FormattedMessage id="my-component.description" />
276
704
  </p>
705
+ <p>
706
+ <FormattedMessage id="my-component.welcomeMessage" />
707
+ </p>
277
708
  </div>
278
709
  );
279
- }
710
+ };
711
+
712
+ export default MyComponent;
280
713
  ```
281
714
 
282
- > The **`id`** prop in `<FormattedMessage>` must match the **top-level key** (`my-component`) plus any sub-keys (`helloWorld`).
715
+ ```jsx fileName="src/components/MyComponent/index.csx" codeFormat="commonjs"
716
+ const React = require("react");
717
+ const { FormattedMessage } = require("react-intl");
283
718
 
284
- ### Approach B: `useIntl()`
719
+ const MyComponent = () => {
720
+ return (
721
+ <div>
722
+ <h1>
723
+ <FormattedMessage id="my-component.helloWorld" />
724
+ </h1>
725
+ <p>
726
+ <FormattedMessage id="my-component.description" />
727
+ </p>
728
+ <p>
729
+ <FormattedMessage id="my-component.welcomeMessage" />
730
+ </p>
731
+ </div>
732
+ );
733
+ };
734
+
735
+ module.exports = MyComponent;
736
+ ```
737
+
738
+ > The **`id`** prop in `<FormattedMessage>` must match the flattened key structure: `namespace.key` (e.g., `my-component.helloWorld`).
739
+
740
+ #### Approach B: Using `useIntl()`
741
+
742
+ For more dynamic usage and to access translations in JavaScript logic:
743
+
744
+ ```tsx fileName="src/components/MyComponent/MyComponent.tsx" codeFormat="typescript"
745
+ import React from "react";
746
+ import { useIntl } from "react-intl";
747
+
748
+ const MyComponent: React.FC = () => {
749
+ const intl = useIntl();
750
+
751
+ return (
752
+ <div>
753
+ <h1>{intl.formatMessage({ id: "my-component.helloWorld" })}</h1>
754
+ <p>{intl.formatMessage({ id: "my-component.description" })}</p>
755
+ <button
756
+ aria-label={intl.formatMessage({ id: "my-component.welcomeMessage" })}
757
+ >
758
+ {intl.formatMessage({ id: "my-component.welcomeMessage" })}
759
+ </button>
760
+ </div>
761
+ );
762
+ };
285
763
 
286
- For more dynamic usage:
764
+ export default MyComponent;
765
+ ```
287
766
 
288
- ```tsx title="src/components/MyComponent/index.tsx"
767
+ ```jsx fileName="src/components/MyComponent/MyComponent.mjx" codeFormat="esm"
289
768
  import React from "react";
290
769
  import { useIntl } from "react-intl";
291
770
 
292
- export default function MyComponent() {
771
+ const MyComponent = () => {
293
772
  const intl = useIntl();
294
773
 
295
774
  return (
296
775
  <div>
297
776
  <h1>{intl.formatMessage({ id: "my-component.helloWorld" })}</h1>
298
777
  <p>{intl.formatMessage({ id: "my-component.description" })}</p>
778
+ <button
779
+ aria-label={intl.formatMessage({ id: "my-component.welcomeMessage" })}
780
+ >
781
+ {intl.formatMessage({ id: "my-component.welcomeMessage" })}
782
+ </button>
783
+ </div>
784
+ );
785
+ };
786
+
787
+ export default MyComponent;
788
+ ```
789
+
790
+ ```jsx fileName="src/components/MyComponent/MyComponent.csx" codeFormat="commonjs"
791
+ const React = require("react");
792
+ const { useIntl } = require("react-intl");
793
+
794
+ const MyComponent = () => {
795
+ const intl = useIntl();
796
+
797
+ return (
798
+ <div>
799
+ <h1>{intl.formatMessage({ id: "my-component.helloWorld" })}</h1>
800
+ <p>{intl.formatMessage({ id: "my-component.description" })}</p>
801
+ <button
802
+ aria-label={intl.formatMessage({ id: "my-component.welcomeMessage" })}
803
+ >
804
+ {intl.formatMessage({ id: "my-component.welcomeMessage" })}
805
+ </button>
806
+ </div>
807
+ );
808
+ };
809
+
810
+ module.exports = MyComponent;
811
+ ```
812
+
813
+ ### (Optional) Step 8: Change the Language of Your Content
814
+
815
+ To allow users to switch languages, create a locale switcher component:
816
+
817
+ ```tsx fileName="src/components/LocaleSwitcher.tsx" codeFormat="typescript"
818
+ import React from "react";
819
+ import { useLocale } from "../context/LocaleContext";
820
+
821
+ const localeNames: Record<string, string> = {
822
+ en: "English",
823
+ fr: "Français",
824
+ es: "Español",
825
+ };
826
+
827
+ const LocaleSwitcher: React.FC = () => {
828
+ const { locale, setLocale, availableLocales } = useLocale();
829
+
830
+ return (
831
+ <div>
832
+ <label htmlFor="locale-select">Choose language: </label>
833
+ <select
834
+ id="locale-select"
835
+ value={locale}
836
+ onChange={(e) => setLocale(e.target.value)}
837
+ >
838
+ {availableLocales.map((loc) => (
839
+ <option key={loc} value={loc}>
840
+ {localeNames[loc] || loc}
841
+ </option>
842
+ ))}
843
+ </select>
844
+ </div>
845
+ );
846
+ };
847
+
848
+ export default LocaleSwitcher;
849
+ ```
850
+
851
+ ```jsx fileName="src/components/LocaleSwitcher.mjx" codeFormat="esm"
852
+ import React from "react";
853
+ import { useLocale } from "../context/LocaleContext";
854
+
855
+ const localeNames = {
856
+ en: "English",
857
+ fr: "Français",
858
+ es: "Español",
859
+ };
860
+
861
+ const LocaleSwitcher = () => {
862
+ const { locale, setLocale, availableLocales } = useLocale();
863
+
864
+ return (
865
+ <div>
866
+ <label htmlFor="locale-select">Choose language: </label>
867
+ <select
868
+ id="locale-select"
869
+ value={locale}
870
+ onChange={(e) => setLocale(e.target.value)}
871
+ >
872
+ {availableLocales.map((loc) => (
873
+ <option key={loc} value={loc}>
874
+ {localeNames[loc] || loc}
875
+ </option>
876
+ ))}
877
+ </select>
299
878
  </div>
300
879
  );
880
+ };
881
+
882
+ export default LocaleSwitcher;
883
+ ```
884
+
885
+ ```jsx fileName="src/components/LocaleSwitcher.csx" codeFormat="commonjs"
886
+ const React = require("react");
887
+ const { useLocale } = require("../context/LocaleContext");
888
+
889
+ const localeNames = {
890
+ en: "English",
891
+ fr: "Français",
892
+ es: "Español",
893
+ };
894
+
895
+ const LocaleSwitcher = () => {
896
+ const { locale, setLocale, availableLocales } = useLocale();
897
+
898
+ return React.createElement(
899
+ "div",
900
+ null,
901
+ React.createElement(
902
+ "label",
903
+ { htmlFor: "locale-select" },
904
+ "Choose language: "
905
+ ),
906
+ React.createElement(
907
+ "select",
908
+ {
909
+ id: "locale-select",
910
+ value: locale,
911
+ onChange: (e) => setLocale(e.target.value),
912
+ },
913
+ availableLocales.map((loc) =>
914
+ React.createElement(
915
+ "option",
916
+ { key: loc, value: loc },
917
+ localeNames[loc] || loc
918
+ )
919
+ )
920
+ )
921
+ );
922
+ };
923
+
924
+ module.exports = LocaleSwitcher;
925
+ ```
926
+
927
+ Then use the `LocaleSwitcher` component in your app:
928
+
929
+ ```tsx fileName="src/App.tsx" codeFormat="typescript"
930
+ import React from "react";
931
+ import MyComponent from "./components/MyComponent";
932
+ import LocaleSwitcher from "./components/LocaleSwitcher";
933
+
934
+ const App: React.FC = () => {
935
+ return (
936
+ <div>
937
+ <LocaleSwitcher />
938
+ <MyComponent />
939
+ </div>
940
+ );
941
+ };
942
+
943
+ export default App;
944
+ ```
945
+
946
+ ### (Optional) Step 9: Advanced Message Formatting
947
+
948
+ react-intl supports advanced formatting features like pluralization, date/time formatting, and number formatting. Here are some examples:
949
+
950
+ #### Pluralization
951
+
952
+ ```typescript fileName="src/components/ItemCount.content.ts" codeFormat="typescript"
953
+ import { t, type Dictionary } from "intlayer";
954
+
955
+ const content = {
956
+ key: "item-count",
957
+ content: {
958
+ items: t({
959
+ en: "{count, plural, =0 {No items} one {One item} other {# items}}",
960
+ fr: "{count, plural, =0 {Aucun article} one {Un article} other {# articles}}",
961
+ es: "{count, plural, =0 {Sin artículos} one {Un artículo} other {# artículos}}",
962
+ }),
963
+ },
964
+ } satisfies Dictionary;
965
+
966
+ export default content;
967
+ ```
968
+
969
+ ```tsx fileName="src/components/ItemCount.tsx" codeFormat="typescript"
970
+ import React from "react";
971
+ import { FormattedMessage } from "react-intl";
972
+
973
+ interface ItemCountProps {
974
+ count: number;
301
975
  }
976
+
977
+ const ItemCount: React.FC<ItemCountProps> = ({ count }) => {
978
+ return (
979
+ <p>
980
+ <FormattedMessage id="item-count.items" values={{ count }} />
981
+ </p>
982
+ );
983
+ };
984
+
985
+ export default ItemCount;
302
986
  ```
303
987
 
304
- Either approach is valid choose whichever style suits your app.
988
+ #### Date and Number Formatting
305
989
 
306
- ---
990
+ ```tsx fileName="src/components/FormattedData.tsx" codeFormat="typescript"
991
+ import React from "react";
992
+ import { FormattedDate, FormattedNumber, FormattedTime } from "react-intl";
307
993
 
308
- ## Updating or Adding New Translations
994
+ const FormattedData: React.FC = () => {
995
+ const today = new Date();
996
+ const price = 1234.56;
309
997
 
310
- 1. **Add or modify** content in any `*.content.*` file.
311
- 2. Rerun `intlayer build` to regenerate the JSON files under `./react-intl/messages`.
312
- 3. React (and react-intl) will pick up the updates next time you rebuild or reload your application.
998
+ return (
999
+ <div>
1000
+ <p>
1001
+ Date: <FormattedDate value={today} />
1002
+ </p>
1003
+ <p>
1004
+ Time: <FormattedTime value={today} />
1005
+ </p>
1006
+ <p>
1007
+ Price: <FormattedNumber value={price} style="currency" currency="USD" />
1008
+ </p>
1009
+ </div>
1010
+ );
1011
+ };
313
1012
 
314
- ---
1013
+ export default FormattedData;
1014
+ ```
315
1015
 
316
- ## TypeScript Integration (Optional)
1016
+ ### (Optional) Step 10: Handle Missing Translations
317
1017
 
318
- If you’re using TypeScript, Intlayer can **generate type definitions** for your translations.
1018
+ By default, react-intl will render the message ID if a translation is missing. You can customize this behavior:
319
1019
 
320
- - Make sure `tsconfig.json` includes your `types` folder (or whichever output folder Intlayer generates) in the `"include"` array.
1020
+ ```typescript fileName="src/main.tsx" codeFormat="typescript"
1021
+ import React from "react";
1022
+ import ReactDOM from "react-dom/client";
1023
+ import { IntlProvider } from "react-intl";
1024
+ import App from "./App";
321
1025
 
322
- ```json5
1026
+ // Custom handler for missing translations
1027
+ const onError = (err: any) => {
1028
+ if (err.code === "MISSING_TRANSLATION") {
1029
+ console.warn("Missing translation", err.message);
1030
+ return;
1031
+ }
1032
+ throw err;
1033
+ };
1034
+
1035
+ ReactDOM.createRoot(document.getElementById("root")!).render(
1036
+ <React.StrictMode>
1037
+ <IntlProvider locale="en" messages={{}} onError={onError}>
1038
+ <App />
1039
+ </IntlProvider>
1040
+ </React.StrictMode>
1041
+ );
1042
+ ```
1043
+
1044
+ ### (Optional) Step 11: TypeScript Integration
1045
+
1046
+ Intlayer can generate TypeScript type definitions for your translations, providing compile-time type safety.
1047
+
1048
+ Ensure your `tsconfig.json` includes the generated types:
1049
+
1050
+ ```json5 fileName="tsconfig.json"
323
1051
  {
324
1052
  "compilerOptions": {
325
- // ...
1053
+ // ... your other compiler options
326
1054
  },
327
- "include": ["src", "types"],
1055
+ "include": [
1056
+ "src",
1057
+ ".intlayer/**/*.ts", // Include Intlayer generated types
1058
+ ],
328
1059
  }
329
1060
  ```
330
1061
 
331
- The generated types can help detect missing translations or invalid keys in your React components at compile time.
1062
+ This enables autocompletion and compile-time checks for translation keys in your IDE.
332
1063
 
333
- ---
1064
+ ### Configure TypeScript
1065
+
1066
+ Intlayer uses module augmentation to get benefits of TypeScript and make your codebase stronger.
1067
+
1068
+ ![Autocompletion](https://github.com/aymericzip/intlayer/blob/main/docs/assets/autocompletion.png?raw=true)
334
1069
 
335
- ## Git Configuration
1070
+ ![Translation Error](https://github.com/aymericzip/intlayer/blob/main/docs/assets/translation_error.png?raw=true)
336
1071
 
337
- It’s common to **exclude** Intlayer’s internal build artifacts from version control. In your `.gitignore`, add:
1072
+ Ensure your TypeScript configuration includes the autogenerated types.
338
1073
 
339
- ```plaintext
340
- # Ignore intlayer build artifacts
1074
+ ```json5 fileName="tsconfig.json"
1075
+ {
1076
+ // ... Your existing TypeScript configurations
1077
+ "include": [
1078
+ // ... Your existing TypeScript configurations
1079
+ ".intlayer/**/*.ts", // Include the auto-generated types
1080
+ ],
1081
+ }
1082
+ ```
1083
+
1084
+ ### Git Configuration
1085
+
1086
+ It's recommended to ignore the files generated by Intlayer. This allows you to avoid committing them to your Git repository.
1087
+
1088
+ Add the following to your `.gitignore` file:
1089
+
1090
+ ```plaintext fileName=".gitignore"
1091
+ # Ignore the files generated by Intlayer
341
1092
  .intlayer
342
- react-intl
1093
+
1094
+ # Optionally ignore generated message files if they're rebuilt in CI/CD
1095
+ intl
343
1096
  ```
344
1097
 
345
- Depending on your workflow, you may also want to ignore or commit the final dictionaries in `./react-intl/messages`. If your CI/CD pipeline regenerates them, you can safely ignore them; otherwise, commit them if you need them for production deployments.
1098
+ Depending on your workflow, you may want to commit the `./intl/messages` files if they're needed for production deployments. If your CI/CD pipeline regenerates them, you can safely ignore them.