New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

fes-locale-gen

Package Overview
Dependencies
Maintainers
0
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fes-locale-gen - npm Package Compare versions

Comparing version 1.0.11 to 1.0.12-beta.1

example/source/pages/test2/a.tsx

9

package.json
{
"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,

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc