react-intl 3.12.0 → 4.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/dist/components/message.d.ts +1 -1
  3. package/dist/components/message.js +2 -2
  4. package/dist/components/plural.d.ts +1 -1
  5. package/dist/components/provider.js +13 -8
  6. package/dist/error.d.ts +11 -0
  7. package/dist/error.js +28 -0
  8. package/dist/formatters/dateTime.js +5 -4
  9. package/dist/formatters/displayName.js +4 -2
  10. package/dist/formatters/list.js +4 -2
  11. package/dist/formatters/message.d.ts +1 -2
  12. package/dist/formatters/message.js +17 -34
  13. package/dist/formatters/number.js +3 -2
  14. package/dist/formatters/plural.js +4 -2
  15. package/dist/formatters/relativeTime.js +4 -2
  16. package/dist/index.d.ts +2 -2
  17. package/dist/index.js +6 -4
  18. package/dist/react-intl.api.md +29 -22
  19. package/dist/react-intl.d.ts +77 -36
  20. package/dist/react-intl.js +6267 -5860
  21. package/dist/react-intl.js.map +1 -1
  22. package/dist/react-intl.min.js +1 -1
  23. package/dist/react-intl.min.js.map +1 -1
  24. package/dist/types.d.ts +5 -5
  25. package/dist/utils.d.ts +3 -4
  26. package/dist/utils.js +2 -18
  27. package/lib/components/message.d.ts +1 -1
  28. package/lib/components/message.js +2 -2
  29. package/lib/components/plural.d.ts +1 -1
  30. package/lib/components/provider.js +15 -10
  31. package/lib/error.d.ts +11 -0
  32. package/lib/error.js +9 -0
  33. package/lib/formatters/dateTime.js +6 -5
  34. package/lib/formatters/displayName.js +6 -4
  35. package/lib/formatters/list.js +6 -4
  36. package/lib/formatters/message.d.ts +1 -2
  37. package/lib/formatters/message.js +17 -31
  38. package/lib/formatters/number.js +4 -3
  39. package/lib/formatters/plural.js +6 -4
  40. package/lib/formatters/relativeTime.js +6 -4
  41. package/lib/index.d.ts +2 -2
  42. package/lib/index.js +4 -2
  43. package/lib/react-intl.d.ts +21 -17
  44. package/lib/tsdoc-metadata.json +1 -1
  45. package/lib/types.d.ts +5 -5
  46. package/lib/utils.d.ts +3 -4
  47. package/lib/utils.js +2 -16
  48. package/package.json +45 -47
  49. package/src/components/message.tsx +6 -5
  50. package/src/components/provider.tsx +25 -14
  51. package/src/error.ts +18 -0
  52. package/src/formatters/dateTime.ts +30 -5
  53. package/src/formatters/displayName.ts +15 -4
  54. package/src/formatters/list.ts +15 -4
  55. package/src/formatters/message.ts +49 -66
  56. package/src/formatters/number.ts +16 -3
  57. package/src/formatters/plural.ts +15 -4
  58. package/src/formatters/relativeTime.ts +15 -4
  59. package/src/index.ts +4 -2
  60. package/src/types.ts +5 -7
  61. package/src/utils.ts +4 -25
  62. package/dist/components/html-message.d.ts +0 -11
  63. package/dist/components/html-message.js +0 -75
  64. package/lib/components/html-message.d.ts +0 -11
  65. package/lib/components/html-message.js +0 -43
  66. package/src/components/html-message.tsx +0 -68
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.7.1"
8
+ "packageVersion": "7.7.8"
9
9
  }
10
10
  ]
11
11
  }
package/lib/types.d.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  import * as React from 'react';
2
- import IntlMessageFormat, { Formats, PrimitiveType, FormatXMLElementFn } from 'intl-messageformat';
2
+ import IntlMessageFormat, { Formats, PrimitiveType, FormatXMLElementFn, FormatError } from 'intl-messageformat';
3
3
  import IntlRelativeTimeFormat, { IntlRelativeTimeFormatOptions } from '@formatjs/intl-relativetimeformat';
4
4
  import { MessageFormatElement } from 'intl-messageformat-parser';
5
5
  import { UnifiedNumberFormatOptions } from '@formatjs/intl-unified-numberformat';
6
6
  import IntlListFormat, { IntlListFormatOptions } from '@formatjs/intl-listformat';
7
7
  import { DisplayNames, DisplayNamesOptions } from '@formatjs/intl-displaynames';
8
+ import { ReactIntlError } from './error';
8
9
  export interface IntlConfig {
9
10
  locale: string;
10
11
  timeZone?: string;
@@ -13,7 +14,7 @@ export interface IntlConfig {
13
14
  messages: Record<string, string> | Record<string, MessageFormatElement[]>;
14
15
  defaultLocale: string;
15
16
  defaultFormats: CustomFormats;
16
- onError(err: string): void;
17
+ onError(err: ReactIntlError | FormatError): void;
17
18
  }
18
19
  export interface CustomFormats extends Partial<Formats> {
19
20
  relative?: Record<string, IntlRelativeTimeFormatOptions>;
@@ -27,7 +28,7 @@ export declare type FormatRelativeTimeOptions = Exclude<IntlRelativeTimeFormatOp
27
28
  export declare type FormatPluralOptions = Exclude<Intl.PluralRulesOptions, 'localeMatcher'> & CustomFormatConfig;
28
29
  export declare type FormatListOptions = Exclude<IntlListFormatOptions, 'localeMatcher'>;
29
30
  export declare type FormatDisplayNameOptions = Exclude<DisplayNamesOptions, 'localeMatcher'>;
30
- export interface IntlFormatters {
31
+ export interface IntlFormatters<T = React.ReactNode> {
31
32
  formatDate(value: Parameters<Intl.DateTimeFormat['format']>[0] | string, opts?: FormatDateOptions): string;
32
33
  formatTime(value: Parameters<Intl.DateTimeFormat['format']>[0] | string, opts?: FormatDateOptions): string;
33
34
  formatDateToParts(value: Parameters<Intl.DateTimeFormat['format']>[0] | string, opts?: FormatDateOptions): Intl.DateTimeFormatPart[];
@@ -37,8 +38,7 @@ export interface IntlFormatters {
37
38
  formatNumberToParts(value: Parameters<Intl.NumberFormat['format']>[0], opts?: FormatNumberOptions): Intl.NumberFormatPart[];
38
39
  formatPlural(value: Parameters<Intl.PluralRules['select']>[0], opts?: FormatPluralOptions): ReturnType<Intl.PluralRules['select']>;
39
40
  formatMessage(descriptor: MessageDescriptor, values?: Record<string, PrimitiveType>): string;
40
- formatMessage(descriptor: MessageDescriptor, values?: Record<string, PrimitiveType | React.ReactElement | FormatXMLElementFn>): string | React.ReactNodeArray;
41
- formatHTMLMessage(descriptor: MessageDescriptor, values?: Record<string, PrimitiveType>): React.ReactNode;
41
+ formatMessage(descriptor: MessageDescriptor, values?: Record<string, PrimitiveType | React.ReactElement | FormatXMLElementFn<T>>): string | React.ReactNodeArray;
42
42
  formatList(values: Array<string>, opts?: FormatListOptions): string;
43
43
  formatList(values: Array<string | React.ReactNode>, opts?: FormatListOptions): React.ReactNode;
44
44
  formatDisplayName(value: Parameters<DisplayNames['of']>[0], opts?: FormatDisplayNameOptions): string | undefined;
package/lib/utils.d.ts CHANGED
@@ -1,10 +1,9 @@
1
1
  import { IntlConfig, IntlCache, CustomFormats, Formatters } from './types';
2
2
  import { IntlRelativeTimeFormatOptions } from '@formatjs/intl-relativetimeformat';
3
- export declare function escape(str: string): string;
3
+ import { ReactIntlError } from './error';
4
4
  export declare function filterProps<T extends Record<string, any>, K extends string>(props: T, whitelist: Array<K>, defaults?: Partial<T>): Pick<T, K>;
5
5
  export declare function invariantIntlContext(intl?: any): asserts intl;
6
- export declare function createError(message: string, exception?: Error): string;
7
- export declare function defaultErrorHandler(error: string): void;
6
+ export declare function defaultErrorHandler(error: ReactIntlError): void;
8
7
  export declare const DEFAULT_INTL_CONFIG: Pick<IntlConfig, 'formats' | 'messages' | 'timeZone' | 'textComponent' | 'defaultLocale' | 'defaultFormats' | 'onError'>;
9
8
  export declare function createIntlCache(): IntlCache;
10
9
  /**
@@ -12,4 +11,4 @@ export declare function createIntlCache(): IntlCache;
12
11
  * @param cache explicit cache to prevent leaking memory
13
12
  */
14
13
  export declare function createFormatters(cache?: IntlCache): Formatters;
15
- export declare function getNamedFormat<T extends keyof CustomFormats>(formats: CustomFormats, type: T, name: string, onError: (err: string) => void): Intl.NumberFormatOptions | Intl.DateTimeFormatOptions | IntlRelativeTimeFormatOptions | undefined;
14
+ export declare function getNamedFormat<T extends keyof CustomFormats>(formats: CustomFormats, type: T, name: string, onError: (err: ReactIntlError) => void): Intl.NumberFormatOptions | Intl.DateTimeFormatOptions | IntlRelativeTimeFormatOptions | undefined;
package/lib/utils.js CHANGED
@@ -12,17 +12,7 @@ import * as React from 'react';
12
12
  import IntlMessageFormat from 'intl-messageformat';
13
13
  import memoizeIntlConstructor from 'intl-format-cache';
14
14
  import { invariant } from '@formatjs/intl-utils';
15
- const ESCAPED_CHARS = {
16
- 38: '&amp;',
17
- 62: '&gt;',
18
- 60: '&lt;',
19
- 34: '&quot;',
20
- 39: '&#x27;',
21
- };
22
- const UNSAFE_CHARS_REGEX = /[&><"']/g;
23
- export function escape(str) {
24
- return ('' + str).replace(UNSAFE_CHARS_REGEX, match => ESCAPED_CHARS[match.charCodeAt(0)]);
25
- }
15
+ import { ReactIntlError } from './error';
26
16
  export function filterProps(props, whitelist, defaults = {}) {
27
17
  return whitelist.reduce((filtered, name) => {
28
18
  if (name in props) {
@@ -38,10 +28,6 @@ export function invariantIntlContext(intl) {
38
28
  invariant(intl, '[React Intl] Could not find required `intl` object. ' +
39
29
  '<IntlProvider> needs to exist in the component ancestry.');
40
30
  }
41
- export function createError(message, exception) {
42
- const eMsg = exception ? `\n${exception.stack}` : '';
43
- return `[React Intl] ${message}${eMsg}`;
44
- }
45
31
  export function defaultErrorHandler(error) {
46
32
  if (process.env.NODE_ENV !== 'production') {
47
33
  console.error(error);
@@ -94,5 +80,5 @@ export function getNamedFormat(formats, type, name, onError) {
94
80
  if (format) {
95
81
  return format;
96
82
  }
97
- onError(createError(`No ${type} format named: ${name}`));
83
+ onError(new ReactIntlError("UNSUPPORTED_FORMATTER" /* UNSUPPORTED_FORMATTER */, `No ${type} format named: ${name}`));
98
84
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-intl",
3
- "version": "3.12.0",
3
+ "version": "4.1.1",
4
4
  "description": "Internationalize React apps. This library provides React components and an API to format dates, numbers, and strings, including pluralization and handling translations.",
5
5
  "keywords": [
6
6
  "intl",
@@ -131,75 +131,73 @@
131
131
  "types": "./lib/react-intl.d.ts",
132
132
  "sideEffects": false,
133
133
  "dependencies": {
134
- "@formatjs/intl-displaynames": "^1.2.0",
135
- "@formatjs/intl-listformat": "^1.3.7",
136
- "@formatjs/intl-relativetimeformat": "^4.5.7",
137
- "@formatjs/intl-unified-numberformat": "^3.0.4",
138
- "@formatjs/intl-utils": "^2.0.4",
139
- "@formatjs/macro": "^0.2.6",
134
+ "@formatjs/intl-displaynames": "^1.2.1",
135
+ "@formatjs/intl-listformat": "^1.4.1",
136
+ "@formatjs/intl-relativetimeformat": "^4.5.9",
137
+ "@formatjs/intl-unified-numberformat": "^3.2.0",
138
+ "@formatjs/intl-utils": "^2.2.0",
140
139
  "@types/hoist-non-react-statics": "^3.3.1",
141
140
  "@types/invariant": "^2.2.31",
142
- "hoist-non-react-statics": "^3.3.1",
143
- "intl-format-cache": "^4.2.19",
144
- "intl-locales-supported": "^1.8.4",
145
- "intl-messageformat": "^7.8.2",
146
- "intl-messageformat-parser": "^3.6.2",
141
+ "hoist-non-react-statics": "^3.3.2",
142
+ "intl-format-cache": "^4.2.21",
143
+ "intl-messageformat": "^8.2.1",
144
+ "intl-messageformat-parser": "^4.1.0",
147
145
  "shallow-equal": "^1.2.1"
148
146
  },
149
147
  "peerDependencies": {
150
148
  "react": "^16.3.0"
151
149
  },
152
150
  "devDependencies": {
153
- "@babel/core": "^7.7.7",
154
- "@babel/node": "^7.7.7",
155
- "@babel/plugin-proposal-class-properties": "^7.7.4",
156
- "@babel/plugin-transform-modules-commonjs": "^7.7.5",
157
- "@babel/preset-env": "^7.7.7",
158
- "@babel/preset-react": "^7.7.4",
159
- "@formatjs/intl-pluralrules": "^1.5.0",
160
- "@microsoft/api-documenter": "^7.7.3",
161
- "@microsoft/api-extractor": "^7.7.1",
151
+ "@babel/core": "^7.8.7",
152
+ "@babel/node": "^7.8.7",
153
+ "@babel/plugin-proposal-class-properties": "^7.8.3",
154
+ "@babel/plugin-transform-modules-commonjs": "^7.8.3",
155
+ "@babel/preset-env": "^7.8.7",
156
+ "@babel/preset-react": "^7.8.3",
157
+ "@formatjs/intl-pluralrules": "^1.5.2",
158
+ "@microsoft/api-documenter": "^7.7.12",
159
+ "@microsoft/api-extractor": "^7.7.8",
162
160
  "@types/benchmark": "^1.0.31",
163
- "@types/enzyme": "^3.10.4",
164
- "@types/jest": "^24.0.25",
161
+ "@types/enzyme": "^3.10.5",
162
+ "@types/jest": "^25.1.3",
165
163
  "@types/prop-types": "^15.7.3",
166
- "@types/react": "^16.9.17",
167
- "@types/react-dom": "^16.9.4",
168
- "@typescript-eslint/eslint-plugin": "^2.15.0",
169
- "@typescript-eslint/parser": "^2.15.0",
170
- "babel-jest": "^24.9.0",
171
- "benchmark": "^2.1.0",
172
- "core-js": "^3.6.2",
173
- "cross-env": "^6.0.3",
164
+ "@types/react": "^16.9.23",
165
+ "@types/react-dom": "^16.9.5",
166
+ "@typescript-eslint/eslint-plugin": "^2.22.0",
167
+ "@typescript-eslint/parser": "^2.22.0",
168
+ "babel-jest": "^25.1.0",
169
+ "benchmark": "^2.1.4",
170
+ "core-js": "^3.6.4",
171
+ "cross-env": "^7.0.2",
174
172
  "enzyme": "^3.11.0",
175
173
  "enzyme-adapter-react-16": "^1.15.2",
176
- "enzyme-to-json": "^3.4.3",
174
+ "enzyme-to-json": "^3.4.4",
177
175
  "eslint": "^6.8.0",
178
- "eslint-plugin-react": "^7.17.0",
176
+ "eslint-plugin-react": "^7.18.3",
179
177
  "fs-extra": "^8.1.0",
180
- "full-icu": "^1.3.0",
178
+ "full-icu": "^1.3.1",
181
179
  "glob": "^7.1.6",
182
- "jest": "^24.9.0",
180
+ "jest": "^25.1.0",
183
181
  "markdown-toc": "^1.2.0",
184
- "mkdirp": "^0.5.1",
182
+ "mkdirp": "^1.0.3",
185
183
  "parcel": "^1.12.4",
186
184
  "pre-commit": "^1.2.2",
187
185
  "prettier": "^1.19.1",
188
- "react": "^16.12.0",
189
- "react-dom": "^16.12.0",
190
- "rimraf": "^3.0.0",
191
- "rollup": "^1.29.0",
186
+ "react": "^16.13.0",
187
+ "react-dom": "^16.13.0",
188
+ "rimraf": "^3.0.2",
189
+ "rollup": "^1.32.0",
192
190
  "rollup-plugin-babel": "^4.3.3",
193
191
  "rollup-plugin-commonjs": "^10.1.0",
194
192
  "rollup-plugin-node-resolve": "^5.2.0",
195
- "rollup-plugin-replace": "^2.0.0",
196
- "rollup-plugin-typescript2": "^0.25.3",
193
+ "rollup-plugin-replace": "^2.2.0",
194
+ "rollup-plugin-typescript2": "^0.26.0",
197
195
  "rollup-plugin-uglify": "^6.0.4",
198
- "standard-version": "^7.0.1",
199
- "ts-jest": "^24.3.0",
200
- "ts-node": "^8.5.4",
201
- "tslib": "^1.9.3",
202
- "typescript": "^3.7.0"
196
+ "standard-version": "^7.1.0",
197
+ "ts-jest": "^25.2.1",
198
+ "ts-node": "^8.6.2",
199
+ "tslib": "^1.11.1",
200
+ "typescript": "^3.8.3"
203
201
  },
204
202
  "scripts": {
205
203
  "benchmark": "cross-env NODE_ENV=production TS_NODE_PROJECT=./tsconfig.cjs.json ts-node test/perf/index.tsx",
@@ -18,13 +18,13 @@ import * as shallowEquals_ from 'shallow-equal/objects';
18
18
  const shallowEquals: typeof shallowEquals_ =
19
19
  (shallowEquals_ as any).default || shallowEquals_;
20
20
 
21
- const defaultFormatMessage = (
21
+ function defaultFormatMessage<T = React.ReactNode>(
22
22
  descriptor: MessageDescriptor,
23
23
  values?: Record<
24
24
  string,
25
- PrimitiveType | React.ReactElement | FormatXMLElementFn
25
+ PrimitiveType | React.ReactElement | FormatXMLElementFn<T>
26
26
  >
27
- ): string => {
27
+ ): string {
28
28
  if (process.env.NODE_ENV !== 'production') {
29
29
  console.error(
30
30
  '[React Intl] Could not find required `intl` object. <IntlProvider> needs to exist in the component ancestry. Using default message as fallback.'
@@ -40,7 +40,7 @@ const defaultFormatMessage = (
40
40
  descriptor,
41
41
  values as any
42
42
  );
43
- };
43
+ }
44
44
 
45
45
  export interface Props<
46
46
  V extends Record<string, any> = Record<string, React.ReactNode>
@@ -51,9 +51,10 @@ export interface Props<
51
51
  }
52
52
 
53
53
  class FormattedMessage<
54
+ T = React.ReactNode,
54
55
  V extends Record<string, any> = Record<
55
56
  string,
56
- PrimitiveType | React.ReactElement | FormatXMLElementFn
57
+ PrimitiveType | React.ReactElement | FormatXMLElementFn<T>
57
58
  >
58
59
  > extends React.Component<Props<V>> {
59
60
  static displayName = 'FormattedMessage';
@@ -7,14 +7,12 @@
7
7
  import * as React from 'react';
8
8
  import {Provider} from './injectIntl';
9
9
  import {
10
- createError,
11
10
  DEFAULT_INTL_CONFIG,
12
11
  createFormatters,
13
12
  invariantIntlContext,
14
13
  createIntlCache,
15
14
  } from '../utils';
16
15
  import {IntlConfig, IntlShape, Omit, IntlCache} from '../types';
17
- import areIntlLocalesSupported from 'intl-locales-supported';
18
16
  import {formatNumber, formatNumberToParts} from '../formatters/number';
19
17
  import {formatRelativeTime} from '../formatters/relativeTime';
20
18
  import {
@@ -24,10 +22,11 @@ import {
24
22
  formatTimeToParts,
25
23
  } from '../formatters/dateTime';
26
24
  import {formatPlural} from '../formatters/plural';
27
- import {formatMessage, formatHTMLMessage} from '../formatters/message';
25
+ import {formatMessage} from '../formatters/message';
28
26
  import * as shallowEquals_ from 'shallow-equal/objects';
29
27
  import {formatList} from '../formatters/list';
30
28
  import {formatDisplayName} from '../formatters/displayName';
29
+ import {ReactIntlError, ReactIntlErrorCode} from '../error';
31
30
  const shallowEquals: typeof shallowEquals_ =
32
31
  (shallowEquals_ as any).default || shallowEquals_;
33
32
 
@@ -80,26 +79,39 @@ export function createIntl(
80
79
  ): IntlShape {
81
80
  const formatters = createFormatters(cache);
82
81
  const resolvedConfig = {...DEFAULT_INTL_CONFIG, ...config};
83
- if (
84
- !resolvedConfig.locale ||
85
- !areIntlLocalesSupported(resolvedConfig.locale)
86
- ) {
87
- const {locale, defaultLocale, onError} = resolvedConfig;
88
- if (typeof onError === 'function') {
82
+ const {locale, defaultLocale, onError} = resolvedConfig;
83
+ if (!locale) {
84
+ if (onError) {
89
85
  onError(
90
- createError(
91
- `Missing locale data for locale: "${locale}". ` +
92
- `Using default locale: "${defaultLocale}" as fallback.`
86
+ new ReactIntlError(
87
+ ReactIntlErrorCode.INVALID_CONFIG,
88
+ `"locale" was not configured, using "${defaultLocale}" as fallback. See https://github.com/formatjs/react-intl/blob/master/docs/API.md#intlshape for more details`
93
89
  )
94
90
  );
95
91
  }
96
-
97
92
  // Since there's no registered locale data for `locale`, this will
98
93
  // fallback to the `defaultLocale` to make sure things can render.
99
94
  // The `messages` are overridden to the `defaultProps` empty object
100
95
  // to maintain referential equality across re-renders. It's assumed
101
96
  // each <FormattedMessage> contains a `defaultMessage` prop.
102
97
  resolvedConfig.locale = resolvedConfig.defaultLocale || 'en';
98
+ } else if (!Intl.NumberFormat.supportedLocalesOf(locale).length && onError) {
99
+ onError(
100
+ new ReactIntlError(
101
+ ReactIntlErrorCode.MISSING_DATA,
102
+ `Missing locale data for locale: "${locale}" in Intl.NumberFormat. Using default locale: "${defaultLocale}" as fallback. See https://github.com/formatjs/react-intl/blob/master/docs/Getting-Started.md#runtime-requirements for more details`
103
+ )
104
+ );
105
+ } else if (
106
+ !Intl.DateTimeFormat.supportedLocalesOf(locale).length &&
107
+ onError
108
+ ) {
109
+ onError(
110
+ new ReactIntlError(
111
+ ReactIntlErrorCode.MISSING_DATA,
112
+ `Missing locale data for locale: "${locale}" in Intl.DateTimeFormat. Using default locale: "${defaultLocale}" as fallback. See https://github.com/formatjs/react-intl/blob/master/docs/Getting-Started.md#runtime-requirements for more details`
113
+ )
114
+ );
103
115
  }
104
116
  return {
105
117
  ...resolvedConfig,
@@ -145,7 +157,6 @@ export function createIntl(
145
157
  formatters.getPluralRules
146
158
  ),
147
159
  formatMessage: formatMessage.bind(null, resolvedConfig, formatters),
148
- formatHTMLMessage: formatHTMLMessage.bind(null, resolvedConfig, formatters),
149
160
  formatList: formatList.bind(null, resolvedConfig, formatters.getListFormat),
150
161
  formatDisplayName: formatDisplayName.bind(
151
162
  null,
package/src/error.ts ADDED
@@ -0,0 +1,18 @@
1
+ export const enum ReactIntlErrorCode {
2
+ FORMAT_ERROR = 'FORMAT_ERROR',
3
+ UNSUPPORTED_FORMATTER = 'UNSUPPORTED_FORMATTER',
4
+ INVALID_CONFIG = 'INVALID_CONFIG',
5
+ MISSING_DATA = 'MISSING_DATA',
6
+ MISSING_TRANSLATION = 'MISSING_TRANSLATION'
7
+ }
8
+
9
+ export class ReactIntlError extends Error {
10
+ public code: ReactIntlErrorCode
11
+ constructor(code: ReactIntlErrorCode, message: string, exception?: Error) {
12
+ super(`[React Intl Error ${code}] ${message} ${exception ? `\n${exception.stack}` : ''}`)
13
+ this.code = code
14
+ if (typeof Error.captureStackTrace === 'function') {
15
+ Error.captureStackTrace(this, ReactIntlError)
16
+ }
17
+ }
18
+ }
@@ -6,7 +6,8 @@
6
6
 
7
7
  import {Formatters, IntlConfig, IntlFormatters} from '../types';
8
8
 
9
- import {createError, filterProps, getNamedFormat} from '../utils';
9
+ import {filterProps, getNamedFormat} from '../utils';
10
+ import {ReactIntlError, ReactIntlErrorCode} from '../error';
10
11
 
11
12
  const DATE_TIME_FORMAT_OPTIONS: Array<keyof Intl.DateTimeFormatOptions> = [
12
13
  'localeMatcher',
@@ -74,7 +75,13 @@ export function formatDate(
74
75
  date
75
76
  );
76
77
  } catch (e) {
77
- config.onError(createError('Error formatting date.', e));
78
+ config.onError(
79
+ new ReactIntlError(
80
+ ReactIntlErrorCode.FORMAT_ERROR,
81
+ 'Error formatting date.',
82
+ e
83
+ )
84
+ );
78
85
  }
79
86
 
80
87
  return String(date);
@@ -93,7 +100,13 @@ export function formatTime(
93
100
  date
94
101
  );
95
102
  } catch (e) {
96
- config.onError(createError('Error formatting time.', e));
103
+ config.onError(
104
+ new ReactIntlError(
105
+ ReactIntlErrorCode.FORMAT_ERROR,
106
+ 'Error formatting time.',
107
+ e
108
+ )
109
+ );
97
110
  }
98
111
 
99
112
  return String(date);
@@ -114,7 +127,13 @@ export function formatDateToParts(
114
127
  options
115
128
  ).formatToParts(date);
116
129
  } catch (e) {
117
- config.onError(createError('Error formatting date.', e));
130
+ config.onError(
131
+ new ReactIntlError(
132
+ ReactIntlErrorCode.FORMAT_ERROR,
133
+ 'Error formatting date.',
134
+ e
135
+ )
136
+ );
118
137
  }
119
138
 
120
139
  return [];
@@ -136,7 +155,13 @@ export function formatTimeToParts(
136
155
  options
137
156
  ).formatToParts(date);
138
157
  } catch (e) {
139
- config.onError(createError('Error formatting time.', e));
158
+ config.onError(
159
+ new ReactIntlError(
160
+ ReactIntlErrorCode.FORMAT_ERROR,
161
+ 'Error formatting time.',
162
+ e
163
+ )
164
+ );
140
165
  }
141
166
 
142
167
  return [];
@@ -1,9 +1,11 @@
1
1
  import {IntlConfig, Formatters, IntlFormatters} from '../types';
2
- import {filterProps, createError} from '../utils';
2
+ import {filterProps} from '../utils';
3
3
  import {
4
4
  DisplayNamesOptions,
5
5
  DisplayNames as IntlDisplayNames,
6
6
  } from '@formatjs/intl-displaynames';
7
+ import {FormatError, ErrorCode} from 'intl-messageformat';
8
+ import {ReactIntlErrorCode, ReactIntlError} from '../error';
7
9
 
8
10
  const DISPLAY_NAMES_OPTONS: Array<keyof DisplayNamesOptions> = [
9
11
  'localeMatcher',
@@ -21,15 +23,24 @@ export function formatDisplayName(
21
23
  const DisplayNames: typeof IntlDisplayNames = (Intl as any).DisplayNames;
22
24
  if (!DisplayNames) {
23
25
  onError(
24
- createError(`Intl.DisplayNames is not available in this environment.
26
+ new FormatError(
27
+ `Intl.DisplayNames is not available in this environment.
25
28
  Try polyfilling it using "@formatjs/intl-displaynames"
26
- `)
29
+ `,
30
+ ErrorCode.MISSING_INTL_API
31
+ )
27
32
  );
28
33
  }
29
34
  const filteredOptions = filterProps(options, DISPLAY_NAMES_OPTONS);
30
35
  try {
31
36
  return getDisplayNames(locale, filteredOptions).of(value);
32
37
  } catch (e) {
33
- onError(createError('Error formatting display name.', e));
38
+ onError(
39
+ new ReactIntlError(
40
+ ReactIntlErrorCode.FORMAT_ERROR,
41
+ 'Error formatting display name.',
42
+ e
43
+ )
44
+ );
34
45
  }
35
46
  }
@@ -1,7 +1,9 @@
1
1
  import * as React from 'react';
2
2
  import {IntlConfig, Formatters, IntlFormatters} from '../types';
3
- import {filterProps, createError} from '../utils';
3
+ import {filterProps} from '../utils';
4
4
  import IntlListFormat, {IntlListFormatOptions} from '@formatjs/intl-listformat';
5
+ import {FormatError, ErrorCode} from 'intl-messageformat';
6
+ import {ReactIntlError, ReactIntlErrorCode} from '../error';
5
7
 
6
8
  const LIST_FORMAT_OPTIONS: Array<keyof IntlListFormatOptions> = [
7
9
  'localeMatcher',
@@ -30,9 +32,12 @@ export function formatList(
30
32
  const ListFormat: typeof IntlListFormat = (Intl as any).ListFormat;
31
33
  if (!ListFormat) {
32
34
  onError(
33
- createError(`Intl.ListFormat is not available in this environment.
35
+ new FormatError(
36
+ `Intl.ListFormat is not available in this environment.
34
37
  Try polyfilling it using "@formatjs/intl-listformat"
35
- `)
38
+ `,
39
+ ErrorCode.MISSING_INTL_API
40
+ )
36
41
  );
37
42
  }
38
43
  const filteredOptions = filterProps(options, LIST_FORMAT_OPTIONS);
@@ -65,7 +70,13 @@ Try polyfilling it using "@formatjs/intl-listformat"
65
70
  return all;
66
71
  }, []);
67
72
  } catch (e) {
68
- onError(createError('Error formatting list.', e));
73
+ onError(
74
+ new ReactIntlError(
75
+ ReactIntlErrorCode.FORMAT_ERROR,
76
+ 'Error formatting list.',
77
+ e
78
+ )
79
+ );
69
80
  }
70
81
 
71
82
  return values;