@vocoder/cli 0.2.4 → 0.8.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/LICENSE +21 -0
- package/dist/bin.mjs +68 -106
- package/dist/bin.mjs.map +1 -1
- package/dist/chunk-7LFRSUPU.mjs +50638 -0
- package/dist/chunk-7LFRSUPU.mjs.map +1 -0
- package/dist/lib.d.mts +50 -3
- package/dist/lib.mjs +8 -5
- package/dist/lib.mjs.map +1 -1
- package/package.json +15 -15
- package/dist/chunk-TFAPB25S.mjs +0 -277
- package/dist/chunk-TFAPB25S.mjs.map +0 -1
package/dist/lib.d.mts
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
interface VocoderConfig {
|
|
2
|
+
/** Glob patterns for files to extract strings from. */
|
|
3
|
+
include?: string[];
|
|
4
|
+
/** Glob patterns to exclude. */
|
|
5
|
+
exclude?: string[];
|
|
6
|
+
/**
|
|
7
|
+
* Git branches that trigger string extraction and translation.
|
|
8
|
+
* Synced to the Vocoder dashboard on each push — change here to update.
|
|
9
|
+
*/
|
|
10
|
+
targetBranches?: string[];
|
|
11
|
+
/**
|
|
12
|
+
* Directory to write translated locale files after sync (optional).
|
|
13
|
+
* If set, `vocoder sync` writes {locale}.json files to this path.
|
|
14
|
+
*/
|
|
15
|
+
localesPath?: string;
|
|
16
|
+
}
|
|
17
|
+
/** Type helper for vocoder.config.ts — provides autocomplete and type checking. */
|
|
18
|
+
declare function defineConfig(config: VocoderConfig): VocoderConfig;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Load vocoder.config.{ts,js,mjs,json} from the given directory.
|
|
22
|
+
* Uses Babel AST parsing so it works for both TypeScript and JavaScript
|
|
23
|
+
* without requiring runtime execution or extra transpilation dependencies.
|
|
24
|
+
*
|
|
25
|
+
* Supports the common patterns:
|
|
26
|
+
* export default { include: [...], exclude: [...] }
|
|
27
|
+
* export default defineConfig({ include: [...], exclude: [...] })
|
|
28
|
+
*
|
|
29
|
+
* Returns null if no config file is found or parsing fails.
|
|
30
|
+
*/
|
|
31
|
+
declare function loadVocoderConfig(cwd: string): VocoderConfig | null;
|
|
32
|
+
|
|
33
|
+
interface ExtractedString {
|
|
34
|
+
key: string;
|
|
35
|
+
text: string;
|
|
36
|
+
file: string;
|
|
37
|
+
line: number;
|
|
38
|
+
context?: string;
|
|
39
|
+
formality?: "formal" | "informal" | "neutral" | "auto";
|
|
40
|
+
}
|
|
41
|
+
declare class StringExtractor {
|
|
42
|
+
extractFromProject(pattern: string | string[], projectRoot?: string, excludePattern?: string | string[]): Promise<ExtractedString[]>;
|
|
43
|
+
private extractFromFile;
|
|
44
|
+
private extractPluralSelectICU;
|
|
45
|
+
private extractTemplateText;
|
|
46
|
+
private getStringAttribute;
|
|
47
|
+
private deduplicateStrings;
|
|
48
|
+
}
|
|
3
49
|
|
|
4
50
|
interface LocaleInfo {
|
|
5
51
|
nativeName: string;
|
|
@@ -16,6 +62,7 @@ interface SyncPolicyConfig {
|
|
|
16
62
|
interface APIProjectConfig {
|
|
17
63
|
projectName: string;
|
|
18
64
|
organizationName: string;
|
|
65
|
+
shortCode: string;
|
|
19
66
|
sourceLocale: string;
|
|
20
67
|
targetLocales: string[];
|
|
21
68
|
targetBranches: string[];
|
|
@@ -133,4 +180,4 @@ declare function getSetupSnippets(params: {
|
|
|
133
180
|
targetBranches: string[];
|
|
134
181
|
}): SetupSnippets;
|
|
135
182
|
|
|
136
|
-
export { type APIProjectConfig, type DetectedEcosystem, type DetectedFramework, type LimitErrorResponse, type LocalDetectionResult, type LocaleInfo, type LocalesMap, type PackageManager, type SetupSnippets, type SyncPolicyConfig, type SyncPolicyErrorResponse, type TranslationBatchResponse, type TranslationSnapshotResponse, type TranslationStatusResponse, buildInstallCommand, detectLocalEcosystem, getPackagesToInstall, getSetupSnippets };
|
|
183
|
+
export { type APIProjectConfig, type DetectedEcosystem, type DetectedFramework, type ExtractedString, type LimitErrorResponse, type LocalDetectionResult, type LocaleInfo, type LocalesMap, type PackageManager, type SetupSnippets, StringExtractor, type SyncPolicyConfig, type SyncPolicyErrorResponse, type TranslationBatchResponse, type TranslationSnapshotResponse, type TranslationStatusResponse, type VocoderConfig, buildInstallCommand, defineConfig, detectLocalEcosystem, getPackagesToInstall, getSetupSnippets, loadVocoderConfig };
|
package/dist/lib.mjs
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from 'module'; const require = __createRequire(import.meta.url);
|
|
1
2
|
import {
|
|
2
3
|
StringExtractor,
|
|
3
4
|
buildInstallCommand,
|
|
4
5
|
detectLocalEcosystem,
|
|
5
6
|
getPackagesToInstall,
|
|
6
|
-
getSetupSnippets
|
|
7
|
-
|
|
7
|
+
getSetupSnippets,
|
|
8
|
+
loadVocoderConfig
|
|
9
|
+
} from "./chunk-7LFRSUPU.mjs";
|
|
8
10
|
|
|
9
|
-
// src/
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
// ../config/src/index.ts
|
|
12
|
+
function defineConfig(config) {
|
|
13
|
+
return config;
|
|
14
|
+
}
|
|
12
15
|
export {
|
|
13
16
|
StringExtractor,
|
|
14
17
|
buildInstallCommand,
|
package/dist/lib.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["
|
|
1
|
+
{"version":3,"sources":["../../config/src/index.ts"],"sourcesContent":["export interface VocoderConfig {\n\t/** Glob patterns for files to extract strings from. */\n\tinclude?: string[];\n\t/** Glob patterns to exclude. */\n\texclude?: string[];\n\t/**\n\t * Git branches that trigger string extraction and translation.\n\t * Synced to the Vocoder dashboard on each push — change here to update.\n\t */\n\ttargetBranches?: string[];\n\t/**\n\t * Directory to write translated locale files after sync (optional).\n\t * If set, `vocoder sync` writes {locale}.json files to this path.\n\t */\n\tlocalesPath?: string;\n}\n\n/** Type helper for vocoder.config.ts — provides autocomplete and type checking. */\nexport function defineConfig(config: VocoderConfig): VocoderConfig {\n\treturn config;\n}\n\n/**\n * Canonical translation bundle format shared by the build plugin and CLI.\n * Both read and write this shape — keeps cache files identical regardless of\n * which tool produced them.\n *\n * translations: locale → sourceKey (hash) → translated text\n * config.locales: locale metadata snapshot for the runtime\n */\nexport interface VocoderTranslationData {\n\tconfig: {\n\t\tsourceLocale: string;\n\t\ttargetLocales: string[];\n\t\tlocales: Record<string, {\n\t\t\tnativeName: string;\n\t\t\tdir?: \"rtl\";\n\t\t\tcurrencyCode?: string;\n\t\t\tordinalForms?: { type: \"suffix\"; suffixes: { zero?: string; one?: string; two?: string; few?: string; many?: string; other: string } } | { type: \"word\"; words: Record<string, Record<number, string>> };\n\t\t}>;\n\t};\n\ttranslations: Record<string, Record<string, string>>;\n\tupdatedAt: string | null;\n}\n"],"mappings":";;;;;;;;;;;AAkBO,SAAS,aAAa,QAAsC;AAClE,SAAO;AACR;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vocoder/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "CLI tool for Vocoder translation workflow",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -38,19 +38,7 @@
|
|
|
38
38
|
"bugs": {
|
|
39
39
|
"url": "https://github.com/vocoder/vocoder-sdk/issues"
|
|
40
40
|
},
|
|
41
|
-
"scripts": {
|
|
42
|
-
"build": "tsup",
|
|
43
|
-
"dev": "tsup --watch --no-dts --clean=false",
|
|
44
|
-
"watch": "tsup --watch",
|
|
45
|
-
"test": "vitest run --exclude 'src/__tests__/integration/**'",
|
|
46
|
-
"test:watch": "vitest",
|
|
47
|
-
"test:unit": "vitest run --exclude 'src/__tests__/integration/**'",
|
|
48
|
-
"test:integration": "RUN_INTEGRATION=true vitest run src/__tests__/integration",
|
|
49
|
-
"typecheck": "tsc --noEmit"
|
|
50
|
-
},
|
|
51
41
|
"dependencies": {
|
|
52
|
-
"@vocoder/config": "workspace:*",
|
|
53
|
-
"@vocoder/extractor": "workspace:*",
|
|
54
42
|
"@clack/core": "0.4.1",
|
|
55
43
|
"@clack/prompts": "^0.9.1",
|
|
56
44
|
"chalk": "^5.3.0",
|
|
@@ -62,9 +50,21 @@
|
|
|
62
50
|
"@types/node": "^20.19.9",
|
|
63
51
|
"tsup": "^8.0.0",
|
|
64
52
|
"typescript": "^5.4.0",
|
|
65
|
-
"vitest": "^1.0.0"
|
|
53
|
+
"vitest": "^1.0.0",
|
|
54
|
+
"@vocoder/extractor": "0.8.0",
|
|
55
|
+
"@vocoder/config": "0.8.0"
|
|
66
56
|
},
|
|
67
57
|
"engines": {
|
|
68
58
|
"node": ">=18"
|
|
59
|
+
},
|
|
60
|
+
"scripts": {
|
|
61
|
+
"build": "tsup",
|
|
62
|
+
"dev": "tsup --watch --no-dts --clean=false",
|
|
63
|
+
"watch": "tsup --watch",
|
|
64
|
+
"test": "vitest run --exclude 'src/__tests__/integration/**'",
|
|
65
|
+
"test:watch": "vitest",
|
|
66
|
+
"test:unit": "vitest run --exclude 'src/__tests__/integration/**'",
|
|
67
|
+
"test:integration": "RUN_INTEGRATION=true vitest run src/__tests__/integration",
|
|
68
|
+
"typecheck": "tsc --noEmit"
|
|
69
69
|
}
|
|
70
|
-
}
|
|
70
|
+
}
|
package/dist/chunk-TFAPB25S.mjs
DELETED
|
@@ -1,277 +0,0 @@
|
|
|
1
|
-
// src/utils/detect-local.ts
|
|
2
|
-
import { existsSync, readFileSync } from "fs";
|
|
3
|
-
import { join } from "path";
|
|
4
|
-
function detectLocalEcosystem(cwd = process.cwd()) {
|
|
5
|
-
const packageManager = detectPackageManager(cwd);
|
|
6
|
-
const pkg = readPackageJson(cwd);
|
|
7
|
-
if (!pkg) {
|
|
8
|
-
return {
|
|
9
|
-
ecosystem: null,
|
|
10
|
-
framework: null,
|
|
11
|
-
packageManager,
|
|
12
|
-
uiPackage: null,
|
|
13
|
-
hasUnplugin: false,
|
|
14
|
-
hasExtractor: false,
|
|
15
|
-
hasConfig: false,
|
|
16
|
-
hasUiPackage: false,
|
|
17
|
-
sourceLocale: null
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
const allDeps = {
|
|
21
|
-
...pkg.dependencies ?? {},
|
|
22
|
-
...pkg.devDependencies ?? {}
|
|
23
|
-
};
|
|
24
|
-
const hasUnplugin = "@vocoder/plugin" in allDeps;
|
|
25
|
-
const hasExtractor = "@vocoder/extractor" in allDeps;
|
|
26
|
-
const hasConfig = "@vocoder/config" in allDeps;
|
|
27
|
-
const { ecosystem, framework, uiPackage } = detectFromDeps(allDeps, cwd);
|
|
28
|
-
const hasUiPackage = uiPackage !== null && uiPackage in allDeps;
|
|
29
|
-
return {
|
|
30
|
-
ecosystem,
|
|
31
|
-
framework,
|
|
32
|
-
packageManager,
|
|
33
|
-
uiPackage,
|
|
34
|
-
hasUnplugin,
|
|
35
|
-
hasExtractor,
|
|
36
|
-
hasConfig,
|
|
37
|
-
hasUiPackage,
|
|
38
|
-
sourceLocale: null
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
function detectPackageManager(cwd) {
|
|
42
|
-
if (existsSync(join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
43
|
-
if (existsSync(join(cwd, "bun.lockb")) || existsSync(join(cwd, "bun.lock")))
|
|
44
|
-
return "bun";
|
|
45
|
-
if (existsSync(join(cwd, "yarn.lock"))) return "yarn";
|
|
46
|
-
return "npm";
|
|
47
|
-
}
|
|
48
|
-
function readPackageJson(cwd) {
|
|
49
|
-
const pkgPath = join(cwd, "package.json");
|
|
50
|
-
if (!existsSync(pkgPath)) return null;
|
|
51
|
-
try {
|
|
52
|
-
return JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
53
|
-
} catch {
|
|
54
|
-
return null;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
function detectFromDeps(allDeps, cwd) {
|
|
58
|
-
if ("vue" in allDeps) {
|
|
59
|
-
const framework = "nuxt" in allDeps ? "nuxt" : null;
|
|
60
|
-
return { ecosystem: "vue", framework, uiPackage: "@vocoder/vue" };
|
|
61
|
-
}
|
|
62
|
-
if ("svelte" in allDeps) {
|
|
63
|
-
const framework = "@sveltejs/kit" in allDeps ? "sveltekit" : null;
|
|
64
|
-
return { ecosystem: "svelte", framework, uiPackage: "@vocoder/svelte" };
|
|
65
|
-
}
|
|
66
|
-
if ("@angular/core" in allDeps || existsSync(join(cwd, "angular.json"))) {
|
|
67
|
-
return {
|
|
68
|
-
ecosystem: "angular",
|
|
69
|
-
framework: "angular",
|
|
70
|
-
uiPackage: "@vocoder/angular"
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
if ("react" in allDeps) {
|
|
74
|
-
let framework = null;
|
|
75
|
-
if ("next" in allDeps) framework = "nextjs";
|
|
76
|
-
else if ("@remix-run/react" in allDeps) framework = "remix";
|
|
77
|
-
else if ("gatsby" in allDeps) framework = "gatsby";
|
|
78
|
-
else if ("vite" in allDeps) framework = "vite";
|
|
79
|
-
return { ecosystem: "react", framework, uiPackage: "@vocoder/react" };
|
|
80
|
-
}
|
|
81
|
-
return { ecosystem: null, framework: null, uiPackage: null };
|
|
82
|
-
}
|
|
83
|
-
function buildInstallCommand(packageManager, packages, dev = false) {
|
|
84
|
-
if (packages.length === 0) return "";
|
|
85
|
-
const pkgList = packages.join(" ");
|
|
86
|
-
const devFlag = dev ? " -D" : "";
|
|
87
|
-
switch (packageManager) {
|
|
88
|
-
case "pnpm":
|
|
89
|
-
return `pnpm add${devFlag} ${pkgList}`;
|
|
90
|
-
case "yarn":
|
|
91
|
-
return `yarn add${devFlag} ${pkgList}`;
|
|
92
|
-
case "bun":
|
|
93
|
-
return `bun add${devFlag} ${pkgList}`;
|
|
94
|
-
default:
|
|
95
|
-
return `npm install${devFlag} ${pkgList}`;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
function getPackagesToInstall(detection) {
|
|
99
|
-
const devPackages = [];
|
|
100
|
-
const runtimePackages = [];
|
|
101
|
-
if (!detection.hasUnplugin) devPackages.push("@vocoder/plugin");
|
|
102
|
-
if (!detection.hasExtractor) devPackages.push("@vocoder/extractor");
|
|
103
|
-
if (!detection.hasConfig) devPackages.push("@vocoder/config");
|
|
104
|
-
if (detection.uiPackage && !detection.hasUiPackage)
|
|
105
|
-
runtimePackages.push(detection.uiPackage);
|
|
106
|
-
return { devPackages, runtimePackages };
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// src/utils/setup-snippets.ts
|
|
110
|
-
function getSetupSnippets(params) {
|
|
111
|
-
const { framework, ecosystem, sourceLocale } = params;
|
|
112
|
-
return {
|
|
113
|
-
pluginStep: getPluginSnippet(framework, ecosystem),
|
|
114
|
-
providerStep: getProviderSnippet(ecosystem, sourceLocale),
|
|
115
|
-
wrapStep: getWrapSnippet(ecosystem),
|
|
116
|
-
whatsNext: "Push to a target branch to trigger translations."
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
function getPluginSnippet(framework, ecosystem) {
|
|
120
|
-
switch (framework) {
|
|
121
|
-
case "nextjs":
|
|
122
|
-
return {
|
|
123
|
-
file: "next.config.ts",
|
|
124
|
-
code: `import { withVocoder } from '@vocoder/plugin/next';
|
|
125
|
-
|
|
126
|
-
export default withVocoder({
|
|
127
|
-
// your existing Next.js config
|
|
128
|
-
});`
|
|
129
|
-
};
|
|
130
|
-
case "vite":
|
|
131
|
-
case "remix":
|
|
132
|
-
return {
|
|
133
|
-
file: "vite.config.ts",
|
|
134
|
-
code: `import vocoder from '@vocoder/plugin/vite';
|
|
135
|
-
|
|
136
|
-
export default defineConfig({
|
|
137
|
-
plugins: [
|
|
138
|
-
vocoder(),
|
|
139
|
-
// your other plugins
|
|
140
|
-
],
|
|
141
|
-
});`
|
|
142
|
-
};
|
|
143
|
-
case "nuxt":
|
|
144
|
-
return {
|
|
145
|
-
file: "nuxt.config.ts",
|
|
146
|
-
code: `import vocoder from '@vocoder/plugin/vite';
|
|
147
|
-
|
|
148
|
-
export default defineNuxtConfig({
|
|
149
|
-
vite: {
|
|
150
|
-
plugins: [vocoder()],
|
|
151
|
-
},
|
|
152
|
-
});`
|
|
153
|
-
};
|
|
154
|
-
case "sveltekit":
|
|
155
|
-
return {
|
|
156
|
-
file: "vite.config.ts",
|
|
157
|
-
code: `import vocoder from '@vocoder/plugin/vite';
|
|
158
|
-
import { sveltekit } from '@sveltejs/kit/vite';
|
|
159
|
-
|
|
160
|
-
export default defineConfig({
|
|
161
|
-
plugins: [
|
|
162
|
-
sveltekit(),
|
|
163
|
-
vocoder(),
|
|
164
|
-
],
|
|
165
|
-
});`
|
|
166
|
-
};
|
|
167
|
-
case "gatsby":
|
|
168
|
-
return {
|
|
169
|
-
file: "gatsby-node.js",
|
|
170
|
-
code: `const vocoder = require('@vocoder/plugin/webpack');
|
|
171
|
-
|
|
172
|
-
exports.onCreateWebpackConfig = ({ actions }) => {
|
|
173
|
-
actions.setWebpackConfig({
|
|
174
|
-
plugins: [vocoder()],
|
|
175
|
-
});
|
|
176
|
-
};`
|
|
177
|
-
};
|
|
178
|
-
case "angular":
|
|
179
|
-
return null;
|
|
180
|
-
// Angular CLI doesn't expose plugin config easily
|
|
181
|
-
default:
|
|
182
|
-
if (ecosystem) {
|
|
183
|
-
return {
|
|
184
|
-
file: "your bundler config",
|
|
185
|
-
code: `// Vite
|
|
186
|
-
import vocoder from '@vocoder/plugin/vite';
|
|
187
|
-
// Webpack
|
|
188
|
-
const vocoder = require('@vocoder/plugin/webpack');
|
|
189
|
-
|
|
190
|
-
// Add vocoder() to your plugins array`
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
return null;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
function getProviderSnippet(ecosystem, sourceLocale) {
|
|
197
|
-
switch (ecosystem) {
|
|
198
|
-
case "react":
|
|
199
|
-
return {
|
|
200
|
-
file: "your root layout or App component",
|
|
201
|
-
code: `import { VocoderProvider } from '@vocoder/react';
|
|
202
|
-
|
|
203
|
-
<VocoderProvider defaultLocale="${sourceLocale}">
|
|
204
|
-
{children}
|
|
205
|
-
</VocoderProvider>`
|
|
206
|
-
};
|
|
207
|
-
case "vue":
|
|
208
|
-
return {
|
|
209
|
-
file: "your app entry",
|
|
210
|
-
code: `import { createVocoder } from '@vocoder/vue';
|
|
211
|
-
|
|
212
|
-
const vocoder = createVocoder({
|
|
213
|
-
defaultLocale: '${sourceLocale}',
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
app.use(vocoder);`
|
|
217
|
-
};
|
|
218
|
-
case "svelte":
|
|
219
|
-
return {
|
|
220
|
-
file: "your root layout",
|
|
221
|
-
code: `<script>
|
|
222
|
-
import { VocoderProvider } from '@vocoder/svelte';
|
|
223
|
-
</script>
|
|
224
|
-
|
|
225
|
-
<VocoderProvider defaultLocale="${sourceLocale}">
|
|
226
|
-
<slot />
|
|
227
|
-
</VocoderProvider>`
|
|
228
|
-
};
|
|
229
|
-
default:
|
|
230
|
-
return null;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
function getWrapSnippet(ecosystem) {
|
|
234
|
-
switch (ecosystem) {
|
|
235
|
-
case "react":
|
|
236
|
-
return {
|
|
237
|
-
code: `import { T } from '@vocoder/react';
|
|
238
|
-
|
|
239
|
-
<T>Hello, world!</T>`
|
|
240
|
-
};
|
|
241
|
-
case "vue":
|
|
242
|
-
return {
|
|
243
|
-
code: `<template>
|
|
244
|
-
<T>Hello, world!</T>
|
|
245
|
-
</template>
|
|
246
|
-
|
|
247
|
-
<script setup>
|
|
248
|
-
import { T } from '@vocoder/vue';
|
|
249
|
-
</script>`
|
|
250
|
-
};
|
|
251
|
-
case "svelte":
|
|
252
|
-
return {
|
|
253
|
-
code: `<script>
|
|
254
|
-
import { T } from '@vocoder/svelte';
|
|
255
|
-
</script>
|
|
256
|
-
|
|
257
|
-
<T>Hello, world!</T>`
|
|
258
|
-
};
|
|
259
|
-
default:
|
|
260
|
-
return {
|
|
261
|
-
code: `// Wrap translatable strings with <T>
|
|
262
|
-
<T>Hello, world!</T>`
|
|
263
|
-
};
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// src/utils/extract.ts
|
|
268
|
-
import { StringExtractor } from "@vocoder/extractor";
|
|
269
|
-
|
|
270
|
-
export {
|
|
271
|
-
detectLocalEcosystem,
|
|
272
|
-
buildInstallCommand,
|
|
273
|
-
getPackagesToInstall,
|
|
274
|
-
getSetupSnippets,
|
|
275
|
-
StringExtractor
|
|
276
|
-
};
|
|
277
|
-
//# sourceMappingURL=chunk-TFAPB25S.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/detect-local.ts","../src/utils/setup-snippets.ts","../src/utils/extract.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport type PackageManager = \"pnpm\" | \"npm\" | \"yarn\" | \"bun\";\n\nexport type DetectedFramework =\n\t| \"nextjs\"\n\t| \"vite\"\n\t| \"remix\"\n\t| \"nuxt\"\n\t| \"sveltekit\"\n\t| \"gatsby\"\n\t| \"angular\"\n\t| null;\n\nexport type DetectedEcosystem = \"react\" | \"vue\" | \"svelte\" | \"angular\" | null;\n\nexport interface LocalDetectionResult {\n\tecosystem: DetectedEcosystem;\n\tframework: DetectedFramework;\n\tpackageManager: PackageManager;\n\tuiPackage: string | null;\n\thasUnplugin: boolean;\n\thasExtractor: boolean;\n\thasConfig: boolean;\n\thasUiPackage: boolean;\n\tsourceLocale: string | null;\n}\n\n/**\n * Detect the local project's ecosystem, framework, and package manager\n * by inspecting filesystem artifacts. No network calls.\n */\nexport function detectLocalEcosystem(\n\tcwd: string = process.cwd(),\n): LocalDetectionResult {\n\tconst packageManager = detectPackageManager(cwd);\n\tconst pkg = readPackageJson(cwd);\n\n\tif (!pkg) {\n\t\treturn {\n\t\t\tecosystem: null,\n\t\t\tframework: null,\n\t\t\tpackageManager,\n\t\t\tuiPackage: null,\n\t\t\thasUnplugin: false,\n\t\t\thasExtractor: false,\n\t\t\thasConfig: false,\n\t\t\thasUiPackage: false,\n\t\t\tsourceLocale: null,\n\t\t};\n\t}\n\n\tconst allDeps = {\n\t\t...((pkg.dependencies as Record<string, string>) ?? {}),\n\t\t...((pkg.devDependencies as Record<string, string>) ?? {}),\n\t};\n\n\tconst hasUnplugin = \"@vocoder/plugin\" in allDeps;\n\tconst hasExtractor = \"@vocoder/extractor\" in allDeps;\n\tconst hasConfig = \"@vocoder/config\" in allDeps;\n\n\t// Detect ecosystem + framework\n\tconst { ecosystem, framework, uiPackage } = detectFromDeps(allDeps, cwd);\n\tconst hasUiPackage = uiPackage !== null && uiPackage in allDeps;\n\n\treturn {\n\t\tecosystem,\n\t\tframework,\n\t\tpackageManager,\n\t\tuiPackage,\n\t\thasUnplugin,\n\t\thasExtractor,\n\t\thasConfig,\n\t\thasUiPackage,\n\t\tsourceLocale: null,\n\t};\n}\n\nfunction detectPackageManager(cwd: string): PackageManager {\n\tif (existsSync(join(cwd, \"pnpm-lock.yaml\"))) return \"pnpm\";\n\tif (existsSync(join(cwd, \"bun.lockb\")) || existsSync(join(cwd, \"bun.lock\")))\n\t\treturn \"bun\";\n\tif (existsSync(join(cwd, \"yarn.lock\"))) return \"yarn\";\n\treturn \"npm\";\n}\n\nfunction readPackageJson(cwd: string): Record<string, unknown> | null {\n\tconst pkgPath = join(cwd, \"package.json\");\n\tif (!existsSync(pkgPath)) return null;\n\ttry {\n\t\treturn JSON.parse(readFileSync(pkgPath, \"utf-8\")) as Record<\n\t\t\tstring,\n\t\t\tunknown\n\t\t>;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction detectFromDeps(\n\tallDeps: Record<string, string>,\n\tcwd: string,\n): {\n\tecosystem: DetectedEcosystem;\n\tframework: DetectedFramework;\n\tuiPackage: string | null;\n} {\n\t// Vue ecosystem\n\tif (\"vue\" in allDeps) {\n\t\tconst framework = \"nuxt\" in allDeps ? (\"nuxt\" as const) : null;\n\t\treturn { ecosystem: \"vue\", framework, uiPackage: \"@vocoder/vue\" };\n\t}\n\n\t// Svelte ecosystem\n\tif (\"svelte\" in allDeps) {\n\t\tconst framework =\n\t\t\t\"@sveltejs/kit\" in allDeps ? (\"sveltekit\" as const) : null;\n\t\treturn { ecosystem: \"svelte\", framework, uiPackage: \"@vocoder/svelte\" };\n\t}\n\n\t// Angular ecosystem\n\tif (\"@angular/core\" in allDeps || existsSync(join(cwd, \"angular.json\"))) {\n\t\treturn {\n\t\t\tecosystem: \"angular\",\n\t\t\tframework: \"angular\",\n\t\t\tuiPackage: \"@vocoder/angular\",\n\t\t};\n\t}\n\n\t// React ecosystem (most common — check last)\n\tif (\"react\" in allDeps) {\n\t\tlet framework: DetectedFramework = null;\n\t\tif (\"next\" in allDeps) framework = \"nextjs\";\n\t\telse if (\"@remix-run/react\" in allDeps) framework = \"remix\";\n\t\telse if (\"gatsby\" in allDeps) framework = \"gatsby\";\n\t\telse if (\"vite\" in allDeps) framework = \"vite\";\n\t\treturn { ecosystem: \"react\", framework, uiPackage: \"@vocoder/react\" };\n\t}\n\n\treturn { ecosystem: null, framework: null, uiPackage: null };\n}\n\n/**\n * Build the install command for packages that aren't already installed.\n * Pass dev=true for devDependencies (-D flag).\n */\nexport function buildInstallCommand(\n\tpackageManager: PackageManager,\n\tpackages: string[],\n\tdev = false,\n): string {\n\tif (packages.length === 0) return \"\";\n\tconst pkgList = packages.join(\" \");\n\tconst devFlag = dev ? \" -D\" : \"\";\n\tswitch (packageManager) {\n\t\tcase \"pnpm\":\n\t\t\treturn `pnpm add${devFlag} ${pkgList}`;\n\t\tcase \"yarn\":\n\t\t\treturn `yarn add${devFlag} ${pkgList}`;\n\t\tcase \"bun\":\n\t\t\treturn `bun add${devFlag} ${pkgList}`;\n\t\tdefault:\n\t\t\treturn `npm install${devFlag} ${pkgList}`;\n\t}\n}\n\n/**\n * Get the lists of packages that need to be installed, split by dep type.\n * devPackages → devDependencies (build tools)\n * runtimePackages → dependencies (used at runtime in the app)\n */\nexport function getPackagesToInstall(detection: LocalDetectionResult): {\n\tdevPackages: string[];\n\truntimePackages: string[];\n} {\n\tconst devPackages: string[] = [];\n\tconst runtimePackages: string[] = [];\n\n\tif (!detection.hasUnplugin) devPackages.push(\"@vocoder/plugin\");\n\tif (!detection.hasExtractor) devPackages.push(\"@vocoder/extractor\");\n\tif (!detection.hasConfig) devPackages.push(\"@vocoder/config\");\n\n\tif (detection.uiPackage && !detection.hasUiPackage)\n\t\truntimePackages.push(detection.uiPackage);\n\n\treturn { devPackages, runtimePackages };\n}\n","import type { DetectedEcosystem, DetectedFramework } from \"./detect-local.js\";\n\nexport interface SetupSnippets {\n\tpluginStep: { file: string; code: string } | null;\n\tproviderStep: { file: string; code: string } | null;\n\twrapStep: { code: string };\n\twhatsNext: string;\n}\n\n/**\n * Generate framework-specific setup snippets.\n */\nexport function getSetupSnippets(params: {\n\tframework: DetectedFramework;\n\tecosystem: DetectedEcosystem;\n\tsourceLocale: string;\n\ttargetBranches: string[];\n}): SetupSnippets {\n\tconst { framework, ecosystem, sourceLocale } = params;\n\n\treturn {\n\t\tpluginStep: getPluginSnippet(framework, ecosystem),\n\t\tproviderStep: getProviderSnippet(ecosystem, sourceLocale),\n\t\twrapStep: getWrapSnippet(ecosystem),\n\t\twhatsNext: \"Push to a target branch to trigger translations.\",\n\t};\n}\n\nfunction getPluginSnippet(\n\tframework: DetectedFramework,\n\tecosystem: DetectedEcosystem,\n): { file: string; code: string } | null {\n\tswitch (framework) {\n\t\tcase \"nextjs\":\n\t\t\treturn {\n\t\t\t\tfile: \"next.config.ts\",\n\t\t\t\tcode: `import { withVocoder } from '@vocoder/plugin/next';\n\nexport default withVocoder({\n // your existing Next.js config\n});`,\n\t\t\t};\n\n\t\tcase \"vite\":\n\t\tcase \"remix\":\n\t\t\treturn {\n\t\t\t\tfile: \"vite.config.ts\",\n\t\t\t\tcode: `import vocoder from '@vocoder/plugin/vite';\n\nexport default defineConfig({\n plugins: [\n vocoder(),\n // your other plugins\n ],\n});`,\n\t\t\t};\n\n\t\tcase \"nuxt\":\n\t\t\treturn {\n\t\t\t\tfile: \"nuxt.config.ts\",\n\t\t\t\tcode: `import vocoder from '@vocoder/plugin/vite';\n\nexport default defineNuxtConfig({\n vite: {\n plugins: [vocoder()],\n },\n});`,\n\t\t\t};\n\n\t\tcase \"sveltekit\":\n\t\t\treturn {\n\t\t\t\tfile: \"vite.config.ts\",\n\t\t\t\tcode: `import vocoder from '@vocoder/plugin/vite';\nimport { sveltekit } from '@sveltejs/kit/vite';\n\nexport default defineConfig({\n plugins: [\n sveltekit(),\n vocoder(),\n ],\n});`,\n\t\t\t};\n\n\t\tcase \"gatsby\":\n\t\t\treturn {\n\t\t\t\tfile: \"gatsby-node.js\",\n\t\t\t\tcode: `const vocoder = require('@vocoder/plugin/webpack');\n\nexports.onCreateWebpackConfig = ({ actions }) => {\n actions.setWebpackConfig({\n plugins: [vocoder()],\n });\n};`,\n\t\t\t};\n\n\t\tcase \"angular\":\n\t\t\treturn null; // Angular CLI doesn't expose plugin config easily\n\n\t\tdefault:\n\t\t\t// No known framework — if they have React/Vue/Svelte, they likely have a bundler\n\t\t\t// but we can't guess which config file. Give generic advice.\n\t\t\tif (ecosystem) {\n\t\t\t\treturn {\n\t\t\t\t\tfile: \"your bundler config\",\n\t\t\t\t\tcode: `// Vite\nimport vocoder from '@vocoder/plugin/vite';\n// Webpack\nconst vocoder = require('@vocoder/plugin/webpack');\n\n// Add vocoder() to your plugins array`,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn null;\n\t}\n}\n\nfunction getProviderSnippet(\n\tecosystem: DetectedEcosystem,\n\tsourceLocale: string,\n): { file: string; code: string } | null {\n\tswitch (ecosystem) {\n\t\tcase \"react\":\n\t\t\treturn {\n\t\t\t\tfile: \"your root layout or App component\",\n\t\t\t\tcode: `import { VocoderProvider } from '@vocoder/react';\n\n<VocoderProvider defaultLocale=\"${sourceLocale}\">\n {children}\n</VocoderProvider>`,\n\t\t\t};\n\n\t\tcase \"vue\":\n\t\t\treturn {\n\t\t\t\tfile: \"your app entry\",\n\t\t\t\tcode: `import { createVocoder } from '@vocoder/vue';\n\nconst vocoder = createVocoder({\n defaultLocale: '${sourceLocale}',\n});\n\napp.use(vocoder);`,\n\t\t\t};\n\n\t\tcase \"svelte\":\n\t\t\treturn {\n\t\t\t\tfile: \"your root layout\",\n\t\t\t\tcode: `<script>\n import { VocoderProvider } from '@vocoder/svelte';\n</script>\n\n<VocoderProvider defaultLocale=\"${sourceLocale}\">\n <slot />\n</VocoderProvider>`,\n\t\t\t};\n\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\nfunction getWrapSnippet(ecosystem: DetectedEcosystem): { code: string } {\n\tswitch (ecosystem) {\n\t\tcase \"react\":\n\t\t\treturn {\n\t\t\t\tcode: `import { T } from '@vocoder/react';\n\n<T>Hello, world!</T>`,\n\t\t\t};\n\n\t\tcase \"vue\":\n\t\t\treturn {\n\t\t\t\tcode: `<template>\n <T>Hello, world!</T>\n</template>\n\n<script setup>\nimport { T } from '@vocoder/vue';\n</script>`,\n\t\t\t};\n\n\t\tcase \"svelte\":\n\t\t\treturn {\n\t\t\t\tcode: `<script>\n import { T } from '@vocoder/svelte';\n</script>\n\n<T>Hello, world!</T>`,\n\t\t\t};\n\n\t\tdefault:\n\t\t\treturn {\n\t\t\t\tcode: `// Wrap translatable strings with <T>\n<T>Hello, world!</T>`,\n\t\t\t};\n\t}\n}\n","export { type ExtractedString, StringExtractor } from \"@vocoder/extractor\";\n"],"mappings":";AAAA,SAAS,YAAY,oBAAoB;AACzC,SAAS,YAAY;AAgCd,SAAS,qBACf,MAAc,QAAQ,IAAI,GACH;AACvB,QAAM,iBAAiB,qBAAqB,GAAG;AAC/C,QAAM,MAAM,gBAAgB,GAAG;AAE/B,MAAI,CAAC,KAAK;AACT,WAAO;AAAA,MACN,WAAW;AAAA,MACX,WAAW;AAAA,MACX;AAAA,MACA,WAAW;AAAA,MACX,aAAa;AAAA,MACb,cAAc;AAAA,MACd,WAAW;AAAA,MACX,cAAc;AAAA,MACd,cAAc;AAAA,IACf;AAAA,EACD;AAEA,QAAM,UAAU;AAAA,IACf,GAAK,IAAI,gBAA2C,CAAC;AAAA,IACrD,GAAK,IAAI,mBAA8C,CAAC;AAAA,EACzD;AAEA,QAAM,cAAc,qBAAqB;AACzC,QAAM,eAAe,wBAAwB;AAC7C,QAAM,YAAY,qBAAqB;AAGvC,QAAM,EAAE,WAAW,WAAW,UAAU,IAAI,eAAe,SAAS,GAAG;AACvE,QAAM,eAAe,cAAc,QAAQ,aAAa;AAExD,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc;AAAA,EACf;AACD;AAEA,SAAS,qBAAqB,KAA6B;AAC1D,MAAI,WAAW,KAAK,KAAK,gBAAgB,CAAC,EAAG,QAAO;AACpD,MAAI,WAAW,KAAK,KAAK,WAAW,CAAC,KAAK,WAAW,KAAK,KAAK,UAAU,CAAC;AACzE,WAAO;AACR,MAAI,WAAW,KAAK,KAAK,WAAW,CAAC,EAAG,QAAO;AAC/C,SAAO;AACR;AAEA,SAAS,gBAAgB,KAA6C;AACrE,QAAM,UAAU,KAAK,KAAK,cAAc;AACxC,MAAI,CAAC,WAAW,OAAO,EAAG,QAAO;AACjC,MAAI;AACH,WAAO,KAAK,MAAM,aAAa,SAAS,OAAO,CAAC;AAAA,EAIjD,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAEA,SAAS,eACR,SACA,KAKC;AAED,MAAI,SAAS,SAAS;AACrB,UAAM,YAAY,UAAU,UAAW,SAAmB;AAC1D,WAAO,EAAE,WAAW,OAAO,WAAW,WAAW,eAAe;AAAA,EACjE;AAGA,MAAI,YAAY,SAAS;AACxB,UAAM,YACL,mBAAmB,UAAW,cAAwB;AACvD,WAAO,EAAE,WAAW,UAAU,WAAW,WAAW,kBAAkB;AAAA,EACvE;AAGA,MAAI,mBAAmB,WAAW,WAAW,KAAK,KAAK,cAAc,CAAC,GAAG;AACxE,WAAO;AAAA,MACN,WAAW;AAAA,MACX,WAAW;AAAA,MACX,WAAW;AAAA,IACZ;AAAA,EACD;AAGA,MAAI,WAAW,SAAS;AACvB,QAAI,YAA+B;AACnC,QAAI,UAAU,QAAS,aAAY;AAAA,aAC1B,sBAAsB,QAAS,aAAY;AAAA,aAC3C,YAAY,QAAS,aAAY;AAAA,aACjC,UAAU,QAAS,aAAY;AACxC,WAAO,EAAE,WAAW,SAAS,WAAW,WAAW,iBAAiB;AAAA,EACrE;AAEA,SAAO,EAAE,WAAW,MAAM,WAAW,MAAM,WAAW,KAAK;AAC5D;AAMO,SAAS,oBACf,gBACA,UACA,MAAM,OACG;AACT,MAAI,SAAS,WAAW,EAAG,QAAO;AAClC,QAAM,UAAU,SAAS,KAAK,GAAG;AACjC,QAAM,UAAU,MAAM,QAAQ;AAC9B,UAAQ,gBAAgB;AAAA,IACvB,KAAK;AACJ,aAAO,WAAW,OAAO,IAAI,OAAO;AAAA,IACrC,KAAK;AACJ,aAAO,WAAW,OAAO,IAAI,OAAO;AAAA,IACrC,KAAK;AACJ,aAAO,UAAU,OAAO,IAAI,OAAO;AAAA,IACpC;AACC,aAAO,cAAc,OAAO,IAAI,OAAO;AAAA,EACzC;AACD;AAOO,SAAS,qBAAqB,WAGnC;AACD,QAAM,cAAwB,CAAC;AAC/B,QAAM,kBAA4B,CAAC;AAEnC,MAAI,CAAC,UAAU,YAAa,aAAY,KAAK,iBAAiB;AAC9D,MAAI,CAAC,UAAU,aAAc,aAAY,KAAK,oBAAoB;AAClE,MAAI,CAAC,UAAU,UAAW,aAAY,KAAK,iBAAiB;AAE5D,MAAI,UAAU,aAAa,CAAC,UAAU;AACrC,oBAAgB,KAAK,UAAU,SAAS;AAEzC,SAAO,EAAE,aAAa,gBAAgB;AACvC;;;AC/KO,SAAS,iBAAiB,QAKf;AACjB,QAAM,EAAE,WAAW,WAAW,aAAa,IAAI;AAE/C,SAAO;AAAA,IACN,YAAY,iBAAiB,WAAW,SAAS;AAAA,IACjD,cAAc,mBAAmB,WAAW,YAAY;AAAA,IACxD,UAAU,eAAe,SAAS;AAAA,IAClC,WAAW;AAAA,EACZ;AACD;AAEA,SAAS,iBACR,WACA,WACwC;AACxC,UAAQ,WAAW;AAAA,IAClB,KAAK;AACJ,aAAO;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,MAKP;AAAA,IAED,KAAK;AAAA,IACL,KAAK;AACJ,aAAO;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQP;AAAA,IAED,KAAK;AACJ,aAAO;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOP;AAAA,IAED,KAAK;AACJ,aAAO;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASP;AAAA,IAED,KAAK;AACJ,aAAO;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOP;AAAA,IAED,KAAK;AACJ,aAAO;AAAA;AAAA,IAER;AAGC,UAAI,WAAW;AACd,eAAO;AAAA,UACN,MAAM;AAAA,UACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAMP;AAAA,MACD;AACA,aAAO;AAAA,EACT;AACD;AAEA,SAAS,mBACR,WACA,cACwC;AACxC,UAAQ,WAAW;AAAA,IAClB,KAAK;AACJ,aAAO;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA;AAAA,kCAEwB,YAAY;AAAA;AAAA;AAAA,MAG3C;AAAA,IAED,KAAK;AACJ,aAAO;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA;AAAA;AAAA,oBAGU,YAAY;AAAA;AAAA;AAAA;AAAA,MAI7B;AAAA,IAED,KAAK;AACJ,aAAO;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA;AAAA;AAAA;AAAA,kCAIwB,YAAY;AAAA;AAAA;AAAA,MAG3C;AAAA,IAED;AACC,aAAO;AAAA,EACT;AACD;AAEA,SAAS,eAAe,WAAgD;AACvE,UAAQ,WAAW;AAAA,IAClB,KAAK;AACJ,aAAO;AAAA,QACN,MAAM;AAAA;AAAA;AAAA,MAGP;AAAA,IAED,KAAK;AACJ,aAAO;AAAA,QACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOP;AAAA,IAED,KAAK;AACJ,aAAO;AAAA,QACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,MAKP;AAAA,IAED;AACC,aAAO;AAAA,QACN,MAAM;AAAA;AAAA,MAEP;AAAA,EACF;AACD;;;ACnMA,SAA+B,uBAAuB;","names":[]}
|