@metasyncsite/translations-client-ts 1.0.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/README.md +322 -0
- package/dist/apiClient.d.ts +10 -0
- package/dist/apiClient.d.ts.map +1 -0
- package/dist/apiClient.js +36 -0
- package/dist/apiClient.js.map +1 -0
- package/dist/bin/pull.d.ts +3 -0
- package/dist/bin/pull.d.ts.map +1 -0
- package/dist/bin/pull.js +99 -0
- package/dist/bin/pull.js.map +1 -0
- package/dist/bin/push.d.ts +3 -0
- package/dist/bin/push.d.ts.map +1 -0
- package/dist/bin/push.js +111 -0
- package/dist/bin/push.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/langReader.d.ts +22 -0
- package/dist/langReader.d.ts.map +1 -0
- package/dist/langReader.js +118 -0
- package/dist/langReader.js.map +1 -0
- package/dist/langWriter.d.ts +20 -0
- package/dist/langWriter.d.ts.map +1 -0
- package/dist/langWriter.js +71 -0
- package/dist/langWriter.js.map +1 -0
- package/dist/types.d.ts +63 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
# @metasyncsite/translations-client-ts
|
|
2
|
+
|
|
3
|
+
TypeScript client for pushing and pulling i18n translations to/from the Translation Manager. Works with any Node.js project: Vue, React, Next.js, Nuxt, etc.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
- Node.js >= 18
|
|
10
|
+
- TypeScript >= 5.0 (dev dependency)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @metasyncsite/translations-client-ts
|
|
18
|
+
# or
|
|
19
|
+
pnpm add @metasyncsite/translations-client-ts
|
|
20
|
+
# or
|
|
21
|
+
yarn add @metasyncsite/translations-client-ts
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Local Installation (without npm registry)
|
|
27
|
+
|
|
28
|
+
If the package is not yet published, you have three options:
|
|
29
|
+
|
|
30
|
+
### Option 1 — file path in package.json (recommended)
|
|
31
|
+
|
|
32
|
+
Build the package first, then reference it by path in your project's `package.json`:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@metasyncsite/translations-client-ts": "file:../path/to/translations-client-node-ts"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Then run:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm install
|
|
46
|
+
# or
|
|
47
|
+
pnpm install
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
> The path must point to the package root (where `package.json` lives). Use a relative or absolute path.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
### Option 2 — npm pack (portable tarball)
|
|
55
|
+
|
|
56
|
+
Build and pack the package into a `.tgz` file, then install that file in any project:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# Inside the package directory
|
|
60
|
+
cd packages/translations-client-node-ts
|
|
61
|
+
npm run build
|
|
62
|
+
npm pack
|
|
63
|
+
# → creates metasyncsite-translations-client-ts-1.0.0.tgz
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Then install the tarball in your project:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npm install /path/to/metasyncsite-translations-client-ts-1.0.0.tgz
|
|
70
|
+
# or
|
|
71
|
+
pnpm add /path/to/metasyncsite-translations-client-ts-1.0.0.tgz
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
> Good when you want to share the package without a registry — just copy the `.tgz` file.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
### Option 3 — npm link (symlink, for active development)
|
|
79
|
+
|
|
80
|
+
Use this when you're actively editing the package and want changes to reflect immediately:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# 1. Inside the package directory — register a global symlink
|
|
84
|
+
cd packages/translations-client-node-ts
|
|
85
|
+
npm run build
|
|
86
|
+
npm link
|
|
87
|
+
|
|
88
|
+
# 2. Inside your consuming project — link to it
|
|
89
|
+
cd /path/to/your-project
|
|
90
|
+
npm link @metasyncsite/translations-client-ts
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
To unlink when done:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# Inside your project
|
|
97
|
+
npm unlink @metasyncsite/translations-client-ts
|
|
98
|
+
|
|
99
|
+
# Inside the package directory
|
|
100
|
+
npm unlink
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
> With `npm link`, you must re-run `npm run build` (or `npm run dev` for watch mode) after each source change.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Build (if working from source)
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
cd packages/translations-client-node-ts
|
|
111
|
+
npm install
|
|
112
|
+
npm run build # compiles src/ → dist/
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Configuration
|
|
118
|
+
|
|
119
|
+
The client reads credentials from environment variables or CLI flags.
|
|
120
|
+
|
|
121
|
+
### Environment variables
|
|
122
|
+
|
|
123
|
+
Add to your project's `.env`:
|
|
124
|
+
|
|
125
|
+
```env
|
|
126
|
+
TRANSLATIONS_URL=https://translations.example.com
|
|
127
|
+
TRANSLATIONS_TOKEN=your-api-token
|
|
128
|
+
TRANSLATIONS_LOCALES_PATH=src/locales # optional, default: src/locales
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## CLI Usage
|
|
134
|
+
|
|
135
|
+
After installing the package, two CLI commands are available:
|
|
136
|
+
|
|
137
|
+
### Push (upload local translations → Translation Manager)
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
npx translations-push
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
With explicit flags:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
npx translations-push \
|
|
147
|
+
--url https://translations.example.com \
|
|
148
|
+
--token your-api-token \
|
|
149
|
+
--path src/locales \
|
|
150
|
+
--locale en \ # push only this locale (optional)
|
|
151
|
+
--overwrite true \ # overwrite existing keys (default: true)
|
|
152
|
+
--dry-run \ # preview without sending
|
|
153
|
+
--exclude i18n.json,test.json # comma-separated files to skip
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Pull (download translations from Translation Manager → local files)
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
npx translations-pull
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
With explicit flags:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
npx translations-pull \
|
|
166
|
+
--url https://translations.example.com \
|
|
167
|
+
--token your-api-token \
|
|
168
|
+
--path src/locales \
|
|
169
|
+
--locale de \ # pull only this locale (optional)
|
|
170
|
+
--layout grouped \ # force layout: flat | grouped (optional, auto-detected)
|
|
171
|
+
--dry-run # preview without writing files
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Add to package.json scripts
|
|
175
|
+
|
|
176
|
+
```json
|
|
177
|
+
{
|
|
178
|
+
"scripts": {
|
|
179
|
+
"translations:push": "translations-push",
|
|
180
|
+
"translations:pull": "translations-pull"
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Locale Layouts
|
|
188
|
+
|
|
189
|
+
The client auto-detects which layout your project uses:
|
|
190
|
+
|
|
191
|
+
| Layout | Structure | Example |
|
|
192
|
+
|--------|-----------|---------|
|
|
193
|
+
| `flat` | One JSON file per locale | `locales/en.json`, `locales/de.json` |
|
|
194
|
+
| `grouped` | One subdirectory per locale | `locales/en/auth.json`, `locales/de/auth.json` |
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Programmatic API
|
|
199
|
+
|
|
200
|
+
Import and use the client functions directly in TypeScript:
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
import {
|
|
204
|
+
readLocales,
|
|
205
|
+
detectLayout,
|
|
206
|
+
pushLocale,
|
|
207
|
+
writeGroupedLocale,
|
|
208
|
+
writeFlatLocale,
|
|
209
|
+
} from '@metasyncsite/translations-client-ts'
|
|
210
|
+
|
|
211
|
+
import type {
|
|
212
|
+
LocaleData,
|
|
213
|
+
LocaleGroups,
|
|
214
|
+
PushLocaleParams,
|
|
215
|
+
PushResult,
|
|
216
|
+
} from '@metasyncsite/translations-client-ts'
|
|
217
|
+
|
|
218
|
+
// Read all locales from disk
|
|
219
|
+
const locales: LocaleData[] = readLocales('./src/locales')
|
|
220
|
+
|
|
221
|
+
// Push a single locale
|
|
222
|
+
const result: PushResult = await pushLocale({
|
|
223
|
+
url: 'https://translations.example.com',
|
|
224
|
+
token: 'your-api-token',
|
|
225
|
+
locale: 'en',
|
|
226
|
+
groups: locales[0].groups,
|
|
227
|
+
overwrite: true,
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
console.log(`${result.new} new, ${result.updated} updated, ${result.total} total`)
|
|
231
|
+
|
|
232
|
+
// Detect layout
|
|
233
|
+
const layout = detectLayout('./src/locales') // 'flat' | 'grouped' | null
|
|
234
|
+
|
|
235
|
+
// Write pulled translations to disk
|
|
236
|
+
const groups: LocaleGroups = { auth: { 'login': 'Login', 'logout': 'Logout' } }
|
|
237
|
+
writeGroupedLocale('./src/locales', 'en', groups)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## API Reference
|
|
243
|
+
|
|
244
|
+
### `readLocales(localesPath, excludeFiles?)`
|
|
245
|
+
|
|
246
|
+
Auto-detects layout and reads all locale files.
|
|
247
|
+
|
|
248
|
+
| Param | Type | Description |
|
|
249
|
+
|-------|------|-------------|
|
|
250
|
+
| `localesPath` | `string` | Absolute or relative path to locales directory |
|
|
251
|
+
| `excludeFiles` | `string[]` | Filenames to skip (e.g. `['index.json']`) |
|
|
252
|
+
|
|
253
|
+
Returns: `LocaleData[]`
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
### `detectLayout(localesPath)`
|
|
258
|
+
|
|
259
|
+
Returns `'flat'`, `'grouped'`, or `null` if the directory doesn't exist or is empty.
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
### `pushLocale(params)`
|
|
264
|
+
|
|
265
|
+
Pushes one locale's groups to the Translation Manager API.
|
|
266
|
+
|
|
267
|
+
| Param | Type | Default |
|
|
268
|
+
|-------|------|---------|
|
|
269
|
+
| `url` | `string` | — |
|
|
270
|
+
| `token` | `string` | — |
|
|
271
|
+
| `locale` | `string` | — |
|
|
272
|
+
| `groups` | `LocaleGroups` | — |
|
|
273
|
+
| `overwrite` | `boolean` | `true` |
|
|
274
|
+
|
|
275
|
+
Returns: `Promise<PushResult>`
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
### `writeGroupedLocale(localesPath, locale, groups)`
|
|
280
|
+
|
|
281
|
+
Writes translations in grouped layout (`locales/{locale}/{group}.json`).
|
|
282
|
+
The special `_json` group is written as `locales/{locale}.json`.
|
|
283
|
+
|
|
284
|
+
Returns: `string[]` — paths of written files.
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
### `writeFlatLocale(localesPath, locale, groups)`
|
|
289
|
+
|
|
290
|
+
Merges all groups and writes `locales/{locale}.json`.
|
|
291
|
+
|
|
292
|
+
Returns: `string[]` — paths of written files.
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
### `unflatten(flat)`
|
|
297
|
+
|
|
298
|
+
Converts dot-notation keys back to a nested object.
|
|
299
|
+
|
|
300
|
+
```ts
|
|
301
|
+
unflatten({ 'auth.login': 'Login' })
|
|
302
|
+
// → { auth: { login: 'Login' } }
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## Types
|
|
308
|
+
|
|
309
|
+
All exported types are available from the main entry point:
|
|
310
|
+
|
|
311
|
+
```ts
|
|
312
|
+
import type {
|
|
313
|
+
FlatKeys, // Record<string, string>
|
|
314
|
+
LocaleGroups, // Record<string, FlatKeys>
|
|
315
|
+
LocaleLayout, // 'flat' | 'grouped'
|
|
316
|
+
LocaleData, // { locale: string, groups: LocaleGroups }
|
|
317
|
+
PushLocaleParams,
|
|
318
|
+
PushResult, // { new: number, updated: number, total: number }
|
|
319
|
+
PullOptions,
|
|
320
|
+
PushOptions,
|
|
321
|
+
} from '@metasyncsite/translations-client-ts'
|
|
322
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PushLocaleParams, PushResult } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Push a single locale's translations to the Translation Manager API.
|
|
4
|
+
*/
|
|
5
|
+
export declare function pushLocale({ url, token, locale, groups, overwrite, }: PushLocaleParams): Promise<PushResult>;
|
|
6
|
+
/**
|
|
7
|
+
* Fetch JSON from a Translation Manager API endpoint.
|
|
8
|
+
*/
|
|
9
|
+
export declare function fetchJson<T = unknown>(url: string, token: string): Promise<T>;
|
|
10
|
+
//# sourceMappingURL=apiClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiClient.d.ts","sourceRoot":"","sources":["../src/apiClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAE9D;;GAEG;AACH,wBAAsB,UAAU,CAAC,EAC/B,GAAG,EACH,KAAK,EACL,MAAM,EACN,MAAM,EACN,SAAgB,GACjB,EAAE,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,CAmBxC;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAanF"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Push a single locale's translations to the Translation Manager API.
|
|
3
|
+
*/
|
|
4
|
+
export async function pushLocale({ url, token, locale, groups, overwrite = true, }) {
|
|
5
|
+
const endpoint = `${url.replace(/\/$/, '')}/api/v1/import`;
|
|
6
|
+
const response = await fetch(endpoint, {
|
|
7
|
+
method: 'POST',
|
|
8
|
+
headers: {
|
|
9
|
+
'Content-Type': 'application/json',
|
|
10
|
+
Accept: 'application/json',
|
|
11
|
+
Authorization: `Bearer ${token}`,
|
|
12
|
+
},
|
|
13
|
+
body: JSON.stringify({ locale, groups, overwrite }),
|
|
14
|
+
});
|
|
15
|
+
if (!response.ok) {
|
|
16
|
+
const body = await response.text();
|
|
17
|
+
throw new Error(`HTTP ${response.status}: ${body}`);
|
|
18
|
+
}
|
|
19
|
+
return response.json();
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Fetch JSON from a Translation Manager API endpoint.
|
|
23
|
+
*/
|
|
24
|
+
export async function fetchJson(url, token) {
|
|
25
|
+
const res = await fetch(url, {
|
|
26
|
+
headers: {
|
|
27
|
+
Accept: 'application/json',
|
|
28
|
+
Authorization: `Bearer ${token}`,
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
if (!res.ok) {
|
|
32
|
+
throw new Error(`HTTP ${res.status}: ${await res.text()}`);
|
|
33
|
+
}
|
|
34
|
+
return res.json();
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=apiClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiClient.js","sourceRoot":"","sources":["../src/apiClient.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,EAC/B,GAAG,EACH,KAAK,EACL,MAAM,EACN,MAAM,EACN,SAAS,GAAG,IAAI,GACC;IACjB,MAAM,QAAQ,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,gBAAgB,CAAA;IAE1D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE;QACrC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,MAAM,EAAE,kBAAkB;YAC1B,aAAa,EAAE,UAAU,KAAK,EAAE;SACjC;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;KACpD,CAAC,CAAA;IAEF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;QAClC,MAAM,IAAI,KAAK,CAAC,QAAQ,QAAQ,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC,CAAA;IACrD,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,EAAyB,CAAA;AAC/C,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAc,GAAW,EAAE,KAAa;IACrE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAC3B,OAAO,EAAE;YACP,MAAM,EAAE,kBAAkB;YAC1B,aAAa,EAAE,UAAU,KAAK,EAAE;SACjC;KACF,CAAC,CAAA;IAEF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,QAAQ,GAAG,CAAC,MAAM,KAAK,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IAC5D,CAAC;IAED,OAAO,GAAG,CAAC,IAAI,EAAgB,CAAA;AACjC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../src/bin/pull.ts"],"names":[],"mappings":""}
|
package/dist/bin/pull.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
3
|
+
import { resolve, join } from 'node:path';
|
|
4
|
+
import { detectLayout } from '../langReader.js';
|
|
5
|
+
import { writeGroupedLocale, writeFlatLocale } from '../langWriter.js';
|
|
6
|
+
import { fetchJson } from '../apiClient.js';
|
|
7
|
+
function loadDotEnv(cwd) {
|
|
8
|
+
const envPath = join(cwd, '.env');
|
|
9
|
+
if (!existsSync(envPath)) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const lines = readFileSync(envPath, 'utf8').split('\n');
|
|
13
|
+
for (const line of lines) {
|
|
14
|
+
const trimmed = line.trim();
|
|
15
|
+
if (!trimmed || trimmed.startsWith('#')) {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
const eqIndex = trimmed.indexOf('=');
|
|
19
|
+
if (eqIndex === -1) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
const key = trimmed.slice(0, eqIndex).trim();
|
|
23
|
+
const rawValue = trimmed.slice(eqIndex + 1).trim();
|
|
24
|
+
const value = rawValue.replace(/^["']|["']$/g, '');
|
|
25
|
+
if (!(key in process.env)) {
|
|
26
|
+
process.env[key] = value;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function parseArgs(argv) {
|
|
31
|
+
const args = { flags: {} };
|
|
32
|
+
for (let i = 0; i < argv.length; i++) {
|
|
33
|
+
const arg = argv[i];
|
|
34
|
+
if (arg.startsWith('--')) {
|
|
35
|
+
const eqIdx = arg.indexOf('=');
|
|
36
|
+
const rawKey = eqIdx === -1 ? arg.slice(2) : arg.slice(2, eqIdx);
|
|
37
|
+
const key = rawKey.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
38
|
+
if (eqIdx !== -1) {
|
|
39
|
+
args.flags[key] = arg.slice(eqIdx + 1);
|
|
40
|
+
}
|
|
41
|
+
else if (argv[i + 1] && !argv[i + 1].startsWith('--')) {
|
|
42
|
+
args.flags[key] = argv[i + 1];
|
|
43
|
+
i++;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
args.flags[key] = true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return args;
|
|
51
|
+
}
|
|
52
|
+
async function main() {
|
|
53
|
+
const cwd = process.cwd();
|
|
54
|
+
loadDotEnv(cwd);
|
|
55
|
+
const { flags } = parseArgs(process.argv.slice(2));
|
|
56
|
+
const url = flags['url'] ?? process.env['TRANSLATIONS_URL'];
|
|
57
|
+
const token = flags['token'] ?? process.env['TRANSLATIONS_TOKEN'];
|
|
58
|
+
const localesPath = resolve(cwd, flags['path'] ??
|
|
59
|
+
process.env['TRANSLATIONS_LOCALES_PATH'] ??
|
|
60
|
+
'src/locales');
|
|
61
|
+
const onlyLocale = flags['locale'] ?? null;
|
|
62
|
+
const dryRun = flags['dryRun'] === true || flags['dryRun'] === 'true';
|
|
63
|
+
const forcedLayout = flags['layout'] ?? null;
|
|
64
|
+
if (!url || !token) {
|
|
65
|
+
console.error('Error: TRANSLATIONS_URL and TRANSLATIONS_TOKEN are required.');
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
const base = url.replace(/\/$/, '');
|
|
69
|
+
const langData = await fetchJson(`${base}/api/v1/languages`, token);
|
|
70
|
+
let locales = langData.data.map((l) => l.code);
|
|
71
|
+
if (onlyLocale) {
|
|
72
|
+
locales = locales.filter((c) => c === onlyLocale);
|
|
73
|
+
if (locales.length === 0) {
|
|
74
|
+
console.warn(`Locale "${onlyLocale}" not found in Translation Manager.`);
|
|
75
|
+
process.exit(0);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const layout = forcedLayout ?? detectLayout(localesPath) ?? 'grouped';
|
|
79
|
+
const prefix = dryRun ? '[DRY RUN] ' : '';
|
|
80
|
+
console.log(`${prefix}Pulling ${locales.length} locale(s) [${layout} layout]: ${locales.join(', ')}`);
|
|
81
|
+
for (const locale of locales) {
|
|
82
|
+
const data = await fetchJson(`${base}/api/v1/translations/${locale}?format=nested`, token);
|
|
83
|
+
const groups = data.data ?? {};
|
|
84
|
+
const keyCount = Object.values(groups).reduce((sum, g) => sum + Object.keys(g).length, 0);
|
|
85
|
+
if (dryRun) {
|
|
86
|
+
console.log(` ${locale}: ${keyCount} keys across ${Object.keys(groups).length} group(s).`);
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
const written = layout === 'grouped'
|
|
90
|
+
? writeGroupedLocale(localesPath, locale, groups)
|
|
91
|
+
: writeFlatLocale(localesPath, locale, groups);
|
|
92
|
+
console.log(` ✓ ${locale}: ${keyCount} keys → ${written.length} file(s) written.`);
|
|
93
|
+
}
|
|
94
|
+
if (!dryRun) {
|
|
95
|
+
console.log('\nDone.');
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
main();
|
|
99
|
+
//# sourceMappingURL=pull.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pull.js","sourceRoot":"","sources":["../../src/bin/pull.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../src/bin/push.ts"],"names":[],"mappings":""}
|
package/dist/bin/push.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
3
|
+
import { resolve, join } from 'node:path';
|
|
4
|
+
import { readLocales } from '../langReader.js';
|
|
5
|
+
import { pushLocale } from '../apiClient.js';
|
|
6
|
+
function loadDotEnv(cwd) {
|
|
7
|
+
const envPath = join(cwd, '.env');
|
|
8
|
+
if (!existsSync(envPath)) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const lines = readFileSync(envPath, 'utf8').split('\n');
|
|
12
|
+
for (const line of lines) {
|
|
13
|
+
const trimmed = line.trim();
|
|
14
|
+
if (!trimmed || trimmed.startsWith('#')) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
const eqIndex = trimmed.indexOf('=');
|
|
18
|
+
if (eqIndex === -1) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
const key = trimmed.slice(0, eqIndex).trim();
|
|
22
|
+
const rawValue = trimmed.slice(eqIndex + 1).trim();
|
|
23
|
+
const value = rawValue.replace(/^["']|["']$/g, '');
|
|
24
|
+
if (!(key in process.env)) {
|
|
25
|
+
process.env[key] = value;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function parseArgs(argv) {
|
|
30
|
+
const args = { flags: {}, positional: [] };
|
|
31
|
+
for (let i = 0; i < argv.length; i++) {
|
|
32
|
+
const arg = argv[i];
|
|
33
|
+
if (arg.startsWith('--')) {
|
|
34
|
+
const eqIdx = arg.indexOf('=');
|
|
35
|
+
const rawKey = eqIdx === -1 ? arg.slice(2) : arg.slice(2, eqIdx);
|
|
36
|
+
const key = rawKey.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
37
|
+
if (eqIdx !== -1) {
|
|
38
|
+
args.flags[key] = arg.slice(eqIdx + 1);
|
|
39
|
+
}
|
|
40
|
+
else if (argv[i + 1] && !argv[i + 1].startsWith('--')) {
|
|
41
|
+
args.flags[key] = argv[i + 1];
|
|
42
|
+
i++;
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
args.flags[key] = true;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
args.positional.push(arg);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return args;
|
|
53
|
+
}
|
|
54
|
+
async function main() {
|
|
55
|
+
const cwd = process.cwd();
|
|
56
|
+
loadDotEnv(cwd);
|
|
57
|
+
const { flags } = parseArgs(process.argv.slice(2));
|
|
58
|
+
const url = flags['url'] ?? process.env['TRANSLATIONS_URL'];
|
|
59
|
+
const token = flags['token'] ?? process.env['TRANSLATIONS_TOKEN'];
|
|
60
|
+
const localesPath = resolve(cwd, flags['path'] ??
|
|
61
|
+
process.env['TRANSLATIONS_LOCALES_PATH'] ??
|
|
62
|
+
'src/locales');
|
|
63
|
+
const onlyLocale = flags['locale'] ?? null;
|
|
64
|
+
const overwrite = flags['overwrite'] !== 'false' && flags['overwrite'] !== false;
|
|
65
|
+
const dryRun = flags['dryRun'] === true || flags['dryRun'] === 'true';
|
|
66
|
+
const excludeFiles = typeof flags['exclude'] === 'string' ? flags['exclude'].split(',') : [];
|
|
67
|
+
if (!url || !token) {
|
|
68
|
+
console.error('Error: TRANSLATIONS_URL and TRANSLATIONS_TOKEN are required.');
|
|
69
|
+
console.error('Set them in .env or pass --url and --token flags.');
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
let locales = readLocales(localesPath, excludeFiles);
|
|
73
|
+
if (locales.length === 0) {
|
|
74
|
+
console.warn(`No locale files found in: ${localesPath}`);
|
|
75
|
+
process.exit(0);
|
|
76
|
+
}
|
|
77
|
+
if (onlyLocale) {
|
|
78
|
+
locales = locales.filter((l) => l.locale === onlyLocale);
|
|
79
|
+
if (locales.length === 0) {
|
|
80
|
+
console.warn(`Locale "${onlyLocale}" not found in: ${localesPath}`);
|
|
81
|
+
process.exit(0);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const prefix = dryRun ? '[DRY RUN] ' : '';
|
|
85
|
+
console.log(`${prefix}Pushing ${locales.length} locale(s): ${locales.map((l) => l.locale).join(', ')}`);
|
|
86
|
+
let totalNew = 0;
|
|
87
|
+
let totalUpdated = 0;
|
|
88
|
+
let totalKeys = 0;
|
|
89
|
+
for (const { locale, groups } of locales) {
|
|
90
|
+
const keyCount = Object.values(groups).reduce((sum, g) => sum + Object.keys(g).length, 0);
|
|
91
|
+
if (dryRun) {
|
|
92
|
+
console.log(` ${locale}: ${keyCount} keys across ${Object.keys(groups).length} group(s).`);
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
const data = await pushLocale({ url, token, locale, groups, overwrite });
|
|
97
|
+
totalNew += data.new ?? 0;
|
|
98
|
+
totalUpdated += data.updated ?? 0;
|
|
99
|
+
totalKeys += data.total ?? keyCount;
|
|
100
|
+
console.log(` ✓ ${locale}: ${data.total ?? keyCount} keys — ${data.new ?? 0} new, ${data.updated ?? 0} updated.`);
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
console.error(` ✗ ${locale}: ${err instanceof Error ? err.message : String(err)}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (!dryRun) {
|
|
107
|
+
console.log(`\nDone. Total: ${totalKeys} keys — ${totalNew} new, ${totalUpdated} updated.`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
main();
|
|
111
|
+
//# sourceMappingURL=push.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"push.js","sourceRoot":"","sources":["../../src/bin/push.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { readLocales, readFlatLayout, readGroupedLayout, detectLayout } from './langReader.js';
|
|
2
|
+
export { pushLocale, fetchJson } from './apiClient.js';
|
|
3
|
+
export { unflatten, writeGroupedLocale, writeFlatLocale } from './langWriter.js';
|
|
4
|
+
export type { FlatKeys, LocaleGroups, LocaleLayout, LocaleData, PushLocaleParams, PushResult, PullOptions, PushOptions, } from './types.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9F,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AACtD,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAChF,YAAY,EACV,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,WAAW,GACZ,MAAM,YAAY,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9F,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AACtD,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { LocaleData, LocaleLayout } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Detect which locale layout the locales directory uses.
|
|
4
|
+
*
|
|
5
|
+
* Layout `flat` — one file per locale: locales/en.json, locales/de.json
|
|
6
|
+
* Layout `grouped` — one subdirectory per locale: locales/en/auth.json, locales/de/auth.json
|
|
7
|
+
*/
|
|
8
|
+
export declare function detectLayout(localesPath: string): LocaleLayout | null;
|
|
9
|
+
/**
|
|
10
|
+
* Read translations in flat layout (one JSON per locale).
|
|
11
|
+
* All keys are placed in the `_json` group to match Laravel's JSON translation convention.
|
|
12
|
+
*/
|
|
13
|
+
export declare function readFlatLayout(localesPath: string, excludeFiles?: string[]): LocaleData[];
|
|
14
|
+
/**
|
|
15
|
+
* Read translations in grouped layout (subdirectory per locale, multiple group files).
|
|
16
|
+
*/
|
|
17
|
+
export declare function readGroupedLayout(localesPath: string, excludeFiles?: string[]): LocaleData[];
|
|
18
|
+
/**
|
|
19
|
+
* Auto-detect layout and read all locales from the given path.
|
|
20
|
+
*/
|
|
21
|
+
export declare function readLocales(localesPath: string, excludeFiles?: string[]): LocaleData[];
|
|
22
|
+
//# sourceMappingURL=langReader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"langReader.d.ts","sourceRoot":"","sources":["../src/langReader.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAY,UAAU,EAAgB,YAAY,EAAE,MAAM,YAAY,CAAA;AAiClF;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAmBrE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,GAAE,MAAM,EAAO,GAAG,UAAU,EAAE,CAwB7F;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,GAAE,MAAM,EAAO,GAAG,UAAU,EAAE,CAiChG;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,GAAE,MAAM,EAAO,GAAG,UAAU,EAAE,CAU1F"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join, basename, extname } from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Flatten a nested object into dot-notation keys.
|
|
5
|
+
* { auth: { login: 'Login' } } → { 'auth.login': 'Login' }
|
|
6
|
+
*/
|
|
7
|
+
function flatten(obj, prefix = '') {
|
|
8
|
+
const result = {};
|
|
9
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
10
|
+
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
11
|
+
if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
|
12
|
+
Object.assign(result, flatten(value, fullKey));
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
result[fullKey] = String(value ?? '');
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Read and parse a JSON file. Returns an empty object on failure.
|
|
22
|
+
*/
|
|
23
|
+
function readJson(filePath) {
|
|
24
|
+
try {
|
|
25
|
+
return JSON.parse(readFileSync(filePath, 'utf8'));
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Detect which locale layout the locales directory uses.
|
|
33
|
+
*
|
|
34
|
+
* Layout `flat` — one file per locale: locales/en.json, locales/de.json
|
|
35
|
+
* Layout `grouped` — one subdirectory per locale: locales/en/auth.json, locales/de/auth.json
|
|
36
|
+
*/
|
|
37
|
+
export function detectLayout(localesPath) {
|
|
38
|
+
if (!existsSync(localesPath)) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
const entries = readdirSync(localesPath, { withFileTypes: true });
|
|
42
|
+
const hasJsonFiles = entries.some((e) => e.isFile() && e.name.endsWith('.json'));
|
|
43
|
+
const hasDirs = entries.some((e) => e.isDirectory());
|
|
44
|
+
if (hasDirs) {
|
|
45
|
+
return 'grouped';
|
|
46
|
+
}
|
|
47
|
+
if (hasJsonFiles) {
|
|
48
|
+
return 'flat';
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Read translations in flat layout (one JSON per locale).
|
|
54
|
+
* All keys are placed in the `_json` group to match Laravel's JSON translation convention.
|
|
55
|
+
*/
|
|
56
|
+
export function readFlatLayout(localesPath, excludeFiles = []) {
|
|
57
|
+
const entries = readdirSync(localesPath, { withFileTypes: true });
|
|
58
|
+
const result = [];
|
|
59
|
+
for (const entry of entries) {
|
|
60
|
+
if (!entry.isFile() || !entry.name.endsWith('.json')) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (excludeFiles.includes(entry.name)) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const locale = basename(entry.name, '.json');
|
|
67
|
+
const filePath = join(localesPath, entry.name);
|
|
68
|
+
const parsed = readJson(filePath);
|
|
69
|
+
result.push({
|
|
70
|
+
locale,
|
|
71
|
+
groups: { _json: flatten(parsed) },
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Read translations in grouped layout (subdirectory per locale, multiple group files).
|
|
78
|
+
*/
|
|
79
|
+
export function readGroupedLayout(localesPath, excludeFiles = []) {
|
|
80
|
+
const entries = readdirSync(localesPath, { withFileTypes: true });
|
|
81
|
+
const result = [];
|
|
82
|
+
for (const entry of entries) {
|
|
83
|
+
if (!entry.isDirectory()) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const locale = entry.name;
|
|
87
|
+
const localePath = join(localesPath, locale);
|
|
88
|
+
const groups = {};
|
|
89
|
+
for (const file of readdirSync(localePath)) {
|
|
90
|
+
if (extname(file) !== '.json') {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (excludeFiles.includes(file)) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const groupName = basename(file, '.json');
|
|
97
|
+
const parsed = readJson(join(localePath, file));
|
|
98
|
+
groups[groupName] = flatten(parsed);
|
|
99
|
+
}
|
|
100
|
+
if (Object.keys(groups).length > 0) {
|
|
101
|
+
result.push({ locale, groups });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Auto-detect layout and read all locales from the given path.
|
|
108
|
+
*/
|
|
109
|
+
export function readLocales(localesPath, excludeFiles = []) {
|
|
110
|
+
const layout = detectLayout(localesPath);
|
|
111
|
+
if (!layout) {
|
|
112
|
+
return [];
|
|
113
|
+
}
|
|
114
|
+
return layout === 'grouped'
|
|
115
|
+
? readGroupedLayout(localesPath, excludeFiles)
|
|
116
|
+
: readFlatLayout(localesPath, excludeFiles);
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=langReader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"langReader.js","sourceRoot":"","sources":["../src/langReader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { FlatKeys, LocaleGroups } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Restore dot-notation flat keys back to a nested object.
|
|
4
|
+
* { 'auth.login': 'Login' } → { auth: { login: 'Login' } }
|
|
5
|
+
*/
|
|
6
|
+
export declare function unflatten(flat: FlatKeys): Record<string, unknown>;
|
|
7
|
+
/**
|
|
8
|
+
* Write translations for a single locale in grouped layout.
|
|
9
|
+
*
|
|
10
|
+
* Each group becomes its own file: locales/{locale}/{group}.json
|
|
11
|
+
* The special `_json` group is written as locales/{locale}.json (root-level).
|
|
12
|
+
*/
|
|
13
|
+
export declare function writeGroupedLocale(localesPath: string, locale: string, groups: LocaleGroups): string[];
|
|
14
|
+
/**
|
|
15
|
+
* Write translations for a single locale in flat layout.
|
|
16
|
+
*
|
|
17
|
+
* All groups are merged into a single locales/{locale}.json file.
|
|
18
|
+
*/
|
|
19
|
+
export declare function writeFlatLocale(localesPath: string, locale: string, groups: LocaleGroups): string[];
|
|
20
|
+
//# sourceMappingURL=langWriter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"langWriter.d.ts","sourceRoot":"","sources":["../src/langWriter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAExD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAqBjE;AAeD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,YAAY,GACnB,MAAM,EAAE,CAkBV;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,YAAY,GACnB,MAAM,EAAE,CAYV"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join, dirname } from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Restore dot-notation flat keys back to a nested object.
|
|
5
|
+
* { 'auth.login': 'Login' } → { auth: { login: 'Login' } }
|
|
6
|
+
*/
|
|
7
|
+
export function unflatten(flat) {
|
|
8
|
+
const result = {};
|
|
9
|
+
for (const [dotKey, value] of Object.entries(flat)) {
|
|
10
|
+
const parts = dotKey.split('.');
|
|
11
|
+
let cursor = result;
|
|
12
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
13
|
+
const part = parts[i];
|
|
14
|
+
if (typeof cursor[part] !== 'object' || cursor[part] === null) {
|
|
15
|
+
cursor[part] = {};
|
|
16
|
+
}
|
|
17
|
+
cursor = cursor[part];
|
|
18
|
+
}
|
|
19
|
+
cursor[parts[parts.length - 1]] = value;
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Write a JSON file, creating parent directories as needed.
|
|
25
|
+
*/
|
|
26
|
+
function writeJson(filePath, data) {
|
|
27
|
+
const dir = dirname(filePath);
|
|
28
|
+
if (!existsSync(dir)) {
|
|
29
|
+
mkdirSync(dir, { recursive: true });
|
|
30
|
+
}
|
|
31
|
+
writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n', 'utf8');
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Write translations for a single locale in grouped layout.
|
|
35
|
+
*
|
|
36
|
+
* Each group becomes its own file: locales/{locale}/{group}.json
|
|
37
|
+
* The special `_json` group is written as locales/{locale}.json (root-level).
|
|
38
|
+
*/
|
|
39
|
+
export function writeGroupedLocale(localesPath, locale, groups) {
|
|
40
|
+
const written = [];
|
|
41
|
+
for (const [groupName, flatKeys] of Object.entries(groups)) {
|
|
42
|
+
const nested = unflatten(flatKeys);
|
|
43
|
+
if (groupName === '_json') {
|
|
44
|
+
const filePath = join(localesPath, `${locale}.json`);
|
|
45
|
+
writeJson(filePath, nested);
|
|
46
|
+
written.push(filePath);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
const filePath = join(localesPath, locale, `${groupName}.json`);
|
|
50
|
+
writeJson(filePath, nested);
|
|
51
|
+
written.push(filePath);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return written;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Write translations for a single locale in flat layout.
|
|
58
|
+
*
|
|
59
|
+
* All groups are merged into a single locales/{locale}.json file.
|
|
60
|
+
*/
|
|
61
|
+
export function writeFlatLocale(localesPath, locale, groups) {
|
|
62
|
+
const merged = {};
|
|
63
|
+
for (const flatKeys of Object.values(groups)) {
|
|
64
|
+
Object.assign(merged, flatKeys);
|
|
65
|
+
}
|
|
66
|
+
const nested = unflatten(merged);
|
|
67
|
+
const filePath = join(localesPath, `${locale}.json`);
|
|
68
|
+
writeJson(filePath, nested);
|
|
69
|
+
return [filePath];
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=langWriter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"langWriter.js","sourceRoot":"","sources":["../src/langWriter.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/** Flat map of dot-notation keys to string values. */
|
|
2
|
+
export type FlatKeys = Record<string, string>;
|
|
3
|
+
/** A locale's translations grouped by file/group name. */
|
|
4
|
+
export type LocaleGroups = Record<string, FlatKeys>;
|
|
5
|
+
/** Detected directory layout of the locales folder. */
|
|
6
|
+
export type LocaleLayout = 'flat' | 'grouped';
|
|
7
|
+
/** A single locale's data as returned by readLocales(). */
|
|
8
|
+
export interface LocaleData {
|
|
9
|
+
locale: string;
|
|
10
|
+
groups: LocaleGroups;
|
|
11
|
+
}
|
|
12
|
+
/** Parameters for pushLocale(). */
|
|
13
|
+
export interface PushLocaleParams {
|
|
14
|
+
/** Base URL of the Translation Manager (e.g. https://translations.example.com). */
|
|
15
|
+
url: string;
|
|
16
|
+
/** API bearer token. */
|
|
17
|
+
token: string;
|
|
18
|
+
/** Locale code, e.g. 'en', 'de'. */
|
|
19
|
+
locale: string;
|
|
20
|
+
/** Translation groups to push. */
|
|
21
|
+
groups: LocaleGroups;
|
|
22
|
+
/** When true, existing keys will be overwritten. Defaults to true. */
|
|
23
|
+
overwrite?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/** Response from the Translation Manager import endpoint. */
|
|
26
|
+
export interface PushResult {
|
|
27
|
+
new: number;
|
|
28
|
+
updated: number;
|
|
29
|
+
total: number;
|
|
30
|
+
}
|
|
31
|
+
/** Parameters for pullLocale() / the pull CLI. */
|
|
32
|
+
export interface PullOptions {
|
|
33
|
+
/** Base URL of the Translation Manager. */
|
|
34
|
+
url: string;
|
|
35
|
+
/** API bearer token. */
|
|
36
|
+
token: string;
|
|
37
|
+
/** Absolute path to the locales directory. */
|
|
38
|
+
localesPath: string;
|
|
39
|
+
/** Restrict pull to a single locale code. */
|
|
40
|
+
locale?: string | null;
|
|
41
|
+
/** Force layout instead of auto-detecting. */
|
|
42
|
+
layout?: LocaleLayout | null;
|
|
43
|
+
/** Dry-run: report what would be written without writing. */
|
|
44
|
+
dryRun?: boolean;
|
|
45
|
+
}
|
|
46
|
+
/** Parameters for pushAll() / the push CLI. */
|
|
47
|
+
export interface PushOptions {
|
|
48
|
+
/** Base URL of the Translation Manager. */
|
|
49
|
+
url: string;
|
|
50
|
+
/** API bearer token. */
|
|
51
|
+
token: string;
|
|
52
|
+
/** Absolute path to the locales directory. */
|
|
53
|
+
localesPath: string;
|
|
54
|
+
/** Restrict push to a single locale code. */
|
|
55
|
+
locale?: string | null;
|
|
56
|
+
/** When true, existing keys will be overwritten. Defaults to true. */
|
|
57
|
+
overwrite?: boolean;
|
|
58
|
+
/** Dry-run: report what would be sent without sending. */
|
|
59
|
+
dryRun?: boolean;
|
|
60
|
+
/** JSON filenames to exclude from reading. */
|
|
61
|
+
excludeFiles?: string[];
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAE7C,0DAA0D;AAC1D,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;AAEnD,uDAAuD;AACvD,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,SAAS,CAAA;AAE7C,2DAA2D;AAC3D,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,YAAY,CAAA;CACrB;AAED,mCAAmC;AACnC,MAAM,WAAW,gBAAgB;IAC/B,mFAAmF;IACnF,GAAG,EAAE,MAAM,CAAA;IACX,wBAAwB;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAA;IACd,kCAAkC;IAClC,MAAM,EAAE,YAAY,CAAA;IACpB,sEAAsE;IACtE,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,6DAA6D;AAC7D,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;CACd;AAED,kDAAkD;AAClD,MAAM,WAAW,WAAW;IAC1B,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAA;IACX,wBAAwB;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAA;IACnB,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,YAAY,GAAG,IAAI,CAAA;IAC5B,6DAA6D;IAC7D,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,+CAA+C;AAC/C,MAAM,WAAW,WAAW;IAC1B,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAA;IACX,wBAAwB;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAA;IACnB,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,sEAAsE;IACtE,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,8CAA8C;IAC9C,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;CACxB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@metasyncsite/translations-client-ts",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Push/pull i18n translations (Vue, React, Next.js, etc.) to the MetaSyncSite Translation Manager — TypeScript edition",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=18.0.0"
|
|
8
|
+
},
|
|
9
|
+
"bin": {
|
|
10
|
+
"translations-push": "./dist/bin/push.js",
|
|
11
|
+
"translations-pull": "./dist/bin/pull.js"
|
|
12
|
+
},
|
|
13
|
+
"main": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"import": "./dist/index.js",
|
|
18
|
+
"types": "./dist/index.d.ts"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsc",
|
|
26
|
+
"dev": "tsc --watch",
|
|
27
|
+
"prepublishOnly": "npm run build"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/node": "^22.0.0",
|
|
31
|
+
"typescript": "^5.4.0"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"i18n",
|
|
35
|
+
"vue-i18n",
|
|
36
|
+
"translations",
|
|
37
|
+
"localization",
|
|
38
|
+
"typescript"
|
|
39
|
+
]
|
|
40
|
+
}
|