i18nsmith 0.1.7 → 0.1.9
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/build.mjs +31 -0
- package/dist/index.js +109365 -22
- package/package.json +12 -7
- package/dist/commands/audit.js +0 -180
- package/dist/commands/audit.js.map +0 -1
- package/dist/commands/backup.js +0 -85
- package/dist/commands/backup.js.map +0 -1
- package/dist/commands/check.js +0 -151
- package/dist/commands/check.js.map +0 -1
- package/dist/commands/config.js +0 -235
- package/dist/commands/config.js.map +0 -1
- package/dist/commands/debug-patterns.js +0 -192
- package/dist/commands/debug-patterns.js.map +0 -1
- package/dist/commands/debug-patterns.test.js +0 -109
- package/dist/commands/debug-patterns.test.js.map +0 -1
- package/dist/commands/diagnose.js +0 -117
- package/dist/commands/diagnose.js.map +0 -1
- package/dist/commands/init.js +0 -450
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/init.test.js +0 -74
- package/dist/commands/init.test.js.map +0 -1
- package/dist/commands/install-hooks.js +0 -52
- package/dist/commands/install-hooks.js.map +0 -1
- package/dist/commands/preflight.js +0 -417
- package/dist/commands/preflight.js.map +0 -1
- package/dist/commands/preflight.test.js +0 -108
- package/dist/commands/preflight.test.js.map +0 -1
- package/dist/commands/rename.js +0 -204
- package/dist/commands/rename.js.map +0 -1
- package/dist/commands/scaffold-adapter.js +0 -204
- package/dist/commands/scaffold-adapter.js.map +0 -1
- package/dist/commands/scaffold-adapter.test.js +0 -102
- package/dist/commands/scaffold-adapter.test.js.map +0 -1
- package/dist/commands/scan.js +0 -93
- package/dist/commands/scan.js.map +0 -1
- package/dist/commands/sync-seed.test.js +0 -86
- package/dist/commands/sync-seed.test.js.map +0 -1
- package/dist/commands/sync.js +0 -590
- package/dist/commands/sync.js.map +0 -1
- package/dist/commands/transform.js +0 -114
- package/dist/commands/transform.js.map +0 -1
- package/dist/commands/translate/csv-handler.js +0 -270
- package/dist/commands/translate/csv-handler.js.map +0 -1
- package/dist/commands/translate/executor.js +0 -117
- package/dist/commands/translate/executor.js.map +0 -1
- package/dist/commands/translate/index.js +0 -170
- package/dist/commands/translate/index.js.map +0 -1
- package/dist/commands/translate/reporter.js +0 -103
- package/dist/commands/translate/reporter.js.map +0 -1
- package/dist/commands/translate/types.js +0 -5
- package/dist/commands/translate/types.js.map +0 -1
- package/dist/commands/translate.js +0 -7
- package/dist/commands/translate.js.map +0 -1
- package/dist/commands/translate.test.js +0 -118
- package/dist/commands/translate.test.js.map +0 -1
- package/dist/e2e.test.js +0 -376
- package/dist/e2e.test.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/integration.test.js +0 -320
- package/dist/integration.test.js.map +0 -1
- package/dist/utils/diagnostics-exit.js +0 -49
- package/dist/utils/diagnostics-exit.js.map +0 -1
- package/dist/utils/diagnostics-exit.test.js +0 -40
- package/dist/utils/diagnostics-exit.test.js.map +0 -1
- package/dist/utils/diff-utils.js +0 -30
- package/dist/utils/diff-utils.js.map +0 -1
- package/dist/utils/diff-utils.test.js +0 -30
- package/dist/utils/diff-utils.test.js.map +0 -1
- package/dist/utils/exit-codes.js +0 -168
- package/dist/utils/exit-codes.js.map +0 -1
- package/dist/utils/package-manager.js +0 -40
- package/dist/utils/package-manager.js.map +0 -1
- package/dist/utils/pkg.js +0 -24
- package/dist/utils/pkg.js.map +0 -1
- package/dist/utils/provider-injector.js +0 -223
- package/dist/utils/provider-injector.js.map +0 -1
- package/dist/utils/provider-injector.test.js +0 -67
- package/dist/utils/provider-injector.test.js.map +0 -1
- package/dist/utils/scaffold.js +0 -197
- package/dist/utils/scaffold.js.map +0 -1
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { Command } from 'commander';
|
|
3
|
-
import { registerScaffoldAdapter } from './scaffold-adapter';
|
|
4
|
-
import * as scaffoldModule from '../utils/scaffold.js';
|
|
5
|
-
vi.mock('@i18nsmith/core', () => ({
|
|
6
|
-
loadConfig: vi.fn().mockResolvedValue({
|
|
7
|
-
version: 1,
|
|
8
|
-
sourceLanguage: 'en',
|
|
9
|
-
targetLanguages: ['es'],
|
|
10
|
-
localesDir: 'locales',
|
|
11
|
-
include: ['src/**/*.{ts,tsx}'],
|
|
12
|
-
exclude: [],
|
|
13
|
-
minTextLength: 1,
|
|
14
|
-
translationAdapter: { module: 'react-i18next', hookName: 'useTranslation' },
|
|
15
|
-
keyGeneration: { namespace: 'common', shortHashLen: 6 },
|
|
16
|
-
seedTargetLocales: false,
|
|
17
|
-
sync: {
|
|
18
|
-
translationIdentifier: 't',
|
|
19
|
-
validateInterpolations: false,
|
|
20
|
-
placeholderFormats: ['doubleCurly', 'percentCurly', 'percentSymbol'],
|
|
21
|
-
emptyValuePolicy: 'warn',
|
|
22
|
-
emptyValueMarkers: ['todo'],
|
|
23
|
-
dynamicKeyAssumptions: [],
|
|
24
|
-
},
|
|
25
|
-
}),
|
|
26
|
-
diagnoseWorkspace: vi.fn().mockResolvedValue({
|
|
27
|
-
localesDir: 'locales',
|
|
28
|
-
localeFiles: [],
|
|
29
|
-
detectedLocales: [],
|
|
30
|
-
runtimePackages: [],
|
|
31
|
-
providerFiles: [],
|
|
32
|
-
adapterFiles: [],
|
|
33
|
-
translationUsage: {
|
|
34
|
-
hookName: 'useTranslation',
|
|
35
|
-
translationIdentifier: 't',
|
|
36
|
-
filesExamined: 0,
|
|
37
|
-
hookOccurrences: 0,
|
|
38
|
-
identifierOccurrences: 0,
|
|
39
|
-
hookExampleFiles: [],
|
|
40
|
-
identifierExampleFiles: [],
|
|
41
|
-
},
|
|
42
|
-
actionableItems: [],
|
|
43
|
-
conflicts: [],
|
|
44
|
-
recommendations: [],
|
|
45
|
-
}),
|
|
46
|
-
}));
|
|
47
|
-
vi.mock('inquirer', () => ({
|
|
48
|
-
default: {
|
|
49
|
-
prompt: vi.fn().mockResolvedValue({
|
|
50
|
-
type: 'custom',
|
|
51
|
-
sourceLanguage: 'en',
|
|
52
|
-
localesDir: 'locales',
|
|
53
|
-
filePath: 'src/contexts/translation-context.tsx',
|
|
54
|
-
force: false,
|
|
55
|
-
}),
|
|
56
|
-
},
|
|
57
|
-
}));
|
|
58
|
-
vi.mock('../utils/scaffold.js', () => ({
|
|
59
|
-
scaffoldTranslationContext: vi.fn().mockResolvedValue({
|
|
60
|
-
path: 'src/contexts/translation-context.tsx',
|
|
61
|
-
content: '// mock content',
|
|
62
|
-
written: true,
|
|
63
|
-
}),
|
|
64
|
-
scaffoldI18next: vi.fn().mockResolvedValue({
|
|
65
|
-
i18nPath: 'src/lib/i18n.ts',
|
|
66
|
-
providerPath: 'src/components/i18n-provider.tsx',
|
|
67
|
-
i18nResult: { path: 'src/lib/i18n.ts', content: '// i18n', written: true },
|
|
68
|
-
providerResult: { path: 'src/components/i18n-provider.tsx', content: '// provider', written: true },
|
|
69
|
-
}),
|
|
70
|
-
}));
|
|
71
|
-
vi.mock('../utils/pkg.js', () => ({
|
|
72
|
-
readPackageJson: vi.fn().mockResolvedValue({}),
|
|
73
|
-
hasDependency: vi.fn().mockReturnValue(false),
|
|
74
|
-
}));
|
|
75
|
-
describe('scaffold-adapter command', () => {
|
|
76
|
-
it('should register the scaffold-adapter command', () => {
|
|
77
|
-
const program = new Command();
|
|
78
|
-
registerScaffoldAdapter(program);
|
|
79
|
-
const command = program.commands.find((cmd) => cmd.name() === 'scaffold-adapter');
|
|
80
|
-
expect(command).toBeDefined();
|
|
81
|
-
});
|
|
82
|
-
describe('--dry-run flag', () => {
|
|
83
|
-
beforeEach(() => {
|
|
84
|
-
vi.clearAllMocks();
|
|
85
|
-
});
|
|
86
|
-
afterEach(() => {
|
|
87
|
-
vi.restoreAllMocks();
|
|
88
|
-
});
|
|
89
|
-
it('should pass dryRun option to scaffoldTranslationContext', async () => {
|
|
90
|
-
const scaffoldSpy = vi.spyOn(scaffoldModule, 'scaffoldTranslationContext');
|
|
91
|
-
scaffoldSpy.mockResolvedValue({
|
|
92
|
-
path: 'src/contexts/translation-context.tsx',
|
|
93
|
-
content: '// mock dry-run content',
|
|
94
|
-
written: false,
|
|
95
|
-
});
|
|
96
|
-
// Verify the dryRun parameter is passed correctly through the scaffold options
|
|
97
|
-
expect(scaffoldSpy).not.toHaveBeenCalled();
|
|
98
|
-
// Note: Full integration test would require mocking more dependencies
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
//# sourceMappingURL=scaffold-adapter.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"scaffold-adapter.test.js","sourceRoot":"","sources":["../../src/commands/scaffold-adapter.test.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/scan.js
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import fs from 'fs/promises';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import chalk from 'chalk';
|
|
4
|
-
import { loadConfigWithMeta, Scanner } from '@i18nsmith/core';
|
|
5
|
-
const collectTargetPatterns = (value, previous) => {
|
|
6
|
-
const list = Array.isArray(value) ? value : [value];
|
|
7
|
-
const tokens = list
|
|
8
|
-
.flatMap((entry) => entry.split(','))
|
|
9
|
-
.map((token) => token.trim())
|
|
10
|
-
.filter(Boolean);
|
|
11
|
-
return [...previous, ...tokens];
|
|
12
|
-
};
|
|
13
|
-
function printCandidateTable(candidates) {
|
|
14
|
-
const preview = candidates.slice(0, 50).map((candidate) => ({
|
|
15
|
-
File: candidate.filePath,
|
|
16
|
-
Line: candidate.position.line,
|
|
17
|
-
Column: candidate.position.column,
|
|
18
|
-
Kind: candidate.kind,
|
|
19
|
-
Context: candidate.context ?? '',
|
|
20
|
-
Text: candidate.text.length > 60
|
|
21
|
-
? `${candidate.text.slice(0, 57)}...`
|
|
22
|
-
: candidate.text,
|
|
23
|
-
}));
|
|
24
|
-
console.table(preview);
|
|
25
|
-
if (candidates.length > 50) {
|
|
26
|
-
console.log(chalk.gray(`Showing first 50 of ${candidates.length} candidates.`));
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
export function registerScan(program) {
|
|
30
|
-
program
|
|
31
|
-
.command('scan')
|
|
32
|
-
.description('Scan project for strings to translate')
|
|
33
|
-
.option('-c, --config <path>', 'Path to i18nsmith config file', 'i18n.config.json')
|
|
34
|
-
.option('--json', 'Print raw JSON results', false)
|
|
35
|
-
.option('--report <path>', 'Write JSON summary to a file (for CI or editors)')
|
|
36
|
-
.option('--list-files', 'List the files that were scanned', false)
|
|
37
|
-
.option('--include <patterns...>', 'Override include globs from config (comma or space separated)', collectTargetPatterns, [])
|
|
38
|
-
.option('--exclude <patterns...>', 'Override exclude globs from config (comma or space separated)', collectTargetPatterns, [])
|
|
39
|
-
.action(async (options) => {
|
|
40
|
-
console.log(chalk.blue('Starting scan...'));
|
|
41
|
-
try {
|
|
42
|
-
const { config, projectRoot, configPath } = await loadConfigWithMeta(options.config);
|
|
43
|
-
// Inform user if config was found in a parent directory
|
|
44
|
-
const cwd = process.cwd();
|
|
45
|
-
if (projectRoot !== cwd) {
|
|
46
|
-
console.log(chalk.gray(`Config found at ${path.relative(cwd, configPath)}`));
|
|
47
|
-
console.log(chalk.gray(`Using project root: ${projectRoot}\n`));
|
|
48
|
-
}
|
|
49
|
-
if (options.include?.length) {
|
|
50
|
-
config.include = options.include;
|
|
51
|
-
}
|
|
52
|
-
if (options.exclude?.length) {
|
|
53
|
-
config.exclude = options.exclude;
|
|
54
|
-
}
|
|
55
|
-
const scanner = new Scanner(config, { workspaceRoot: projectRoot });
|
|
56
|
-
const summary = scanner.scan();
|
|
57
|
-
if (options.report) {
|
|
58
|
-
const outputPath = path.resolve(process.cwd(), options.report);
|
|
59
|
-
await fs.mkdir(path.dirname(outputPath), { recursive: true });
|
|
60
|
-
await fs.writeFile(outputPath, JSON.stringify(summary, null, 2));
|
|
61
|
-
console.log(chalk.green(`Scan report written to ${outputPath}`));
|
|
62
|
-
}
|
|
63
|
-
if (options.json) {
|
|
64
|
-
console.log(JSON.stringify(summary, null, 2));
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
console.log(chalk.green(`Scanned ${summary.filesScanned} file${summary.filesScanned === 1 ? '' : 's'} and found ${summary.candidates.length} candidate${summary.candidates.length === 1 ? '' : 's'}.`));
|
|
68
|
-
if (summary.candidates.length === 0) {
|
|
69
|
-
console.log(chalk.yellow('No translatable strings found.'));
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
printCandidateTable(summary.candidates);
|
|
73
|
-
if (options.listFiles) {
|
|
74
|
-
if (summary.filesExamined.length === 0) {
|
|
75
|
-
console.log(chalk.yellow('No files matched the configured include/exclude patterns.'));
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
console.log(chalk.blue(`Files scanned (${summary.filesExamined.length}):`));
|
|
79
|
-
const preview = summary.filesExamined.slice(0, 200);
|
|
80
|
-
preview.forEach((file) => console.log(` • ${file}`));
|
|
81
|
-
if (summary.filesExamined.length > preview.length) {
|
|
82
|
-
console.log(chalk.gray(` ...and ${summary.filesExamined.length - preview.length} more. Use --target to narrow the list.`));
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
catch (error) {
|
|
88
|
-
console.error(chalk.red('Scan failed:'), error.message);
|
|
89
|
-
process.exitCode = 1;
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
//# sourceMappingURL=scan.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import fs from 'fs/promises';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import os from 'os';
|
|
5
|
-
import { execSync } from 'child_process';
|
|
6
|
-
describe('sync --seed-target-locales', () => {
|
|
7
|
-
let tempDir;
|
|
8
|
-
beforeEach(async () => {
|
|
9
|
-
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'i18nsmith-seed-test-'));
|
|
10
|
-
// Create basic project structure
|
|
11
|
-
await fs.mkdir(path.join(tempDir, 'src'), { recursive: true });
|
|
12
|
-
await fs.mkdir(path.join(tempDir, 'locales'), { recursive: true });
|
|
13
|
-
// Create source file with translation calls
|
|
14
|
-
await fs.writeFile(path.join(tempDir, 'src', 'App.tsx'), `import { useTranslation } from 'react-i18next';
|
|
15
|
-
export function App() {
|
|
16
|
-
const { t } = useTranslation();
|
|
17
|
-
return <div>{t('greeting')}{t('farewell')}</div>;
|
|
18
|
-
}
|
|
19
|
-
`);
|
|
20
|
-
// Create source locale with both keys
|
|
21
|
-
await fs.writeFile(path.join(tempDir, 'locales', 'en.json'), JSON.stringify({ greeting: 'Hello', farewell: 'Goodbye' }, null, 2));
|
|
22
|
-
// Create empty target locale
|
|
23
|
-
await fs.writeFile(path.join(tempDir, 'locales', 'fr.json'), JSON.stringify({}, null, 2));
|
|
24
|
-
// Create config
|
|
25
|
-
await fs.writeFile(path.join(tempDir, 'i18n.config.json'), JSON.stringify({
|
|
26
|
-
version: 1,
|
|
27
|
-
sourceLanguage: 'en',
|
|
28
|
-
targetLanguages: ['fr'],
|
|
29
|
-
localesDir: 'locales',
|
|
30
|
-
include: ['src/**/*.{ts,tsx}'],
|
|
31
|
-
}, null, 2));
|
|
32
|
-
});
|
|
33
|
-
afterEach(async () => {
|
|
34
|
-
await fs.rm(tempDir, { recursive: true, force: true });
|
|
35
|
-
});
|
|
36
|
-
const runCli = (args) => {
|
|
37
|
-
const cliPath = path.resolve(__dirname, '..', '..', 'dist', 'index.js');
|
|
38
|
-
try {
|
|
39
|
-
return execSync(`node ${cliPath} ${args}`, {
|
|
40
|
-
cwd: tempDir,
|
|
41
|
-
encoding: 'utf8',
|
|
42
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
catch (error) {
|
|
46
|
-
const err = error;
|
|
47
|
-
return (err.stdout ?? '') + (err.stderr ?? '');
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
it('seeds target locales with empty string by default', async () => {
|
|
51
|
-
const output = runCli('sync --write --seed-target-locales');
|
|
52
|
-
expect(output).toContain('Syncing');
|
|
53
|
-
const frContent = await fs.readFile(path.join(tempDir, 'locales', 'fr.json'), 'utf8');
|
|
54
|
-
const frData = JSON.parse(frContent);
|
|
55
|
-
// Should have both keys seeded in target locale
|
|
56
|
-
expect(frData.greeting).toBe('');
|
|
57
|
-
expect(frData.farewell).toBe('');
|
|
58
|
-
});
|
|
59
|
-
it('seeds target locales with custom seed value', async () => {
|
|
60
|
-
const output = runCli('sync --write --seed-target-locales --seed-value "[TODO]"');
|
|
61
|
-
expect(output).toContain('Syncing');
|
|
62
|
-
const frContent = await fs.readFile(path.join(tempDir, 'locales', 'fr.json'), 'utf8');
|
|
63
|
-
const frData = JSON.parse(frContent);
|
|
64
|
-
// Should have both keys seeded with [TODO]
|
|
65
|
-
expect(frData.greeting).toBe('[TODO]');
|
|
66
|
-
expect(frData.farewell).toBe('[TODO]');
|
|
67
|
-
});
|
|
68
|
-
it('does not seed when flag is not provided', async () => {
|
|
69
|
-
const output = runCli('sync --write');
|
|
70
|
-
expect(output).toContain('Syncing');
|
|
71
|
-
const frContent = await fs.readFile(path.join(tempDir, 'locales', 'fr.json'), 'utf8');
|
|
72
|
-
const frData = JSON.parse(frContent);
|
|
73
|
-
// Target locale should remain empty (no seeding)
|
|
74
|
-
expect(Object.keys(frData).length).toBe(0);
|
|
75
|
-
});
|
|
76
|
-
it('dry-run shows what would be seeded', async () => {
|
|
77
|
-
const output = runCli('sync --seed-target-locales');
|
|
78
|
-
expect(output).toContain('DRY RUN');
|
|
79
|
-
expect(output).toContain('missing');
|
|
80
|
-
// File should not be modified
|
|
81
|
-
const frContent = await fs.readFile(path.join(tempDir, 'locales', 'fr.json'), 'utf8');
|
|
82
|
-
const frData = JSON.parse(frContent);
|
|
83
|
-
expect(Object.keys(frData).length).toBe(0);
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
//# sourceMappingURL=sync-seed.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sync-seed.test.js","sourceRoot":"","sources":["../../src/commands/sync-seed.test.ts"],"names":[],"mappings":"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"}
|