Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added packages/base/public/static/xlsx_template.xlsx
Binary file not shown.
Binary file added packages/sqle/public/static/xlsx_template.xlsx
Binary file not shown.
230 changes: 230 additions & 0 deletions packages/sqle/src/locale/__tests__/fileUploadI18n.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
import execWorkflowZhCN from '../zh-CN/execWorkflow';
import execWorkflowEnUS from '../en-US/execWorkflow';
import sqlAuditZhCN from '../zh-CN/sqlAudit';
import sqlAuditEnUS from '../en-US/sqlAudit';

/**
* Recursively collect all leaf key paths from a nested object.
* E.g. { a: { b: 'v', c: 'v2' } } => ['a.b', 'a.c']
*/
const collectKeyPaths = (
obj: Record<string, unknown>,
prefix = ''
): string[] => {
const keys: string[] = [];
for (const key of Object.keys(obj)) {
const fullPath = prefix ? `${prefix}.${key}` : key;
const value = obj[key];
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
keys.push(
...collectKeyPaths(value as Record<string, unknown>, fullPath)
);
} else {
keys.push(fullPath);
}
}
return keys;
};

/**
* Resolve a nested key path (e.g. 'create.form.sqlInfo.zipFile') on an object.
*/
const resolveKeyPath = (
obj: Record<string, unknown>,
path: string
): unknown => {
return path.split('.').reduce((acc: unknown, part: string) => {
if (acc && typeof acc === 'object') {
return (acc as Record<string, unknown>)[part];
}
return undefined;
}, obj);
};

describe('i18n key completeness for file upload changes', () => {
describe('execWorkflow - zh-CN and en-US key parity', () => {
const zhKeys = collectKeyPaths(
execWorkflowZhCN as unknown as Record<string, unknown>
);
const enKeys = collectKeyPaths(
execWorkflowEnUS as unknown as Record<string, unknown>
);

it('zh-CN should not have keys missing in en-US', () => {
const missingInEn = zhKeys.filter((k) => !enKeys.includes(k));
expect(missingInEn).toEqual([]);
});

it('en-US should not have keys missing in zh-CN', () => {
const missingInZh = enKeys.filter((k) => !zhKeys.includes(k));
expect(missingInZh).toEqual([]);
});
});

describe('sqlAudit - zh-CN and en-US key parity', () => {
const zhKeys = collectKeyPaths(
sqlAuditZhCN as unknown as Record<string, unknown>
);
const enKeys = collectKeyPaths(
sqlAuditEnUS as unknown as Record<string, unknown>
);

it('zh-CN should not have keys missing in en-US', () => {
const missingInEn = zhKeys.filter((k) => !enKeys.includes(k));
expect(missingInEn).toEqual([]);
});

it('en-US should not have keys missing in zh-CN', () => {
const missingInZh = enKeys.filter((k) => !zhKeys.includes(k));
expect(missingInZh).toEqual([]);
});
});

describe('execWorkflow - required file upload keys exist', () => {
const requiredKeys = [
'create.form.sqlInfo.sqlFileTips',
'create.form.sqlInfo.zipFile',
'create.form.sqlInfo.zipFileTips',
'create.form.sqlInfo.uploadZipFile',
'create.form.sqlInfo.xlsxTemplateTips',
'create.form.sqlInfo.downloadTemplate',
'create.form.sqlInfo.noSqlColumnFound'
];

it.each(requiredKeys)(
'key "%s" should exist in zh-CN',
(keyPath) => {
const value = resolveKeyPath(
execWorkflowZhCN as unknown as Record<string, unknown>,
keyPath
);
expect(value).toBeDefined();
expect(typeof value).toBe('string');
expect((value as string).length).toBeGreaterThan(0);
}
);

it.each(requiredKeys)(
'key "%s" should exist in en-US',
(keyPath) => {
const value = resolveKeyPath(
execWorkflowEnUS as unknown as Record<string, unknown>,
keyPath
);
expect(value).toBeDefined();
expect(typeof value).toBe('string');
expect((value as string).length).toBeGreaterThan(0);
}
);
});

describe('sqlAudit - required file upload keys exist', () => {
const requiredKeys = [
'create.sqlInfo.uploadTypeEnum.zipFile',
'create.sqlInfo.uploadLabelEnum.zipFile',
'create.sqlInfo.uploadFileTip.sqlFile',
'create.sqlInfo.uploadFileTip.zipFile',
'create.sqlInfo.xlsxTemplateTips',
'create.sqlInfo.downloadTemplate',
'create.sqlInfo.noSqlColumnFound'
];

it.each(requiredKeys)(
'key "%s" should exist in zh-CN',
(keyPath) => {
const value = resolveKeyPath(
sqlAuditZhCN as unknown as Record<string, unknown>,
keyPath
);
expect(value).toBeDefined();
expect(typeof value).toBe('string');
expect((value as string).length).toBeGreaterThan(0);
}
);

it.each(requiredKeys)(
'key "%s" should exist in en-US',
(keyPath) => {
const value = resolveKeyPath(
sqlAuditEnUS as unknown as Record<string, unknown>,
keyPath
);
expect(value).toBeDefined();
expect(typeof value).toBe('string');
expect((value as string).length).toBeGreaterThan(0);
}
);
});

describe('execWorkflow - file upload tip content correctness', () => {
it('zh-CN sqlFileTips should mention .sql, .txt, .java, .xlsx', () => {
const tip = (execWorkflowZhCN as Record<string, unknown> as any).create
.form.sqlInfo.sqlFileTips;
expect(tip).toContain('.sql');
expect(tip).toContain('.txt');
expect(tip).toContain('.java');
expect(tip).toContain('.xlsx');
});

it('zh-CN zipFileTips should mention .zip, .rar, .7z', () => {
const tip = (execWorkflowZhCN as Record<string, unknown> as any).create
.form.sqlInfo.zipFileTips;
expect(tip).toContain('.zip');
expect(tip).toContain('.rar');
expect(tip).toContain('.7z');
});

it('en-US sqlFileTips should mention .sql, .txt, .java, .xlsx', () => {
const tip = (execWorkflowEnUS as Record<string, unknown> as any).create
.form.sqlInfo.sqlFileTips;
expect(tip).toContain('.sql');
expect(tip).toContain('.txt');
expect(tip).toContain('.java');
expect(tip).toContain('.xlsx');
});

it('en-US zipFileTips should mention .zip, .rar, .7z', () => {
const tip = (execWorkflowEnUS as Record<string, unknown> as any).create
.form.sqlInfo.zipFileTips;
expect(tip).toContain('.zip');
expect(tip).toContain('.rar');
expect(tip).toContain('.7z');
});
});

describe('sqlAudit - file upload tip content correctness', () => {
it('zh-CN uploadFileTip.sqlFile should mention .sql, .txt, .java, .xlsx', () => {
const tip = (sqlAuditZhCN as Record<string, unknown> as any).create
.sqlInfo.uploadFileTip.sqlFile;
expect(tip).toContain('.sql');
expect(tip).toContain('.txt');
expect(tip).toContain('.java');
expect(tip).toContain('.xlsx');
});

it('zh-CN uploadFileTip.zipFile should mention .zip, .rar, .7z', () => {
const tip = (sqlAuditZhCN as Record<string, unknown> as any).create
.sqlInfo.uploadFileTip.zipFile;
expect(tip).toContain('.zip');
expect(tip).toContain('.rar');
expect(tip).toContain('.7z');
});

it('en-US uploadFileTip.sqlFile should mention .sql, .txt, .java, .xlsx', () => {
const tip = (sqlAuditEnUS as Record<string, unknown> as any).create
.sqlInfo.uploadFileTip.sqlFile;
expect(tip).toContain('.sql');
expect(tip).toContain('.txt');
expect(tip).toContain('.java');
expect(tip).toContain('.xlsx');
});

it('en-US uploadFileTip.zipFile should mention .zip, .rar, .7z', () => {
const tip = (sqlAuditEnUS as Record<string, unknown> as any).create
.sqlInfo.uploadFileTip.zipFile;
expect(tip).toContain('.zip');
expect(tip).toContain('.rar');
expect(tip).toContain('.7z');
});
});
});
11 changes: 7 additions & 4 deletions packages/sqle/src/locale/en-US/execWorkflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,21 +80,24 @@ export default {

sql: 'SQL statement',
sqlFile: 'SQL file',
sqlFileTips: 'Click to select a SQL file or drag the file to this area',
sqlFileTips: 'Click to select a file or drag the file to this area. Supports .sql, .txt, .java, .xlsx formats',
mybatisFile: 'Mybatis XML file',
mybatisFileTips:
'Click to select an XML file or drag the file to this area',
zipFile: 'Zip file',
zipFile: 'Compressed file',
zipFileTips:
'Click to select a zip file or drag the file to this area, currently only supports SQL auditing of .xml and .sql files in the ZIP file',
'Click to select a compressed file or drag the file to this area. Supports .zip, .rar, .7z formats. Only .sql, .xml, .txt, .java files in the archive will be audited',

addInstanceTips: 'Please add DB instance',
addInstance: 'Add DB instance',
uploadType: 'Select SQL statement upload method',
manualInput: 'Enter SQL statement',
uploadFile: 'Upload SQL file',
updateMybatisFile: 'Upload Mybatis XML file',
uploadZipFile: 'Upload ZIP file',
uploadZipFile: 'Upload compressed file',
xlsxTemplateTips: 'Please use the standard template format',
downloadTemplate: 'Download template',
noSqlColumnFound: 'No column containing SQL found, please refer to the template',

audit: 'Audit',
analyze: 'SQL analysis',
Expand Down
13 changes: 8 additions & 5 deletions packages/sqle/src/locale/en-US/sqlAudit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,25 +73,28 @@ export default {
sql: 'Input SQL statement',
sqlFile: 'Upload SQL file',
mybatisFile: 'Upload Mybatis XML file',
zipFile: 'Upload ZIP file',
zipFile: 'Upload compressed file',
git: 'Configure GIT repository'
},
uploadLabelEnum: {
sql: 'SQL statement',
sqlFile: 'SQL file',
mybatisFile: 'Mybatis XML file',
zipFile: 'ZIP file',
zipFile: 'Compressed file',
gitUrl: 'GIT address',
gitUrlTips:
'Please enter the HTTP(S) clone address of the git repository. if it is a private GIT repository, you must enter the account and password with read permission'
},
uploadFileTip: {
sqlFile: 'Click to select a SQL file or drag the file to this area',
sqlFile: 'Click to select a file or drag the file to this area. Supports .sql, .txt, .java, .xlsx formats',
mybatisFile:
'Click to select a Mybatis XML file or drag the file to this area',
zipFile:
'Click to select a ZIP file or drag the file to this area. currently, only .xml and .sql files in the ZIP file can be audited for SQL'
}
'Click to select a compressed file or drag the file to this area. Supports .zip, .rar, .7z formats. Only .sql, .xml, .txt, .java files in the archive will be audited'
},
xlsxTemplateTips: 'Please use the standard template format',
downloadTemplate: 'Download template',
noSqlColumnFound: 'No column containing SQL found, please refer to the template'
}
},
result: {
Expand Down
11 changes: 7 additions & 4 deletions packages/sqle/src/locale/zh-CN/execWorkflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,20 +76,23 @@ export default {

sql: 'SQL语句',
sqlFile: 'SQL文件',
sqlFileTips: '点击选择SQL文件或将文件拖拽到此区域',
sqlFileTips: '点击选择文件或将文件拖拽到此区域,支持 .sql, .txt, .java, .xlsx 格式',
mybatisFile: 'Mybatis的XML文件',
mybatisFileTips: '点击选择XML文件或将文件拖拽到此区域',
zipFile: 'zip文件',
zipFile: '压缩包',
zipFileTips:
'点击选择zip文件或将文件拖拽到此区域,当前仅支持对ZIP文件中的.xml文件及.sql文件做SQL审核',
'点击选择压缩包或将文件拖拽到此区域,支持 .zip, .rar, .7z 格式,仅支持对压缩包内 .sql, .xml, .txt, .java 文件做SQL审核',

addInstanceTips: '请添加数据源',
addInstance: '添加数据源',
uploadType: '选择SQL语句上传方式',
manualInput: '输入SQL语句',
uploadFile: '上传SQL文件',
updateMybatisFile: '上传Mybatis的XML文件',
uploadZipFile: '上传ZIP文件',
uploadZipFile: '上传压缩包',
xlsxTemplateTips: '请使用标准模板格式',
downloadTemplate: '下载模板',
noSqlColumnFound: '未找到包含SQL的列,请参照模板格式',

audit: '审核',
analyze: 'SQL分析',
Expand Down
13 changes: 8 additions & 5 deletions packages/sqle/src/locale/zh-CN/sqlAudit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,14 @@ export default {
sql: '输入SQL语句',
sqlFile: '上传SQL文件',
mybatisFile: '上传Mybatis的XML文件',
zipFile: '上传ZIP文件',
zipFile: '上传压缩包',
git: '配置GIT仓库'
},
uploadLabelEnum: {
sql: 'SQL语句',
sqlFile: 'SQL文件',
mybatisFile: 'Mybatis的XML文件',
zipFile: 'ZIP文件',
zipFile: '压缩包',
gitUrl: 'GIT地址',
gitProtocol: 'Git协议类型',
gitUrlTips: '请输入代码仓库地址',
Expand All @@ -101,11 +101,14 @@ export default {
sshAuthTips: '使用SSH协议克隆仓库时,需要先配置SSH密钥。'
},
uploadFileTip: {
sqlFile: '点击选择SQL文件或将文件拖拽到此区域',
sqlFile: '点击选择文件或将文件拖拽到此区域,支持 .sql, .txt, .java, .xlsx 格式',
mybatisFile: '点击选择Mybatis的XML文件或将文件拖拽到此区域',
zipFile:
'点击选择ZIP文件或将文件拖拽到此区域,当前仅支持对ZIP文件中的.xml文件及.sql文件做SQL审核'
}
'点击选择压缩包或将文件拖拽到此区域,支持 .zip, .rar, .7z 格式,仅支持对压缩包内 .sql, .xml, .txt, .java 文件做SQL审核'
},
xlsxTemplateTips: '请使用标准模板格式',
downloadTemplate: '下载模板',
noSqlColumnFound: '未找到包含SQL的列,请参照模板格式'
}
},
result: {
Expand Down
Loading
Loading