@translation-cms/sync 1.2.4 → 1.2.6
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 +371 -247
- package/dist/bin.js +7 -4
- package/dist/bin.js.map +1 -1
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +19 -1
- package/dist/commands/sync.js.map +1 -1
- package/dist/config/resolve-config.d.ts +6 -0
- package/dist/config/resolve-config.d.ts.map +1 -1
- package/dist/config/resolve-config.js +16 -0
- package/dist/config/resolve-config.js.map +1 -1
- package/dist/core/api-internals/pull.d.ts +1 -1
- package/dist/core/api-internals/pull.d.ts.map +1 -1
- package/dist/core/api-internals/pull.js +175 -43
- package/dist/core/api-internals/pull.js.map +1 -1
- package/dist/core/api-internals/sync.d.ts.map +1 -1
- package/dist/core/api-internals/sync.js.map +1 -1
- package/dist/core/cache.d.ts +23 -0
- package/dist/core/cache.d.ts.map +1 -1
- package/dist/core/cache.js +90 -0
- package/dist/core/cache.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,29 +1,51 @@
|
|
|
1
1
|
# @translation-cms/sync
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Automatisch vertaalsleutels uit je codebase scannen, syncen met de Translations
|
|
4
|
+
CMS, en vertalingen ophalen als lokale JSON-bestanden. Gebouwd voor Next.js +
|
|
5
|
+
i18next.
|
|
5
6
|
|
|
6
|
-
##
|
|
7
|
+
## Wat is dit?
|
|
8
|
+
|
|
9
|
+
Een CLI-tool die je workflow vereenvoudigt:
|
|
10
|
+
|
|
11
|
+
- 🔍 **Scant** je code voor translation keys (React-i18next patroon)
|
|
12
|
+
- 📤 **Synct** nieuwe keys naar de Translations CMS
|
|
13
|
+
- 📥 **Haalt** vertalingen op als JSON-bestanden
|
|
14
|
+
- 🎯 **Preview** functie waarin editors live kunnen zien hoe hun tekst in je app
|
|
15
|
+
eruit ziet
|
|
7
16
|
|
|
8
17
|
```
|
|
9
|
-
|
|
10
|
-
2. sync-translations pull → fetches translations, writes src/lib/i18n/dictionaries/{locale}.json
|
|
11
|
-
3. i18next loads the files → static imports in client.ts, dynamic imports in server.ts
|
|
18
|
+
Your Code → scan → CMS → pull → JSON files → i18next → Your App
|
|
12
19
|
```
|
|
13
20
|
|
|
14
21
|
---
|
|
15
22
|
|
|
16
|
-
|
|
23
|
+
# Setup Handleiding — Van Nul Tot Functie
|
|
24
|
+
|
|
25
|
+
## Stap 1: Vereisten
|
|
26
|
+
|
|
27
|
+
Controleer wat je nodig hebt:
|
|
28
|
+
|
|
29
|
+
- ✅ Next.js project (v14+)
|
|
30
|
+
- ✅ pnpm (aanbevolen) of npm
|
|
31
|
+
- ✅ Translations CMS account + project aangemaakt
|
|
32
|
+
- ✅ CMS project credentials (URL, project ID, API key)
|
|
33
|
+
|
|
34
|
+
## Stap 2: Installatie
|
|
17
35
|
|
|
18
36
|
```bash
|
|
19
37
|
pnpm add @translation-cms/sync
|
|
20
38
|
```
|
|
21
39
|
|
|
22
|
-
|
|
40
|
+
Plus de peer dependencies:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pnpm add i18next react-i18next i18next-resources-to-backend
|
|
44
|
+
```
|
|
23
45
|
|
|
24
|
-
##
|
|
46
|
+
## Stap 3: CMS Credentials Instellen
|
|
25
47
|
|
|
26
|
-
|
|
48
|
+
Maak `.env.local` aan in je project root:
|
|
27
49
|
|
|
28
50
|
```bash
|
|
29
51
|
NEXT_PUBLIC_CMS_URL=https://cms.example.com
|
|
@@ -31,168 +53,175 @@ NEXT_PUBLIC_CMS_PROJECT_ID=your-project-id
|
|
|
31
53
|
NEXT_PUBLIC_CMS_ANON_KEY=your-api-key
|
|
32
54
|
```
|
|
33
55
|
|
|
34
|
-
|
|
56
|
+
Deze krijg je uit je CMS project settings.
|
|
35
57
|
|
|
36
|
-
|
|
37
|
-
|
|
58
|
+
## Stap 4: Automatische Setup (Aanbevolen)
|
|
59
|
+
|
|
60
|
+
Run de interactive setup wizard:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pnpm sync-translations init
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Dit maakt automatisch aan:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
src/lib/i18n/
|
|
70
|
+
├── settings.ts # i18next configuratie
|
|
71
|
+
├── types.ts # TypeScript types voor translations
|
|
72
|
+
├── client.ts # 'use client' hook + static imports
|
|
73
|
+
├── server.ts # Server component support
|
|
74
|
+
├── provider.tsx # Provider wrapper
|
|
75
|
+
└── dictionaries/
|
|
76
|
+
├── en.json # Engels (leeg, wordt gevuld door pull)
|
|
77
|
+
└── nl.json # Nederlands (leeg, wordt gevuld door pull)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Ook `.translationsrc.json` wordt gegenereerd:
|
|
38
81
|
|
|
39
82
|
```json
|
|
40
83
|
{
|
|
41
84
|
"outputDir": "./src/lib/i18n/dictionaries",
|
|
42
85
|
"pullTtlMs": 300000,
|
|
43
|
-
"excludedDirs": ["e2e", "fixtures"],
|
|
44
|
-
"routeParams": {
|
|
45
|
-
"/[locale]/blog/[slug]": { "slug": "first-post" },
|
|
46
|
-
"/[locale]/products/[slug]": { "slug": "product-a" }
|
|
47
|
-
}
|
|
86
|
+
"excludedDirs": ["e2e", "node_modules", "fixtures"],
|
|
87
|
+
"routeParams": {}
|
|
48
88
|
}
|
|
49
89
|
```
|
|
50
90
|
|
|
51
|
-
**
|
|
52
|
-
|
|
53
|
-
---
|
|
91
|
+
**Let op:** `routeParams` kan leeg blijven! De scanner genereert automatisch
|
|
92
|
+
sensible defaults voor alle dynamic routes.
|
|
54
93
|
|
|
55
|
-
##
|
|
94
|
+
## Stap 5: Eerste Sync — Keys Uploaden
|
|
56
95
|
|
|
57
|
-
|
|
96
|
+
Scan je code en upload gedetecteerde keys naar de CMS:
|
|
58
97
|
|
|
59
98
|
```bash
|
|
60
|
-
sync-translations
|
|
99
|
+
pnpm sync-translations sync
|
|
61
100
|
```
|
|
62
101
|
|
|
63
|
-
|
|
102
|
+
Dit zal:
|
|
64
103
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
client.ts ← 'use client', static imports
|
|
70
|
-
server.ts ← RSC, dynamic import()
|
|
71
|
-
provider.tsx ← TranslationProvider
|
|
72
|
-
dictionaries/
|
|
73
|
-
en.json ← populated by: sync-translations pull
|
|
74
|
-
nl.json
|
|
75
|
-
```
|
|
104
|
+
1. Je code scannen op translation keys (`t('namespace:key')` patroon)
|
|
105
|
+
2. Route detecteren waar elke key gebruikt wordt
|
|
106
|
+
3. Nieuwe keys naar CMS uploaden
|
|
107
|
+
4. Rapport tonen (welke keys toegevoegd/gewijzigd)
|
|
76
108
|
|
|
77
|
-
|
|
109
|
+
Controleer in de CMS of je keys verschenen zijn ✅
|
|
78
110
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
111
|
+
**Bij eerste sync:** je krijgt mogelijk een error dat geen vertalingen kunnen
|
|
112
|
+
worden gedownload — dit is normaal! De keys zijn net geupload maar hebben nog
|
|
113
|
+
geen vertalingen. Ga naar je CMS, vul vertalingen in, dan draai je `pull`
|
|
114
|
+
opnieuw.
|
|
83
115
|
|
|
84
|
-
|
|
116
|
+
## Stap 5b: Vertalingen Toevoegen in CMS
|
|
85
117
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
```
|
|
118
|
+
1. Open je Translations CMS project
|
|
119
|
+
2. Je keys staan nu gelistd (zonder vertalingen)
|
|
120
|
+
3. Vul vertalingen in per locale (English, Nederlands, etc.)
|
|
121
|
+
4. Klik Save
|
|
92
122
|
|
|
93
|
-
|
|
123
|
+
## Stap 6: Vertalingen Ophalen
|
|
94
124
|
|
|
95
|
-
|
|
125
|
+
Als je de eerste sync hebt gedaan EN vertalingen in de CMS hebt ingevuld:
|
|
96
126
|
|
|
97
127
|
```bash
|
|
98
|
-
|
|
99
|
-
|
|
128
|
+
pnpm sync-translations pull
|
|
129
|
+
```
|
|
100
130
|
|
|
101
|
-
|
|
102
|
-
sync-translations pull
|
|
103
|
-
sync-translations pull --force # ignore TTL
|
|
104
|
-
sync-translations pull --output ./locales # custom output dir
|
|
105
|
-
sync-translations pull --env staging # pull staging environment
|
|
106
|
-
sync-translations pull --ttl 600000 # custom TTL in ms
|
|
131
|
+
Dit haalt vertalingen op van de CMS en schrijft ze naar lokale JSON:
|
|
107
132
|
|
|
108
|
-
|
|
109
|
-
|
|
133
|
+
- `dictionaries/en.json` → English vertalingen
|
|
134
|
+
- `dictionaries/nl.json` → Nederlandse vertalingen
|
|
135
|
+
- etc. (één per locale)
|
|
110
136
|
|
|
111
|
-
|
|
112
|
-
sync-translations status
|
|
137
|
+
## Stap 7: Integratie in je Project
|
|
113
138
|
|
|
114
|
-
|
|
115
|
-
sync-translations watch
|
|
139
|
+
### A. Root Layout Setup
|
|
116
140
|
|
|
117
|
-
|
|
118
|
-
sync-translations init
|
|
119
|
-
```
|
|
141
|
+
Voeg de provider toe aan je `src/app/layout.tsx`:
|
|
120
142
|
|
|
121
|
-
|
|
122
|
-
|
|
143
|
+
```tsx
|
|
144
|
+
import { TranslationProvider } from '@/lib/i18n/provider';
|
|
123
145
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
146
|
+
export default function RootLayout({
|
|
147
|
+
children,
|
|
148
|
+
}: {
|
|
149
|
+
children: React.ReactNode;
|
|
150
|
+
}) {
|
|
151
|
+
return (
|
|
152
|
+
<html>
|
|
153
|
+
<body>
|
|
154
|
+
<TranslationProvider>{children}</TranslationProvider>
|
|
155
|
+
</body>
|
|
156
|
+
</html>
|
|
157
|
+
);
|
|
128
158
|
}
|
|
129
159
|
```
|
|
130
160
|
|
|
131
|
-
###
|
|
161
|
+
### B. Server Components (Aanbevolen)
|
|
132
162
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
| `--dry-run` | `sync` | Print what would change, skip posting |
|
|
136
|
-
| `--force` | `sync`, `pull` | Skip cache / force re-sync |
|
|
137
|
-
| `--report <file>` | `sync` | Write JSON report to file |
|
|
138
|
-
| `--output <dir>` | `pull` | Output directory for JSON files |
|
|
139
|
-
| `--env <name>` | `pull` | Pull from a specific environment |
|
|
140
|
-
| `--ttl <ms>` | `pull` | Override cache TTL |
|
|
141
|
-
| `--project-id` | all | Override project ID |
|
|
142
|
-
| `--api-key` | all | Override API key |
|
|
143
|
-
| `--cms-url` | all | Override CMS URL |
|
|
163
|
+
```tsx
|
|
164
|
+
import { getTranslation } from '@/lib/i18n/server';
|
|
144
165
|
|
|
145
|
-
|
|
166
|
+
export default async function Page() {
|
|
167
|
+
const { t } = await getTranslation('common');
|
|
146
168
|
|
|
147
|
-
|
|
169
|
+
return (
|
|
170
|
+
<div>
|
|
171
|
+
<h1>{t('common:app.title')}</h1>
|
|
172
|
+
<p>{t('common:app.description')}</p>
|
|
173
|
+
</div>
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
```
|
|
148
177
|
|
|
149
|
-
|
|
150
|
-
translations at build time — no flash, no loading state:
|
|
178
|
+
### C. Client Components
|
|
151
179
|
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
import
|
|
155
|
-
import nl from './dictionaries/nl.json';
|
|
180
|
+
```tsx
|
|
181
|
+
'use client';
|
|
182
|
+
import { useTranslation } from '@/lib/i18n/client';
|
|
156
183
|
|
|
157
|
-
|
|
184
|
+
export function MyButton() {
|
|
185
|
+
const { t } = useTranslation('common');
|
|
158
186
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
resources,
|
|
162
|
-
});
|
|
187
|
+
return <button>{t('common:button.click')}</button>;
|
|
188
|
+
}
|
|
163
189
|
```
|
|
164
190
|
|
|
165
|
-
|
|
166
|
-
`import()` — no HTTP, reads directly from the filesystem:
|
|
191
|
+
### D. Multiple Namespaces (Met Type-Checking)
|
|
167
192
|
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
)
|
|
193
|
+
```tsx
|
|
194
|
+
const { t } = useTranslation(['common', 'auth']);
|
|
195
|
+
|
|
196
|
+
// ✅ Dit werkt
|
|
197
|
+
t('common:nav.home');
|
|
198
|
+
t('auth:login.email');
|
|
199
|
+
|
|
200
|
+
// ❌ Dit geeft een type error
|
|
201
|
+
t('payments:amount'); // namespace niet toegevoegd
|
|
173
202
|
```
|
|
174
203
|
|
|
175
|
-
|
|
204
|
+
## Stap 8: Automatische Sync in je Workflow
|
|
176
205
|
|
|
177
|
-
|
|
178
|
-
// Client component
|
|
179
|
-
import { useTranslation } from '@/lib/i18n/client';
|
|
180
|
-
const { t } = useTranslation('common');
|
|
181
|
-
t('common:nav.home');
|
|
206
|
+
Voeg dit toe aan `package.json`:
|
|
182
207
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
208
|
+
```json
|
|
209
|
+
{
|
|
210
|
+
"scripts": {
|
|
211
|
+
"dev": "sync-translations pull && next dev",
|
|
212
|
+
"build": "sync-translations pull && next build"
|
|
213
|
+
}
|
|
214
|
+
}
|
|
187
215
|
```
|
|
188
216
|
|
|
189
|
-
|
|
217
|
+
Nu pull je automatisch de latest vertalingen bij startup ⚡
|
|
218
|
+
|
|
219
|
+
## Stap 9 (Optioneel): Preview Mode Instellen
|
|
190
220
|
|
|
191
|
-
|
|
221
|
+
Enable live in-context preview — editors kunnen live zien hoe hun tekst in je
|
|
222
|
+
app eruit ziet.
|
|
192
223
|
|
|
193
|
-
|
|
194
|
-
matching element in your app (loaded in an iframe) is highlighted. Navigation
|
|
195
|
-
and interactions are blocked during preview.
|
|
224
|
+
Voeg dit toe aan je root layout:
|
|
196
225
|
|
|
197
226
|
```tsx
|
|
198
227
|
'use client';
|
|
@@ -202,198 +231,293 @@ import { initPreviewListener } from '@translation-cms/sync';
|
|
|
202
231
|
export function CMSPreview() {
|
|
203
232
|
useEffect(() => {
|
|
204
233
|
if (process.env.NODE_ENV === 'development') {
|
|
205
|
-
initPreviewListener(
|
|
234
|
+
initPreviewListener({
|
|
235
|
+
onLocaleSwitch: locale => {
|
|
236
|
+
// wijzig taal als CMS een ander locale selecteert
|
|
237
|
+
window.location.href = `/${locale}`;
|
|
238
|
+
},
|
|
239
|
+
});
|
|
206
240
|
}
|
|
207
241
|
}, []);
|
|
208
242
|
return null;
|
|
209
243
|
}
|
|
210
244
|
```
|
|
211
245
|
|
|
212
|
-
|
|
246
|
+
En voeg toe in layout:
|
|
213
247
|
|
|
214
|
-
|
|
248
|
+
```tsx
|
|
249
|
+
<TranslationProvider>
|
|
250
|
+
<CMSPreview />
|
|
251
|
+
{children}
|
|
252
|
+
</TranslationProvider>
|
|
253
|
+
```
|
|
215
254
|
|
|
216
|
-
|
|
255
|
+
Voeg `data-cms-key` toe op elementen voor nauwkeurige highlighting:
|
|
217
256
|
|
|
218
257
|
```tsx
|
|
219
|
-
<h1 data-cms-key="
|
|
220
|
-
<p data-cms-key="common:welcome">{t('common:welcome', { name })}</p>
|
|
258
|
+
<h1 data-cms-key="common:page.title">{t('common:page.title')}</h1>
|
|
221
259
|
```
|
|
222
260
|
|
|
223
|
-
|
|
261
|
+
---
|
|
224
262
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
263
|
+
# CLI Commands Reference
|
|
264
|
+
|
|
265
|
+
## Basiscommands
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
# Scan code + upload naar CMS
|
|
269
|
+
pnpm sync-translations sync
|
|
270
|
+
|
|
271
|
+
# Download vertalingen naar lokale JSON
|
|
272
|
+
pnpm sync-translations pull
|
|
273
|
+
|
|
274
|
+
# Bekijk wat er zou veranderen (zonder upload)
|
|
275
|
+
pnpm sync-translations sync --dry-run
|
|
276
|
+
|
|
277
|
+
# Bekijk verschil met vorige sync
|
|
278
|
+
pnpm sync-translations status
|
|
279
|
+
|
|
280
|
+
# Watch mode — auto-sync bij bestand wijzigingen
|
|
281
|
+
pnpm sync-translations watch
|
|
282
|
+
|
|
283
|
+
# Interactieve setup
|
|
284
|
+
pnpm sync-translations init
|
|
229
285
|
```
|
|
230
286
|
|
|
231
|
-
|
|
287
|
+
## Advanced Flags
|
|
232
288
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
289
|
+
| Flag | Beschrijving |
|
|
290
|
+
| ----------------- | ------------------------------------ |
|
|
291
|
+
| `--dry-run` | Toon wijzigingen, voer niet uit |
|
|
292
|
+
| `--force` | Negeer cache, force hernieuwen |
|
|
293
|
+
| `--output <dir>` | Custom output map voor JSON |
|
|
294
|
+
| `--env <name>` | Pull uit staging/production omgeving |
|
|
295
|
+
| `--ttl <ms>` | Overschrijf cache TTL (ms) |
|
|
296
|
+
| `--project-id` | Overschrijf project ID |
|
|
297
|
+
| `--api-key` | Overschrijf API key |
|
|
298
|
+
| `--cms-url` | Overschrijf CMS URL |
|
|
299
|
+
| `--report <file>` | Schrijf sync rapport naar JSON file |
|
|
300
|
+
|
|
301
|
+
## Voorbeelden
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
# Force refresh, negeer cache
|
|
305
|
+
pnpm sync-translations pull --force
|
|
306
|
+
|
|
307
|
+
# Custom output directory
|
|
308
|
+
pnpm sync-translations pull --output ./locales
|
|
309
|
+
|
|
310
|
+
# Pull uit staging environment
|
|
311
|
+
pnpm sync-translations pull --env staging
|
|
312
|
+
|
|
313
|
+
# Schrijf rapport van wijzigingen
|
|
314
|
+
pnpm sync-translations sync --report ./sync-report.json
|
|
241
315
|
```
|
|
242
316
|
|
|
243
|
-
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
# Key Scanner — Hoe Werkt Het
|
|
320
|
+
|
|
321
|
+
De tool herkent deze patronen in je code:
|
|
244
322
|
|
|
245
323
|
```ts
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
324
|
+
// ✅ React-i18next hook
|
|
325
|
+
const { t } = useTranslation('blog');
|
|
326
|
+
t('blog:post.title');
|
|
249
327
|
|
|
250
|
-
|
|
328
|
+
// ✅ Trans component
|
|
329
|
+
<Trans i18nKey="blog:post.title" />
|
|
251
330
|
|
|
252
|
-
|
|
253
|
-
|
|
331
|
+
// ✅ String literal
|
|
332
|
+
const key = 'blog:post.title';
|
|
333
|
+
```
|
|
254
334
|
|
|
255
|
-
|
|
256
|
-
'use client';
|
|
257
|
-
import { useState, useEffect } from 'react';
|
|
258
|
-
import {
|
|
259
|
-
initPreviewListener,
|
|
260
|
-
registerPreviewAction,
|
|
261
|
-
} from '@translation-cms/sync';
|
|
335
|
+
### Format: `namespace:key`
|
|
262
336
|
|
|
263
|
-
|
|
264
|
-
const [open, setOpen] = useState(false);
|
|
337
|
+
Alle keys moeten dit format volgen. Anders krijg je een warning:
|
|
265
338
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
registerPreviewAction('nav.menu', () => {
|
|
270
|
-
setOpen(true);
|
|
271
|
-
});
|
|
272
|
-
}
|
|
273
|
-
}, []);
|
|
339
|
+
```ts
|
|
340
|
+
// ✅ Goed
|
|
341
|
+
t('common:button.save');
|
|
274
342
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
<button onClick={() => setOpen(!open)}>Menu</button>
|
|
278
|
-
{open && (
|
|
279
|
-
<div>
|
|
280
|
-
<a href="/">
|
|
281
|
-
<span data-cms-key="nav:home">{t('nav:home')}</span>
|
|
282
|
-
</a>
|
|
283
|
-
<a href="/about">
|
|
284
|
-
<span data-cms-key="nav:about">{t('nav:about')}</span>
|
|
285
|
-
</a>
|
|
286
|
-
</div>
|
|
287
|
-
)}
|
|
288
|
-
</nav>
|
|
289
|
-
);
|
|
290
|
-
}
|
|
343
|
+
// ❌ Fout — namespace mist
|
|
344
|
+
t('save');
|
|
291
345
|
```
|
|
292
346
|
|
|
293
|
-
|
|
347
|
+
### Dynamische Routes — Auto-Generated routeParams
|
|
294
348
|
|
|
295
|
-
|
|
349
|
+
**Hoe het werkt:**
|
|
296
350
|
|
|
297
|
-
|
|
298
|
-
2. Fill in **Preview action** field with your action ID (e.g., `nav.menu`,
|
|
299
|
-
`modal.signup`)
|
|
300
|
-
3. Click **Update**
|
|
351
|
+
Bij elke `pnpm sync-translations sync`:
|
|
301
352
|
|
|
302
|
-
|
|
353
|
+
1. Scanner detecteert automatisch alle routes met dynamic parameters (bijv.
|
|
354
|
+
`/[locale]/blog/[slug]`)
|
|
355
|
+
2. Voor elke `[param]` wordt automatisch een sensible default gegenereerd:
|
|
356
|
+
- `locale` / `lang` → `"en"`
|
|
357
|
+
- `id`, `postId`, `productId` → `"123"`
|
|
358
|
+
- `slug` → `"demo"`
|
|
359
|
+
- `username` → `"demo-user"`
|
|
360
|
+
- `email` → `"demo@example.com"`
|
|
361
|
+
3. Dit wordt opgeslagen in `.cms-sync-cache-meta.json` (mag je negeren)
|
|
362
|
+
4. De CMS gebruikt deze om werkende preview URLs te genereren
|
|
303
363
|
|
|
304
|
-
|
|
305
|
-
2. Auto-open the menu/dialog/modal by sending a `CMS_TRIGGER_ACTION` message
|
|
306
|
-
3. Highlight the matching `data-cms-key` element
|
|
364
|
+
**Je hoeft niks te doen!** — alles werkt out-of-the-box.
|
|
307
365
|
|
|
308
|
-
**
|
|
309
|
-
names registered during initialization. Common patterns:
|
|
366
|
+
**Handmatig overschrijven (optioneel):**
|
|
310
367
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
368
|
+
Als je andere test-waarden wil gebruiken, vul je `.translationsrc.json` in:
|
|
369
|
+
|
|
370
|
+
```json
|
|
371
|
+
{
|
|
372
|
+
"routeParams": {
|
|
373
|
+
"/[locale]/products/[id]": { "id": "prod-999" },
|
|
374
|
+
"/[locale]/blog/[slug]": { "slug": "my-custom-post" }
|
|
375
|
+
}
|
|
376
|
+
}
|
|
320
377
|
```
|
|
321
378
|
|
|
322
|
-
|
|
379
|
+
Dit overschrijft de auto-generated waarden. Alles wat je hier toevoegt krijgt
|
|
380
|
+
prioriteit.
|
|
323
381
|
|
|
324
|
-
|
|
382
|
+
### Cache bestanden
|
|
325
383
|
|
|
326
|
-
|
|
327
|
-
registerPreviewAction('nav.mobile-menu', () => setMobileMenuOpen(true));
|
|
328
|
-
```
|
|
384
|
+
Bij elke sync worden twee cache bestanden aangemaakt:
|
|
329
385
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
- Clicks Update
|
|
386
|
+
- `.cms-sync-cache.json` — Geüploade keys en hun routes (voor diff bij volgende
|
|
387
|
+
sync)
|
|
388
|
+
- `.cms-sync-cache-meta.json` — Auto-generated route params (mag je .gitignore
|
|
389
|
+
toevoegen)
|
|
335
390
|
|
|
336
|
-
|
|
337
|
-
- Editor clicks "Show in app"
|
|
338
|
-
- Mobile menu auto-opens
|
|
339
|
-
- `<span data-cms-key="common:nav.home">` element is highlighted in yellow
|
|
340
|
-
- Editor sees the translation in context
|
|
391
|
+
### Scanner Opties
|
|
341
392
|
|
|
342
|
-
|
|
393
|
+
Customize scan gedrag in `.translationsrc.json`:
|
|
343
394
|
|
|
344
|
-
|
|
395
|
+
```json
|
|
396
|
+
{
|
|
397
|
+
"excludedDirs": ["e2e", "node_modules", "fixtures"],
|
|
398
|
+
"sourceExtensions": [".ts", ".tsx", ".js", ".jsx"],
|
|
399
|
+
"reservedCssNamespaces": ["after", "before"]
|
|
400
|
+
}
|
|
401
|
+
```
|
|
345
402
|
|
|
346
403
|
---
|
|
347
404
|
|
|
348
|
-
|
|
405
|
+
# Advanced Features
|
|
349
406
|
|
|
350
|
-
|
|
407
|
+
## Preview Mode — Live Highlighting
|
|
351
408
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
const { t } = useTranslation('blog');
|
|
355
|
-
t('blog:post.title');
|
|
409
|
+
Editors kunnen in de CMS klikken op "Show in app" en je app opent in een iframe
|
|
410
|
+
met live highlighting van het element.
|
|
356
411
|
|
|
357
|
-
|
|
358
|
-
<Trans i18nKey="blog:post.title" />
|
|
412
|
+
### Setup
|
|
359
413
|
|
|
360
|
-
|
|
361
|
-
|
|
414
|
+
```tsx
|
|
415
|
+
'use client';
|
|
416
|
+
import { initPreviewListener } from '@translation-cms/sync';
|
|
417
|
+
|
|
418
|
+
useEffect(() => {
|
|
419
|
+
initPreviewListener({
|
|
420
|
+
highlightStyles: {
|
|
421
|
+
outline: '3px solid #3b82f6',
|
|
422
|
+
outlineOffset: '2px',
|
|
423
|
+
backgroundColor: 'rgba(59, 130, 246, 0.1)',
|
|
424
|
+
},
|
|
425
|
+
});
|
|
426
|
+
}, []);
|
|
362
427
|
```
|
|
363
428
|
|
|
364
|
-
|
|
365
|
-
|
|
429
|
+
### Element Targeting
|
|
430
|
+
|
|
431
|
+
Gebruik `data-cms-key` voor nauwkeurige targeting:
|
|
432
|
+
|
|
433
|
+
```tsx
|
|
434
|
+
<h1 data-cms-key="blog:title">{t('blog:title')}</h1>
|
|
435
|
+
<p data-cms-key="blog:excerpt">{t('blog:excerpt')}</p>
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
---
|
|
366
439
|
|
|
367
|
-
|
|
440
|
+
# JSON Output Format
|
|
368
441
|
|
|
369
|
-
|
|
370
|
-
routes (e.g. `/[locale]/blog/[slug]`), add mock params in `.translationsrc.json`
|
|
371
|
-
so the CMS can generate a working preview URL:
|
|
442
|
+
Na `sync-translations pull` worden dit soort bestanden gegenereerd:
|
|
372
443
|
|
|
373
444
|
```json
|
|
374
445
|
{
|
|
375
|
-
"
|
|
376
|
-
"
|
|
377
|
-
"
|
|
446
|
+
"common": {
|
|
447
|
+
"app.title": "Mijn App",
|
|
448
|
+
"button.save": "Opslaan",
|
|
449
|
+
"nav.home": "Home"
|
|
450
|
+
},
|
|
451
|
+
"auth": {
|
|
452
|
+
"login.email": "Email",
|
|
453
|
+
"login.password": "Wachtwoord"
|
|
378
454
|
}
|
|
379
455
|
}
|
|
380
456
|
```
|
|
381
457
|
|
|
382
|
-
|
|
383
|
-
no need to repeat params per key.
|
|
458
|
+
**Structuur:**
|
|
384
459
|
|
|
385
|
-
|
|
460
|
+
- Top-level keys = namespaces
|
|
461
|
+
- Nested keys = translation strings
|
|
462
|
+
- 1 bestand per taal (`en.json`, `nl.json`, etc.)
|
|
386
463
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
464
|
+
---
|
|
465
|
+
|
|
466
|
+
# Troubleshooting
|
|
467
|
+
|
|
468
|
+
### Geen keys gevonden
|
|
469
|
+
|
|
470
|
+
```bash
|
|
471
|
+
# Check scanner configuratie
|
|
472
|
+
pnpm sync-translations sync --dry-run
|
|
393
473
|
```
|
|
394
474
|
|
|
475
|
+
Zorg dat je keys `namespace:key` format gebruiken.
|
|
476
|
+
|
|
477
|
+
### Environment variables niet gevonden
|
|
478
|
+
|
|
479
|
+
Controleer `.env.local`:
|
|
480
|
+
|
|
481
|
+
```bash
|
|
482
|
+
cat .env.local | grep NEXT_PUBLIC_CMS
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
Moet `NEXT_PUBLIC_CMS_URL`, `NEXT_PUBLIC_CMS_PROJECT_ID`,
|
|
486
|
+
`NEXT_PUBLIC_CMS_ANON_KEY` bevatten.
|
|
487
|
+
|
|
488
|
+
### Pull werkt niet
|
|
489
|
+
|
|
490
|
+
```bash
|
|
491
|
+
# Force refresh, negeer cache
|
|
492
|
+
pnpm sync-translations pull --force
|
|
493
|
+
|
|
494
|
+
# Check configuratie
|
|
495
|
+
cat .translationsrc.json
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
### Type errors in TypeScript
|
|
499
|
+
|
|
500
|
+
Zorg dat `src/lib/i18n/types.ts` correct gegenereerd is en dat je namespaces in
|
|
501
|
+
`.translationsrc.json` staan.
|
|
502
|
+
|
|
503
|
+
---
|
|
504
|
+
|
|
505
|
+
# Best Practices
|
|
506
|
+
|
|
507
|
+
1. **Gebruik server components** waar mogelijk — beter voor performance
|
|
508
|
+
2. **Voeg `data-cms-key` toe** op visueel belangrijke elementen
|
|
509
|
+
3. **Commit `.translationsrc.json`** naar git — niet `.env.local`
|
|
510
|
+
4. **Negeer cache bestanden:** voeg toe aan `.gitignore`:
|
|
511
|
+
```
|
|
512
|
+
.cms-sync-cache.json
|
|
513
|
+
.cms-sync-cache-meta.json
|
|
514
|
+
.last-pulled
|
|
515
|
+
```
|
|
516
|
+
5. **Run `sync` in CI/CD** op main branch — catch missing translations
|
|
517
|
+
6. **Voeg `pull` toe aan build script** — altijd fresh translations
|
|
518
|
+
|
|
395
519
|
---
|
|
396
520
|
|
|
397
|
-
|
|
521
|
+
# License
|
|
398
522
|
|
|
399
523
|
MIT
|