i18next-cli 1.24.13 → 1.24.15
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/dist/cjs/cli.js +1 -1
- package/dist/cjs/rename-key.js +1 -1
- package/dist/esm/cli.js +1 -1
- package/dist/esm/rename-key.js +1 -1
- package/package.json +6 -6
- package/types/cli.d.ts +3 -1
- package/types/cli.d.ts.map +1 -1
- package/CHANGELOG.md +0 -599
- package/src/cli.ts +0 -283
- package/src/config.ts +0 -215
- package/src/extractor/core/ast-visitors.ts +0 -259
- package/src/extractor/core/extractor.ts +0 -250
- package/src/extractor/core/key-finder.ts +0 -142
- package/src/extractor/core/translation-manager.ts +0 -750
- package/src/extractor/index.ts +0 -7
- package/src/extractor/parsers/ast-utils.ts +0 -87
- package/src/extractor/parsers/call-expression-handler.ts +0 -793
- package/src/extractor/parsers/comment-parser.ts +0 -424
- package/src/extractor/parsers/expression-resolver.ts +0 -391
- package/src/extractor/parsers/jsx-handler.ts +0 -488
- package/src/extractor/parsers/jsx-parser.ts +0 -1463
- package/src/extractor/parsers/scope-manager.ts +0 -445
- package/src/extractor/plugin-manager.ts +0 -116
- package/src/extractor.ts +0 -15
- package/src/heuristic-config.ts +0 -92
- package/src/index.ts +0 -22
- package/src/init.ts +0 -175
- package/src/linter.ts +0 -345
- package/src/locize.ts +0 -263
- package/src/migrator.ts +0 -208
- package/src/rename-key.ts +0 -398
- package/src/status.ts +0 -380
- package/src/syncer.ts +0 -133
- package/src/types-generator.ts +0 -139
- package/src/types.ts +0 -577
- package/src/utils/default-value.ts +0 -45
- package/src/utils/file-utils.ts +0 -167
- package/src/utils/funnel-msg-tracker.ts +0 -84
- package/src/utils/logger.ts +0 -36
- package/src/utils/nested-object.ts +0 -135
- package/src/utils/validation.ts +0 -72
package/src/locize.ts
DELETED
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
import { execa } from 'execa'
|
|
2
|
-
import chalk from 'chalk'
|
|
3
|
-
import ora from 'ora'
|
|
4
|
-
import inquirer from 'inquirer'
|
|
5
|
-
import { resolve, sep } from 'node:path'
|
|
6
|
-
import type { I18nextToolkitConfig } from './types'
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Verifies that the locize-cli tool is installed and accessible.
|
|
10
|
-
*
|
|
11
|
-
* @throws Exits the process with error code 1 if locize-cli is not found
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* ```typescript
|
|
15
|
-
* await checkLocizeCliExists()
|
|
16
|
-
* // Continues execution if locize-cli is available
|
|
17
|
-
* // Otherwise exits with installation instructions
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
20
|
-
async function checkLocizeCliExists (): Promise<void> {
|
|
21
|
-
try {
|
|
22
|
-
await execa('locize', ['--version'])
|
|
23
|
-
} catch (error: any) {
|
|
24
|
-
if (error.code === 'ENOENT') {
|
|
25
|
-
console.error(chalk.red('Error: `locize-cli` command not found.'))
|
|
26
|
-
console.log(chalk.yellow('Please install it globally to use the locize integration:'))
|
|
27
|
-
console.log(chalk.cyan('npm install -g locize-cli'))
|
|
28
|
-
process.exit(1)
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Interactive setup wizard for configuring Locize credentials.
|
|
35
|
-
*
|
|
36
|
-
* This function guides users through setting up their Locize integration when
|
|
37
|
-
* configuration is missing or invalid. It:
|
|
38
|
-
* 1. Prompts for Project ID, API Key, and version
|
|
39
|
-
* 2. Validates required fields
|
|
40
|
-
* 3. Temporarily sets credentials for the current run
|
|
41
|
-
* 4. Provides security recommendations for storing credentials
|
|
42
|
-
* 5. Shows code examples for proper configuration
|
|
43
|
-
*
|
|
44
|
-
* @param config - Configuration object to update with new credentials
|
|
45
|
-
* @returns Promise resolving to the Locize configuration or undefined if setup was cancelled
|
|
46
|
-
*
|
|
47
|
-
* @example
|
|
48
|
-
* ```typescript
|
|
49
|
-
* const locizeConfig = await interactiveCredentialSetup(config)
|
|
50
|
-
* if (locizeConfig) {
|
|
51
|
-
* // Proceed with sync using the new credentials
|
|
52
|
-
* }
|
|
53
|
-
* ```
|
|
54
|
-
*/
|
|
55
|
-
async function interactiveCredentialSetup (config: I18nextToolkitConfig): Promise<{ projectId?: string, apiKey?: string, version?: string } | undefined> {
|
|
56
|
-
console.log(chalk.yellow('\nLocize configuration is missing or invalid. Let\'s set it up!'))
|
|
57
|
-
|
|
58
|
-
const answers = await inquirer.prompt([
|
|
59
|
-
{
|
|
60
|
-
type: 'input',
|
|
61
|
-
name: 'projectId',
|
|
62
|
-
message: 'What is your locize Project ID? (Find this in your project settings on www.locize.app)',
|
|
63
|
-
validate: input => !!input || 'Project ID cannot be empty.',
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
type: 'password',
|
|
67
|
-
name: 'apiKey',
|
|
68
|
-
message: 'What is your locize API key? (Create or use one in your project settings > "API Keys")',
|
|
69
|
-
validate: input => !!input || 'API Key cannot be empty.',
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
type: 'input',
|
|
73
|
-
name: 'version',
|
|
74
|
-
message: 'What version do you want to sync with?',
|
|
75
|
-
default: 'latest',
|
|
76
|
-
},
|
|
77
|
-
])
|
|
78
|
-
|
|
79
|
-
if (!answers.projectId) {
|
|
80
|
-
console.error(chalk.red('Project ID is required to continue.'))
|
|
81
|
-
return undefined
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const { save } = await inquirer.prompt([{
|
|
85
|
-
type: 'confirm',
|
|
86
|
-
name: 'save',
|
|
87
|
-
message: 'Would you like to see how to save these credentials for future use?',
|
|
88
|
-
default: true,
|
|
89
|
-
}])
|
|
90
|
-
|
|
91
|
-
if (save) {
|
|
92
|
-
const envSnippet = `
|
|
93
|
-
# Add this to your .env file (and ensure .env is in your .gitignore!)
|
|
94
|
-
LOCIZE_API_KEY=${answers.apiKey}
|
|
95
|
-
`
|
|
96
|
-
const configSnippet = `
|
|
97
|
-
// Add this to your i18next.config.ts file
|
|
98
|
-
locize: {
|
|
99
|
-
projectId: '${answers.projectId}',
|
|
100
|
-
// For security, apiKey is best set via an environment variable
|
|
101
|
-
apiKey: process.env.LOCIZE_API_KEY,
|
|
102
|
-
version: '${answers.version}',
|
|
103
|
-
},`
|
|
104
|
-
|
|
105
|
-
console.log(chalk.cyan('\nGreat! For the best security, we recommend using environment variables for your API key.'))
|
|
106
|
-
console.log(chalk.bold('\nRecommended approach (.env file):'))
|
|
107
|
-
console.log(chalk.green(envSnippet))
|
|
108
|
-
console.log(chalk.bold('Then, in your i18next.config.ts:'))
|
|
109
|
-
console.log(chalk.green(configSnippet))
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return {
|
|
113
|
-
projectId: answers.projectId,
|
|
114
|
-
apiKey: answers.apiKey,
|
|
115
|
-
version: answers.version,
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Helper function to build the array of arguments for the execa call.
|
|
121
|
-
* This ensures the logic is consistent for both the initial run and the retry.
|
|
122
|
-
*/
|
|
123
|
-
function buildArgs (command: string, config: I18nextToolkitConfig, cliOptions: any): string[] {
|
|
124
|
-
const { locize: locizeConfig = {}, extract } = config
|
|
125
|
-
const { projectId, apiKey, version } = locizeConfig
|
|
126
|
-
|
|
127
|
-
const commandArgs: string[] = [command]
|
|
128
|
-
|
|
129
|
-
if (projectId) commandArgs.push('--project-id', projectId)
|
|
130
|
-
if (apiKey) commandArgs.push('--api-key', apiKey)
|
|
131
|
-
if (version) commandArgs.push('--ver', version)
|
|
132
|
-
// TODO: there might be more configurable locize-cli options in future
|
|
133
|
-
|
|
134
|
-
// Pass-through options from the CLI
|
|
135
|
-
if (command === 'sync') {
|
|
136
|
-
const updateValues = cliOptions.updateValues ?? locizeConfig.updateValues
|
|
137
|
-
if (updateValues) commandArgs.push('--update-values', 'true')
|
|
138
|
-
const srcLngOnly = cliOptions.srcLngOnly ?? locizeConfig.sourceLanguageOnly
|
|
139
|
-
if (srcLngOnly) commandArgs.push('--reference-language-only', 'true')
|
|
140
|
-
const compareMtime = cliOptions.compareMtime ?? locizeConfig.compareModificationTime
|
|
141
|
-
if (compareMtime) commandArgs.push('--compare-modification-time', 'true')
|
|
142
|
-
const dryRun = cliOptions.dryRun ?? locizeConfig.dryRun
|
|
143
|
-
if (dryRun) commandArgs.push('--dry', 'true')
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Derive a sensible base path for locize from the configured output.
|
|
147
|
-
// If output is a string template we can strip the language placeholder.
|
|
148
|
-
// If output is a function we cannot reliably infer the base; fall back to cwd.
|
|
149
|
-
let basePath: string
|
|
150
|
-
try {
|
|
151
|
-
if (typeof extract.output === 'string') {
|
|
152
|
-
const outputNormalized = extract.output.replace(/\\/g, '/')
|
|
153
|
-
const baseCandidate = outputNormalized.includes('/{{language}}/')
|
|
154
|
-
? outputNormalized.split('/{{language}}/')[0]
|
|
155
|
-
: outputNormalized.replace('{{language}}', '')
|
|
156
|
-
const baseCandidateWithSep = baseCandidate.split('/').join(sep)
|
|
157
|
-
basePath = resolve(process.cwd(), baseCandidateWithSep)
|
|
158
|
-
} else if (typeof extract.output === 'function') {
|
|
159
|
-
// Try calling the function with the primary language to get an example path,
|
|
160
|
-
// then strip the language folder if present. If that fails, fallback to cwd.
|
|
161
|
-
try {
|
|
162
|
-
const sample = extract.output(config.extract.primaryLanguage || 'en')
|
|
163
|
-
const sampleNormalized = String(sample).replace(/\\/g, '/')
|
|
164
|
-
const baseCandidate = sampleNormalized.includes('/' + (config.extract.primaryLanguage || 'en') + '/')
|
|
165
|
-
? sampleNormalized.split('/' + (config.extract.primaryLanguage || 'en') + '/')[0]
|
|
166
|
-
: sampleNormalized.replace(config.extract.primaryLanguage || 'en', '')
|
|
167
|
-
basePath = resolve(process.cwd(), baseCandidate.split('/').join(sep))
|
|
168
|
-
} catch {
|
|
169
|
-
basePath = resolve(process.cwd(), '.')
|
|
170
|
-
}
|
|
171
|
-
} else {
|
|
172
|
-
basePath = resolve(process.cwd(), '.')
|
|
173
|
-
}
|
|
174
|
-
} catch {
|
|
175
|
-
basePath = resolve(process.cwd(), '.')
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
commandArgs.push('--path', basePath)
|
|
179
|
-
|
|
180
|
-
return commandArgs
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Executes a locize-cli command with proper error handling and credential management.
|
|
185
|
-
*
|
|
186
|
-
* This is the core function that:
|
|
187
|
-
* 1. Validates that locize-cli is installed
|
|
188
|
-
* 2. Builds command arguments from configuration and CLI options
|
|
189
|
-
* 3. Executes the locize command with proper credential handling
|
|
190
|
-
* 4. Provides interactive credential setup on authentication errors
|
|
191
|
-
* 5. Handles retries with new credentials
|
|
192
|
-
* 6. Reports success or failure with appropriate exit codes
|
|
193
|
-
*
|
|
194
|
-
* @param command - The locize command to execute ('sync', 'download', or 'migrate')
|
|
195
|
-
* @param config - The toolkit configuration with locize settings
|
|
196
|
-
* @param cliOptions - Additional options passed from CLI arguments
|
|
197
|
-
*
|
|
198
|
-
* @example
|
|
199
|
-
* ```typescript
|
|
200
|
-
* // Sync local files to Locize
|
|
201
|
-
* await runLocizeCommand('sync', config, { updateValues: true })
|
|
202
|
-
*
|
|
203
|
-
* // Download translations from Locize
|
|
204
|
-
* await runLocizeCommand('download', config)
|
|
205
|
-
*
|
|
206
|
-
* // Migrate local files to a new Locize project
|
|
207
|
-
* await runLocizeCommand('migrate', config)
|
|
208
|
-
* ```
|
|
209
|
-
*/
|
|
210
|
-
async function runLocizeCommand (command: 'sync' | 'download' | 'migrate', config: I18nextToolkitConfig, cliOptions: any = {}) {
|
|
211
|
-
await checkLocizeCliExists()
|
|
212
|
-
|
|
213
|
-
const spinner = ora(`Running 'locize ${command}'...\n`).start()
|
|
214
|
-
|
|
215
|
-
let effectiveConfig = config
|
|
216
|
-
|
|
217
|
-
try {
|
|
218
|
-
// 1. First attempt
|
|
219
|
-
const initialArgs = buildArgs(command, effectiveConfig, cliOptions)
|
|
220
|
-
console.log(chalk.cyan(`\nRunning 'locize ${initialArgs.join(' ')}'...`))
|
|
221
|
-
const result = await execa('locize', initialArgs, { stdio: 'pipe' })
|
|
222
|
-
|
|
223
|
-
spinner.succeed(chalk.green(`'locize ${command}' completed successfully.`))
|
|
224
|
-
if (result?.stdout) console.log(result.stdout) // Print captured output on success
|
|
225
|
-
} catch (error: any) {
|
|
226
|
-
const stderr = error.stderr || ''
|
|
227
|
-
if (stderr.includes('missing required argument')) {
|
|
228
|
-
// 2. Auth failure, trigger interactive setup
|
|
229
|
-
const newCredentials = await interactiveCredentialSetup(effectiveConfig)
|
|
230
|
-
if (newCredentials) {
|
|
231
|
-
effectiveConfig = { ...effectiveConfig, locize: newCredentials }
|
|
232
|
-
|
|
233
|
-
spinner.start('Retrying with new credentials...')
|
|
234
|
-
try {
|
|
235
|
-
// 3. Retry attempt, rebuilding args with the NOW-UPDATED currentConfig object
|
|
236
|
-
const retryArgs = buildArgs(command, effectiveConfig, cliOptions)
|
|
237
|
-
console.log(chalk.cyan(`\nRunning 'locize ${retryArgs.join(' ')}'...`))
|
|
238
|
-
const result = await execa('locize', retryArgs, { stdio: 'pipe' })
|
|
239
|
-
|
|
240
|
-
spinner.succeed(chalk.green('Retry successful!'))
|
|
241
|
-
if (result?.stdout) console.log(result.stdout)
|
|
242
|
-
} catch (retryError: any) {
|
|
243
|
-
spinner.fail(chalk.red('Error during retry.'))
|
|
244
|
-
console.error(retryError.stderr || retryError.message)
|
|
245
|
-
process.exit(1)
|
|
246
|
-
}
|
|
247
|
-
} else {
|
|
248
|
-
spinner.fail('Operation cancelled.')
|
|
249
|
-
process.exit(1) // User aborted the prompt
|
|
250
|
-
}
|
|
251
|
-
} else {
|
|
252
|
-
// Handle other errors
|
|
253
|
-
spinner.fail(chalk.red(`Error executing 'locize ${command}'.`))
|
|
254
|
-
console.error(stderr || error.message)
|
|
255
|
-
process.exit(1)
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
console.log(chalk.green(`\n✅ 'locize ${command}' completed successfully.`))
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
export const runLocizeSync = (config: I18nextToolkitConfig, cliOptions?: any) => runLocizeCommand('sync', config, cliOptions)
|
|
262
|
-
export const runLocizeDownload = (config: I18nextToolkitConfig, cliOptions?: any) => runLocizeCommand('download', config, cliOptions)
|
|
263
|
-
export const runLocizeMigrate = (config: I18nextToolkitConfig, cliOptions?: any) => runLocizeCommand('migrate', config, cliOptions)
|
package/src/migrator.ts
DELETED
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
import { resolve } from 'node:path'
|
|
2
|
-
import { writeFile, access } from 'node:fs/promises'
|
|
3
|
-
import { pathToFileURL } from 'node:url'
|
|
4
|
-
import { createJiti } from 'jiti'
|
|
5
|
-
import { getTsConfigAliases } from './config'
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Path where the new configuration file will be created
|
|
9
|
-
*/
|
|
10
|
-
const newConfigPath = resolve(process.cwd(), 'i18next.config.ts')
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* List of possible new configuration file names that would prevent migration
|
|
14
|
-
*/
|
|
15
|
-
const POSSIBLE_NEW_CONFIGS = [
|
|
16
|
-
'i18next.config.ts',
|
|
17
|
-
'i18next.config.js',
|
|
18
|
-
'i18next.config.mjs',
|
|
19
|
-
'i18next.config.cjs',
|
|
20
|
-
]
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* List of supported legacy configuration file extensions
|
|
24
|
-
*/
|
|
25
|
-
const LEGACY_CONFIG_EXTENSIONS = ['.js', '.mjs', '.cjs', '.ts']
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Helper function to find a legacy config file with various extensions
|
|
29
|
-
*/
|
|
30
|
-
async function findLegacyConfigFile (basePath: string): Promise<string | null> {
|
|
31
|
-
// If the provided path already has an extension, use it directly
|
|
32
|
-
if (LEGACY_CONFIG_EXTENSIONS.some(ext => basePath.endsWith(ext))) {
|
|
33
|
-
try {
|
|
34
|
-
await access(basePath)
|
|
35
|
-
return basePath
|
|
36
|
-
} catch {
|
|
37
|
-
return null
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Try different extensions
|
|
42
|
-
for (const ext of LEGACY_CONFIG_EXTENSIONS) {
|
|
43
|
-
const fullPath = `${basePath}${ext}`
|
|
44
|
-
try {
|
|
45
|
-
await access(fullPath)
|
|
46
|
-
return fullPath
|
|
47
|
-
} catch {
|
|
48
|
-
// Continue to next extension
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return null
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Loads a legacy config file using the appropriate loader (jiti for TS, dynamic import for JS/MJS/CJS)
|
|
57
|
-
*/
|
|
58
|
-
async function loadLegacyConfig (configPath: string): Promise<any> {
|
|
59
|
-
try {
|
|
60
|
-
let config: any
|
|
61
|
-
|
|
62
|
-
// Use jiti for TypeScript files, native import for JavaScript
|
|
63
|
-
if (configPath.endsWith('.ts')) {
|
|
64
|
-
const aliases = await getTsConfigAliases()
|
|
65
|
-
const jiti = createJiti(process.cwd(), {
|
|
66
|
-
alias: aliases,
|
|
67
|
-
interopDefault: false,
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
const configModule = await jiti.import(configPath, { default: true })
|
|
71
|
-
config = configModule
|
|
72
|
-
} else {
|
|
73
|
-
const configUrl = pathToFileURL(configPath).href
|
|
74
|
-
const configModule = await import(`${configUrl}?t=${Date.now()}`)
|
|
75
|
-
config = configModule.default
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return config
|
|
79
|
-
} catch (error) {
|
|
80
|
-
console.error(`Error loading legacy config from ${configPath}:`, error)
|
|
81
|
-
return null
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Migrates a legacy i18next-parser configuration file to the new
|
|
87
|
-
* i18next-cli configuration format.
|
|
88
|
-
*
|
|
89
|
-
* This function:
|
|
90
|
-
* 1. Checks if a legacy config file exists (supports .js, .mjs, .cjs, .ts)
|
|
91
|
-
* 2. Prevents migration if any new config file already exists
|
|
92
|
-
* 3. Dynamically imports the old configuration using appropriate loader
|
|
93
|
-
* 4. Maps old configuration properties to new format:
|
|
94
|
-
* - `$LOCALE` → `{{language}}`
|
|
95
|
-
* - `$NAMESPACE` → `{{namespace}}`
|
|
96
|
-
* - Maps lexer functions and components
|
|
97
|
-
* - Creates sensible defaults for new features
|
|
98
|
-
* 5. Generates a new TypeScript configuration file
|
|
99
|
-
* 6. Provides warnings for deprecated features
|
|
100
|
-
*
|
|
101
|
-
* @param customConfigPath - Optional custom path to the legacy config file
|
|
102
|
-
*
|
|
103
|
-
* @example
|
|
104
|
-
* ```bash
|
|
105
|
-
* # Migrate default config
|
|
106
|
-
* npx i18next-cli migrate-config
|
|
107
|
-
*
|
|
108
|
-
* # Migrate custom config with extension
|
|
109
|
-
* npx i18next-cli migrate-config i18next-parser.config.mjs
|
|
110
|
-
*
|
|
111
|
-
* # Migrate custom config without extension (will try .js, .mjs, .cjs, .ts)
|
|
112
|
-
* npx i18next-cli migrate-config my-custom-config
|
|
113
|
-
* ```
|
|
114
|
-
*/
|
|
115
|
-
export async function runMigrator (customConfigPath?: string) {
|
|
116
|
-
let oldConfigPath: string | null
|
|
117
|
-
|
|
118
|
-
if (customConfigPath) {
|
|
119
|
-
oldConfigPath = await findLegacyConfigFile(resolve(process.cwd(), customConfigPath))
|
|
120
|
-
if (!oldConfigPath) {
|
|
121
|
-
console.log(`No legacy config file found at or near: ${customConfigPath}`)
|
|
122
|
-
console.log('Tried extensions: .js, .mjs, .cjs, .ts')
|
|
123
|
-
return
|
|
124
|
-
}
|
|
125
|
-
} else {
|
|
126
|
-
// Default behavior: look for i18next-parser.config.* files
|
|
127
|
-
oldConfigPath = await findLegacyConfigFile(resolve(process.cwd(), 'i18next-parser.config'))
|
|
128
|
-
if (!oldConfigPath) {
|
|
129
|
-
console.log('No i18next-parser.config.* found. Nothing to migrate.')
|
|
130
|
-
console.log('Tried: i18next-parser.config.js, .mjs, .cjs, .ts')
|
|
131
|
-
return
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
console.log(`Attempting to migrate legacy config from: ${oldConfigPath}...`)
|
|
136
|
-
|
|
137
|
-
// Check if ANY new config file already exists
|
|
138
|
-
for (const configFile of POSSIBLE_NEW_CONFIGS) {
|
|
139
|
-
try {
|
|
140
|
-
const fullPath = resolve(process.cwd(), configFile)
|
|
141
|
-
await access(fullPath)
|
|
142
|
-
console.warn(`Warning: A new configuration file already exists at "${configFile}". Migration skipped to avoid overwriting.`)
|
|
143
|
-
return
|
|
144
|
-
} catch (e) {
|
|
145
|
-
// File doesn't exist, which is good
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Load the legacy config using the appropriate loader
|
|
150
|
-
const oldConfig = await loadLegacyConfig(oldConfigPath)
|
|
151
|
-
|
|
152
|
-
if (!oldConfig) {
|
|
153
|
-
console.error('Could not read the legacy config file.')
|
|
154
|
-
return
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// --- Start Migration Logic ---
|
|
158
|
-
const newConfig = {
|
|
159
|
-
locales: oldConfig.locales || ['en'],
|
|
160
|
-
extract: {
|
|
161
|
-
input: oldConfig.input || 'src/**/*.{js,jsx,ts,tsx}',
|
|
162
|
-
output: (oldConfig.output || 'locales/$LOCALE/$NAMESPACE.json')
|
|
163
|
-
.replace('$LOCALE', '{{language}}')
|
|
164
|
-
.replace('$NAMESPACE', '{{namespace}}'),
|
|
165
|
-
defaultNS: oldConfig.defaultNamespace || 'translation',
|
|
166
|
-
keySeparator: oldConfig.keySeparator,
|
|
167
|
-
nsSeparator: oldConfig.namespaceSeparator,
|
|
168
|
-
contextSeparator: oldConfig.contextSeparator,
|
|
169
|
-
// A simple mapping for functions
|
|
170
|
-
functions: oldConfig.lexers?.js?.functions || ['t', '*.t'],
|
|
171
|
-
transComponents: oldConfig.lexers?.js?.components || ['Trans'],
|
|
172
|
-
},
|
|
173
|
-
types: {
|
|
174
|
-
input: ['locales/{{language}}/{{namespace}}.json'], // Sensible default
|
|
175
|
-
output: 'src/types/i18next.d.ts', // Sensible default
|
|
176
|
-
},
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// Make the migration smarter: if 't' is a function, also add the '*.t' wildcard
|
|
180
|
-
// to provide better out-of-the-box support for common patterns like `i18n.t`.
|
|
181
|
-
if (newConfig.extract.functions.includes('t') && !newConfig.extract.functions.includes('*.t')) {
|
|
182
|
-
newConfig.extract.functions.push('*.t')
|
|
183
|
-
}
|
|
184
|
-
// --- End Migration Logic ---
|
|
185
|
-
|
|
186
|
-
// Generate the new file content as a string
|
|
187
|
-
const newConfigFileContent = `
|
|
188
|
-
import { defineConfig } from 'i18next-cli';
|
|
189
|
-
|
|
190
|
-
export default defineConfig(${JSON.stringify(newConfig, null, 2)});
|
|
191
|
-
`
|
|
192
|
-
|
|
193
|
-
await writeFile(newConfigPath, newConfigFileContent.trim())
|
|
194
|
-
|
|
195
|
-
console.log('✅ Success! Migration complete.')
|
|
196
|
-
console.log(`New configuration file created at: ${newConfigPath}`)
|
|
197
|
-
console.warn('\nPlease review the generated file and adjust paths for "types.input" if necessary.')
|
|
198
|
-
|
|
199
|
-
// Warning for deprecated features
|
|
200
|
-
if (oldConfig.keepRemoved) {
|
|
201
|
-
console.warn('Warning: The "keepRemoved" option is deprecated. Consider using the "preservePatterns" feature for dynamic keys.')
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// Warning for compatibilityJSON v3
|
|
205
|
-
if (oldConfig.i18nextOptions?.compatibilityJSON === 'v3') {
|
|
206
|
-
console.warn('Warning: compatibilityJSON "v3" is not supported in i18next-cli. Only i18next v4 format is supported.')
|
|
207
|
-
}
|
|
208
|
-
}
|