mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-09-26 17:52:59 +02:00
add translations and error messages for encrypted/password protected files being edited
This commit is contained in:
parent
f412a3a60e
commit
c9ac919c55
@ -74,6 +74,8 @@
|
||||
},
|
||||
"error": {
|
||||
"pdfPassword": "The PDF Document is passworded and either the password was not provided or was incorrect",
|
||||
"encryptedPdfMustRemovePassword": "This PDF is encrypted or password-protected. Please unlock it before converting to PDF/A.",
|
||||
"incorrectPasswordProvided": "The PDF password is incorrect or not provided.",
|
||||
"_value": "Error",
|
||||
"dismissAllErrors": "Dismiss All Errors",
|
||||
"sorry": "Sorry for the issue!",
|
||||
|
@ -68,6 +68,8 @@
|
||||
},
|
||||
"error": {
|
||||
"pdfPassword": "The PDF Document is passworded and either the password was not provided or was incorrect",
|
||||
"encryptedPdfMustRemovePassword": "This PDF is encrypted or password-protected. Please unlock it before converting to PDF/A.",
|
||||
"incorrectPasswordProvided": "The PDF password is incorrect or not provided.",
|
||||
"_value": "Error",
|
||||
"sorry": "Sorry for the issue!",
|
||||
"needHelp": "Need help / Found an issue?",
|
||||
|
@ -1,6 +1,7 @@
|
||||
import axios from 'axios';
|
||||
import { alert } from '../components/toast';
|
||||
import { broadcastErroredFiles, extractErrorFileIds, normalizeAxiosErrorData } from './errorUtils';
|
||||
import { showSpecialErrorToast } from './specialErrorToasts';
|
||||
|
||||
const FRIENDLY_FALLBACK = 'There was an error processing your request.';
|
||||
|
||||
@ -49,6 +50,11 @@ function extractAxiosErrorMessage(error: any): { title: string; body: string } {
|
||||
if (typeof raw === 'string') return raw;
|
||||
try { return JSON.stringify(data); } catch { return ''; }
|
||||
})();
|
||||
// Specific friendly mapping for encrypted PDFs (centralized toast also fires in interceptor)
|
||||
if (ENCRYPTION_ERROR_REGEX.test(body)) {
|
||||
const title = titleForStatus(error.response?.status);
|
||||
return { title, body: ENCRYPTION_FRIENDLY };
|
||||
}
|
||||
const ids = extractIds();
|
||||
const title = titleForStatus(status);
|
||||
if (ids && ids.length > 0) {
|
||||
@ -64,6 +70,9 @@ function extractAxiosErrorMessage(error: any): { title: string; body: string } {
|
||||
}
|
||||
try {
|
||||
const msg = (error?.message || String(error)) as string;
|
||||
if (ENCRYPTION_ERROR_REGEX.test(msg)) {
|
||||
return { title: 'Request error', body: ENCRYPTION_FRIENDLY };
|
||||
}
|
||||
return { title: 'Network error', body: isUnhelpfulMessage(msg) ? FRIENDLY_FALLBACK : msg };
|
||||
} catch (e) {
|
||||
// ignore extraction errors
|
||||
@ -109,7 +118,17 @@ const __INTERCEPTOR_ID__ = axios.interceptors.response.use(
|
||||
}
|
||||
}
|
||||
|
||||
alert({ alertType: 'error', title, body, expandable: true, isPersistentPopup: false });
|
||||
// Show specialized friendly toasts if matched; otherwise show the generic one
|
||||
const raw = (error?.response?.data) as any;
|
||||
let rawString: string | undefined;
|
||||
try {
|
||||
if (typeof raw === 'string') rawString = raw;
|
||||
else rawString = await normalizeAxiosErrorData(raw).then((d) => (typeof d === 'string' ? d : JSON.stringify(d)));
|
||||
} catch { /* ignore */ }
|
||||
const handled = showSpecialErrorToast(rawString, { status });
|
||||
if (!handled) {
|
||||
alert({ alertType: 'error', title, body, expandable: true, isPersistentPopup: false });
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
57
frontend/src/services/specialErrorToasts.ts
Normal file
57
frontend/src/services/specialErrorToasts.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import { alert } from '../components/toast';
|
||||
|
||||
interface ErrorToastMapping {
|
||||
regex: RegExp;
|
||||
i18nKey: string;
|
||||
defaultMessage: string;
|
||||
}
|
||||
|
||||
// Centralized list of special backend error message patterns → friendly, translated toasts
|
||||
const MAPPINGS: ErrorToastMapping[] = [
|
||||
{
|
||||
regex: /pdf contains an encryption dictionary/i,
|
||||
i18nKey: 'errors.encryptedPdfMustRemovePassword',
|
||||
defaultMessage: 'This PDF is encrypted. Please unlock it using the Unlock PDF Forms tool.'
|
||||
},
|
||||
{
|
||||
regex: /the pdf document is passworded and either the password was not provided or was incorrect/i,
|
||||
i18nKey: 'errors.incorrectPasswordProvided',
|
||||
defaultMessage: 'The PDF password is incorrect or not provided.'
|
||||
},
|
||||
];
|
||||
|
||||
function titleForStatus(status?: number): string {
|
||||
if (!status) return 'Network error';
|
||||
if (status >= 500) return 'Server error';
|
||||
if (status >= 400) return 'Request error';
|
||||
return 'Request failed';
|
||||
}
|
||||
|
||||
/**
|
||||
* Match a raw backend error string against known patterns and show a friendly toast.
|
||||
* Returns true if a special toast was shown, false otherwise.
|
||||
*/
|
||||
export function showSpecialErrorToast(rawError: string | undefined, options?: { status?: number }): boolean {
|
||||
const message = (rawError || '').toString();
|
||||
if (!message) return false;
|
||||
|
||||
for (const mapping of MAPPINGS) {
|
||||
if (mapping.regex.test(message)) {
|
||||
// Best-effort translation without hard dependency on i18n config
|
||||
let body = mapping.defaultMessage;
|
||||
try {
|
||||
const anyGlobal: any = (globalThis as any);
|
||||
const i18next = anyGlobal?.i18next;
|
||||
if (i18next && typeof i18next.t === 'function') {
|
||||
body = i18next.t(mapping.i18nKey, { defaultValue: mapping.defaultMessage });
|
||||
}
|
||||
} catch { /* ignore translation errors */ }
|
||||
const title = titleForStatus(options?.status);
|
||||
alert({ alertType: 'error', title, body, expandable: true, isPersistentPopup: false });
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user