next-auto-i18n 0.7.2 → 0.8.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.
- package/DOCUMENTATION.md +86 -37
- package/README.md +141 -115
- package/dist/cli/doc-generator.d.ts +1 -2
- package/dist/cli/doc-generator.d.ts.map +1 -1
- package/dist/cli/doc-generator.js +0 -11
- package/dist/cli/doc-generator.js.map +1 -1
- package/dist/cli/index.js +184 -320
- package/dist/cli/index.js.map +1 -1
- package/dist/engine/analysis.d.ts +10 -0
- package/dist/engine/analysis.d.ts.map +1 -0
- package/dist/engine/analysis.js +139 -0
- package/dist/engine/analysis.js.map +1 -0
- package/dist/engine/apply.d.ts +11 -0
- package/dist/engine/apply.d.ts.map +1 -0
- package/dist/engine/apply.js +265 -0
- package/dist/engine/apply.js.map +1 -0
- package/dist/engine/index.d.ts +6 -0
- package/dist/engine/index.d.ts.map +1 -0
- package/dist/engine/index.js +6 -0
- package/dist/engine/index.js.map +1 -0
- package/dist/engine/planning.d.ts +24 -0
- package/dist/engine/planning.d.ts.map +1 -0
- package/dist/engine/planning.js +192 -0
- package/dist/engine/planning.js.map +1 -0
- package/dist/engine/report.d.ts +6 -0
- package/dist/engine/report.d.ts.map +1 -0
- package/dist/engine/report.js +132 -0
- package/dist/engine/report.js.map +1 -0
- package/dist/engine/types.d.ts +104 -0
- package/dist/engine/types.d.ts.map +1 -0
- package/dist/engine/types.js +2 -0
- package/dist/engine/types.js.map +1 -0
- package/dist/generator/index.d.ts +7 -17
- package/dist/generator/index.d.ts.map +1 -1
- package/dist/generator/index.js +13 -14
- package/dist/generator/index.js.map +1 -1
- package/dist/injector/layout-injector.d.ts +0 -1
- package/dist/injector/layout-injector.d.ts.map +1 -1
- package/dist/injector/layout-injector.js +0 -1
- package/dist/injector/layout-injector.js.map +1 -1
- package/dist/injector/locale-structure-injector.d.ts +0 -4
- package/dist/injector/locale-structure-injector.d.ts.map +1 -1
- package/dist/injector/locale-structure-injector.js +34 -64
- package/dist/injector/locale-structure-injector.js.map +1 -1
- package/dist/injector/middleware-injector.d.ts.map +1 -1
- package/dist/injector/middleware-injector.js +0 -6
- package/dist/injector/middleware-injector.js.map +1 -1
- package/dist/injector/request-injector.d.ts.map +1 -1
- package/dist/injector/request-injector.js +0 -2
- package/dist/injector/request-injector.js.map +1 -1
- package/dist/injector/routing-injector.d.ts.map +1 -1
- package/dist/injector/routing-injector.js +0 -2
- package/dist/injector/routing-injector.js.map +1 -1
- package/dist/rewriter/const-rewriter.d.ts.map +1 -1
- package/dist/rewriter/const-rewriter.js +0 -8
- package/dist/rewriter/const-rewriter.js.map +1 -1
- package/dist/rewriter/index.d.ts +0 -12
- package/dist/rewriter/index.d.ts.map +1 -1
- package/dist/rewriter/index.js +0 -10
- package/dist/rewriter/index.js.map +1 -1
- package/dist/rewriter/jsx-rewriter.d.ts +7 -10
- package/dist/rewriter/jsx-rewriter.d.ts.map +1 -1
- package/dist/rewriter/jsx-rewriter.js +66 -18
- package/dist/rewriter/jsx-rewriter.js.map +1 -1
- package/dist/scanner/ast-parser.d.ts +0 -1
- package/dist/scanner/ast-parser.d.ts.map +1 -1
- package/dist/scanner/ast-parser.js +0 -1
- package/dist/scanner/ast-parser.js.map +1 -1
- package/dist/scanner/filters.d.ts +2 -0
- package/dist/scanner/filters.d.ts.map +1 -1
- package/dist/scanner/filters.js +23 -20
- package/dist/scanner/filters.js.map +1 -1
- package/dist/scanner/index.d.ts +17 -2
- package/dist/scanner/index.d.ts.map +1 -1
- package/dist/scanner/index.js +28 -11
- package/dist/scanner/index.js.map +1 -1
- package/dist/scanner/string-extractor.d.ts +7 -1
- package/dist/scanner/string-extractor.d.ts.map +1 -1
- package/dist/scanner/string-extractor.js +3 -19
- package/dist/scanner/string-extractor.js.map +1 -1
- package/dist/translator/deepl.d.ts.map +1 -1
- package/dist/translator/deepl.js +0 -1
- package/dist/translator/deepl.js.map +1 -1
- package/dist/translator/index.d.ts +2 -0
- package/dist/translator/index.d.ts.map +1 -1
- package/dist/translator/index.js +37 -6
- package/dist/translator/index.js.map +1 -1
- package/dist/translator/provider.d.ts +5 -0
- package/dist/translator/provider.d.ts.map +1 -0
- package/dist/translator/provider.js +25 -0
- package/dist/translator/provider.js.map +1 -0
- package/package.json +1 -1
package/DOCUMENTATION.md
CHANGED
|
@@ -8,15 +8,18 @@
|
|
|
8
8
|
<a href="https://github.com/stvekoulo/next-auto-i18n/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/next-auto-i18n" alt="license"></a>
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
|
-
<p align="center"><strong>
|
|
11
|
+
<p align="center"><strong>Conservative i18n automation for Next.js App Router projects.</strong></p>
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
> This document complements the README. The README is the shortest source of truth for public guarantees. When behavior differs between examples and real project constraints, the engine always prefers safe refusal or manual guidance over risky mutation.
|
|
14
|
+
|
|
15
|
+
next-auto-i18n is a CLI tool for existing Next.js projects. It scans the codebase via AST, extracts translatable strings, translates them through DeepL, rewrites safe cases automatically, and applies conservative `next-intl` injection when the project structure is compatible.
|
|
14
16
|
|
|
15
17
|
---
|
|
16
18
|
|
|
17
19
|
## Table of Contents
|
|
18
20
|
|
|
19
21
|
- [Why next-auto-i18n?](#why-next-auto-i18n)
|
|
22
|
+
- [Compatibility Matrix](#compatibility-matrix)
|
|
20
23
|
- [Prerequisites](#prerequisites)
|
|
21
24
|
- [Installation](#installation)
|
|
22
25
|
- [Quick Start](#quick-start)
|
|
@@ -34,6 +37,49 @@ next-auto-i18n is a CLI tool that fully automates internationalization (i18n) in
|
|
|
34
37
|
|
|
35
38
|
---
|
|
36
39
|
|
|
40
|
+
## Compatibility Matrix
|
|
41
|
+
|
|
42
|
+
### Project structure
|
|
43
|
+
|
|
44
|
+
| Target | Status | Notes |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| `app/` | Supported | Primary target |
|
|
47
|
+
| `src/app/` | Supported | Scanner and injectors handle both roots |
|
|
48
|
+
| `components/`, `ui/`, `features/`, `shared/` | Supported for scan | Included in the default scan scope |
|
|
49
|
+
| custom monorepo layouts | Partial | Depends on actual source tree and ignore rules |
|
|
50
|
+
|
|
51
|
+
### Rewriting behavior
|
|
52
|
+
|
|
53
|
+
| Case | Status | Behavior |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| simple JSX text | Supported | auto rewrite |
|
|
56
|
+
| supported JSX attributes | Supported | auto rewrite |
|
|
57
|
+
| template literals | Supported | generated key + rewrite when safe |
|
|
58
|
+
| module-scope strings | Partial | translated, but often manual integration |
|
|
59
|
+
| ambiguous JSX spacing | Conservative | skipped with diagnostics |
|
|
60
|
+
| unparseable source file | Blocked | file skipped, warning emitted |
|
|
61
|
+
|
|
62
|
+
### Next.js injection
|
|
63
|
+
|
|
64
|
+
| Target | Status | Behavior |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| `next.config.*` | Supported | inject if compatible, otherwise block |
|
|
67
|
+
| `middleware.ts` / `proxy.ts` | Supported | created or skipped if already present |
|
|
68
|
+
| `i18n/routing.ts` | Supported | created or skipped |
|
|
69
|
+
| `i18n/request.ts` | Supported | created or skipped |
|
|
70
|
+
| `LanguageSwitcher` | Supported | can be injected independently |
|
|
71
|
+
| `app/[locale]/` restructuring | Conservative | refused on complex root layouts |
|
|
72
|
+
|
|
73
|
+
### Runtime guarantees
|
|
74
|
+
|
|
75
|
+
| Situation | Outcome |
|
|
76
|
+
|---|---|
|
|
77
|
+
| safe project shape | full or near-full automation |
|
|
78
|
+
| mixed safe and unsafe operations | partial run with explicit manual actions |
|
|
79
|
+
| risky mutation candidate | skipped instead of forced |
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
37
83
|
## Why next-auto-i18n?
|
|
38
84
|
|
|
39
85
|
### Manual setup vs next-auto-i18n
|
|
@@ -273,28 +319,37 @@ next-auto-i18n add-locale zh
|
|
|
273
319
|
|
|
274
320
|
### `next-auto-i18n extract`
|
|
275
321
|
|
|
276
|
-
Scans the project, translates all strings, and generates a Markdown integration guide — **without modifying any source file**.
|
|
322
|
+
Scans the project, translates all strings, and generates a Markdown integration guide — **without modifying any source file**.
|
|
277
323
|
|
|
278
324
|
```bash
|
|
279
|
-
next-auto-i18n extract
|
|
280
|
-
next-auto-i18n extract --locale en,es
|
|
281
|
-
next-auto-i18n extract --out docs/i18n-guide.md
|
|
325
|
+
next-auto-i18n extract # Interactive (asks locale if no config)
|
|
326
|
+
next-auto-i18n extract --locale en,es # Skip locale prompt
|
|
327
|
+
next-auto-i18n extract --out docs/i18n-guide.md # Custom output path
|
|
328
|
+
next-auto-i18n extract --inject # Also configure Next.js after extraction
|
|
329
|
+
next-auto-i18n extract --switcher # Inject only the Language Switcher widget
|
|
330
|
+
next-auto-i18n extract --no-module-scope # Exclude module-scope const strings entirely
|
|
282
331
|
```
|
|
283
332
|
|
|
284
333
|
| Flag | Description |
|
|
285
334
|
|------|-------------|
|
|
286
|
-
| `--locale <locales>` | Comma-separated target locales (used if no
|
|
335
|
+
| `--locale <locales>` | Comma-separated target locales (used if no config file exists) |
|
|
287
336
|
| `--out <path>` | Output path for the Markdown guide (default: `i18n-guide.md`) |
|
|
337
|
+
| `--inject` | Runs the full Next.js setup after translation: `next.config`, `middleware.ts`, `i18n/routing.ts`, `i18n/request.ts`, `app/[locale]/` structure, Language Switcher |
|
|
338
|
+
| `--switcher` | Injects only the floating Language Switcher component (without `--inject`) |
|
|
339
|
+
| `--no-module-scope` | Excludes strings declared inside module-scope `const` from detection and translation |
|
|
288
340
|
|
|
289
341
|
**What it does:**
|
|
290
342
|
|
|
291
343
|
1. Scans your project for translatable strings (same AST engine as `init`)
|
|
292
|
-
2.
|
|
293
|
-
3.
|
|
294
|
-
4.
|
|
295
|
-
5.
|
|
344
|
+
2. *(if `--no-module-scope`)* Detects and filters out module-scope strings before key generation
|
|
345
|
+
3. Generates/updates `messages/<sourceLocale>.json` with stable key merge
|
|
346
|
+
4. Translates to all target locales via DeepL (incremental — only new strings)
|
|
347
|
+
5. Detects module-scope strings that require manual integration (unless `--no-module-scope`)
|
|
348
|
+
6. *(if `--inject`)* Configures the full Next.js i18n infrastructure
|
|
349
|
+
7. *(if `--switcher`)* Injects the Language Switcher component
|
|
350
|
+
8. Generates `i18n-guide.md` with full integration instructions
|
|
296
351
|
|
|
297
|
-
**What it does
|
|
352
|
+
**What it never does:** modify any `.tsx`/`.ts`/`.jsx`/`.js` source file.
|
|
298
353
|
|
|
299
354
|
**Generated guide contents:**
|
|
300
355
|
|
|
@@ -302,38 +357,29 @@ next-auto-i18n extract --out docs/i18n-guide.md # Custom output path
|
|
|
302
357
|
- List of generated translation files
|
|
303
358
|
- Usage examples (Client Component with `useTranslations`, Server Component with `getTranslations`)
|
|
304
359
|
- Module-scope strings section with before/after code examples
|
|
305
|
-
- Per-file
|
|
360
|
+
- Per-file tables: line number, type, original text, key, ready-to-paste replacement code
|
|
306
361
|
- Complete key reference table
|
|
307
362
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
```
|
|
311
|
-
▸ Configuration
|
|
312
|
-
✓ Configuration chargée (fr → en, es)
|
|
313
|
-
|
|
314
|
-
▸ Scan du projet
|
|
315
|
-
✓ 47 strings trouvées dans 12 fichiers
|
|
316
|
-
components/Hero.tsx 8 strings
|
|
317
|
-
components/Navbar.tsx 5 strings
|
|
318
|
-
...
|
|
363
|
+
---
|
|
319
364
|
|
|
320
|
-
|
|
321
|
-
✓ 42 clés → ./messages/fr.json
|
|
365
|
+
### `next-auto-i18n extract sync`
|
|
322
366
|
|
|
323
|
-
|
|
324
|
-
✓ 84 strings traduites
|
|
325
|
-
./messages/en.json
|
|
326
|
-
./messages/es.json
|
|
367
|
+
Sub-command of `extract`. Rescans the project, integrates new strings, and synchronises translations — **without rewriting source files**. Uses the same stable key merge as `sync`.
|
|
327
368
|
|
|
328
|
-
|
|
329
|
-
|
|
369
|
+
```bash
|
|
370
|
+
next-auto-i18n extract sync # Rescan + update JSON + translate
|
|
371
|
+
next-auto-i18n extract sync --inject # + configure Next.js after sync
|
|
372
|
+
next-auto-i18n extract sync --switcher # + inject the Language Switcher
|
|
373
|
+
next-auto-i18n extract sync --no-module-scope # Exclude module-scope strings
|
|
374
|
+
```
|
|
330
375
|
|
|
331
|
-
|
|
332
|
-
|
|
376
|
+
| Flag | Description |
|
|
377
|
+
|------|-------------|
|
|
378
|
+
| `--inject` | Runs full Next.js setup after synchronisation |
|
|
379
|
+
| `--switcher` | Injects only the Language Switcher component |
|
|
380
|
+
| `--no-module-scope` | Excludes module-scope strings from detection and translation |
|
|
333
381
|
|
|
334
|
-
|
|
335
|
-
Consultez le guide pour intégrer les traductions manuellement.
|
|
336
|
-
```
|
|
382
|
+
Requires an existing `auto-i18n.config.json` and `messages/<sourceLocale>.json` (run `init` or `extract` first).
|
|
337
383
|
|
|
338
384
|
---
|
|
339
385
|
|
|
@@ -953,6 +999,9 @@ The test suite covers all modules:
|
|
|
953
999
|
- [x] `next-auto-i18n sync` — rescan and incremental update (stable key merge)
|
|
954
1000
|
- [x] `next-auto-i18n missing` — report untranslated keys
|
|
955
1001
|
- [x] `next-auto-i18n extract` — translate + generate guide without touching source
|
|
1002
|
+
- [x] `next-auto-i18n extract sync` — incremental sync without source rewrite
|
|
1003
|
+
- [x] `--inject` / `--switcher` options on `extract` and `extract sync`
|
|
1004
|
+
- [x] `--no-module-scope` option to exclude const module-scope strings
|
|
956
1005
|
- [x] Floating language switcher widget (auto-injected, customizable)
|
|
957
1006
|
- [x] Automatic `next-intl` dependency installation
|
|
958
1007
|
- [x] `app/[locale]/` structure auto-creation (required by next-intl App Router)
|
package/README.md
CHANGED
|
@@ -4,70 +4,89 @@
|
|
|
4
4
|

|
|
5
5
|

|
|
6
6
|
|
|
7
|
-
>
|
|
7
|
+
> CLI d’internationalisation pour projets Next.js App Router, avec scan AST, génération de messages, traduction DeepL, réécriture prudente et injection `next-intl`.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
`next-auto-i18n` scanne votre code, extrait les strings traduisibles, génère les clés i18n, remplit les fichiers `messages/*.json`, traduit via DeepL et applique les mutations sûres du projet. Quand une réécriture ou une injection n’est pas jugée fiable, le CLI s’arrête proprement sur cette cible et renvoie une action manuelle recommandée au lieu de modifier silencieusement votre code.
|
|
10
10
|
|
|
11
|
-
**
|
|
11
|
+
La version actuelle est pensée pour être **utile en automatique**, mais aussi **conservatrice** sur les cas ambigus.
|
|
12
|
+
|
|
13
|
+
Le complément de documentation se trouve dans [DOCUMENTATION.md](./DOCUMENTATION.md).
|
|
12
14
|
|
|
13
15
|
## Installation
|
|
14
16
|
|
|
15
17
|
```bash
|
|
16
|
-
npm install -D next-auto-i18n
|
|
18
|
+
npm install -D next-auto-i18n next-intl
|
|
17
19
|
```
|
|
18
20
|
|
|
19
|
-
Ou directement
|
|
21
|
+
Ou directement :
|
|
20
22
|
|
|
21
23
|
```bash
|
|
22
24
|
npx next-auto-i18n init
|
|
23
25
|
```
|
|
24
26
|
|
|
25
|
-
##
|
|
27
|
+
## Prérequis
|
|
28
|
+
|
|
29
|
+
- Node.js `>= 18`
|
|
30
|
+
- Un projet Next.js avec App Router
|
|
31
|
+
- `next-intl` installé dans le projet
|
|
32
|
+
- Une clé API DeepL
|
|
33
|
+
|
|
34
|
+
## Ce que le package fait vraiment
|
|
26
35
|
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
36
|
+
- Scan AST des fichiers `.tsx`, `.jsx`, `.ts`, `.js`
|
|
37
|
+
- Extraction des strings JSX, attributs traduisibles et template literals
|
|
38
|
+
- Génération incrémentale des clés dans `messages/<locale>.json`
|
|
39
|
+
- Traduction DeepL avec validation des placeholders
|
|
40
|
+
- Réécriture automatique des cas sûrs
|
|
41
|
+
- Détection des cas risqués : module-scope, JSX ambigu, fichiers non parsables
|
|
42
|
+
- Injection Next.js conservatrice : applique ce qui est sûr, bloque ce qui doit rester manuel
|
|
43
|
+
- Reporting structuré : `success`, `partial`, `failed`, diagnostics et actions manuelles
|
|
30
44
|
|
|
31
|
-
##
|
|
45
|
+
## Ce que le package ne promet pas
|
|
46
|
+
|
|
47
|
+
- Il ne réécrit pas tous les cas JSX complexes.
|
|
48
|
+
- Il ne force pas la restructuration `app/[locale]` si le layout racine paraît trop personnalisé.
|
|
49
|
+
- Il ne “corrige pas quand même” un projet ambigu.
|
|
50
|
+
- Il ne garantit pas un projet 100% migré sans validation humaine sur les cas avancés.
|
|
51
|
+
|
|
52
|
+
## Démarrage rapide
|
|
32
53
|
|
|
33
54
|
```bash
|
|
34
55
|
npx next-auto-i18n init
|
|
35
56
|
```
|
|
36
57
|
|
|
37
|
-
Le CLI vous guide
|
|
58
|
+
Le CLI vous guide sur :
|
|
38
59
|
|
|
39
|
-
1.
|
|
40
|
-
2.
|
|
41
|
-
3.
|
|
60
|
+
1. la locale source
|
|
61
|
+
2. les locales cibles
|
|
62
|
+
3. la clé DeepL
|
|
42
63
|
|
|
43
|
-
|
|
64
|
+
Puis il :
|
|
44
65
|
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
-
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
- Genere `i18n/routing.ts` + `i18n/request.ts` (requis pour les Server Components)
|
|
52
|
-
- Cree la structure `app/[locale]/` requise par le App Router next-intl
|
|
53
|
-
- Injecte un **Language Switcher flottant** (personnalisable) pour changer de langue
|
|
54
|
-
- Detecte les strings dans les `const` module-scope et vous guide pour les integrer manuellement
|
|
66
|
+
- crée `auto-i18n.config.json`
|
|
67
|
+
- alimente `messages/<sourceLocale>.json`
|
|
68
|
+
- traduit les locales cibles
|
|
69
|
+
- réécrit les fichiers sûrs
|
|
70
|
+
- tente les injections Next.js sûres
|
|
71
|
+
- signale clairement les parties à traiter manuellement
|
|
55
72
|
|
|
56
73
|
## Commandes
|
|
57
74
|
|
|
58
75
|
### `next-auto-i18n init`
|
|
59
76
|
|
|
60
|
-
|
|
77
|
+
Initialise le projet : scan, messages, traduction, réécriture, injection.
|
|
61
78
|
|
|
62
79
|
```bash
|
|
63
|
-
next-auto-i18n init
|
|
64
|
-
next-auto-i18n init --dry-run
|
|
65
|
-
next-auto-i18n init --locale en,es,de
|
|
80
|
+
next-auto-i18n init
|
|
81
|
+
next-auto-i18n init --dry-run
|
|
82
|
+
next-auto-i18n init --locale en,es,de
|
|
66
83
|
```
|
|
67
84
|
|
|
85
|
+
`--dry-run` montre d’abord un aperçu et demande confirmation avant d’appliquer.
|
|
86
|
+
|
|
68
87
|
### `next-auto-i18n sync`
|
|
69
88
|
|
|
70
|
-
Rescanne le projet,
|
|
89
|
+
Rescanne le projet, fusionne les nouvelles strings et synchronise les traductions sans régénérer toute la base.
|
|
71
90
|
|
|
72
91
|
```bash
|
|
73
92
|
next-auto-i18n sync
|
|
@@ -75,19 +94,30 @@ next-auto-i18n sync
|
|
|
75
94
|
|
|
76
95
|
### `next-auto-i18n extract`
|
|
77
96
|
|
|
78
|
-
|
|
97
|
+
Génère ou met à jour les fichiers `messages/*.json`, traduit, puis produit un guide Markdown sans modifier les fichiers source applicatifs.
|
|
79
98
|
|
|
80
99
|
```bash
|
|
81
|
-
next-auto-i18n extract
|
|
82
|
-
next-auto-i18n extract --out docs/i18n-guide.md
|
|
83
|
-
next-auto-i18n extract --
|
|
100
|
+
next-auto-i18n extract
|
|
101
|
+
next-auto-i18n extract --out docs/i18n-guide.md
|
|
102
|
+
next-auto-i18n extract --inject
|
|
103
|
+
next-auto-i18n extract --switcher
|
|
104
|
+
next-auto-i18n extract --no-module-scope
|
|
84
105
|
```
|
|
85
106
|
|
|
86
|
-
|
|
107
|
+
### `next-auto-i18n extract sync`
|
|
108
|
+
|
|
109
|
+
Version incrémentale de `extract`.
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
next-auto-i18n extract sync
|
|
113
|
+
next-auto-i18n extract sync --inject
|
|
114
|
+
next-auto-i18n extract sync --switcher
|
|
115
|
+
next-auto-i18n extract sync --no-module-scope
|
|
116
|
+
```
|
|
87
117
|
|
|
88
118
|
### `next-auto-i18n add-locale <locale>`
|
|
89
119
|
|
|
90
|
-
Ajoute une
|
|
120
|
+
Ajoute une locale cible, traduit les clés existantes et met à jour l’infrastructure Next.js avec les mêmes garde-fous que le reste du moteur.
|
|
91
121
|
|
|
92
122
|
```bash
|
|
93
123
|
next-auto-i18n add-locale ar
|
|
@@ -95,121 +125,117 @@ next-auto-i18n add-locale ar
|
|
|
95
125
|
|
|
96
126
|
### `next-auto-i18n missing`
|
|
97
127
|
|
|
98
|
-
Affiche les
|
|
128
|
+
Affiche les clés manquantes par locale cible.
|
|
99
129
|
|
|
100
130
|
```bash
|
|
101
131
|
next-auto-i18n missing
|
|
102
132
|
```
|
|
103
133
|
|
|
104
|
-
##
|
|
105
|
-
|
|
106
|
-
Le fichier `auto-i18n.config.json` est genere automatiquement :
|
|
107
|
-
|
|
108
|
-
```json
|
|
109
|
-
{
|
|
110
|
-
"sourceLocale": "fr",
|
|
111
|
-
"targetLocales": ["en", "es"],
|
|
112
|
-
"provider": "deepl",
|
|
113
|
-
"apiKeyEnv": "AUTO_I18N_DEEPL_KEY",
|
|
114
|
-
"messagesDir": "./messages",
|
|
115
|
-
"ignore": ["node_modules", ".next", "**/*.test.*", "**/*.spec.*"]
|
|
116
|
-
}
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
La cle API est stockee dans `.env.local` (jamais commitee) :
|
|
134
|
+
## Modèle de sécurité
|
|
120
135
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
136
|
+
- `.env.local` et `*.backup` sont ajoutés au `.gitignore`
|
|
137
|
+
- les placeholders de traduction sont validés avant écriture
|
|
138
|
+
- les réécritures ambiguës sont exclues au lieu d’être appliquées de force
|
|
139
|
+
- les injecteurs Next.js retournent `applicable`, `already_present`, `manual_required` ou `blocked`
|
|
140
|
+
- le run global peut finir en `partial` avec actions manuelles listées
|
|
124
141
|
|
|
125
|
-
##
|
|
142
|
+
## Compatibilité
|
|
126
143
|
|
|
127
|
-
###
|
|
144
|
+
### Structures de projet
|
|
128
145
|
|
|
129
|
-
|
|
146
|
+
| Structure | Statut | Notes |
|
|
147
|
+
|---|---|---|
|
|
148
|
+
| `app/` | supporté | cas principal |
|
|
149
|
+
| `src/app/` | supporté | supporté par le scanner et les injecteurs |
|
|
150
|
+
| `components/`, `ui/`, `features/`, `shared/` | supporté au scan | scan AST étendu |
|
|
151
|
+
| monorepo avec conventions très custom | partiel | dépend de la structure réellement scannée |
|
|
130
152
|
|
|
131
|
-
|
|
132
|
-
- Attributs : `placeholder="Rechercher..."`
|
|
133
|
-
- Template literals : `` `Bienvenue ${name}` ``
|
|
153
|
+
### Réécriture AST
|
|
134
154
|
|
|
135
|
-
|
|
155
|
+
| Cas | Statut | Comportement |
|
|
156
|
+
|---|---|---|
|
|
157
|
+
| texte JSX simple | supporté | réécriture automatique |
|
|
158
|
+
| attributs traduisibles | supporté | réécriture automatique |
|
|
159
|
+
| template literals simples | supporté | génération de clé + réécriture |
|
|
160
|
+
| strings module-scope | partiel | traduites, mais intégration souvent manuelle |
|
|
161
|
+
| JSX inline ambigu ou espaces sensibles | conservateur | exclu de la réécriture auto |
|
|
162
|
+
| fichier non parsable | bloqué | diagnostic remonté, aucune mutation |
|
|
136
163
|
|
|
137
|
-
###
|
|
164
|
+
### Injection Next.js
|
|
138
165
|
|
|
139
|
-
|
|
166
|
+
| Cible | Statut | Comportement |
|
|
167
|
+
|---|---|---|
|
|
168
|
+
| `next.config.*` | supporté | injection si sûre, sinon blocage explicite |
|
|
169
|
+
| `middleware.ts` / `proxy.ts` | supporté | création prudente selon contexte |
|
|
170
|
+
| `i18n/routing.ts` | supporté | création ou skip si déjà présent |
|
|
171
|
+
| `i18n/request.ts` | supporté | création ou skip si déjà présent |
|
|
172
|
+
| `LanguageSwitcher` | supporté | injecteur isolé possible |
|
|
173
|
+
| `app/[locale]/` | conservateur | refus explicite sur layout complexe |
|
|
140
174
|
|
|
141
|
-
|
|
142
|
-
|--------|-----|
|
|
143
|
-
| `Bonjour` | `bonjour` |
|
|
144
|
-
| `Ajouter au panier` | `ajouter_au_panier` |
|
|
145
|
-
| `` `Bienvenue ${name}` `` | `bienvenue_name` |
|
|
175
|
+
### Versions et dépendances
|
|
146
176
|
|
|
147
|
-
|
|
177
|
+
| Élément | Statut |
|
|
178
|
+
|---|---|
|
|
179
|
+
| Node.js 18+ | requis |
|
|
180
|
+
| Next.js App Router | requis |
|
|
181
|
+
| `next-intl` | requis |
|
|
182
|
+
| DeepL Free / Pro | supporté |
|
|
148
183
|
|
|
149
|
-
|
|
150
|
-
- Mode incrementiel : seules les cles manquantes sont traduites
|
|
151
|
-
- Compatible DeepL Free (500k chars/mois) et Pro
|
|
152
|
-
- Restauration automatique des entites HTML (`'`, `'`, etc.)
|
|
184
|
+
## Exemples de comportement
|
|
153
185
|
|
|
154
|
-
###
|
|
186
|
+
### Cas sûr
|
|
155
187
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
| `placeholder="Chercher"` | `placeholder={t("chercher")}` |
|
|
160
|
-
| `` `Salut ${name}` `` | `t("salut_name", { name })` |
|
|
188
|
+
```tsx
|
|
189
|
+
<p>Bonjour</p>
|
|
190
|
+
```
|
|
161
191
|
|
|
162
|
-
|
|
163
|
-
- Client Components : `useTranslations()` (next-intl)
|
|
164
|
-
- Les strings dans des `const` module-scope (hors composant) sont **detectees et signalees** avec le fichier + numero de ligne — elles sont traduites dans les JSON mais pas reecrites automatiquement (voir section suivante)
|
|
192
|
+
devient :
|
|
165
193
|
|
|
166
|
-
|
|
194
|
+
```tsx
|
|
195
|
+
<p>{t("bonjour")}</p>
|
|
196
|
+
```
|
|
167
197
|
|
|
168
|
-
|
|
198
|
+
### Cas module-scope
|
|
169
199
|
|
|
170
200
|
```tsx
|
|
171
|
-
|
|
172
|
-
const items = ['Accueil', 'A propos', 'Contact'];
|
|
173
|
-
|
|
174
|
-
// ✅ apres — deplacez la const dans le composant
|
|
175
|
-
export function Nav() {
|
|
176
|
-
const t = useTranslations();
|
|
177
|
-
const items = [t('accueil'), t('a_propos'), t('contact')];
|
|
178
|
-
}
|
|
201
|
+
const items = ['Accueil', 'Contact'];
|
|
179
202
|
```
|
|
180
203
|
|
|
181
|
-
|
|
204
|
+
Le package peut générer les messages, mais laissera une action manuelle plutôt que d’injecter `t()` à un endroit où il n’est pas accessible.
|
|
182
205
|
|
|
183
|
-
###
|
|
206
|
+
### Cas layout complexe
|
|
184
207
|
|
|
185
|
-
|
|
186
|
-
- `middleware.ts` / `proxy.ts` : routing i18n (proxy.ts si Next.js >= 16)
|
|
187
|
-
- `i18n/routing.ts` : definit les locales
|
|
188
|
-
- `i18n/request.ts` : configuration `getRequestConfig` pour les Server Components
|
|
189
|
-
- `app/[locale]/layout.tsx` : cree avec `NextIntlClientProvider` + `LanguageSwitcher`
|
|
190
|
-
- `app/[locale]/page.tsx` : la page existante est deplacee ici
|
|
191
|
-
- `app/layout.tsx` : simplifie en HTML shell (`<html><body>{children}</body></html>`)
|
|
208
|
+
Si le layout racine contient de la logique sensible ou certains patterns considérés à risque, l’injection de `app/[locale]` est marquée `manual required`. Les autres injections sûres peuvent continuer.
|
|
192
209
|
|
|
193
|
-
|
|
210
|
+
## Configuration
|
|
194
211
|
|
|
195
|
-
|
|
212
|
+
Le fichier `auto-i18n.config.json` est généré automatiquement :
|
|
196
213
|
|
|
197
|
-
|
|
214
|
+
```json
|
|
215
|
+
{
|
|
216
|
+
"sourceLocale": "fr",
|
|
217
|
+
"targetLocales": ["en", "es"],
|
|
218
|
+
"provider": "deepl",
|
|
219
|
+
"apiKeyEnv": "AUTO_I18N_DEEPL_KEY",
|
|
220
|
+
"messagesDir": "./messages",
|
|
221
|
+
"ignore": ["node_modules", ".next", "**/*.test.*", "**/*.spec.*"]
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
La clé API est stockée dans `.env.local` :
|
|
198
226
|
|
|
199
|
-
|
|
200
|
-
-
|
|
201
|
-
|
|
202
|
-
- Backups automatiques (`*.backup`) avant chaque reecriture
|
|
227
|
+
```bash
|
|
228
|
+
AUTO_I18N_DEEPL_KEY=votre-cle
|
|
229
|
+
```
|
|
203
230
|
|
|
204
|
-
##
|
|
231
|
+
## Développement
|
|
205
232
|
|
|
206
233
|
```bash
|
|
207
|
-
git clone https://github.com/stvekoulo/auto-i18n.git
|
|
234
|
+
git clone https://github.com/stvekoulo/next-auto-i18n.git
|
|
208
235
|
cd next-auto-i18n
|
|
209
236
|
npm install
|
|
210
|
-
npm
|
|
211
|
-
npm
|
|
212
|
-
npm run dev -- init # test local
|
|
237
|
+
npm run build
|
|
238
|
+
npm test
|
|
213
239
|
```
|
|
214
240
|
|
|
215
241
|
## Licence
|
|
@@ -4,14 +4,13 @@ export interface FileDocEntry {
|
|
|
4
4
|
/** Chemin relatif depuis projectRoot (pour l'affichage). */
|
|
5
5
|
relPath: string;
|
|
6
6
|
strings: ExtractedString[];
|
|
7
|
-
/** Valeurs des strings au module-scope
|
|
7
|
+
/** Valeurs des strings au module-scope. */
|
|
8
8
|
moduleScopeValues: Set<string>;
|
|
9
9
|
}
|
|
10
10
|
export interface DocOptions {
|
|
11
11
|
projectRoot: string;
|
|
12
12
|
sourceLocale: string;
|
|
13
13
|
targetLocales: string[];
|
|
14
|
-
/** Chemin relatif du dossier messages (pour l'affichage). */
|
|
15
14
|
messagesDir: string;
|
|
16
15
|
keyMap: Map<string, string>;
|
|
17
16
|
files: FileDocEntry[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doc-generator.d.ts","sourceRoot":"","sources":["../../src/cli/doc-generator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAEtE,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,
|
|
1
|
+
{"version":3,"file":"doc-generator.d.ts","sourceRoot":"","sources":["../../src/cli/doc-generator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAEtE,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,2CAA2C;IAC3C,iBAAiB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAgCD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,CA+JpD;AAED,wBAAsB,WAAW,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAGpE"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { writeFile } from 'fs/promises';
|
|
2
|
-
// ── Helpers ────────────────────────────────────────────────────────────────
|
|
3
2
|
function escapeCell(s) {
|
|
4
3
|
return s.replace(/\|/g, '\\|').replace(/[\r\n]+/g, ' ');
|
|
5
4
|
}
|
|
@@ -25,19 +24,16 @@ function replacementCode(s, key) {
|
|
|
25
24
|
}
|
|
26
25
|
return `{t("${key}")}`;
|
|
27
26
|
}
|
|
28
|
-
// ── Markdown builder ───────────────────────────────────────────────────────
|
|
29
27
|
export function buildDoc(options) {
|
|
30
28
|
const { sourceLocale, targetLocales, messagesDir, keyMap, files, date } = options;
|
|
31
29
|
const totalStrings = files.reduce((sum, f) => sum + f.strings.length, 0);
|
|
32
30
|
const totalKeys = keyMap.size;
|
|
33
31
|
const moduleScopeTotal = files.reduce((sum, f) => sum + f.moduleScopeValues.size, 0);
|
|
34
32
|
const L = [];
|
|
35
|
-
// ── En-tête ──────────────────────────────────────────────────────────────
|
|
36
33
|
L.push('# Guide d\'intégration i18n — next-auto-i18n');
|
|
37
34
|
L.push('');
|
|
38
35
|
L.push(`> Généré le **${date}** · ✅ Aucun fichier source modifié.`);
|
|
39
36
|
L.push('');
|
|
40
|
-
// ── Résumé ───────────────────────────────────────────────────────────────
|
|
41
37
|
L.push('## Résumé');
|
|
42
38
|
L.push('');
|
|
43
39
|
L.push(`| | |`);
|
|
@@ -49,7 +45,6 @@ export function buildDoc(options) {
|
|
|
49
45
|
L.push(`| ⚠️ Action manuelle | **${moduleScopeTotal}** string${moduleScopeTotal > 1 ? 's' : ''} module-scope (voir section dédiée) |`);
|
|
50
46
|
}
|
|
51
47
|
L.push('');
|
|
52
|
-
// ── Fichiers générés ─────────────────────────────────────────────────────
|
|
53
48
|
L.push('## Fichiers générés');
|
|
54
49
|
L.push('');
|
|
55
50
|
L.push('| Fichier | Description |');
|
|
@@ -59,7 +54,6 @@ export function buildDoc(options) {
|
|
|
59
54
|
L.push(`| \`${messagesDir}/${locale}.json\` | Traductions (${locale}) |`);
|
|
60
55
|
}
|
|
61
56
|
L.push('');
|
|
62
|
-
// ── Guide d'utilisation ───────────────────────────────────────────────────
|
|
63
57
|
L.push('## Comment utiliser les traductions');
|
|
64
58
|
L.push('');
|
|
65
59
|
L.push('### Composant Client (`\'use client\'`)');
|
|
@@ -87,7 +81,6 @@ export function buildDoc(options) {
|
|
|
87
81
|
L.push('');
|
|
88
82
|
L.push('> 💡 Lancez `npx next-auto-i18n init` pour configurer automatiquement le routing, le middleware et les layouts.');
|
|
89
83
|
L.push('');
|
|
90
|
-
// ── Section module-scope ─────────────────────────────────────────────────
|
|
91
84
|
if (moduleScopeTotal > 0) {
|
|
92
85
|
L.push('---');
|
|
93
86
|
L.push('');
|
|
@@ -116,7 +109,6 @@ export function buildDoc(options) {
|
|
|
116
109
|
L.push('```');
|
|
117
110
|
L.push('');
|
|
118
111
|
}
|
|
119
|
-
// ── Strings par fichier ───────────────────────────────────────────────────
|
|
120
112
|
L.push('---');
|
|
121
113
|
L.push('');
|
|
122
114
|
L.push('## Strings par fichier');
|
|
@@ -134,7 +126,6 @@ export function buildDoc(options) {
|
|
|
134
126
|
L.push(`> ⚠️ **${moduleScopeValues.size}** string${moduleScopeValues.size > 1 ? 's' : ''} module-scope dans ce fichier.`);
|
|
135
127
|
L.push('');
|
|
136
128
|
}
|
|
137
|
-
// Strings auto-remplaçables
|
|
138
129
|
if (autoStrings.length > 0) {
|
|
139
130
|
if (hasModuleScope)
|
|
140
131
|
L.push('**Remplacements automatiques :**');
|
|
@@ -149,7 +140,6 @@ export function buildDoc(options) {
|
|
|
149
140
|
}
|
|
150
141
|
L.push('');
|
|
151
142
|
}
|
|
152
|
-
// Strings module-scope (action manuelle)
|
|
153
143
|
if (manualStrings.length > 0) {
|
|
154
144
|
L.push('**Action manuelle requise (module-scope) :**');
|
|
155
145
|
L.push('');
|
|
@@ -167,7 +157,6 @@ export function buildDoc(options) {
|
|
|
167
157
|
L.push('---');
|
|
168
158
|
L.push('');
|
|
169
159
|
}
|
|
170
|
-
// ── Toutes les clés ───────────────────────────────────────────────────────
|
|
171
160
|
L.push('## Référence complète des clés');
|
|
172
161
|
L.push('');
|
|
173
162
|
L.push(`Toutes les clés générées dans \`${messagesDir}/${sourceLocale}.json\` :`);
|