mirror of
https://github.com/langgenius/dify.git
synced 2025-12-19 17:27:16 -05:00
146 lines
4.2 KiB
JavaScript
146 lines
4.2 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
const fs = require('fs')
|
|
const path = require('path')
|
|
const { camelCase } = require('lodash')
|
|
const ts = require('typescript')
|
|
|
|
// Import the NAMESPACES array from i18next-config.ts
|
|
function getNamespacesFromConfig() {
|
|
const configPath = path.join(__dirname, 'i18next-config.ts')
|
|
const configContent = fs.readFileSync(configPath, 'utf8')
|
|
const sourceFile = ts.createSourceFile(configPath, configContent, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS)
|
|
|
|
const namespaces = []
|
|
|
|
const visit = (node) => {
|
|
if (
|
|
ts.isVariableDeclaration(node)
|
|
&& node.name.getText() === 'NAMESPACES'
|
|
&& node.initializer
|
|
&& ts.isArrayLiteralExpression(node.initializer)
|
|
) {
|
|
node.initializer.elements.forEach((el) => {
|
|
if (ts.isStringLiteral(el))
|
|
namespaces.push(el.text)
|
|
})
|
|
}
|
|
ts.forEachChild(node, visit)
|
|
}
|
|
|
|
visit(sourceFile)
|
|
|
|
if (!namespaces.length)
|
|
throw new Error('Could not find NAMESPACES array in i18next-config.ts')
|
|
|
|
return namespaces
|
|
}
|
|
|
|
function generateTypeDefinitions(namespaces) {
|
|
const header = `// TypeScript type definitions for Dify's i18next configuration
|
|
// This file is auto-generated. Do not edit manually.
|
|
// To regenerate, run: pnpm run gen:i18n-types
|
|
import 'react-i18next'
|
|
|
|
// Extract types from translation files using typeof import pattern`
|
|
|
|
// Generate individual type definitions
|
|
const typeDefinitions = namespaces.map(namespace => {
|
|
const typeName = camelCase(namespace).replace(/^\w/, c => c.toUpperCase()) + 'Messages'
|
|
return `type ${typeName} = typeof import('../i18n/en-US/${namespace}').default`
|
|
}).join('\n')
|
|
|
|
// Generate Messages interface
|
|
const messagesInterface = `
|
|
// Complete type structure that matches i18next-config.ts camelCase conversion
|
|
export type Messages = {
|
|
${namespaces.map(namespace => {
|
|
const camelCased = camelCase(namespace)
|
|
const typeName = camelCase(namespace).replace(/^\w/, c => c.toUpperCase()) + 'Messages'
|
|
return ` ${camelCased}: ${typeName};`
|
|
}).join('\n')}
|
|
}`
|
|
|
|
const utilityTypes = `
|
|
// Utility type to flatten nested object keys into dot notation
|
|
type FlattenKeys<T> = T extends object
|
|
? {
|
|
[K in keyof T]: T[K] extends object
|
|
? \`\${K & string}.\${FlattenKeys<T[K]> & string}\`
|
|
: \`\${K & string}\`
|
|
}[keyof T]
|
|
: never
|
|
|
|
export type ValidTranslationKeys = FlattenKeys<Messages>`
|
|
|
|
const moduleDeclarations = `
|
|
// Extend react-i18next with Dify's type structure
|
|
declare module 'react-i18next' {
|
|
interface CustomTypeOptions {
|
|
defaultNS: 'translation';
|
|
resources: {
|
|
translation: Messages;
|
|
};
|
|
}
|
|
}
|
|
|
|
// Extend i18next for complete type safety
|
|
declare module 'i18next' {
|
|
interface CustomTypeOptions {
|
|
defaultNS: 'translation';
|
|
resources: {
|
|
translation: Messages;
|
|
};
|
|
}
|
|
}`
|
|
|
|
return [header, typeDefinitions, messagesInterface, utilityTypes, moduleDeclarations].join('\n\n')
|
|
}
|
|
|
|
function main() {
|
|
const args = process.argv.slice(2)
|
|
const checkMode = args.includes('--check')
|
|
|
|
try {
|
|
console.log('📦 Generating i18n type definitions...')
|
|
|
|
// Get namespaces from config
|
|
const namespaces = getNamespacesFromConfig()
|
|
console.log(`✅ Found ${namespaces.length} namespaces`)
|
|
|
|
// Generate type definitions
|
|
const typeDefinitions = generateTypeDefinitions(namespaces)
|
|
|
|
const outputPath = path.join(__dirname, '../types/i18n.d.ts')
|
|
|
|
if (checkMode) {
|
|
// Check mode: compare with existing file
|
|
if (!fs.existsSync(outputPath)) {
|
|
console.error('❌ Type definitions file does not exist')
|
|
process.exit(1)
|
|
}
|
|
|
|
const existingContent = fs.readFileSync(outputPath, 'utf8')
|
|
if (existingContent.trim() !== typeDefinitions.trim()) {
|
|
console.error('❌ Type definitions are out of sync')
|
|
console.error(' Run: pnpm run gen:i18n-types')
|
|
process.exit(1)
|
|
}
|
|
|
|
console.log('✅ Type definitions are in sync')
|
|
} else {
|
|
// Generate mode: write file
|
|
fs.writeFileSync(outputPath, typeDefinitions)
|
|
console.log(`✅ Generated type definitions: ${outputPath}`)
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('❌ Error:', error.message)
|
|
process.exit(1)
|
|
}
|
|
}
|
|
|
|
if (require.main === module) {
|
|
main()
|
|
}
|