use-intl 3.25.1 → 4.0.0-beta-00a79d4

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 (119) hide show
  1. package/core.d.ts +2 -1
  2. package/dist/esm/development/core.js +82 -0
  3. package/dist/esm/development/index.js +7 -0
  4. package/dist/{development/createFormatter-D2v4ATzl.js → esm/development/initializeConfig-DSmAVNvj.js} +277 -129
  5. package/dist/esm/development/react.js +184 -0
  6. package/dist/esm/production/core.js +1 -0
  7. package/dist/esm/production/index.js +1 -0
  8. package/dist/esm/production/initializeConfig-BE7tJS3N.js +1 -0
  9. package/dist/esm/production/react.js +1 -0
  10. package/dist/types/{src/core → core}/AbstractIntlMessages.d.ts +3 -2
  11. package/dist/types/core/AppConfig.d.ts +25 -0
  12. package/dist/types/{src/core → core}/DateTimeFormatOptions.d.ts +1 -1
  13. package/dist/types/{src/core → core}/Formats.d.ts +2 -2
  14. package/dist/types/core/ICUArgs.d.ts +3 -0
  15. package/dist/types/core/ICUTags.d.ts +2 -0
  16. package/dist/types/{src/core → core}/IntlConfig.d.ts +6 -13
  17. package/dist/types/core/IntlError.d.ts +6 -0
  18. package/dist/types/{src/core/IntlError.d.ts → core/IntlErrorCode.d.ts} +2 -6
  19. package/dist/types/core/MessageKeys.d.ts +10 -0
  20. package/dist/types/core/TranslationValues.d.ts +9 -0
  21. package/dist/types/{src/core → core}/convertFormatsToIntlMessageFormat.d.ts +4 -4
  22. package/dist/types/{src/core → core}/createBaseTranslator.d.ts +9 -12
  23. package/dist/types/core/createFormatter.d.ts +28 -0
  24. package/dist/types/core/createTranslator.d.ts +52 -0
  25. package/dist/types/core/createTranslatorImpl.d.ts +17 -0
  26. package/dist/types/{src/core → core}/defaults.d.ts +1 -1
  27. package/dist/types/{src/core → core}/formatters.d.ts +1 -1
  28. package/dist/types/core/hasLocale.d.ts +10 -0
  29. package/dist/types/core/index.d.ts +20 -0
  30. package/dist/types/{src/core → core}/initializeConfig.d.ts +4 -4
  31. package/dist/types/core/types.d.ts +3 -0
  32. package/dist/types/{src/core → core}/validateMessages.d.ts +2 -2
  33. package/dist/types/core.d.ts +1 -0
  34. package/dist/types/index.d.ts +2 -0
  35. package/dist/types/{src/react → react}/IntlContext.d.ts +2 -2
  36. package/dist/types/react/IntlProvider.d.ts +7 -0
  37. package/dist/types/react/index.d.ts +7 -0
  38. package/dist/types/{src/react → react}/useFormatter.d.ts +1 -1
  39. package/dist/types/{src/react → react}/useIntlContext.d.ts +1 -1
  40. package/dist/types/react/useLocale.d.ts +2 -0
  41. package/dist/types/react/useMessages.d.ts +2 -0
  42. package/dist/types/react/useNow.d.ts +8 -0
  43. package/dist/types/react/useTimeZone.d.ts +1 -0
  44. package/dist/types/react/useTranslations.d.ts +12 -0
  45. package/dist/types/react/useTranslationsImpl.d.ts +9 -0
  46. package/dist/types/react.d.ts +1 -0
  47. package/package.json +18 -24
  48. package/react.d.ts +2 -1
  49. package/_IntlProvider.d.ts +0 -1
  50. package/_useLocale.d.ts +0 -1
  51. package/dist/_IntlProvider.js +0 -7
  52. package/dist/_useLocale.js +0 -7
  53. package/dist/core.js +0 -7
  54. package/dist/development/IntlContext-BKfsnzBx.js +0 -7
  55. package/dist/development/_IntlProvider.js +0 -61
  56. package/dist/development/_useLocale-0Rl9uR82.js +0 -19
  57. package/dist/development/_useLocale.js +0 -11
  58. package/dist/development/core.js +0 -69
  59. package/dist/development/index.js +0 -31
  60. package/dist/development/initializeConfig-BhfMSHP7.js +0 -185
  61. package/dist/development/react.js +0 -151
  62. package/dist/esm/IntlContext-DoS4CDM3.js +0 -1
  63. package/dist/esm/_IntlProvider.js +0 -1
  64. package/dist/esm/_useLocale-v-ZT5JoE.js +0 -1
  65. package/dist/esm/_useLocale.js +0 -1
  66. package/dist/esm/core.js +0 -1
  67. package/dist/esm/createFormatter-zqPbsiYR.js +0 -1
  68. package/dist/esm/index.js +0 -1
  69. package/dist/esm/initializeConfig-D2A8plWf.js +0 -1
  70. package/dist/esm/react.js +0 -1
  71. package/dist/index.js +0 -7
  72. package/dist/production/IntlContext-DcFt0tgW.js +0 -1
  73. package/dist/production/_IntlProvider.js +0 -1
  74. package/dist/production/_useLocale-CpTrqBDt.js +0 -1
  75. package/dist/production/_useLocale.js +0 -1
  76. package/dist/production/core.js +0 -1
  77. package/dist/production/createFormatter-CZeYe_QF.js +0 -1
  78. package/dist/production/index.js +0 -1
  79. package/dist/production/initializeConfig-AbYTngyP.js +0 -1
  80. package/dist/production/react.js +0 -1
  81. package/dist/react.js +0 -7
  82. package/dist/types/src/_IntlProvider.d.ts +0 -1
  83. package/dist/types/src/_useLocale.d.ts +0 -1
  84. package/dist/types/src/core/TranslationValues.d.ts +0 -6
  85. package/dist/types/src/core/createFormatter.d.ts +0 -27
  86. package/dist/types/src/core/createFormatter.test.d.ts +0 -1
  87. package/dist/types/src/core/createTranslator.d.ts +0 -71
  88. package/dist/types/src/core/createTranslator.test.d.ts +0 -1
  89. package/dist/types/src/core/createTranslatorImpl.d.ts +0 -17
  90. package/dist/types/src/core/index.d.ts +0 -18
  91. package/dist/types/src/core/utils/MessageKeys.d.ts +0 -5
  92. package/dist/types/src/core/utils/NamespaceKeys.d.ts +0 -5
  93. package/dist/types/src/core/utils/NestedKeyOf.d.ts +0 -4
  94. package/dist/types/src/core/utils/NestedValueOf.d.ts +0 -2
  95. package/dist/types/src/core.d.ts +0 -1
  96. package/dist/types/src/index.d.ts +0 -2
  97. package/dist/types/src/react/IntlProvider.d.ts +0 -7
  98. package/dist/types/src/react/IntlProvider.test.d.ts +0 -1
  99. package/dist/types/src/react/index.d.ts +0 -7
  100. package/dist/types/src/react/index.test.d.ts +0 -1
  101. package/dist/types/src/react/useFormatter.test.d.ts +0 -1
  102. package/dist/types/src/react/useLocale.d.ts +0 -1
  103. package/dist/types/src/react/useLocale.test.d.ts +0 -1
  104. package/dist/types/src/react/useMessages.d.ts +0 -2
  105. package/dist/types/src/react/useMessages.test.d.ts +0 -1
  106. package/dist/types/src/react/useNow.d.ts +0 -23
  107. package/dist/types/src/react/useNow.test.d.ts +0 -1
  108. package/dist/types/src/react/useTimeZone.d.ts +0 -1
  109. package/dist/types/src/react/useTimeZone.test.d.ts +0 -1
  110. package/dist/types/src/react/useTranslations.d.ts +0 -62
  111. package/dist/types/src/react/useTranslations.test.d.ts +0 -1
  112. package/dist/types/src/react/useTranslationsImpl.d.ts +0 -9
  113. package/dist/types/src/react.d.ts +0 -1
  114. package/dist/types/test/setup.d.ts +0 -1
  115. /package/dist/types/{src/core → core}/NumberFormatOptions.d.ts +0 -0
  116. /package/dist/types/{src/core → core}/RelativeTimeFormatOptions.d.ts +0 -0
  117. /package/dist/types/{src/core → core}/TimeZone.d.ts +0 -0
  118. /package/dist/types/{src/core → core}/joinPath.d.ts +0 -0
  119. /package/dist/types/{src/core → core}/resolveNamespace.d.ts +0 -0
@@ -1,27 +1,32 @@
1
- 'use strict';
1
+ import { IntlMessageFormat } from 'intl-messageformat';
2
+ import { isValidElement, cloneElement } from 'react';
3
+ import { memoize, strategies } from '@formatjs/fast-memoize';
2
4
 
3
- var IntlMessageFormat = require('intl-messageformat');
4
- var React = require('react');
5
- var initializeConfig = require('./initializeConfig-BhfMSHP7.js');
6
-
7
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
-
9
- var IntlMessageFormat__default = /*#__PURE__*/_interopDefault(IntlMessageFormat);
10
-
11
- function setTimeZoneInFormats(formats, timeZone) {
12
- if (!formats) return formats;
13
-
14
- // The only way to set a time zone with `intl-messageformat` is to merge it into the formats
15
- // https://github.com/formatjs/formatjs/blob/8256c5271505cf2606e48e3c97ecdd16ede4f1b5/packages/intl/src/message.ts#L15
16
- return Object.keys(formats).reduce((acc, key) => {
17
- acc[key] = {
18
- timeZone,
19
- ...formats[key]
20
- };
21
- return acc;
22
- }, {});
5
+ class IntlError extends Error {
6
+ constructor(code, originalMessage) {
7
+ let message = code;
8
+ if (originalMessage) {
9
+ message += ': ' + originalMessage;
10
+ }
11
+ super(message);
12
+ this.code = code;
13
+ if (originalMessage) {
14
+ this.originalMessage = originalMessage;
15
+ }
16
+ }
23
17
  }
24
18
 
19
+ var IntlErrorCode = /*#__PURE__*/function (IntlErrorCode) {
20
+ IntlErrorCode["MISSING_MESSAGE"] = "MISSING_MESSAGE";
21
+ IntlErrorCode["MISSING_FORMAT"] = "MISSING_FORMAT";
22
+ IntlErrorCode["ENVIRONMENT_FALLBACK"] = "ENVIRONMENT_FALLBACK";
23
+ IntlErrorCode["INSUFFICIENT_PATH"] = "INSUFFICIENT_PATH";
24
+ IntlErrorCode["INVALID_MESSAGE"] = "INVALID_MESSAGE";
25
+ IntlErrorCode["INVALID_KEY"] = "INVALID_KEY";
26
+ IntlErrorCode["FORMATTING_ERROR"] = "FORMATTING_ERROR";
27
+ return IntlErrorCode;
28
+ }(IntlErrorCode || {});
29
+
25
30
  /**
26
31
  * `intl-messageformat` uses separate keys for `date` and `time`, but there's
27
32
  * only one native API: `Intl.DateTimeFormat`. Additionally you might want to
@@ -29,43 +34,124 @@ function setTimeZoneInFormats(formats, timeZone) {
29
34
  * seem so useful. We offer a single `dateTime` namespace instead, but we have
30
35
  * to convert the format before `intl-messageformat` can be used.
31
36
  */
32
- function convertFormatsToIntlMessageFormat(formats, timeZone) {
33
- const formatsWithTimeZone = timeZone ? {
34
- ...formats,
35
- dateTime: setTimeZoneInFormats(formats.dateTime, timeZone)
36
- } : formats;
37
- const mfDateDefaults = IntlMessageFormat__default.default.formats.date;
38
- const defaultDateFormats = timeZone ? setTimeZoneInFormats(mfDateDefaults, timeZone) : mfDateDefaults;
39
- const mfTimeDefaults = IntlMessageFormat__default.default.formats.time;
40
- const defaultTimeFormats = timeZone ? setTimeZoneInFormats(mfTimeDefaults, timeZone) : mfTimeDefaults;
41
- return {
42
- ...formatsWithTimeZone,
37
+ function convertFormatsToIntlMessageFormat(globalFormats, inlineFormats, timeZone) {
38
+ const mfDateDefaults = IntlMessageFormat.formats.date;
39
+ const mfTimeDefaults = IntlMessageFormat.formats.time;
40
+ const dateTimeFormats = {
41
+ ...globalFormats?.dateTime,
42
+ ...inlineFormats?.dateTime
43
+ };
44
+ const allFormats = {
43
45
  date: {
44
- ...defaultDateFormats,
45
- ...formatsWithTimeZone.dateTime
46
+ ...mfDateDefaults,
47
+ ...dateTimeFormats
46
48
  },
47
49
  time: {
48
- ...defaultTimeFormats,
49
- ...formatsWithTimeZone.dateTime
50
+ ...mfTimeDefaults,
51
+ ...dateTimeFormats
52
+ },
53
+ number: {
54
+ ...globalFormats?.number,
55
+ ...inlineFormats?.number
56
+ }
57
+ // (list is not supported in ICU messages)
58
+ };
59
+ if (timeZone) {
60
+ // The only way to set a time zone with `intl-messageformat` is to merge it into the formats
61
+ // https://github.com/formatjs/formatjs/blob/8256c5271505cf2606e48e3c97ecdd16ede4f1b5/packages/intl/src/message.ts#L15
62
+ ['date', 'time'].forEach(property => {
63
+ const formats = allFormats[property];
64
+ for (const [key, value] of Object.entries(formats)) {
65
+ formats[key] = {
66
+ timeZone,
67
+ ...value
68
+ };
69
+ }
70
+ });
71
+ }
72
+ return allFormats;
73
+ }
74
+
75
+ function joinPath(...parts) {
76
+ return parts.filter(Boolean).join('.');
77
+ }
78
+
79
+ /**
80
+ * Contains defaults that are used for all entry points into the core.
81
+ * See also `InitializedIntlConfiguration`.
82
+ */
83
+
84
+ function defaultGetMessageFallback(props) {
85
+ return joinPath(props.namespace, props.key);
86
+ }
87
+ function defaultOnError(error) {
88
+ console.error(error);
89
+ }
90
+
91
+ function createCache() {
92
+ return {
93
+ dateTime: {},
94
+ number: {},
95
+ message: {},
96
+ relativeTime: {},
97
+ pluralRules: {},
98
+ list: {},
99
+ displayNames: {}
100
+ };
101
+ }
102
+ function createMemoCache(store) {
103
+ return {
104
+ create() {
105
+ return {
106
+ get(key) {
107
+ return store[key];
108
+ },
109
+ set(key, value) {
110
+ store[key] = value;
111
+ }
112
+ };
50
113
  }
51
114
  };
52
115
  }
116
+ function memoFn(fn, cache) {
117
+ return memoize(fn, {
118
+ cache: createMemoCache(cache),
119
+ strategy: strategies.variadic
120
+ });
121
+ }
122
+ function memoConstructor(ConstructorFn, cache) {
123
+ return memoFn((...args) => new ConstructorFn(...args), cache);
124
+ }
125
+ function createIntlFormatters(cache) {
126
+ const getDateTimeFormat = memoConstructor(Intl.DateTimeFormat, cache.dateTime);
127
+ const getNumberFormat = memoConstructor(Intl.NumberFormat, cache.number);
128
+ const getPluralRules = memoConstructor(Intl.PluralRules, cache.pluralRules);
129
+ const getRelativeTimeFormat = memoConstructor(Intl.RelativeTimeFormat, cache.relativeTime);
130
+ const getListFormat = memoConstructor(Intl.ListFormat, cache.list);
131
+ const getDisplayNames = memoConstructor(Intl.DisplayNames, cache.displayNames);
132
+ return {
133
+ getDateTimeFormat,
134
+ getNumberFormat,
135
+ getPluralRules,
136
+ getRelativeTimeFormat,
137
+ getListFormat,
138
+ getDisplayNames
139
+ };
140
+ }
53
141
 
54
142
  // Placed here for improved tree shaking. Somehow when this is placed in
55
143
  // `formatters.tsx`, then it can't be shaken off from `next-intl`.
56
144
  function createMessageFormatter(cache, intlFormatters) {
57
- const getMessageFormat = initializeConfig.memoFn(function () {
58
- return new IntlMessageFormat__default.default(arguments.length <= 0 ? undefined : arguments[0], arguments.length <= 1 ? undefined : arguments[1], arguments.length <= 2 ? undefined : arguments[2], {
59
- formatters: intlFormatters,
60
- ...(arguments.length <= 3 ? undefined : arguments[3])
61
- });
62
- }, cache.message);
145
+ const getMessageFormat = memoFn((...args) => new IntlMessageFormat(args[0], args[1], args[2], {
146
+ formatters: intlFormatters,
147
+ ...args[3]
148
+ }), cache.message);
63
149
  return getMessageFormat;
64
150
  }
65
151
  function resolvePath(locale, messages, key, namespace) {
66
- const fullKey = initializeConfig.joinPath(namespace, key);
152
+ const fullKey = joinPath(namespace, key);
67
153
  if (!messages) {
68
- throw new Error("No messages available at `".concat(namespace, "`.") );
154
+ throw new Error(`No messages available at \`${namespace}\`.` );
69
155
  }
70
156
  let message = messages;
71
157
  key.split('.').forEach(part => {
@@ -73,15 +159,13 @@ function resolvePath(locale, messages, key, namespace) {
73
159
 
74
160
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
75
161
  if (part == null || next == null) {
76
- throw new Error("Could not resolve `".concat(fullKey, "` in messages for locale `").concat(locale, "`.") );
162
+ throw new Error(`Could not resolve \`${fullKey}\` in messages for locale \`${locale}\`.` );
77
163
  }
78
164
  message = next;
79
165
  });
80
166
  return message;
81
167
  }
82
168
  function prepareTranslationValues(values) {
83
- if (Object.keys(values).length === 0) return undefined;
84
-
85
169
  // Workaround for https://github.com/formatjs/formatjs/issues/1467
86
170
  const transformedValues = {};
87
171
  Object.keys(values).forEach(key => {
@@ -91,7 +175,7 @@ function prepareTranslationValues(values) {
91
175
  if (typeof value === 'function') {
92
176
  transformed = chunks => {
93
177
  const result = value(chunks);
94
- return /*#__PURE__*/React.isValidElement(result) ? /*#__PURE__*/React.cloneElement(result, {
178
+ return /*#__PURE__*/isValidElement(result) ? /*#__PURE__*/cloneElement(result, {
95
179
  key: key + index++
96
180
  }) : result;
97
181
  };
@@ -102,37 +186,38 @@ function prepareTranslationValues(values) {
102
186
  });
103
187
  return transformedValues;
104
188
  }
105
- function getMessagesOrError(locale, messages, namespace) {
106
- let onError = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : initializeConfig.defaultOnError;
189
+ function getMessagesOrError(locale, messages, namespace, onError = defaultOnError) {
107
190
  try {
108
191
  if (!messages) {
109
- throw new Error("No messages were configured on the provider." );
192
+ throw new Error(`No messages were configured on the provider.` );
110
193
  }
111
194
  const retrievedMessages = namespace ? resolvePath(locale, messages, namespace) : messages;
112
195
 
113
196
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
114
197
  if (!retrievedMessages) {
115
- throw new Error("No messages for namespace `".concat(namespace, "` found.") );
198
+ throw new Error(`No messages for namespace \`${namespace}\` found.` );
116
199
  }
117
200
  return retrievedMessages;
118
201
  } catch (error) {
119
- const intlError = new initializeConfig.IntlError(initializeConfig.IntlErrorCode.MISSING_MESSAGE, error.message);
202
+ const intlError = new IntlError(IntlErrorCode.MISSING_MESSAGE, error.message);
120
203
  onError(intlError);
121
204
  return intlError;
122
205
  }
123
206
  }
124
207
  function getPlainMessage(candidate, values) {
125
- if (values) return undefined;
126
- const unescapedMessage = candidate.replace(/'([{}])/gi, '$1');
208
+ {
209
+ // Keep fast path in development
210
+ if (values) return undefined;
127
211
 
128
- // Placeholders can be in the message if there are default values,
129
- // or if the user has forgotten to provide values. In the latter
130
- // case we need to compile the message to receive an error.
131
- const hasPlaceholders = /<|{/.test(unescapedMessage);
132
- if (!hasPlaceholders) {
133
- return unescapedMessage;
212
+ // Despite potentially no values being available, there can still be
213
+ // placeholders in the message if the user has forgotten to provide
214
+ // values. In this case we compile the message to receive an error.
215
+ const unescapedMessage = candidate.replace(/'([{}])/gi, '$1');
216
+ const hasPlaceholders = /<|{/.test(unescapedMessage);
217
+ if (!hasPlaceholders) {
218
+ return unescapedMessage;
219
+ }
134
220
  }
135
- return undefined;
136
221
  }
137
222
  function createBaseTranslator(config) {
138
223
  const messagesOrError = getMessagesOrError(config.locale, config.messages, config.namespace, config.onError);
@@ -141,22 +226,20 @@ function createBaseTranslator(config) {
141
226
  messagesOrError
142
227
  });
143
228
  }
144
- function createBaseTranslatorImpl(_ref) {
145
- let {
146
- cache,
147
- defaultTranslationValues,
148
- formats: globalFormats,
149
- formatters,
150
- getMessageFallback = initializeConfig.defaultGetMessageFallback,
151
- locale,
152
- messagesOrError,
153
- namespace,
154
- onError,
155
- timeZone
156
- } = _ref;
157
- const hasMessagesError = messagesOrError instanceof initializeConfig.IntlError;
229
+ function createBaseTranslatorImpl({
230
+ cache,
231
+ formats: globalFormats,
232
+ formatters,
233
+ getMessageFallback = defaultGetMessageFallback,
234
+ locale,
235
+ messagesOrError,
236
+ namespace,
237
+ onError,
238
+ timeZone
239
+ }) {
240
+ const hasMessagesError = messagesOrError instanceof IntlError;
158
241
  function getFallbackFromErrorAndNotify(key, code, message) {
159
- const error = new initializeConfig.IntlError(code, message);
242
+ const error = new IntlError(code, message);
160
243
  onError(error);
161
244
  return getMessageFallback({
162
245
  error,
@@ -181,19 +264,19 @@ function createBaseTranslatorImpl(_ref) {
181
264
  try {
182
265
  message = resolvePath(locale, messages, key, namespace);
183
266
  } catch (error) {
184
- return getFallbackFromErrorAndNotify(key, initializeConfig.IntlErrorCode.MISSING_MESSAGE, error.message);
267
+ return getFallbackFromErrorAndNotify(key, IntlErrorCode.MISSING_MESSAGE, error.message);
185
268
  }
186
269
  if (typeof message === 'object') {
187
270
  let code, errorMessage;
188
271
  if (Array.isArray(message)) {
189
- code = initializeConfig.IntlErrorCode.INVALID_MESSAGE;
272
+ code = IntlErrorCode.INVALID_MESSAGE;
190
273
  {
191
- errorMessage = "Message at `".concat(initializeConfig.joinPath(namespace, key), "` resolved to an array, but only strings are supported. See https://next-intl-docs.vercel.app/docs/usage/messages#arrays-of-messages");
274
+ errorMessage = `Message at \`${joinPath(namespace, key)}\` resolved to an array, but only strings are supported. See https://next-intl-docs.vercel.app/docs/usage/messages#arrays-of-messages`;
192
275
  }
193
276
  } else {
194
- code = initializeConfig.IntlErrorCode.INSUFFICIENT_PATH;
277
+ code = IntlErrorCode.INSUFFICIENT_PATH;
195
278
  {
196
- errorMessage = "Message at `".concat(initializeConfig.joinPath(namespace, key), "` resolved to an object, but only strings are supported. Use a `.` to retrieve nested messages. See https://next-intl-docs.vercel.app/docs/usage/messages#structuring-messages");
279
+ errorMessage = `Message at \`${joinPath(namespace, key)}\` resolved to an object, but only strings are supported. Use a \`.\` to retrieve nested messages. See https://next-intl-docs.vercel.app/docs/usage/messages#structuring-messages`;
197
280
  }
198
281
  }
199
282
  return getFallbackFromErrorAndNotify(key, code, errorMessage);
@@ -210,10 +293,7 @@ function createBaseTranslatorImpl(_ref) {
210
293
  formatters.getMessageFormat = createMessageFormatter(cache, formatters);
211
294
  }
212
295
  try {
213
- messageFormat = formatters.getMessageFormat(message, locale, convertFormatsToIntlMessageFormat({
214
- ...globalFormats,
215
- ...formats
216
- }, timeZone), {
296
+ messageFormat = formatters.getMessageFormat(message, locale, convertFormatsToIntlMessageFormat(globalFormats, formats, timeZone), {
217
297
  formatters: {
218
298
  ...formatters,
219
299
  getDateTimeFormat(locales, options) {
@@ -227,7 +307,7 @@ function createBaseTranslatorImpl(_ref) {
227
307
  });
228
308
  } catch (error) {
229
309
  const thrownError = error;
230
- return getFallbackFromErrorAndNotify(key, initializeConfig.IntlErrorCode.INVALID_MESSAGE, thrownError.message + ('originalMessage' in thrownError ? " (".concat(thrownError.originalMessage, ")") : '') );
310
+ return getFallbackFromErrorAndNotify(key, IntlErrorCode.INVALID_MESSAGE, thrownError.message + ('originalMessage' in thrownError ? ` (${thrownError.originalMessage})` : '') );
231
311
  }
232
312
  try {
233
313
  const formattedMessage = messageFormat.format(
@@ -235,20 +315,17 @@ function createBaseTranslatorImpl(_ref) {
235
315
  // for rich text elements since a recent minor update. This
236
316
  // needs to be evaluated in detail, possibly also in regards
237
317
  // to be able to format to parts.
238
- prepareTranslationValues({
239
- ...defaultTranslationValues,
240
- ...values
241
- }));
318
+ values ? prepareTranslationValues(values) : values);
242
319
  if (formattedMessage == null) {
243
- throw new Error("Unable to format `".concat(key, "` in ").concat(namespace ? "namespace `".concat(namespace, "`") : 'messages') );
320
+ throw new Error(`Unable to format \`${key}\` in ${namespace ? `namespace \`${namespace}\`` : 'messages'}` );
244
321
  }
245
322
 
246
323
  // Limit the function signature to return strings or React elements
247
- return /*#__PURE__*/React.isValidElement(formattedMessage) ||
324
+ return /*#__PURE__*/isValidElement(formattedMessage) ||
248
325
  // Arrays of React elements
249
326
  Array.isArray(formattedMessage) || typeof formattedMessage === 'string' ? formattedMessage : String(formattedMessage);
250
327
  } catch (error) {
251
- return getFallbackFromErrorAndNotify(key, initializeConfig.IntlErrorCode.FORMATTING_ERROR, error.message);
328
+ return getFallbackFromErrorAndNotify(key, IntlErrorCode.FORMATTING_ERROR, error.message);
252
329
  }
253
330
  }
254
331
  function translateFn(/** Use a dot to indicate a level of nesting (e.g. `namespace.nestedLabel`). */
@@ -257,7 +334,7 @@ function createBaseTranslatorImpl(_ref) {
257
334
  formats) {
258
335
  const result = translateBaseFn(key, values, formats);
259
336
  if (typeof result !== 'string') {
260
- return getFallbackFromErrorAndNotify(key, initializeConfig.IntlErrorCode.INVALID_MESSAGE, "The message `".concat(key, "` in ").concat(namespace ? "namespace `".concat(namespace, "`") : 'messages', " didn't resolve to a string. If you want to format rich text, use `t.rich` instead.") );
337
+ return getFallbackFromErrorAndNotify(key, IntlErrorCode.INVALID_MESSAGE, `The message \`${key}\` in ${namespace ? `namespace \`${namespace}\`` : 'messages'} didn't resolve to a string. If you want to format rich text, use \`t.rich\` instead.` );
261
338
  }
262
339
  return result;
263
340
  }
@@ -269,13 +346,8 @@ function createBaseTranslatorImpl(_ref) {
269
346
  // @ts-expect-error -- `MarkupTranslationValues` is practically a sub type
270
347
  // of `RichTranslationValues` but TypeScript isn't smart enough here.
271
348
  values, formats);
272
-
273
- // When only string chunks are provided to the parser, only
274
- // strings should be returned here. Note that we need a runtime
275
- // check for this since rich text values could be accidentally
276
- // inherited from `defaultTranslationValues`.
277
349
  if (typeof result !== 'string') {
278
- const error = new initializeConfig.IntlError(initializeConfig.IntlErrorCode.FORMATTING_ERROR, "`t.markup` only accepts functions for formatting that receive and return strings.\n\nE.g. t.markup('markup', {b: (chunks) => `<b>${chunks}</b>`})" );
350
+ const error = new IntlError(IntlErrorCode.FORMATTING_ERROR, "`t.markup` only accepts functions for formatting that receive and return strings.\n\nE.g. t.markup('markup', {b: (chunks) => `<b>${chunks}</b>`})");
279
351
  onError(error);
280
352
  return getMessageFallback({
281
353
  error,
@@ -298,7 +370,7 @@ function createBaseTranslatorImpl(_ref) {
298
370
  try {
299
371
  return resolvePath(locale, messages, key, namespace);
300
372
  } catch (error) {
301
- return getFallbackFromErrorAndNotify(key, initializeConfig.IntlErrorCode.MISSING_MESSAGE, error.message);
373
+ return getFallbackFromErrorAndNotify(key, IntlErrorCode.MISSING_MESSAGE, error.message);
302
374
  }
303
375
  };
304
376
  translateFn.has = key => {
@@ -308,7 +380,7 @@ function createBaseTranslatorImpl(_ref) {
308
380
  try {
309
381
  resolvePath(locale, messagesOrError, key, namespace);
310
382
  return true;
311
- } catch (_unused) {
383
+ } catch {
312
384
  return false;
313
385
  }
314
386
  };
@@ -371,26 +443,24 @@ function calculateRelativeTimeValue(seconds, unit) {
371
443
  // will include fractions like '2.1 hours ago'.
372
444
  return Math.round(seconds / UNIT_SECONDS[unit]);
373
445
  }
374
- function createFormatter(_ref) {
375
- let {
376
- _cache: cache = initializeConfig.createCache(),
377
- _formatters: formatters = initializeConfig.createIntlFormatters(cache),
446
+ function createFormatter(props) {
447
+ const {
448
+ _cache: cache = createCache(),
449
+ _formatters: formatters = createIntlFormatters(cache),
378
450
  formats,
379
451
  locale,
380
- now: globalNow,
381
- onError = initializeConfig.defaultOnError,
452
+ onError = defaultOnError,
382
453
  timeZone: globalTimeZone
383
- } = _ref;
454
+ } = props;
384
455
  function applyTimeZone(options) {
385
- var _options;
386
- if (!((_options = options) !== null && _options !== void 0 && _options.timeZone)) {
456
+ if (!options?.timeZone) {
387
457
  if (globalTimeZone) {
388
458
  options = {
389
459
  ...options,
390
460
  timeZone: globalTimeZone
391
461
  };
392
462
  } else {
393
- onError(new initializeConfig.IntlError(initializeConfig.IntlErrorCode.ENVIRONMENT_FALLBACK, "The `timeZone` parameter wasn't provided and there is no global default configured. Consider adding a global default to avoid markup mismatches caused by environment differences. Learn more: https://next-intl-docs.vercel.app/docs/configuration#time-zone" ));
463
+ onError(new IntlError(IntlErrorCode.ENVIRONMENT_FALLBACK, `The \`timeZone\` parameter wasn't provided and there is no global default configured. Consider adding a global default to avoid markup mismatches caused by environment differences. Learn more: https://next-intl-docs.vercel.app/docs/configuration#time-zone` ));
394
464
  }
395
465
  }
396
466
  return options;
@@ -399,9 +469,9 @@ function createFormatter(_ref) {
399
469
  let options;
400
470
  if (typeof formatOrOptions === 'string') {
401
471
  const formatName = formatOrOptions;
402
- options = typeFormats === null || typeFormats === void 0 ? void 0 : typeFormats[formatName];
472
+ options = typeFormats?.[formatName];
403
473
  if (!options) {
404
- const error = new initializeConfig.IntlError(initializeConfig.IntlErrorCode.MISSING_FORMAT, "Format `".concat(formatName, "` is not available. You can configure it on the provider or provide custom options.") );
474
+ const error = new IntlError(IntlErrorCode.MISSING_FORMAT, `Format \`${formatName}\` is not available. You can configure it on the provider or provide custom options.` );
405
475
  onError(error);
406
476
  throw error;
407
477
  }
@@ -414,13 +484,13 @@ function createFormatter(_ref) {
414
484
  let options;
415
485
  try {
416
486
  options = resolveFormatOrOptions(typeFormats, formatOrOptions);
417
- } catch (_unused) {
487
+ } catch {
418
488
  return getFallback();
419
489
  }
420
490
  try {
421
491
  return formatter(options);
422
492
  } catch (error) {
423
- onError(new initializeConfig.IntlError(initializeConfig.IntlErrorCode.FORMATTING_ERROR, error.message));
493
+ onError(new IntlError(IntlErrorCode.FORMATTING_ERROR, error.message));
424
494
  return getFallback();
425
495
  }
426
496
  }
@@ -429,7 +499,7 @@ function createFormatter(_ref) {
429
499
  /** If a time zone is supplied, the `value` is converted to that time zone.
430
500
  * Otherwise the user time zone will be used. */
431
501
  formatOrOptions) {
432
- return getFormattedValue(formatOrOptions, formats === null || formats === void 0 ? void 0 : formats.dateTime, options => {
502
+ return getFormattedValue(formatOrOptions, formats?.dateTime, options => {
433
503
  options = applyTimeZone(options);
434
504
  return formatters.getDateTimeFormat(locale, options).format(value);
435
505
  }, () => String(value));
@@ -440,24 +510,26 @@ function createFormatter(_ref) {
440
510
  /** If a time zone is supplied, the values are converted to that time zone.
441
511
  * Otherwise the user time zone will be used. */
442
512
  formatOrOptions) {
443
- return getFormattedValue(formatOrOptions, formats === null || formats === void 0 ? void 0 : formats.dateTime, options => {
513
+ return getFormattedValue(formatOrOptions, formats?.dateTime, options => {
444
514
  options = applyTimeZone(options);
445
515
  return formatters.getDateTimeFormat(locale, options).formatRange(start, end);
446
516
  }, () => [dateTime(start), dateTime(end)].join(' – '));
447
517
  }
448
518
  function number(value, formatOrOptions) {
449
- return getFormattedValue(formatOrOptions, formats === null || formats === void 0 ? void 0 : formats.number, options => formatters.getNumberFormat(locale, options).format(value), () => String(value));
519
+ return getFormattedValue(formatOrOptions, formats?.number, options => formatters.getNumberFormat(locale, options).format(value), () => String(value));
450
520
  }
451
521
  function getGlobalNow() {
452
- if (globalNow) {
453
- return globalNow;
522
+ // Only read when necessary to avoid triggering a `dynamicIO` error
523
+ // unnecessarily (`now` is only needed for `format.relativeTime`)
524
+ if (props.now) {
525
+ return props.now;
454
526
  } else {
455
- onError(new initializeConfig.IntlError(initializeConfig.IntlErrorCode.ENVIRONMENT_FALLBACK, "The `now` parameter wasn't provided and there is no global default configured. Consider adding a global default to avoid markup mismatches caused by environment differences. Learn more: https://next-intl-docs.vercel.app/docs/configuration#now" ));
527
+ onError(new IntlError(IntlErrorCode.ENVIRONMENT_FALLBACK, `The \`now\` parameter wasn't provided and there is no global default configured, therefore the current time will be used as a fallback. To avoid markup mismatches caused by environment differences, either provide the \`now\` parameter or configure a global default. Learn more: https://next-intl-docs.vercel.app/docs/configuration#now` ));
456
528
  return new Date();
457
529
  }
458
530
  }
459
531
  function relativeTime(/** The date time that needs to be formatted. */
460
- date, /** The reference point in time to which `date` will be formatted in relation to. */
532
+ date, /** The reference point in time to which `date` will be formatted in relation to. If this value is absent, a globally configured `now` value or alternatively the current time will be used. */
461
533
  nowOrOptions) {
462
534
  try {
463
535
  let nowDate, unit;
@@ -496,7 +568,7 @@ function createFormatter(_ref) {
496
568
  const value = calculateRelativeTimeValue(seconds, unit);
497
569
  return formatters.getRelativeTimeFormat(locale, opts).format(value, unit);
498
570
  } catch (error) {
499
- onError(new initializeConfig.IntlError(initializeConfig.IntlErrorCode.FORMATTING_ERROR, error.message));
571
+ onError(new IntlError(IntlErrorCode.FORMATTING_ERROR, error.message));
500
572
  return String(date);
501
573
  }
502
574
  }
@@ -519,7 +591,7 @@ function createFormatter(_ref) {
519
591
  serializedValue.push(serializedItem);
520
592
  index++;
521
593
  }
522
- return getFormattedValue(formatOrOptions, formats === null || formats === void 0 ? void 0 : formats.list,
594
+ return getFormattedValue(formatOrOptions, formats?.list,
523
595
  // @ts-expect-error -- `richValues.size` is used to determine the return type, but TypeScript can't infer the meaning of this correctly
524
596
  options => {
525
597
  const result = formatters.getListFormat(locale, options).formatToParts(serializedValue).map(part => part.type === 'literal' ? part.value : richValues.get(part.value) || part.value);
@@ -539,6 +611,82 @@ function createFormatter(_ref) {
539
611
  };
540
612
  }
541
613
 
542
- exports.createBaseTranslator = createBaseTranslator;
543
- exports.createFormatter = createFormatter;
544
- exports.resolveNamespace = resolveNamespace;
614
+ function validateMessagesSegment(messages, invalidKeyLabels, parentPath) {
615
+ Object.entries(messages).forEach(([key, messageOrMessages]) => {
616
+ if (key.includes('.')) {
617
+ let keyLabel = key;
618
+ if (parentPath) keyLabel += ` (at ${parentPath})`;
619
+ invalidKeyLabels.push(keyLabel);
620
+ }
621
+
622
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
623
+ if (messageOrMessages != null && typeof messageOrMessages === 'object') {
624
+ validateMessagesSegment(messageOrMessages, invalidKeyLabels, joinPath(parentPath, key));
625
+ }
626
+ });
627
+ }
628
+ function validateMessages(messages, onError) {
629
+ const invalidKeyLabels = [];
630
+ validateMessagesSegment(messages, invalidKeyLabels);
631
+ if (invalidKeyLabels.length > 0) {
632
+ onError(new IntlError(IntlErrorCode.INVALID_KEY, `Namespace keys can not contain the character "." as this is used to express nesting. Please remove it or replace it with another character.
633
+
634
+ Invalid ${invalidKeyLabels.length === 1 ? 'key' : 'keys'}: ${invalidKeyLabels.join(', ')}
635
+
636
+ If you're migrating from a flat structure, you can convert your messages as follows:
637
+
638
+ import {set} from "lodash";
639
+
640
+ const input = {
641
+ "one.one": "1.1",
642
+ "one.two": "1.2",
643
+ "two.one.one": "2.1.1"
644
+ };
645
+
646
+ const output = Object.entries(input).reduce(
647
+ (acc, [key, value]) => set(acc, key, value),
648
+ {}
649
+ );
650
+
651
+ // Output:
652
+ //
653
+ // {
654
+ // "one": {
655
+ // "one": "1.1",
656
+ // "two": "1.2"
657
+ // },
658
+ // "two": {
659
+ // "one": {
660
+ // "one": "2.1.1"
661
+ // }
662
+ // }
663
+ // }
664
+ ` ));
665
+ }
666
+ }
667
+
668
+ /**
669
+ * Enhances the incoming props with defaults.
670
+ */
671
+ function initializeConfig({
672
+ getMessageFallback,
673
+ messages,
674
+ onError,
675
+ ...rest
676
+ }) {
677
+ const finalOnError = onError || defaultOnError;
678
+ const finalGetMessageFallback = getMessageFallback || defaultGetMessageFallback;
679
+ {
680
+ if (messages) {
681
+ validateMessages(messages, finalOnError);
682
+ }
683
+ }
684
+ return {
685
+ ...rest,
686
+ messages,
687
+ onError: finalOnError,
688
+ getMessageFallback: finalGetMessageFallback
689
+ };
690
+ }
691
+
692
+ export { IntlError as I, IntlErrorCode as a, createIntlFormatters as b, createFormatter as c, createCache as d, createBaseTranslator as e, defaultGetMessageFallback as f, defaultOnError as g, initializeConfig as i, resolveNamespace as r };