gsheets-i18n 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 +414 -0
- package/dist/cjs/cli/index.js +125 -0
- package/dist/cjs/cli/index.js.map +1 -0
- package/dist/cjs/index.js +57 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/lib/auth.js +34 -0
- package/dist/cjs/lib/auth.js.map +1 -0
- package/dist/cjs/lib/defaultKeyMap.js +106 -0
- package/dist/cjs/lib/defaultKeyMap.js.map +1 -0
- package/dist/cjs/lib/driveClient.js +50 -0
- package/dist/cjs/lib/driveClient.js.map +1 -0
- package/dist/cjs/lib/folderExtractor.js +63 -0
- package/dist/cjs/lib/folderExtractor.js.map +1 -0
- package/dist/cjs/lib/parser.js +120 -0
- package/dist/cjs/lib/parser.js.map +1 -0
- package/dist/cjs/lib/sheetExtractor.js +52 -0
- package/dist/cjs/lib/sheetExtractor.js.map +1 -0
- package/dist/cjs/lib/sheetsClient.js +37 -0
- package/dist/cjs/lib/sheetsClient.js.map +1 -0
- package/dist/cjs/lib/writer.js +33 -0
- package/dist/cjs/lib/writer.js.map +1 -0
- package/dist/cjs/types/index.js +4 -0
- package/dist/cjs/types/index.js.map +1 -0
- package/dist/esm/cli/index.js +123 -0
- package/dist/esm/cli/index.js.map +1 -0
- package/dist/esm/index.js +54 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/lib/auth.js +31 -0
- package/dist/esm/lib/auth.js.map +1 -0
- package/dist/esm/lib/defaultKeyMap.js +103 -0
- package/dist/esm/lib/defaultKeyMap.js.map +1 -0
- package/dist/esm/lib/driveClient.js +43 -0
- package/dist/esm/lib/driveClient.js.map +1 -0
- package/dist/esm/lib/folderExtractor.js +60 -0
- package/dist/esm/lib/folderExtractor.js.map +1 -0
- package/dist/esm/lib/parser.js +114 -0
- package/dist/esm/lib/parser.js.map +1 -0
- package/dist/esm/lib/sheetExtractor.js +49 -0
- package/dist/esm/lib/sheetExtractor.js.map +1 -0
- package/dist/esm/lib/sheetsClient.js +33 -0
- package/dist/esm/lib/sheetsClient.js.map +1 -0
- package/dist/esm/lib/writer.js +30 -0
- package/dist/esm/lib/writer.js.map +1 -0
- package/dist/esm/types/index.js +3 -0
- package/dist/esm/types/index.js.map +1 -0
- package/dist/types/cli/index.d.ts +3 -0
- package/dist/types/cli/index.d.ts.map +1 -0
- package/dist/types/index.d.ts +21 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/lib/auth.d.ts +9 -0
- package/dist/types/lib/auth.d.ts.map +1 -0
- package/dist/types/lib/defaultKeyMap.d.ts +9 -0
- package/dist/types/lib/defaultKeyMap.d.ts.map +1 -0
- package/dist/types/lib/driveClient.d.ts +20 -0
- package/dist/types/lib/driveClient.d.ts.map +1 -0
- package/dist/types/lib/folderExtractor.d.ts +23 -0
- package/dist/types/lib/folderExtractor.d.ts.map +1 -0
- package/dist/types/lib/parser.d.ts +60 -0
- package/dist/types/lib/parser.d.ts.map +1 -0
- package/dist/types/lib/sheetExtractor.d.ts +26 -0
- package/dist/types/lib/sheetExtractor.d.ts.map +1 -0
- package/dist/types/lib/sheetsClient.d.ts +15 -0
- package/dist/types/lib/sheetsClient.d.ts.map +1 -0
- package/dist/types/lib/writer.d.ts +9 -0
- package/dist/types/lib/writer.d.ts.map +1 -0
- package/dist/types/types/index.d.ts +153 -0
- package/dist/types/types/index.d.ts.map +1 -0
- package/package.json +62 -0
package/README.md
ADDED
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
# gsheets-i18n
|
|
2
|
+
|
|
3
|
+
Generate i18n JSON files from a Google Spreadsheet — as a CLI tool or a Node.js library.
|
|
4
|
+
|
|
5
|
+
Each tab of your spreadsheet becomes a **namespace**, each row a **translation key**, and each language column an output file. The result is one `<locale>.json` file per language, with nested keys, ready to drop into React i18next, Vue i18n, or any similar framework.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
- [How it works](#how-it-works)
|
|
12
|
+
- [Installation](#installation)
|
|
13
|
+
- [Google Setup](#google-setup)
|
|
14
|
+
- [Spreadsheet Format](#spreadsheet-format)
|
|
15
|
+
- [CLI Usage](#cli-usage)
|
|
16
|
+
- [Programmatic API](#programmatic-api)
|
|
17
|
+
- [Key Mapping](#key-mapping)
|
|
18
|
+
- [Folder Mode](#folder-mode)
|
|
19
|
+
- [Configuration Reference](#configuration-reference)
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## How it works
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
Google Spreadsheet
|
|
27
|
+
┌─────────────────────────────────────────────┐
|
|
28
|
+
│ Tab: "actions" │
|
|
29
|
+
│ key │ EN │ FR │
|
|
30
|
+
│ save │ Save │ Enregistrer │
|
|
31
|
+
│ cancel │ Cancel │ Annuler │
|
|
32
|
+
│ │ │
|
|
33
|
+
│ Tab: "errors" │ │
|
|
34
|
+
│ key │ EN │ FR │
|
|
35
|
+
│ not_found │ Not found│ Introuvable │
|
|
36
|
+
└─────────────────────────────────────────────┘
|
|
37
|
+
│
|
|
38
|
+
▼ gsheets-i18n
|
|
39
|
+
|
|
40
|
+
en.json fr.json
|
|
41
|
+
{ {
|
|
42
|
+
"actions": { "actions": {
|
|
43
|
+
"save": "Save", "save": "Enregistrer",
|
|
44
|
+
"cancel": "Cancel" "cancel": "Annuler"
|
|
45
|
+
}, },
|
|
46
|
+
"errors": { "errors": {
|
|
47
|
+
"not_found": "Not found" "not_found": "Introuvable"
|
|
48
|
+
} }
|
|
49
|
+
} }
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
In your code you then access translations with dotted paths:
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
t("actions.save") // → "Save"
|
|
56
|
+
t("errors.not_found") // → "Not found"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Installation
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# As a dev dependency (recommended for most projects)
|
|
65
|
+
npm install --save-dev gsheets-i18n
|
|
66
|
+
|
|
67
|
+
# Or globally for CLI use
|
|
68
|
+
npm install -g gsheets-i18n
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Requirements:** Node.js ≥ 18
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Google Setup
|
|
76
|
+
|
|
77
|
+
### 1. Create a Service Account
|
|
78
|
+
|
|
79
|
+
1. Go to the [Google Cloud Console](https://console.cloud.google.com/)
|
|
80
|
+
2. Create or select a project
|
|
81
|
+
3. Go to **APIs & Services → Credentials**
|
|
82
|
+
4. Click **Create Credentials → Service Account**
|
|
83
|
+
5. Give it a name and click **Done**
|
|
84
|
+
6. Open the service account, go to **Keys → Add Key → Create new key → JSON**
|
|
85
|
+
7. Download the JSON file — this is your `service-account.json`
|
|
86
|
+
|
|
87
|
+
### 2. Enable the required APIs
|
|
88
|
+
|
|
89
|
+
In **APIs & Services → Enabled APIs**, enable:
|
|
90
|
+
|
|
91
|
+
- **Google Sheets API**
|
|
92
|
+
- **Google Drive API** ← only required for [folder mode](#folder-mode)
|
|
93
|
+
|
|
94
|
+
### 3. Share your spreadsheet with the service account
|
|
95
|
+
|
|
96
|
+
Open your Google Spreadsheet, click **Share**, and add the service account email (looks like `name@project.iam.gserviceaccount.com`) with **Viewer** permissions.
|
|
97
|
+
|
|
98
|
+
> ⚠️ Keep `service-account.json` out of version control. Add it to `.gitignore`.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Spreadsheet Format
|
|
103
|
+
|
|
104
|
+
### Basic structure
|
|
105
|
+
|
|
106
|
+
Each **tab** represents a namespace. Rows are translation keys, columns are languages.
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
┌──────────────────┬──────────────┬────────────────┬────────────────┐
|
|
110
|
+
│ key │ EN │ FR │ DE │
|
|
111
|
+
├──────────────────┼──────────────┼────────────────┼────────────────┤
|
|
112
|
+
│ save │ Save │ Enregistrer │ Speichern │
|
|
113
|
+
│ cancel │ Cancel │ Annuler │ Abbrechen │
|
|
114
|
+
│ confirm │ Confirm │ Confirmer │ Bestätigen │
|
|
115
|
+
└──────────────────┴──────────────┴────────────────┴────────────────┘
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
- **Row 1** — Header row: first cell is ignored (label for the key column), remaining cells are language identifiers.
|
|
119
|
+
- **Column A** — Translation key. Supports **dot notation** for nesting: `modal.title` → `{ modal: { title: "…" } }`.
|
|
120
|
+
- **Other columns** — One language per column. The header value is mapped to a locale code (see [Key Mapping](#key-mapping)).
|
|
121
|
+
|
|
122
|
+
### Skipping tabs and columns
|
|
123
|
+
|
|
124
|
+
Prefix a tab name or column header with `_` to exclude it from output:
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
Tab name "_notes" → ignored entirely
|
|
128
|
+
Column header "_dev" → ignored entirely
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Dot notation in keys
|
|
132
|
+
|
|
133
|
+
Use dots in your key to create nested output objects:
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
key │ EN
|
|
137
|
+
modal.title │ Confirm action
|
|
138
|
+
modal.body │ Are you sure?
|
|
139
|
+
modal.actions.confirm │ Yes, proceed
|
|
140
|
+
modal.actions.cancel │ Go back
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Produces:
|
|
144
|
+
|
|
145
|
+
```json
|
|
146
|
+
{
|
|
147
|
+
"modal": {
|
|
148
|
+
"title": "Confirm action",
|
|
149
|
+
"body": "Are you sure?",
|
|
150
|
+
"actions": {
|
|
151
|
+
"confirm": "Yes, proceed",
|
|
152
|
+
"cancel": "Go back"
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Multiple tabs
|
|
159
|
+
|
|
160
|
+
Each tab becomes a top-level namespace in the output:
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
Tab "actions" + key "save" → { "actions": { "save": "…" } }
|
|
164
|
+
Tab "errors" + key "404" → { "errors": { "404": "…" } }
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## CLI Usage
|
|
170
|
+
|
|
171
|
+
### Sheet mode
|
|
172
|
+
|
|
173
|
+
Extract from a single spreadsheet (all non-internal tabs):
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
gsheets-i18n sheet \
|
|
177
|
+
--sheet-id 4BxiM*****pms \
|
|
178
|
+
--key ./service-account.json \
|
|
179
|
+
--out ./src/locales
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Extract only one specific tab (by its numeric tab ID):
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
gsheets-i18n sheet \
|
|
186
|
+
--sheet-id 4BxiM*****pms \
|
|
187
|
+
--key ./service-account.json \
|
|
188
|
+
--tab-id 0 \
|
|
189
|
+
--out ./src/locales
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
> **Finding the tab ID:** Right-click a tab in your browser → "Copy link" — the URL contains `#gid=<tabId>`.
|
|
193
|
+
|
|
194
|
+
### Folder mode
|
|
195
|
+
|
|
196
|
+
Scan a Drive folder recursively and extract from every spreadsheet found:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
gsheets-i18n folder \
|
|
200
|
+
--folder-id 1A2B3C4D5E6F7G8H9I0J \
|
|
201
|
+
--key ./service-account.json \
|
|
202
|
+
--out ./src/locales
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Output example
|
|
206
|
+
|
|
207
|
+
```
|
|
208
|
+
✔ Done in 1.24s
|
|
209
|
+
|
|
210
|
+
📂 /your/project/src/locales
|
|
211
|
+
|
|
212
|
+
de.json (3 top-level keys)
|
|
213
|
+
en.json (3 top-level keys)
|
|
214
|
+
fr.json (3 top-level keys)
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Adding to package.json scripts
|
|
218
|
+
|
|
219
|
+
```json
|
|
220
|
+
{
|
|
221
|
+
"scripts": {
|
|
222
|
+
"i18n:pull": "gsheets-i18n sheet --sheet-id YOUR_ID --key ./service-account.json --out ./src/locales"
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Programmatic API
|
|
230
|
+
|
|
231
|
+
```ts
|
|
232
|
+
import { extract } from "gsheets-i18n";
|
|
233
|
+
|
|
234
|
+
const result = await extract({
|
|
235
|
+
serviceAccountKey: "./service-account.json",
|
|
236
|
+
source: {
|
|
237
|
+
mode: "sheet",
|
|
238
|
+
spreadsheetId: "4BxiM*****pms",
|
|
239
|
+
},
|
|
240
|
+
outputDir: "./src/locales",
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
console.log(`Generated ${result.files.length} files in ${result.durationMs}ms`);
|
|
244
|
+
// → Generated 3 files in 1240ms
|
|
245
|
+
|
|
246
|
+
for (const file of result.files) {
|
|
247
|
+
console.log(`${file.locale}: ${file.path} (${file.keyCount} keys)`);
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
The `extract()` function returns a `Promise<ExtractResult>`:
|
|
252
|
+
|
|
253
|
+
```ts
|
|
254
|
+
interface ExtractResult {
|
|
255
|
+
files: OutputFile[]; // One entry per generated file
|
|
256
|
+
durationMs: number; // Total wall-clock time
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
interface OutputFile {
|
|
260
|
+
locale: string; // e.g. "en", "fr", "zh-TW"
|
|
261
|
+
path: string; // Absolute path to the written file
|
|
262
|
+
keyCount: number; // Number of top-level namespace keys
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Key Mapping
|
|
269
|
+
|
|
270
|
+
Column headers in your sheet are mapped to BCP-47 locale codes. A wide range of spellings is supported out of the box:
|
|
271
|
+
|
|
272
|
+
| Header in sheet | Output locale code |
|
|
273
|
+
|----------------------------|--------------------|
|
|
274
|
+
| `EN`, `ENG`, `English` | `en` |
|
|
275
|
+
| `FR`, `FRE`, `French`, `Français` | `fr` |
|
|
276
|
+
| `DE`, `GER`, `German`, `Deutsch` | `de` |
|
|
277
|
+
| `ZH-TW`, `CHT`, `繁體中文` | `zh-TW` |
|
|
278
|
+
| `ZH-CN`, `CHS`, `简体中文` | `zh-CN` |
|
|
279
|
+
| `JA`, `JPN`, `Japanese`, `日本語` | `ja` |
|
|
280
|
+
| … and many more | |
|
|
281
|
+
|
|
282
|
+
### Custom key map via the spreadsheet
|
|
283
|
+
|
|
284
|
+
Add a tab named `_keymap` to your spreadsheet to define project-specific mappings:
|
|
285
|
+
|
|
286
|
+
```
|
|
287
|
+
┌──────────────┬───────┬──────┬───────┐
|
|
288
|
+
│ (ignored) │ fr │ en │ pt-BR │
|
|
289
|
+
├──────────────┼───────┼──────┼───────┤
|
|
290
|
+
│ Français │ fr │ │ │
|
|
291
|
+
│ Anglais │ │ en │ │
|
|
292
|
+
│ Brésilien │ │ │ pt-BR │
|
|
293
|
+
└──────────────┴───────┴──────┴───────┘
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Custom key map via CLI or API
|
|
297
|
+
|
|
298
|
+
Pass a JSON file to the CLI:
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
gsheets-i18n sheet --sheet-id … --key-map ./my-key-map.json
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Or pass an object to the API:
|
|
305
|
+
|
|
306
|
+
```ts
|
|
307
|
+
await extract({
|
|
308
|
+
// …
|
|
309
|
+
localeKeyMap: {
|
|
310
|
+
"Français": "fr",
|
|
311
|
+
"Anglais": "en",
|
|
312
|
+
"Brésilien": "pt-BR",
|
|
313
|
+
},
|
|
314
|
+
});
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
**Priority (highest → lowest):**
|
|
318
|
+
1. `_keymap` tab in the spreadsheet
|
|
319
|
+
2. `localeKeyMap` option / `--key-map` file
|
|
320
|
+
3. Built-in defaults
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## Folder Mode
|
|
325
|
+
|
|
326
|
+
In folder mode, the library recursively scans a Google Drive folder:
|
|
327
|
+
|
|
328
|
+
- Each **sub-folder** name becomes a path component of the namespace
|
|
329
|
+
- Each **spreadsheet** name becomes the innermost namespace component
|
|
330
|
+
- Files and folders starting with `_` are **skipped**
|
|
331
|
+
- A spreadsheet named `_keymap` in any folder applies its mappings to everything inside that folder
|
|
332
|
+
|
|
333
|
+
**Example Drive structure:**
|
|
334
|
+
|
|
335
|
+
```
|
|
336
|
+
📁 my-translations/
|
|
337
|
+
├── 📁 app/
|
|
338
|
+
│ ├── 📄 actions ← spreadsheet
|
|
339
|
+
│ └── 📄 errors ← spreadsheet
|
|
340
|
+
└── 📄 common ← spreadsheet
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Produces keys structured as:
|
|
344
|
+
|
|
345
|
+
```json
|
|
346
|
+
{
|
|
347
|
+
"app": {
|
|
348
|
+
"actions": { "save": "…" },
|
|
349
|
+
"errors": { "404": "…" }
|
|
350
|
+
},
|
|
351
|
+
"common": { "yes": "…" }
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## Configuration Reference
|
|
358
|
+
|
|
359
|
+
### `extract(options)` — full options
|
|
360
|
+
|
|
361
|
+
| Option | Type | Default | Description |
|
|
362
|
+
|---------------------|-----------------------------|--------------------------|-------------|
|
|
363
|
+
| `serviceAccountKey` | `string \| ServiceAccountKey` | *(required)* | Path to key file or parsed key object |
|
|
364
|
+
| `source` | `SheetModeOptions \| FolderModeOptions` | *(required)* | What to extract |
|
|
365
|
+
| `outputDir` | `string` | `"./i18n"` | Directory for output files |
|
|
366
|
+
| `localeKeyMap` | `Record<string, string>` | `{}` | Custom header → locale mappings |
|
|
367
|
+
| `includeEmpty` | `boolean` | `false` | Write keys with empty values |
|
|
368
|
+
| `indent` | `number \| string` | `2` | JSON indentation (`2`, `4`, `"\t"`) |
|
|
369
|
+
|
|
370
|
+
### `SheetModeOptions`
|
|
371
|
+
|
|
372
|
+
| Option | Type | Default | Description |
|
|
373
|
+
|-----------------|----------|---------|-------------|
|
|
374
|
+
| `mode` | `"sheet"` | *(required)* | |
|
|
375
|
+
| `spreadsheetId` | `string` | *(required)* | Google Spreadsheet ID |
|
|
376
|
+
| `tabId` | `number` | all tabs | Specific tab to extract |
|
|
377
|
+
| `startColumn` | `number` | `0` | Skip leading columns |
|
|
378
|
+
|
|
379
|
+
### `FolderModeOptions`
|
|
380
|
+
|
|
381
|
+
| Option | Type | Default | Description |
|
|
382
|
+
|------------|-----------|---------|-------------|
|
|
383
|
+
| `mode` | `"folder"` | *(required)* | |
|
|
384
|
+
| `folderId` | `string` | *(required)* | Google Drive folder ID |
|
|
385
|
+
|
|
386
|
+
### CLI flags — `sheet` command
|
|
387
|
+
|
|
388
|
+
| Flag | Default | Description |
|
|
389
|
+
|---------------------------|--------------------------|-------------|
|
|
390
|
+
| `-s, --sheet-id <id>` | *(required)* | Spreadsheet ID |
|
|
391
|
+
| `-k, --key <path>` | `./service-account.json` | Key file path |
|
|
392
|
+
| `-o, --out <path>` | `./i18n` | Output directory |
|
|
393
|
+
| `-t, --tab-id <id>` | all tabs | Numeric tab ID |
|
|
394
|
+
| `--start-column <n>` | `0` | Skip leading columns |
|
|
395
|
+
| `--include-empty` | `false` | Include empty values |
|
|
396
|
+
| `--indent <n\|"tab">` | `2` | JSON indentation |
|
|
397
|
+
| `--key-map <path>` | — | Custom key map JSON |
|
|
398
|
+
|
|
399
|
+
### CLI flags — `folder` command
|
|
400
|
+
|
|
401
|
+
| Flag | Default | Description |
|
|
402
|
+
|-----------------------|--------------------------|-------------|
|
|
403
|
+
| `-f, --folder-id <id>` | *(required)* | Drive folder ID |
|
|
404
|
+
| `-k, --key <path>` | `./service-account.json` | Key file path |
|
|
405
|
+
| `-o, --out <path>` | `./i18n` | Output directory |
|
|
406
|
+
| `--include-empty` | `false` | Include empty values |
|
|
407
|
+
| `--indent <n\|"tab">` | `2` | JSON indentation |
|
|
408
|
+
| `--key-map <path>` | — | Custom key map JSON |
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## License
|
|
413
|
+
|
|
414
|
+
MIT
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const index_js_1 = require("../index.js");
|
|
6
|
+
const promises_1 = require("node:fs/promises");
|
|
7
|
+
const node_path_1 = require("node:path");
|
|
8
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
9
|
+
function parseIndent(value) {
|
|
10
|
+
if (value === "tab" || value === "\t")
|
|
11
|
+
return "\t";
|
|
12
|
+
const num = Number(value);
|
|
13
|
+
if (!Number.isNaN(num) && num >= 0 && num <= 8)
|
|
14
|
+
return num;
|
|
15
|
+
throw new Error(`Invalid indent value: "${value}". Use a number 0–8 or "tab".`);
|
|
16
|
+
}
|
|
17
|
+
function fatal(message) {
|
|
18
|
+
console.error(`\n ✖ ${message}\n`);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
// ─── CLI definition ───────────────────────────────────────────────────────────
|
|
22
|
+
const program = new commander_1.Command();
|
|
23
|
+
program
|
|
24
|
+
.name("sheets-i18n")
|
|
25
|
+
.description("Generate i18n JSON files from a Google Spreadsheet or Drive folder.")
|
|
26
|
+
.version("1.0.0");
|
|
27
|
+
// ── sheet command ─────────────────────────────────────────────────────────────
|
|
28
|
+
program
|
|
29
|
+
.command("sheet")
|
|
30
|
+
.description("Extract from a single Google Spreadsheet")
|
|
31
|
+
.requiredOption("-s, --sheet-id <spreadsheetId>", "Google Spreadsheet ID (from the URL)")
|
|
32
|
+
.requiredOption("-k, --key <path>", "Path to the Service Account JSON key file", "./service-account.json")
|
|
33
|
+
.option("-o, --out <path>", "Output directory for the generated JSON files", "./i18n")
|
|
34
|
+
.option("-t, --tab-id <id>", "Numeric tab ID to extract (default: all tabs)")
|
|
35
|
+
.option("--start-column <n>", "Zero-based column index to start reading from", "0")
|
|
36
|
+
.option("--include-empty", "Include keys with empty values in the output", false)
|
|
37
|
+
.option("--indent <value>", 'JSON indentation: a number of spaces or "tab"', "2")
|
|
38
|
+
.option("--key-map <path>", "Path to a JSON file with custom locale key mappings")
|
|
39
|
+
.action(async (opts) => {
|
|
40
|
+
let localeKeyMap;
|
|
41
|
+
if (opts.keyMap) {
|
|
42
|
+
try {
|
|
43
|
+
const raw = await (0, promises_1.readFile)((0, node_path_1.resolve)(process.cwd(), opts.keyMap), "utf-8");
|
|
44
|
+
localeKeyMap = JSON.parse(raw);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
fatal(`Could not read key map file: ${opts.keyMap}`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
console.log("\n ⏳ Extracting translations…\n");
|
|
52
|
+
try {
|
|
53
|
+
const result = await (0, index_js_1.extract)({
|
|
54
|
+
serviceAccountKey: opts.key,
|
|
55
|
+
source: {
|
|
56
|
+
mode: "sheet",
|
|
57
|
+
spreadsheetId: opts.sheetId,
|
|
58
|
+
tabId: opts.tabId !== undefined ? Number(opts.tabId) : undefined,
|
|
59
|
+
startColumn: Number(opts.startColumn),
|
|
60
|
+
},
|
|
61
|
+
outputDir: opts.out,
|
|
62
|
+
localeKeyMap,
|
|
63
|
+
includeEmpty: opts.includeEmpty,
|
|
64
|
+
indent: parseIndent(opts.indent),
|
|
65
|
+
});
|
|
66
|
+
console.log(` ✔ Done in ${(result.durationMs / 1000).toFixed(2)}s\n`);
|
|
67
|
+
console.log(` 📂 ${(0, node_path_1.resolve)(process.cwd(), opts.out)}\n`);
|
|
68
|
+
for (const file of result.files) {
|
|
69
|
+
console.log(` ${file.locale}.json (${file.keyCount} top-level keys)`);
|
|
70
|
+
}
|
|
71
|
+
console.log();
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
fatal(err instanceof Error ? err.message : String(err));
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
// ── folder command ────────────────────────────────────────────────────────────
|
|
78
|
+
program
|
|
79
|
+
.command("folder")
|
|
80
|
+
.description("Extract from all spreadsheets inside a Google Drive folder")
|
|
81
|
+
.requiredOption("-f, --folder-id <folderId>", "Google Drive folder ID (from the URL)")
|
|
82
|
+
.requiredOption("-k, --key <path>", "Path to the Service Account JSON key file", "./service-account.json")
|
|
83
|
+
.option("-o, --out <path>", "Output directory for the generated JSON files", "./i18n")
|
|
84
|
+
.option("--include-empty", "Include keys with empty values in the output", false)
|
|
85
|
+
.option("--indent <value>", 'JSON indentation: a number of spaces or "tab"', "2")
|
|
86
|
+
.option("--key-map <path>", "Path to a JSON file with custom locale key mappings")
|
|
87
|
+
.action(async (opts) => {
|
|
88
|
+
let localeKeyMap;
|
|
89
|
+
if (opts.keyMap) {
|
|
90
|
+
try {
|
|
91
|
+
const raw = await (0, promises_1.readFile)((0, node_path_1.resolve)(process.cwd(), opts.keyMap), "utf-8");
|
|
92
|
+
localeKeyMap = JSON.parse(raw);
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
fatal(`Could not read key map file: ${opts.keyMap}`);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
console.log("\n ⏳ Extracting translations…\n");
|
|
100
|
+
try {
|
|
101
|
+
const result = await (0, index_js_1.extract)({
|
|
102
|
+
serviceAccountKey: opts.key,
|
|
103
|
+
source: {
|
|
104
|
+
mode: "folder",
|
|
105
|
+
folderId: opts.folderId,
|
|
106
|
+
},
|
|
107
|
+
outputDir: opts.out,
|
|
108
|
+
localeKeyMap,
|
|
109
|
+
includeEmpty: opts.includeEmpty,
|
|
110
|
+
indent: parseIndent(opts.indent),
|
|
111
|
+
});
|
|
112
|
+
console.log(` ✔ Done in ${(result.durationMs / 1000).toFixed(2)}s\n`);
|
|
113
|
+
console.log(` 📂 ${(0, node_path_1.resolve)(process.cwd(), opts.out)}\n`);
|
|
114
|
+
for (const file of result.files) {
|
|
115
|
+
console.log(` ${file.locale}.json (${file.keyCount} top-level keys)`);
|
|
116
|
+
}
|
|
117
|
+
console.log();
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
fatal(err instanceof Error ? err.message : String(err));
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
// ─── Parse ────────────────────────────────────────────────────────────────────
|
|
124
|
+
program.parse();
|
|
125
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":";;;AACA,yCAAoC;AACpC,0CAAsC;AACtC,+CAA4C;AAC5C,yCAAoC;AAEpC,iFAAiF;AAEjF,SAAS,WAAW,CAAC,KAAa;IAChC,IAAI,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACnD,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC1B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC;IAC3D,MAAM,IAAI,KAAK,CAAC,0BAA0B,KAAK,+BAA+B,CAAC,CAAC;AAClF,CAAC;AAED,SAAS,KAAK,CAAC,OAAe;IAC5B,OAAO,CAAC,KAAK,CAAC,UAAU,OAAO,IAAI,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,iFAAiF;AAEjF,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,aAAa,CAAC;KACnB,WAAW,CACV,qEAAqE,CACtE;KACA,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,iFAAiF;AACjF,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,0CAA0C,CAAC;KACvD,cAAc,CACb,gCAAgC,EAChC,sCAAsC,CACvC;KACA,cAAc,CACb,kBAAkB,EAClB,2CAA2C,EAC3C,wBAAwB,CACzB;KACA,MAAM,CACL,kBAAkB,EAClB,+CAA+C,EAC/C,QAAQ,CACT;KACA,MAAM,CACL,mBAAmB,EACnB,+CAA+C,CAChD;KACA,MAAM,CACL,oBAAoB,EACpB,+CAA+C,EAC/C,GAAG,CACJ;KACA,MAAM,CACL,iBAAiB,EACjB,8CAA8C,EAC9C,KAAK,CACN;KACA,MAAM,CACL,kBAAkB,EAClB,+CAA+C,EAC/C,GAAG,CACJ;KACA,MAAM,CACL,kBAAkB,EAClB,qDAAqD,CACtD;KACA,MAAM,CAAC,KAAK,EAAE,IASd,EAAE,EAAE;IACH,IAAI,YAAgD,CAAC;IAErD,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,IAAA,mBAAQ,EAAC,IAAA,mBAAO,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;YACzE,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA2B,CAAC;QAC3D,CAAC;QAAC,MAAM,CAAC;YACP,KAAK,CAAC,gCAAgC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YACrD,OAAO;QACT,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IAEjD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,IAAA,kBAAO,EAAC;YAC3B,iBAAiB,EAAE,IAAI,CAAC,GAAG;YAC3B,MAAM,EAAE;gBACN,IAAI,EAAE,OAAO;gBACb,aAAa,EAAE,IAAI,CAAC,OAAO;gBAC3B,KAAK,EAAE,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS;gBAChE,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC;aACtC;YACD,SAAS,EAAE,IAAI,CAAC,GAAG;YACnB,YAAY;YACZ,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,MAAM,EAAE,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC;SACjC,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACxE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAA,mBAAO,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC3D,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YAChC,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,MAAM,WAAW,IAAI,CAAC,QAAQ,kBAAkB,CAAC,CAAC;QAC9E,CAAC;QACD,OAAO,CAAC,GAAG,EAAE,CAAC;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,iFAAiF;AACjF,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,4DAA4D,CAAC;KACzE,cAAc,CACb,4BAA4B,EAC5B,uCAAuC,CACxC;KACA,cAAc,CACb,kBAAkB,EAClB,2CAA2C,EAC3C,wBAAwB,CACzB;KACA,MAAM,CACL,kBAAkB,EAClB,+CAA+C,EAC/C,QAAQ,CACT;KACA,MAAM,CACL,iBAAiB,EACjB,8CAA8C,EAC9C,KAAK,CACN;KACA,MAAM,CACL,kBAAkB,EAClB,+CAA+C,EAC/C,GAAG,CACJ;KACA,MAAM,CACL,kBAAkB,EAClB,qDAAqD,CACtD;KACA,MAAM,CAAC,KAAK,EAAE,IAOd,EAAE,EAAE;IACH,IAAI,YAAgD,CAAC;IAErD,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,IAAA,mBAAQ,EAAC,IAAA,mBAAO,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;YACzE,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA2B,CAAC;QAC3D,CAAC;QAAC,MAAM,CAAC;YACP,KAAK,CAAC,gCAAgC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YACrD,OAAO;QACT,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IAEjD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,IAAA,kBAAO,EAAC;YAC3B,iBAAiB,EAAE,IAAI,CAAC,GAAG;YAC3B,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,IAAI,CAAC,QAAQ;aACxB;YACD,SAAS,EAAE,IAAI,CAAC,GAAG;YACnB,YAAY;YACZ,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,MAAM,EAAE,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC;SACjC,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACxE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAA,mBAAO,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC3D,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YAChC,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,MAAM,WAAW,IAAI,CAAC,QAAQ,kBAAkB,CAAC,CAAC;QAC9E,CAAC;QACD,OAAO,CAAC,GAAG,EAAE,CAAC;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,iFAAiF;AACjF,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extract = extract;
|
|
4
|
+
const auth_js_1 = require("./lib/auth.js");
|
|
5
|
+
const sheetExtractor_js_1 = require("./lib/sheetExtractor.js");
|
|
6
|
+
const folderExtractor_js_1 = require("./lib/folderExtractor.js");
|
|
7
|
+
const writer_js_1 = require("./lib/writer.js");
|
|
8
|
+
/**
|
|
9
|
+
* Extracts translations from Google Sheets and writes one JSON file per locale.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { extract } from "sheets-i18n";
|
|
14
|
+
*
|
|
15
|
+
* await extract({
|
|
16
|
+
* serviceAccountKey: "./service-account.json",
|
|
17
|
+
* source: {
|
|
18
|
+
* mode: "sheet",
|
|
19
|
+
* spreadsheetId: "4BxiM********upms",
|
|
20
|
+
* },
|
|
21
|
+
* outputDir: "./src/locales",
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
async function extract(options) {
|
|
26
|
+
const startTime = Date.now();
|
|
27
|
+
const { serviceAccountKey, source, outputDir = "./i18n", localeKeyMap, includeEmpty = false, indent = 2, } = options;
|
|
28
|
+
// 1. Authenticate
|
|
29
|
+
const auth = await (0, auth_js_1.createAuthClient)(serviceAccountKey);
|
|
30
|
+
// 2. Extract translations
|
|
31
|
+
let translations;
|
|
32
|
+
if (source.mode === "sheet") {
|
|
33
|
+
translations = await (0, sheetExtractor_js_1.extractFromSheet)({
|
|
34
|
+
auth,
|
|
35
|
+
spreadsheetId: source.spreadsheetId,
|
|
36
|
+
tabId: source.tabId,
|
|
37
|
+
startColumn: source.startColumn,
|
|
38
|
+
includeEmpty,
|
|
39
|
+
userKeyMap: localeKeyMap,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
translations = await (0, folderExtractor_js_1.extractFromFolder)({
|
|
44
|
+
auth,
|
|
45
|
+
folderId: source.folderId,
|
|
46
|
+
includeEmpty,
|
|
47
|
+
userKeyMap: localeKeyMap,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
// 3. Write files
|
|
51
|
+
const files = await (0, writer_js_1.writeTranslationFiles)(translations, outputDir, indent);
|
|
52
|
+
return {
|
|
53
|
+
files,
|
|
54
|
+
durationMs: Date.now() - startTime,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;AAoCA,0BA2CC;AA/ED,2CAAiD;AACjD,+DAA2D;AAC3D,iEAA6D;AAC7D,+CAAwD;AAgBxD;;;;;;;;;;;;;;;;GAgBG;AACI,KAAK,UAAU,OAAO,CAAC,OAAuB;IACnD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,MAAM,EACJ,iBAAiB,EACjB,MAAM,EACN,SAAS,GAAG,QAAQ,EACpB,YAAY,EACZ,YAAY,GAAG,KAAK,EACpB,MAAM,GAAG,CAAC,GACX,GAAG,OAAO,CAAC;IAEZ,kBAAkB;IAClB,MAAM,IAAI,GAAG,MAAM,IAAA,0BAAgB,EAAC,iBAAiB,CAAC,CAAC;IAEvD,0BAA0B;IAC1B,IAAI,YAAY,CAAC;IAEjB,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC5B,YAAY,GAAG,MAAM,IAAA,oCAAgB,EAAC;YACpC,IAAI;YACJ,aAAa,EAAE,MAAM,CAAC,aAAa;YACnC,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,YAAY;YACZ,UAAU,EAAE,YAAY;SACzB,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,YAAY,GAAG,MAAM,IAAA,sCAAiB,EAAC;YACrC,IAAI;YACJ,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,YAAY;YACZ,UAAU,EAAE,YAAY;SACzB,CAAC,CAAC;IACL,CAAC;IAED,iBAAiB;IACjB,MAAM,KAAK,GAAG,MAAM,IAAA,iCAAqB,EAAC,YAAY,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;IAE3E,OAAO;QACL,KAAK;QACL,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;KACnC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createAuthClient = createAuthClient;
|
|
4
|
+
const googleapis_1 = require("googleapis");
|
|
5
|
+
const promises_1 = require("node:fs/promises");
|
|
6
|
+
const node_path_1 = require("node:path");
|
|
7
|
+
const SCOPES = [
|
|
8
|
+
"https://www.googleapis.com/auth/spreadsheets.readonly",
|
|
9
|
+
"https://www.googleapis.com/auth/drive.readonly",
|
|
10
|
+
];
|
|
11
|
+
/**
|
|
12
|
+
* Builds an authenticated Google JWT client from a Service Account key.
|
|
13
|
+
*
|
|
14
|
+
* @param keySource - Either a file-system path to the key JSON, or the parsed object.
|
|
15
|
+
*/
|
|
16
|
+
async function createAuthClient(keySource) {
|
|
17
|
+
let key;
|
|
18
|
+
if (typeof keySource === "string") {
|
|
19
|
+
const absolutePath = (0, node_path_1.resolve)(process.cwd(), keySource);
|
|
20
|
+
const raw = await (0, promises_1.readFile)(absolutePath, "utf-8");
|
|
21
|
+
key = JSON.parse(raw);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
key = keySource;
|
|
25
|
+
}
|
|
26
|
+
const client = new googleapis_1.google.auth.JWT({
|
|
27
|
+
email: key.client_email,
|
|
28
|
+
key: key.private_key,
|
|
29
|
+
scopes: SCOPES,
|
|
30
|
+
});
|
|
31
|
+
await client.authorize();
|
|
32
|
+
return client;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/lib/auth.ts"],"names":[],"mappings":";;AAeA,4CAqBC;AApCD,2CAAoC;AACpC,+CAA4C;AAC5C,yCAAoC;AAGpC,MAAM,MAAM,GAAG;IACb,uDAAuD;IACvD,gDAAgD;CACjD,CAAC;AAEF;;;;GAIG;AACI,KAAK,UAAU,gBAAgB,CACpC,SAAqC;IAErC,IAAI,GAAsB,CAAC;IAE3B,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE,CAAC;QAClC,MAAM,YAAY,GAAG,IAAA,mBAAO,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,CAAC,CAAC;QACvD,MAAM,GAAG,GAAG,MAAM,IAAA,mBAAQ,EAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QAClD,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAsB,CAAC;IAC7C,CAAC;SAAM,CAAC;QACN,GAAG,GAAG,SAAS,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,mBAAM,CAAC,IAAI,CAAC,GAAG,CAAC;QACjC,KAAK,EAAE,GAAG,CAAC,YAAY;QACvB,GAAG,EAAE,GAAG,CAAC,WAAW;QACpB,MAAM,EAAE,MAAM;KACf,CAAC,CAAC;IAEH,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC;IACzB,OAAO,MAAM,CAAC;AAChB,CAAC"}
|