langctl 0.1.2 → 0.3.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.
Files changed (63) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/LICENSE +1 -1
  3. package/README.md +159 -1151
  4. package/dist/commands/auth.js +82 -24
  5. package/dist/commands/config.js +36 -25
  6. package/dist/commands/export.js +11 -112
  7. package/dist/commands/import.js +32 -164
  8. package/dist/commands/init.js +59 -80
  9. package/dist/commands/keys.js +145 -381
  10. package/dist/commands/org.js +45 -140
  11. package/dist/commands/projects.js +125 -390
  12. package/dist/commands/pull.js +78 -183
  13. package/dist/commands/push.js +125 -0
  14. package/dist/commands/team.js +68 -272
  15. package/dist/core/config.js +130 -0
  16. package/dist/core/errors.js +67 -0
  17. package/dist/core/files.js +38 -0
  18. package/dist/core/http.js +121 -0
  19. package/dist/core/output.js +96 -0
  20. package/dist/core/project.js +58 -0
  21. package/dist/core/prompts.js +56 -0
  22. package/dist/formats/index.js +285 -0
  23. package/dist/index.js +261 -508
  24. package/dist/version.js +4 -0
  25. package/package.json +22 -16
  26. package/.gitattributes +0 -2
  27. package/NEXT_PHASE.md +0 -618
  28. package/WORKING_INSTRUCTIONS.md +0 -1389
  29. package/dist/auth.d.ts +0 -37
  30. package/dist/auth.js +0 -112
  31. package/dist/commands/auth.d.ts +0 -3
  32. package/dist/commands/config.d.ts +0 -2
  33. package/dist/commands/debug.d.ts +0 -3
  34. package/dist/commands/debug.js +0 -57
  35. package/dist/commands/export.d.ts +0 -14
  36. package/dist/commands/import.d.ts +0 -11
  37. package/dist/commands/init.d.ts +0 -2
  38. package/dist/commands/keys.d.ts +0 -25
  39. package/dist/commands/org.d.ts +0 -13
  40. package/dist/commands/projects.d.ts +0 -30
  41. package/dist/commands/pull.d.ts +0 -9
  42. package/dist/commands/team.d.ts +0 -29
  43. package/dist/config.d.ts +0 -47
  44. package/dist/config.js +0 -69
  45. package/dist/exporters/index.d.ts +0 -36
  46. package/dist/exporters/index.js +0 -214
  47. package/dist/index.d.ts +0 -3
  48. package/dist/supabase.d.ts +0 -14
  49. package/dist/supabase.js +0 -30
  50. package/dist/utils/banner.d.ts +0 -9
  51. package/dist/utils/banner.js +0 -24
  52. package/translations/en.json +0 -5
  53. package/translations/en.xml +0 -9
  54. package/translations/fr.json +0 -4
  55. package/translations/fr.xml +0 -7
  56. package/translations/hi.json +0 -4
  57. package/translations/hi.xml +0 -7
  58. package/translations/ios/en.strings +0 -9
  59. package/translations/ios/fr.strings +0 -6
  60. package/translations/ios/hi.strings +0 -6
  61. package/translations/ios/ja.strings +0 -6
  62. package/translations/ja.json +0 -4
  63. package/translations/ja.xml +0 -7
package/README.md CHANGED
@@ -1,1191 +1,199 @@
1
- # Langctl CLI
1
+ <div align="center">
2
2
 
3
- > CLI-first translation management for developers
3
+ # langctl
4
4
 
5
- Langctl is a powerful command-line tool that lets you manage translations directly from your terminal. Create projects, manage translation keys, invite team members, export in multiple formats, and integrate seamlessly into your CI/CD pipeline.
5
+ **Translation management from your terminal and CI**
6
6
 
7
- ## Features
7
+ [![npm version](https://img.shields.io/npm/v/langctl.svg)](https://www.npmjs.com/package/langctl)
8
+ [![CI](https://github.com/litcode-pvt-ltd/langctl-cli/actions/workflows/ci.yml/badge.svg)](https://github.com/litcode-pvt-ltd/langctl-cli/actions/workflows/ci.yml)
9
+ [![license](https://img.shields.io/npm/l/langctl.svg)](LICENSE)
8
10
 
9
- - 🚀 **Complete Project Management** - Create, update, and manage translation projects
10
- - 🔑 **Translation Key CRUD** - Full control over translation keys and values
11
- - 👥 **Team Management** - Invite members, manage roles, and handle invitations
12
- - 📊 **Organization Insights** - View stats, plan limits, and usage metrics
13
- - 📦 **Multi-Format Export** - Support for JSON, iOS, Android, Flutter, and i18n
14
- - 🔄 **Import Translations** - Bulk import from JSON files
15
- - 🤖 **CI/CD Ready** - Perfect for automated workflows
16
- - 🌍 **Multi-Language Support** - Manage unlimited languages per project
11
+ [Website](https://langctl.com) · [Docs](https://langctl.com/docs) · [Sign up](https://app.langctl.com/signup)
17
12
 
18
- ## Installation
13
+ </div>
19
14
 
20
- ```bash
21
- npm install -g langctl
22
- ```
23
-
24
- Or use with npx (no installation required):
25
-
26
- ```bash
27
- npx langctl --help
28
- ```
29
-
30
- ## Quick Start
31
-
32
- ### 1. Get Your API Key
33
-
34
- 1. Visit [app.langctl.com](https://app.langctl.com) and sign in
35
- 2. Go to **Settings → API Keys**
36
- 3. Click **"Generate New Key"**
37
- 4. Copy the key (it's only shown once!)
38
-
39
- ### 2. Authenticate
40
-
41
- ```bash
42
- # Interactive setup
43
- langctl init
44
-
45
- # Or authenticate directly
46
- langctl auth lc_your_api_key_here
47
- ```
48
-
49
- ### 3. Explore Your Organization
50
-
51
- ```bash
52
- # View organization info
53
- langctl org info
54
-
55
- # Check statistics
56
- langctl org stats
57
-
58
- # List your projects
59
- langctl projects list
60
- ```
61
-
62
- ### 4. Start Working with Translations
63
-
64
- ```bash
65
- # List translation keys
66
- langctl keys list my-project
67
-
68
- # Export translations
69
- langctl export my-project --language en --format json
70
-
71
- # Create a new key
72
- langctl keys create my-project home.welcome \
73
- --value-en "Welcome!" \
74
- --value-es "¡Bienvenido!"
75
- ```
76
-
77
- ---
78
-
79
- ## Commands Overview
80
-
81
- ### Authentication
82
- - `langctl init` - Interactive setup wizard
83
- - `langctl auth <api-key>` - Authenticate with API key
84
- - `langctl logout` - Clear credentials
85
- - `langctl config` - View current configuration
86
-
87
- ### Organization
88
- - `langctl org info` - View organization details
89
- - `langctl org stats` - View organization statistics
90
- - `langctl org plan` - View subscription plan and limits
91
-
92
- ### Projects
93
- - `langctl projects list` - List all projects
94
- - `langctl projects create <name>` - Create new project
95
- - `langctl projects get <slug>` - Get project details
96
- - `langctl projects update <slug>` - Update project
97
- - `langctl projects delete <slug>` - Delete project
98
- - `langctl projects add-language <slug> <language>` - Add language
99
- - `langctl projects remove-language <slug> <language>` - Remove language
100
- - `langctl projects stats <slug>` - View project statistics
101
-
102
- ### Translation Keys
103
- - `langctl keys list <project>` - List translation keys
104
- - `langctl keys get <project> <key>` - Get key details
105
- - `langctl keys create <project> <key>` - Create new key
106
- - `langctl keys delete <project> <key>` - Delete key
107
- - `langctl keys translate <project> <key>` - Update translation
108
- - `langctl keys publish <project> <keys...>` - Publish/unpublish keys
109
-
110
- ### Team
111
- - `langctl team list` - List team members
112
- - `langctl team get <email>` - Get member details
113
- - `langctl team invite <email>` - Invite team member
114
- - `langctl team remove <email>` - Remove team member
115
- - `langctl team update-role <email> <role>` - Update member role
116
- - `langctl team invitations` - List invitations
117
- - `langctl team revoke-invitation <email>` - Revoke invitation
118
-
119
- ### Import/Export
120
- - `langctl export <project>` - Export translations
121
- - `langctl import <project> <file>` - Import translations
122
-
123
- ---
124
-
125
- ## Detailed Command Reference
126
-
127
- ### Authentication Commands
128
-
129
- #### `langctl init`
130
-
131
- Interactive setup wizard that guides you through authentication and configuration.
132
-
133
- ```bash
134
- langctl init
135
- ```
136
-
137
- #### `langctl auth <api-key>`
138
-
139
- Authenticate with an API key from your dashboard.
140
-
141
- ```bash
142
- langctl auth lc_abc123...
143
- ```
144
-
145
- #### `langctl logout`
146
-
147
- Clear stored authentication credentials.
148
-
149
- ```bash
150
- langctl logout
151
- ```
152
-
153
- #### `langctl config`
154
-
155
- Display current configuration (API key, organization, etc.).
156
-
157
- ```bash
158
- langctl config
159
- ```
160
-
161
- ---
162
-
163
- ### Organization Commands
164
-
165
- #### `langctl org info`
166
-
167
- View your organization details.
168
-
169
- ```bash
170
- langctl org info
171
- ```
172
-
173
- **Output:**
174
- - Organization name and ID
175
- - Slug
176
- - Subscription plan
177
- - Creation date
178
-
179
- #### `langctl org stats`
180
-
181
- View comprehensive organization statistics.
182
-
183
- ```bash
184
- langctl org stats
185
- ```
186
-
187
- **Output:**
188
- - Total team members
189
- - Number of projects
190
- - Translation key counts (total, published, unpublished)
191
- - Languages used across projects
192
- - API keys and webhooks
193
-
194
- #### `langctl org plan`
195
-
196
- View subscription plan details and resource limits.
197
-
198
- ```bash
199
- langctl org plan
200
- ```
201
-
202
- **Output:**
203
- - Current plan (Free, Pro, Team, Enterprise)
204
- - Max members allowed
205
- - Max projects allowed
206
- - Max keys per project
207
- - Max API keys allowed
208
-
209
- ---
210
-
211
- ### Project Management Commands
212
-
213
- #### `langctl projects list`
214
-
215
- List all projects you have access to.
216
-
217
- ```bash
218
- langctl projects list
219
- ```
220
-
221
- **Output:**
222
- - Project name and slug
223
- - Description
224
- - Supported languages
225
- - Default language
226
- - Available modules
227
-
228
- #### `langctl projects create <name>`
229
-
230
- Create a new translation project.
231
-
232
- ```bash
233
- langctl projects create "Mobile App" \
234
- --description "iOS and Android translations" \
235
- --languages en,es,fr,de \
236
- --default-language en
237
- ```
238
-
239
- **Options:**
240
- - `-d, --description <text>` - Project description
241
- - `-l, --languages <langs>` - Comma-separated language codes (default: `en`)
242
- - `--default-language <code>` - Default language (default: first language)
243
-
244
- **Examples:**
245
-
246
- ```bash
247
- # Simple project with English only
248
- langctl projects create "My App"
249
-
250
- # Multi-language project
251
- langctl projects create "Global App" \
252
- -l en,es,fr,de,ja \
253
- --default-language en
254
-
255
- # With description
256
- langctl projects create "Mobile App" \
257
- -d "Translation keys for mobile application" \
258
- -l en,es
259
- ```
260
-
261
- #### `langctl projects get <slug>`
262
-
263
- Get detailed information about a specific project.
264
-
265
- ```bash
266
- langctl projects get my-app
267
- ```
268
-
269
- **Output:**
270
- - Project name, ID, and slug
271
- - Description
272
- - All supported languages
273
- - Default language
274
- - List of modules
275
-
276
- #### `langctl projects update <slug>`
277
-
278
- Update project details.
279
-
280
- ```bash
281
- langctl projects update my-app \
282
- --name "New Name" \
283
- --description "Updated description" \
284
- --languages en,es,fr,de,ja \
285
- --default-language en
286
- ```
287
-
288
- **Options:**
289
- - `-n, --name <name>` - Update project name
290
- - `-d, --description <text>` - Update description
291
- - `-l, --languages <langs>` - Update supported languages
292
- - `--default-language <code>` - Update default language
293
-
294
- **Examples:**
295
-
296
- ```bash
297
- # Change project name
298
- langctl projects update my-app --name "Better Name"
15
+ `langctl` keeps the translation files in your repository in sync with [Langctl](https://langctl.com):
16
+ **pull** translations into JSON, Android, iOS or Flutter files, **push** new source strings,
17
+ and **check** in CI that committed files are up to date.
299
18
 
300
- # Add more languages
301
- langctl projects update my-app -l en,es,fr,de,ja,zh
302
-
303
- # Update description only
304
- langctl projects update my-app -d "New project description"
305
- ```
306
-
307
- #### `langctl projects delete <slug>`
308
-
309
- Delete a project (soft delete - can be recovered).
310
-
311
- ```bash
312
- langctl projects delete my-app
19
+ ```console
20
+ $ langctl init # once per repo: pick a project, format and path → langctl.json
21
+ $ langctl pull # download translations
22
+ + src/locales/en.json created
23
+ + src/locales/es.json created 41/45 translated
24
+ $ langctl push # upload new strings from your source-language file
25
+ en src/locales/en.json 3 new, 0 updated, 42 unchanged
313
26
  ```
314
27
 
315
- **Warning:** This will mark the project as deleted. Contact support to recover deleted projects.
316
-
317
- #### `langctl projects add-language <slug> <language>`
318
-
319
- Add a new language to an existing project.
28
+ ## Install
320
29
 
321
30
  ```bash
322
- langctl projects add-language my-app de
323
- ```
324
-
325
- **Examples:**
326
-
327
- ```bash
328
- # Add German
329
- langctl projects add-language my-app de
330
-
331
- # Add Japanese
332
- langctl projects add-language my-app ja
333
-
334
- # Add Chinese
335
- langctl projects add-language my-app zh
336
- ```
337
-
338
- #### `langctl projects remove-language <slug> <language>`
339
-
340
- Remove a language from a project.
341
-
342
- ```bash
343
- langctl projects remove-language my-app de
344
- ```
345
-
346
- **Note:** Cannot remove the default language. Change default language first if needed.
347
-
348
- #### `langctl projects stats <slug>`
349
-
350
- View project statistics.
351
-
352
- ```bash
353
- langctl projects stats my-app
354
- ```
355
-
356
- **Output:**
357
- - Total translation keys
358
- - Published vs unpublished counts
359
- - Number of modules
360
- - List of module names
361
-
362
- ---
363
-
364
- ### Translation Key Commands
365
-
366
- #### `langctl keys list <project>`
367
-
368
- List translation keys for a project.
369
-
370
- ```bash
371
- langctl keys list my-app
372
- ```
373
-
374
- **Options:**
375
- - `-m, --module <name>` - Filter by module
376
- - `-p, --published` - Show only published keys
377
- - `-s, --search <term>` - Search in key names
378
- - `--limit <number>` - Limit results (default: 100)
379
- - `--offset <number>` - Offset for pagination (default: 0)
380
-
381
- **Examples:**
382
-
383
- ```bash
384
- # List all keys
385
- langctl keys list my-app
386
-
387
- # Filter by module
388
- langctl keys list my-app --module auth
389
-
390
- # Show only published keys
391
- langctl keys list my-app --published
392
-
393
- # Search for specific keys
394
- langctl keys list my-app --search "welcome"
395
-
396
- # Pagination
397
- langctl keys list my-app --limit 50 --offset 0
398
- langctl keys list my-app --limit 50 --offset 50
399
- ```
400
-
401
- #### `langctl keys get <project> <key>`
402
-
403
- Get detailed information about a specific translation key.
404
-
405
- ```bash
406
- langctl keys get my-app home.welcome
407
- ```
408
-
409
- **Output:**
410
- - Key name and ID
411
- - Description
412
- - Module
413
- - Published status
414
- - All translations for all languages
415
-
416
- #### `langctl keys create <project> <key>`
417
-
418
- Create a new translation key with values for multiple languages.
419
-
420
- ```bash
421
- langctl keys create my-app home.welcome \
422
- --description "Welcome message on homepage" \
423
- --module home \
424
- --value-en "Welcome to our app!" \
425
- --value-es "¡Bienvenido a nuestra aplicación!" \
426
- --value-fr "Bienvenue dans notre application!" \
427
- --value-de "Willkommen in unserer App!"
428
- ```
429
-
430
- **Options:**
431
- - `-d, --description <text>` - Key description
432
- - `-m, --module <name>` - Module/namespace for organization
433
- - `--value-en <value>` - English translation
434
- - `--value-es <value>` - Spanish translation
435
- - `--value-fr <value>` - French translation
436
- - `--value-de <value>` - German translation
437
- - `--tags <tags>` - Comma-separated tags
438
-
439
- **Supported language options:**
440
- You can use `--value-{language}` for any language code in your project.
441
-
442
- **Examples:**
443
-
444
- ```bash
445
- # Simple key with one language
446
- langctl keys create my-app button.submit --value-en "Submit"
447
-
448
- # Multi-language key
449
- langctl keys create my-app home.title \
450
- --module home \
451
- --value-en "Home" \
452
- --value-es "Inicio" \
453
- --value-fr "Accueil"
454
-
455
- # With description and tags
456
- langctl keys create my-app error.network \
457
- --description "Network connection error" \
458
- --module errors \
459
- --value-en "Network error occurred" \
460
- --tags error,network
461
- ```
462
-
463
- #### `langctl keys delete <project> <key>`
464
-
465
- Delete a translation key.
466
-
467
- ```bash
468
- langctl keys delete my-app home.welcome
469
- ```
470
-
471
- #### `langctl keys translate <project> <key>`
472
-
473
- Update the translation value for a specific language.
474
-
475
- ```bash
476
- langctl keys translate my-app home.welcome \
477
- --language es \
478
- --value "¡Bienvenido!"
479
- ```
480
-
481
- **Options:**
482
- - `-l, --language <code>` - Language code (required)
483
- - `-v, --value <text>` - Translation value (required)
484
-
485
- **Examples:**
486
-
487
- ```bash
488
- # Update Spanish translation
489
- langctl keys translate my-app home.title -l es -v "Inicio"
490
-
491
- # Update French translation
492
- langctl keys translate my-app button.submit -l fr -v "Soumettre"
493
-
494
- # Add translation for new language
495
- langctl keys translate my-app home.welcome -l de -v "Willkommen"
496
- ```
497
-
498
- #### `langctl keys publish <project> <keys...>`
499
-
500
- Publish or unpublish translation keys.
501
-
502
- ```bash
503
- # Publish keys
504
- langctl keys publish my-app home.welcome home.title button.submit
505
-
506
- # Unpublish keys
507
- langctl keys publish my-app home.welcome --unpublish
508
- ```
509
-
510
- **Options:**
511
- - `--unpublish` - Unpublish instead of publish
512
-
513
- **Examples:**
514
-
515
- ```bash
516
- # Publish single key
517
- langctl keys publish my-app home.welcome
518
-
519
- # Publish multiple keys
520
- langctl keys publish my-app home.welcome home.title home.subtitle
521
-
522
- # Unpublish keys
523
- langctl keys publish my-app test.key --unpublish
524
- ```
525
-
526
- ---
527
-
528
- ### Team Management Commands
529
-
530
- #### `langctl team list`
531
-
532
- List all team members in your organization.
533
-
534
- ```bash
535
- langctl team list
536
- ```
537
-
538
- **Output:**
539
- - Member email
540
- - Role (viewer, member, admin, owner)
541
- - Join date
542
-
543
- #### `langctl team get <email>`
544
-
545
- Get details about a specific team member.
546
-
547
- ```bash
548
- langctl team get user@example.com
549
- ```
550
-
551
- #### `langctl team invite <email>`
552
-
553
- Invite a new team member.
554
-
555
- ```bash
556
- langctl team invite user@example.com --role member
557
- ```
558
-
559
- **Options:**
560
- - `-r, --role <role>` - Member role (default: `member`)
561
- - `viewer` - Read-only access
562
- - `member` - Can manage translations
563
- - `admin` - Full project and team management
564
-
565
- **Examples:**
566
-
567
- ```bash
568
- # Invite as member (default)
569
- langctl team invite user@example.com
570
-
571
- # Invite as admin
572
- langctl team invite admin@example.com --role admin
573
-
574
- # Invite as viewer
575
- langctl team invite viewer@example.com --role viewer
576
- ```
577
-
578
- #### `langctl team remove <email>`
579
-
580
- Remove a team member from your organization.
581
-
582
- ```bash
583
- langctl team remove user@example.com
584
- ```
585
-
586
- **Note:** Cannot remove the organization owner. Cannot remove yourself (use appropriate UI for that).
587
-
588
- #### `langctl team update-role <email> <role>`
589
-
590
- Update a team member's role.
591
-
592
- ```bash
593
- langctl team update-role user@example.com admin
594
- ```
595
-
596
- **Valid roles:** `viewer`, `member`, `admin`
597
-
598
- **Examples:**
599
-
600
- ```bash
601
- # Promote to admin
602
- langctl team update-role user@example.com admin
603
-
604
- # Demote to viewer
605
- langctl team update-role user@example.com viewer
606
- ```
607
-
608
- #### `langctl team invitations`
609
-
610
- List all invitations (pending, accepted, or cancelled).
611
-
612
- ```bash
613
- # List all invitations
614
- langctl team invitations
615
-
616
- # List only pending invitations
617
- langctl team invitations --pending
618
- ```
619
-
620
- **Options:**
621
- - `-p, --pending` - Show only pending invitations
622
-
623
- #### `langctl team revoke-invitation <email>`
624
-
625
- Revoke a pending invitation.
626
-
627
- ```bash
628
- langctl team revoke-invitation user@example.com
629
- ```
630
-
631
- ---
632
-
633
- ### Export/Import Commands
634
-
635
- #### `langctl export <project>`
636
-
637
- Export translations in various formats.
638
-
639
- ```bash
640
- langctl export my-app --language en --format flat-json
641
- ```
642
-
643
- **Options:**
644
- - `-l, --language <code>` - Language to export (default: exports all languages)
645
- - `-f, --format <type>` - Export format (default: `flat-json`)
646
- - `-o, --output <path>` - Output file path (optional)
647
- - `-m, --module <name>` - Export only specific module
648
- - `--include-unpublished` - Include unpublished keys (default: published only)
649
-
650
- **Supported formats:**
651
- - `flat-json` - Flat key-value JSON (default)
652
- - `nested-json` - Nested JSON structure
653
- - `i18n-json` - i18next compatible format
654
- - `android-xml` - Android strings.xml format
655
- - `ios-strings` - iOS Localizable.strings format
656
- - `flutter-arb` - Flutter ARB format
657
-
658
- **Examples:**
659
-
660
- ```bash
661
- # Export single language as JSON
662
- langctl export my-app -l en -f flat-json
663
-
664
- # Export all languages
665
- langctl export my-app
666
-
667
- # Export for iOS
668
- langctl export my-app -l en -f ios-strings -o ./ios/en.lproj/Localizable.strings
669
-
670
- # Export for Android
671
- langctl export my-app -l es -f android-xml -o ./android/res/values-es/strings.xml
672
-
673
- # Export for Flutter
674
- langctl export my-app -l fr -f flutter-arb -o ./lib/l10n/app_fr.arb
675
-
676
- # Export specific module
677
- langctl export my-app -l en --module auth
678
-
679
- # Include unpublished translations
680
- langctl export my-app -l en --include-unpublished
681
- ```
682
-
683
- #### `langctl import <project> <file>`
684
-
685
- Import translations from a JSON file.
686
-
687
- ```bash
688
- langctl import my-app translations.json --language en
689
- ```
690
-
691
- **Options:**
692
- - `-l, --language <code>` - Target language (required)
693
- - `--overwrite` - Overwrite existing translations
694
- - `--publish` - Auto-publish imported keys
695
-
696
- **Examples:**
697
-
698
- ```bash
699
- # Import English translations
700
- langctl import my-app en.json -l en
701
-
702
- # Import and overwrite existing
703
- langctl import my-app en.json -l en --overwrite
704
-
705
- # Import and auto-publish
706
- langctl import my-app en.json -l en --publish
707
-
708
- # Import multiple languages
709
- langctl import my-app en.json -l en --publish
710
- langctl import my-app es.json -l es --publish
711
- langctl import my-app fr.json -l fr --publish
712
- ```
713
-
714
- **Supported JSON formats:**
715
-
716
- ```json
717
- // Flat format (recommended)
718
- {
719
- "home.welcome": "Welcome!",
720
- "home.subtitle": "Get started",
721
- "button.submit": "Submit"
722
- }
723
-
724
- // Nested format (auto-flattened)
725
- {
726
- "home": {
727
- "welcome": "Welcome!",
728
- "subtitle": "Get started"
729
- },
730
- "button": {
731
- "submit": "Submit"
732
- }
733
- }
734
- ```
735
-
736
- ---
737
-
738
- ## Export Format Examples
739
-
740
- ### Flat JSON (Default)
741
-
742
- ```json
743
- {
744
- "home.welcome": "Welcome!",
745
- "home.subtitle": "Get started with {{appName}}",
746
- "button.submit": "Submit"
747
- }
748
- ```
749
-
750
- ### Nested JSON
751
-
752
- ```json
753
- {
754
- "home": {
755
- "welcome": "Welcome!",
756
- "subtitle": "Get started with {{appName}}"
757
- },
758
- "button": {
759
- "submit": "Submit"
760
- }
761
- }
762
- ```
763
-
764
- ### i18next JSON
765
-
766
- ```json
767
- {
768
- "home": {
769
- "welcome": "Welcome!",
770
- "subtitle": "Get started with {{appName}}"
771
- }
772
- }
773
- ```
774
-
775
- ### iOS Strings
776
-
777
- ```
778
- /* Welcome message */
779
- "home.welcome" = "Welcome!";
780
-
781
- /* Homepage subtitle with app name placeholder */
782
- "home.subtitle" = "Get started with %@";
783
- ```
784
-
785
- ### Android XML
786
-
787
- ```xml
788
- <?xml version="1.0" encoding="utf-8"?>
789
- <resources>
790
- <!-- Welcome message -->
791
- <string name="home.welcome">Welcome!</string>
792
-
793
- <!-- Homepage subtitle with app name placeholder -->
794
- <string name="home.subtitle">Get started with %1$s</string>
795
- </resources>
796
- ```
797
-
798
- ### Flutter ARB
799
-
800
- ```json
801
- {
802
- "@@locale": "en",
803
- "home.welcome": "Welcome!",
804
- "@home.welcome": {
805
- "description": "Welcome message"
806
- },
807
- "home.subtitle": "Get started with {appName}",
808
- "@home.subtitle": {
809
- "description": "Homepage subtitle",
810
- "placeholders": {
811
- "appName": {
812
- "type": "String"
813
- }
814
- }
815
- }
816
- }
817
- ```
818
-
819
- ---
820
-
821
- ## Real-World Workflows
822
-
823
- ### Complete Project Setup
824
-
825
- ```bash
826
- # 1. Authenticate
827
- langctl auth lc_your_api_key_here
828
-
829
- # 2. Create project
830
- langctl projects create "Mobile App" \
831
- -l en,es,fr,de \
832
- --default-language en \
833
- -d "iOS and Android application"
834
-
835
- # 3. Add translation keys
836
- langctl keys create mobile-app home.welcome \
837
- --module home \
838
- --value-en "Welcome!" \
839
- --value-es "¡Bienvenido!" \
840
- --value-fr "Bienvenue!"
841
-
842
- langctl keys create mobile-app button.submit \
843
- --module common \
844
- --value-en "Submit" \
845
- --value-es "Enviar" \
846
- --value-fr "Soumettre"
847
-
848
- # 4. Publish keys
849
- langctl keys publish mobile-app home.welcome button.submit
850
-
851
- # 5. Export for platforms
852
- langctl export mobile-app -l en -f ios-strings -o ./ios/en.lproj/
853
- langctl export mobile-app -l en -f android-xml -o ./android/res/values/
854
- ```
855
-
856
- ### Bulk Import Workflow
857
-
858
- ```bash
859
- # 1. Prepare JSON files (en.json, es.json, fr.json)
860
- # 2. Import all languages
861
- langctl import my-app en.json -l en --publish
862
- langctl import my-app es.json -l es --publish
863
- langctl import my-app fr.json -l fr --publish
864
-
865
- # 3. Verify imports
866
- langctl keys list my-app --published
867
- langctl projects stats my-app
868
- ```
869
-
870
- ### Team Collaboration
871
-
872
- ```bash
873
- # 1. Invite team members
874
- langctl team invite developer@example.com --role member
875
- langctl team invite manager@example.com --role admin
876
-
877
- # 2. Check invitations
878
- langctl team invitations --pending
879
-
880
- # 3. Manage roles
881
- langctl team update-role developer@example.com admin
882
-
883
- # 4. View team
884
- langctl team list
31
+ npm install -g langctl # Node.js 20 or newer
32
+ # or, without installing:
33
+ npx langctl --help
885
34
  ```
886
35
 
887
- ### Multi-Platform Export
888
-
889
- ```bash
890
- # Export for all platforms
891
- PROJECT="my-app"
892
- LANG="en"
893
-
894
- # Web (i18next)
895
- langctl export $PROJECT -l $LANG -f i18n-json -o ./src/locales/$LANG.json
36
+ ## Quick start
896
37
 
897
- # iOS
898
- langctl export $PROJECT -l $LANG -f ios-strings -o ./ios/$LANG.lproj/Localizable.strings
38
+ 1. Create an API key at **[app.langctl.com → API Keys](https://app.langctl.com/organization/api-keys)** (it is shown only once).
39
+ 2. In your repository:
899
40
 
900
- # Android
901
- langctl export $PROJECT -l $LANG -f android-xml -o ./android/res/values/strings.xml
41
+ ```bash
42
+ langctl init
43
+ ```
902
44
 
903
- # Flutter
904
- langctl export $PROJECT -l $LANG -f flutter-arb -o ./lib/l10n/app_$LANG.arb
905
- ```
45
+ This asks for the key (input is hidden), lets you pick the project, file format and location,
46
+ and writes a `langctl.json` you can commit. Then:
906
47
 
907
- ---
48
+ ```bash
49
+ langctl pull # write translation files
50
+ langctl push # upload new keys from your source language file
51
+ ```
908
52
 
909
- ## CI/CD Integration
53
+ Keys are only included in `pull` once they are **published** — drafts stay out of your app until
54
+ someone reviews them (`--include-drafts` to override).
910
55
 
911
- ### GitHub Actions
56
+ ## Use it in CI
912
57
 
913
- Automated translation sync workflow:
58
+ No config file or login step is needed — set the key as a secret environment variable.
914
59
 
915
60
  ```yaml
916
- name: Sync Translations
917
-
918
- on:
919
- schedule:
920
- - cron: '0 0 * * *' # Daily at midnight
921
- workflow_dispatch: # Manual trigger
922
-
61
+ # .github/workflows/i18n.yml
62
+ name: translations
63
+ on: [pull_request]
923
64
  jobs:
924
- sync-translations:
65
+ i18n:
925
66
  runs-on: ubuntu-latest
926
67
  steps:
927
- - uses: actions/checkout@v3
928
-
929
- - name: Setup Node.js
930
- uses: actions/setup-node@v3
931
- with:
932
- node-version: '18'
933
-
934
- - name: Install Langctl
935
- run: npm install -g langctl
936
-
937
- - name: Authenticate
68
+ - uses: actions/checkout@v4
69
+ - uses: actions/setup-node@v4
70
+ with: { node-version: 22 }
71
+ - run: npx langctl@0 pull --check # fail if committed files are out of date
938
72
  env:
939
73
  LANGCTL_API_KEY: ${{ secrets.LANGCTL_API_KEY }}
940
- run: langctl auth $LANGCTL_API_KEY
941
-
942
- - name: Export Translations
943
- run: |
944
- langctl export my-project -l en -f i18n-json -o ./locales/en.json
945
- langctl export my-project -l es -f i18n-json -o ./locales/es.json
946
- langctl export my-project -l fr -f i18n-json -o ./locales/fr.json
947
-
948
- - name: Commit Changes
949
- run: |
950
- git config user.name "Langctl Bot"
951
- git config user.email "bot@langctl.com"
952
- git add locales/
953
- git diff --staged --quiet || git commit -m "chore: update translations [skip ci]"
954
- git push
955
- ```
956
-
957
- ### GitLab CI
958
-
959
- ```yaml
960
- sync-translations:
961
- image: node:18
962
- script:
963
- - npm install -g langctl
964
- - langctl auth $LANGCTL_API_KEY
965
- - langctl export my-project -l en -f json -o ./locales/en.json
966
- - langctl export my-project -l es -f json -o ./locales/es.json
967
- - git config user.name "Langctl Bot"
968
- - git config user.email "bot@langctl.com"
969
- - git add locales/
970
- - git diff --staged --quiet || git commit -m "chore: update translations"
971
- - git push origin $CI_COMMIT_BRANCH
972
- only:
973
- - schedules
974
- ```
975
-
976
- ### Docker
977
-
978
- ```dockerfile
979
- FROM node:18-alpine
980
-
981
- RUN npm install -g langctl
982
-
983
- WORKDIR /app
984
-
985
- COPY . .
986
-
987
- # Set API key via environment variable
988
- ENV LANGCTL_API_KEY=""
989
-
990
- # Example: Export translations on build
991
- RUN langctl auth $LANGCTL_API_KEY && \
992
- langctl export my-project -l en -f json -o ./public/locales/en.json
993
74
  ```
994
75
 
995
- ---
996
-
997
- ## Best Practices
998
-
999
- ### Project Organization
1000
-
1001
- 1. **Use modules** to organize keys by feature:
1002
- ```bash
1003
- langctl keys create app auth.login.title --module auth
1004
- langctl keys create app home.hero.title --module home
1005
- langctl keys create app settings.profile.name --module settings
1006
- ```
1007
-
1008
- 2. **Follow naming conventions**:
1009
- ```
1010
- module.screen.element
1011
- auth.login.title
1012
- home.hero.subtitle
1013
- ```
1014
-
1015
- 3. **Add descriptions** to keys:
1016
- ```bash
1017
- langctl keys create app button.submit \
1018
- --description "Primary action button across the app" \
1019
- --value-en "Submit"
1020
- ```
1021
-
1022
- ### Translation Workflow
1023
-
1024
- 1. **Create keys unpublished** (draft mode)
1025
- 2. **Add translations** for all languages
1026
- 3. **Review and test** translations
1027
- 4. **Publish** when ready:
1028
- ```bash
1029
- langctl keys publish my-app key1 key2 key3
1030
- ```
1031
-
1032
- 5. **Export** published translations only:
1033
- ```bash
1034
- langctl export my-app -l en
1035
- ```
1036
-
1037
- ### Team Management
1038
-
1039
- 1. **Use appropriate roles**:
1040
- - `viewer` - Stakeholders, reviewers (read-only)
1041
- - `member` - Translators, content writers
1042
- - `admin` - Project managers, team leads
1043
-
1044
- 2. **Regular access reviews**:
1045
- ```bash
1046
- langctl team list
1047
- langctl team invitations
1048
- ```
1049
-
1050
- ### Security
76
+ Other useful CI commands:
1051
77
 
1052
- 1. **Never commit API keys** to version control
1053
- 2. **Use environment variables**:
1054
- ```bash
1055
- export LANGCTL_API_KEY="lc_..."
1056
- langctl auth $LANGCTL_API_KEY
1057
- ```
1058
-
1059
- 3. **Rotate keys periodically** from [app.langctl.com](https://app.langctl.com)
1060
-
1061
- 4. **Use different keys** for different environments:
1062
- - Development key for local work
1063
- - CI/CD key for automated workflows
1064
- - Production key for releases
1065
-
1066
- ---
1067
-
1068
- ## Troubleshooting
1069
-
1070
- ### Authentication Issues
1071
-
1072
- **"Not authenticated" error:**
1073
78
  ```bash
1074
- # Solution: Authenticate with your API key
1075
- langctl auth lc_your_api_key_here
79
+ langctl push --dry-run --json # preview what a push would change
80
+ langctl push --publish # upload and publish new source strings (e.g. on main)
81
+ langctl pull --require-complete # fail if any language is missing translations
82
+ langctl whoami --json # verify the key, org and scopes
1076
83
  ```
1077
84
 
1078
- **"Invalid API key" error:**
1079
- - Verify key format (starts with `lc_`, 67 characters total)
1080
- - Check key hasn't been revoked at [app.langctl.com](https://app.langctl.com)
1081
- - Generate a new key if needed
1082
-
1083
- ### Project Issues
85
+ In CI `langctl` never prompts and never animates: spinners are off when `CI` is set or output
86
+ isn't a terminal, destructive commands require `--yes`, and every failure has a distinct
87
+ [exit code](#exit-codes). Use a key with only the scopes the job needs — `translations:read`
88
+ is enough for `pull`.
1084
89
 
1085
- **"Project not found" error:**
1086
- ```bash
1087
- # Check project slug (not name)
1088
- langctl projects list
90
+ ## `langctl.json`
1089
91
 
1090
- # Use the slug shown in the list
1091
- langctl keys list correct-slug-here
92
+ ```json
93
+ {
94
+ "project": "web-app",
95
+ "format": "json",
96
+ "output": "src/locales/{lang}.json"
97
+ }
1092
98
  ```
1093
99
 
1094
- **Cannot remove language:**
1095
- - Cannot remove the default language
1096
- - Change default language first:
1097
- ```bash
1098
- langctl projects update my-app --default-language en
1099
- langctl projects remove-language my-app fr
1100
- ```
1101
-
1102
- ### Import/Export Issues
1103
-
1104
- **Import fails with format error:**
1105
- - Ensure JSON is valid
1106
- - Use flat key-value format or nested objects
1107
- - Check language code is valid
1108
-
1109
- **Export shows no keys:**
1110
- - Verify keys are published:
1111
- ```bash
1112
- langctl keys list my-app --published
1113
- ```
1114
- - Or include unpublished:
1115
- ```bash
1116
- langctl export my-app -l en --include-unpublished
1117
- ```
1118
-
1119
- ### Connection Issues
1120
-
1121
- If experiencing connectivity problems:
1122
- 1. Check your internet connection
1123
- 2. Verify you're not behind a restrictive firewall
1124
- 3. Try again in a few moments
1125
- 4. Contact support if issue persists
1126
-
1127
- ---
1128
-
1129
- ## FAQ
1130
-
1131
- **Q: What's the difference between slug and name?**
1132
- A: The slug is the URL-friendly identifier (e.g., `my-app`), while the name is the display name (e.g., "My App"). Use slugs in CLI commands.
1133
-
1134
- **Q: Can I use the CLI without installing it?**
1135
- A: Yes! Use `npx langctl` instead of `langctl` for any command.
1136
-
1137
- **Q: How do I get my project slug?**
1138
- A: Run `langctl projects list` to see all project slugs.
1139
-
1140
- **Q: Can I export multiple languages at once?**
1141
- A: Yes, run `langctl export my-app` without `-l` flag to export all languages.
1142
-
1143
- **Q: What happens to unpublished keys?**
1144
- A: They're excluded from exports by default. Use `--include-unpublished` to include them.
1145
-
1146
- **Q: Can I undo a delete operation?**
1147
- A: Projects and keys use soft deletes. Contact support to recover deleted items.
1148
-
1149
- **Q: How do I change my default language?**
1150
- A: Run: `langctl projects update my-app --default-language <new-language>`
1151
-
1152
- **Q: Can I use the CLI in CI/CD?**
1153
- A: Yes! Store your API key as a secret and use it in your workflow. See [CI/CD Integration](#cicd-integration).
1154
-
1155
- ---
1156
-
1157
- ## Platform Support
1158
-
1159
- - ✅ macOS (Apple Silicon & Intel)
1160
- - ✅ Linux (x64, ARM64)
1161
- - ✅ Windows (x64, ARM64)
1162
- - ✅ Node.js 16.0.0 or higher
1163
-
1164
- ---
1165
-
1166
- ## Links
1167
-
1168
- - **Website:** [langctl.com](https://langctl.com)
1169
- - **Dashboard:** [app.langctl.com](https://app.langctl.com)
1170
- - **Documentation:** [langctl.com/docs](https://langctl.com/docs)
1171
- - **GitHub:** [github.com/siddharthsaxena0/langctl](https://github.com/siddharthsaxena0/langctl)
1172
- - **Report Issues:** [github.com/siddharthsaxena0/langctl/issues](https://github.com/siddharthsaxena0/langctl/issues)
1173
- - **Email Support:** [hello@langctl.com](mailto:hello@langctl.com)
1174
-
1175
- ---
1176
-
1177
- ## Contributing
1178
-
1179
- We welcome contributions! Please see our [contributing guidelines](CONTRIBUTING.md) for details.
1180
-
1181
- ---
100
+ | Field | Description |
101
+ | --- | --- |
102
+ | `project` | Project slug (`langctl projects list`). |
103
+ | `format` | `json` (default), `nested-json`, `android`, `ios`, `arb` — see below. |
104
+ | `output` | Path template, relative to `langctl.json`. Variables: `{lang}` (`pt-BR`), `{lang_}` (`pt_BR`), `{android}` (`values`, `values-pt-rBR`). |
105
+ | `languages` | Languages to pull (default: all project languages). |
106
+ | `sourceLanguage` | Language `push` uploads by default (default: the project's default language). |
107
+ | `includeDrafts` | Pull unpublished keys too (default `false`). |
108
+ | `module` | Only pull/push keys in this module. |
109
+
110
+ Command-line flags override the file; `langctl` looks for `langctl.json` in the current directory and its parents.
111
+
112
+ ## Formats
113
+
114
+ | Format | Default path | Notes |
115
+ | --- | --- | --- |
116
+ | `json` | `locales/{lang}.json` | Flat `{"home.title": "…"}` (i18next, vue-i18n, …). Import also accepts nested JSON. |
117
+ | `nested-json` | `locales/{lang}.json` | `{"home": {"title": "…"}}`. Fails if a key is both a string and a parent. |
118
+ | `android` | `res/{android}/strings.xml` | Names become valid resources (`home.title` → `home_title`); `{{name}}` → `%1$s`. |
119
+ | `ios` | `{lang}.lproj/Localizable.strings` | `{{name}}` → `%1$@`. |
120
+ | `arb` | `lib/l10n/app_{lang_}.arb` | Flutter; ids become Dart identifiers (`home.title` → `homeTitle`); placeholders declared. |
121
+
122
+ Placeholders are stored as `{{name}}`. A placeholder used twice gets the same position on every
123
+ platform, and literal `%` is escaped where needed. Output is sorted and has no timestamps, so a
124
+ pull only changes files when translations change. If two keys map to the same Android/ARB name,
125
+ the pull fails and names both keys instead of silently dropping one.
126
+
127
+ ## Commands
128
+
129
+ | Command | Description |
130
+ | --- | --- |
131
+ | `langctl init` | Set up a repo (auth if needed, write `langctl.json`). Flags: `--project --format --output --force`. |
132
+ | `langctl pull [project]` | Download translations. `-l/--languages`, `-f/--format`, `-o/--output`, `-m/--module`, `--include-drafts`, `--check`, `--dry-run`, `--require-complete`. |
133
+ | `langctl push [project]` | Upload files. Default: source language only; `-l all` for every language. `--overwrite`, `--publish`, `--dry-run`, `-i/--input`. |
134
+ | `langctl export [project]` | One-off export: `-l es -f android -o strings.xml`. |
135
+ | `langctl import [project] <file>` | One-off import of a single file: `-l es`, `--overwrite`, `--publish`, `--dry-run`. |
136
+ | `langctl auth [--stdin]` | Store an API key in `~/.langctl/config.json` (mode 600). `echo "$KEY" \| langctl auth --stdin`. |
137
+ | `langctl whoami` | Show org, key source, scopes and API latency. |
138
+ | `langctl logout` · `langctl config` · `langctl formats` | Remove the stored key · show effective config · list formats. |
139
+ | `langctl projects list\|get\|create\|update\|delete\|add-language\|remove-language\|stats` | Manage projects. `stats` shows translation coverage per language. |
140
+ | `langctl keys list\|get\|create\|update\|translate\|delete\|publish\|unpublish` | Manage keys, e.g. `keys create web home.title --value en="Welcome" --value es="Bienvenido" --publish`. |
141
+ | `langctl team list\|invite\|remove\|update-role\|invitations\|revoke-invitation` | Team management (key needs the `org:admin` scope). |
142
+ | `langctl org info\|stats\|plan` | Organization details, usage and plan limits. |
143
+
144
+ Global flags (any position): `--json` · `-q/--quiet` · `--verbose` (log HTTP requests) · `-y/--yes` ·
145
+ `--api-key` · `--api-url` · `--timeout <seconds>` · `--no-color`. Run `langctl <command> --help` for details.
146
+
147
+ ## Configuration & environment
148
+
149
+ | Variable | Purpose |
150
+ | --- | --- |
151
+ | `LANGCTL_API_KEY` | API key (takes precedence over the stored key). |
152
+ | `LANGCTL_API_URL` | API base URL (default `https://api.langctl.com/api/v1`). |
153
+ | `LANGCTL_TIMEOUT` | Request timeout in seconds (default 30). Idempotent requests are retried with backoff on network errors, 429 and 5xx. |
154
+ | `LANGCTL_CONFIG_DIR` | Where the user config lives (default `~/.langctl`). |
155
+ | `NO_COLOR` / `CI` | Disable colors / force non-interactive mode. |
156
+ | `NODE_EXTRA_CA_CERTS` | Trust a corporate proxy's CA. |
157
+
158
+ ## Exit codes
159
+
160
+ | Code | Meaning |
161
+ | --- | --- |
162
+ | 0 | Success |
163
+ | 1 | Error (including a cancelled confirmation, `--require-complete` failures) |
164
+ | 2 | Invalid usage — bad flag, unknown language/format, refused without `--yes` |
165
+ | 3 | Not authenticated, invalid/revoked key, or missing permission (scope) |
166
+ | 4 | Project, key, member or file not found |
167
+ | 5 | Network error, timeout, or the API is unavailable |
168
+ | 6 | Plan limit reached |
169
+ | 7 | `pull --check`: files are out of date |
170
+
171
+ With `--json`, errors are also printed to stdout as `{"error": {"message", "exitCode", "hint"}}`.
172
+
173
+ ## Upgrading from 0.2
174
+
175
+ - Requires **Node.js 20+** (0.2 already needed it in practice).
176
+ - `pull`/`export` default paths follow each platform's layout (`locales/{lang}.json`,
177
+ `res/values-xx/strings.xml`, `xx.lproj/…`, `app_xx.arb`). Use `-o` or `langctl.json` to keep your old paths.
178
+ - Exporting several languages to one file is now an error instead of silently overwriting it.
179
+ - Android and ARB output now uses valid identifiers (`home_title`, `homeTitle`) and correct escaping.
180
+ - Destructive commands (`projects delete`, `keys delete`, removing languages, `team remove`) ask for
181
+ confirmation, and require `--yes` when not run interactively.
182
+ - `keys translate` takes the text with `-t/--text` (`-v` is the version flag); `keys create`
183
+ accepts `--value LANG=TEXT` for any language. The `debug` command was replaced by `whoami`.
184
+ - `team` commands need an API key with the `org:admin` scope.
185
+
186
+ See [CHANGELOG.md](CHANGELOG.md) for everything else.
187
+
188
+ ## Development
189
+
190
+ ```bash
191
+ npm ci
192
+ npm test # unit tests
193
+ npm run build
194
+ LANGCTL_API_KEY=lc_… LANGCTL_E2E_PROJECT=<test-project> npm run test:e2e # against a real API
195
+ ```
1182
196
 
1183
197
  ## License
1184
198
 
1185
- MIT License - see [LICENSE](LICENSE) file for details.
1186
-
1187
- ---
1188
-
1189
- **Built with ❤️ by the Langctl team**
1190
-
1191
- *Making translation management simple, fast, and developer-friendly.*
199
+ MIT