Files
remark42/frontend/app/utils/errorUtils.ts
T
b22cd5f76a Add localization (#602)
* #10 add localization

* #10 revert locale from dev page

* #10 add more examples

* #10 localize auth panel

* #10 localize some comment message

* #10 localize some comment form message

* #10 translate vote messages

* #10 translate comment message

* #10 use messages value for translate reference

* #10 fix compile issue

* #10 use messages value for translate reference

* #10 use messages value for translate reference

* #10 use messages value for translate reference

* #10 use messages value for translate reference

* #10 use messages value for translate reference

* #10 translate comment message

* #10 translate comment form

* #10 translate comment form

* #10 translate root component

* #10 translate user info

* #10 translate settings

* #10 translate settings

* #10 translate toolbar

* #10 translate errors messages

* #10 sort dict

* #10 fix after rebase

* #10 localize anonymousLoginForm

* #10 localize emailLoginForm

* #10 update size-limit

* #10 localize subscribe by rss

* #10 localize subscribe by email

* #10 add de locale

* #10 increase limit size

* #10 auto generate loadLocale

* #10 add some documentation

* #10 fix error messages

* fix typo

* don't bundle en locale

* fix message id

* change size limits

* Update extract message pattern

Co-Authored-By: Pavel Mineev <pavel@mineev.me>

Co-authored-by: Pavel Mineev <pavel@mineev.me>
2020-03-04 14:56:00 -06:00

222 lines
5.0 KiB
TypeScript

import { IntlShape, defineMessages, MessageDescriptor } from 'react-intl';
const messages = defineMessages({
failedFetch: {
id: 'errors.failed-fetch',
defaultMessage: 'Failed to fetch. Please check your internet connection or try again a bit later',
description: {
code: -2,
},
},
0: {
id: 'errors.0',
defaultMessage: 'Something went wrong. Please try again a bit later.',
description: {
code: 0,
},
},
1: {
id: 'errors.1',
defaultMessage: 'Comment cannot be found. Please refresh the page and try again.',
description: {
code: 1,
},
},
2: {
id: 'errors.2',
defaultMessage: 'Failed to unmarshal incoming request.',
description: {
code: 2,
},
},
3: {
id: 'errors.3',
defaultMessage: `You don't have permission for this operation.`,
description: {
code: 3,
},
},
4: {
id: 'errors.4',
defaultMessage: `Invalid comment data.`,
description: {
code: 4,
},
},
5: {
id: 'errors.5',
defaultMessage: `Comment cannot be found. Please refresh the page and try again.`,
description: {
code: 5,
},
},
6: {
id: 'errors.6',
defaultMessage: `Site cannot be found. Please refresh the page and try again.`,
description: {
code: 6,
},
},
7: {
id: 'errors.7',
defaultMessage: `User has been blocked.`,
description: {
code: 7,
},
},
8: {
id: 'errors.8',
defaultMessage: `User has been blocked.`,
description: {
code: 8,
},
},
9: {
id: 'errors.9',
defaultMessage: `Comment changing failed. Please try again a bit later.`,
description: {
code: 9,
},
},
10: {
id: 'errors.10',
defaultMessage: `It is too late to edit the comment.`,
description: {
code: 10,
},
},
11: {
id: 'errors.11',
defaultMessage: `Comment already has reply, editing is not possible.`,
description: {
code: 11,
},
},
12: {
id: 'errors.12',
defaultMessage: `Cannot save voting result. Please try again a bit later.`,
description: {
code: 12,
},
},
13: {
id: 'errors.13',
defaultMessage: `You cannot vote for your own comment.`,
description: {
code: 13,
},
},
14: {
id: 'errors.14',
defaultMessage: `You have already voted for the comment.`,
description: {
code: 14,
},
},
15: {
id: 'errors.15',
defaultMessage: `Too many votes for the comment.`,
description: {
code: 15,
},
},
16: {
id: 'errors.16',
defaultMessage: `Min score reached for the comment.`,
description: {
code: 16,
},
},
17: {
id: 'errors.17',
defaultMessage: `Action rejected. Please try again a bit later.`,
description: {
code: 17,
},
},
18: {
id: 'errors.18',
defaultMessage: `Requested file cannot be found.`,
description: {
code: 18,
},
},
});
/**
* map of codes that server returns in its response in case of error
* to client readable version
*/
const errorMessageForCodes = new Map<number, MessageDescriptor>();
Object.entries(messages).forEach(([, messageDescriptor]) => {
errorMessageForCodes.set(messageDescriptor.description.code, messageDescriptor);
});
export const httpMessages = defineMessages({
notAuthorized: {
id: 'errors.not-authorized',
defaultMessage: 'Not authorized.',
},
forbidden: {
id: 'errors.forbidden',
defaultMessage: 'Forbidden.',
},
toManyRequest: {
id: 'errors.to-many-request',
defaultMessage: 'You have reached maximum request limit.',
},
unexpectedError: {
id: 'errors.unexpected-error',
defaultMessage: 'Something went wrong.',
},
});
/**
* map of http rest codes to ui label, used by fetcher to generate error with `-1` code
*/
export const httpErrorMap = new Map([
[401, httpMessages.notAuthorized],
[403, httpMessages.forbidden],
[429, httpMessages.toManyRequest],
]);
export function isFailedFetch(e?: Error): boolean {
return Boolean(e && e.message && e.message === `Failed to fetch`);
}
export type FetcherError =
| string
| {
/**
* Error code, that is part of server error response.
*
* Note that -1 is reserved for error where `error` field shall be used directly
*/
code?: number;
details?: string;
error: string;
};
export function extractErrorMessageFromResponse(response: FetcherError, intl: IntlShape): string {
const defaultErrorMessage = intl.formatMessage(errorMessageForCodes.get(0) || messages['0']);
if (!response) {
return defaultErrorMessage;
}
if (typeof response === 'string') {
return response;
}
if (
typeof response.code === 'number' &&
(errorMessageForCodes.has(response.code) || httpErrorMap.has(response.code))
) {
const messageDescriptor =
errorMessageForCodes.get(response.code) || httpErrorMap.get(response.code) || messages['0'];
return intl.formatMessage(messageDescriptor);
}
return defaultErrorMessage;
}