diff --git a/packages/sqle/src/hooks/useRuleCategories/index.data.ts b/packages/sqle/src/hooks/useRuleCategories/index.data.ts index 423dc29f8..1df7317f7 100644 --- a/packages/sqle/src/hooks/useRuleCategories/index.data.ts +++ b/packages/sqle/src/hooks/useRuleCategories/index.data.ts @@ -2,15 +2,19 @@ import { t } from '../../locale'; export type DictionaryType = { [key: string]: string }; -export const RuleCategoryDictionary: DictionaryType = { +// Use getter functions instead of static constants so that t() is called at +// render time, returning the translation for the *current* language rather +// than the language that was active when the module was first imported. + +export const getRuleCategoryDictionary = (): DictionaryType => ({ audit_accuracy: t('rule.category.auditAccuracy'), audit_purpose: t('rule.category.auditPurpose'), operand: t('rule.category.operand'), sql: t('rule.category.sql'), performance_cost: t('rule.category.performanceCost') -}; +}); -export const RuleCategoryOperandDictionary = { +export const getRuleCategoryOperandDictionary = (): DictionaryType => ({ database: t('rule.category.tag.database'), table_space: t('rule.category.tag.tableSpace'), table: t('rule.category.tag.table'), @@ -24,9 +28,9 @@ export const RuleCategoryOperandDictionary = { user: t('rule.category.tag.user'), sequence: t('rule.category.tag.sequence'), business: t('rule.category.tag.business') -}; +}); -export const RuleCategorySqlDictionary = { +export const getRuleCategorySqlDictionary = (): DictionaryType => ({ ddl: t('rule.category.tag.ddl'), dcl: t('rule.category.tag.dcl'), dml: t('rule.category.tag.dml'), @@ -42,30 +46,88 @@ export const RuleCategorySqlDictionary = { sql_procedure: t('rule.category.tag.procedure'), sql_trigger: t('rule.category.tag.trigger'), sql_view: t('rule.category.tag.view') -}; +}); -export const RuleCategoryAuditPurposeDictionary = { +export const getRuleCategoryAuditPurposeDictionary = (): DictionaryType => ({ correction: t('rule.category.tag.correction'), security: t('rule.category.tag.security'), maintenance: t('rule.category.tag.maintenance'), performance: t('rule.category.tag.performance') -}; +}); -export const RuleCategoryAuditAccuracyDictionary = { +export const getRuleCategoryAuditAccuracyDictionary = (): DictionaryType => ({ online: t('rule.category.tag.online'), offline: t('rule.category.tag.offline') -}; +}); -export const RuleCategoryPerformanceCostDictionary = { +export const getRuleCategoryPerformanceCostDictionary = (): DictionaryType => ({ high: t('rule.category.tag.high'), medium: t('rule.category.tag.medium'), low: t('rule.category.tag.low') -}; +}); + +export const getRuleCategoryDictionaryGroup = (): { + [key: string]: DictionaryType; +} => ({ + audit_accuracy: getRuleCategoryAuditAccuracyDictionary(), + audit_purpose: getRuleCategoryAuditPurposeDictionary(), + operand: getRuleCategoryOperandDictionary(), + sql: getRuleCategorySqlDictionary(), + performance_cost: getRuleCategoryPerformanceCostDictionary() +}); + +// Backward-compatible aliases: these are kept so that existing imports +// continue to compile, but they still evaluate t() lazily via Proxy. +const makeLazyDict = (getter: () => DictionaryType): DictionaryType => + new Proxy( + {}, + { + get(_target, prop: string) { + return getter()[prop]; + }, + ownKeys() { + return Object.keys(getter()); + }, + getOwnPropertyDescriptor(_target, prop: string) { + const val = getter()[prop]; + if (val !== undefined) { + return { configurable: true, enumerable: true, value: val }; + } + return undefined; + } + } + ); -export const RuleCategoryDictionaryGroup: { [key: string]: DictionaryType } = { - audit_accuracy: RuleCategoryAuditAccuracyDictionary, - audit_purpose: RuleCategoryAuditPurposeDictionary, - operand: RuleCategoryOperandDictionary, - sql: RuleCategorySqlDictionary, - performance_cost: RuleCategoryPerformanceCostDictionary -}; +export const RuleCategoryDictionary: DictionaryType = makeLazyDict( + getRuleCategoryDictionary +); +export const RuleCategoryOperandDictionary: DictionaryType = makeLazyDict( + getRuleCategoryOperandDictionary +); +export const RuleCategorySqlDictionary: DictionaryType = makeLazyDict( + getRuleCategorySqlDictionary +); +export const RuleCategoryAuditPurposeDictionary: DictionaryType = makeLazyDict( + getRuleCategoryAuditPurposeDictionary +); +export const RuleCategoryAuditAccuracyDictionary: DictionaryType = makeLazyDict( + getRuleCategoryAuditAccuracyDictionary +); +export const RuleCategoryPerformanceCostDictionary: DictionaryType = + makeLazyDict(getRuleCategoryPerformanceCostDictionary); +export const RuleCategoryDictionaryGroup: { [key: string]: DictionaryType } = + new Proxy({} as { [key: string]: DictionaryType }, { + get(_target, prop: string) { + return getRuleCategoryDictionaryGroup()[prop]; + }, + ownKeys() { + return Object.keys(getRuleCategoryDictionaryGroup()); + }, + getOwnPropertyDescriptor(_target, prop: string) { + const val = getRuleCategoryDictionaryGroup()[prop]; + if (val !== undefined) { + return { configurable: true, enumerable: true, value: val }; + } + return undefined; + } + }); diff --git a/packages/sqle/src/hooks/useRuleCategories/index.tsx b/packages/sqle/src/hooks/useRuleCategories/index.tsx index 42f668621..6ffdd2de0 100644 --- a/packages/sqle/src/hooks/useRuleCategories/index.tsx +++ b/packages/sqle/src/hooks/useRuleCategories/index.tsx @@ -2,11 +2,16 @@ import ruleTemplate from '@actiontech/shared/lib/api/sqle/service/rule_template' import { useRequest } from 'ahooks'; import { ResponseCode } from '@actiontech/dms-kit'; import { ReactNode, useMemo } from 'react'; -import { RuleCategoryDictionaryGroup, DictionaryType } from './index.data'; +import { + getRuleCategoryDictionaryGroup, + DictionaryType +} from './index.data'; import { Typography } from 'antd'; import { RuleCategoryOptionStyleWrapper } from './style'; +import { useTranslation } from 'react-i18next'; const useRuleCategories = (showOptionCount = false) => { + const { i18n } = useTranslation(); const { data: ruleCategories, loading: getRuleCategoriesLoading } = useRequest(() => ruleTemplate.getCategoryStatistics().then((res) => { @@ -39,13 +44,14 @@ const useRuleCategories = (showOptionCount = false) => { return dictionary?.[tag]; }; + const dictionaryGroup = getRuleCategoryDictionaryGroup(); const optionGroup: { [key: string]: | Array<{ label: ReactNode; value: string; text: string }> | undefined; } = {}; Object.keys(ruleCategories ?? {}).forEach((key) => { - const dictionary = RuleCategoryDictionaryGroup[key]; + const dictionary = dictionaryGroup[key]; optionGroup[key] = ruleCategories?.[key]?.map((i) => ({ label: renderOptionLabel(dictionary, i.tag ?? '', i.count ?? 0), value: i.tag ?? '', @@ -59,7 +65,8 @@ const useRuleCategories = (showOptionCount = false) => { auditPurposeOptions: optionGroup.audit_purpose, performanceLevelOptions: optionGroup.performance_cost }; - }, [ruleCategories, showOptionCount]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [ruleCategories, showOptionCount, i18n.language]); return { ruleCategories, diff --git a/packages/sqle/src/locale/en-US/rule.ts b/packages/sqle/src/locale/en-US/rule.ts index 3cf83d42f..638a1a4d4 100644 --- a/packages/sqle/src/locale/en-US/rule.ts +++ b/packages/sqle/src/locale/en-US/rule.ts @@ -31,5 +31,49 @@ export default { ruleDetail: { title: 'View rule', knowledge: 'Rule knowledge base' + }, + category: { + auditAccuracy: 'Audit Accuracy', + auditPurpose: 'Audit Purpose', + operand: 'Operand', + sql: 'SQL Category', + performanceCost: 'Performance Cost', + performanceLevelTips: + 'High-cost rules generate extensive data scans or complex queries that may significantly impact database performance. Use with caution in production environments.', + tag: { + online: 'Online', + offline: 'Offline', + database: 'Database', + tableSpace: 'Tablespace', + table: 'Table', + column: 'Column', + index: 'Index', + view: 'View', + procedure: 'Stored Procedure', + function: 'Function', + trigger: 'Trigger', + event: 'Event', + user: 'User', + ddl: 'DDL', + dcl: 'DCL', + dml: 'DML', + integrity: 'Integrity Constraint', + query: 'Query', + transaction: 'Transaction Control', + privilege: 'Data Privilege', + management: 'Database Management', + complete: 'Completeness Constraint', + join: 'Join', + table_space: 'Tablespace', + sequence: 'Sequence', + business: 'Business Data', + correction: 'Correctness', + security: 'Security', + maintenance: 'Maintainability', + performance: 'Performance', + high: 'High Cost', + medium: 'Medium Cost', + low: 'Low Cost' + } } };