fes-locale-gen
Advanced tools
Comparing version 1.0.11 to 1.0.12-beta.1
{ | ||
"name": "fes-locale-gen", | ||
"version": "1.0.11", | ||
"version": "1.0.12-beta.1", | ||
"description": "", | ||
@@ -13,3 +13,6 @@ "main": "index.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
"test": "echo \"Error: no test specified\" && exit 1", | ||
"dev": "node ./src/locale -d example/source/pages", | ||
"translate": "node ./src/locale translate", | ||
"list": "node ./src/locale config list" | ||
}, | ||
@@ -20,2 +23,4 @@ "dependencies": { | ||
"@babel/traverse": "^7.25.7", | ||
"@babel/types": "^7.25.9", | ||
"@typescript-eslint/parser": "^8.12.2", | ||
"@vue/compiler-sfc": "^3.5.12", | ||
@@ -22,0 +27,0 @@ "dotenv": "^16.4.5", |
@@ -16,2 +16,3 @@ #!/usr/bin/env node | ||
const { OpenAI } = require('openai'); | ||
const t = require('@babel/types'); | ||
const readline = require('readline'); | ||
@@ -44,8 +45,12 @@ | ||
ast = parse(inputFileContent, { | ||
ecmaVersion: 2020, | ||
sourceType: 'module', | ||
ecmaFeatures: { | ||
parser: '@typescript-eslint/parser', // 指定 TypeScript 解析器 | ||
parserOptions: { | ||
ecmaVersion: 2020, | ||
sourceType: 'module', | ||
ecmaFeatures: { | ||
jsx: true, | ||
tsx: true, // 支持 TypeScript JSX | ||
}, | ||
}, | ||
}); | ||
}); | ||
// console.log('parse completed'); | ||
@@ -72,3 +77,3 @@ } catch (e) { | ||
sourceType: isModule ? 'module' : 'script', | ||
plugins: ['jsx'], | ||
plugins: ['jsx', 'typescript'], | ||
}); | ||
@@ -94,3 +99,3 @@ | ||
StringLiteral(path) { | ||
if (/[\u4e00-\u9fa5]/.test(path.node.value) && | ||
if (path.parent.type !== 'JSXAttribute' && /[\u4e00-\u9fa5]/.test(path.node.value) && | ||
!path.findParent(p => p.isCallExpression() && (p.node.callee.name === '$t' || (p.node.callee.type === 'MemberExpression' && p.node.callee.object.name === 'locale' && p.node.callee.property.name === 't'))) && | ||
@@ -107,6 +112,32 @@ !path.node.value.startsWith('_.$t(') && | ||
end: path.node.end, | ||
text: isJSFile ? `locale.t('_.${escapedText}')` : `$t('_.${escapedText}')` | ||
text: `$t('_.${escapedText}')` | ||
}); | ||
} | ||
}, | ||
// 处理标签属性中的中文字符 | ||
JSXAttribute(path) { | ||
if (t.isJSXIdentifier(path.node.name) && t.isStringLiteral(path.node.value) && /[\u4e00-\u9fa5]/.test(path.node.value.value)) { | ||
const trimmedText = path.node.value.value.trim(); | ||
if (trimmedText && !trimmedText.startsWith('$t(\'_')) { | ||
const escapedText = escapeForTranslation(trimmedText); | ||
replacedTexts.add(escapedText); | ||
const wrappedText = `${path.node.name.name}={$t('_.${escapedText}')}`; | ||
replacements.push({ start: path.node.start, end: path.node.end, text: wrappedText }); | ||
} | ||
} | ||
}, | ||
// 处理标签内的中文字符 | ||
JSXText(path) { | ||
if (/[\u4e00-\u9fa5]/.test(path.node.value) && !path.node.value.startsWith('$t(\'_') ) { | ||
const text = path.node.value.trim(); | ||
const escapedText = escapeForTranslation(text); | ||
replacedTexts.add(escapedText); | ||
const wrappedText = '{`${' + `$t('_.${escapedText}')` + '}`}'; | ||
replacements.push({ | ||
start: path.node.start, | ||
end: path.node.end, | ||
text: wrappedText | ||
}); | ||
} | ||
}, | ||
TemplateLiteral(path) { | ||
@@ -126,3 +157,3 @@ if (!path.findParent((p) => p.isCallExpression() && p.node.callee.type === 'MemberExpression' && p.node.callee.object.name === 'console')) { | ||
end: quasi.end, | ||
text: isJSFile ? `\${locale.t('_.${escapedText}')}` : `\${$t('_.${escapedText}')}` | ||
text: `\${$t('_.${escapedText}')}` | ||
}); | ||
@@ -145,3 +176,3 @@ } | ||
sourceType: isModule ? 'module' : 'script', | ||
plugins: ['jsx'], | ||
plugins: ['jsx', 'typescript'], | ||
}); | ||
@@ -179,40 +210,54 @@ | ||
// 只有在非 JS 文件的情况下才添加 $t 声明 | ||
if (!isJSFile) { | ||
ast = parseJS(code, { | ||
sourceType: isModule ? 'module' : 'script', | ||
plugins: ['jsx'], | ||
}); | ||
ast = parseJS(code, { | ||
sourceType: isModule ? 'module' : 'script', | ||
plugins: ['jsx', 'typescript'], | ||
}); | ||
let hasDollarTDeclaration = false; | ||
let hasDollarTDeclaration = false; | ||
// 第三次遍历:检查是否有使用插件 | ||
traverse(ast, { | ||
ImportDeclaration(path) { | ||
lastImportIndex = Math.max(lastImportIndex, path.node.loc.end.line); | ||
}, | ||
VariableDeclaration(path) { | ||
path.node.declarations.forEach(declaration => { | ||
if (declaration.init && | ||
declaration.init.type === 'CallExpression' && | ||
declaration.init.callee.name === 'useI18n') { | ||
if (declaration.id.type === 'ObjectPattern') { | ||
const tProperty = declaration.id.properties.find(prop => | ||
prop.key.name === 't' && prop.value.name === '$t' | ||
); | ||
if (tProperty) { | ||
hasDollarTDeclaration = true; | ||
} | ||
// 第三次遍历:检查是否有使用插件 | ||
traverse(ast, { | ||
ImportDeclaration(path) { | ||
lastImportIndex = Math.max(lastImportIndex, path.node.loc.end.line); | ||
}, | ||
VariableDeclaration(path) { | ||
path.node.declarations.forEach(declaration => { | ||
if (declaration.init && | ||
declaration.init.type === 'CallExpression' && | ||
declaration.init.callee.name === 'useI18n') { | ||
if (declaration.id.type === 'ObjectPattern') { | ||
const tProperty = declaration.id.properties.find(prop => | ||
prop.key.name === 't' && prop.value.name === '$t' | ||
); | ||
if (tProperty) { | ||
hasDollarTDeclaration = true; | ||
} | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
// 添加 $t 声明(如果需要) | ||
if (!hasDollarTDeclaration) { | ||
const lines = code.split('\n'); | ||
const insertIndex = lastImportIndex !== -1 ? lastImportIndex + 1 : 0; | ||
lines.splice(insertIndex, 0, `\nconst { t: $t } = useI18n();\n`); | ||
code = lines.join('\n'); | ||
} | ||
// 检查是否有 const $t = locale.t 的代码 | ||
if ( | ||
declaration.id.type === 'Identifier' && | ||
declaration.id.name === '$t' && | ||
declaration.init && | ||
declaration.init.type === 'MemberExpression' && | ||
declaration.init.object.name === 'locale' && | ||
declaration.init.property.name === 't' | ||
) { | ||
hasDollarTDeclaration = true; | ||
} | ||
}); | ||
}, | ||
}); | ||
// 添加 $t 声明(如果需要) | ||
if (!hasDollarTDeclaration) { | ||
const lines = code.split('\n'); | ||
const insertIndex = lastImportIndex !== -1 ? lastImportIndex + 1 : 0; | ||
const text = isJSFile? `\nconst $t = locale.t;\n`: `\nconst { t: $t } = useI18n();\n` | ||
lines.splice(insertIndex, 0, text); | ||
code = lines.join('\n'); | ||
} | ||
@@ -235,4 +280,9 @@ } | ||
handleAttributeNode(attr, replacements); | ||
}else if (attr.value && attr.value.type === 'VExpressionContainer' && t.isConditionalExpression(attr.value.expression)) { | ||
handleConditionExpression(attr.value.expression, replacements); | ||
} | ||
} | ||
} else if (node.type === 'VExpressionContainer' && t.isConditionalExpression(node.expression)) { | ||
handleConditionExpression(node.expression, replacements); | ||
} | ||
@@ -267,2 +317,30 @@ | ||
function handleConditionExpression(node, replacements) { | ||
// 检查字符串是否包含中文 | ||
const containsChinese = (str)=> { | ||
return /[\u4e00-\u9fa5]+/.test(str); | ||
} | ||
// 处理三元运算符 | ||
if (containsChinese(node.consequent.value)) { | ||
const trimmedText = node.consequent.value.trim(); | ||
if (trimmedText && !trimmedText.startsWith('$t(\'_')) { | ||
const escapedText = escapeForTranslation(trimmedText); | ||
replacedTexts.add(escapedText); | ||
const wrappedText = '`${' + `$t('_.${escapedText}')` + '}`'; | ||
replacements.push({ start: node.consequent.range[0], end: node.consequent.range[1], text: `${wrappedText}` }); | ||
} | ||
} | ||
if (containsChinese(node.alternate.value)) { | ||
const trimmedText = node.alternate.value.trim(); | ||
if (trimmedText && !trimmedText.startsWith('$t(\'_')) { | ||
const escapedText = escapeForTranslation(trimmedText); | ||
replacedTexts.add(escapedText); | ||
const wrappedText = '`${' + `$t('_.${escapedText}')` + '}`'; | ||
replacements.push({ start: node.alternate.range[0], end: node.alternate.range[1], text: `${wrappedText}` }); | ||
} | ||
} | ||
} | ||
function singleFileProcessor(filePath) { | ||
@@ -272,3 +350,3 @@ const fileContent = fs.readFileSync(filePath, 'utf-8'); | ||
if (fileExt === '.js' || fileExt === '.jsx') { | ||
if (fileExt === '.js' || fileExt === '.jsx' || fileExt === '.ts' || fileExt === '.tsx') { | ||
const processedContent = processJavaScript(fileContent, true, false, true); | ||
@@ -449,3 +527,4 @@ return { | ||
async function applyInDir(filePath, dirPath, excludedDirList, extractTxt) { | ||
const files = glob.sync(path.join(dirPath, '**/*.{vue,js,jsx}').replace(/\\/g, '/'), { | ||
// console.log('dirPath', dirPath, excludedDirList); | ||
const files = glob.sync(path.join(dirPath, '**/*.{vue,js,jsx,tsx,ts}').replace(/\\/g, '/'), { | ||
ignore: excludedDirList, | ||
@@ -470,3 +549,3 @@ }); | ||
hour12: false | ||
}).replace(/[\s]/g, '-').replace(/[/]/g, ''); | ||
}).replace(/[\s/:]/g, ''); | ||
@@ -505,3 +584,3 @@ for (let i = 0; i < files.length; i++) { | ||
const errorLogPath = path.join(outputDirectory, `error-log-${currentTime}.json`); | ||
const errorLogPath = path.join(outputDirectory, `errorlog-${currentTime}.json`); | ||
fs.writeFileSync( | ||
@@ -508,0 +587,0 @@ errorLogPath, |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
57485
14
808
11
3
+ Added@babel/types@^7.25.9
+ Added@nodelib/fs.scandir@2.1.5(transitive)
+ Added@nodelib/fs.stat@2.0.5(transitive)
+ Added@nodelib/fs.walk@1.2.8(transitive)
+ Added@typescript-eslint/parser@8.23.0(transitive)
+ Added@typescript-eslint/scope-manager@8.23.0(transitive)
+ Added@typescript-eslint/types@8.23.0(transitive)
+ Added@typescript-eslint/typescript-estree@8.23.0(transitive)
+ Added@typescript-eslint/visitor-keys@8.23.0(transitive)
+ Addedbraces@3.0.3(transitive)
+ Addedfast-glob@3.3.3(transitive)
+ Addedfastq@1.19.0(transitive)
+ Addedfill-range@7.1.1(transitive)
+ Addedglob-parent@5.1.2(transitive)
+ Addedis-number@7.0.0(transitive)
+ Addedmerge2@1.4.1(transitive)
+ Addedmicromatch@4.0.8(transitive)
+ Addedminimatch@9.0.5(transitive)
+ Addedpicomatch@2.3.1(transitive)
+ Addedqueue-microtask@1.2.3(transitive)
+ Addedreusify@1.0.4(transitive)
+ Addedrun-parallel@1.2.0(transitive)
+ Addedto-regex-range@5.0.1(transitive)
+ Addedts-api-utils@2.0.1(transitive)
+ Addedtypescript@5.7.3(transitive)