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
package/dist/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/dist/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/dist/utils.js CHANGED
@@ -14,18 +14,7 @@ var React = require("react");
14
14
  var intl_messageformat_1 = require("intl-messageformat");
15
15
  var intl_format_cache_1 = require("intl-format-cache");
16
16
  var intl_utils_1 = require("@formatjs/intl-utils");
17
- var ESCAPED_CHARS = {
18
- 38: '&amp;',
19
- 62: '&gt;',
20
- 60: '&lt;',
21
- 34: '&quot;',
22
- 39: '&#x27;',
23
- };
24
- var UNSAFE_CHARS_REGEX = /[&><"']/g;
25
- function escape(str) {
26
- return ('' + str).replace(UNSAFE_CHARS_REGEX, function (match) { return ESCAPED_CHARS[match.charCodeAt(0)]; });
27
- }
28
- exports.escape = escape;
17
+ var error_1 = require("./error");
29
18
  function filterProps(props, whitelist, defaults) {
30
19
  if (defaults === void 0) { defaults = {}; }
31
20
  return whitelist.reduce(function (filtered, name) {
@@ -44,11 +33,6 @@ function invariantIntlContext(intl) {
44
33
  '<IntlProvider> needs to exist in the component ancestry.');
45
34
  }
46
35
  exports.invariantIntlContext = invariantIntlContext;
47
- function createError(message, exception) {
48
- var eMsg = exception ? "\n" + exception.stack : '';
49
- return "[React Intl] " + message + eMsg;
50
- }
51
- exports.createError = createError;
52
36
  function defaultErrorHandler(error) {
53
37
  if (process.env.NODE_ENV !== 'production') {
54
38
  console.error(error);
@@ -105,6 +89,6 @@ function getNamedFormat(formats, type, name, onError) {
105
89
  if (format) {
106
90
  return format;
107
91
  }
108
- onError(createError("No " + type + " format named: " + name));
92
+ onError(new error_1.ReactIntlError("UNSUPPORTED_FORMATTER" /* UNSUPPORTED_FORMATTER */, "No " + type + " format named: " + name));
109
93
  }
110
94
  exports.getNamedFormat = getNamedFormat;
@@ -6,7 +6,7 @@ export interface Props<V extends Record<string, any> = Record<string, React.Reac
6
6
  tagName?: React.ElementType<any>;
7
7
  children?(...nodes: React.ReactNodeArray): React.ReactNode;
8
8
  }
9
- declare class FormattedMessage<V extends Record<string, any> = Record<string, PrimitiveType | React.ReactElement | FormatXMLElementFn>> extends React.Component<Props<V>> {
9
+ declare class FormattedMessage<T = React.ReactNode, V extends Record<string, any> = Record<string, PrimitiveType | React.ReactElement | FormatXMLElementFn<T>>> extends React.Component<Props<V>> {
10
10
  static displayName: string;
11
11
  static defaultProps: {
12
12
  values: {};
@@ -20,12 +20,12 @@ import { formatMessage } from '../formatters/message';
20
20
  import { invariantIntlContext, DEFAULT_INTL_CONFIG, createFormatters, } from '../utils';
21
21
  import * as shallowEquals_ from 'shallow-equal/objects';
22
22
  const shallowEquals = shallowEquals_.default || shallowEquals_;
23
- const defaultFormatMessage = (descriptor, values) => {
23
+ function defaultFormatMessage(descriptor, values) {
24
24
  if (process.env.NODE_ENV !== 'production') {
25
25
  console.error('[React Intl] Could not find required `intl` object. <IntlProvider> needs to exist in the component ancestry. Using default message as fallback.');
26
26
  }
27
27
  return formatMessage(Object.assign(Object.assign({}, DEFAULT_INTL_CONFIG), { locale: 'en' }), createFormatters(), descriptor, values);
28
- };
28
+ }
29
29
  class FormattedMessage extends React.Component {
30
30
  shouldComponentUpdate(nextProps) {
31
31
  const _a = this.props, { values } = _a, otherProps = __rest(_a, ["values"]);
@@ -11,7 +11,7 @@ interface Props extends FormatPluralOptions {
11
11
  many?: React.ReactNode;
12
12
  children?(value: React.ReactNode): React.ReactElement | null;
13
13
  }
14
- declare const _default: React.ForwardRefExoticComponent<Pick<Props, "children" | "other" | "zero" | "one" | "two" | "few" | "many" | "format" | "localeMatcher" | "type" | "value"> & {
14
+ declare const _default: React.ForwardRefExoticComponent<Pick<Props, "children" | "other" | "zero" | "one" | "two" | "few" | "many" | "localeMatcher" | "format" | "type" | "value"> & {
15
15
  forwardedRef?: ((instance: any) => void) | React.RefObject<any> | null | undefined;
16
16
  } & React.RefAttributes<any>> & {
17
17
  WrappedComponent: React.ComponentType<Props>;
@@ -5,16 +5,16 @@
5
5
  */
6
6
  import * as React from 'react';
7
7
  import { Provider } from './injectIntl';
8
- import { createError, DEFAULT_INTL_CONFIG, createFormatters, invariantIntlContext, createIntlCache, } from '../utils';
9
- import areIntlLocalesSupported from 'intl-locales-supported';
8
+ import { DEFAULT_INTL_CONFIG, createFormatters, invariantIntlContext, createIntlCache, } from '../utils';
10
9
  import { formatNumber, formatNumberToParts } from '../formatters/number';
11
10
  import { formatRelativeTime } from '../formatters/relativeTime';
12
11
  import { formatDate, formatTime, formatDateToParts, formatTimeToParts, } from '../formatters/dateTime';
13
12
  import { formatPlural } from '../formatters/plural';
14
- import { formatMessage, formatHTMLMessage } from '../formatters/message';
13
+ import { formatMessage } from '../formatters/message';
15
14
  import * as shallowEquals_ from 'shallow-equal/objects';
16
15
  import { formatList } from '../formatters/list';
17
16
  import { formatDisplayName } from '../formatters/displayName';
17
+ import { ReactIntlError } from '../error';
18
18
  const shallowEquals = shallowEquals_.default || shallowEquals_;
19
19
  function processIntlConfig(config) {
20
20
  return {
@@ -36,12 +36,10 @@ function processIntlConfig(config) {
36
36
  export function createIntl(config, cache) {
37
37
  const formatters = createFormatters(cache);
38
38
  const resolvedConfig = Object.assign(Object.assign({}, DEFAULT_INTL_CONFIG), config);
39
- if (!resolvedConfig.locale ||
40
- !areIntlLocalesSupported(resolvedConfig.locale)) {
41
- const { locale, defaultLocale, onError } = resolvedConfig;
42
- if (typeof onError === 'function') {
43
- onError(createError(`Missing locale data for locale: "${locale}". ` +
44
- `Using default locale: "${defaultLocale}" as fallback.`));
39
+ const { locale, defaultLocale, onError } = resolvedConfig;
40
+ if (!locale) {
41
+ if (onError) {
42
+ onError(new ReactIntlError("INVALID_CONFIG" /* INVALID_CONFIG */, `"locale" was not configured, using "${defaultLocale}" as fallback. See https://github.com/formatjs/react-intl/blob/master/docs/API.md#intlshape for more details`));
45
43
  }
46
44
  // Since there's no registered locale data for `locale`, this will
47
45
  // fallback to the `defaultLocale` to make sure things can render.
@@ -50,7 +48,14 @@ export function createIntl(config, cache) {
50
48
  // each <FormattedMessage> contains a `defaultMessage` prop.
51
49
  resolvedConfig.locale = resolvedConfig.defaultLocale || 'en';
52
50
  }
53
- return Object.assign(Object.assign({}, resolvedConfig), { formatters, formatNumber: formatNumber.bind(null, resolvedConfig, formatters.getNumberFormat), formatNumberToParts: formatNumberToParts.bind(null, resolvedConfig, formatters.getNumberFormat), formatRelativeTime: formatRelativeTime.bind(null, resolvedConfig, formatters.getRelativeTimeFormat), formatDate: formatDate.bind(null, resolvedConfig, formatters.getDateTimeFormat), formatDateToParts: formatDateToParts.bind(null, resolvedConfig, formatters.getDateTimeFormat), formatTime: formatTime.bind(null, resolvedConfig, formatters.getDateTimeFormat), formatTimeToParts: formatTimeToParts.bind(null, resolvedConfig, formatters.getDateTimeFormat), formatPlural: formatPlural.bind(null, resolvedConfig, formatters.getPluralRules), formatMessage: formatMessage.bind(null, resolvedConfig, formatters), formatHTMLMessage: formatHTMLMessage.bind(null, resolvedConfig, formatters), formatList: formatList.bind(null, resolvedConfig, formatters.getListFormat), formatDisplayName: formatDisplayName.bind(null, resolvedConfig, formatters.getDisplayNames) });
51
+ else if (!Intl.NumberFormat.supportedLocalesOf(locale).length && onError) {
52
+ onError(new ReactIntlError("MISSING_DATA" /* MISSING_DATA */, `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`));
53
+ }
54
+ else if (!Intl.DateTimeFormat.supportedLocalesOf(locale).length &&
55
+ onError) {
56
+ onError(new ReactIntlError("MISSING_DATA" /* MISSING_DATA */, `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`));
57
+ }
58
+ return Object.assign(Object.assign({}, resolvedConfig), { formatters, formatNumber: formatNumber.bind(null, resolvedConfig, formatters.getNumberFormat), formatNumberToParts: formatNumberToParts.bind(null, resolvedConfig, formatters.getNumberFormat), formatRelativeTime: formatRelativeTime.bind(null, resolvedConfig, formatters.getRelativeTimeFormat), formatDate: formatDate.bind(null, resolvedConfig, formatters.getDateTimeFormat), formatDateToParts: formatDateToParts.bind(null, resolvedConfig, formatters.getDateTimeFormat), formatTime: formatTime.bind(null, resolvedConfig, formatters.getDateTimeFormat), formatTimeToParts: formatTimeToParts.bind(null, resolvedConfig, formatters.getDateTimeFormat), formatPlural: formatPlural.bind(null, resolvedConfig, formatters.getPluralRules), formatMessage: formatMessage.bind(null, resolvedConfig, formatters), formatList: formatList.bind(null, resolvedConfig, formatters.getListFormat), formatDisplayName: formatDisplayName.bind(null, resolvedConfig, formatters.getDisplayNames) });
54
59
  }
55
60
  export default class IntlProvider extends React.PureComponent {
56
61
  constructor() {
package/lib/error.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ export declare 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
+ export declare class ReactIntlError extends Error {
9
+ code: ReactIntlErrorCode;
10
+ constructor(code: ReactIntlErrorCode, message: string, exception?: Error);
11
+ }
package/lib/error.js ADDED
@@ -0,0 +1,9 @@
1
+ export class ReactIntlError extends Error {
2
+ constructor(code, message, exception) {
3
+ super(`[React Intl Error ${code}] ${message} ${exception ? `\n${exception.stack}` : ''}`);
4
+ this.code = code;
5
+ if (typeof Error.captureStackTrace === 'function') {
6
+ Error.captureStackTrace(this, ReactIntlError);
7
+ }
8
+ }
9
+ }
@@ -3,7 +3,8 @@
3
3
  * Copyrights licensed under the New BSD License.
4
4
  * See the accompanying LICENSE file for terms.
5
5
  */
6
- import { createError, filterProps, getNamedFormat } from '../utils';
6
+ import { filterProps, getNamedFormat } from '../utils';
7
+ import { ReactIntlError } from '../error';
7
8
  const DATE_TIME_FORMAT_OPTIONS = [
8
9
  'localeMatcher',
9
10
  'formatMatcher',
@@ -38,7 +39,7 @@ export function formatDate(config, getDateTimeFormat, value, options = {}) {
38
39
  return getFormatter(config, 'date', getDateTimeFormat, options).format(date);
39
40
  }
40
41
  catch (e) {
41
- config.onError(createError('Error formatting date.', e));
42
+ config.onError(new ReactIntlError("FORMAT_ERROR" /* FORMAT_ERROR */, 'Error formatting date.', e));
42
43
  }
43
44
  return String(date);
44
45
  }
@@ -48,7 +49,7 @@ export function formatTime(config, getDateTimeFormat, value, options = {}) {
48
49
  return getFormatter(config, 'time', getDateTimeFormat, options).format(date);
49
50
  }
50
51
  catch (e) {
51
- config.onError(createError('Error formatting time.', e));
52
+ config.onError(new ReactIntlError("FORMAT_ERROR" /* FORMAT_ERROR */, 'Error formatting time.', e));
52
53
  }
53
54
  return String(date);
54
55
  }
@@ -58,7 +59,7 @@ export function formatDateToParts(config, getDateTimeFormat, value, options = {}
58
59
  return getFormatter(config, 'date', getDateTimeFormat, options).formatToParts(date);
59
60
  }
60
61
  catch (e) {
61
- config.onError(createError('Error formatting date.', e));
62
+ config.onError(new ReactIntlError("FORMAT_ERROR" /* FORMAT_ERROR */, 'Error formatting date.', e));
62
63
  }
63
64
  return [];
64
65
  }
@@ -68,7 +69,7 @@ export function formatTimeToParts(config, getDateTimeFormat, value, options = {}
68
69
  return getFormatter(config, 'time', getDateTimeFormat, options).formatToParts(date);
69
70
  }
70
71
  catch (e) {
71
- config.onError(createError('Error formatting time.', e));
72
+ config.onError(new ReactIntlError("FORMAT_ERROR" /* FORMAT_ERROR */, 'Error formatting time.', e));
72
73
  }
73
74
  return [];
74
75
  }
@@ -1,4 +1,6 @@
1
- import { filterProps, createError } from '../utils';
1
+ import { filterProps } from '../utils';
2
+ import { FormatError } from 'intl-messageformat';
3
+ import { ReactIntlError } from '../error';
2
4
  const DISPLAY_NAMES_OPTONS = [
3
5
  'localeMatcher',
4
6
  'style',
@@ -8,15 +10,15 @@ const DISPLAY_NAMES_OPTONS = [
8
10
  export function formatDisplayName({ locale, onError }, getDisplayNames, value, options = {}) {
9
11
  const DisplayNames = Intl.DisplayNames;
10
12
  if (!DisplayNames) {
11
- onError(createError(`Intl.DisplayNames is not available in this environment.
13
+ onError(new FormatError(`Intl.DisplayNames is not available in this environment.
12
14
  Try polyfilling it using "@formatjs/intl-displaynames"
13
- `));
15
+ `, 2 /* MISSING_INTL_API */));
14
16
  }
15
17
  const filteredOptions = filterProps(options, DISPLAY_NAMES_OPTONS);
16
18
  try {
17
19
  return getDisplayNames(locale, filteredOptions).of(value);
18
20
  }
19
21
  catch (e) {
20
- onError(createError('Error formatting display name.', e));
22
+ onError(new ReactIntlError("FORMAT_ERROR" /* FORMAT_ERROR */, 'Error formatting display name.', e));
21
23
  }
22
24
  }
@@ -1,4 +1,6 @@
1
- import { filterProps, createError } from '../utils';
1
+ import { filterProps } from '../utils';
2
+ import { FormatError } from 'intl-messageformat';
3
+ import { ReactIntlError } from '../error';
2
4
  const LIST_FORMAT_OPTIONS = [
3
5
  'localeMatcher',
4
6
  'type',
@@ -11,9 +13,9 @@ function generateToken(i) {
11
13
  export function formatList({ locale, onError }, getListFormat, values, options = {}) {
12
14
  const ListFormat = Intl.ListFormat;
13
15
  if (!ListFormat) {
14
- onError(createError(`Intl.ListFormat is not available in this environment.
16
+ onError(new FormatError(`Intl.ListFormat is not available in this environment.
15
17
  Try polyfilling it using "@formatjs/intl-listformat"
16
- `));
18
+ `, 2 /* MISSING_INTL_API */));
17
19
  }
18
20
  const filteredOptions = filterProps(options, LIST_FORMAT_OPTIONS);
19
21
  try {
@@ -45,7 +47,7 @@ Try polyfilling it using "@formatjs/intl-listformat"
45
47
  }, []);
46
48
  }
47
49
  catch (e) {
48
- onError(createError('Error formatting list.', e));
50
+ onError(new ReactIntlError("FORMAT_ERROR" /* FORMAT_ERROR */, 'Error formatting list.', e));
49
51
  }
50
52
  return values;
51
53
  }
@@ -1,6 +1,5 @@
1
1
  import * as React from 'react';
2
2
  import { Formatters, IntlConfig, MessageDescriptor } from '../types';
3
3
  import { PrimitiveType } from 'intl-messageformat';
4
- export declare const prepareIntlMessageFormatHtmlOutput: (chunks: (string | object)[]) => React.ReactElement<any, string | ((props: any) => React.ReactElement<any, string | any | (new (props: any) => React.Component<any, any, any>)> | null) | (new (props: any) => React.Component<any, any, any>)>;
4
+ export declare const prepareIntlMessageFormatHtmlOutput: <T>(chunks: (string | T)[]) => React.ReactElement<any, string | ((props: any) => React.ReactElement<any, string | any | (new (props: any) => React.Component<any, any, any>)> | null) | (new (props: any) => React.Component<any, any, any>)>;
5
5
  export declare function formatMessage({ locale, formats, messages, defaultLocale, defaultFormats, onError, }: Pick<IntlConfig, 'locale' | 'formats' | 'messages' | 'defaultLocale' | 'defaultFormats' | 'onError'>, state: Formatters, messageDescriptor?: MessageDescriptor, values?: Record<string, PrimitiveType>): string;
6
- export declare function formatHTMLMessage(config: Pick<IntlConfig, 'locale' | 'formats' | 'messages' | 'defaultLocale' | 'defaultFormats' | 'onError'>, state: Formatters, messageDescriptor?: MessageDescriptor, rawValues?: Record<string, PrimitiveType>): React.ReactNode;
@@ -5,8 +5,8 @@
5
5
  */
6
6
  import * as React from 'react';
7
7
  import { invariant } from '@formatjs/intl-utils';
8
- import { createError, escape } from '../utils';
9
8
  import IntlMessageFormat from 'intl-messageformat';
9
+ import { ReactIntlError } from '../error';
10
10
  function setTimeZoneInOptions(opts, timeZone) {
11
11
  return Object.keys(opts).reduce((all, k) => {
12
12
  all[k] = Object.assign({ timeZone }, opts[k]);
@@ -35,60 +35,46 @@ export function formatMessage({ locale, formats, messages, defaultLocale, defaul
35
35
  const message = messages && messages[String(id)];
36
36
  formats = deepMergeFormatsAndSetTimeZone(formats, timeZone);
37
37
  defaultFormats = deepMergeFormatsAndSetTimeZone(defaultFormats, timeZone);
38
- let formattedMessageParts = [];
38
+ let formattedMessageParts = '';
39
39
  if (message) {
40
40
  try {
41
41
  const formatter = state.getMessageFormat(message, locale, formats, {
42
42
  formatters: state,
43
43
  });
44
- formattedMessageParts = formatter.formatHTMLMessage(values);
44
+ formattedMessageParts = formatter.format(values);
45
45
  }
46
46
  catch (e) {
47
- onError(createError(`Error formatting message: "${id}" for locale: "${locale}"` +
47
+ onError(new ReactIntlError("FORMAT_ERROR" /* FORMAT_ERROR */, `Error formatting message: "${id}" for locale: "${locale}"` +
48
48
  (defaultMessage ? ', using default message as fallback.' : ''), e));
49
49
  }
50
50
  }
51
- else {
51
+ else if (!defaultMessage ||
52
+ (locale && locale.toLowerCase() !== defaultLocale.toLowerCase())) {
52
53
  // This prevents warnings from littering the console in development
53
54
  // when no `messages` are passed into the <IntlProvider> for the
54
- // default locale, and a default message is in the source.
55
- if (!defaultMessage ||
56
- (locale && locale.toLowerCase() !== defaultLocale.toLowerCase())) {
57
- onError(createError(`Missing message: "${id}" for locale: "${locale}"` +
58
- (defaultMessage ? ', using default message as fallback.' : '')));
59
- }
55
+ // default locale.
56
+ onError(new ReactIntlError("MISSING_TRANSLATION" /* MISSING_TRANSLATION */, `Missing message: "${id}" for locale: "${locale}"` +
57
+ (defaultMessage ? ', using default message as fallback.' : '')));
60
58
  }
61
- if (!formattedMessageParts.length && defaultMessage) {
59
+ if (!formattedMessageParts && defaultMessage) {
62
60
  try {
63
61
  const formatter = state.getMessageFormat(defaultMessage, defaultLocale, defaultFormats);
64
- formattedMessageParts = formatter.formatHTMLMessage(values);
62
+ formattedMessageParts = formatter.format(values);
65
63
  }
66
64
  catch (e) {
67
- onError(createError(`Error formatting the default message for: "${id}"`, e));
65
+ onError(new ReactIntlError("FORMAT_ERROR" /* FORMAT_ERROR */, `Error formatting the default message for: "${id}"`, e));
68
66
  }
69
67
  }
70
- if (!formattedMessageParts.length) {
71
- onError(createError(`Cannot format message: "${id}", ` +
68
+ if (!formattedMessageParts) {
69
+ onError(new ReactIntlError("FORMAT_ERROR" /* FORMAT_ERROR */, `Cannot format message: "${id}", ` +
72
70
  `using message ${message || defaultMessage ? 'source' : 'id'} as fallback.`));
73
71
  if (typeof message === 'string') {
74
72
  return message || defaultMessage || String(id);
75
73
  }
76
74
  return defaultMessage || String(id);
77
75
  }
78
- if (formattedMessageParts.length === 1 &&
79
- typeof formattedMessageParts[0] === 'string') {
80
- return formattedMessageParts[0] || defaultMessage || String(id);
76
+ if (Array.isArray(formattedMessageParts)) {
77
+ return prepareIntlMessageFormatHtmlOutput(formattedMessageParts);
81
78
  }
82
- return prepareIntlMessageFormatHtmlOutput(formattedMessageParts);
83
- }
84
- export function formatHTMLMessage(config, state, messageDescriptor = { id: '' }, rawValues = {}) {
85
- // Process all the values before they are used when formatting the ICU
86
- // Message string. Since the formatted message might be injected via
87
- // `innerHTML`, all String-based values need to be HTML-escaped.
88
- const escapedValues = Object.keys(rawValues).reduce((escaped, name) => {
89
- const value = rawValues[name];
90
- escaped[name] = typeof value === 'string' ? escape(value) : value;
91
- return escaped;
92
- }, {});
93
- return formatMessage(config, state, messageDescriptor, escapedValues);
79
+ return formattedMessageParts;
94
80
  }
@@ -1,4 +1,5 @@
1
- import { getNamedFormat, filterProps, createError } from '../utils';
1
+ import { getNamedFormat, filterProps } from '../utils';
2
+ import { ReactIntlError } from '../error';
2
3
  const NUMBER_FORMAT_OPTIONS = [
3
4
  'localeMatcher',
4
5
  'style',
@@ -34,7 +35,7 @@ export function formatNumber(config, getNumberFormat, value, options = {}) {
34
35
  return getFormatter(config, getNumberFormat, options).format(value);
35
36
  }
36
37
  catch (e) {
37
- config.onError(createError('Error formatting number.', e));
38
+ config.onError(new ReactIntlError("FORMAT_ERROR" /* FORMAT_ERROR */, 'Error formatting number.', e));
38
39
  }
39
40
  return String(value);
40
41
  }
@@ -43,7 +44,7 @@ export function formatNumberToParts(config, getNumberFormat, value, options = {}
43
44
  return getFormatter(config, getNumberFormat, options).formatToParts(value);
44
45
  }
45
46
  catch (e) {
46
- config.onError(createError('Error formatting number.', e));
47
+ config.onError(new ReactIntlError("FORMAT_ERROR" /* FORMAT_ERROR */, 'Error formatting number.', e));
47
48
  }
48
49
  return [];
49
50
  }
@@ -1,20 +1,22 @@
1
- import { filterProps, createError } from '../utils';
1
+ import { filterProps } from '../utils';
2
+ import { ReactIntlError } from '../error';
3
+ import { FormatError } from 'intl-messageformat';
2
4
  const PLURAL_FORMAT_OPTIONS = [
3
5
  'localeMatcher',
4
6
  'type',
5
7
  ];
6
8
  export function formatPlural({ locale, onError }, getPluralRules, value, options = {}) {
7
9
  if (!Intl.PluralRules) {
8
- onError(createError(`Intl.PluralRules is not available in this environment.
10
+ onError(new FormatError(`Intl.PluralRules is not available in this environment.
9
11
  Try polyfilling it using "@formatjs/intl-pluralrules"
10
- `));
12
+ `, 2 /* MISSING_INTL_API */));
11
13
  }
12
14
  const filteredOptions = filterProps(options, PLURAL_FORMAT_OPTIONS);
13
15
  try {
14
16
  return getPluralRules(locale, filteredOptions).select(value);
15
17
  }
16
18
  catch (e) {
17
- onError(createError('Error formatting plural.', e));
19
+ onError(new ReactIntlError("FORMAT_ERROR" /* FORMAT_ERROR */, 'Error formatting plural.', e));
18
20
  }
19
21
  return 'other';
20
22
  }
@@ -1,4 +1,6 @@
1
- import { getNamedFormat, filterProps, createError } from '../utils';
1
+ import { getNamedFormat, filterProps } from '../utils';
2
+ import { FormatError } from 'intl-messageformat';
3
+ import { ReactIntlError } from '../error';
2
4
  const RELATIVE_TIME_FORMAT_OPTIONS = [
3
5
  'numeric',
4
6
  'style',
@@ -15,15 +17,15 @@ export function formatRelativeTime(config, getRelativeTimeFormat, value, unit, o
15
17
  }
16
18
  const RelativeTimeFormat = Intl.RelativeTimeFormat;
17
19
  if (!RelativeTimeFormat) {
18
- config.onError(createError(`Intl.RelativeTimeFormat is not available in this environment.
20
+ config.onError(new FormatError(`Intl.RelativeTimeFormat is not available in this environment.
19
21
  Try polyfilling it using "@formatjs/intl-relativetimeformat"
20
- `));
22
+ `, 2 /* MISSING_INTL_API */));
21
23
  }
22
24
  try {
23
25
  return getFormatter(config, getRelativeTimeFormat, options).format(value, unit);
24
26
  }
25
27
  catch (e) {
26
- config.onError(createError('Error formatting relative time.', e));
28
+ config.onError(new ReactIntlError("FORMAT_ERROR" /* FORMAT_ERROR */, 'Error formatting relative time.', e));
27
29
  }
28
30
  return String(value);
29
31
  }
package/lib/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  export * from './types';
3
- export { defineMessages } from '@formatjs/macro';
3
+ export declare function defineMessages<T, U extends Record<string, T>>(msgs: U): U;
4
4
  import { CustomFormatConfig } from './types';
5
5
  import { UnifiedNumberFormatOptions } from '@formatjs/intl-unified-numberformat';
6
6
  import { IntlListFormatOptions } from '@formatjs/intl-listformat';
@@ -35,5 +35,5 @@ export { FormattedNumberParts } from './components/createFormattedComponent';
35
35
  export { default as FormattedRelativeTime } from './components/relative';
36
36
  export { default as FormattedPlural } from './components/plural';
37
37
  export { default as FormattedMessage } from './components/message';
38
- export { default as FormattedHTMLMessage } from './components/html-message';
39
38
  export { createIntlCache } from './utils';
39
+ export { ReactIntlError, ReactIntlErrorCode } from './error';
package/lib/index.js CHANGED
@@ -1,4 +1,6 @@
1
- export { defineMessages } from '@formatjs/macro';
1
+ export function defineMessages(msgs) {
2
+ return msgs;
3
+ }
2
4
  import { createFormattedComponent, createFormattedDateTimePartsComponent, } from './components/createFormattedComponent';
3
5
  export { default as injectIntl, Provider as RawIntlProvider, Context as IntlContext, } from './components/injectIntl';
4
6
  export { default as useIntl } from './components/useIntl';
@@ -15,5 +17,5 @@ export { FormattedNumberParts } from './components/createFormattedComponent';
15
17
  export { default as FormattedRelativeTime } from './components/relative';
16
18
  export { default as FormattedPlural } from './components/plural';
17
19
  export { default as FormattedMessage } from './components/message';
18
- export { default as FormattedHTMLMessage } from './components/html-message';
19
20
  export { createIntlCache } from './utils';
21
+ export { ReactIntlError } from './error';
@@ -1,7 +1,7 @@
1
- import { defineMessages } from '@formatjs/macro';
2
1
  import { DisplayNames } from '@formatjs/intl-displaynames';
3
2
  import { DisplayNamesOptions } from '@formatjs/intl-displaynames';
4
3
  import { DisplayNamesOptions as DisplayNamesOptions_2 } from '@formatjs/intl-displaynames/lib';
4
+ import { FormatError } from 'intl-messageformat';
5
5
  import { Formats } from 'intl-messageformat';
6
6
  import { FormatXMLElementFn } from 'intl-messageformat';
7
7
  import IntlListFormat from '@formatjs/intl-listformat';
@@ -33,7 +33,8 @@ export declare interface CustomFormats extends Partial<Formats> {
33
33
  }
34
34
 
35
35
  declare const DEFAULT_INTL_CONFIG: Pick<IntlConfig, 'formats' | 'messages' | 'timeZone' | 'textComponent' | 'defaultLocale' | 'defaultFormats' | 'onError'>;
36
- export { defineMessages }
36
+
37
+ export declare function defineMessages<T, U extends Record<string, T>>(msgs: U): U;
37
38
 
38
39
  export declare type FormatDateOptions = Exclude<Intl.DateTimeFormatOptions, 'localeMatcher'> & CustomFormatConfig;
39
40
 
@@ -60,20 +61,11 @@ export declare const FormattedDisplayName: React.FC<DisplayNamesOptions_2 & {
60
61
  value: string | number | object;
61
62
  }>;
62
63
 
63
- export declare class FormattedHTMLMessage extends FormattedMessage<Record<string, PrimitiveType>> {
64
- static displayName: string;
65
- static defaultProps: {
66
- tagName: "span";
67
- values: {};
68
- };
69
- render(): JSX.Element;
70
- }
71
-
72
64
  export declare const FormattedList: React.FC<IntlListFormatOptions & {
73
65
  value: React.ReactNode[];
74
66
  }>;
75
67
 
76
- export declare class FormattedMessage<V extends Record<string, any> = Record<string, PrimitiveType | React.ReactElement | FormatXMLElementFn>> extends React.Component<Props_3<V>> {
68
+ export declare class FormattedMessage<T = React.ReactNode, V extends Record<string, any> = Record<string, PrimitiveType | React.ReactElement | FormatXMLElementFn<T>>> extends React.Component<Props_3<V>> {
77
69
  static displayName: string;
78
70
  static defaultProps: {
79
71
  values: {};
@@ -91,7 +83,7 @@ export declare const FormattedNumberParts: React.FC<Formatter['formatNumber'] &
91
83
  children(val: Intl.NumberFormatPart[]): React.ReactElement | null;
92
84
  }>;
93
85
 
94
- export declare const FormattedPlural: React.ForwardRefExoticComponent<Pick<Props_2, "children" | "other" | "zero" | "one" | "two" | "few" | "many" | "format" | "localeMatcher" | "type" | "value"> & {
86
+ export declare const FormattedPlural: React.ForwardRefExoticComponent<Pick<Props_2, "children" | "other" | "zero" | "one" | "two" | "few" | "many" | "localeMatcher" | "format" | "type" | "value"> & {
95
87
  forwardedRef?: ((instance: any) => void) | React.RefObject<any> | null | undefined;
96
88
  } & React.RefAttributes<any>> & {
97
89
  WrappedComponent: React.ComponentType<Props_2>;
@@ -164,12 +156,12 @@ export declare interface IntlConfig {
164
156
  messages: Record<string, string> | Record<string, MessageFormatElement[]>;
165
157
  defaultLocale: string;
166
158
  defaultFormats: CustomFormats;
167
- onError(err: string): void;
159
+ onError(err: ReactIntlError | FormatError): void;
168
160
  }
169
161
 
170
162
  export declare const IntlContext: React.Context<IntlShape>;
171
163
 
172
- export declare interface IntlFormatters {
164
+ export declare interface IntlFormatters<T = React.ReactNode> {
173
165
  formatDate(value: Parameters<Intl.DateTimeFormat['format']>[0] | string, opts?: FormatDateOptions): string;
174
166
  formatTime(value: Parameters<Intl.DateTimeFormat['format']>[0] | string, opts?: FormatDateOptions): string;
175
167
  formatDateToParts(value: Parameters<Intl.DateTimeFormat['format']>[0] | string, opts?: FormatDateOptions): Intl.DateTimeFormatPart[];
@@ -179,8 +171,7 @@ export declare interface IntlFormatters {
179
171
  formatNumberToParts(value: Parameters<Intl.NumberFormat['format']>[0], opts?: FormatNumberOptions): Intl.NumberFormatPart[];
180
172
  formatPlural(value: Parameters<Intl.PluralRules['select']>[0], opts?: FormatPluralOptions): ReturnType<Intl.PluralRules['select']>;
181
173
  formatMessage(descriptor: MessageDescriptor, values?: Record<string, PrimitiveType>): string;
182
- formatMessage(descriptor: MessageDescriptor, values?: Record<string, PrimitiveType | React.ReactElement | FormatXMLElementFn>): string | React.ReactNodeArray;
183
- formatHTMLMessage(descriptor: MessageDescriptor, values?: Record<string, PrimitiveType>): React.ReactNode;
174
+ formatMessage(descriptor: MessageDescriptor, values?: Record<string, PrimitiveType | React.ReactElement | FormatXMLElementFn<T>>): string | React.ReactNodeArray;
184
175
  formatList(values: Array<string>, opts?: FormatListOptions): string;
185
176
  formatList(values: Array<string | React.ReactNode>, opts?: FormatListOptions): React.ReactNode;
186
177
  formatDisplayName(value: Parameters<DisplayNames['of']>[0], opts?: FormatDisplayNameOptions): string | undefined;
@@ -242,6 +233,19 @@ declare interface Props_3<V extends Record<string, any> = Record<string, React.R
242
233
 
243
234
  export declare const RawIntlProvider: React.Provider<IntlShape>;
244
235
 
236
+ export declare class ReactIntlError extends Error {
237
+ code: ReactIntlErrorCode;
238
+ constructor(code: ReactIntlErrorCode, message: string, exception?: Error);
239
+ }
240
+
241
+ export declare const enum ReactIntlErrorCode {
242
+ FORMAT_ERROR = "FORMAT_ERROR",
243
+ UNSUPPORTED_FORMATTER = "UNSUPPORTED_FORMATTER",
244
+ INVALID_CONFIG = "INVALID_CONFIG",
245
+ MISSING_DATA = "MISSING_DATA",
246
+ MISSING_TRANSLATION = "MISSING_TRANSLATION"
247
+ }
248
+
245
249
  declare interface State {
246
250
  /**
247
251
  * Explicit intl cache to prevent memory leaks