@abdess76/i18nkit 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -0
- package/LICENSE +21 -0
- package/README.md +309 -0
- package/bin/cli.js +48 -0
- package/bin/commands/apply.js +48 -0
- package/bin/commands/check-sync.js +35 -0
- package/bin/commands/extract-utils.js +216 -0
- package/bin/commands/extract.js +198 -0
- package/bin/commands/find-orphans.js +36 -0
- package/bin/commands/help.js +34 -0
- package/bin/commands/index.js +79 -0
- package/bin/commands/translate.js +51 -0
- package/bin/commands/version.js +17 -0
- package/bin/commands/watch.js +34 -0
- package/bin/core/applier-utils.js +144 -0
- package/bin/core/applier.js +165 -0
- package/bin/core/args.js +147 -0
- package/bin/core/backup.js +74 -0
- package/bin/core/command-interface.js +69 -0
- package/bin/core/config.js +108 -0
- package/bin/core/context.js +86 -0
- package/bin/core/detector.js +152 -0
- package/bin/core/file-walker.js +159 -0
- package/bin/core/fs-adapter.js +56 -0
- package/bin/core/help-generator.js +208 -0
- package/bin/core/index.js +63 -0
- package/bin/core/json-utils.js +213 -0
- package/bin/core/key-generator.js +75 -0
- package/bin/core/log-utils.js +26 -0
- package/bin/core/orphan-finder.js +208 -0
- package/bin/core/parser-utils.js +187 -0
- package/bin/core/paths.js +60 -0
- package/bin/core/plugin-interface.js +83 -0
- package/bin/core/plugin-resolver-utils.js +166 -0
- package/bin/core/plugin-resolver.js +211 -0
- package/bin/core/sync-checker-utils.js +99 -0
- package/bin/core/sync-checker.js +199 -0
- package/bin/core/translator.js +197 -0
- package/bin/core/types.js +297 -0
- package/bin/core/watcher.js +119 -0
- package/bin/plugins/adapter-transloco.js +156 -0
- package/bin/plugins/parser-angular.js +56 -0
- package/bin/plugins/parser-primeng.js +79 -0
- package/bin/plugins/parser-typescript.js +66 -0
- package/bin/plugins/provider-deepl.js +65 -0
- package/bin/plugins/provider-mymemory.js +192 -0
- package/package.json +123 -0
- package/types/index.d.ts +85 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to
|
|
7
|
+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
8
|
+
|
|
9
|
+
## [1.0.0] - 01-12-2025
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Initial release
|
|
14
|
+
- Zero-dependency CLI for i18n extraction
|
|
15
|
+
- Angular + Transloco support with PrimeNG patterns
|
|
16
|
+
- Auto-apply feature to replace hardcoded strings
|
|
17
|
+
- Sync check to compare language files
|
|
18
|
+
- Orphan key detection
|
|
19
|
+
- Translation API integration (MyMemory + DeepL)
|
|
20
|
+
- Watch mode for development
|
|
21
|
+
- CI mode with strict validation
|
|
22
|
+
- Configuration file support (i18nkit.config.js, i18nkit.config.json)
|
|
23
|
+
- Custom key mapping (.i18n-keys.json)
|
|
24
|
+
- Backup system before modifications
|
|
25
|
+
- Interactive mode for confirmations
|
|
26
|
+
- Dry-run mode for previews
|
|
27
|
+
- Flat and nested output formats
|
|
28
|
+
- ICU message format support
|
|
29
|
+
- ES2024 features (Array.fromAsync, Promise.withResolvers, Set.difference)
|
|
30
|
+
|
|
31
|
+
### Technical
|
|
32
|
+
|
|
33
|
+
- Pure Node.js implementation (no external dependencies)
|
|
34
|
+
- Requires Node.js >= 22.0.0
|
|
35
|
+
- Uses modern JavaScript patterns and optimizations
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Abdessamad DERRAZ
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
# i18nkit
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
[](https://npmjs.com/package/i18nkit)
|
|
6
|
+
[](https://nodejs.org)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
[](package.json)
|
|
9
|
+
[](https://abdess.github.io/i18nkit/)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
Universal i18n toolkit: extract translation keys, sync language files, detect
|
|
14
|
+
missing translations. Zero dependencies, extensible via plugins.
|
|
15
|
+
|
|
16
|
+
## Why i18nkit?
|
|
17
|
+
|
|
18
|
+
Managing translations is tedious: find hardcoded strings, create translation
|
|
19
|
+
keys, keep language files in sync. **i18nkit automates it.**
|
|
20
|
+
|
|
21
|
+
| Problem | Solution |
|
|
22
|
+
| -------------------------------- | ------------------------------ |
|
|
23
|
+
| Hardcoded strings in templates | Auto-extract translatable text |
|
|
24
|
+
| Manual pipe/function replacement | Auto-apply in one command |
|
|
25
|
+
| Missing translations across lang | Sync check with CI integration |
|
|
26
|
+
| Unused keys bloating bundles | Orphan detection to clean up |
|
|
27
|
+
| Manual translation copy-paste | API translation (free + pro) |
|
|
28
|
+
|
|
29
|
+
## Current Support
|
|
30
|
+
|
|
31
|
+
- **Angular + Transloco** - Full support out of the box
|
|
32
|
+
- **PrimeNG components** - Auto-extraction of translatable attributes
|
|
33
|
+
|
|
34
|
+
Extensible via plugins for other frameworks and libraries.
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
### 1. Install
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm install --save-dev i18nkit
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 2. Add scripts to package.json
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"scripts": {
|
|
49
|
+
"i18n": "i18nkit --lang fr --merge",
|
|
50
|
+
"i18n:apply": "i18nkit --auto-apply --init-langs en,fr",
|
|
51
|
+
"i18n:check": "i18nkit --check-sync --strict",
|
|
52
|
+
"i18n:orphans": "i18nkit --find-orphans --strict",
|
|
53
|
+
"i18n:translate": "i18nkit --translate fr:en",
|
|
54
|
+
"i18n:watch": "i18nkit --watch",
|
|
55
|
+
"i18n:ci": "npm run i18n:check && npm run i18n:orphans"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 3. Run
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# First time: extract + apply + create language files
|
|
64
|
+
npm run i18n:apply
|
|
65
|
+
|
|
66
|
+
# Development: watch mode
|
|
67
|
+
npm run i18n:watch
|
|
68
|
+
|
|
69
|
+
# Before commit / CI
|
|
70
|
+
npm run i18n:ci
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## How It Works
|
|
74
|
+
|
|
75
|
+
**Before:**
|
|
76
|
+
|
|
77
|
+
```html
|
|
78
|
+
<h1>Welcome to our app</h1>
|
|
79
|
+
<button label="Submit" />
|
|
80
|
+
<input placeholder="Enter your name" />
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**After:**
|
|
84
|
+
|
|
85
|
+
```html
|
|
86
|
+
<h1>{{ 'home.titles.welcome_to_our_app' | transloco }}</h1>
|
|
87
|
+
<button [label]="'home.buttons.submit' | transloco" />
|
|
88
|
+
<input [placeholder]="'home.forms.enter_your_name' | transloco" />
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Generated `fr.json`:**
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"home": {
|
|
96
|
+
"titles": { "welcome_to_our_app": "Welcome to our app" },
|
|
97
|
+
"buttons": { "submit": "Submit" },
|
|
98
|
+
"forms": { "enter_your_name": "Enter your name" }
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Commands
|
|
104
|
+
|
|
105
|
+
| Script | Command | Description |
|
|
106
|
+
| ------------------------ | --------------------------- | ---------------------------- |
|
|
107
|
+
| `npm run i18n` | `--lang fr --merge` | Extract, merge with existing |
|
|
108
|
+
| `npm run i18n:apply` | `--auto-apply --init-langs` | Extract + replace + create |
|
|
109
|
+
| `npm run i18n:check` | `--check-sync --strict` | Validate files are in sync |
|
|
110
|
+
| `npm run i18n:orphans` | `--find-orphans --strict` | Find unused keys |
|
|
111
|
+
| `npm run i18n:translate` | `--translate fr:en` | Translate via API |
|
|
112
|
+
| `npm run i18n:watch` | `--watch` | Re-run on file changes |
|
|
113
|
+
|
|
114
|
+
## Configuration
|
|
115
|
+
|
|
116
|
+
Create `i18nkit.config.js` in your project root:
|
|
117
|
+
|
|
118
|
+
```javascript
|
|
119
|
+
module.exports = {
|
|
120
|
+
src: 'src/app',
|
|
121
|
+
i18nDir: 'src/assets/i18n',
|
|
122
|
+
lang: 'fr',
|
|
123
|
+
format: 'nested',
|
|
124
|
+
backup: true,
|
|
125
|
+
excludedFolders: ['node_modules', 'dist', '.git'],
|
|
126
|
+
};
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Or `i18nkit.config.json`:
|
|
130
|
+
|
|
131
|
+
```json
|
|
132
|
+
{
|
|
133
|
+
"src": "src/app",
|
|
134
|
+
"i18nDir": "src/assets/i18n",
|
|
135
|
+
"lang": "fr",
|
|
136
|
+
"format": "nested"
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Supported Patterns
|
|
141
|
+
|
|
142
|
+
### HTML Templates
|
|
143
|
+
|
|
144
|
+
| Pattern | Example |
|
|
145
|
+
| ------------ | ---------------------------------- |
|
|
146
|
+
| Text content | `<h1>Welcome</h1>` |
|
|
147
|
+
| Attributes | `alt`, `title`, `placeholder` |
|
|
148
|
+
| Angular 17+ | `@if`, `@for`, `@switch`, `@defer` |
|
|
149
|
+
|
|
150
|
+
### Component Libraries
|
|
151
|
+
|
|
152
|
+
| Library | Extracted Attributes |
|
|
153
|
+
| ---------------- | ---------------------------- |
|
|
154
|
+
| PrimeNG | `label`, `tooltip`, `header` |
|
|
155
|
+
| Angular Material | `placeholder`, `label` |
|
|
156
|
+
| Bootstrap | `title`, `alt` |
|
|
157
|
+
|
|
158
|
+
## Translation APIs
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
# Free: MyMemory API
|
|
162
|
+
npm run i18n:translate
|
|
163
|
+
|
|
164
|
+
# Free with higher rate limit
|
|
165
|
+
npx i18nkit --translate fr:en --email you@example.com
|
|
166
|
+
|
|
167
|
+
# Pro: DeepL API (best quality)
|
|
168
|
+
DEEPL_API_KEY=xxx npx i18nkit --translate fr:en --deepl
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## CI/CD Integration
|
|
172
|
+
|
|
173
|
+
### GitHub Actions
|
|
174
|
+
|
|
175
|
+
```yaml
|
|
176
|
+
name: i18n
|
|
177
|
+
on: [push, pull_request]
|
|
178
|
+
|
|
179
|
+
jobs:
|
|
180
|
+
validate:
|
|
181
|
+
runs-on: ubuntu-latest
|
|
182
|
+
steps:
|
|
183
|
+
- uses: actions/checkout@v4
|
|
184
|
+
- uses: actions/setup-node@v4
|
|
185
|
+
with:
|
|
186
|
+
node-version: 22
|
|
187
|
+
- run: npm ci
|
|
188
|
+
- run: npm run i18n:ci
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Key Mapping
|
|
192
|
+
|
|
193
|
+
Override auto-generated keys with `.i18n-keys.json`:
|
|
194
|
+
|
|
195
|
+
```json
|
|
196
|
+
{
|
|
197
|
+
"Welcome to our app": "common.welcome",
|
|
198
|
+
"Submit": "buttons.submit",
|
|
199
|
+
"Cancel": "buttons.cancel"
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Plugin System
|
|
204
|
+
|
|
205
|
+
i18nkit is built to be extended. Create plugins for any framework, library, or
|
|
206
|
+
translation service.
|
|
207
|
+
|
|
208
|
+
| Plugin Type | Purpose | Example Use Case |
|
|
209
|
+
| ------------ | -------------------------- | ------------------ |
|
|
210
|
+
| **parser** | Extract strings from files | Vue, Svelte, React |
|
|
211
|
+
| **adapter** | Transform to i18n syntax | i18next, vue-i18n |
|
|
212
|
+
| **provider** | Translate via API | Google, AWS, Azure |
|
|
213
|
+
|
|
214
|
+
### Quick Example
|
|
215
|
+
|
|
216
|
+
```javascript
|
|
217
|
+
// plugins/my-parser.js
|
|
218
|
+
module.exports = {
|
|
219
|
+
name: 'parser-vue',
|
|
220
|
+
type: 'parser',
|
|
221
|
+
meta: { description: 'Extract from Vue SFC' },
|
|
222
|
+
extensions: ['.vue'],
|
|
223
|
+
detect: ctx => ctx.pkg.dependencies?.['vue'],
|
|
224
|
+
extract(content) {
|
|
225
|
+
return [{ text: 'Hello', context: 'greeting' }];
|
|
226
|
+
},
|
|
227
|
+
};
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
```javascript
|
|
231
|
+
// i18nkit.config.js
|
|
232
|
+
module.exports = {
|
|
233
|
+
plugins: ['./plugins/my-parser.js'],
|
|
234
|
+
};
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**Full guide:** [PLUGINS.md](PLUGINS.md)
|
|
238
|
+
|
|
239
|
+
### Community Plugins
|
|
240
|
+
|
|
241
|
+
Publish your plugin to npm:
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
npm publish i18nkit-parser-svelte
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
i18nkit auto-discovers packages named `i18nkit-*` or `@yourorg/i18nkit-*`.
|
|
248
|
+
|
|
249
|
+
**Want to contribute?** Check [builtin plugins](bin/plugins/) for reference
|
|
250
|
+
implementations.
|
|
251
|
+
|
|
252
|
+
## Options
|
|
253
|
+
|
|
254
|
+
```text
|
|
255
|
+
--src <path> Source directory (default: src/app)
|
|
256
|
+
--i18n-dir <path> i18n directory (default: src/assets/i18n)
|
|
257
|
+
--lang <code> Language code
|
|
258
|
+
--format <type> nested | flat (default: nested)
|
|
259
|
+
--merge Merge with existing translations
|
|
260
|
+
--auto-apply Extract and apply pipes
|
|
261
|
+
--init-langs <codes> Create language files (e.g., en,fr,es)
|
|
262
|
+
--check-sync Compare language files
|
|
263
|
+
--find-orphans Find unused keys
|
|
264
|
+
--translate <src:tgt> Translate via API (e.g., fr:en)
|
|
265
|
+
--deepl Use DeepL API
|
|
266
|
+
--watch Watch mode
|
|
267
|
+
--dry-run Preview only
|
|
268
|
+
--strict Exit 1 on issues
|
|
269
|
+
--ci CI mode (strict + json output)
|
|
270
|
+
--verbose Detailed output
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## Exit Codes
|
|
274
|
+
|
|
275
|
+
| Code | Meaning |
|
|
276
|
+
| ---- | -------------------------------------------------- |
|
|
277
|
+
| 0 | Success |
|
|
278
|
+
| 1 | Missing translations or sync problems (`--strict`) |
|
|
279
|
+
| 2 | Error (file not found, parse error) |
|
|
280
|
+
|
|
281
|
+
## API Documentation
|
|
282
|
+
|
|
283
|
+
Full API reference:
|
|
284
|
+
[abdess.github.io/i18nkit](https://abdess.github.io/i18nkit/)
|
|
285
|
+
|
|
286
|
+
## Requirements
|
|
287
|
+
|
|
288
|
+
- Node.js >= 22.0.0
|
|
289
|
+
|
|
290
|
+
## Contributing
|
|
291
|
+
|
|
292
|
+
i18nkit welcomes community contributions:
|
|
293
|
+
|
|
294
|
+
- **Plugins** - Create parsers for new frameworks, adapters for i18n libraries,
|
|
295
|
+
or providers for translation APIs
|
|
296
|
+
- **Bug reports** - Open an issue with reproduction steps
|
|
297
|
+
- **Feature requests** - Suggest improvements via GitHub issues
|
|
298
|
+
|
|
299
|
+
See [PLUGINS.md](PLUGINS.md) for the plugin development guide.
|
|
300
|
+
|
|
301
|
+
## License
|
|
302
|
+
|
|
303
|
+
MIT
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
[GitHub](https://github.com/Abdess/i18nkit) ·
|
|
308
|
+
[npm](https://npmjs.com/package/i18nkit) ·
|
|
309
|
+
[Issues](https://github.com/Abdess/i18nkit/issues) · [Plugin Guide](PLUGINS.md)
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
const { createContext, detectCommand, EXIT_CODES } = require('./core/context');
|
|
6
|
+
const { getCommand } = require('./commands');
|
|
7
|
+
const core = require('./core');
|
|
8
|
+
|
|
9
|
+
const args = process.argv.slice(2);
|
|
10
|
+
const commandName = detectCommand(args);
|
|
11
|
+
const command = getCommand(commandName);
|
|
12
|
+
|
|
13
|
+
if (!command) {
|
|
14
|
+
console.error(`Unknown command: ${commandName}`);
|
|
15
|
+
process.exit(EXIT_CODES.ERROR);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function handleError(err, verbose) {
|
|
19
|
+
console.error('Error:', err.message);
|
|
20
|
+
if (verbose) {
|
|
21
|
+
console.error(err.stack);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const backups = core.getBackupFiles();
|
|
25
|
+
if (backups.size > 0) {
|
|
26
|
+
console.log('\nRestoring backups...');
|
|
27
|
+
console.log(`Restored ${core.restoreBackups()} file(s)`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
process.exit(EXIT_CODES.ERROR);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function main() {
|
|
34
|
+
const ctx = createContext(args);
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const result = await command.run(ctx);
|
|
38
|
+
const exitCode = result?.exitCode ?? EXIT_CODES.SUCCESS;
|
|
39
|
+
|
|
40
|
+
if (exitCode !== null) {
|
|
41
|
+
process.exit(exitCode);
|
|
42
|
+
}
|
|
43
|
+
} catch (err) {
|
|
44
|
+
handleError(err, ctx.verbose);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
main();
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Apply command - replaces source text with translation keys.
|
|
5
|
+
* Applies findings from report.json to source files with backup support.
|
|
6
|
+
* @module commands/apply
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { getArgValue, applyTranslations } = require('../core');
|
|
10
|
+
|
|
11
|
+
function getApplyOptions(ctx) {
|
|
12
|
+
const { srcDir, backupDir, adapter, backup, dryRun, verbose, interactive, log } = ctx;
|
|
13
|
+
return { srcDir, backupDir, adapter, backup, dryRun, verbose, interactive, log };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function validateApplyFile(applyFile, exitCodes) {
|
|
17
|
+
if (!applyFile) {
|
|
18
|
+
console.error('Missing --apply <report.json> argument');
|
|
19
|
+
return { exitCode: exitCodes.ERROR };
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
module.exports = {
|
|
25
|
+
name: 'apply',
|
|
26
|
+
category: 'apply',
|
|
27
|
+
description: 'Apply translations from a report file to source files',
|
|
28
|
+
|
|
29
|
+
options: [
|
|
30
|
+
{ flag: '--apply <report.json>', description: 'Path to the report file' },
|
|
31
|
+
{ flag: '--backup', description: 'Create backups before modifying (default: on)' },
|
|
32
|
+
{ flag: '--no-backup', description: 'Disable backup creation' },
|
|
33
|
+
{ flag: '--interactive', description: 'Ask for confirmation before changes' },
|
|
34
|
+
],
|
|
35
|
+
|
|
36
|
+
examples: ['i18nkit --apply .i18n/report.json', 'i18nkit --apply report.json --no-backup'],
|
|
37
|
+
|
|
38
|
+
async run(ctx) {
|
|
39
|
+
const { args, config, exitCodes } = ctx;
|
|
40
|
+
const applyFile = getArgValue(args, config, '--apply', null, null);
|
|
41
|
+
const error = validateApplyFile(applyFile, exitCodes);
|
|
42
|
+
if (error) {
|
|
43
|
+
return error;
|
|
44
|
+
}
|
|
45
|
+
await applyTranslations(applyFile, getApplyOptions(ctx));
|
|
46
|
+
return { exitCode: exitCodes.SUCCESS };
|
|
47
|
+
},
|
|
48
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Check-sync command - validates i18n file consistency.
|
|
5
|
+
* Detects missing keys, identical values, and ICU format mismatches.
|
|
6
|
+
* @module commands/check-sync
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { checkSync } = require('../core');
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
name: 'check-sync',
|
|
13
|
+
category: 'validation',
|
|
14
|
+
description: 'Compare language files for missing or identical keys',
|
|
15
|
+
|
|
16
|
+
options: [
|
|
17
|
+
{ flag: '--strict', description: 'Exit with error if missing or untranslated keys found' },
|
|
18
|
+
],
|
|
19
|
+
|
|
20
|
+
examples: ['i18nkit --check-sync', 'i18nkit --check-sync --strict'],
|
|
21
|
+
|
|
22
|
+
async run(ctx) {
|
|
23
|
+
const { i18nDir, format, strict, log, exitCodes } = ctx;
|
|
24
|
+
|
|
25
|
+
const result = await checkSync({
|
|
26
|
+
i18nDir,
|
|
27
|
+
format,
|
|
28
|
+
strict,
|
|
29
|
+
log,
|
|
30
|
+
exitCodes: { success: exitCodes.SUCCESS, untranslated: exitCodes.UNTRANSLATED },
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
return { exitCode: result.exitCode ?? exitCodes.SUCCESS };
|
|
34
|
+
},
|
|
35
|
+
};
|