intl-messageformat 4.1.1 → 4.4.0

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 (38) hide show
  1. package/CHANGELOG.md +32 -44
  2. package/LICENSE +0 -0
  3. package/README.md +108 -59
  4. package/core.js +1 -0
  5. package/dist/compiler.d.ts +10 -4
  6. package/dist/compiler.js +11 -14
  7. package/dist/compiler.js.map +1 -1
  8. package/dist/core.d.ts +78 -0
  9. package/dist/core.js +248 -0
  10. package/dist/core.js.map +1 -0
  11. package/dist/index.d.ts +4 -16
  12. package/dist/index.js +7 -198
  13. package/dist/index.js.map +1 -1
  14. package/dist/umd/intl-messageformat.js +1548 -1373
  15. package/dist/umd/intl-messageformat.js.map +1 -1
  16. package/dist/umd/intl-messageformat.min.js +1 -1
  17. package/dist/umd/intl-messageformat.min.js.map +1 -1
  18. package/index.js +0 -0
  19. package/lib/compiler.d.ts +10 -4
  20. package/lib/compiler.js +11 -14
  21. package/lib/compiler.js.map +1 -1
  22. package/lib/core.d.ts +78 -0
  23. package/lib/core.js +245 -0
  24. package/lib/core.js.map +1 -0
  25. package/lib/index.d.ts +4 -16
  26. package/lib/index.js +4 -198
  27. package/lib/index.js.map +1 -1
  28. package/package.json +4 -4
  29. package/src/compiler.ts +39 -16
  30. package/src/core.ts +269 -0
  31. package/src/index.ts +6 -242
  32. package/.nyc_output/34ec6f1e-d2e9-445f-8813-bd6e8b5975bb.json +0 -1
  33. package/.nyc_output/9b57550b-ff23-4ed6-b289-f7ff8d2beb4f.json +0 -1
  34. package/.nyc_output/b696f16a-7b55-4692-a441-41aa11ca2fb0.json +0 -1
  35. package/.nyc_output/processinfo/34ec6f1e-d2e9-445f-8813-bd6e8b5975bb.json +0 -1
  36. package/.nyc_output/processinfo/9b57550b-ff23-4ed6-b289-f7ff8d2beb4f.json +0 -1
  37. package/.nyc_output/processinfo/b696f16a-7b55-4692-a441-41aa11ca2fb0.json +0 -1
  38. package/.nyc_output/processinfo/index.json +0 -1
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;EAIE;AAEF,OAAO,MAAM,MAAM,2BAA2B,CAAC;AAC/C,OAAO,iBAAiB,MAAM,QAAQ,CAAC;AAEvC,iBAAiB,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC;AAGzC,cAAc,QAAQ,CAAC;AAEvB,eAAe,iBAAiB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "intl-messageformat",
3
- "version": "4.1.1",
3
+ "version": "4.4.0",
4
4
  "description": "Formats ICU Message strings with number, date, plural, and select placeholders to create localized messages.",
5
5
  "keywords": [
6
6
  "i18n",
@@ -31,11 +31,11 @@
31
31
  "module": "lib/index.js",
32
32
  "typings": "lib/index.d.ts",
33
33
  "dependencies": {
34
- "intl-messageformat-parser": "^1.6.7"
34
+ "intl-messageformat-parser": "^1.8.1"
35
35
  },
36
36
  "scripts": {
37
37
  "clean": "rimraf dist lib",
38
- "benchmark": "ts-node --project tests/tsconfig.json tests/benchmark",
38
+ "benchmark": "ts-node --project ./tsconfig.cjs.json tests/benchmark",
39
39
  "build": "tsc && tsc -p tsconfig.cjs.json && rollup -c rollup.config.js",
40
40
  "test": "mocha --opts ../../mocha.opts tests/index.ts",
41
41
  "karma:local": "karma start karma.conf.js",
@@ -46,5 +46,5 @@
46
46
  "test": "tests"
47
47
  },
48
48
  "license": "BSD-3-Clause",
49
- "gitHead": "10a14dda59e32f7fdae54fe258da0eed1437c9cc"
49
+ "gitHead": "60ddf374ed659ffe2f3807c3c7df411c80492761"
50
50
  }
package/src/compiler.ts CHANGED
@@ -18,6 +18,18 @@ export interface Formats {
18
18
  time: Record<string, Intl.DateTimeFormatOptions>;
19
19
  }
20
20
 
21
+ export interface Formatters {
22
+ getNumberFormat(
23
+ ...args: ConstructorParameters<typeof Intl.NumberFormat>
24
+ ): Intl.NumberFormat;
25
+ getDateTimeFormat(
26
+ ...args: ConstructorParameters<typeof Intl.DateTimeFormat>
27
+ ): Intl.DateTimeFormat;
28
+ getPluralRules(
29
+ ...args: ConstructorParameters<typeof Intl.PluralRules>
30
+ ): Intl.PluralRules;
31
+ }
32
+
21
33
  export type Pattern =
22
34
  | string
23
35
  | PluralOffsetString
@@ -35,10 +47,16 @@ export default class Compiler {
35
47
  private pluralNumberFormat: Intl.NumberFormat | null = null;
36
48
  private currentPlural: ArgumentElement | null | undefined = null;
37
49
  private pluralStack: Array<ArgumentElement | null | undefined> = [];
50
+ private formatters: Formatters;
38
51
 
39
- constructor(locales: string | string[], formats: Formats) {
52
+ constructor(
53
+ locales: string | string[],
54
+ formats: Formats,
55
+ formatters: Formatters
56
+ ) {
40
57
  this.locales = locales;
41
58
  this.formats = formats;
59
+ this.formatters = formatters;
42
60
  }
43
61
 
44
62
  compile(ast: MessageFormatPattern): Pattern[] {
@@ -96,6 +114,7 @@ export default class Compiler {
96
114
 
97
115
  compileArgument(element: ArgumentElement) {
98
116
  const { format, id } = element;
117
+ const { formatters } = this;
99
118
 
100
119
  if (!format) {
101
120
  return new StringFormat(id);
@@ -106,31 +125,38 @@ export default class Compiler {
106
125
  case 'numberFormat':
107
126
  return {
108
127
  id,
109
- format: new Intl.NumberFormat(locales, formats.number[format.style])
110
- .format
128
+ format: formatters.getNumberFormat(
129
+ locales,
130
+ formats.number[format.style]
131
+ ).format
111
132
  };
112
133
 
113
134
  case 'dateFormat':
114
135
  return {
115
136
  id,
116
- format: new Intl.DateTimeFormat(locales, formats.date[format.style])
117
- .format
137
+ format: formatters.getDateTimeFormat(
138
+ locales,
139
+ formats.date[format.style]
140
+ ).format
118
141
  };
119
142
 
120
143
  case 'timeFormat':
121
144
  return {
122
145
  id,
123
- format: new Intl.DateTimeFormat(locales, formats.time[format.style])
124
- .format
146
+ format: formatters.getDateTimeFormat(
147
+ locales,
148
+ formats.time[format.style]
149
+ ).format
125
150
  };
126
151
 
127
152
  case 'pluralFormat':
128
153
  return new PluralFormat(
129
154
  id,
130
- format.ordinal,
131
155
  format.offset,
132
156
  this.compileOptions(element),
133
- locales
157
+ formatters.getPluralRules(locales, {
158
+ type: format.ordinal ? 'ordinal' : 'cardinal'
159
+ })
134
160
  );
135
161
 
136
162
  case 'selectFormat':
@@ -176,7 +202,7 @@ abstract class Formatter {
176
202
  abstract format(value: string | number): string;
177
203
  }
178
204
 
179
- export class StringFormat extends Formatter {
205
+ class StringFormat extends Formatter {
180
206
  format(value: number | string) {
181
207
  if (!value && typeof value !== 'number') {
182
208
  return '';
@@ -186,24 +212,21 @@ export class StringFormat extends Formatter {
186
212
  }
187
213
  }
188
214
 
189
- export class PluralFormat {
215
+ class PluralFormat {
190
216
  public id: string;
191
217
  private offset: number;
192
218
  private options: Record<string, Pattern[]>;
193
219
  private pluralRules: Intl.PluralRules;
194
220
  constructor(
195
221
  id: string,
196
- useOrdinal: boolean,
197
222
  offset: number,
198
223
  options: Record<string, Pattern[]>,
199
- locales: string | string[]
224
+ pluralRules: Intl.PluralRules
200
225
  ) {
201
226
  this.id = id;
202
227
  this.offset = offset;
203
228
  this.options = options;
204
- this.pluralRules = new Intl.PluralRules(locales, {
205
- type: useOrdinal ? 'ordinal' : 'cardinal'
206
- });
229
+ this.pluralRules = pluralRules;
207
230
  }
208
231
 
209
232
  getOption(value: number) {
package/src/core.ts ADDED
@@ -0,0 +1,269 @@
1
+ /*
2
+ Copyright (c) 2014, Yahoo! Inc. All rights reserved.
3
+ Copyrights licensed under the New BSD License.
4
+ See the accompanying LICENSE file for terms.
5
+ */
6
+
7
+ /* jslint esnext: true */
8
+
9
+ import Compiler, {
10
+ Formats,
11
+ isSelectOrPluralFormat,
12
+ Pattern,
13
+ Formatters
14
+ } from './compiler';
15
+ import parser, { MessageFormatPattern } from 'intl-messageformat-parser';
16
+
17
+ // -- MessageFormat --------------------------------------------------------
18
+
19
+ function resolveLocale(locales: string | string[]): string {
20
+ if (typeof locales === 'string') {
21
+ locales = [locales];
22
+ }
23
+ try {
24
+ return Intl.NumberFormat.supportedLocalesOf(locales, {
25
+ // IE11 localeMatcher `lookup` seems to convert `en` -> `en-US`
26
+ // but not other browsers,
27
+ localeMatcher: 'best fit'
28
+ })[0];
29
+ } catch (e) {
30
+ return IntlMessageFormat.defaultLocale;
31
+ }
32
+ }
33
+
34
+ function formatPatterns(
35
+ pattern: Pattern[],
36
+ values?: Record<string, string | number | boolean | null | undefined>
37
+ ) {
38
+ let result = '';
39
+ for (const part of pattern) {
40
+ // Exist early for string parts.
41
+ if (typeof part === 'string') {
42
+ result += part;
43
+ continue;
44
+ }
45
+
46
+ const { id } = part;
47
+
48
+ // Enforce that all required values are provided by the caller.
49
+ if (!(values && id in values)) {
50
+ throw new FormatError(`A value must be provided for: ${id}`, id);
51
+ }
52
+
53
+ const value = values[id];
54
+
55
+ // Recursively format plural and select parts' option — which can be a
56
+ // nested pattern structure. The choosing of the option to use is
57
+ // abstracted-by and delegated-to the part helper object.
58
+ if (isSelectOrPluralFormat(part)) {
59
+ result += formatPatterns(part.getOption(value as any), values);
60
+ } else {
61
+ result += part.format(value as any);
62
+ }
63
+ }
64
+
65
+ return result;
66
+ }
67
+
68
+ function mergeConfig(c1: Record<string, object>, c2?: Record<string, object>) {
69
+ if (!c2) {
70
+ return c1;
71
+ }
72
+ return {
73
+ ...(c1 || {}),
74
+ ...(c2 || {}),
75
+ ...Object.keys(c1).reduce((all: Record<string, object>, k) => {
76
+ all[k] = {
77
+ ...c1[k],
78
+ ...(c2[k] || {})
79
+ };
80
+ return all;
81
+ }, {})
82
+ };
83
+ }
84
+
85
+ function mergeConfigs(
86
+ defaultConfig: Formats,
87
+ configs?: Partial<Formats>
88
+ ): Formats {
89
+ if (!configs) {
90
+ return defaultConfig;
91
+ }
92
+
93
+ return (Object.keys(defaultConfig) as Array<keyof Formats>).reduce(
94
+ (all: Formats, k: keyof Formats) => {
95
+ all[k] = mergeConfig(defaultConfig[k], configs[k]);
96
+ return all;
97
+ },
98
+ { ...defaultConfig }
99
+ );
100
+ }
101
+
102
+ class FormatError extends Error {
103
+ public readonly variableId?: string;
104
+ constructor(msg?: string, variableId?: string) {
105
+ super(msg);
106
+ this.variableId = variableId;
107
+ }
108
+ }
109
+
110
+ export interface Options {
111
+ formatters?: Formatters;
112
+ }
113
+
114
+ export function createDefaultFormatters(): Formatters {
115
+ return {
116
+ getNumberFormat(...args) {
117
+ return new Intl.NumberFormat(...args);
118
+ },
119
+ getDateTimeFormat(...args) {
120
+ return new Intl.DateTimeFormat(...args);
121
+ },
122
+ getPluralRules(...args) {
123
+ return new Intl.PluralRules(...args);
124
+ }
125
+ };
126
+ }
127
+
128
+ export class IntlMessageFormat {
129
+ private ast: MessageFormatPattern;
130
+ private locale: string;
131
+ private pattern: Pattern[];
132
+ private message: string | MessageFormatPattern;
133
+ constructor(
134
+ message: string | MessageFormatPattern,
135
+ locales: string | string[] = IntlMessageFormat.defaultLocale,
136
+ overrideFormats?: Partial<Formats>,
137
+ opts?: Options
138
+ ) {
139
+ if (typeof message === 'string') {
140
+ if (!IntlMessageFormat.__parse) {
141
+ throw new TypeError(
142
+ 'IntlMessageFormat.__parse must be set to process `message` of type `string`'
143
+ );
144
+ }
145
+ // Parse string messages into an AST.
146
+ this.ast = IntlMessageFormat.__parse(message);
147
+ } else {
148
+ this.ast = message;
149
+ }
150
+
151
+ this.message = message;
152
+
153
+ if (!(this.ast && this.ast.type === 'messageFormatPattern')) {
154
+ throw new TypeError('A message must be provided as a String or AST.');
155
+ }
156
+
157
+ // Creates a new object with the specified `formats` merged with the default
158
+ // formats.
159
+ const formats = mergeConfigs(IntlMessageFormat.formats, overrideFormats);
160
+
161
+ // Defined first because it's used to build the format pattern.
162
+ this.locale = resolveLocale(locales || []);
163
+
164
+ let formatters = (opts && opts.formatters) || createDefaultFormatters();
165
+
166
+ // Compile the `ast` to a pattern that is highly optimized for repeated
167
+ // `format()` invocations. **Note:** This passes the `locales` set provided
168
+ // to the constructor instead of just the resolved locale.
169
+ this.pattern = new Compiler(locales, formats, formatters).compile(this.ast);
170
+
171
+ // "Bind" `format()` method to `this` so it can be passed by reference like
172
+ // the other `Intl` APIs.
173
+ }
174
+
175
+ format = (
176
+ values?: Record<string, string | number | boolean | null | undefined>
177
+ ) => {
178
+ try {
179
+ return formatPatterns(this.pattern, values);
180
+ } catch (e) {
181
+ if (e.variableId) {
182
+ throw new Error(
183
+ `The intl string context variable '${e.variableId}' was not provided to the string '${this.message}'`
184
+ );
185
+ } else {
186
+ throw e;
187
+ }
188
+ }
189
+ };
190
+ resolvedOptions() {
191
+ return { locale: this.locale };
192
+ }
193
+ getAst() {
194
+ return this.ast;
195
+ }
196
+ static defaultLocale = 'en';
197
+ static __parse: typeof parser['parse'] | undefined = undefined;
198
+ // Default format options used as the prototype of the `formats` provided to the
199
+ // constructor. These are used when constructing the internal Intl.NumberFormat
200
+ // and Intl.DateTimeFormat instances.
201
+ static formats = {
202
+ number: {
203
+ currency: {
204
+ style: 'currency'
205
+ },
206
+
207
+ percent: {
208
+ style: 'percent'
209
+ }
210
+ },
211
+
212
+ date: {
213
+ short: {
214
+ month: 'numeric',
215
+ day: 'numeric',
216
+ year: '2-digit'
217
+ },
218
+
219
+ medium: {
220
+ month: 'short',
221
+ day: 'numeric',
222
+ year: 'numeric'
223
+ },
224
+
225
+ long: {
226
+ month: 'long',
227
+ day: 'numeric',
228
+ year: 'numeric'
229
+ },
230
+
231
+ full: {
232
+ weekday: 'long',
233
+ month: 'long',
234
+ day: 'numeric',
235
+ year: 'numeric'
236
+ }
237
+ },
238
+
239
+ time: {
240
+ short: {
241
+ hour: 'numeric',
242
+ minute: 'numeric'
243
+ },
244
+
245
+ medium: {
246
+ hour: 'numeric',
247
+ minute: 'numeric',
248
+ second: 'numeric'
249
+ },
250
+
251
+ long: {
252
+ hour: 'numeric',
253
+ minute: 'numeric',
254
+ second: 'numeric',
255
+ timeZoneName: 'short'
256
+ },
257
+
258
+ full: {
259
+ hour: 'numeric',
260
+ minute: 'numeric',
261
+ second: 'numeric',
262
+ timeZoneName: 'short'
263
+ }
264
+ }
265
+ };
266
+ }
267
+
268
+ export { Formats, Pattern } from './compiler';
269
+ export default IntlMessageFormat;
package/src/index.ts CHANGED
@@ -4,248 +4,12 @@ Copyrights licensed under the New BSD License.
4
4
  See the accompanying LICENSE file for terms.
5
5
  */
6
6
 
7
- /* jslint esnext: true */
7
+ import parser from 'intl-messageformat-parser';
8
+ import IntlMessageFormat from './core';
8
9
 
9
- import Compiler, { Formats, isSelectOrPluralFormat, Pattern } from './compiler';
10
- import parser, { MessageFormatPattern } from 'intl-messageformat-parser';
11
-
12
- // -- MessageFormat --------------------------------------------------------
13
-
14
- function resolveLocale(locales: string | string[]): string {
15
- if (typeof locales === 'string') {
16
- locales = [locales];
17
- }
18
- try {
19
- return Intl.NumberFormat.supportedLocalesOf(locales, {
20
- // IE11 localeMatcher `lookup` seems to convert `en` -> `en-US`
21
- // but not other browsers,
22
- localeMatcher: 'best fit'
23
- })[0];
24
- } catch (e) {
25
- return MessageFormat.defaultLocale;
26
- }
27
- }
28
-
29
- function formatPatterns(
30
- pattern: Pattern[],
31
- values?: Record<string, string | number | boolean | null | undefined>
32
- ) {
33
- let result = '';
34
- for (const part of pattern) {
35
- // Exist early for string parts.
36
- if (typeof part === 'string') {
37
- result += part;
38
- continue;
39
- }
40
-
41
- const { id } = part;
42
-
43
- // Enforce that all required values are provided by the caller.
44
- if (!(values && id in values)) {
45
- throw new FormatError(`A value must be provided for: ${id}`, id);
46
- }
47
-
48
- const value = values[id];
49
-
50
- // Recursively format plural and select parts' option — which can be a
51
- // nested pattern structure. The choosing of the option to use is
52
- // abstracted-by and delegated-to the part helper object.
53
- if (isSelectOrPluralFormat(part)) {
54
- result += formatPatterns(part.getOption(value as any), values);
55
- } else {
56
- result += part.format(value as any);
57
- }
58
- }
59
-
60
- return result;
61
- }
62
-
63
- function mergeConfig(c1: Record<string, object>, c2?: Record<string, object>) {
64
- if (!c2) {
65
- return c1;
66
- }
67
- return {
68
- ...(c1 || {}),
69
- ...(c2 || {}),
70
- ...Object.keys(c1).reduce((all: Record<string, object>, k) => {
71
- all[k] = {
72
- ...c1[k],
73
- ...(c2[k] || {})
74
- };
75
- return all;
76
- }, {})
77
- };
78
- }
79
-
80
- function mergeConfigs(
81
- defaultConfig: Formats,
82
- configs?: Partial<Formats>
83
- ): Formats {
84
- if (!configs) {
85
- return defaultConfig;
86
- }
87
-
88
- return (Object.keys(defaultConfig) as Array<keyof Formats>).reduce(
89
- (all: Formats, k: keyof Formats) => {
90
- all[k] = mergeConfig(defaultConfig[k], configs[k]);
91
- return all;
92
- },
93
- { ...defaultConfig }
94
- );
95
- }
96
-
97
- class FormatError extends Error {
98
- public readonly variableId?: string;
99
- constructor(msg?: string, variableId?: string) {
100
- super(msg);
101
- this.variableId = variableId;
102
- }
103
- }
104
-
105
- export interface IntlMessageFormat {
106
- new (
107
- message: string | MessageFormatPattern,
108
- locales?: string | string[],
109
- overrideFormats?: Partial<Formats>
110
- ): IntlMessageFormat;
111
- (
112
- message: string | MessageFormatPattern,
113
- locales?: string | string[],
114
- overrideFormats?: Partial<Formats>
115
- ): IntlMessageFormat;
116
- format(
117
- values?: Record<string, string | number | boolean | null | undefined>
118
- ): string;
119
- resolvedOptions(): { locale: string };
120
- getAst(): ReturnType<typeof parser['parse']>;
121
- defaultLocale: string;
122
- formats: Formats;
123
- __parse: typeof parser['parse'];
124
- }
125
-
126
- const MessageFormat: IntlMessageFormat = ((
127
- message: string | MessageFormatPattern,
128
- locales: string | string[] = MessageFormat.defaultLocale,
129
- overrideFormats?: Partial<Formats>
130
- ) => {
131
- // Parse string messages into an AST.
132
- const ast =
133
- typeof message === 'string' ? MessageFormat.__parse(message) : message;
134
-
135
- if (!(ast && ast.type === 'messageFormatPattern')) {
136
- throw new TypeError('A message must be provided as a String or AST.');
137
- }
138
-
139
- // Creates a new object with the specified `formats` merged with the default
140
- // formats.
141
- const formats = mergeConfigs(MessageFormat.formats, overrideFormats);
142
-
143
- // Defined first because it's used to build the format pattern.
144
- const locale = resolveLocale(locales || []);
145
-
146
- // Compile the `ast` to a pattern that is highly optimized for repeated
147
- // `format()` invocations. **Note:** This passes the `locales` set provided
148
- // to the constructor instead of just the resolved locale.
149
- const pattern = new Compiler(locales, formats).compile(ast);
150
-
151
- // "Bind" `format()` method to `this` so it can be passed by reference like
152
- // the other `Intl` APIs.
153
- return {
154
- format(
155
- values?: Record<string, string | number | boolean | null | undefined>
156
- ) {
157
- try {
158
- return formatPatterns(pattern, values);
159
- } catch (e) {
160
- if (e.variableId) {
161
- throw new Error(
162
- `The intl string context variable '${e.variableId}' was not provided to the string '${message}'`
163
- );
164
- } else {
165
- throw e;
166
- }
167
- }
168
- },
169
- resolvedOptions() {
170
- return { locale };
171
- },
172
- getAst() {
173
- return ast;
174
- }
175
- };
176
- }) as any;
177
-
178
- MessageFormat.defaultLocale = 'en';
179
- // Default format options used as the prototype of the `formats` provided to the
180
- // constructor. These are used when constructing the internal Intl.NumberFormat
181
- // and Intl.DateTimeFormat instances.
182
- MessageFormat.formats = {
183
- number: {
184
- currency: {
185
- style: 'currency'
186
- },
187
-
188
- percent: {
189
- style: 'percent'
190
- }
191
- },
192
-
193
- date: {
194
- short: {
195
- month: 'numeric',
196
- day: 'numeric',
197
- year: '2-digit'
198
- },
199
-
200
- medium: {
201
- month: 'short',
202
- day: 'numeric',
203
- year: 'numeric'
204
- },
205
-
206
- long: {
207
- month: 'long',
208
- day: 'numeric',
209
- year: 'numeric'
210
- },
211
-
212
- full: {
213
- weekday: 'long',
214
- month: 'long',
215
- day: 'numeric',
216
- year: 'numeric'
217
- }
218
- },
219
-
220
- time: {
221
- short: {
222
- hour: 'numeric',
223
- minute: 'numeric'
224
- },
225
-
226
- medium: {
227
- hour: 'numeric',
228
- minute: 'numeric',
229
- second: 'numeric'
230
- },
231
-
232
- long: {
233
- hour: 'numeric',
234
- minute: 'numeric',
235
- second: 'numeric',
236
- timeZoneName: 'short'
237
- },
238
-
239
- full: {
240
- hour: 'numeric',
241
- minute: 'numeric',
242
- second: 'numeric',
243
- timeZoneName: 'short'
244
- }
245
- }
246
- };
247
-
248
- MessageFormat.__parse = parser.parse;
10
+ IntlMessageFormat.__parse = parser.parse;
249
11
 
250
12
  export { Formats, Pattern } from './compiler';
251
- export default MessageFormat;
13
+ export * from './core';
14
+ export { Formatters } from './compiler';
15
+ export default IntlMessageFormat;
@@ -1 +0,0 @@
1
- {"uuid":"34ec6f1e-d2e9-445f-8813-bd6e8b5975bb","parent":null,"pid":5446,"argv":["/home/longho/.nvm/versions/node/v12.3.1/bin/node","/home/longho/.nvm/versions/node/v12.3.1/bin/npm","t"],"execArgv":[],"cwd":"/mnt/c/src/formatjs/packages/intl-messageformat","time":1559351011753,"ppid":5429,"root":"94cf06ed-2315-4819-86e9-a1ae5ab2cbb0","coverageFilename":"/mnt/c/src/formatjs/packages/intl-messageformat/.nyc_output/34ec6f1e-d2e9-445f-8813-bd6e8b5975bb.json","files":[]}