mirror of
https://github.com/dataelement/bisheng.git
synced 2026-09-01 15:32:50 +08:00
fix(frontend): generic fallback at every error-copy exit (ledger #11)
- new api_errors `fallback` key (3 languages); naked i18n keys can no longer
reach users when a code has no translation (gateway codes, pre-CI legacy)
- client (6 exits): SSE/WS/chat-input/route/request-layer fall back to generic
Chinese; t(key, vars) kept so {{xxx}} templates still interpolate
- platform (5 exits): fall back status_message -> generic copy (admin keeps
backend diagnostics); chatErrorMessage's literal "error" fallback removed
This commit is contained in:
@@ -121,7 +121,14 @@ export const translateApiErrorMessage = (data: any) => {
|
||||
if (statusMessageKey && i18next.exists(statusMessageKey)) {
|
||||
return i18next.t(statusMessageKey, data?.data);
|
||||
}
|
||||
return statusMessage || (statusCodeKey ? i18next.t(statusCodeKey, data?.data) : "");
|
||||
// Last resort keeps t(key, vars) so {{xxx}} templates still interpolate from
|
||||
// data.data; defaultValue guards the truly-untranslated case — never the raw key.
|
||||
return (
|
||||
statusMessage ||
|
||||
(statusCodeKey
|
||||
? String(i18next.t(statusCodeKey, { ...(data?.data || {}), defaultValue: String(i18next.t("api_errors.fallback")) }))
|
||||
: "")
|
||||
);
|
||||
};
|
||||
|
||||
// License degradation (gateway returns 11001): throttle the toast so a burst of
|
||||
|
||||
@@ -227,7 +227,7 @@ export default function useSSE(
|
||||
|
||||
// localize
|
||||
const _data = {
|
||||
text: localize(`api_errors.${data?.status_code}`, data?.data),
|
||||
text: localize(`api_errors.${data?.status_code}`, { ...(data?.data || {}), defaultValue: localize('api_errors.fallback') }),
|
||||
}
|
||||
errorHandler({ data: _data, submission: { ...submission, userMessage } as EventSubmission });
|
||||
});
|
||||
|
||||
@@ -392,5 +392,6 @@
|
||||
"24005": "Invalid quota_config or department_id value",
|
||||
"90001": "You do not have permission to access the admin backend. Please contact the administrator to request access if needed.",
|
||||
"90002": "Your current role does not have permission to access the workbench. Please contact the administrator if needed.",
|
||||
"personIdAlreadyExists": "Person ID already exists"
|
||||
"personIdAlreadyExists": "Person ID already exists",
|
||||
"fallback": "The operation failed. Please try again later."
|
||||
}
|
||||
|
||||
@@ -392,5 +392,6 @@
|
||||
"24005": "quota_configまたはdepartment_idの値が無効です。",
|
||||
"90001": "現在のアカウントには管理バックエンドへのアクセス権限がありません。必要な場合は、管理者に連絡して権限を開通してください。",
|
||||
"90002": "現在のロールにはワークベンチへのアクセス権限がありません。必要な場合は管理者に連絡してください。",
|
||||
"personIdAlreadyExists": "Person ID は既に存在します"
|
||||
"personIdAlreadyExists": "Person ID は既に存在します",
|
||||
"fallback": "操作に失敗しました。しばらくしてから再試行してください。"
|
||||
}
|
||||
|
||||
@@ -392,5 +392,6 @@
|
||||
"24005": "quota_config 或 department_id 配置无效。",
|
||||
"90001": "您当前角色没有访问管理后台的权限。如有需要,请联系管理员开通。",
|
||||
"90002": "您当前角色没有访问工作台的权限。如有需要,请联系管理员开通。",
|
||||
"personIdAlreadyExists": "人员 ID 已存在"
|
||||
"personIdAlreadyExists": "人员 ID 已存在",
|
||||
"fallback": "操作失败,请稍后重试"
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ export default function ChatInput({ readOnly, v }) {
|
||||
// ... Placeholder 和 AutoFocus 逻辑保持不变 ...
|
||||
const placholder = useMemo(() => {
|
||||
return inputDisabled ?
|
||||
(inputMsg.code ? localize(`api_errors.${inputMsg.code}`, inputMsg.data) : ' ')
|
||||
(inputMsg.code ? localize(`api_errors.${inputMsg.code}`, { ...(inputMsg.data || {}), defaultValue: localize('api_errors.fallback') }) : ' ')
|
||||
: localize('com_ui_please_enter_question')
|
||||
}, [inputDisabled, inputMsg, localize]);
|
||||
|
||||
|
||||
@@ -204,7 +204,7 @@ export const useWebSocket = (helpers) => {
|
||||
}
|
||||
if (![10421, 13002].includes(code)) {
|
||||
showToast({
|
||||
message: code === 500 ? message : localize(`api_errors.${String(code)}`, data.message?.data),
|
||||
message: code === 500 ? message : localize(`api_errors.${String(code)}`, { ...(data.message?.data || {}), defaultValue: localize('api_errors.fallback') }),
|
||||
severity: NotificationSeverity.ERROR,
|
||||
})
|
||||
} else {
|
||||
|
||||
@@ -55,7 +55,7 @@ const useErrorPrompt = () => {
|
||||
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
showToast({ message: localize(`api_errors.${error}`), status: 'error' });
|
||||
showToast({ message: localize(`api_errors.${error}`, { defaultValue: localize('api_errors.fallback') }), status: 'error' });
|
||||
}
|
||||
}, []);
|
||||
};
|
||||
@@ -392,5 +392,6 @@
|
||||
"24005": "Invalid quota_config or department_id value",
|
||||
"90001": "You do not have permission to access the admin backend. Please contact the administrator to request access if needed.",
|
||||
"90002": "Your current role does not have permission to access the workbench. Please contact the administrator if needed.",
|
||||
"personIdAlreadyExists": "Person ID already exists"
|
||||
"personIdAlreadyExists": "Person ID already exists",
|
||||
"fallback": "The operation failed. Please try again later."
|
||||
}
|
||||
|
||||
@@ -392,5 +392,6 @@
|
||||
"24005": "quota_configまたはdepartment_idの値が無効です。",
|
||||
"90001": "現在のアカウントには管理バックエンドへのアクセス権限がありません。必要な場合は、管理者に連絡して権限を開通してください。",
|
||||
"90002": "現在のロールにはワークベンチへのアクセス権限がありません。必要な場合は管理者に連絡してください。",
|
||||
"personIdAlreadyExists": "Person ID は既に存在します"
|
||||
"personIdAlreadyExists": "Person ID は既に存在します",
|
||||
"fallback": "操作に失敗しました。しばらくしてから再試行してください。"
|
||||
}
|
||||
|
||||
@@ -392,5 +392,6 @@
|
||||
"24005": "quota_config 或 department_id 配置无效。",
|
||||
"90001": "您当前角色没有访问管理后台的权限。如有需要,请联系管理员开通。",
|
||||
"90002": "您当前角色没有访问工作台的权限。如有需要,请联系管理员开通。",
|
||||
"personIdAlreadyExists": "人员 ID 已存在"
|
||||
"personIdAlreadyExists": "人员 ID 已存在",
|
||||
"fallback": "操作失败,请稍后重试"
|
||||
}
|
||||
|
||||
@@ -392,5 +392,6 @@
|
||||
"24005": "Invalid quota_config or department_id value",
|
||||
"90001": "You do not have permission to access the admin backend. Please contact the administrator to request access if needed.",
|
||||
"90002": "Your current role does not have permission to access the workbench. Please contact the administrator if needed.",
|
||||
"personIdAlreadyExists": "Person ID already exists"
|
||||
"personIdAlreadyExists": "Person ID already exists",
|
||||
"fallback": "The operation failed. Please try again later."
|
||||
}
|
||||
|
||||
@@ -392,5 +392,6 @@
|
||||
"24005": "quota_configまたはdepartment_idの値が無効です。",
|
||||
"90001": "現在のアカウントには管理バックエンドへのアクセス権限がありません。必要な場合は、管理者に連絡して権限を開通してください。",
|
||||
"90002": "現在のロールにはワークベンチへのアクセス権限がありません。必要な場合は管理者に連絡してください。",
|
||||
"personIdAlreadyExists": "Person ID は既に存在します"
|
||||
"personIdAlreadyExists": "Person ID は既に存在します",
|
||||
"fallback": "操作に失敗しました。しばらくしてから再試行してください。"
|
||||
}
|
||||
|
||||
@@ -392,5 +392,6 @@
|
||||
"24005": "quota_config 或 department_id 配置无效。",
|
||||
"90001": "您当前角色没有访问管理后台的权限。如有需要,请联系管理员开通。",
|
||||
"90002": "您当前角色没有访问工作台的权限。如有需要,请联系管理员开通。",
|
||||
"personIdAlreadyExists": "人员 ID 已存在"
|
||||
"personIdAlreadyExists": "人员 ID 已存在",
|
||||
"fallback": "操作失败,请稍后重试"
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ export default function App() {
|
||||
useEffect(() => {
|
||||
if (window.url_error) {
|
||||
toast({
|
||||
description: t(`api_errors:${window.url_error}`, { defaultValue: String(window.url_error) }),
|
||||
description: t(`api_errors:${window.url_error}`, { defaultValue: t('api_errors:fallback') }),
|
||||
variant: 'error',
|
||||
});
|
||||
delete window.url_error
|
||||
|
||||
@@ -33,7 +33,7 @@ export function resolveChatErrorMessage(
|
||||
payload: ChatErrorPayload | null | undefined,
|
||||
translate: Translate,
|
||||
): string {
|
||||
const fallbackMessage = payload?.status_message || "error";
|
||||
const fallbackMessage = payload?.status_message || String(translate("api_errors:fallback") ?? "");
|
||||
const statusCode = payload?.status_code;
|
||||
|
||||
const interpolationParams =
|
||||
|
||||
@@ -283,7 +283,7 @@ export default function ChatInput({ autoRun, version, clear, form, wsUrl, onBefo
|
||||
}
|
||||
|
||||
// 记录
|
||||
const errorMsg = status_code == 500 ? status_message || data.message.message : t(`api_errors:${status_code}`, params)
|
||||
const errorMsg = status_code == 500 ? status_message || data.message.message : t(`api_errors:${status_code}`, { ...(params || {}), defaultValue: status_message || t('api_errors:fallback') })
|
||||
addNotification({
|
||||
type: 'error',
|
||||
title: 'runtime error',
|
||||
|
||||
@@ -64,7 +64,7 @@ export const useErrorPrompt = () => {
|
||||
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
toast({ description: t(`api_errors:${error}`), variant: 'error' });
|
||||
toast({ description: t(`api_errors:${error}`, { defaultValue: t('api_errors:fallback') }), variant: 'error' });
|
||||
|
||||
// Clear the 'error' parameter from the URL
|
||||
const newUrl = window.location.origin + window.location.pathname;
|
||||
|
||||
@@ -93,7 +93,7 @@ export const StatusIndicator: React.FC<StatusIndicatorProps> = ({ status, remark
|
||||
}
|
||||
const mediaMessage = formatMediaParseFailureMessage(obj, t);
|
||||
if (mediaMessage) return mediaMessage;
|
||||
return t(`api_errors:${obj.status_code}`, obj.data)
|
||||
return t(`api_errors:${obj.status_code}`, { ...(obj.data || {}), defaultValue: obj.status_message || t('api_errors:fallback') })
|
||||
} catch (error) {
|
||||
return trimmedRemark
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user