@brickflow/cli 0.0.29 → 0.0.31

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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # @brickflow/cli
2
2
 
3
+ ## 0.0.31
4
+
5
+ ### Patch Changes
6
+
7
+ - Translation folders migration
8
+
9
+ ## 0.0.30
10
+
11
+ ### Patch Changes
12
+
13
+ - Unlink lint tailwind if not path
14
+
3
15
  ## 0.0.29
4
16
 
5
17
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brickflow/cli",
3
- "version": "0.0.29",
3
+ "version": "0.0.31",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "index.mjs",
@@ -58,7 +58,7 @@ function buildContents(strings, sourceLocale, targetLocales, componentContext) {
58
58
  }
59
59
 
60
60
  function buildSystemInstruction() {
61
- const { productContext, terminology, tone } = getTranslateRuntimeConfig()
61
+ const { productContext } = getTranslateRuntimeConfig()
62
62
 
63
63
  return [
64
64
  'You are a professional localization engine for a paid adult content platform.',
@@ -66,12 +66,6 @@ function buildSystemInstruction() {
66
66
  'PRODUCT CONTEXT:',
67
67
  productContext,
68
68
  '',
69
- 'TERMINOLOGY:',
70
- terminology,
71
- '',
72
- 'TONE:',
73
- tone,
74
- '',
75
69
  'RULES:',
76
70
  '- Return only raw JSON.',
77
71
  '- Preserve JSON shape exactly.',
@@ -1,9 +1,8 @@
1
1
  import fs from 'fs'
2
- import { globSync } from 'glob'
3
2
  import { dirname, join, relative } from 'path'
4
3
 
5
4
  import { resolveWorkspaceRoot } from '../shared/workspace-root.js'
6
- import { getAiContextState } from './ai-context.js'
5
+ import { getContextFilePath, readAiContextDescription } from '../translate-context/ai-context.js'
7
6
  import { translateBatch } from './ai.js'
8
7
  import { buildTranslateHelp, parseTranslateRuntimeArgs, setTranslateRuntimeConfig } from './runtime-config.js'
9
8
  import { listTranslationTargets, sortObjectKeys, stringifySortedJson } from './utils.js'
@@ -17,9 +16,11 @@ if (rawArgs.includes('--help') || rawArgs.includes('-h')) {
17
16
  }
18
17
 
19
18
  const { options } = parseTranslateRuntimeArgs(rawArgs)
19
+ let requestedLanguageCodes
20
20
 
21
21
  try {
22
22
  setTranslateRuntimeConfig(options)
23
+ requestedLanguageCodes = parseLanguageCodes(options.locales)
23
24
  } catch (error) {
24
25
  console.error(error instanceof Error ? error.message : String(error))
25
26
  console.error('')
@@ -27,45 +28,9 @@ try {
27
28
  process.exit(1)
28
29
  }
29
30
 
30
- const DEFAULT_LANGUAGE_CODES = [
31
- 'bn',
32
- 'cz',
33
- 'dk',
34
- 'de',
35
- 'en',
36
- 'es',
37
- 'fi',
38
- 'fr',
39
- 'hi',
40
- 'hu',
41
- 'it',
42
- 'ja',
43
- 'nl',
44
- 'no',
45
- 'pl',
46
- 'pt',
47
- 'ru',
48
- 'si',
49
- 'se',
50
- 'sk',
51
- ]
52
31
  const BATCH_MAX_ITEMS = readPositiveInt('TRANSLATE_BATCH_MAX_ITEMS', 30)
53
32
  const BATCH_MAX_CHARS = readPositiveInt('TRANSLATE_BATCH_MAX_CHARS', 3500)
54
- const languagePaths = globSync(
55
- '{packages/brick,apps/*}/{components/**/translate,pages-translate/*,layouts/**,global/*}/generated/*.json',
56
- {
57
- absolute: true,
58
- cwd: workspaceRoot,
59
- ignore: ['**/node_modules/**', '**/.nuxt/**', '**/dist/**', '**/.output/**', '**/coverage/**', '**/public/**'],
60
- },
61
- ).sort()
62
-
63
- const languageCodes = [
64
- ...new Set([
65
- ...languagePaths.map((filePath) => filePath.replace(/.*\/([^/]+)\.json$/, '$1')),
66
- ...DEFAULT_LANGUAGE_CODES,
67
- ]),
68
- ].sort()
33
+ const languageCodes = requestedLanguageCodes
69
34
 
70
35
  const tasks = listTranslationTargets(workspaceRoot).map(({ samplePath, sourceFilePath }) => ({
71
36
  sample: readJson(samplePath),
@@ -141,25 +106,52 @@ function normalizeEol(content) {
141
106
  return String(content).replace(/\r\n/g, '\n')
142
107
  }
143
108
 
144
- async function processSample({ sample, samplePath, sourceFilePath }) {
109
+ function parseLanguageCodes(value) {
110
+ if (value === undefined || value === null) {
111
+ throw new Error('Missing required translate option: --locales')
112
+ }
113
+
114
+ const localeCodes = [
115
+ ...new Set(
116
+ String(value)
117
+ .split(/[\s,]+/)
118
+ .filter(Boolean),
119
+ ),
120
+ ].map((code) => code.toLowerCase())
121
+
122
+ if (localeCodes.length === 0 || localeCodes.some((code) => !/^[a-z]{2,3}(?:-[a-z0-9]{2,8})*$/.test(code))) {
123
+ throw new Error(
124
+ 'Invalid --locales value. Use comma-separated locale codes, for example: --locales en,pl,ru,de',
125
+ )
126
+ }
127
+
128
+ if (!localeCodes.includes('en')) {
129
+ throw new Error('Missing required locale: en. Add it to --locales, for example: --locales en,pl,ru,de')
130
+ }
131
+
132
+ return localeCodes.sort()
133
+ }
134
+
135
+ async function processSample({ sample, samplePath }) {
136
+ const componentContext = readAiContextDescription(samplePath)
137
+
138
+ if (!componentContext) {
139
+ throw new Error(
140
+ `Missing AI context: ${relative(workspaceRoot, getContextFilePath(samplePath))}. Run "brick translate-context" first.`,
141
+ )
142
+ }
143
+
145
144
  writeSortedJsonIfNeeded(samplePath, sample)
146
145
 
147
- const generatedDir = join(dirname(samplePath), 'generated')
148
- const enPath = join(generatedDir, 'en.json')
149
- const currentEn = existsJson(enPath) ? readJson(enPath) : {}
146
+ const dataPath = join(dirname(samplePath), 'data.json')
147
+ const currentData = existsJson(dataPath) ? readJson(dataPath) : {}
148
+ const currentEn = currentData.en ?? {}
150
149
  const currentByLanguage = new Map(
151
- languageCodes.map((languageCode) => [
152
- languageCode,
153
- existsJson(join(generatedDir, `${languageCode}.json`))
154
- ? readJson(join(generatedDir, `${languageCode}.json`))
155
- : {},
156
- ]),
150
+ languageCodes.map((languageCode) => [languageCode, currentData[languageCode] ?? {}]),
157
151
  )
158
152
  const resultByLanguage = new Map(languageCodes.map((languageCode) => [languageCode, {}]))
159
153
  const pendingEntriesByLocales = new Map()
160
154
 
161
- fs.mkdirSync(generatedDir, { recursive: true })
162
-
163
155
  for (const [key, sampleValue] of Object.entries(sample)) {
164
156
  const missingLocales = []
165
157
 
@@ -201,15 +193,6 @@ async function processSample({ sample, samplePath, sourceFilePath }) {
201
193
  }
202
194
  }
203
195
 
204
- let componentContext = null
205
-
206
- if (pendingEntriesByLocales.size > 0) {
207
- componentContext = getAiContextState({
208
- samplePath,
209
- sourceFilePath,
210
- }).description
211
- }
212
-
213
196
  for (const [localeKey, entries] of pendingEntriesByLocales) {
214
197
  const targetLocales = localeKey.split(',').filter(Boolean)
215
198
  const chunks = splitIntoBatches(entries, BATCH_MAX_ITEMS, BATCH_MAX_CHARS)
@@ -243,11 +226,13 @@ async function processSample({ sample, samplePath, sourceFilePath }) {
243
226
  }
244
227
  }
245
228
 
229
+ const nextData = {}
230
+
246
231
  for (const languageCode of languageCodes) {
247
- const generatedPath = join(generatedDir, `${languageCode}.json`)
248
- const languageResult = sortObjectKeys(resultByLanguage.get(languageCode) ?? {})
249
- writeTextPreservingEol(generatedPath, stringifySortedJson(languageResult))
232
+ nextData[languageCode] = sortObjectKeys(resultByLanguage.get(languageCode) ?? {})
250
233
  }
234
+
235
+ writeTextPreservingEol(dataPath, stringifySortedJson(nextData))
251
236
  }
252
237
 
253
238
  function readJson(filePath) {
@@ -2,32 +2,29 @@ export const DEFAULT_CONTEXT_MODEL = 'gemini-3.1-flash-lite-preview'
2
2
 
3
3
  let runtimeConfig = null
4
4
 
5
- export function buildTranslateHelp(command = 'brick translate') {
5
+ export function buildTranslateHelp(command = 'brick translate', { includeLocales = true } = {}) {
6
+ const localesRequired = includeLocales ? '\n --locales "en,pl,ru,de"' : ''
7
+ const localesExample = includeLocales ? ' --locales "en,pl,ru,de" \\\n' : ''
8
+
6
9
  return `${command}
7
10
 
8
11
  Required options:
9
12
  --product-context "<text>"
10
- --terminology "<text>"
11
- --tone "<text>"
12
- --api-key "<key>"
13
+ --api-key "<key>"${localesRequired}
13
14
 
14
15
  Optional:
15
16
  --context-model "<model>" Default: ${DEFAULT_CONTEXT_MODEL}
16
17
 
17
18
  Example:
18
19
  ${command} \\
19
- --product-context "Creators sell adult content packs with free previews and paid unlocks." \\
20
- --terminology "Bundle=content pack; Unlock=paid access; VIP=premium content" \\
21
- --tone "Natural, modern, conversion-oriented, explicit when source is explicit." \\
20
+ --product-context "Creators sell goods packs." \\
22
21
  --api-key "your-gemini-api-key" \\
23
- --context-model "${DEFAULT_CONTEXT_MODEL}"`
22
+ ${localesExample} --context-model "${DEFAULT_CONTEXT_MODEL}"`
24
23
  }
25
24
 
26
25
  export function getTranslateRuntimeConfig() {
27
26
  if (!runtimeConfig) {
28
- throw new Error(
29
- 'Translate runtime config is not initialized. Pass --product-context, --terminology, --tone, and --api-key.',
30
- )
27
+ throw new Error('Translate runtime config is not initialized. Pass --product-context and --api-key.')
31
28
  }
32
29
 
33
30
  return runtimeConfig
@@ -37,9 +34,8 @@ export function parseTranslateRuntimeArgs(rawArgs) {
37
34
  const options = {
38
35
  apiKey: null,
39
36
  contextModel: DEFAULT_CONTEXT_MODEL,
37
+ locales: undefined,
40
38
  productContext: null,
41
- terminology: null,
42
- tone: null,
43
39
  }
44
40
  const positional = []
45
41
 
@@ -52,18 +48,6 @@ export function parseTranslateRuntimeArgs(rawArgs) {
52
48
  continue
53
49
  }
54
50
 
55
- if (value === '--terminology') {
56
- options.terminology = rawArgs[index + 1] ?? null
57
- index += 1
58
- continue
59
- }
60
-
61
- if (value === '--tone') {
62
- options.tone = rawArgs[index + 1] ?? null
63
- index += 1
64
- continue
65
- }
66
-
67
51
  if (value === '--api-key') {
68
52
  options.apiKey = rawArgs[index + 1] ?? null
69
53
  index += 1
@@ -76,6 +60,12 @@ export function parseTranslateRuntimeArgs(rawArgs) {
76
60
  continue
77
61
  }
78
62
 
63
+ if (value === '--locales') {
64
+ options.locales = rawArgs[index + 1] ?? null
65
+ index += 1
66
+ continue
67
+ }
68
+
79
69
  positional.push(value)
80
70
  }
81
71
 
@@ -100,14 +90,6 @@ export function validateTranslateRuntimeConfig(config) {
100
90
  missing.push('--product-context')
101
91
  }
102
92
 
103
- if (!config.terminology) {
104
- missing.push('--terminology')
105
- }
106
-
107
- if (!config.tone) {
108
- missing.push('--tone')
109
- }
110
-
111
93
  if (!config.apiKey) {
112
94
  missing.push('--api-key')
113
95
  }
@@ -19,7 +19,7 @@ const IGNORED_GLOB_PATTERNS = [
19
19
  ]
20
20
  const IGNORED_SOURCE_SEGMENTS = ['/node_modules/', '/.nuxt/', '/dist/', '/.output/', '/coverage/', '/public/']
21
21
  const TRANSLATION_SAMPLE_GLOB =
22
- '{packages/brick,apps/*}/{components/**/translate,pages-translate/*,layouts/**,global/*}/sample.json'
22
+ '{packages/brick,apps/*}/{components/**/translate,pages-translate/*,layouts-translate/**,script-translate/*}/sample.json'
23
23
 
24
24
  export function compileVueToJS(code, filePath) {
25
25
  const { descriptor } = parseSFC(code)
@@ -171,6 +171,10 @@ export function getTranslationPaths(id) {
171
171
  /\.(?:js|ts)$/.test(normalizedId) &&
172
172
  !normalizedId.endsWith('.d.ts')
173
173
 
174
+ if (isComponent && !normalizedId.endsWith('/index.vue')) {
175
+ return null
176
+ }
177
+
174
178
  if (!isComponent && !isPage && !isLayout && !isScript) {
175
179
  return null
176
180
  }
@@ -204,13 +208,9 @@ export function getTranslationPaths(id) {
204
208
  }
205
209
 
206
210
  if (isLayout) {
207
- const layoutDir = normalizedId.split('/').slice(0, -1).join('/')
208
- const fileName =
209
- normalizedId
210
- .split('/')
211
- .pop()
212
- ?.replace(/\.\w+$/, '') ?? ''
213
- const baseDir = join(layoutDir, fileName)
211
+ const layoutsRoot = `${normalizedId.split('/layouts/')[0]}/layouts`
212
+ const layoutPath = normalizedId.split('/layouts/')[1].replace(/\.\w+$/, '')
213
+ const baseDir = join(layoutsRoot, '..', 'layouts-translate', layoutPath)
214
214
 
215
215
  return {
216
216
  baseDir,
@@ -222,7 +222,7 @@ export function getTranslationPaths(id) {
222
222
  }
223
223
  }
224
224
 
225
- const baseDir = join(projectRoot, 'global', getComponentName(normalizedId))
225
+ const baseDir = join(projectRoot, 'script-translate', getComponentName(normalizedId))
226
226
 
227
227
  return {
228
228
  baseDir,
@@ -1,27 +1,30 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import fs from 'fs'
4
+ import { globSync } from 'glob'
4
5
  import { dirname, join, relative, resolve } from 'path'
5
6
  import { fileURLToPath } from 'url'
6
7
 
7
8
  import { resolveWorkspaceRoot } from '../shared/workspace-root.js'
8
- import { generateContentWithLimits } from './gemini.js'
9
+ import { generateContentWithLimits } from '../translate/gemini.js'
9
10
  import {
10
11
  buildTranslateHelp,
11
12
  DEFAULT_CONTEXT_MODEL,
12
13
  getTranslateRuntimeConfig,
13
14
  parseTranslateRuntimeArgs,
14
15
  setTranslateRuntimeConfig,
15
- } from './runtime-config.js'
16
- import { listTranslationTargets, stringifySortedJson } from './utils.js'
16
+ } from '../translate/runtime-config.js'
17
+ import { listTranslationTargets, stringifySortedJson } from '../translate/utils.js'
17
18
 
18
19
  const workspaceRoot = resolveWorkspaceRoot()
19
20
  const CONTEXT_FILE_NAME = 'ai-context.json'
21
+ const CONTEXT_FILE_GLOB =
22
+ '{packages/brick,apps/*}/{components/**/translate,pages-translate/*,layouts-translate/**,script-translate/*}/ai-context.json'
20
23
  const CHANGE_THRESHOLD = readFloat('TRANSLATE_CONTEXT_MIN_CHANGE', 0.3)
21
24
  const SOURCE_MAX_CHARS = readPositiveInt('TRANSLATE_CONTEXT_SOURCE_MAX_CHARS', 16000)
22
25
 
23
26
  export function buildAiContextHelp(command = 'brick translate-context') {
24
- return `${buildTranslateHelp(command)}\n\nExtra:\n --force`
27
+ return `${buildTranslateHelp(command, { includeLocales: false })}\n\nExtra:\n --force`
25
28
  }
26
29
 
27
30
  export function calculateChangeRatio(previousSource, nextSource) {
@@ -55,13 +58,8 @@ export async function ensureAiContext({ force = false, sample, samplePath, sourc
55
58
  })
56
59
 
57
60
  const next = {
58
- changeRatio: state.changeRatio,
59
61
  description,
60
- samplePath: relative(workspaceRoot, samplePath),
61
- sourceFilePath: relative(workspaceRoot, state.sourceFilePath),
62
62
  sourceSnapshot: state.sourceCode,
63
- updatedAt: new Date().toISOString(),
64
- version: 1,
65
63
  }
66
64
 
67
65
  writeTextPreservingEol(state.contextPath, stringifySortedJson(next))
@@ -116,6 +114,30 @@ export function getContextFilePath(samplePath) {
116
114
  return join(dirname(samplePath), CONTEXT_FILE_NAME)
117
115
  }
118
116
 
117
+ export function readAiContextDescription(samplePath) {
118
+ const description = readContextFile(getContextFilePath(samplePath))?.description
119
+
120
+ return typeof description === 'string' && description.length > 0 ? description : null
121
+ }
122
+
123
+ export function removeObsoleteAiContexts(targets, rootDir = workspaceRoot) {
124
+ const activeContextPaths = new Set(targets.map(({ samplePath }) => getContextFilePath(samplePath)))
125
+ const contextPaths = globSync(CONTEXT_FILE_GLOB, {
126
+ absolute: true,
127
+ cwd: rootDir,
128
+ nodir: true,
129
+ }).sort()
130
+
131
+ for (const contextPath of contextPaths) {
132
+ if (activeContextPaths.has(contextPath)) {
133
+ continue
134
+ }
135
+
136
+ fs.rmSync(contextPath)
137
+ console.log(`šŸ—‘ļø Context removed (sample not found): ${relative(rootDir, contextPath)}`)
138
+ }
139
+ }
140
+
119
141
  export async function runAiContextCli(rawArgs = process.argv.slice(3), command = 'brick translate-context') {
120
142
  const helpText = buildAiContextHelp(command)
121
143
 
@@ -144,22 +166,41 @@ export async function runAiContextCli(rawArgs = process.argv.slice(3), command =
144
166
  ? targets.filter(({ samplePath }) => requestedSamplePaths.has(samplePath))
145
167
  : targets
146
168
 
169
+ if (!requestedSamplePaths) {
170
+ removeObsoleteAiContexts(targets)
171
+ }
172
+
173
+ const progress = createProgress(targetEntries.length)
174
+
147
175
  for (const { samplePath, sourceFilePath } of targetEntries) {
148
176
  if (!sourceFilePath || !fs.existsSync(samplePath)) {
177
+ console.warn(`āš ļø Context skipped (source not found): ${relative(workspaceRoot, samplePath)}`)
178
+ progress(samplePath, 'skipped')
179
+ continue
180
+ }
181
+
182
+ const state = getAiContextState({ force, samplePath, sourceFilePath })
183
+
184
+ if (!state.shouldRegenerate) {
185
+ progress(samplePath, 'unchanged')
149
186
  continue
150
187
  }
151
188
 
152
- const description = await ensureAiContext({
189
+ await ensureAiContext({
153
190
  force,
154
191
  sample: JSON.parse(fs.readFileSync(samplePath, 'utf-8')),
155
192
  samplePath,
156
193
  sourceFilePath,
157
194
  })
158
195
 
159
- if (description) {
160
- console.log(`🧠 Context updated: ${relative(workspaceRoot, samplePath)}`)
161
- }
196
+ progress(samplePath, 'updated')
162
197
  }
198
+
199
+ if (targetEntries.length > 0) {
200
+ process.stdout.write('\n')
201
+ }
202
+
203
+ console.log(`āœ… Done: ${targetEntries.length} context files`)
163
204
  }
164
205
 
165
206
  function buildContextContents({ sampleEntries, samplePath, sourceCode, sourceFilePath }) {
@@ -176,23 +217,19 @@ function buildContextContents({ sampleEntries, samplePath, sourceCode, sourceFil
176
217
  }
177
218
 
178
219
  function buildContextSystemInstruction() {
179
- const { productContext, terminology, tone } = getTranslateRuntimeConfig()
220
+ const { productContext } = getTranslateRuntimeConfig()
180
221
 
181
222
  return [
182
223
  'You are generating translation context for a UI component.',
183
224
  'Write a compact but informative description for translators.',
184
225
  'Product context:',
185
226
  productContext,
186
- 'Terminology:',
187
- terminology,
188
- 'Tone:',
189
- tone,
190
227
  'Focus on:',
191
228
  '- what the component or page does',
192
229
  '- main user actions',
193
230
  '- important entities and domain meaning',
194
231
  '- what the shown strings likely refer to',
195
- '- tone or UX intent if obvious',
232
+ '- UX intent if obvious',
196
233
  'Rules:',
197
234
  '- Return plain text only.',
198
235
  '- Write 4 to 8 short sentences.',
@@ -209,6 +246,28 @@ function cleanText(text) {
209
246
  .trim()
210
247
  }
211
248
 
249
+ function createProgress(total) {
250
+ let done = 0
251
+ const start = Date.now()
252
+
253
+ return function update(samplePath, status) {
254
+ done += 1
255
+
256
+ const percent = total === 0 ? 100 : Math.round((done * 100) / total)
257
+ const filled = Math.round(percent / 5)
258
+ const empty = 20 - filled
259
+ const elapsed = ((Date.now() - start) / 1000).toFixed(1)
260
+ const shortName = shortenPath(relative(workspaceRoot, samplePath))
261
+
262
+ process.stdout.write(
263
+ `\r🧠 Context: [${'ā–ˆ'.repeat(filled)}${' '.repeat(empty)}] ` +
264
+ `${percent}% (${done}/${total}) ` +
265
+ `ā± ${elapsed}s ` +
266
+ `\x1b[90m${status} ${shortName}\x1b[0m\x1b[K`,
267
+ )
268
+ }
269
+ }
270
+
212
271
  function detectEol(filePath) {
213
272
  if (!fs.existsSync(filePath)) {
214
273
  return '\n'
@@ -301,6 +360,14 @@ function readPositiveInt(name, fallback) {
301
360
  return Number.isFinite(value) && value > 0 ? value : fallback
302
361
  }
303
362
 
363
+ function shortenPath(filePath, maxLength = 72) {
364
+ if (filePath.length <= maxLength) {
365
+ return filePath
366
+ }
367
+
368
+ return `...${filePath.slice(-(maxLength - 3))}`
369
+ }
370
+
304
371
  function writeTextPreservingEol(filePath, content) {
305
372
  const eol = detectEol(filePath)
306
373
  const normalized = String(content).replace(/\r?\n/g, eol)
@@ -308,5 +375,5 @@ function writeTextPreservingEol(filePath, content) {
308
375
  }
309
376
 
310
377
  if (process.argv[1] === fileURLToPath(import.meta.url)) {
311
- await runAiContextCli(process.argv.slice(2), 'node packages/cli/src/translate/ai-context.js')
378
+ await runAiContextCli(process.argv.slice(2), 'node packages/cli/src/translate-context/ai-context.js')
312
379
  }
@@ -1,3 +1,3 @@
1
- import { runAiContextCli } from '../translate/ai-context.js'
1
+ import { runAiContextCli } from './ai-context.js'
2
2
 
3
3
  await runAiContextCli(process.argv.slice(3))
@@ -26,11 +26,11 @@ if (args.length > 0) {
26
26
  }
27
27
 
28
28
  const workspaceRoot = resolveWorkspaceRoot()
29
- const activeGeneratedDirs = new Set()
29
+ const activeTranslationDirs = new Set()
30
30
  const cleanupRoots = new Set()
31
31
  const staticCleanupRoots = [
32
- path.resolve(workspaceRoot, 'packages/brick/global'),
33
- ...globSync('apps/*/global', {
32
+ path.resolve(workspaceRoot, 'packages/brick/script-translate'),
33
+ ...globSync('apps/*/script-translate', {
34
34
  absolute: true,
35
35
  cwd: workspaceRoot,
36
36
  }),
@@ -52,12 +52,12 @@ for (const file of filtered) {
52
52
  progress(file)
53
53
  }
54
54
 
55
- cleanupGeneratedDirs()
55
+ cleanupTranslationDirs()
56
56
 
57
57
  process.stdout.write('\n')
58
58
  console.log('āœ… Done')
59
59
 
60
- function cleanupGeneratedDirs() {
60
+ function cleanupTranslationDirs() {
61
61
  for (const rootDir of cleanupRoots) {
62
62
  if (!fs.existsSync(rootDir)) {
63
63
  continue
@@ -70,7 +70,7 @@ function cleanupGeneratedDirs() {
70
70
 
71
71
  const targetDir = path.resolve(rootDir, entry.name)
72
72
 
73
- if (!activeGeneratedDirs.has(targetDir)) {
73
+ if (!activeTranslationDirs.has(targetDir)) {
74
74
  removeDir(targetDir)
75
75
  }
76
76
  }
@@ -127,16 +127,7 @@ function ensureSortedJsonFile(filePath) {
127
127
  }
128
128
 
129
129
  function ensureSortedTranslationJsons(baseDir, samplePath) {
130
- const filesToCheck = [samplePath, path.resolve(baseDir, 'ai-context.json')]
131
- const generatedDir = path.resolve(baseDir, 'generated')
132
-
133
- if (fs.existsSync(generatedDir)) {
134
- for (const entry of fs.readdirSync(generatedDir, { withFileTypes: true })) {
135
- if (entry.isFile() && entry.name.endsWith('.json')) {
136
- filesToCheck.push(path.resolve(generatedDir, entry.name))
137
- }
138
- }
139
- }
130
+ const filesToCheck = [samplePath, path.resolve(baseDir, 'ai-context.json'), path.resolve(baseDir, 'data.json')]
140
131
 
141
132
  for (const filePath of filesToCheck) {
142
133
  try {
@@ -165,7 +156,7 @@ Usage:
165
156
 
166
157
  Notes:
167
158
  Scans source files and regenerates translation sample.json files
168
- Removes obsolete generated translation directories
159
+ Removes obsolete translation directories
169
160
  Verifies and normalizes translation JSON key ordering`)
170
161
  }
171
162
 
@@ -241,7 +232,7 @@ function writeTranslations(id, strings) {
241
232
  }
242
233
 
243
234
  if (isPage || isLayout || isScript) {
244
- activeGeneratedDirs.add(baseDir)
235
+ activeTranslationDirs.add(baseDir)
245
236
  }
246
237
 
247
238
  fs.mkdirSync(baseDir, { recursive: true })