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