This is an automated email from the ASF dual-hosted git repository.
lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git
The following commit(s) were added to refs/heads/rocketmq-studio by this push:
new 4e7ac54dc fix(audit): route the audit page's remaining hardcoded
strings through the dictionary (#6480)
4e7ac54dc is described below
commit 4e7ac54dc70dc832505c2e954caacb3088f8f63b
Author: 0 <[email protected]>
AuthorDate: Thu Oct 15 18:12:43 2026 +0800
fix(audit): route the audit page's remaining hardcoded strings through the
dictionary (#6480)
* fix(audit): take the remaining audit-page strings through the translation
table
Four error toasts (record load, summary load, cleanup, export) and the
cleanup-window suffix rendered hardcoded Chinese on an otherwise
localized page. They now resolve through t() with audit.* keys for both
languages, and a test renders the page in English to pin the load toast
and the cleanup suffix.
Fixes #5223
* fix(audit): cover every localized toast and keep t in the effect deps
---
web/src/i18n/translations.ts | 17 +++++++++++
web/src/pages/ops/__tests__/AuditPage.test.tsx | 41 ++++++++++++++++++++++++++
web/src/pages/ops/audit.tsx | 13 ++++----
3 files changed, 65 insertions(+), 6 deletions(-)
diff --git a/web/src/i18n/translations.ts b/web/src/i18n/translations.ts
index f7d9cf1e3..7e743b4ec 100644
--- a/web/src/i18n/translations.ts
+++ b/web/src/i18n/translations.ts
@@ -1637,6 +1637,23 @@ const translations: Record<string, Record<Lang, string>>
= {
'audit.cleanupDays': { zh: '清理 {n} 天之前的日志', en: 'Clean logs older than {n}
days' },
'audit.cleanupConfirm': { zh: '确认清理', en: 'Confirm Cleanup' },
'audit.cleanupSuccess': { zh: '已清理 {n} 天之前的日志', en: 'Cleaned logs older than
{n} days' },
+ 'audit.loadFailed': {
+ zh: '审计日志加载失败,请稍后重试',
+ en: 'Failed to load audit logs, please retry later',
+ },
+ 'audit.summaryLoadFailed': {
+ zh: '审计概览加载失败,请稍后重试',
+ en: 'Failed to load the audit summary, please retry later',
+ },
+ 'audit.cleanupFailed': {
+ zh: '清理审计日志失败,请稍后重试',
+ en: 'Failed to clean audit logs, please retry later',
+ },
+ 'audit.exportFailed': {
+ zh: '导出审计日志失败,请稍后重试',
+ en: 'Failed to export audit logs, please retry later',
+ },
+ 'audit.cleanupDaysSuffix': { zh: '天之前的日志', en: 'days and older' },
'audit.summaryMatched': { zh: '匹配记录', en: 'Matched Records' },
'audit.summarySuccessRate': { zh: '成功率', en: 'Success Rate' },
'audit.summaryOperators': { zh: '操作人数', en: 'Operators' },
diff --git a/web/src/pages/ops/__tests__/AuditPage.test.tsx
b/web/src/pages/ops/__tests__/AuditPage.test.tsx
index fc5fd5108..283ed6e7b 100644
--- a/web/src/pages/ops/__tests__/AuditPage.test.tsx
+++ b/web/src/pages/ops/__tests__/AuditPage.test.tsx
@@ -338,6 +338,47 @@ describe('Audit page', () => {
expect(container.querySelector('.ant-spin-spinning')).not.toBeNull();
});
+ it('renders the cleanup window and the error toasts in the display
language', async () => {
+ window.localStorage.setItem('rocketmq-studio-language', 'en');
+ const user = userEvent.setup();
+ vi.mocked(opsService.listAuditRecords).mockRejectedValueOnce(new
Error('boom'));
+ vi.mocked(opsService.getAuditSummary).mockRejectedValueOnce(new
Error('boom'));
+
+ renderWithProviders(<AuditPage />);
+
+ // The load failure toast and the cleanup-window suffix were hardcoded
Chinese.
+ expect(
+ await screen.findByText('Failed to load audit logs, please retry later'),
+ ).toBeInTheDocument();
+ expect(
+ await screen.findByText('Failed to load the audit summary, please retry
later'),
+ ).toBeInTheDocument();
+ await user.click(screen.getByRole('button', { name: /Cleanup/ }));
+ expect(await screen.findByText('days and older')).toBeInTheDocument();
+ expect(screen.queryByText('天之前的日志')).not.toBeInTheDocument();
+ });
+
+ it('renders the cleanup and export failure toasts in the display language',
async () => {
+ window.localStorage.setItem('rocketmq-studio-language', 'en');
+ const user = userEvent.setup();
+ vi.mocked(opsService.cleanupAuditLogs).mockRejectedValueOnce(new
Error('boom'));
+ vi.mocked(opsService.exportAuditLogs).mockRejectedValueOnce(new
Error('boom'));
+
+ renderWithProviders(<AuditPage />);
+ expect(await screen.findByText('topic-a')).toBeInTheDocument();
+
+ await user.click(screen.getByRole('button', { name: /export/i }));
+ expect(
+ await screen.findByText('Failed to export audit logs, please retry
later'),
+ ).toBeInTheDocument();
+
+ await user.click(screen.getByRole('button', { name: /cleanup/i }));
+ await user.click(await screen.findByRole('button', { name: /confirm
cleanup/i }));
+ expect(
+ await screen.findByText('Failed to clean audit logs, please retry
later'),
+ ).toBeInTheDocument();
+ });
+
it('ignores stale filter-option responses after cleanup refreshes', async ()
=> {
const user = userEvent.setup();
const staleOptions = deferred<Awaited<ReturnType<typeof
opsService.getAuditFilterOptions>>>();
diff --git a/web/src/pages/ops/audit.tsx b/web/src/pages/ops/audit.tsx
index 5a8533ac3..bee2c6ac5 100644
--- a/web/src/pages/ops/audit.tsx
+++ b/web/src/pages/ops/audit.tsx
@@ -165,7 +165,7 @@ const AuditPage: React.FC = () => {
})
.catch(() => {
if (recordsRequestRef.current === requestId) {
- message.error('审计日志加载失败,请稍后重试');
+ message.error(t('audit.loadFailed'));
}
})
.finally(() => {
@@ -181,6 +181,7 @@ const AuditPage: React.FC = () => {
dateRange,
resultFilter,
refreshKey,
+ t,
]);
useEffect(
@@ -224,7 +225,7 @@ const AuditPage: React.FC = () => {
if (!cancelled) setSummary(value);
})
.catch(() => {
- if (!cancelled) message.error('审计概览加载失败,请稍后重试');
+ if (!cancelled) message.error(t('audit.summaryLoadFailed'));
})
.finally(() => {
if (!cancelled) setSummaryLoading(false);
@@ -232,7 +233,7 @@ const AuditPage: React.FC = () => {
return () => {
cancelled = true;
};
- }, [activeFilter, refreshKey]);
+ }, [activeFilter, refreshKey, t]);
const { Text } = Typography;
@@ -302,7 +303,7 @@ const AuditPage: React.FC = () => {
message.success(t('audit.cleanupSuccess', { n: cleanupDays }));
setCleanupModalOpen(false);
} catch {
- message.error('清理审计日志失败,请稍后重试');
+ message.error(t('audit.cleanupFailed'));
} finally {
cleanupInFlightRef.current = false;
setCleaning(false);
@@ -316,7 +317,7 @@ const AuditPage: React.FC = () => {
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8' });
downloadBlob(blob,
`rocketmq-audit-logs-${dayjs().format('YYYY-MM-DD')}.csv`);
} catch {
- message.error('导出审计日志失败,请稍后重试');
+ message.error(t('audit.exportFailed'));
} finally {
setExporting(false);
}
@@ -601,7 +602,7 @@ const AuditPage: React.FC = () => {
value={cleanupDays}
onChange={(v) => setCleanupDays(v ?? 30)}
/>
- <span>天之前的日志</span>
+ <span>{t('audit.cleanupDaysSuffix')}</span>
</Flex>
</Flex>
</Modal>