@translation-cms/sync 1.2.10 → 1.2.12
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/README.md +301 -156
- package/dist/api.d.ts +79 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +151 -0
- package/dist/api.js.map +1 -0
- package/dist/bin.js +51 -17
- package/dist/bin.js.map +1 -1
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +18 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/pull.d.ts +7 -0
- package/dist/commands/pull.d.ts.map +1 -1
- package/dist/commands/pull.js +15 -2
- package/dist/commands/pull.js.map +1 -1
- package/dist/commands/status.d.ts +12 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +16 -0
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/sync.d.ts +10 -0
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +19 -3
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/watch.d.ts +14 -0
- package/dist/commands/watch.d.ts.map +1 -1
- package/dist/commands/watch.js +23 -3
- package/dist/commands/watch.js.map +1 -1
- package/dist/config/config-internals/args.d.ts +11 -0
- package/dist/config/config-internals/args.d.ts.map +1 -0
- package/dist/config/config-internals/args.js +22 -0
- package/dist/config/config-internals/args.js.map +1 -0
- package/dist/config/config-internals/env.d.ts +10 -0
- package/dist/config/config-internals/env.d.ts.map +1 -0
- package/dist/config/config-internals/env.js +35 -0
- package/dist/config/config-internals/env.js.map +1 -0
- package/dist/config/config-internals/file.d.ts +11 -0
- package/dist/config/config-internals/file.d.ts.map +1 -0
- package/dist/config/config-internals/file.js +28 -0
- package/dist/config/config-internals/file.js.map +1 -0
- package/dist/config/config-internals/resolve.d.ts +21 -0
- package/dist/config/config-internals/resolve.d.ts.map +1 -0
- package/dist/config/config-internals/resolve.js +73 -0
- package/dist/config/config-internals/resolve.js.map +1 -0
- package/dist/config/config-internals/root.d.ts +9 -0
- package/dist/config/config-internals/root.d.ts.map +1 -0
- package/dist/config/config-internals/root.js +22 -0
- package/dist/config/config-internals/root.js.map +1 -0
- package/dist/config/config-internals/types.d.ts +83 -0
- package/dist/config/config-internals/types.d.ts.map +1 -0
- package/dist/config/config-internals/types.js +9 -0
- package/dist/config/config-internals/types.js.map +1 -0
- package/dist/config/resolve-config.d.ts +9 -90
- package/dist/config/resolve-config.d.ts.map +1 -1
- package/dist/config/resolve-config.js +7 -123
- package/dist/config/resolve-config.js.map +1 -1
- package/dist/core/api-internals/pull.d.ts +9 -1
- package/dist/core/api-internals/pull.d.ts.map +1 -1
- package/dist/core/api-internals/pull.js +41 -28
- package/dist/core/api-internals/pull.js.map +1 -1
- package/dist/core/api-internals/sync.d.ts +9 -2
- package/dist/core/api-internals/sync.d.ts.map +1 -1
- package/dist/core/api-internals/sync.js +18 -2
- package/dist/core/api-internals/sync.js.map +1 -1
- package/dist/core/cache-internals/format.d.ts +16 -0
- package/dist/core/cache-internals/format.d.ts.map +1 -1
- package/dist/core/cache-internals/format.js +17 -0
- package/dist/core/cache-internals/format.js.map +1 -1
- package/dist/core/cache-internals/params.d.ts.map +1 -1
- package/dist/core/cache-internals/params.js +24 -24
- package/dist/core/cache-internals/params.js.map +1 -1
- package/dist/core/cache-internals/pull.d.ts +12 -0
- package/dist/core/cache-internals/pull.d.ts.map +1 -1
- package/dist/core/cache-internals/pull.js +13 -0
- package/dist/core/cache-internals/pull.js.map +1 -1
- package/dist/core/cache-internals/sync.d.ts +23 -0
- package/dist/core/cache-internals/sync.d.ts.map +1 -1
- package/dist/core/cache-internals/sync.js +33 -0
- package/dist/core/cache-internals/sync.js.map +1 -1
- package/dist/core/cache-internals/types.d.ts +20 -0
- package/dist/core/cache-internals/types.d.ts.map +1 -1
- package/dist/core/scanner-internals/ast.d.ts +23 -5
- package/dist/core/scanner-internals/ast.d.ts.map +1 -1
- package/dist/core/scanner-internals/ast.js +25 -5
- package/dist/core/scanner-internals/ast.js.map +1 -1
- package/dist/core/scanner-internals/file-walker.d.ts +3 -2
- package/dist/core/scanner-internals/file-walker.d.ts.map +1 -1
- package/dist/core/scanner-internals/file-walker.js +10 -12
- package/dist/core/scanner-internals/file-walker.js.map +1 -1
- package/dist/core/scanner-internals/import-resolver.d.ts +9 -1
- package/dist/core/scanner-internals/import-resolver.d.ts.map +1 -1
- package/dist/core/scanner-internals/import-resolver.js +58 -63
- package/dist/core/scanner-internals/import-resolver.js.map +1 -1
- package/dist/core/scanner-internals/key-extractor.d.ts +12 -8
- package/dist/core/scanner-internals/key-extractor.d.ts.map +1 -1
- package/dist/core/scanner-internals/key-extractor.js +125 -97
- package/dist/core/scanner-internals/key-extractor.js.map +1 -1
- package/dist/core/scanner-internals/route-detector.d.ts +16 -8
- package/dist/core/scanner-internals/route-detector.d.ts.map +1 -1
- package/dist/core/scanner-internals/route-detector.js +37 -33
- package/dist/core/scanner-internals/route-detector.js.map +1 -1
- package/dist/core/scanner.d.ts.map +1 -1
- package/dist/core/scanner.js +25 -8
- package/dist/core/scanner.js.map +1 -1
- package/dist/next.d.ts +28 -0
- package/dist/next.d.ts.map +1 -0
- package/dist/next.js +65 -0
- package/dist/next.js.map +1 -0
- package/dist/preview/internals/highlight.d.ts +16 -7
- package/dist/preview/internals/highlight.d.ts.map +1 -1
- package/dist/preview/internals/highlight.js +71 -60
- package/dist/preview/internals/highlight.js.map +1 -1
- package/dist/scaffold/intenrals/scaffold.d.ts +17 -0
- package/dist/scaffold/intenrals/scaffold.d.ts.map +1 -1
- package/dist/scaffold/intenrals/scaffold.js +19 -0
- package/dist/scaffold/intenrals/scaffold.js.map +1 -1
- package/package.json +16 -3
package/README.md
CHANGED
|
@@ -1,18 +1,98 @@
|
|
|
1
1
|
# @translation-cms/sync
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
CMS,
|
|
5
|
-
i18next.
|
|
3
|
+
Automatically scan translation keys from your codebase, sync with the
|
|
4
|
+
Translations CMS, and fetch translations as local JSON files. Built for
|
|
5
|
+
Next.js + i18next.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Integration Methods
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Choose the approach that fits your workflow:
|
|
10
10
|
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
|
|
11
|
+
- **Next.js Plugin** (Recommended) — Automatic sync on `next dev` and
|
|
12
|
+
`next build`
|
|
13
|
+
- **CLI** (Manual) — `pnpm sync-translations` for on-demand control
|
|
14
|
+
- **Programmatic API** — Call sync/pull directly in your code or scripts
|
|
15
|
+
|
|
16
|
+
### Method 1: Next.js Plugin (Automatic)
|
|
17
|
+
|
|
18
|
+
Edit `next.config.ts`:
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import withTranslationsCMS from '@translation-cms/sync/next';
|
|
22
|
+
|
|
23
|
+
export default withTranslationsCMS(
|
|
24
|
+
{
|
|
25
|
+
// your Next.js config
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
pullOnBuild: true, // auto pull on build
|
|
29
|
+
pullOnDev: true, // auto pull on dev startup
|
|
30
|
+
}
|
|
31
|
+
);
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Your translations sync automatically. That's it. No extra commands needed.
|
|
35
|
+
|
|
36
|
+
### Method 2: CLI (Manual)
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# Scan code + upload to CMS
|
|
40
|
+
pnpm sync-translations sync
|
|
41
|
+
|
|
42
|
+
# Download translations
|
|
43
|
+
pnpm sync-translations pull
|
|
44
|
+
|
|
45
|
+
# Watch mode — auto-sync on file changes
|
|
46
|
+
pnpm sync-translations watch
|
|
47
|
+
|
|
48
|
+
# Interactive setup
|
|
49
|
+
pnpm sync-translations init
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Method 3: Programmatic API
|
|
53
|
+
|
|
54
|
+
Use in scripts, build tools, or CI/CD:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import { syncTranslations, pullTranslations } from '@translation-cms/sync/api';
|
|
58
|
+
|
|
59
|
+
// Scan and upload keys
|
|
60
|
+
await syncTranslations({
|
|
61
|
+
projectRoot: './my-app',
|
|
62
|
+
verbose: true,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Download translations
|
|
66
|
+
await pullTranslations({
|
|
67
|
+
projectRoot: './my-app',
|
|
68
|
+
environment: 'production',
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Sync and pull in one go
|
|
72
|
+
import { syncAndPull } from '@translation-cms/sync/api';
|
|
73
|
+
await syncAndPull({ projectRoot: './my-app' });
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Choose Your Method
|
|
77
|
+
|
|
78
|
+
| Method | When to Use | Setup Time |
|
|
79
|
+
| -------------------- | --------------------------------- | ---------- |
|
|
80
|
+
| **Next.js Plugin** | Team projects, automatic workflow | 5 min |
|
|
81
|
+
| **CLI** | Manual control, debugging, CI/CD | 10 min |
|
|
82
|
+
| **Programmatic API** | Custom workflows, scripts | 5 min |
|
|
83
|
+
|
|
84
|
+
**Recommended:** Start with the **Next.js Plugin** for automatic updates during
|
|
85
|
+
development, then add CLI or API commands as needed.
|
|
86
|
+
|
|
87
|
+
## What is this?
|
|
88
|
+
|
|
89
|
+
Hybrid translation management system with three integration methods:
|
|
90
|
+
|
|
91
|
+
- **Scans** your code for translation keys (React-i18next pattern)
|
|
92
|
+
- **Syncs** new keys to the Translations CMS
|
|
93
|
+
- **Fetches** translations as JSON files
|
|
94
|
+
- **Automatic or manual** — choose what works for your team
|
|
95
|
+
- **Programmatic API** — bring your own CI/CD or tooling
|
|
16
96
|
|
|
17
97
|
```
|
|
18
98
|
Your Code → scan → CMS → pull → JSON files → i18next → Your App
|
|
@@ -20,32 +100,87 @@ Your Code → scan → CMS → pull → JSON files → i18next → Your App
|
|
|
20
100
|
|
|
21
101
|
---
|
|
22
102
|
|
|
23
|
-
|
|
103
|
+
## Programmatic API Reference
|
|
104
|
+
|
|
105
|
+
Use these functions when you need fine-grained control or integration with
|
|
106
|
+
custom workflows. Perfect for CI/CD pipelines, build tools, or custom scripts.
|
|
107
|
+
|
|
108
|
+
### `syncTranslations(options?)`
|
|
24
109
|
|
|
25
|
-
|
|
110
|
+
Scans your codebase for translation keys and uploads them to the CMS.
|
|
26
111
|
|
|
27
|
-
|
|
112
|
+
```ts
|
|
113
|
+
import { syncTranslations } from '@translation-cms/sync/api';
|
|
114
|
+
|
|
115
|
+
const result = await syncTranslations({
|
|
116
|
+
projectRoot: './apps/web', // auto-detect if omitted
|
|
117
|
+
dryRun: false, // preview without uploading
|
|
118
|
+
force: false, // ignore cache
|
|
119
|
+
reportPath: './sync-report.json', // optional report output
|
|
120
|
+
verbose: true, // detailed logging
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
console.log(`Added ${result.keysAdded} keys`);
|
|
124
|
+
```
|
|
28
125
|
|
|
29
|
-
|
|
30
|
-
- ✅ pnpm (aanbevolen) of npm
|
|
31
|
-
- ✅ Translations CMS account + project aangemaakt
|
|
32
|
-
- ✅ CMS project credentials (URL, project ID, API key)
|
|
126
|
+
### `pullTranslations(options?)`
|
|
33
127
|
|
|
34
|
-
|
|
128
|
+
Fetches translations from the CMS and writes them as JSON files.
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
import { pullTranslations } from '@translation-cms/sync/api';
|
|
132
|
+
|
|
133
|
+
const result = await pullTranslations({
|
|
134
|
+
projectRoot: './apps/web', // auto-detect if omitted
|
|
135
|
+
outputDir: './src/i18n/locales', // custom output location
|
|
136
|
+
force: false, // ignore cache
|
|
137
|
+
ttl: 300000, // cache duration in ms
|
|
138
|
+
environment: 'production', // pull from specific env
|
|
139
|
+
verbose: true, // detailed logging
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### `syncAndPull(options?)`
|
|
144
|
+
|
|
145
|
+
Convenience function: sync keys then pull translations in one call.
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
import { syncAndPull } from '@translation-cms/sync/api';
|
|
149
|
+
|
|
150
|
+
const { synced, pulled } = await syncAndPull({
|
|
151
|
+
projectRoot: './apps/web',
|
|
152
|
+
verbose: true,
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
# Setup Guide — From Zero to Working
|
|
159
|
+
|
|
160
|
+
## Step 1: Prerequisites
|
|
161
|
+
|
|
162
|
+
Check what you need:
|
|
163
|
+
|
|
164
|
+
- Next.js project (v14+)
|
|
165
|
+
- pnpm (recommended) or npm
|
|
166
|
+
- Translations CMS account + project created
|
|
167
|
+
- CMS project credentials (URL, project ID, API key)
|
|
168
|
+
|
|
169
|
+
## Step 2: Installation
|
|
35
170
|
|
|
36
171
|
```bash
|
|
37
172
|
pnpm add @translation-cms/sync
|
|
38
173
|
```
|
|
39
174
|
|
|
40
|
-
Plus
|
|
175
|
+
Plus the peer dependencies:
|
|
41
176
|
|
|
42
177
|
```bash
|
|
43
178
|
pnpm add i18next react-i18next i18next-resources-to-backend
|
|
44
179
|
```
|
|
45
180
|
|
|
46
|
-
##
|
|
181
|
+
## Step 3: Set Up CMS Credentials
|
|
47
182
|
|
|
48
|
-
|
|
183
|
+
Create `.env.local` in your project root:
|
|
49
184
|
|
|
50
185
|
```bash
|
|
51
186
|
NEXT_PUBLIC_CMS_URL=https://cms.example.com
|
|
@@ -53,38 +188,37 @@ NEXT_PUBLIC_CMS_PROJECT_ID=your-project-id
|
|
|
53
188
|
CMS_SYNC_API_KEY=your-jwt-api-key
|
|
54
189
|
```
|
|
55
190
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
JWT te genereren.
|
|
191
|
+
The `CMS_SYNC_API_KEY` is a **JWT token**. You can find it in the CMS under
|
|
192
|
+
**Project Settings → Environments → your environment → API Key**. If the key
|
|
193
|
+
there still looks like a UUID, use "Regenerate" to generate a JWT.
|
|
60
194
|
|
|
61
|
-
> **
|
|
62
|
-
>
|
|
63
|
-
> `NEXT_PUBLIC_CMS_ANON_KEY`
|
|
195
|
+
> **Note:** use `CMS_SYNC_API_KEY` (without `NEXT_PUBLIC_`). This prevents the
|
|
196
|
+
> JWT from accidentally ending up in the browser. The old name
|
|
197
|
+
> `NEXT_PUBLIC_CMS_ANON_KEY` still works as a fallback, but is discouraged.
|
|
64
198
|
|
|
65
|
-
##
|
|
199
|
+
## Step 4: Automatic Setup (Recommended)
|
|
66
200
|
|
|
67
|
-
Run
|
|
201
|
+
Run the interactive setup wizard:
|
|
68
202
|
|
|
69
203
|
```bash
|
|
70
204
|
pnpm sync-translations init
|
|
71
205
|
```
|
|
72
206
|
|
|
73
|
-
|
|
207
|
+
This automatically creates:
|
|
74
208
|
|
|
75
209
|
```
|
|
76
210
|
src/lib/i18n/
|
|
77
|
-
├── settings.ts # i18next
|
|
78
|
-
├── types.ts # TypeScript types
|
|
211
|
+
├── settings.ts # i18next configuration
|
|
212
|
+
├── types.ts # TypeScript types for translations
|
|
79
213
|
├── client.ts # 'use client' hook + static imports
|
|
80
214
|
├── server.ts # Server component support
|
|
81
215
|
├── provider.tsx # Provider wrapper
|
|
82
216
|
└── dictionaries/
|
|
83
|
-
├── en.json #
|
|
84
|
-
└── nl.json #
|
|
217
|
+
├── en.json # English (empty, filled by pull)
|
|
218
|
+
└── nl.json # Dutch (empty, filled by pull)
|
|
85
219
|
```
|
|
86
220
|
|
|
87
|
-
|
|
221
|
+
Also `.translationsrc.json` is generated:
|
|
88
222
|
|
|
89
223
|
```json
|
|
90
224
|
{
|
|
@@ -95,57 +229,56 @@ Ook `.translationsrc.json` wordt gegenereerd:
|
|
|
95
229
|
}
|
|
96
230
|
```
|
|
97
231
|
|
|
98
|
-
**
|
|
99
|
-
sensible defaults
|
|
232
|
+
**Note:** `routeParams` can stay empty! The scanner automatically generates
|
|
233
|
+
sensible defaults for all dynamic routes.
|
|
100
234
|
|
|
101
|
-
##
|
|
235
|
+
## Step 5: First Sync — Upload Keys
|
|
102
236
|
|
|
103
|
-
Scan
|
|
237
|
+
Scan your code and upload detected keys to the CMS:
|
|
104
238
|
|
|
105
239
|
```bash
|
|
106
240
|
pnpm sync-translations sync
|
|
107
241
|
```
|
|
108
242
|
|
|
109
|
-
|
|
243
|
+
This will:
|
|
110
244
|
|
|
111
|
-
1.
|
|
112
|
-
2.
|
|
113
|
-
3.
|
|
114
|
-
4.
|
|
245
|
+
1. Scan your code for translation keys (`t('namespace:key')` pattern)
|
|
246
|
+
2. Detect routes where each key is used
|
|
247
|
+
3. Upload new keys to CMS
|
|
248
|
+
4. Show report (which keys added/changed)
|
|
115
249
|
|
|
116
|
-
|
|
250
|
+
Check in the CMS if your keys appeared.
|
|
117
251
|
|
|
118
|
-
**
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
opnieuw.
|
|
252
|
+
**On first sync:** you might get an error that no translations can be downloaded
|
|
253
|
+
— this is normal! The keys were just uploaded but don't have translations yet.
|
|
254
|
+
Go to your CMS, fill in translations, then run `pull` again.
|
|
122
255
|
|
|
123
|
-
##
|
|
256
|
+
## Step 5b: Add Translations in CMS
|
|
124
257
|
|
|
125
|
-
1. Open
|
|
126
|
-
2.
|
|
127
|
-
3.
|
|
128
|
-
4.
|
|
258
|
+
1. Open your Translations CMS project
|
|
259
|
+
2. Your keys are now listed (without translations)
|
|
260
|
+
3. Fill in translations per locale (English, Dutch, etc.)
|
|
261
|
+
4. Click Save
|
|
129
262
|
|
|
130
|
-
##
|
|
263
|
+
## Step 6: Fetch Translations
|
|
131
264
|
|
|
132
|
-
|
|
265
|
+
If you've done the first sync AND filled in translations in the CMS:
|
|
133
266
|
|
|
134
267
|
```bash
|
|
135
268
|
pnpm sync-translations pull
|
|
136
269
|
```
|
|
137
270
|
|
|
138
|
-
|
|
271
|
+
This fetches translations from the CMS and writes them to local JSON:
|
|
139
272
|
|
|
140
|
-
- `dictionaries/en.json` → English
|
|
141
|
-
- `dictionaries/nl.json` →
|
|
142
|
-
- etc. (
|
|
273
|
+
- `dictionaries/en.json` → English translations
|
|
274
|
+
- `dictionaries/nl.json` → Dutch translations
|
|
275
|
+
- etc. (one per locale)
|
|
143
276
|
|
|
144
|
-
##
|
|
277
|
+
## Step 7: Integration in Your Project
|
|
145
278
|
|
|
146
279
|
### A. Root Layout Setup
|
|
147
280
|
|
|
148
|
-
|
|
281
|
+
Add the provider to your `src/app/layout.tsx`:
|
|
149
282
|
|
|
150
283
|
```tsx
|
|
151
284
|
import { TranslationProvider } from '@/lib/i18n/provider';
|
|
@@ -165,7 +298,7 @@ export default function RootLayout({
|
|
|
165
298
|
}
|
|
166
299
|
```
|
|
167
300
|
|
|
168
|
-
### B. Server Components (
|
|
301
|
+
### B. Server Components (Recommended)
|
|
169
302
|
|
|
170
303
|
```tsx
|
|
171
304
|
import { getTranslation } from '@/lib/i18n/server';
|
|
@@ -195,22 +328,22 @@ export function MyButton() {
|
|
|
195
328
|
}
|
|
196
329
|
```
|
|
197
330
|
|
|
198
|
-
### D. Multiple Namespaces (
|
|
331
|
+
### D. Multiple Namespaces (With Type-Checking)
|
|
199
332
|
|
|
200
333
|
```tsx
|
|
201
334
|
const { t } = useTranslation(['common', 'auth']);
|
|
202
335
|
|
|
203
|
-
//
|
|
336
|
+
// This works
|
|
204
337
|
t('common:nav.home');
|
|
205
338
|
t('auth:login.email');
|
|
206
339
|
|
|
207
|
-
//
|
|
208
|
-
t('payments:amount'); // namespace
|
|
340
|
+
// This gives a type error
|
|
341
|
+
t('payments:amount'); // namespace not added
|
|
209
342
|
```
|
|
210
343
|
|
|
211
|
-
##
|
|
344
|
+
## Step 8: Automatic Sync in Your Workflow
|
|
212
345
|
|
|
213
|
-
|
|
346
|
+
Add this to `package.json`:
|
|
214
347
|
|
|
215
348
|
```json
|
|
216
349
|
{
|
|
@@ -221,14 +354,14 @@ Voeg dit toe aan `package.json`:
|
|
|
221
354
|
}
|
|
222
355
|
```
|
|
223
356
|
|
|
224
|
-
|
|
357
|
+
Now you automatically pull the latest translations on startup.
|
|
225
358
|
|
|
226
|
-
##
|
|
359
|
+
## Step 9 (Optional): Set Up Preview Mode
|
|
227
360
|
|
|
228
|
-
Enable live in-context preview — editors
|
|
229
|
-
app
|
|
361
|
+
Enable live in-context preview — editors can live see how their text looks in
|
|
362
|
+
your app.
|
|
230
363
|
|
|
231
|
-
|
|
364
|
+
Add this to your root layout:
|
|
232
365
|
|
|
233
366
|
```tsx
|
|
234
367
|
'use client';
|
|
@@ -240,7 +373,7 @@ export function CMSPreview() {
|
|
|
240
373
|
if (process.env.NODE_ENV === 'development') {
|
|
241
374
|
initPreviewListener({
|
|
242
375
|
onLocaleSwitch: locale => {
|
|
243
|
-
//
|
|
376
|
+
// change language if CMS selects a different locale
|
|
244
377
|
window.location.href = `/${locale}`;
|
|
245
378
|
},
|
|
246
379
|
});
|
|
@@ -250,7 +383,7 @@ export function CMSPreview() {
|
|
|
250
383
|
}
|
|
251
384
|
```
|
|
252
385
|
|
|
253
|
-
|
|
386
|
+
And add to layout:
|
|
254
387
|
|
|
255
388
|
```tsx
|
|
256
389
|
<TranslationProvider>
|
|
@@ -259,7 +392,7 @@ En voeg toe in layout:
|
|
|
259
392
|
</TranslationProvider>
|
|
260
393
|
```
|
|
261
394
|
|
|
262
|
-
|
|
395
|
+
Add `data-cms-key` to elements for precise highlighting:
|
|
263
396
|
|
|
264
397
|
```tsx
|
|
265
398
|
<h1 data-cms-key="common:page.title">{t('common:page.title')}</h1>
|
|
@@ -269,110 +402,122 @@ Voeg `data-cms-key` toe op elementen voor nauwkeurige highlighting:
|
|
|
269
402
|
|
|
270
403
|
# CLI Commands Reference
|
|
271
404
|
|
|
272
|
-
##
|
|
405
|
+
## Basic Commands
|
|
273
406
|
|
|
274
407
|
```bash
|
|
275
|
-
# Scan code + upload
|
|
408
|
+
# Scan code + upload to CMS
|
|
276
409
|
pnpm sync-translations sync
|
|
277
410
|
|
|
278
|
-
# Download
|
|
411
|
+
# Download translations to local JSON
|
|
279
412
|
pnpm sync-translations pull
|
|
280
413
|
|
|
281
|
-
#
|
|
414
|
+
# See what would change (without upload)
|
|
282
415
|
pnpm sync-translations sync --dry-run
|
|
283
416
|
|
|
284
|
-
#
|
|
417
|
+
# See difference from previous sync
|
|
285
418
|
pnpm sync-translations status
|
|
286
419
|
|
|
287
|
-
# Watch mode — auto-sync
|
|
420
|
+
# Watch mode — auto-sync on file changes
|
|
288
421
|
pnpm sync-translations watch
|
|
289
422
|
|
|
290
|
-
#
|
|
423
|
+
# Interactive setup
|
|
291
424
|
pnpm sync-translations init
|
|
292
425
|
```
|
|
293
426
|
|
|
294
427
|
## Advanced Flags
|
|
295
428
|
|
|
296
|
-
| Flag |
|
|
297
|
-
| ----------------- |
|
|
298
|
-
| `--dry-run` |
|
|
299
|
-
| `--force` |
|
|
300
|
-
| `--output <dir>` | Custom output
|
|
301
|
-
| `--env <name>` | Pull
|
|
302
|
-
| `--ttl <ms>` |
|
|
303
|
-
| `--project-id` |
|
|
304
|
-
| `--api-key` |
|
|
305
|
-
| `--cms-url` |
|
|
306
|
-
| `--report <file>` |
|
|
429
|
+
| Flag | Description |
|
|
430
|
+
| ----------------- | ---------------------------------------- |
|
|
431
|
+
| `--dry-run` | Show changes, don't execute |
|
|
432
|
+
| `--force` | Ignore cache, force refresh |
|
|
433
|
+
| `--output <dir>` | Custom output directory for JSON |
|
|
434
|
+
| `--env <name>` | Pull from staging/production environment |
|
|
435
|
+
| `--ttl <ms>` | Override cache TTL (ms) |
|
|
436
|
+
| `--project-id` | Override project ID |
|
|
437
|
+
| `--api-key` | Override API key |
|
|
438
|
+
| `--cms-url` | Override CMS URL |
|
|
439
|
+
| `--report <file>` | Write sync report to JSON file |
|
|
307
440
|
|
|
308
|
-
##
|
|
441
|
+
## Examples
|
|
309
442
|
|
|
310
443
|
```bash
|
|
311
|
-
# Force refresh,
|
|
444
|
+
# Force refresh, ignore cache
|
|
312
445
|
pnpm sync-translations pull --force
|
|
313
446
|
|
|
314
447
|
# Custom output directory
|
|
315
448
|
pnpm sync-translations pull --output ./locales
|
|
316
449
|
|
|
317
|
-
# Pull
|
|
450
|
+
# Pull from staging environment
|
|
318
451
|
pnpm sync-translations pull --env staging
|
|
319
452
|
|
|
320
|
-
#
|
|
453
|
+
# Write report of changes
|
|
321
454
|
pnpm sync-translations sync --report ./sync-report.json
|
|
322
455
|
```
|
|
323
456
|
|
|
324
457
|
---
|
|
325
458
|
|
|
326
|
-
# Key Scanner —
|
|
459
|
+
# Key Scanner — How It Works
|
|
327
460
|
|
|
328
|
-
|
|
461
|
+
The tool recognizes these patterns in your code:
|
|
329
462
|
|
|
330
463
|
```ts
|
|
331
|
-
//
|
|
464
|
+
// React-i18next hook
|
|
332
465
|
const { t } = useTranslation('blog');
|
|
333
466
|
t('blog:post.title');
|
|
334
467
|
|
|
335
|
-
//
|
|
468
|
+
// Server-side helper
|
|
469
|
+
const { t } = await getTranslation('blog');
|
|
470
|
+
t('blog:post.title');
|
|
471
|
+
|
|
472
|
+
// CMS client helper
|
|
473
|
+
const t = await client.getTranslations(locale, 'blog');
|
|
474
|
+
t('blog:post.title');
|
|
475
|
+
|
|
476
|
+
// Trans component
|
|
336
477
|
<Trans i18nKey="blog:post.title" />
|
|
337
478
|
|
|
338
|
-
//
|
|
339
|
-
|
|
479
|
+
// I18nKey-typed config (only if the file imports `I18nKey`)
|
|
480
|
+
import type { I18nKey } from '@/lib/i18n/types';
|
|
481
|
+
const label: I18nKey = 'sidebar:settings';
|
|
482
|
+
|
|
483
|
+
// Object properties ending in "Key"
|
|
484
|
+
const config = { titleKey: 'blog:post.title' };
|
|
340
485
|
```
|
|
341
486
|
|
|
342
487
|
### Format: `namespace:key`
|
|
343
488
|
|
|
344
|
-
|
|
489
|
+
All keys must follow this format. Otherwise you'll get a warning:
|
|
345
490
|
|
|
346
491
|
```ts
|
|
347
|
-
//
|
|
492
|
+
// Good
|
|
348
493
|
t('common:button.save');
|
|
349
494
|
|
|
350
|
-
//
|
|
495
|
+
// Wrong — namespace missing
|
|
351
496
|
t('save');
|
|
352
497
|
```
|
|
353
498
|
|
|
354
|
-
###
|
|
499
|
+
### Dynamic Routes — Auto-Generated routeParams
|
|
355
500
|
|
|
356
|
-
**
|
|
501
|
+
**How it works:**
|
|
357
502
|
|
|
358
|
-
|
|
503
|
+
At each `pnpm sync-translations sync`:
|
|
359
504
|
|
|
360
|
-
1. Scanner
|
|
505
|
+
1. Scanner automatically detects all routes with dynamic parameters (e.g.
|
|
361
506
|
`/[locale]/blog/[slug]`)
|
|
362
|
-
2.
|
|
507
|
+
2. For each `[param]` a sensible default is automatically generated:
|
|
363
508
|
- `locale` / `lang` → `"en"`
|
|
364
509
|
- `id`, `postId`, `productId` → `"123"`
|
|
365
510
|
- `slug` → `"demo"`
|
|
366
511
|
- `username` → `"demo-user"`
|
|
367
512
|
- `email` → `"demo@example.com"`
|
|
368
|
-
3.
|
|
369
|
-
4.
|
|
513
|
+
3. This is saved in `.cms-sync-cache-meta.json` (you can ignore it)
|
|
514
|
+
4. The CMS uses this to generate working preview URLs
|
|
370
515
|
|
|
371
|
-
**
|
|
516
|
+
**You don't have to do anything!** — everything works out-of-the-box.
|
|
372
517
|
|
|
373
|
-
**
|
|
518
|
+
**Manual override (optional):**
|
|
374
519
|
|
|
375
|
-
|
|
520
|
+
If you want to use different test values, fill in `.translationsrc.json`:
|
|
376
521
|
|
|
377
522
|
```json
|
|
378
523
|
{
|
|
@@ -383,21 +528,21 @@ Als je andere test-waarden wil gebruiken, vul je `.translationsrc.json` in:
|
|
|
383
528
|
}
|
|
384
529
|
```
|
|
385
530
|
|
|
386
|
-
|
|
387
|
-
|
|
531
|
+
This overrides the auto-generated values. Everything you add here takes
|
|
532
|
+
priority.
|
|
388
533
|
|
|
389
|
-
### Cache
|
|
534
|
+
### Cache Files
|
|
390
535
|
|
|
391
|
-
|
|
536
|
+
At each sync two cache files are created:
|
|
392
537
|
|
|
393
|
-
- `.cms-sync-cache.json` —
|
|
538
|
+
- `.cms-sync-cache.json` — Uploaded keys and their routes (for diff on next
|
|
394
539
|
sync)
|
|
395
|
-
- `.cms-sync-cache-meta.json` — Auto-generated route params (
|
|
396
|
-
|
|
540
|
+
- `.cms-sync-cache-meta.json` — Auto-generated route params (you can add to
|
|
541
|
+
.gitignore)
|
|
397
542
|
|
|
398
|
-
### Scanner
|
|
543
|
+
### Scanner Options
|
|
399
544
|
|
|
400
|
-
Customize scan
|
|
545
|
+
Customize scan behavior in `.translationsrc.json`:
|
|
401
546
|
|
|
402
547
|
```json
|
|
403
548
|
{
|
|
@@ -413,8 +558,8 @@ Customize scan gedrag in `.translationsrc.json`:
|
|
|
413
558
|
|
|
414
559
|
## Preview Mode — Live Highlighting
|
|
415
560
|
|
|
416
|
-
Editors
|
|
417
|
-
|
|
561
|
+
Editors can click "Show in app" in the CMS and your app opens in an iframe with
|
|
562
|
+
live highlighting of the element.
|
|
418
563
|
|
|
419
564
|
### Setup
|
|
420
565
|
|
|
@@ -435,7 +580,7 @@ useEffect(() => {
|
|
|
435
580
|
|
|
436
581
|
### Element Targeting
|
|
437
582
|
|
|
438
|
-
|
|
583
|
+
Use `data-cms-key` for precise targeting:
|
|
439
584
|
|
|
440
585
|
```tsx
|
|
441
586
|
<h1 data-cms-key="blog:title">{t('blog:title')}</h1>
|
|
@@ -446,83 +591,83 @@ Gebruik `data-cms-key` voor nauwkeurige targeting:
|
|
|
446
591
|
|
|
447
592
|
# JSON Output Format
|
|
448
593
|
|
|
449
|
-
|
|
594
|
+
After `sync-translations pull` these kinds of files are generated:
|
|
450
595
|
|
|
451
596
|
```json
|
|
452
597
|
{
|
|
453
598
|
"common": {
|
|
454
|
-
"app.title": "
|
|
455
|
-
"button.save": "
|
|
599
|
+
"app.title": "My App",
|
|
600
|
+
"button.save": "Save",
|
|
456
601
|
"nav.home": "Home"
|
|
457
602
|
},
|
|
458
603
|
"auth": {
|
|
459
604
|
"login.email": "Email",
|
|
460
|
-
"login.password": "
|
|
605
|
+
"login.password": "Password"
|
|
461
606
|
}
|
|
462
607
|
}
|
|
463
608
|
```
|
|
464
609
|
|
|
465
|
-
**
|
|
610
|
+
**Structure:**
|
|
466
611
|
|
|
467
612
|
- Top-level keys = namespaces
|
|
468
613
|
- Nested keys = translation strings
|
|
469
|
-
- 1
|
|
614
|
+
- 1 file per language (`en.json`, `nl.json`, etc.)
|
|
470
615
|
|
|
471
616
|
---
|
|
472
617
|
|
|
473
618
|
# Troubleshooting
|
|
474
619
|
|
|
475
|
-
###
|
|
620
|
+
### No keys found
|
|
476
621
|
|
|
477
622
|
```bash
|
|
478
|
-
# Check scanner
|
|
623
|
+
# Check scanner configuration
|
|
479
624
|
pnpm sync-translations sync --dry-run
|
|
480
625
|
```
|
|
481
626
|
|
|
482
|
-
|
|
627
|
+
Make sure your keys use `namespace:key` format.
|
|
483
628
|
|
|
484
|
-
### Environment variables
|
|
629
|
+
### Environment variables not found
|
|
485
630
|
|
|
486
|
-
|
|
631
|
+
Check `.env.local`:
|
|
487
632
|
|
|
488
633
|
```bash
|
|
489
634
|
grep -E 'CMS_URL|CMS_PROJECT_ID|CMS_SYNC_API_KEY' .env.local
|
|
490
635
|
```
|
|
491
636
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
637
|
+
Must contain `NEXT_PUBLIC_CMS_URL`, `NEXT_PUBLIC_CMS_PROJECT_ID` and
|
|
638
|
+
`CMS_SYNC_API_KEY`. The value of `CMS_SYNC_API_KEY` is a JWT token — get it from
|
|
639
|
+
the CMS Project Settings.
|
|
495
640
|
|
|
496
|
-
### Pull
|
|
641
|
+
### Pull doesn't work
|
|
497
642
|
|
|
498
643
|
```bash
|
|
499
|
-
# Force refresh,
|
|
644
|
+
# Force refresh, ignore cache
|
|
500
645
|
pnpm sync-translations pull --force
|
|
501
646
|
|
|
502
|
-
# Check
|
|
647
|
+
# Check configuration
|
|
503
648
|
cat .translationsrc.json
|
|
504
649
|
```
|
|
505
650
|
|
|
506
651
|
### Type errors in TypeScript
|
|
507
652
|
|
|
508
|
-
|
|
509
|
-
`.translationsrc.json
|
|
653
|
+
Make sure `src/lib/i18n/types.ts` is generated correctly and that your
|
|
654
|
+
namespaces are in `.translationsrc.json`.
|
|
510
655
|
|
|
511
656
|
---
|
|
512
657
|
|
|
513
658
|
# Best Practices
|
|
514
659
|
|
|
515
|
-
1. **
|
|
516
|
-
2. **
|
|
517
|
-
3. **Commit `.translationsrc.json`**
|
|
518
|
-
4. **
|
|
660
|
+
1. **Use server components** where possible — better for performance
|
|
661
|
+
2. **Add `data-cms-key`** on visually important elements
|
|
662
|
+
3. **Commit `.translationsrc.json`** to git — not `.env.local`
|
|
663
|
+
4. **Ignore cache files:** add to `.gitignore`:
|
|
519
664
|
```
|
|
520
665
|
.cms-sync-cache.json
|
|
521
666
|
.cms-sync-cache-meta.json
|
|
522
667
|
.last-pulled
|
|
523
668
|
```
|
|
524
|
-
5. **Run `sync` in CI/CD**
|
|
525
|
-
6. **
|
|
669
|
+
5. **Run `sync` in CI/CD** on main branch — catch missing translations
|
|
670
|
+
6. **Add `pull` to build script** — always fresh translations
|
|
526
671
|
|
|
527
672
|
---
|
|
528
673
|
|