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.
- package/CHANGELOG.md +47 -0
- package/dist/components/message.d.ts +1 -1
- package/dist/components/message.js +2 -2
- package/dist/components/plural.d.ts +1 -1
- package/dist/components/provider.js +13 -8
- package/dist/error.d.ts +11 -0
- package/dist/error.js +28 -0
- package/dist/formatters/dateTime.js +5 -4
- package/dist/formatters/displayName.js +4 -2
- package/dist/formatters/list.js +4 -2
- package/dist/formatters/message.d.ts +1 -2
- package/dist/formatters/message.js +17 -34
- package/dist/formatters/number.js +3 -2
- package/dist/formatters/plural.js +4 -2
- package/dist/formatters/relativeTime.js +4 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +6 -4
- package/dist/react-intl.api.md +29 -22
- package/dist/react-intl.d.ts +77 -36
- package/dist/react-intl.js +6267 -5860
- package/dist/react-intl.js.map +1 -1
- package/dist/react-intl.min.js +1 -1
- package/dist/react-intl.min.js.map +1 -1
- package/dist/types.d.ts +5 -5
- package/dist/utils.d.ts +3 -4
- package/dist/utils.js +2 -18
- package/lib/components/message.d.ts +1 -1
- package/lib/components/message.js +2 -2
- package/lib/components/plural.d.ts +1 -1
- package/lib/components/provider.js +15 -10
- package/lib/error.d.ts +11 -0
- package/lib/error.js +9 -0
- package/lib/formatters/dateTime.js +6 -5
- package/lib/formatters/displayName.js +6 -4
- package/lib/formatters/list.js +6 -4
- package/lib/formatters/message.d.ts +1 -2
- package/lib/formatters/message.js +17 -31
- package/lib/formatters/number.js +4 -3
- package/lib/formatters/plural.js +6 -4
- package/lib/formatters/relativeTime.js +6 -4
- package/lib/index.d.ts +2 -2
- package/lib/index.js +4 -2
- package/lib/react-intl.d.ts +21 -17
- package/lib/tsdoc-metadata.json +1 -1
- package/lib/types.d.ts +5 -5
- package/lib/utils.d.ts +3 -4
- package/lib/utils.js +2 -16
- package/package.json +45 -47
- package/src/components/message.tsx +6 -5
- package/src/components/provider.tsx +25 -14
- package/src/error.ts +18 -0
- package/src/formatters/dateTime.ts +30 -5
- package/src/formatters/displayName.ts +15 -4
- package/src/formatters/list.ts +15 -4
- package/src/formatters/message.ts +49 -66
- package/src/formatters/number.ts +16 -3
- package/src/formatters/plural.ts +15 -4
- package/src/formatters/relativeTime.ts +15 -4
- package/src/index.ts +4 -2
- package/src/types.ts +5 -7
- package/src/utils.ts +4 -25
- package/dist/components/html-message.d.ts +0 -11
- package/dist/components/html-message.js +0 -75
- package/lib/components/html-message.d.ts +0 -11
- package/lib/components/html-message.js +0 -43
- 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:
|
|
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
|
|
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
|
-
|
|
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
|
|
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:
|
|
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
|
|
18
|
-
38: '&',
|
|
19
|
-
62: '>',
|
|
20
|
-
60: '<',
|
|
21
|
-
34: '"',
|
|
22
|
-
39: ''',
|
|
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(
|
|
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
|
|
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
|
-
|
|
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" | "
|
|
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 {
|
|
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
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
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 {
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
22
|
+
onError(new ReactIntlError("FORMAT_ERROR" /* FORMAT_ERROR */, 'Error formatting display name.', e));
|
|
21
23
|
}
|
|
22
24
|
}
|
package/lib/formatters/list.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { filterProps
|
|
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(
|
|
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(
|
|
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 |
|
|
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.
|
|
44
|
+
formattedMessageParts = formatter.format(values);
|
|
45
45
|
}
|
|
46
46
|
catch (e) {
|
|
47
|
-
onError(
|
|
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
|
|
55
|
-
|
|
56
|
-
(
|
|
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
|
|
59
|
+
if (!formattedMessageParts && defaultMessage) {
|
|
62
60
|
try {
|
|
63
61
|
const formatter = state.getMessageFormat(defaultMessage, defaultLocale, defaultFormats);
|
|
64
|
-
formattedMessageParts = formatter.
|
|
62
|
+
formattedMessageParts = formatter.format(values);
|
|
65
63
|
}
|
|
66
64
|
catch (e) {
|
|
67
|
-
onError(
|
|
65
|
+
onError(new ReactIntlError("FORMAT_ERROR" /* FORMAT_ERROR */, `Error formatting the default message for: "${id}"`, e));
|
|
68
66
|
}
|
|
69
67
|
}
|
|
70
|
-
if (!formattedMessageParts
|
|
71
|
-
onError(
|
|
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
|
|
79
|
-
|
|
80
|
-
return formattedMessageParts[0] || defaultMessage || String(id);
|
|
76
|
+
if (Array.isArray(formattedMessageParts)) {
|
|
77
|
+
return prepareIntlMessageFormatHtmlOutput(formattedMessageParts);
|
|
81
78
|
}
|
|
82
|
-
return
|
|
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
|
}
|
package/lib/formatters/number.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { getNamedFormat, filterProps
|
|
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(
|
|
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(
|
|
47
|
+
config.onError(new ReactIntlError("FORMAT_ERROR" /* FORMAT_ERROR */, 'Error formatting number.', e));
|
|
47
48
|
}
|
|
48
49
|
return [];
|
|
49
50
|
}
|
package/lib/formatters/plural.js
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
|
-
import { filterProps
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
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
|
|
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';
|
package/lib/react-intl.d.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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" | "
|
|
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:
|
|
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
|
|
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
|