@intlayer/docs 9.3.1 → 9.3.3

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 (151) hide show
  1. package/blog/ar/nextjs-multilingual-seo-comparison.md +10 -10
  2. package/blog/de/nextjs-multilingual-seo-comparison.md +9 -9
  3. package/blog/en/nextjs-multilingual-seo-comparison.md +10 -10
  4. package/blog/en-GB/nextjs-multilingual-seo-comparison.md +10 -10
  5. package/blog/es/nextjs-multilingual-seo-comparison.md +10 -10
  6. package/blog/fr/nextjs-multilingual-seo-comparison.md +10 -10
  7. package/blog/hi/nextjs-multilingual-seo-comparison.md +10 -10
  8. package/blog/id/nextjs-multilingual-seo-comparison.md +10 -10
  9. package/blog/it/nextjs-multilingual-seo-comparison.md +10 -10
  10. package/blog/ja/nextjs-multilingual-seo-comparison.md +9 -9
  11. package/blog/ko/nextjs-multilingual-seo-comparison.md +9 -9
  12. package/blog/pl/nextjs-multilingual-seo-comparison.md +10 -10
  13. package/blog/pt/nextjs-multilingual-seo-comparison.md +9 -9
  14. package/blog/ru/nextjs-multilingual-seo-comparison.md +9 -9
  15. package/blog/tr/nextjs-multilingual-seo-comparison.md +9 -9
  16. package/blog/uk/nextjs-multilingual-seo-comparison.md +10 -10
  17. package/blog/vi/nextjs-multilingual-seo-comparison.md +10 -10
  18. package/blog/zh/nextjs-multilingual-seo-comparison.md +10 -10
  19. package/dist/cjs/generated/docs.entry.cjs +20 -0
  20. package/dist/cjs/generated/docs.entry.cjs.map +1 -1
  21. package/dist/esm/generated/docs.entry.mjs +20 -0
  22. package/dist/esm/generated/docs.entry.mjs.map +1 -1
  23. package/dist/types/generated/docs.entry.d.ts +1 -0
  24. package/dist/types/generated/docs.entry.d.ts.map +1 -1
  25. package/docs/ar/bundle_optimization.md +1 -1
  26. package/docs/ar/configuration.md +32 -9
  27. package/docs/ar/dictionary/content_file.md +0 -22
  28. package/docs/ar/dictionary/function_fetching.md +23 -0
  29. package/docs/ar/eslint.md +336 -0
  30. package/docs/ar/intlayer_with_react_router_v7_fs_routes.md +1 -1
  31. package/docs/bn/configuration.md +34 -9
  32. package/docs/bn/eslint.md +336 -0
  33. package/docs/cs/bundle_optimization.md +1 -1
  34. package/docs/cs/configuration.md +33 -9
  35. package/docs/cs/eslint.md +336 -0
  36. package/docs/de/bundle_optimization.md +1 -1
  37. package/docs/de/configuration.md +34 -9
  38. package/docs/de/dictionary/content_file.md +0 -22
  39. package/docs/de/dictionary/function_fetching.md +23 -0
  40. package/docs/de/eslint.md +336 -0
  41. package/docs/en/bundle_optimization.md +1 -1
  42. package/docs/en/configuration.md +34 -9
  43. package/docs/en/dictionary/content_file.md +0 -22
  44. package/docs/en/dictionary/function_fetching.md +23 -0
  45. package/docs/en/eslint.md +336 -0
  46. package/docs/en/packages/intlayer/getLocalizedPath.md +70 -19
  47. package/docs/en-GB/configuration.md +33 -9
  48. package/docs/en-GB/dictionary/content_file.md +0 -22
  49. package/docs/en-GB/dictionary/function_fetching.md +23 -0
  50. package/docs/en-GB/eslint.md +336 -0
  51. package/docs/en-GB/intlayer_with_create_react_app.md +32 -35
  52. package/docs/en-GB/intlayer_with_react_router_v7_fs_routes.md +1 -1
  53. package/docs/es/bundle_optimization.md +1 -1
  54. package/docs/es/configuration.md +35 -9
  55. package/docs/es/dictionary/content_file.md +0 -22
  56. package/docs/es/dictionary/function_fetching.md +23 -0
  57. package/docs/es/eslint.md +336 -0
  58. package/docs/fr/bundle_optimization.md +1 -1
  59. package/docs/fr/configuration.md +35 -9
  60. package/docs/fr/dictionary/content_file.md +0 -22
  61. package/docs/fr/dictionary/function_fetching.md +23 -0
  62. package/docs/fr/eslint.md +336 -0
  63. package/docs/hi/configuration.md +35 -9
  64. package/docs/hi/dictionary/content_file.md +0 -22
  65. package/docs/hi/dictionary/function_fetching.md +23 -0
  66. package/docs/hi/eslint.md +336 -0
  67. package/docs/hi/intlayer_with_react_router_v7_fs_routes.md +1 -1
  68. package/docs/hi/intlayer_with_vite+svelte.md +2 -2
  69. package/docs/id/configuration.md +35 -9
  70. package/docs/id/dictionary/content_file.md +0 -22
  71. package/docs/id/dictionary/function_fetching.md +23 -0
  72. package/docs/id/eslint.md +336 -0
  73. package/docs/it/bundle_optimization.md +1 -1
  74. package/docs/it/configuration.md +35 -9
  75. package/docs/it/dictionary/content_file.md +0 -22
  76. package/docs/it/dictionary/function_fetching.md +23 -0
  77. package/docs/it/eslint.md +336 -0
  78. package/docs/ja/configuration.md +30 -9
  79. package/docs/ja/dictionary/content_file.md +0 -22
  80. package/docs/ja/dictionary/function_fetching.md +23 -0
  81. package/docs/ja/eslint.md +336 -0
  82. package/docs/ja/intlayer_with_react_router_v7.md +1 -146
  83. package/docs/ja/intlayer_with_vite+react.md +5 -1
  84. package/docs/ko/configuration.md +31 -9
  85. package/docs/ko/dictionary/content_file.md +0 -22
  86. package/docs/ko/dictionary/function_fetching.md +23 -0
  87. package/docs/ko/eslint.md +336 -0
  88. package/docs/ko/intlayer_with_lynx+react.md +4 -0
  89. package/docs/ko/intlayer_with_react_router_v7_fs_routes.md +1 -1
  90. package/docs/ko/intlayer_with_storybook.md +5 -5
  91. package/docs/nl/configuration.md +33 -9
  92. package/docs/nl/eslint.md +336 -0
  93. package/docs/pl/bundle_optimization.md +1 -1
  94. package/docs/pl/configuration.md +34 -9
  95. package/docs/pl/dictionary/content_file.md +0 -22
  96. package/docs/pl/dictionary/function_fetching.md +23 -0
  97. package/docs/pl/eslint.md +336 -0
  98. package/docs/pl/intlayer_with_astro.md +1 -114
  99. package/docs/pl/migration_from_i18next_to_intlayer.md +4 -0
  100. package/docs/pl/migration_from_next-i18next_to_intlayer.md +8 -4
  101. package/docs/pl/migration_from_next-intl_to_intlayer.md +11 -5
  102. package/docs/pl/migration_from_nuxtjs_i18n_to_intlayer.md +8 -4
  103. package/docs/pl/migration_from_react-i18next_to_intlayer.md +8 -4
  104. package/docs/pl/migration_from_vue-i18n_to_intlayer.md +4 -0
  105. package/docs/pt/bundle_optimization.md +1 -1
  106. package/docs/pt/configuration.md +34 -9
  107. package/docs/pt/dictionary/content_file.md +0 -22
  108. package/docs/pt/dictionary/function_fetching.md +23 -0
  109. package/docs/pt/eslint.md +336 -0
  110. package/docs/pt/intlayer_with_astro.md +1 -114
  111. package/docs/ru/bundle_optimization.md +1 -1
  112. package/docs/ru/configuration.md +34 -9
  113. package/docs/ru/dictionary/content_file.md +0 -22
  114. package/docs/ru/dictionary/function_fetching.md +23 -0
  115. package/docs/ru/eslint.md +336 -0
  116. package/docs/tr/bundle_optimization.md +1 -1
  117. package/docs/tr/configuration.md +33 -9
  118. package/docs/tr/dictionary/content_file.md +0 -22
  119. package/docs/tr/dictionary/function_fetching.md +23 -0
  120. package/docs/tr/eslint.md +336 -0
  121. package/docs/uk/configuration.md +35 -9
  122. package/docs/uk/dictionary/content_file.md +0 -22
  123. package/docs/uk/dictionary/function_fetching.md +23 -0
  124. package/docs/uk/eslint.md +336 -0
  125. package/docs/uk/packages/angular-intlayer/exports.md +2 -2
  126. package/docs/ur/configuration.md +35 -9
  127. package/docs/ur/eslint.md +336 -0
  128. package/docs/vi/bundle_optimization.md +1 -1
  129. package/docs/vi/configuration.md +33 -9
  130. package/docs/vi/dictionary/content_file.md +0 -22
  131. package/docs/vi/dictionary/function_fetching.md +23 -0
  132. package/docs/vi/eslint.md +336 -0
  133. package/docs/zh/bundle_optimization.md +1 -1
  134. package/docs/zh/configuration.md +29 -9
  135. package/docs/zh/dictionary/content_file.md +0 -22
  136. package/docs/zh/dictionary/function_fetching.md +23 -0
  137. package/docs/zh/eslint.md +336 -0
  138. package/docs/zh/intlayer_with_create_react_app.md +4 -0
  139. package/docs/zh/intlayer_with_lynx+react.md +4 -0
  140. package/docs/zh/intlayer_with_nextjs_14.md +0 -2
  141. package/docs/zh/intlayer_with_nextjs_15.md +0 -2
  142. package/docs/zh/intlayer_with_nextjs_page_router.md +0 -2
  143. package/docs/zh/intlayer_with_nuxt.md +1 -1
  144. package/docs/zh/intlayer_with_react_router_v7.md +4 -0
  145. package/docs/zh/intlayer_with_react_router_v7_fs_routes.md +4 -0
  146. package/docs/zh/intlayer_with_solid_start.md +1 -1
  147. package/docs/zh/intlayer_with_vite+vue.md +0 -2
  148. package/docs/zh-TW/bundle_optimization.md +1 -1
  149. package/docs/zh-TW/eslint.md +336 -0
  150. package/package.json +7 -7
  151. package/src/generated/docs.entry.ts +20 -0
@@ -0,0 +1,336 @@
1
+ ---
2
+ createdAt: 2026-08-12
3
+ updatedAt: 2026-08-13
4
+ title: ESLint Plugin | Lint rules for Intlayer
5
+ description: Catch hardcoded strings, dynamic calls the Intlayer compiler cannot optimize, and unused dictionary content, with eslint-plugin-intlayer. Works with ESLint and oxlint, across React, Vue, Svelte, Angular and Astro.
6
+ keywords:
7
+ - Intlayer
8
+ - ESLint
9
+ - oxlint
10
+ - Linting
11
+ - i18n
12
+ - Internationalization
13
+ - no-raw-text
14
+ - Hardcoded strings
15
+ - Unused translations
16
+ - Dead content
17
+ - React
18
+ - Vue
19
+ - Svelte
20
+ - Angular
21
+ slugs:
22
+ - doc
23
+ - eslint
24
+ history:
25
+ - version: 9.3.1
26
+ date: 2026-08-12
27
+ changes: "Init history"
28
+ author: aymericzip
29
+ ---
30
+
31
+ # ESLint x OXLint Plugin
32
+
33
+ `eslint-plugin-intlayer` catches the kinds of i18n mistake TypeScript cannot:
34
+
35
+ 1. **Hardcoded text** that never made it into a dictionary.
36
+ 2. **Dynamic calls** that type-check and run, but that the Intlayer compiler cannot optimize.
37
+ 3. **Dead content** — dictionaries and fields nothing in the project reads (opt-in).
38
+
39
+ Unknown dictionary keys, unknown field paths and missing locales are already compile errors, so the plugin does not repeat them.
40
+
41
+ ## Installation
42
+
43
+ ```bash packageManager="npm"
44
+ npm install --save-dev eslint-plugin-intlayer
45
+ ```
46
+
47
+ ```bash packageManager="pnpm"
48
+ pnpm add --save-dev eslint-plugin-intlayer
49
+ ```
50
+
51
+ ```bash packageManager="yarn"
52
+ yarn add --dev eslint-plugin-intlayer
53
+ ```
54
+
55
+ Requires ESLint 9 or later (flat config). ESLint 10 is supported.
56
+
57
+ ## Usage
58
+
59
+ The plugin runs in both ESLint and [oxlint](https://oxc.rs) — the same rules, the same options.
60
+
61
+ <Tabs defaultTab="eslint">
62
+ <Tab label="ESLint" value="eslint">
63
+
64
+ ```javascript fileName="eslint.config.mjs"
65
+ import intlayer from "eslint-plugin-intlayer";
66
+
67
+ export default [...intlayer.configs.recommended];
68
+ ```
69
+
70
+ Or spread a config and set the severities yourself:
71
+
72
+ ```javascript fileName="eslint.config.mjs"
73
+ import intlayer from "eslint-plugin-intlayer";
74
+
75
+ export default [
76
+ ...intlayer.configs.recommended,
77
+ {
78
+ rules: {
79
+ "intlayer/no-raw-text": "warn",
80
+ "intlayer/static-dictionary-key": "error",
81
+ "intlayer/no-dynamic-field-access": "error",
82
+ "intlayer/enforce-adapter-import": "warn",
83
+ "intlayer/no-unused-content": "warn",
84
+ },
85
+ },
86
+ ];
87
+ ```
88
+
89
+ </Tab>
90
+ <Tab label="oxlint" value="oxlint">
91
+
92
+ ```json fileName=".oxlintrc.json"
93
+ {
94
+ "jsPlugins": ["eslint-plugin-intlayer"],
95
+ "rules": {
96
+ "intlayer/no-raw-text": "warn",
97
+ "intlayer/static-dictionary-key": "error",
98
+ "intlayer/no-dynamic-field-access": "error",
99
+ "intlayer/enforce-adapter-import": "warn"
100
+ }
101
+ }
102
+ ```
103
+
104
+ Two caveats: oxlint's JS plugin support is still alpha, and oxlint does not support custom parsers — so `.vue`, `.svelte`, `.astro` and Angular templates are not linted there. Run oxlint over your JS/TS/JSX files and keep ESLint for the rest.
105
+
106
+ `no-unused-content` is left out above on purpose: it needs the working directory and the linted file path from the rule context, which the alpha JS plugin bridge does not guarantee. Run it under ESLint.
107
+
108
+ </Tab>
109
+ </Tabs>
110
+
111
+ ### Configs
112
+
113
+ | Config | `no-raw-text` | `static-dictionary-key` | `no-dynamic-field-access` | `enforce-adapter-import` | `no-unused-content` |
114
+ | --------------- | -------------------------- | ----------------------- | ------------------------- | ------------------------ | ------------------- |
115
+ | `recommended` | warn | error | error | off | off |
116
+ | `strict` | error (+ non-JSX literals) | error | error | error | off |
117
+ | `contract-only` | off | error | error | off | off |
118
+
119
+ `recommended` keeps `no-raw-text` at `warn` on purpose: pointing it at an existing codebase surfaces every untranslated string at once, which should not break your build on day one.
120
+
121
+ `enforce-adapter-import` is off by default — enable it explicitly if you want it.
122
+
123
+ `no-unused-content` is off in every config, `strict` included. It is the one rule that reads your Intlayer configuration and walks your source files from disk, so turning it on should be a deliberate choice rather than something a preset does for you.
124
+
125
+ ## Rules
126
+
127
+ ### `no-raw-text`
128
+
129
+ Reports user-facing text that is not declared in a dictionary. It uses the same detection as `intlayer extract`, so brand names, CSS classes and technical identifiers are ignored.
130
+
131
+ ```jsx
132
+ // ✗ Reported
133
+ <h1>Welcome to our documentation</h1>
134
+ <input placeholder="Enter your email address" />
135
+
136
+ // ✓ Fine
137
+ const { title } = useIntlayer("home");
138
+ <h1>{title}</h1>
139
+ ```
140
+
141
+ Content declaration files (`*.content.ts`, …) are skipped.
142
+
143
+ To fix a whole file at once, run `npx intlayer extract` and let the compiler move the strings into a dictionary for you.
144
+
145
+ **Options**
146
+
147
+ ```javascript fileName="eslint.config.mjs"
148
+ {
149
+ "intlayer/no-raw-text": [
150
+ "warn",
151
+ {
152
+ // Attributes whose value is user-facing text.
153
+ // Default: title, placeholder, alt, aria-label, label
154
+ attributes: ["title", "placeholder", "alt", "aria-label", "label"],
155
+
156
+ // Elements whose content is never user-facing text.
157
+ // Default: code, pre, script, style
158
+ ignoreElements: ["code", "pre", "script", "style"],
159
+
160
+ // Regular expressions for text to never report.
161
+ ignorePatterns: ["^Powered by"],
162
+
163
+ // Also report string literals outside markup. Default: false
164
+ includeStringLiterals: false,
165
+ },
166
+ ],
167
+ }
168
+ ```
169
+
170
+ ### `static-dictionary-key`
171
+
172
+ Requires the dictionary key to be a string literal.
173
+
174
+ The compiler can only pre-load a dictionary when it can read the key directly at the call site. With a computed key it silently skips the optimization and bundles every dictionary instead.
175
+
176
+ ```typescript
177
+ // ✗ Reported
178
+ useIntlayer(dictionaryKey);
179
+ useIntlayer(`home-${suffix}`);
180
+ getTranslations({ namespace: page });
181
+
182
+ // ✗ A variable is still not a literal
183
+ const key = "home";
184
+ useIntlayer(key);
185
+
186
+ // ✓ Fine
187
+ useIntlayer("home");
188
+ getTranslations({ namespace: "home" });
189
+ ```
190
+
191
+ This applies to `useIntlayer`, `getIntlayer` and every compat adapter (`useTranslation`, `useTranslations`, `formatMessage`, `<FormattedMessage id>`, `<Trans i18nKey>`, …).
192
+
193
+ ### `no-dynamic-field-access`
194
+
195
+ Requires the field you read from a dictionary to be statically known.
196
+
197
+ The compiler removes fields it does not see used. A computed access is invisible to it, so the read can return `undefined` at runtime.
198
+
199
+ ```typescript
200
+ // ✗ Reported
201
+ const content = useIntlayer("home");
202
+ content[fieldName];
203
+
204
+ const t = useTranslations("home");
205
+ t(messageKey);
206
+
207
+ // ✓ Fine
208
+ content.title;
209
+ content["title"];
210
+ content.items[0];
211
+ t("hero.title");
212
+ ```
213
+
214
+ ### `enforce-adapter-import`
215
+
216
+ Prefers the `@intlayer/*` compat adapter over the original package. The original only resolves to Intlayer when the bundler alias is configured; the adapter always does. Autofixable with `--fix`.
217
+
218
+ ```typescript
219
+ // ✗ Reported
220
+ import { useTranslation } from "react-i18next";
221
+ import { getTranslations } from "next-intl/server";
222
+
223
+ // ✓ Fine
224
+ import { useTranslation } from "@intlayer/react-i18next";
225
+ import { getTranslations } from "@intlayer/next-intl/server";
226
+ ```
227
+
228
+ ### `no-unused-content`
229
+
230
+ **Off by default.** Reports content nothing in your project reads, plus dictionary keys declared in more than one place.
231
+
232
+ ```typescript fileName="src/home.content.ts"
233
+ export default {
234
+ key: "home", // ✗ Reported when no caller anywhere asks for "home"
235
+ content: {
236
+ title: t({ "en-GB": "Title", en: "Title" }),
237
+
238
+ // ✗ Reported when nothing reads `hero`
239
+ hero: {
240
+ subtitle: t({ "en-GB": "Subtitle", en: "Subtitle" }),
241
+ },
242
+ },
243
+ };
244
+ ```
245
+
246
+ Unlike the other rules, this one cannot answer from the file in front of it — a field is unused only relative to the whole project. On the first content declaration of a lint run it loads your Intlayer configuration, globs the source files that configuration declares (`build.traversePattern`, `compiler.transformPattern`) and runs the same usage analyser that powers `@intlayer/lsp` and the "unused" strikethrough in the VS Code extension. The result is cached for `cacheTtl` milliseconds, so the scan happens once per run rather than once per file.
247
+
248
+ **Options**
249
+
250
+ ```javascript fileName="eslint.config.mjs"
251
+ {
252
+ "intlayer/no-unused-content": [
253
+ "warn",
254
+ {
255
+ // Report dictionary keys nothing references. Default: true
256
+ reportUnusedDictionaries: true,
257
+
258
+ // Report content fields nothing reads. Default: true
259
+ reportUnusedFields: true,
260
+
261
+ // Report keys declared in more than one place. Default: true
262
+ reportDuplicateKeys: true,
263
+
264
+ // Regular expressions for field paths to never report.
265
+ ignoreFields: ["^meta"],
266
+
267
+ // Project root the scan starts from. Default: ESLint's working directory
268
+ baseDir: process.cwd(),
269
+
270
+ // How long one project scan is reused, in ms. Default: 30000
271
+ cacheTtl: 30000,
272
+ },
273
+ ],
274
+ }
275
+ ```
276
+
277
+ Lower `cacheTtl` when you lint from a long-lived editor server and want your edits reflected sooner; set `baseDir` when a single lint run spans several Intlayer projects in a monorepo.
278
+
279
+ > **It errs towards silence.** A false positive here deletes a translation, so nothing is reported when the dictionary is consumed in a way the analysis cannot follow: the content object passed on as a whole, a translator function bound from it (`const t = useTranslations("home")`), a declaration reached through a direct import (`useDictionary(myDictionary)`), a `nest()` from another dictionary, or a field list made non-exhaustive by a spread. Single-file components (`.vue`, `.svelte`, `.astro`) count as using every field of the dictionaries they mention, because their script blocks are not parsed here.
280
+
281
+ `reportDuplicateKeys` reads the unmerged dictionaries the build writes under `.intlayer/`, so it stays quiet until the project has been built at least once. Two declarations sharing a key are merged, which is a legitimate pattern — the report exists because a field defined on both sides silently keeps only one of the two values.
282
+
283
+ The analyser is loaded from `@intlayer/lsp`, which ships as ESM. The rule therefore needs a Node version that can `require()` an ES module — Node 20.19+ or 22.12+. On anything older it reports nothing rather than failing the lint run.
284
+
285
+ ## Frameworks
286
+
287
+ Every rule works across all Intlayer integrations, including inside Vue, Svelte and Angular templates. You only need to tell ESLint which parser reads each file type.
288
+
289
+ | Framework | Files | Parser |
290
+ | ------------------------- | ----------------- | --------------------------------- |
291
+ | React, Preact, Solid, Lit | `.jsx` `.tsx` | `typescript-eslint` |
292
+ | Next.js | `.jsx` `.tsx` | `typescript-eslint` |
293
+ | Vue, Nuxt | `.vue` | `vue-eslint-parser` |
294
+ | Svelte, SvelteKit | `.svelte` | `svelte-eslint-parser` |
295
+ | Angular | `.ts` | `typescript-eslint` |
296
+ | Angular templates | `.component.html` | `@angular-eslint/template-parser` |
297
+ | Astro | `.astro` | `astro-eslint-parser` |
298
+
299
+ ```javascript fileName="eslint.config.mjs"
300
+ import intlayer from "eslint-plugin-intlayer";
301
+ import tseslint from "typescript-eslint";
302
+ import vueParser from "vue-eslint-parser";
303
+ import svelteParser from "svelte-eslint-parser";
304
+ import angularTemplateParser from "@angular-eslint/template-parser";
305
+
306
+ export default [
307
+ ...intlayer.configs.recommended,
308
+
309
+ {
310
+ files: ["**/*.{ts,tsx,jsx}"],
311
+ languageOptions: { parser: tseslint.parser },
312
+ },
313
+ {
314
+ files: ["**/*.vue"],
315
+ languageOptions: {
316
+ parser: vueParser,
317
+ parserOptions: { parser: tseslint.parser },
318
+ },
319
+ },
320
+ {
321
+ files: ["**/*.svelte"],
322
+ languageOptions: {
323
+ parser: svelteParser,
324
+ parserOptions: { parser: tseslint.parser },
325
+ },
326
+ },
327
+ {
328
+ files: ["**/*.component.html"],
329
+ languageOptions: { parser: angularTemplateParser },
330
+ },
331
+ ];
332
+ ```
333
+
334
+ Install only the parsers your project needs.
335
+
336
+ > **Known limitation.** In Vue and Angular templates, an expression such as `{{ content[key] }}` is not checked by `no-dynamic-field-access`. Dynamic reads written in the script block are caught normally.
@@ -33,59 +33,56 @@ author: aymericzip
33
33
 
34
34
  See [Application Template](https://github.com/aymericzip/intlayer-react-cra-template) on GitHub.
35
35
 
36
- ## Step-by-Step Guide to Set Up Intlayer in a React Application
36
+ ## Why Intlayer over alternatives?
37
37
 
38
- <Steps>
38
+ Compared to main solutions like `react-i18next` or `i18next`, Intlayer is a solution that comes with integrated optimisations such as:
39
39
 
40
- <Step number={1} title="Install Dependencies">
40
+ <AccordionGroup>
41
41
 
42
- Install the necessary packages using npm:
42
+ <Accordion header="Full React coverage">
43
43
 
44
- ```bash packageManager="npm"
45
- npx intlayer init --interactive
46
- ```
44
+ Intlayer is optimised to work perfectly with React by offering **component-level content scoping**, **lazy-loaded translations**, and all the features needed for scaling internationalisation (i18n).
47
45
 
48
- ```bash packageManager="pnpm"
49
- pnpm dlx intlayer@canary init --interactive
50
- ```
46
+ </Accordion>
51
47
 
52
- ```bash packageManager="yarn"
53
- yarn dlx intlayer@canary init --interactive
54
- ```
48
+ <Accordion header="Bundle size">
55
49
 
56
- ```bash packageManager="bun"
57
- bunx intlayer@canary init --interactive
58
- ```
50
+ Instead of loading massive JSON files into your pages, load only the necessary content. Intlayer helps **reduce your bundle and page sizes by up to 50%**.
59
51
 
60
- > the `--interactive` flag is optional. Use `intlayer-cli init` if you're an AI agent.
52
+ </Accordion>
61
53
 
62
- > This command will detect your environment and install the required packages. For example:
54
+ <Accordion header="Maintainability">
63
55
 
64
- ```bash packageManager="npm"
65
- npm install intlayer react-intlayer react-scripts-intlayer
66
- ```
56
+ Scoping your application's content **facilitates maintenance** for large-scale applications. You can duplicate or delete a single feature folder without the mental burden of reviewing your entire content codebase. Additionally, Intlayer is **fully typed** to ensure your content's accuracy.
67
57
 
68
- ```bash packageManager="pnpm"
69
- pnpm add intlayer react-intlayer react-scripts-intlayer
70
- ```
58
+ </Accordion>
71
59
 
72
- ```bash packageManager="yarn"
73
- yarn add intlayer react-intlayer react-scripts-intlayer
74
- ```
60
+ <Accordion header="AI Agent">
75
61
 
76
- ```bash packageManager="bun"
77
- bun add intlayer react-intlayer react-scripts-intlayer
78
- ```
62
+ Co-locating content **reduces the context needed** by Large Language Models (LLMs). Intlayer also comes with a suite of tools, such as a **CLI** to test for missing translations, **[LSP](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/lsp.md)**, **[MCP](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/mcp_server.md)**, and **[agent skills](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/agent_skills.md)**, to make the developer experience (DX) even smoother for AI agents.
79
63
 
80
- - **intlayer**
64
+ </Accordion>
81
65
 
82
- The core package that provides internationalisation tools for configuration management, translation, [content declaration](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/dictionary/content_file.md), transpilation, and [CLI commands](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/cli/index.md).
66
+ <Accordion header="Automation">
83
67
 
84
- - **react-intlayer**
68
+ Use automation to translate in your CI/CD pipeline using the LLM of your choice at the cost of your AI provider. Intlayer also offers a **compiler** to automate content extraction, as well as a [web platform](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/intlayer_CMS.md) to help **translate in the background**.
85
69
 
86
- The package that integrates Intlayer with React applications. It provides context providers and hooks for React internationalisation.
70
+ </Accordion>
87
71
 
88
- - **react-scripts-intlayer**
72
+ <Accordion header="Performance">
73
+
74
+ Connecting massive JSON files to components can lead to performance and reactivity issues. Intlayer optimises your content loading at build time.
75
+
76
+ </Accordion>
77
+
78
+ <Accordion header="Scaling with none-dev">
79
+
80
+ More than just an i18n solution, Intlayer provides a **self-hosted [visual editor](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/intlayer_visual_editor.md)** and a **[full CMS](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/intlayer_CMS.md)** to help you manage your multilingual content in **real-time**, making collaboration with translators, copywriters, and other team members seamless. Content can be stored locally and/or remotely.
81
+
82
+ </Accordion>
83
+ </AccordionGroup>
84
+
85
+ ---
89
86
 
90
87
  ## Step-by-Step Guide to Set Up Intlayer in a React Application
91
88
 
@@ -161,7 +161,7 @@ The core package that provides internationalisation tools for configuration mana
161
161
 
162
162
  </Step>
163
163
 
164
- </Steps>
164
+ <Step number={5} title="Create Layout Components">
165
165
 
166
166
  #### File Structure
167
167
 
@@ -159,7 +159,7 @@ pnpm add -D webpack-bundle-analyzer
159
159
  bun add -d webpack-bundle-analyzer
160
160
  ```
161
161
 
162
- ```typescript fileName="webpack.config.ts
162
+ ```typescript fileName="webpack.config.ts"
163
163
  import { BundleAnalyzerPlugin } from "webpack-bundle-analyzer";
164
164
 
165
165
  export default {
@@ -478,6 +478,30 @@ const config: IntlayerConfig = {
478
478
  */
479
479
  purge: true,
480
480
 
481
+ /**
482
+ * Agrupar los fragmentos de diccionario por configuración regional según el
483
+ * límite de división de código que los usa, para que una página cargada de
484
+ * forma diferida obtenga su contenido en una sola petición.
485
+ * Predeterminado: true
486
+ *
487
+ * Nota:
488
+ * - Solo se aplica a los diccionarios que usan `importMode: 'dynamic'`.
489
+ */
490
+ chunkGrouping: true,
491
+
492
+ /**
493
+ * Cargar un diccionario junto con el fragmento que lo usa, en lugar de
494
+ * obtenerlo una vez que ese fragmento se renderiza. Los lectores se renderizan
495
+ * de forma síncrona en lugar de suspenderse, por lo que navegar ya no muestra
496
+ * un parpadeo de carga.
497
+ * Predeterminado: true
498
+ *
499
+ * Nota:
500
+ * - Solo se espera la configuración regional resuelta, por lo que la página
501
+ * solo descarga el idioma que muestra.
502
+ */
503
+ dictionariesPreload: true,
504
+
481
505
  /**
482
506
  * Formato de salida para los archivos de diccionario generados.
483
507
  * Predeterminado: ['cjs', 'esm']
@@ -1056,15 +1080,17 @@ Las opciones de compilación se aplican a los complementos `@intlayer/babel` y `
1056
1080
 
1057
1081
  > Cuando se optimiza, Intlayer reemplazará las llamadas a diccionarios para optimizar el chunking, de modo que el bundle final solo importe los diccionarios que realmente se usan.
1058
1082
 
1059
- | Campo | Descripción | Tipo | Predeterminado | Ejemplo | Nota |
1060
- | ----------------- | -------------------------------------------------------------------------------- | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1061
- | `mode` | Controla el modo de compilación. | `'auto'` &#124; <br/> `'manual'` | `'auto'` | `'manual'` | • `'auto'`: compilación activada automáticamente durante la compilación de la aplicación.<br/>• `'manual'`: solo se ejecuta cuando se lanza explícitamente el comando de compilación.<br/>• Se puede usar para desactivar compilaciones de diccionarios (p. ej. para evitar ejecución en entornos de Node.js). |
1062
- | `optimize` | Controla si la compilación debe optimizarse. | `boolean` | `undefined` | `process.env.NODE_ENV === 'production'` | • Si no se define, la optimización se dispara al compilar el framework (Vite/Next.js).<br/>• `true` fuerza la optimización incluso en modo dev.<br/>• `false` la desactiva.<br/>• Activo, reemplaza las llamadas a diccionarios para optimizar el chunking.<br/>• Depende de los plugins `@intlayer/babel` y `@intlayer/swc`. |
1063
- | `minify` | Minificar los diccionarios para reducir el tamaño del bundle. | `boolean` | `false` | | • Indica si el bundle debe ser minificado.<br/>• Por defecto: `true` en producción.<br/>• Esta opción será ignorada si `optimize` está desactivado.<br/>• Esta opción será ignorada si `editor.enabled` es verdadero. |
1064
- | `purge` | Purgar las claves no utilizadas en los diccionarios. | `boolean` | `false` | | • Indica si el bundle debe ser purgado.<br/>• Por defecto: `true` en producción.<br/>• Esta opción será ignorada si `optimize` está desactivado. |
1065
- | `checkTypes` | Indica si la compilación debe verificar tipos de TypeScript y registrar errores. | `boolean` | `false` | | Puede ralentizar la compilación. |
1066
- | `outputFormat` | Controla el formato de salida de los diccionarios. | `('esm' &#124; 'cjs')[]` | `['esm', 'cjs']` | `['cjs']` | |
1067
- | `traversePattern` | Patrones que definen qué archivos recorrer durante la optimización. | `string[]` | `['**/*.{tsx,ts,js,mjs,cjs,jsx,vue,svelte,svte}', '!**/node_modules/**', '!**/dist/**', '!**/.intlayer/**', '!**/*.config.*', '!**/*.test.*', '!**/*.spec.*', '!**/*.stories.*']` | `['src/**/*.{ts,tsx}', '../ui-library/**/*.{ts,tsx}', '!**/node_modules/**']` | Limite la optimización a los archivos relevantes para mejorar el rendimiento de compilación.<br/>• Se ignora si `optimize` está desactivado.<br/>• Usa patrones glob (glob patterns). |
1083
+ | Campo | Descripción | Tipo | Predeterminado | Ejemplo | Nota |
1084
+ | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1085
+ | `mode` | Controla el modo de compilación. | `'auto'` &#124; <br/> `'manual'` | `'auto'` | `'manual'` | • `'auto'`: compilación activada automáticamente durante la compilación de la aplicación.<br/>• `'manual'`: solo se ejecuta cuando se lanza explícitamente el comando de compilación.<br/>• Se puede usar para desactivar compilaciones de diccionarios (p. ej. para evitar ejecución en entornos de Node.js). |
1086
+ | `optimize` | Controla si la compilación debe optimizarse. | `boolean` | `undefined` | `process.env.NODE_ENV === 'production'` | • Si no se define, la optimización se dispara al compilar el framework (Vite/Next.js).<br/>• `true` fuerza la optimización incluso en modo dev.<br/>• `false` la desactiva.<br/>• Activo, reemplaza las llamadas a diccionarios para optimizar el chunking.<br/>• Depende de los plugins `@intlayer/babel` y `@intlayer/swc`. |
1087
+ | `minify` | Minificar los diccionarios para reducir el tamaño del bundle. | `boolean` | `false` | | • Indica si el bundle debe ser minificado.<br/>• Por defecto: `true` en producción.<br/>• Esta opción será ignorada si `optimize` está desactivado.<br/>• Esta opción será ignorada si `editor.enabled` es verdadero. |
1088
+ | `purge` | Purgar las claves no utilizadas en los diccionarios. | `boolean` | `false` | | • Indica si el bundle debe ser purgado.<br/>• Por defecto: `true` en producción.<br/>• Esta opción será ignorada si `optimize` está desactivado. |
1089
+ | `checkTypes` | Indica si la compilación debe verificar tipos de TypeScript y registrar errores. | `boolean` | `false` | | Puede ralentizar la compilación. |
1090
+ | `chunkGrouping` | Indica si se deben agrupar los fragmentos de diccionario por configuración regional según el límite de división de código que los usa. | `boolean` | `true` | | • Sin agrupación, una página compuesta por muchos componentes emite una petición por diccionario.<br/>• Los diccionarios alcanzados desde varios límites pasan a un fragmento compartido, por lo que ninguna página incluye el contenido de otra.<br/>• Solo se aplica a los diccionarios que usan `importMode: 'dynamic'`.<br/>• Solo se aplica a la compilación del cliente, y solo al empaquetar (no en desarrollo). |
1091
+ | `dictionariesPreload` | Indica si un diccionario debe cargarse junto con el fragmento que lo usa, en lugar de obtenerse una vez que ese fragmento se renderiza. | `boolean` | `true` | | El punto de entrada generado espera la configuración regional de navegación en el nivel superior, por lo que una ruta cargada de forma diferida no se considera cargada hasta que su contenido está disponible.<br/>• Los lectores se renderizan de forma síncrona en lugar de suspenderse, por lo que navegar ya no muestra un parpadeo de carga.<br/>• Solo se espera la configuración regional resuelta, por lo que la página solo descarga el idioma que muestra.<br/>• Solo se aplica a los diccionarios que usan `importMode: 'dynamic'`, en la compilación del cliente.<br/>• Requiere un empaquetador compatible con top-level await (Vite, esbuild). |
1092
+ | `outputFormat` | Controla el formato de salida de los diccionarios. | `('esm' &#124; 'cjs')[]` | `['esm', 'cjs']` | `['cjs']` | |
1093
+ | `traversePattern` | Patrones que definen qué archivos recorrer durante la optimización. | `string[]` | `['**/*.{tsx,ts,js,mjs,cjs,jsx,vue,svelte,svte}', '!**/node_modules/**', '!**/dist/**', '!**/.intlayer/**', '!**/*.config.*', '!**/*.test.*', '!**/*.spec.*', '!**/*.stories.*']` | `['src/**/*.{ts,tsx}', '../ui-library/**/*.{ts,tsx}', '!**/node_modules/**']` | • Limite la optimización a los archivos relevantes para mejorar el rendimiento de compilación.<br/>• Se ignora si `optimize` está desactivado.<br/>• Usa patrones glob (glob patterns). |
1068
1094
 
1069
1095
  ---
1070
1096
 
@@ -535,28 +535,6 @@ Utilizado en conjunto con las Variantes, este campo define alternativas de conte
535
535
 
536
536
  > Consulta [Variantes](https://github.com/aymericzip/intlayer/blob/main/docs/docs/es/dynamic_dictionaries/variants.md) para más información.
537
537
 
538
- #### `meta` (`Record<string, string | number | boolean>`)
539
-
540
- Utilizado en conjunto con los Registros Dinámicos, este campo permite declarar registros gestionados por CMS o datos arbitrarios recuperados en tiempo de ejecución mediante un ID opaco. La identidad del diccionario se define mediante el conjunto arbitrario de pares clave-valor declarados en este campo `meta`.
541
-
542
- **Ejemplo:**
543
-
544
- ```typescript
545
- {
546
- key: "product-copy",
547
- meta: {
548
- id: "prod_abc",
549
- userId: "user_123"
550
- },
551
- content: {
552
- name: "Widget Pro",
553
- description: "The best widget."
554
- }
555
- }
556
- ```
557
-
558
- > Consulta [Registros Dinámicos](https://github.com/aymericzip/intlayer/blob/main/docs/docs/es/dynamic_dictionaries/dynamic_content.md) para más información.
559
-
560
538
  ### Propiedades del CMS
561
539
 
562
540
  ##### `version` (cadena)
@@ -89,6 +89,29 @@ No es posible obtener contenido desde un archivo JSON, usa un archivo .ts o .js
89
89
 
90
90
  En este caso, la función `fakeFetch` simula un retraso para imitar el tiempo de respuesta del servidor. Intlayer ejecuta la función asíncrona y utiliza el resultado como contenido para la clave `text`.
91
91
 
92
+ ## Obtención de contenido remoto
93
+
94
+ También puedes asignar una promesa directamente a un campo de contenido. Intlayer la espera mientras construye los diccionarios e incorpora el valor resuelto:
95
+
96
+ ```typescript fileName="**/*.content.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
97
+ import type { Dictionary } from "intlayer";
98
+
99
+ const remoteContent = {
100
+ key: "remote_content",
101
+ content: {
102
+ externalContent: fetch("https://example.com").then((res) => res.json()),
103
+ },
104
+ } satisfies Dictionary;
105
+
106
+ export default remoteContent;
107
+ ```
108
+
109
+ ```plaintext fileName="**/*.content.json" contentDeclarationFormat="json"
110
+ No es posible obtener contenido desde un archivo JSON, usa un archivo .ts o .js en su lugar
111
+ ```
112
+
113
+ > La solicitud se ejecuta en tiempo de compilación, por lo que los datos obtenidos son una instantánea incrustada en el diccionario. Reconstruye tus diccionarios para actualizarlos.
114
+
92
115
  ## Uso de contenido basado en funciones en componentes React
93
116
 
94
117
  Para usar contenido basado en funciones en un componente React, necesitas importar `useIntlayer` desde `react-intlayer` y llamarlo con el ID del contenido para obtenerlo. Aquí tienes un ejemplo: