@scoutello/i18n-magic 0.15.2 → 0.18.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/README.md +178 -17
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +101 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/check-missing.d.ts +1 -0
- package/dist/commands/check-missing.d.ts.map +1 -0
- package/dist/commands/check-missing.js +13 -0
- package/dist/commands/check-missing.js.map +1 -0
- package/dist/commands/clean.d.ts +3 -0
- package/dist/commands/clean.d.ts.map +1 -0
- package/dist/commands/clean.js +81 -0
- package/dist/commands/clean.js.map +1 -0
- package/dist/commands/create-pruned-namespace-automated.d.ts +20 -0
- package/dist/commands/create-pruned-namespace-automated.d.ts.map +1 -0
- package/dist/commands/create-pruned-namespace-automated.js +98 -0
- package/dist/commands/create-pruned-namespace-automated.js.map +1 -0
- package/dist/commands/create-pruned-namespace.d.ts +3 -0
- package/dist/commands/create-pruned-namespace.d.ts.map +1 -0
- package/dist/commands/create-pruned-namespace.js +122 -0
- package/dist/commands/create-pruned-namespace.js.map +1 -0
- package/dist/commands/replace.d.ts +1 -0
- package/dist/commands/replace.d.ts.map +1 -0
- package/dist/commands/replace.js +58 -0
- package/dist/commands/replace.js.map +1 -0
- package/dist/commands/scan.d.ts +1 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +70 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/sync-locales.d.ts +1 -0
- package/dist/commands/sync-locales.d.ts.map +1 -0
- package/dist/commands/sync-locales.js +78 -0
- package/dist/commands/sync-locales.js.map +1 -0
- package/dist/i18n-magic.cjs.development.js +458 -126
- package/dist/i18n-magic.cjs.development.js.map +1 -1
- package/dist/i18n-magic.cjs.production.min.js +1 -1
- package/dist/i18n-magic.cjs.production.min.js.map +1 -1
- package/dist/i18n-magic.esm.js +449 -126
- package/dist/i18n-magic.esm.js.map +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -9
- package/dist/index.js.map +1 -0
- package/dist/lib/languges.d.ts +1 -0
- package/dist/lib/languges.d.ts.map +1 -0
- package/dist/lib/languges.js +146 -0
- package/dist/lib/languges.js.map +1 -0
- package/dist/lib/types.d.ts +8 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +3 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/utils.d.ts +1 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +220 -0
- package/dist/lib/utils.js.map +1 -0
- package/package.json +37 -14
- package/src/cli.ts +117 -0
- package/src/commands/clean.ts +105 -0
- package/src/commands/create-pruned-namespace-automated.ts +165 -0
- package/src/commands/create-pruned-namespace.ts +165 -0
- package/src/commands/scan.ts +12 -0
- package/src/index.ts +23 -106
- package/src/lib/types.ts +8 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import glob from "fast-glob"
|
|
2
|
+
import { Parser } from "i18next-scanner"
|
|
3
|
+
import fs from "node:fs"
|
|
4
|
+
import type { Configuration } from "../lib/types"
|
|
5
|
+
import {
|
|
6
|
+
getPureKey,
|
|
7
|
+
loadLocalesFile,
|
|
8
|
+
removeDuplicatesFromArray,
|
|
9
|
+
writeLocalesFile,
|
|
10
|
+
} from "../lib/utils"
|
|
11
|
+
|
|
12
|
+
export interface PruneOptions {
|
|
13
|
+
sourceNamespace: string
|
|
14
|
+
newNamespace: string
|
|
15
|
+
globPatterns: string[]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface PruneResult {
|
|
19
|
+
locale: string
|
|
20
|
+
keyCount: number
|
|
21
|
+
success: boolean
|
|
22
|
+
error?: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface PruneResponse {
|
|
26
|
+
success: boolean
|
|
27
|
+
message: string
|
|
28
|
+
keysCount: number
|
|
29
|
+
results?: PruneResult[]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const createPrunedNamespaceAutomated = async (
|
|
33
|
+
config: Configuration,
|
|
34
|
+
options: PruneOptions,
|
|
35
|
+
): Promise<PruneResponse> => {
|
|
36
|
+
const { namespaces, loadPath, savePath, locales, defaultNamespace } = config
|
|
37
|
+
const { sourceNamespace, newNamespace, globPatterns } = options
|
|
38
|
+
|
|
39
|
+
// Validate inputs
|
|
40
|
+
if (!namespaces.includes(sourceNamespace)) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
`Source namespace '${sourceNamespace}' not found in configuration`,
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (namespaces.includes(newNamespace)) {
|
|
47
|
+
throw new Error(`Namespace '${newNamespace}' already exists`)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
console.log(
|
|
51
|
+
`Creating pruned namespace '${newNamespace}' from '${sourceNamespace}'`,
|
|
52
|
+
)
|
|
53
|
+
console.log(`Using glob patterns: ${globPatterns.join(", ")}`)
|
|
54
|
+
|
|
55
|
+
// Extract keys from files matching the glob patterns
|
|
56
|
+
const parser = new Parser({
|
|
57
|
+
nsSeparator: false,
|
|
58
|
+
keySeparator: false,
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
const files = await glob([...globPatterns, "!**/node_modules/**"])
|
|
62
|
+
console.log(`Found ${files.length} files to scan`)
|
|
63
|
+
|
|
64
|
+
const extractedKeys = []
|
|
65
|
+
|
|
66
|
+
for (const file of files) {
|
|
67
|
+
const content = fs.readFileSync(file, "utf-8")
|
|
68
|
+
parser.parseFuncFromString(content, { list: ["t"] }, (key: string) => {
|
|
69
|
+
extractedKeys.push(key)
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const uniqueExtractedKeys = removeDuplicatesFromArray(extractedKeys)
|
|
74
|
+
console.log(`Found ${uniqueExtractedKeys.length} unique translation keys`)
|
|
75
|
+
|
|
76
|
+
// Filter keys that belong to the source namespace
|
|
77
|
+
const relevantKeys = []
|
|
78
|
+
|
|
79
|
+
for (const key of uniqueExtractedKeys) {
|
|
80
|
+
const pureKey = getPureKey(
|
|
81
|
+
key,
|
|
82
|
+
sourceNamespace,
|
|
83
|
+
sourceNamespace === defaultNamespace,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
if (pureKey) {
|
|
87
|
+
relevantKeys.push(pureKey)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
console.log(
|
|
92
|
+
`Found ${relevantKeys.length} keys from namespace '${sourceNamespace}'`,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
if (relevantKeys.length === 0) {
|
|
96
|
+
console.log("No relevant keys found. Exiting...")
|
|
97
|
+
return {
|
|
98
|
+
success: false,
|
|
99
|
+
message: "No relevant keys found",
|
|
100
|
+
keysCount: 0,
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Get translations from source namespace and create new namespace files
|
|
105
|
+
const results: PruneResult[] = []
|
|
106
|
+
|
|
107
|
+
for (const locale of locales) {
|
|
108
|
+
try {
|
|
109
|
+
// Load source namespace translations
|
|
110
|
+
const sourceTranslations = await loadLocalesFile(
|
|
111
|
+
loadPath,
|
|
112
|
+
locale,
|
|
113
|
+
sourceNamespace,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
// Create new namespace with only the keys used in the glob pattern files
|
|
117
|
+
const newNamespaceTranslations: Record<string, string> = {}
|
|
118
|
+
|
|
119
|
+
for (const key of relevantKeys) {
|
|
120
|
+
if (sourceTranslations[key]) {
|
|
121
|
+
newNamespaceTranslations[key] = sourceTranslations[key]
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Write the new namespace file
|
|
126
|
+
await writeLocalesFile(
|
|
127
|
+
savePath,
|
|
128
|
+
locale,
|
|
129
|
+
newNamespace,
|
|
130
|
+
newNamespaceTranslations,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
const keyCount = Object.keys(newNamespaceTranslations).length
|
|
134
|
+
console.log(
|
|
135
|
+
`Created pruned namespace '${newNamespace}' for locale '${locale}' with ${keyCount} keys`,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
results.push({
|
|
139
|
+
locale,
|
|
140
|
+
keyCount,
|
|
141
|
+
success: true,
|
|
142
|
+
})
|
|
143
|
+
} catch (error) {
|
|
144
|
+
console.error(
|
|
145
|
+
`Error creating pruned namespace for locale '${locale}':`,
|
|
146
|
+
error,
|
|
147
|
+
)
|
|
148
|
+
results.push({
|
|
149
|
+
locale,
|
|
150
|
+
keyCount: 0,
|
|
151
|
+
success: false,
|
|
152
|
+
error: error instanceof Error ? error.message : String(error),
|
|
153
|
+
})
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
console.log(`✅ Successfully created pruned namespace '${newNamespace}'`)
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
success: true,
|
|
161
|
+
message: `Created pruned namespace '${newNamespace}' with ${relevantKeys.length} keys`,
|
|
162
|
+
keysCount: relevantKeys.length,
|
|
163
|
+
results,
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import glob from "fast-glob"
|
|
2
|
+
import { Parser } from "i18next-scanner"
|
|
3
|
+
import fs from "node:fs"
|
|
4
|
+
import prompts from "prompts"
|
|
5
|
+
import type { Configuration } from "../lib/types"
|
|
6
|
+
import {
|
|
7
|
+
getPureKey,
|
|
8
|
+
loadLocalesFile,
|
|
9
|
+
removeDuplicatesFromArray,
|
|
10
|
+
writeLocalesFile,
|
|
11
|
+
} from "../lib/utils"
|
|
12
|
+
|
|
13
|
+
export const createPrunedNamespace = async (config: Configuration) => {
|
|
14
|
+
const { namespaces, loadPath, savePath, locales, defaultNamespace } = config
|
|
15
|
+
|
|
16
|
+
// Step 1: Ask for source namespace
|
|
17
|
+
const sourceNamespaceResponse = await prompts({
|
|
18
|
+
type: "select",
|
|
19
|
+
name: "value",
|
|
20
|
+
message: "Select source namespace to create pruned version from:",
|
|
21
|
+
choices: namespaces.map((namespace) => ({
|
|
22
|
+
title: namespace,
|
|
23
|
+
value: namespace,
|
|
24
|
+
})),
|
|
25
|
+
onState: (state) => {
|
|
26
|
+
if (state.aborted) {
|
|
27
|
+
process.nextTick(() => {
|
|
28
|
+
process.exit(0)
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const sourceNamespace = sourceNamespaceResponse.value
|
|
35
|
+
|
|
36
|
+
// Step 2: Ask for new namespace name
|
|
37
|
+
const newNamespaceResponse = await prompts({
|
|
38
|
+
type: "text",
|
|
39
|
+
name: "value",
|
|
40
|
+
message: "Enter the name for the new namespace:",
|
|
41
|
+
validate: (value) => {
|
|
42
|
+
if (!value) return "Namespace name cannot be empty"
|
|
43
|
+
if (namespaces.includes(value)) return "Namespace already exists"
|
|
44
|
+
return true
|
|
45
|
+
},
|
|
46
|
+
onState: (state) => {
|
|
47
|
+
if (state.aborted) {
|
|
48
|
+
process.nextTick(() => {
|
|
49
|
+
process.exit(0)
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const newNamespace = newNamespaceResponse.value
|
|
56
|
+
|
|
57
|
+
// Step 3: Ask for glob patterns to find relevant keys
|
|
58
|
+
const globPatternsResponse = await prompts({
|
|
59
|
+
type: "list",
|
|
60
|
+
name: "value",
|
|
61
|
+
message: "Enter glob patterns to find relevant keys (comma separated):",
|
|
62
|
+
initial: config.globPatterns.join(","),
|
|
63
|
+
separator: ",",
|
|
64
|
+
onState: (state) => {
|
|
65
|
+
if (state.aborted) {
|
|
66
|
+
process.nextTick(() => {
|
|
67
|
+
process.exit(0)
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
const selectedGlobPatterns = globPatternsResponse.value
|
|
74
|
+
|
|
75
|
+
console.log(
|
|
76
|
+
`Finding keys used in files matching: ${selectedGlobPatterns.join(", ")}`,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
// Extract keys from files matching the glob patterns
|
|
80
|
+
const parser = new Parser({
|
|
81
|
+
nsSeparator: false,
|
|
82
|
+
keySeparator: false,
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
const files = await glob([...selectedGlobPatterns, "!**/node_modules/**"])
|
|
86
|
+
console.log(`Found ${files.length} files to scan`)
|
|
87
|
+
|
|
88
|
+
const extractedKeys = []
|
|
89
|
+
|
|
90
|
+
for (const file of files) {
|
|
91
|
+
const content = fs.readFileSync(file, "utf-8")
|
|
92
|
+
parser.parseFuncFromString(content, { list: ["t"] }, (key: string) => {
|
|
93
|
+
extractedKeys.push(key)
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const uniqueExtractedKeys = removeDuplicatesFromArray(extractedKeys)
|
|
98
|
+
console.log(`Found ${uniqueExtractedKeys.length} unique translation keys`)
|
|
99
|
+
|
|
100
|
+
// Filter keys that belong to the source namespace
|
|
101
|
+
const relevantKeys = []
|
|
102
|
+
|
|
103
|
+
for (const key of uniqueExtractedKeys) {
|
|
104
|
+
const pureKey = getPureKey(
|
|
105
|
+
key,
|
|
106
|
+
sourceNamespace,
|
|
107
|
+
sourceNamespace === defaultNamespace,
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
if (pureKey) {
|
|
111
|
+
relevantKeys.push(pureKey)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
console.log(
|
|
116
|
+
`Found ${relevantKeys.length} keys from namespace '${sourceNamespace}'`,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
if (relevantKeys.length === 0) {
|
|
120
|
+
console.log("No relevant keys found. Exiting...")
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Get translations from source namespace and create new namespace files
|
|
125
|
+
for (const locale of locales) {
|
|
126
|
+
try {
|
|
127
|
+
// Load source namespace translations
|
|
128
|
+
const sourceTranslations = await loadLocalesFile(
|
|
129
|
+
loadPath,
|
|
130
|
+
locale,
|
|
131
|
+
sourceNamespace,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
// Create new namespace with only the keys used in the glob pattern files
|
|
135
|
+
const newNamespaceTranslations: Record<string, string> = {}
|
|
136
|
+
|
|
137
|
+
for (const key of relevantKeys) {
|
|
138
|
+
if (sourceTranslations[key]) {
|
|
139
|
+
newNamespaceTranslations[key] = sourceTranslations[key]
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Write the new namespace file
|
|
144
|
+
await writeLocalesFile(
|
|
145
|
+
savePath,
|
|
146
|
+
locale,
|
|
147
|
+
newNamespace,
|
|
148
|
+
newNamespaceTranslations,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
console.log(
|
|
152
|
+
`Created pruned namespace '${newNamespace}' for locale '${locale}' with ${
|
|
153
|
+
Object.keys(newNamespaceTranslations).length
|
|
154
|
+
} keys`,
|
|
155
|
+
)
|
|
156
|
+
} catch (error) {
|
|
157
|
+
console.error(
|
|
158
|
+
`Error creating pruned namespace for locale '${locale}':`,
|
|
159
|
+
error,
|
|
160
|
+
)
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
console.log(`✅ Successfully created pruned namespace '${newNamespace}'`)
|
|
165
|
+
}
|
package/src/commands/scan.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import console from "console"
|
|
1
2
|
import type { Configuration } from "../lib/types"
|
|
2
3
|
import {
|
|
3
4
|
checkAllKeysExist,
|
|
@@ -7,6 +8,7 @@ import {
|
|
|
7
8
|
translateKey,
|
|
8
9
|
writeLocalesFile,
|
|
9
10
|
} from "../lib/utils"
|
|
11
|
+
import { removeUnusedKeys } from "./clean"
|
|
10
12
|
|
|
11
13
|
export const translateMissing = async (config: Configuration) => {
|
|
12
14
|
const {
|
|
@@ -18,8 +20,18 @@ export const translateMissing = async (config: Configuration) => {
|
|
|
18
20
|
context,
|
|
19
21
|
openai,
|
|
20
22
|
disableTranslation,
|
|
23
|
+
autoClear,
|
|
21
24
|
} = config
|
|
22
25
|
|
|
26
|
+
// Run clean command first if autoClear is enabled
|
|
27
|
+
if (autoClear) {
|
|
28
|
+
console.log("🧹 Auto-clearing unused translations before scanning...")
|
|
29
|
+
await removeUnusedKeys(config)
|
|
30
|
+
console.log(
|
|
31
|
+
"✅ Auto-clear completed. Now scanning for missing translations...\n",
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
23
35
|
const newKeys = await getMissingKeys(config)
|
|
24
36
|
|
|
25
37
|
if (newKeys.length === 0) {
|
package/src/index.ts
CHANGED
|
@@ -1,106 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const commands: CommandType[] = [
|
|
25
|
-
{
|
|
26
|
-
name: "scan",
|
|
27
|
-
description:
|
|
28
|
-
"Scan for missing translations, get prompted for each, translate it to the other locales and save it to the JSON file.",
|
|
29
|
-
action: translateMissing,
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
name: "replace",
|
|
33
|
-
description:
|
|
34
|
-
"Replace a translation based on the key, and translate it to the other locales and save it to the JSON file.",
|
|
35
|
-
action: replaceTranslation,
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
name: "check-missing",
|
|
39
|
-
description:
|
|
40
|
-
"Check if there are any missing translations. Useful for a CI/CD pipeline or husky hook.",
|
|
41
|
-
action: checkMissing,
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
name: "sync",
|
|
45
|
-
description:
|
|
46
|
-
"Sync the translations from the default locale to the other locales. Useful for a CI/CD pipeline or husky hook.",
|
|
47
|
-
action: syncLocales,
|
|
48
|
-
},
|
|
49
|
-
]
|
|
50
|
-
|
|
51
|
-
for (const command of commands) {
|
|
52
|
-
const cmd = program.command(command.name).description(command.description)
|
|
53
|
-
|
|
54
|
-
// Add key option to replace command
|
|
55
|
-
if (command.name === "replace") {
|
|
56
|
-
cmd
|
|
57
|
-
.option("-k, --key <key>", "translation key to replace")
|
|
58
|
-
.allowExcessArguments(true)
|
|
59
|
-
.argument("[key]", "translation key to replace")
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
cmd.action(async (arg, options) => {
|
|
63
|
-
const res = dotenv.config({
|
|
64
|
-
path: program.opts().env || ".env",
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
const config: Configuration = await loadConfig({
|
|
68
|
-
configPath: program.opts().config,
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
const isGemini = (config.model as string)?.includes("gemini")
|
|
72
|
-
|
|
73
|
-
// Get API key from environment or config
|
|
74
|
-
const openaiKey = res.parsed.OPENAI_API_KEY || config.OPENAI_API_KEY
|
|
75
|
-
const geminiKey = res.parsed.GEMINI_API_KEY || config.GEMINI_API_KEY
|
|
76
|
-
|
|
77
|
-
// Select appropriate key based on model type
|
|
78
|
-
const key = isGemini ? geminiKey : openaiKey
|
|
79
|
-
|
|
80
|
-
if (!key) {
|
|
81
|
-
const keyType = isGemini ? "GEMINI_API_KEY" : "OPENAI_API_KEY"
|
|
82
|
-
console.error(
|
|
83
|
-
`Please provide a${isGemini ? " Gemini" : "n OpenAI"} API key in your .env file or config, called ${keyType}.`,
|
|
84
|
-
)
|
|
85
|
-
process.exit(1)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const openai = new OpenAI({
|
|
89
|
-
apiKey: key,
|
|
90
|
-
...(isGemini && {
|
|
91
|
-
baseURL: "https://generativelanguage.googleapis.com/v1beta/openai/",
|
|
92
|
-
}),
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
// For replace command, check for key in argument or option
|
|
96
|
-
if (command.name === "replace") {
|
|
97
|
-
// If key is provided as positional argument, use that first
|
|
98
|
-
const keyToUse = typeof arg === "string" ? arg : options.key
|
|
99
|
-
command.action({ ...config, openai }, keyToUse)
|
|
100
|
-
} else {
|
|
101
|
-
command.action({ ...config, openai })
|
|
102
|
-
}
|
|
103
|
-
})
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
program.parse(process.argv)
|
|
1
|
+
// Export command functions for programmatic usage
|
|
2
|
+
export { checkMissing } from "./commands/check-missing"
|
|
3
|
+
export { removeUnusedKeys } from "./commands/clean"
|
|
4
|
+
export { createPrunedNamespace } from "./commands/create-pruned-namespace"
|
|
5
|
+
export { createPrunedNamespaceAutomated } from "./commands/create-pruned-namespace-automated"
|
|
6
|
+
export { replaceTranslation } from "./commands/replace"
|
|
7
|
+
export { translateMissing } from "./commands/scan"
|
|
8
|
+
export { syncLocales } from "./commands/sync-locales"
|
|
9
|
+
|
|
10
|
+
// Export utility functions
|
|
11
|
+
export { loadConfig } from "./lib/utils"
|
|
12
|
+
|
|
13
|
+
// Export types
|
|
14
|
+
export type {
|
|
15
|
+
PruneOptions,
|
|
16
|
+
PruneResponse,
|
|
17
|
+
PruneResult,
|
|
18
|
+
} from "./commands/create-pruned-namespace-automated"
|
|
19
|
+
export type {
|
|
20
|
+
CommandType,
|
|
21
|
+
Configuration,
|
|
22
|
+
NamespacePruneConfig,
|
|
23
|
+
} from "./lib/types"
|
package/src/lib/types.ts
CHANGED
|
@@ -7,6 +7,12 @@ type Model =
|
|
|
7
7
|
| "gemini-2.0-flash"
|
|
8
8
|
| "gemini-2.0-flash-lite"
|
|
9
9
|
|
|
10
|
+
export interface NamespacePruneConfig {
|
|
11
|
+
sourceNamespace: string
|
|
12
|
+
newNamespace: string
|
|
13
|
+
globPatterns: string[]
|
|
14
|
+
}
|
|
15
|
+
|
|
10
16
|
export interface Configuration {
|
|
11
17
|
loadPath:
|
|
12
18
|
| string
|
|
@@ -25,10 +31,12 @@ export interface Configuration {
|
|
|
25
31
|
globPatterns: string[]
|
|
26
32
|
context?: string
|
|
27
33
|
disableTranslation?: boolean
|
|
34
|
+
autoClear?: boolean
|
|
28
35
|
OPENAI_API_KEY?: string
|
|
29
36
|
GEMINI_API_KEY?: string
|
|
30
37
|
model?: Model
|
|
31
38
|
openai?: OpenAI
|
|
39
|
+
pruneNamespaces?: NamespacePruneConfig[]
|
|
32
40
|
}
|
|
33
41
|
|
|
34
42
|
export interface CommandType {
|