@intlayer/docs 9.3.1 → 9.3.2

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 (60) hide show
  1. package/dist/cjs/generated/docs.entry.cjs +20 -0
  2. package/dist/cjs/generated/docs.entry.cjs.map +1 -1
  3. package/dist/esm/generated/docs.entry.mjs +20 -0
  4. package/dist/esm/generated/docs.entry.mjs.map +1 -1
  5. package/dist/types/generated/docs.entry.d.ts +1 -0
  6. package/dist/types/generated/docs.entry.d.ts.map +1 -1
  7. package/docs/ar/eslint.md +336 -0
  8. package/docs/ar/intlayer_with_react_router_v7_fs_routes.md +1 -1
  9. package/docs/bn/eslint.md +336 -0
  10. package/docs/cs/eslint.md +336 -0
  11. package/docs/de/eslint.md +336 -0
  12. package/docs/en/eslint.md +336 -0
  13. package/docs/en-GB/eslint.md +336 -0
  14. package/docs/en-GB/intlayer_with_create_react_app.md +32 -35
  15. package/docs/en-GB/intlayer_with_react_router_v7_fs_routes.md +1 -1
  16. package/docs/es/eslint.md +336 -0
  17. package/docs/fr/eslint.md +336 -0
  18. package/docs/hi/eslint.md +336 -0
  19. package/docs/hi/intlayer_with_react_router_v7_fs_routes.md +1 -1
  20. package/docs/hi/intlayer_with_vite+svelte.md +2 -2
  21. package/docs/id/eslint.md +336 -0
  22. package/docs/it/eslint.md +336 -0
  23. package/docs/ja/eslint.md +336 -0
  24. package/docs/ja/intlayer_with_react_router_v7.md +1 -146
  25. package/docs/ja/intlayer_with_vite+react.md +5 -1
  26. package/docs/ko/eslint.md +336 -0
  27. package/docs/ko/intlayer_with_lynx+react.md +4 -0
  28. package/docs/ko/intlayer_with_react_router_v7_fs_routes.md +1 -1
  29. package/docs/ko/intlayer_with_storybook.md +5 -5
  30. package/docs/nl/eslint.md +336 -0
  31. package/docs/pl/eslint.md +336 -0
  32. package/docs/pl/intlayer_with_astro.md +1 -114
  33. package/docs/pl/migration_from_i18next_to_intlayer.md +4 -0
  34. package/docs/pl/migration_from_next-i18next_to_intlayer.md +8 -4
  35. package/docs/pl/migration_from_next-intl_to_intlayer.md +11 -5
  36. package/docs/pl/migration_from_nuxtjs_i18n_to_intlayer.md +8 -4
  37. package/docs/pl/migration_from_react-i18next_to_intlayer.md +8 -4
  38. package/docs/pl/migration_from_vue-i18n_to_intlayer.md +4 -0
  39. package/docs/pt/eslint.md +336 -0
  40. package/docs/pt/intlayer_with_astro.md +1 -114
  41. package/docs/ru/eslint.md +336 -0
  42. package/docs/tr/eslint.md +336 -0
  43. package/docs/uk/eslint.md +336 -0
  44. package/docs/uk/packages/angular-intlayer/exports.md +2 -2
  45. package/docs/ur/eslint.md +336 -0
  46. package/docs/vi/eslint.md +336 -0
  47. package/docs/zh/eslint.md +336 -0
  48. package/docs/zh/intlayer_with_create_react_app.md +4 -0
  49. package/docs/zh/intlayer_with_lynx+react.md +4 -0
  50. package/docs/zh/intlayer_with_nextjs_14.md +0 -2
  51. package/docs/zh/intlayer_with_nextjs_15.md +0 -2
  52. package/docs/zh/intlayer_with_nextjs_page_router.md +0 -2
  53. package/docs/zh/intlayer_with_nuxt.md +1 -1
  54. package/docs/zh/intlayer_with_react_router_v7.md +4 -0
  55. package/docs/zh/intlayer_with_react_router_v7_fs_routes.md +4 -0
  56. package/docs/zh/intlayer_with_solid_start.md +1 -1
  57. package/docs/zh/intlayer_with_vite+vue.md +0 -2
  58. package/docs/zh-TW/eslint.md +336 -0
  59. package/package.json +6 -6
  60. package/src/generated/docs.entry.ts +20 -0
@@ -0,0 +1,336 @@
1
+ ---
2
+ createdAt: 2026-08-12
3
+ updatedAt: 2026-08-12
4
+ title: Plugin de ESLint | Reglas de lint para Intlayer
5
+ description: Detecta cadenas hardcodeadas, llamadas dinámicas que el compilador de Intlayer no puede optimizar y contenido de diccionario sin usar, con eslint-plugin-intlayer. Funciona con ESLint y oxlint, en React, Vue, Svelte, Angular y Astro.
6
+ keywords:
7
+ - Intlayer
8
+ - ESLint
9
+ - oxlint
10
+ - Lint
11
+ - i18n
12
+ - Internacionalización
13
+ - no-raw-text
14
+ - Cadenas hardcodeadas
15
+ - Traducciones sin usar
16
+ - Contenido muerto
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: "Historial inicial"
28
+ author: aymericzip
29
+ ---
30
+
31
+ # Plugin de ESLint x OXLint
32
+
33
+ `eslint-plugin-intlayer` detecta los tipos de error de i18n que TypeScript no puede ver:
34
+
35
+ 1. **Texto hardcodeado** que nunca llegó a un diccionario.
36
+ 2. **Llamadas dinámicas** que pasan el chequeo de tipos y se ejecutan, pero que el compilador de Intlayer no puede optimizar.
37
+ 3. **Contenido muerto** — diccionarios y campos que nada en el proyecto lee (opcional mediante activación).
38
+
39
+ Las claves de diccionario desconocidas, las rutas de campo desconocidas y las locales faltantes ya son errores de compilación, así que el plugin no las repite.
40
+
41
+ ## Instalación
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
+ Requiere ESLint 9 o posterior (flat config).
56
+
57
+ ## Uso
58
+
59
+ El plugin funciona tanto en ESLint como en [oxlint](https://oxc.rs): las mismas reglas, las mismas opciones.
60
+
61
+ <Tabs defaultTab="eslint">
62
+ <Tab label="ESLint" value="eslint">
63
+
64
+ ```javascript fileName="eslint.config.mjs" codeFormat="esm"
65
+ import intlayer from "eslint-plugin-intlayer";
66
+
67
+ export default [...intlayer.configs.recommended];
68
+ ```
69
+
70
+ O activa las reglas una por una:
71
+
72
+ ```javascript fileName="eslint.config.mjs" codeFormat="esm"
73
+ import intlayer from "eslint-plugin-intlayer";
74
+
75
+ export default [
76
+ {
77
+ plugins: { intlayer },
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
+ Dos advertencias: el soporte de plugins JS en oxlint aún está en fase alfa, y oxlint no admite parsers personalizados; por lo tanto, los archivos `.vue`, `.svelte`, `.astro` y las plantillas de Angular no se analizan allí. Ejecuta oxlint sobre tus archivos JS/TS/JSX y mantén ESLint para el resto.
105
+
106
+ `no-unused-content` se omite intencionadamente arriba: necesita el directorio de trabajo y la ruta del archivo analizado del contexto de la regla, lo cual el puente alfa de plugins JS no garantiza. Ejecútala bajo ESLint.
107
+
108
+ </Tab>
109
+ </Tabs>
110
+
111
+ ### Configuraciones
112
+
113
+ | Configuración | `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 (+ literales fuera de JSX) | error | error | error | off |
117
+ | `contract-only` | off | error | error | off | off |
118
+
119
+ `recommended` mantiene deliberadamente `no-raw-text` en `warn`: apuntarla a una base de código existente detecta todas las cadenas no traducidas de golpe, lo cual no debería romper tu compilación desde el primer día.
120
+
121
+ `enforce-adapter-import` está desactivada por defecto — actívala explícitamente si la deseas.
122
+
123
+ `no-unused-content` está desactivada en todas las configuraciones, incluida `strict`. Es la única regla que lee tu configuración de Intlayer y recorre tus archivos fuente desde el disco, por lo que activarla debe ser una elección deliberada en lugar de algo que un ajuste preestablecido haga por ti.
124
+
125
+ ## Reglas
126
+
127
+ ### `no-raw-text`
128
+
129
+ Informa sobre el texto orientado al usuario que no está declarado en un diccionario. Utiliza la misma detección que `intlayer extract`, por lo que se ignoran nombres de marcas, clases CSS e identificadores técnicos.
130
+
131
+ ```jsx
132
+ // ✗ Reportado
133
+ <h1>Welcome to our documentation</h1>
134
+ <input placeholder="Enter your email address" />
135
+
136
+ // ✓ Correcto
137
+ const { title } = useIntlayer("home");
138
+ <h1>{title}</h1>
139
+ ```
140
+
141
+ Los archivos de declaración de contenido (`*.content.ts`, …) se ignoran.
142
+
143
+ Para corregir un archivo completo de una vez, ejecuta `npx intlayer extract` y deja que el compilador mueva las cadenas a un diccionario por ti.
144
+
145
+ **Opciones**
146
+
147
+ ```javascript fileName="eslint.config.mjs" codeFormat="esm"
148
+ {
149
+ "intlayer/no-raw-text": [
150
+ "warn",
151
+ {
152
+ // Atributos cuyo valor es texto orientado al usuario.
153
+ // Por defecto: title, placeholder, alt, aria-label, label
154
+ attributes: ["title", "placeholder", "alt", "aria-label", "label"],
155
+
156
+ // Elementos cuyo contenido nunca es texto orientado al usuario.
157
+ // Por defecto: code, pre, script, style
158
+ ignoreElements: ["code", "pre", "script", "style"],
159
+
160
+ // Expresiones regulares para texto que nunca se debe reportar.
161
+ ignorePatterns: ["^Powered by"],
162
+
163
+ // También reportar literales de cadena fuera del marcado. Por defecto: false
164
+ includeStringLiterals: false,
165
+ },
166
+ ],
167
+ }
168
+ ```
169
+
170
+ ### `static-dictionary-key`
171
+
172
+ Requiere que la clave del diccionario sea un literal de cadena.
173
+
174
+ El compilador solo puede precargar un diccionario cuando puede leer la clave directamente en el punto de llamada. Con una clave calculada, omite silenciosamente la optimización e incluye todos los diccionarios en el empaquetado.
175
+
176
+ ```typescript
177
+ // ✗ Reportado
178
+ useIntlayer(dictionaryKey);
179
+ useIntlayer(`home-${suffix}`);
180
+ getTranslations({ namespace: page });
181
+
182
+ // ✗ Una variable sigue sin ser un literal
183
+ const key = "home";
184
+ useIntlayer(key);
185
+
186
+ // ✓ Correcto
187
+ useIntlayer("home");
188
+ getTranslations({ namespace: "home" });
189
+ ```
190
+
191
+ Esto se aplica a `useIntlayer`, `getIntlayer` y a todos los adaptadores de compatibilidad (`useTranslation`, `useTranslations`, `formatMessage`, `<FormattedMessage id>`, `<Trans i18nKey>`, …).
192
+
193
+ ### `no-dynamic-field-access`
194
+
195
+ Requiere que el campo que lees de un diccionario sea conocido estáticamente.
196
+
197
+ El compilador elimina los campos que no ve utilizados. Un acceso dinámico le resulta invisible, por lo que la lectura puede devolver `undefined` en tiempo de ejecución.
198
+
199
+ ```typescript
200
+ // ✗ Reportado
201
+ const content = useIntlayer("home");
202
+ content[fieldName];
203
+
204
+ const t = useTranslations("home");
205
+ t(messageKey);
206
+
207
+ // ✓ Correcto
208
+ content.title;
209
+ content["title"];
210
+ content.items[0];
211
+ t("hero.title");
212
+ ```
213
+
214
+ ### `enforce-adapter-import`
215
+
216
+ Prefiere el adaptador de compatibilidad `@intlayer/*` sobre el paquete original. El original solo se resuelve a Intlayer cuando el alias del empaquetador está configurado; el adaptador siempre lo hace. Corregible automáticamente con `--fix`.
217
+
218
+ ```typescript
219
+ // ✗ Reportado
220
+ import { useTranslation } from "react-i18next";
221
+ import { getTranslations } from "next-intl/server";
222
+
223
+ // ✓ Correcto
224
+ import { useTranslation } from "@intlayer/react-i18next";
225
+ import { getTranslations } from "@intlayer/next-intl/server";
226
+ ```
227
+
228
+ ### `no-unused-content`
229
+
230
+ **Desactivada por defecto.** Informa sobre contenido que nada en tu proyecto lee, además de claves de diccionario declaradas en más de un lugar.
231
+
232
+ ```typescript fileName="src/home.content.ts"
233
+ export default {
234
+ key: "home", // ✗ Reportado si ninguna llamada en el proyecto solicita "home"
235
+ content: {
236
+ title: t({ es: "Título", en: "Title" }),
237
+
238
+ // ✗ Reportado si nada lee `hero`
239
+ hero: {
240
+ subtitle: t({ es: "Subtítulo", en: "Subtitle" }),
241
+ },
242
+ },
243
+ };
244
+ ```
245
+
246
+ A diferencia de las otras reglas, esta no puede responder solo a partir del archivo evaluado: un campo no se usa únicamente en relación con todo el proyecto. En la primera declaración de contenido de una ejecución de lint, carga tu configuración de Intlayer, busca los archivos fuente que declara dicha configuración (`build.traversePattern`, `compiler.transformPattern`) y ejecuta el mismo analizador de uso que alimenta `@intlayer/lsp` y el tachado de "no utilizado" en la extensión de VS Code. El resultado se almacena en caché durante `cacheTtl` milisegundos, por lo que el escaneo ocurre una vez por ejecución en lugar de una vez por archivo.
247
+
248
+ **Opciones**
249
+
250
+ ```javascript fileName="eslint.config.mjs" codeFormat="esm"
251
+ {
252
+ "intlayer/no-unused-content": [
253
+ "warn",
254
+ {
255
+ // Reportar claves de diccionario que nada referencia. Por defecto: true
256
+ reportUnusedDictionaries: true,
257
+
258
+ // Reportar campos de contenido que nada lee. Por defecto: true
259
+ reportUnusedFields: true,
260
+
261
+ // Reportar claves declaradas en más de un lugar. Por defecto: true
262
+ reportDuplicateKeys: true,
263
+
264
+ // Expresiones regulares para rutas de campos que nunca se deben reportar.
265
+ ignoreFields: ["^meta"],
266
+
267
+ // Raíz del proyecto desde donde comienza el escaneo. Por defecto: directorio de trabajo de ESLint
268
+ baseDir: process.cwd(),
269
+
270
+ // Tiempo que se reutiliza un escaneo de proyecto, en ms. Por defecto: 30000
271
+ cacheTtl: 30000,
272
+ },
273
+ ],
274
+ }
275
+ ```
276
+
277
+ Reduce `cacheTtl` cuando ejecutes lint desde un servidor de editor de larga duración y quieras que tus ediciones se reflejen antes; configura `baseDir` cuando una sola ejecución de lint abarque varios proyectos de Intlayer en un monorepo.
278
+
279
+ > **Tiende al silencio.** Un falso positivo aquí eliminaría una traducción, por lo que no se reporta nada cuando el diccionario se consume de una manera que el análisis no puede rastrear: el objeto de contenido pasado en su totalidad, una función de traducción vinculada a partir de él (`const t = useTranslations("home")`), una declaración alcanzada mediante una importación directa (`useDictionary(myDictionary)`), un `nest()` de otro diccionario, o una lista de campos hecha no exhaustiva por un spread. Los componentes de un solo archivo (`.vue`, `.svelte`, `.astro`) se consideran como si usaran cada campo de los diccionarios que mencionan, ya que sus bloques de script no se analizan aquí.
280
+
281
+ `reportDuplicateKeys` lee los diccionarios no fusionados que la compilación escribe bajo `.intlayer/`, por lo que permanece silenciosa hasta que el proyecto se haya compilado al menos una vez. Dos declaraciones que comparten una clave se fusionan, lo cual es un patrón legítimo; el reporte existe porque un campo definido en ambos lados conserva silenciosamente solo uno de los dos valores.
282
+
283
+ El analizador se carga desde `@intlayer/lsp`, que se distribuye como ESM. Por lo tanto, la regla necesita una versión de Node que pueda hacer `require()` de un módulo ES: Node 20.19+ o 22.12+. En versiones anteriores no reporta nada en lugar de fallar la ejecución del lint.
284
+
285
+ ## Frameworks
286
+
287
+ Todas las reglas funcionan en todas las integraciones de Intlayer, incluso dentro de plantillas de Vue, Svelte y Angular. Solo necesitas indicarle a ESLint qué parser lee cada tipo de archivo.
288
+
289
+ | Framework | Archivos | 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
+ | Plantillas de Angular | `.component.html` | `@angular-eslint/template-parser` |
297
+ | Astro | `.astro` | `astro-eslint-parser` |
298
+
299
+ ```javascript fileName="eslint.config.mjs" codeFormat="esm"
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
+ Instala solo los parsers que tu proyecto necesite.
335
+
336
+ > **Limitación conocida.** En plantillas de Vue y Angular, una expresión como `{{ content[key] }}` no se verifica con `no-dynamic-field-access`. Las lecturas dinámicas escritas en el bloque script se detectan normalmente.
@@ -0,0 +1,336 @@
1
+ ---
2
+ createdAt: 2026-08-12
3
+ updatedAt: 2026-08-12
4
+ title: Plugin ESLint | Règles de lint pour Intlayer
5
+ description: Détectez les chaînes codées en dur, les appels dynamiques que le compilateur Intlayer ne peut pas optimiser et le contenu de dictionnaire inutilisé, avec eslint-plugin-intlayer. Compatible ESLint et oxlint, sur React, Vue, Svelte, Angular et Astro.
6
+ keywords:
7
+ - Intlayer
8
+ - ESLint
9
+ - oxlint
10
+ - Lint
11
+ - i18n
12
+ - Internationalisation
13
+ - no-raw-text
14
+ - Chaînes codées en dur
15
+ - Traductions inutilisées
16
+ - Contenu mort
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: "Historique initial"
28
+ author: aymericzip
29
+ ---
30
+
31
+ # Plugin ESLint x OXLint
32
+
33
+ `eslint-plugin-intlayer` détecte les types d'erreurs d'i18n que TypeScript ne peut pas voir :
34
+
35
+ 1. **Le texte codé en dur** qui n'a jamais rejoint un dictionnaire.
36
+ 2. **Les appels dynamiques** qui passent le typage et s'exécutent, mais que le compilateur Intlayer ne peut pas optimiser.
37
+ 3. **Le contenu mort** — les dictionnaires et les champs qu'aucun élément du projet ne lit (sur activation explicite).
38
+
39
+ Les clés de dictionnaire inconnues, les chemins de champ inconnus et les locales manquantes sont déjà des erreurs de compilation, le plugin ne les répète donc pas.
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
+ Nécessite ESLint 9 ou une version ultérieure (flat config).
56
+
57
+ ## Utilisation
58
+
59
+ Le plugin fonctionne à la fois avec ESLint et [oxlint](https://oxc.rs) — mêmes règles, mêmes options.
60
+
61
+ <Tabs defaultTab="eslint">
62
+ <Tab label="ESLint" value="eslint">
63
+
64
+ ```javascript fileName="eslint.config.mjs" codeFormat="esm"
65
+ import intlayer from "eslint-plugin-intlayer";
66
+
67
+ export default [...intlayer.configs.recommended];
68
+ ```
69
+
70
+ Ou activez les règles une par une :
71
+
72
+ ```javascript fileName="eslint.config.mjs" codeFormat="esm"
73
+ import intlayer from "eslint-plugin-intlayer";
74
+
75
+ export default [
76
+ {
77
+ plugins: { intlayer },
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
+ Deux réserves : la prise en charge des plugins JS par oxlint est encore en alpha, et oxlint ne prend pas en charge les parsers personnalisés — les fichiers `.vue`, `.svelte`, `.astro` et les templates Angular n'y sont donc pas analysés. Lancez oxlint sur vos fichiers JS/TS/JSX et gardez ESLint pour le reste.
105
+
106
+ `no-unused-content` est volontairement omise ci-dessus : elle nécessite le répertoire de travail et le chemin du fichier analysé issus du contexte de règle, ce que le bridge de plugin JS alpha ne garantit pas. Exécutez-la sous ESLint.
107
+
108
+ </Tab>
109
+ </Tabs>
110
+
111
+ ### Configurations
112
+
113
+ | Configuration | `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 (+ littéraux hors JSX) | error | error | error | off |
117
+ | `contract-only` | off | error | error | off | off |
118
+
119
+ `recommended` maintient volontairement `no-raw-text` à `warn` : pointer cette règle vers une codebase existante fait remonter toutes les chaînes non traduites d'un coup, ce qui ne doit pas casser votre build dès le premier jour.
120
+
121
+ `enforce-adapter-import` est désactivée par défaut — activez-la explicitement si vous la souhaitez.
122
+
123
+ `no-unused-content` est désactivée dans toutes les configurations, y compris `strict`. C'est la seule règle qui lit votre configuration Intlayer et parcourt vos fichiers sources sur le disque ; son activation doit donc être un choix délibéré plutôt qu'un comportement imposé par un preset.
124
+
125
+ ## Règles
126
+
127
+ ### `no-raw-text`
128
+
129
+ Signale le texte destiné à l'utilisateur qui n'est pas déclaré dans un dictionnaire. La règle utilise la même détection que `intlayer extract`, si bien que les noms de marque, les classes CSS et les identifiants techniques sont ignorés.
130
+
131
+ ```jsx
132
+ // ✗ Signalé
133
+ <h1>Welcome to our documentation</h1>
134
+ <input placeholder="Enter your email address" />
135
+
136
+ // ✓ Correct
137
+ const { title } = useIntlayer("home");
138
+ <h1>{title}</h1>
139
+ ```
140
+
141
+ Les fichiers de déclaration de contenu (`*.content.ts`, …) sont ignorés.
142
+
143
+ Pour corriger tout un fichier d'un coup, lancez `npx intlayer extract` et laissez le compilateur déplacer les chaînes dans un dictionnaire pour vous.
144
+
145
+ **Options**
146
+
147
+ ```javascript fileName="eslint.config.mjs" codeFormat="esm"
148
+ {
149
+ "intlayer/no-raw-text": [
150
+ "warn",
151
+ {
152
+ // Attributs dont la valeur est du texte destiné à l'utilisateur.
153
+ // Par défaut : title, placeholder, alt, aria-label, label
154
+ attributes: ["title", "placeholder", "alt", "aria-label", "label"],
155
+
156
+ // Éléments dont le contenu n'est jamais du texte destiné à l'utilisateur.
157
+ // Par défaut : code, pre, script, style
158
+ ignoreElements: ["code", "pre", "script", "style"],
159
+
160
+ // Expressions régulières pour du texte à ne jamais signaler.
161
+ ignorePatterns: ["^Powered by"],
162
+
163
+ // Signaler aussi les littéraux de chaîne hors markup. Par défaut : false
164
+ includeStringLiterals: false,
165
+ },
166
+ ],
167
+ }
168
+ ```
169
+
170
+ ### `static-dictionary-key`
171
+
172
+ Exige que la clé de dictionnaire soit un littéral de chaîne.
173
+
174
+ Le compilateur ne peut précharger un dictionnaire que s'il peut lire la clé directement au site d'appel. Avec une clé calculée, il ignore silencieusement l'optimisation et embarque tous les dictionnaires.
175
+
176
+ ```typescript
177
+ // ✗ Signalé
178
+ useIntlayer(dictionaryKey);
179
+ useIntlayer(`home-${suffix}`);
180
+ getTranslations({ namespace: page });
181
+
182
+ // ✗ Une variable n'est toujours pas un littéral
183
+ const key = "home";
184
+ useIntlayer(key);
185
+
186
+ // ✓ Correct
187
+ useIntlayer("home");
188
+ getTranslations({ namespace: "home" });
189
+ ```
190
+
191
+ Cela s'applique à `useIntlayer`, `getIntlayer` et à chaque adaptateur compat (`useTranslation`, `useTranslations`, `formatMessage`, `<FormattedMessage id>`, `<Trans i18nKey>`, …).
192
+
193
+ ### `no-dynamic-field-access`
194
+
195
+ Exige que le champ que vous lisez dans un dictionnaire soit connu statiquement.
196
+
197
+ Le compilateur supprime les champs dont il ne voit pas l'utilisation. Un accès calculé lui est invisible, la lecture peut donc renvoyer `undefined` à l'exécution.
198
+
199
+ ```typescript
200
+ // ✗ Signalé
201
+ const content = useIntlayer("home");
202
+ content[fieldName];
203
+
204
+ const t = useTranslations("home");
205
+ t(messageKey);
206
+
207
+ // ✓ Correct
208
+ content.title;
209
+ content["title"];
210
+ content.items[0];
211
+ t("hero.title");
212
+ ```
213
+
214
+ ### `enforce-adapter-import`
215
+
216
+ Privilégie l'adaptateur compat `@intlayer/*` par rapport au package d'origine. L'original ne se résout vers Intlayer que si l'alias du bundler est configuré ; l'adaptateur le fait toujours. Corrigeable automatiquement avec `--fix`.
217
+
218
+ ```typescript
219
+ // ✗ Signalé
220
+ import { useTranslation } from "react-i18next";
221
+ import { getTranslations } from "next-intl/server";
222
+
223
+ // ✓ Correct
224
+ import { useTranslation } from "@intlayer/react-i18next";
225
+ import { getTranslations } from "@intlayer/next-intl/server";
226
+ ```
227
+
228
+ ### `no-unused-content`
229
+
230
+ **Désactivée par défaut.** Signale le contenu qu'aucun élément de votre projet ne lit, ainsi que les clés de dictionnaire déclarées à plusieurs endroits.
231
+
232
+ ```typescript fileName="src/home.content.ts"
233
+ export default {
234
+ key: "home", // ✗ Signalé si aucun appelant dans le projet ne demande "home"
235
+ content: {
236
+ title: t({ fr: "Titre", en: "Title" }),
237
+
238
+ // ✗ Signalé si rien ne lit `hero`
239
+ hero: {
240
+ subtitle: t({ fr: "Sous-titre", en: "Subtitle" }),
241
+ },
242
+ },
243
+ };
244
+ ```
245
+
246
+ Contrairement aux autres règles, celle-ci ne peut pas répondre uniquement à partir du fichier en cours d'analyse — un champ n'est inutilisé que par rapport à l'ensemble du projet. Dès la première déclaration de contenu d'une exécution de lint, elle charge votre configuration Intlayer, recherche les fichiers sources définis par cette configuration (`build.traversePattern`, `compiler.transformPattern`) et exécute le même analyseur d'utilisation qui alimente `@intlayer/lsp` et le barré « inutilisé » dans l'extension VS Code. Le résultat est mis en cache pendant `cacheTtl` millisecondes, de sorte que l'analyse est effectuée une fois par exécution plutôt qu'une fois par fichier.
247
+
248
+ **Options**
249
+
250
+ ```javascript fileName="eslint.config.mjs" codeFormat="esm"
251
+ {
252
+ "intlayer/no-unused-content": [
253
+ "warn",
254
+ {
255
+ // Signaler les clés de dictionnaire qu'aucun élément ne référence. Par défaut : true
256
+ reportUnusedDictionaries: true,
257
+
258
+ // Signaler les champs de contenu que rien ne lit. Par défaut : true
259
+ reportUnusedFields: true,
260
+
261
+ // Signaler les clés déclarées à plusieurs endroits. Par défaut : true
262
+ reportDuplicateKeys: true,
263
+
264
+ // Expressions régulières pour les chemins de champs à ne jamais signaler.
265
+ ignoreFields: ["^meta"],
266
+
267
+ // Racine du projet à partir de laquelle commence l'analyse. Par défaut : répertoire de travail d'ESLint
268
+ baseDir: process.cwd(),
269
+
270
+ // Durée de réutilisation d'une analyse de projet, en ms. Par défaut : 30000
271
+ cacheTtl: 30000,
272
+ },
273
+ ],
274
+ }
275
+ ```
276
+
277
+ Diminuez `cacheTtl` si vous lisez depuis un serveur d'éditeur persistant et souhaitez que vos modifications soient prises en compte plus rapidement ; définissez `baseDir` lorsqu'une seule exécution de lint couvre plusieurs projets Intlayer dans un monorepo.
278
+
279
+ > **La règle privilégie le silence.** Un faux positif supprimant une traduction, rien n'est signalé lorsque le dictionnaire est consommé d'une manière que l'analyse ne peut pas suivre : l'objet de contenu transmis dans son intégralité, une fonction de traduction liée à partir de celui-ci (`const t = useTranslations("home")`), une déclaration atteinte via un import direct (`useDictionary(myDictionary)`), un `nest()` depuis un autre dictionnaire, ou une liste de champs rendue non exhaustive par un spread. Les composants monofichiers (`.vue`, `.svelte`, `.astro`) sont considérés comme utilisant chaque champ des dictionnaires qu'ils mentionnent, car leurs blocs de script ne sont pas analysés ici.
280
+
281
+ `reportDuplicateKeys` lit les dictionnaires non fusionnés que le build écrit sous `.intlayer/`, elle reste donc silencieuse jusqu'à ce que le projet ait été compilé au moins une fois. Deux déclarations partageant une clé sont fusionnées, ce qui est un modèle légitime — le rapport existe car un champ défini des deux côtés ne conserve silencieusement que l'une des deux valeurs.
282
+
283
+ L'analyseur est chargé depuis `@intlayer/lsp`, qui est distribué en ESM. La règle nécessite donc une version de Node capable de faire un `require()` sur un module ES — Node 20.19+ ou 22.12+. Sur toute version antérieure, elle ne signale rien plutôt que de faire échouer l'exécution du lint.
284
+
285
+ ## Frameworks
286
+
287
+ Toutes les règles fonctionnent sur l'ensemble des intégrations Intlayer, y compris à l'intérieur des templates Vue, Svelte et Angular. Il vous suffit d'indiquer à ESLint quel parser lit chaque type de fichier.
288
+
289
+ | Framework | Fichiers | 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
+ | Templates Angular | `.component.html` | `@angular-eslint/template-parser` |
297
+ | Astro | `.astro` | `astro-eslint-parser` |
298
+
299
+ ```javascript fileName="eslint.config.mjs" codeFormat="esm"
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
+ N'installez que les parsers dont votre projet a besoin.
335
+
336
+ > **Limitation connue.** Dans les templates Vue et Angular, une expression telle que `{{ content[key] }}` n'est pas vérifiée par `no-dynamic-field-access`. Les lectures dynamiques écrites dans le bloc script sont détectées normalement.