use-intl 0.0.0-canary-5bbd7ad56b530e283b07cff950de61d6af81f00c
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/LICENSE +21 -0
- package/README.md +83 -0
- package/_IntlProvider.d.ts +1 -0
- package/_useLocale.d.ts +1 -0
- package/core.d.ts +1 -0
- package/dist/_IntlProvider.js +7 -0
- package/dist/_useLocale.js +7 -0
- package/dist/core.js +7 -0
- package/dist/development/IntlContext-BKfsnzBx.js +7 -0
- package/dist/development/_IntlProvider.js +61 -0
- package/dist/development/_useLocale-0Rl9uR82.js +19 -0
- package/dist/development/_useLocale.js +11 -0
- package/dist/development/core.js +69 -0
- package/dist/development/createFormatter-TZTkYRKI.js +542 -0
- package/dist/development/index.js +31 -0
- package/dist/development/initializeConfig-o7L_y07P.js +185 -0
- package/dist/development/react.js +151 -0
- package/dist/esm/IntlContext-DoS4CDM3.js +1 -0
- package/dist/esm/_IntlProvider.js +1 -0
- package/dist/esm/_useLocale-v-ZT5JoE.js +1 -0
- package/dist/esm/_useLocale.js +1 -0
- package/dist/esm/core.js +1 -0
- package/dist/esm/createFormatter-D1WNHqdE.js +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/initializeConfig-D2A8plWf.js +1 -0
- package/dist/esm/react.js +1 -0
- package/dist/index.js +7 -0
- package/dist/production/IntlContext-DcFt0tgW.js +1 -0
- package/dist/production/_IntlProvider.js +1 -0
- package/dist/production/_useLocale-CpTrqBDt.js +1 -0
- package/dist/production/_useLocale.js +1 -0
- package/dist/production/core.js +1 -0
- package/dist/production/createFormatter-CTr0qKAI.js +1 -0
- package/dist/production/index.js +1 -0
- package/dist/production/initializeConfig-AbYTngyP.js +1 -0
- package/dist/production/react.js +1 -0
- package/dist/react.js +7 -0
- package/dist/types/src/_IntlProvider.d.ts +1 -0
- package/dist/types/src/_useLocale.d.ts +1 -0
- package/dist/types/src/core/AbstractIntlMessages.d.ts +9 -0
- package/dist/types/src/core/DateTimeFormatOptions.d.ts +73 -0
- package/dist/types/src/core/Formats.d.ts +8 -0
- package/dist/types/src/core/IntlConfig.d.ts +58 -0
- package/dist/types/src/core/IntlError.d.ts +14 -0
- package/dist/types/src/core/NumberFormatOptions.d.ts +3 -0
- package/dist/types/src/core/RelativeTimeFormatOptions.d.ts +7 -0
- package/dist/types/src/core/TimeZone.d.ts +2 -0
- package/dist/types/src/core/TranslationValues.d.ts +6 -0
- package/dist/types/src/core/convertFormatsToIntlMessageFormat.d.ts +11 -0
- package/dist/types/src/core/createBaseTranslator.d.ts +24 -0
- package/dist/types/src/core/createFormatter.d.ts +27 -0
- package/dist/types/src/core/createFormatter.test.d.ts +1 -0
- package/dist/types/src/core/createTranslator.d.ts +71 -0
- package/dist/types/src/core/createTranslator.test.d.ts +1 -0
- package/dist/types/src/core/createTranslatorImpl.d.ts +17 -0
- package/dist/types/src/core/defaults.d.ts +11 -0
- package/dist/types/src/core/formatters.d.ts +25 -0
- package/dist/types/src/core/index.d.ts +16 -0
- package/dist/types/src/core/initializeConfig.d.ts +13 -0
- package/dist/types/src/core/joinPath.d.ts +1 -0
- package/dist/types/src/core/resolveNamespace.d.ts +5 -0
- package/dist/types/src/core/utils/MessageKeys.d.ts +5 -0
- package/dist/types/src/core/utils/NamespaceKeys.d.ts +5 -0
- package/dist/types/src/core/utils/NestedKeyOf.d.ts +4 -0
- package/dist/types/src/core/utils/NestedValueOf.d.ts +2 -0
- package/dist/types/src/core/validateMessages.d.ts +3 -0
- package/dist/types/src/core.d.ts +1 -0
- package/dist/types/src/index.d.ts +2 -0
- package/dist/types/src/react/IntlContext.d.ts +8 -0
- package/dist/types/src/react/IntlProvider.d.ts +7 -0
- package/dist/types/src/react/IntlProvider.test.d.ts +1 -0
- package/dist/types/src/react/index.d.ts +7 -0
- package/dist/types/src/react/index.test.d.ts +1 -0
- package/dist/types/src/react/useFormatter.d.ts +2 -0
- package/dist/types/src/react/useFormatter.test.d.ts +1 -0
- package/dist/types/src/react/useIntlContext.d.ts +2 -0
- package/dist/types/src/react/useLocale.d.ts +1 -0
- package/dist/types/src/react/useLocale.test.d.ts +1 -0
- package/dist/types/src/react/useMessages.d.ts +2 -0
- package/dist/types/src/react/useMessages.test.d.ts +1 -0
- package/dist/types/src/react/useNow.d.ts +23 -0
- package/dist/types/src/react/useNow.test.d.ts +1 -0
- package/dist/types/src/react/useTimeZone.d.ts +1 -0
- package/dist/types/src/react/useTimeZone.test.d.ts +1 -0
- package/dist/types/src/react/useTranslations.d.ts +62 -0
- package/dist/types/src/react/useTranslations.test.d.ts +1 -0
- package/dist/types/src/react/useTranslationsImpl.d.ts +9 -0
- package/dist/types/src/react.d.ts +1 -0
- package/dist/types/test/setup.d.ts +1 -0
- package/package.json +73 -0
- package/react.d.ts +1 -0
|
@@ -0,0 +1,542 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var IntlMessageFormat = require('intl-messageformat');
|
|
4
|
+
var React = require('react');
|
|
5
|
+
var initializeConfig = require('./initializeConfig-o7L_y07P.js');
|
|
6
|
+
|
|
7
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
|
+
|
|
9
|
+
var IntlMessageFormat__default = /*#__PURE__*/_interopDefault(IntlMessageFormat);
|
|
10
|
+
|
|
11
|
+
// eslint-disable-next-line import/no-named-as-default -- False positive
|
|
12
|
+
function setTimeZoneInFormats(formats, timeZone) {
|
|
13
|
+
if (!formats) return formats;
|
|
14
|
+
|
|
15
|
+
// The only way to set a time zone with `intl-messageformat` is to merge it into the formats
|
|
16
|
+
// https://github.com/formatjs/formatjs/blob/8256c5271505cf2606e48e3c97ecdd16ede4f1b5/packages/intl/src/message.ts#L15
|
|
17
|
+
return Object.keys(formats).reduce((acc, key) => {
|
|
18
|
+
acc[key] = {
|
|
19
|
+
timeZone,
|
|
20
|
+
...formats[key]
|
|
21
|
+
};
|
|
22
|
+
return acc;
|
|
23
|
+
}, {});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* `intl-messageformat` uses separate keys for `date` and `time`, but there's
|
|
28
|
+
* only one native API: `Intl.DateTimeFormat`. Additionally you might want to
|
|
29
|
+
* include both a time and a date in a value, therefore the separation doesn't
|
|
30
|
+
* seem so useful. We offer a single `dateTime` namespace instead, but we have
|
|
31
|
+
* to convert the format before `intl-messageformat` can be used.
|
|
32
|
+
*/
|
|
33
|
+
function convertFormatsToIntlMessageFormat(formats, timeZone) {
|
|
34
|
+
const formatsWithTimeZone = timeZone ? {
|
|
35
|
+
...formats,
|
|
36
|
+
dateTime: setTimeZoneInFormats(formats.dateTime, timeZone)
|
|
37
|
+
} : formats;
|
|
38
|
+
const mfDateDefaults = IntlMessageFormat__default.default.formats.date;
|
|
39
|
+
const defaultDateFormats = timeZone ? setTimeZoneInFormats(mfDateDefaults, timeZone) : mfDateDefaults;
|
|
40
|
+
const mfTimeDefaults = IntlMessageFormat__default.default.formats.time;
|
|
41
|
+
const defaultTimeFormats = timeZone ? setTimeZoneInFormats(mfTimeDefaults, timeZone) : mfTimeDefaults;
|
|
42
|
+
return {
|
|
43
|
+
...formatsWithTimeZone,
|
|
44
|
+
date: {
|
|
45
|
+
...defaultDateFormats,
|
|
46
|
+
...(formatsWithTimeZone === null || formatsWithTimeZone === void 0 ? void 0 : formatsWithTimeZone.dateTime)
|
|
47
|
+
},
|
|
48
|
+
time: {
|
|
49
|
+
...defaultTimeFormats,
|
|
50
|
+
...(formatsWithTimeZone === null || formatsWithTimeZone === void 0 ? void 0 : formatsWithTimeZone.dateTime)
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// eslint-disable-next-line import/no-named-as-default -- False positive
|
|
56
|
+
// Placed here for improved tree shaking. Somehow when this is placed in
|
|
57
|
+
// `formatters.tsx`, then it can't be shaken off from `next-intl`.
|
|
58
|
+
function createMessageFormatter(cache, intlFormatters) {
|
|
59
|
+
const getMessageFormat = initializeConfig.memoFn(function () {
|
|
60
|
+
return new IntlMessageFormat__default.default(arguments.length <= 0 ? undefined : arguments[0], arguments.length <= 1 ? undefined : arguments[1], arguments.length <= 2 ? undefined : arguments[2], {
|
|
61
|
+
formatters: intlFormatters,
|
|
62
|
+
...(arguments.length <= 3 ? undefined : arguments[3])
|
|
63
|
+
});
|
|
64
|
+
}, cache.message);
|
|
65
|
+
return getMessageFormat;
|
|
66
|
+
}
|
|
67
|
+
function resolvePath(locale, messages, key, namespace) {
|
|
68
|
+
const fullKey = initializeConfig.joinPath(namespace, key);
|
|
69
|
+
if (!messages) {
|
|
70
|
+
throw new Error("No messages available at `".concat(namespace, "`.") );
|
|
71
|
+
}
|
|
72
|
+
let message = messages;
|
|
73
|
+
key.split('.').forEach(part => {
|
|
74
|
+
const next = message[part];
|
|
75
|
+
if (part == null || next == null) {
|
|
76
|
+
throw new Error("Could not resolve `".concat(fullKey, "` in messages for locale `").concat(locale, "`.") );
|
|
77
|
+
}
|
|
78
|
+
message = next;
|
|
79
|
+
});
|
|
80
|
+
return message;
|
|
81
|
+
}
|
|
82
|
+
function prepareTranslationValues(values) {
|
|
83
|
+
if (Object.keys(values).length === 0) return undefined;
|
|
84
|
+
|
|
85
|
+
// Workaround for https://github.com/formatjs/formatjs/issues/1467
|
|
86
|
+
const transformedValues = {};
|
|
87
|
+
Object.keys(values).forEach(key => {
|
|
88
|
+
let index = 0;
|
|
89
|
+
const value = values[key];
|
|
90
|
+
let transformed;
|
|
91
|
+
if (typeof value === 'function') {
|
|
92
|
+
transformed = chunks => {
|
|
93
|
+
const result = value(chunks);
|
|
94
|
+
return /*#__PURE__*/React.isValidElement(result) ? /*#__PURE__*/React.cloneElement(result, {
|
|
95
|
+
key: key + index++
|
|
96
|
+
}) : result;
|
|
97
|
+
};
|
|
98
|
+
} else {
|
|
99
|
+
transformed = value;
|
|
100
|
+
}
|
|
101
|
+
transformedValues[key] = transformed;
|
|
102
|
+
});
|
|
103
|
+
return transformedValues;
|
|
104
|
+
}
|
|
105
|
+
function getMessagesOrError(locale, messages, namespace) {
|
|
106
|
+
let onError = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : initializeConfig.defaultOnError;
|
|
107
|
+
try {
|
|
108
|
+
if (!messages) {
|
|
109
|
+
throw new Error("No messages were configured on the provider." );
|
|
110
|
+
}
|
|
111
|
+
const retrievedMessages = namespace ? resolvePath(locale, messages, namespace) : messages;
|
|
112
|
+
if (!retrievedMessages) {
|
|
113
|
+
throw new Error("No messages for namespace `".concat(namespace, "` found.") );
|
|
114
|
+
}
|
|
115
|
+
return retrievedMessages;
|
|
116
|
+
} catch (error) {
|
|
117
|
+
const intlError = new initializeConfig.IntlError(initializeConfig.IntlErrorCode.MISSING_MESSAGE, error.message);
|
|
118
|
+
onError(intlError);
|
|
119
|
+
return intlError;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function getPlainMessage(candidate, values) {
|
|
123
|
+
if (values) return undefined;
|
|
124
|
+
const unescapedMessage = candidate.replace(/'([{}])/gi, '$1');
|
|
125
|
+
|
|
126
|
+
// Placeholders can be in the message if there are default values,
|
|
127
|
+
// or if the user has forgotten to provide values. In the latter
|
|
128
|
+
// case we need to compile the message to receive an error.
|
|
129
|
+
const hasPlaceholders = /<|{/.test(unescapedMessage);
|
|
130
|
+
if (!hasPlaceholders) {
|
|
131
|
+
return unescapedMessage;
|
|
132
|
+
}
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
function createBaseTranslator(config) {
|
|
136
|
+
const messagesOrError = getMessagesOrError(config.locale, config.messages, config.namespace, config.onError);
|
|
137
|
+
return createBaseTranslatorImpl({
|
|
138
|
+
...config,
|
|
139
|
+
messagesOrError
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
function createBaseTranslatorImpl(_ref) {
|
|
143
|
+
let {
|
|
144
|
+
cache,
|
|
145
|
+
defaultTranslationValues,
|
|
146
|
+
formats: globalFormats,
|
|
147
|
+
formatters,
|
|
148
|
+
getMessageFallback = initializeConfig.defaultGetMessageFallback,
|
|
149
|
+
locale,
|
|
150
|
+
messagesOrError,
|
|
151
|
+
namespace,
|
|
152
|
+
onError,
|
|
153
|
+
timeZone
|
|
154
|
+
} = _ref;
|
|
155
|
+
const hasMessagesError = messagesOrError instanceof initializeConfig.IntlError;
|
|
156
|
+
function getFallbackFromErrorAndNotify(key, code, message) {
|
|
157
|
+
const error = new initializeConfig.IntlError(code, message);
|
|
158
|
+
onError(error);
|
|
159
|
+
return getMessageFallback({
|
|
160
|
+
error,
|
|
161
|
+
key,
|
|
162
|
+
namespace
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
function translateBaseFn( /** Use a dot to indicate a level of nesting (e.g. `namespace.nestedLabel`). */
|
|
166
|
+
key, /** Key value pairs for values to interpolate into the message. */
|
|
167
|
+
values, /** Provide custom formats for numbers, dates and times. */
|
|
168
|
+
formats) {
|
|
169
|
+
if (hasMessagesError) {
|
|
170
|
+
// We have already warned about this during render
|
|
171
|
+
return getMessageFallback({
|
|
172
|
+
error: messagesOrError,
|
|
173
|
+
key,
|
|
174
|
+
namespace
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
const messages = messagesOrError;
|
|
178
|
+
let message;
|
|
179
|
+
try {
|
|
180
|
+
message = resolvePath(locale, messages, key, namespace);
|
|
181
|
+
} catch (error) {
|
|
182
|
+
return getFallbackFromErrorAndNotify(key, initializeConfig.IntlErrorCode.MISSING_MESSAGE, error.message);
|
|
183
|
+
}
|
|
184
|
+
if (typeof message === 'object') {
|
|
185
|
+
let code, errorMessage;
|
|
186
|
+
if (Array.isArray(message)) {
|
|
187
|
+
code = initializeConfig.IntlErrorCode.INVALID_MESSAGE;
|
|
188
|
+
{
|
|
189
|
+
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");
|
|
190
|
+
}
|
|
191
|
+
} else {
|
|
192
|
+
code = initializeConfig.IntlErrorCode.INSUFFICIENT_PATH;
|
|
193
|
+
{
|
|
194
|
+
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");
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return getFallbackFromErrorAndNotify(key, code, errorMessage);
|
|
198
|
+
}
|
|
199
|
+
let messageFormat;
|
|
200
|
+
|
|
201
|
+
// Hot path that avoids creating an `IntlMessageFormat` instance
|
|
202
|
+
const plainMessage = getPlainMessage(message, values);
|
|
203
|
+
if (plainMessage) return plainMessage;
|
|
204
|
+
|
|
205
|
+
// Lazy init the message formatter for better tree
|
|
206
|
+
// shaking in case message formatting is not used.
|
|
207
|
+
if (!formatters.getMessageFormat) {
|
|
208
|
+
formatters.getMessageFormat = createMessageFormatter(cache, formatters);
|
|
209
|
+
}
|
|
210
|
+
try {
|
|
211
|
+
messageFormat = formatters.getMessageFormat(message, locale, convertFormatsToIntlMessageFormat({
|
|
212
|
+
...globalFormats,
|
|
213
|
+
...formats
|
|
214
|
+
}, timeZone), {
|
|
215
|
+
formatters: {
|
|
216
|
+
...formatters,
|
|
217
|
+
getDateTimeFormat(locales, options) {
|
|
218
|
+
// Workaround for https://github.com/formatjs/formatjs/issues/4279
|
|
219
|
+
return formatters.getDateTimeFormat(locales, {
|
|
220
|
+
timeZone,
|
|
221
|
+
...options
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
} catch (error) {
|
|
227
|
+
const thrownError = error;
|
|
228
|
+
return getFallbackFromErrorAndNotify(key, initializeConfig.IntlErrorCode.INVALID_MESSAGE, thrownError.message + ('originalMessage' in thrownError ? " (".concat(thrownError.originalMessage, ")") : '') );
|
|
229
|
+
}
|
|
230
|
+
try {
|
|
231
|
+
const formattedMessage = messageFormat.format(
|
|
232
|
+
// @ts-expect-error `intl-messageformat` expects a different format
|
|
233
|
+
// for rich text elements since a recent minor update. This
|
|
234
|
+
// needs to be evaluated in detail, possibly also in regards
|
|
235
|
+
// to be able to format to parts.
|
|
236
|
+
prepareTranslationValues({
|
|
237
|
+
...defaultTranslationValues,
|
|
238
|
+
...values
|
|
239
|
+
}));
|
|
240
|
+
if (formattedMessage == null) {
|
|
241
|
+
throw new Error("Unable to format `".concat(key, "` in ").concat(namespace ? "namespace `".concat(namespace, "`") : 'messages') );
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Limit the function signature to return strings or React elements
|
|
245
|
+
return /*#__PURE__*/React.isValidElement(formattedMessage) ||
|
|
246
|
+
// Arrays of React elements
|
|
247
|
+
Array.isArray(formattedMessage) || typeof formattedMessage === 'string' ? formattedMessage : String(formattedMessage);
|
|
248
|
+
} catch (error) {
|
|
249
|
+
return getFallbackFromErrorAndNotify(key, initializeConfig.IntlErrorCode.FORMATTING_ERROR, error.message);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
function translateFn( /** Use a dot to indicate a level of nesting (e.g. `namespace.nestedLabel`). */
|
|
253
|
+
key, /** Key value pairs for values to interpolate into the message. */
|
|
254
|
+
values, /** Provide custom formats for numbers, dates and times. */
|
|
255
|
+
formats) {
|
|
256
|
+
const result = translateBaseFn(key, values, formats);
|
|
257
|
+
if (typeof result !== 'string') {
|
|
258
|
+
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.") );
|
|
259
|
+
}
|
|
260
|
+
return result;
|
|
261
|
+
}
|
|
262
|
+
translateFn.rich = translateBaseFn;
|
|
263
|
+
|
|
264
|
+
// Augment `translateBaseFn` to return plain strings
|
|
265
|
+
translateFn.markup = (key, values, formats) => {
|
|
266
|
+
const result = translateBaseFn(key,
|
|
267
|
+
// @ts-expect-error -- `MarkupTranslationValues` is practically a sub type
|
|
268
|
+
// of `RichTranslationValues` but TypeScript isn't smart enough here.
|
|
269
|
+
values, formats);
|
|
270
|
+
|
|
271
|
+
// When only string chunks are provided to the parser, only
|
|
272
|
+
// strings should be returned here. Note that we need a runtime
|
|
273
|
+
// check for this since rich text values could be accidentally
|
|
274
|
+
// inherited from `defaultTranslationValues`.
|
|
275
|
+
if (typeof result !== 'string') {
|
|
276
|
+
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>`})" );
|
|
277
|
+
onError(error);
|
|
278
|
+
return getMessageFallback({
|
|
279
|
+
error,
|
|
280
|
+
key,
|
|
281
|
+
namespace
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
return result;
|
|
285
|
+
};
|
|
286
|
+
translateFn.raw = key => {
|
|
287
|
+
if (hasMessagesError) {
|
|
288
|
+
// We have already warned about this during render
|
|
289
|
+
return getMessageFallback({
|
|
290
|
+
error: messagesOrError,
|
|
291
|
+
key,
|
|
292
|
+
namespace
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
const messages = messagesOrError;
|
|
296
|
+
try {
|
|
297
|
+
return resolvePath(locale, messages, key, namespace);
|
|
298
|
+
} catch (error) {
|
|
299
|
+
return getFallbackFromErrorAndNotify(key, initializeConfig.IntlErrorCode.MISSING_MESSAGE, error.message);
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
translateFn.has = key => {
|
|
303
|
+
if (hasMessagesError) {
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
try {
|
|
307
|
+
resolvePath(locale, messagesOrError, key, namespace);
|
|
308
|
+
return true;
|
|
309
|
+
} catch (_unused) {
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
return translateFn;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* For the strictly typed messages to work we have to wrap the namespace into
|
|
318
|
+
* a mandatory prefix. See https://stackoverflow.com/a/71529575/343045
|
|
319
|
+
*/
|
|
320
|
+
function resolveNamespace(namespace, namespacePrefix) {
|
|
321
|
+
return namespace === namespacePrefix ? undefined : namespace.slice((namespacePrefix + '.').length);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const SECOND = 1;
|
|
325
|
+
const MINUTE = SECOND * 60;
|
|
326
|
+
const HOUR = MINUTE * 60;
|
|
327
|
+
const DAY = HOUR * 24;
|
|
328
|
+
const WEEK = DAY * 7;
|
|
329
|
+
const MONTH = DAY * (365 / 12); // Approximation
|
|
330
|
+
const QUARTER = MONTH * 3;
|
|
331
|
+
const YEAR = DAY * 365;
|
|
332
|
+
const UNIT_SECONDS = {
|
|
333
|
+
second: SECOND,
|
|
334
|
+
seconds: SECOND,
|
|
335
|
+
minute: MINUTE,
|
|
336
|
+
minutes: MINUTE,
|
|
337
|
+
hour: HOUR,
|
|
338
|
+
hours: HOUR,
|
|
339
|
+
day: DAY,
|
|
340
|
+
days: DAY,
|
|
341
|
+
week: WEEK,
|
|
342
|
+
weeks: WEEK,
|
|
343
|
+
month: MONTH,
|
|
344
|
+
months: MONTH,
|
|
345
|
+
quarter: QUARTER,
|
|
346
|
+
quarters: QUARTER,
|
|
347
|
+
year: YEAR,
|
|
348
|
+
years: YEAR
|
|
349
|
+
};
|
|
350
|
+
function resolveRelativeTimeUnit(seconds) {
|
|
351
|
+
const absValue = Math.abs(seconds);
|
|
352
|
+
if (absValue < MINUTE) {
|
|
353
|
+
return 'second';
|
|
354
|
+
} else if (absValue < HOUR) {
|
|
355
|
+
return 'minute';
|
|
356
|
+
} else if (absValue < DAY) {
|
|
357
|
+
return 'hour';
|
|
358
|
+
} else if (absValue < WEEK) {
|
|
359
|
+
return 'day';
|
|
360
|
+
} else if (absValue < MONTH) {
|
|
361
|
+
return 'week';
|
|
362
|
+
} else if (absValue < YEAR) {
|
|
363
|
+
return 'month';
|
|
364
|
+
}
|
|
365
|
+
return 'year';
|
|
366
|
+
}
|
|
367
|
+
function calculateRelativeTimeValue(seconds, unit) {
|
|
368
|
+
// We have to round the resulting values, as `Intl.RelativeTimeFormat`
|
|
369
|
+
// will include fractions like '2.1 hours ago'.
|
|
370
|
+
return Math.round(seconds / UNIT_SECONDS[unit]);
|
|
371
|
+
}
|
|
372
|
+
function createFormatter(_ref) {
|
|
373
|
+
let {
|
|
374
|
+
_cache: cache = initializeConfig.createCache(),
|
|
375
|
+
_formatters: formatters = initializeConfig.createIntlFormatters(cache),
|
|
376
|
+
formats,
|
|
377
|
+
locale,
|
|
378
|
+
now: globalNow,
|
|
379
|
+
onError = initializeConfig.defaultOnError,
|
|
380
|
+
timeZone: globalTimeZone
|
|
381
|
+
} = _ref;
|
|
382
|
+
function applyTimeZone(options) {
|
|
383
|
+
var _options;
|
|
384
|
+
if (!((_options = options) !== null && _options !== void 0 && _options.timeZone)) {
|
|
385
|
+
if (globalTimeZone) {
|
|
386
|
+
options = {
|
|
387
|
+
...options,
|
|
388
|
+
timeZone: globalTimeZone
|
|
389
|
+
};
|
|
390
|
+
} else {
|
|
391
|
+
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" ));
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return options;
|
|
395
|
+
}
|
|
396
|
+
function resolveFormatOrOptions(typeFormats, formatOrOptions) {
|
|
397
|
+
let options;
|
|
398
|
+
if (typeof formatOrOptions === 'string') {
|
|
399
|
+
const formatName = formatOrOptions;
|
|
400
|
+
options = typeFormats === null || typeFormats === void 0 ? void 0 : typeFormats[formatName];
|
|
401
|
+
if (!options) {
|
|
402
|
+
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.") );
|
|
403
|
+
onError(error);
|
|
404
|
+
throw error;
|
|
405
|
+
}
|
|
406
|
+
} else {
|
|
407
|
+
options = formatOrOptions;
|
|
408
|
+
}
|
|
409
|
+
return options;
|
|
410
|
+
}
|
|
411
|
+
function getFormattedValue(formatOrOptions, typeFormats, formatter, getFallback) {
|
|
412
|
+
let options;
|
|
413
|
+
try {
|
|
414
|
+
options = resolveFormatOrOptions(typeFormats, formatOrOptions);
|
|
415
|
+
} catch (error) {
|
|
416
|
+
return getFallback();
|
|
417
|
+
}
|
|
418
|
+
try {
|
|
419
|
+
return formatter(options);
|
|
420
|
+
} catch (error) {
|
|
421
|
+
onError(new initializeConfig.IntlError(initializeConfig.IntlErrorCode.FORMATTING_ERROR, error.message));
|
|
422
|
+
return getFallback();
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
function dateTime( /** If a number is supplied, this is interpreted as a UTC timestamp. */
|
|
426
|
+
value,
|
|
427
|
+
/** If a time zone is supplied, the `value` is converted to that time zone.
|
|
428
|
+
* Otherwise the user time zone will be used. */
|
|
429
|
+
formatOrOptions) {
|
|
430
|
+
return getFormattedValue(formatOrOptions, formats === null || formats === void 0 ? void 0 : formats.dateTime, options => {
|
|
431
|
+
options = applyTimeZone(options);
|
|
432
|
+
return formatters.getDateTimeFormat(locale, options).format(value);
|
|
433
|
+
}, () => String(value));
|
|
434
|
+
}
|
|
435
|
+
function dateTimeRange( /** If a number is supplied, this is interpreted as a UTC timestamp. */
|
|
436
|
+
start, /** If a number is supplied, this is interpreted as a UTC timestamp. */
|
|
437
|
+
end,
|
|
438
|
+
/** If a time zone is supplied, the values are converted to that time zone.
|
|
439
|
+
* Otherwise the user time zone will be used. */
|
|
440
|
+
formatOrOptions) {
|
|
441
|
+
return getFormattedValue(formatOrOptions, formats === null || formats === void 0 ? void 0 : formats.dateTime, options => {
|
|
442
|
+
options = applyTimeZone(options);
|
|
443
|
+
return formatters.getDateTimeFormat(locale, options).formatRange(start, end);
|
|
444
|
+
}, () => [dateTime(start), dateTime(end)].join(' – '));
|
|
445
|
+
}
|
|
446
|
+
function number(value, formatOrOptions) {
|
|
447
|
+
return getFormattedValue(formatOrOptions, formats === null || formats === void 0 ? void 0 : formats.number, options => formatters.getNumberFormat(locale, options).format(value), () => String(value));
|
|
448
|
+
}
|
|
449
|
+
function getGlobalNow() {
|
|
450
|
+
if (globalNow) {
|
|
451
|
+
return globalNow;
|
|
452
|
+
} else {
|
|
453
|
+
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" ));
|
|
454
|
+
return new Date();
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
function relativeTime( /** The date time that needs to be formatted. */
|
|
458
|
+
date, /** The reference point in time to which `date` will be formatted in relation to. */
|
|
459
|
+
nowOrOptions) {
|
|
460
|
+
try {
|
|
461
|
+
let nowDate, unit;
|
|
462
|
+
const opts = {};
|
|
463
|
+
if (nowOrOptions instanceof Date || typeof nowOrOptions === 'number') {
|
|
464
|
+
nowDate = new Date(nowOrOptions);
|
|
465
|
+
} else if (nowOrOptions) {
|
|
466
|
+
if (nowOrOptions.now != null) {
|
|
467
|
+
nowDate = new Date(nowOrOptions.now);
|
|
468
|
+
} else {
|
|
469
|
+
nowDate = getGlobalNow();
|
|
470
|
+
}
|
|
471
|
+
unit = nowOrOptions.unit;
|
|
472
|
+
opts.style = nowOrOptions.style;
|
|
473
|
+
// @ts-expect-error -- Types are slightly outdated
|
|
474
|
+
opts.numberingSystem = nowOrOptions.numberingSystem;
|
|
475
|
+
}
|
|
476
|
+
if (!nowDate) {
|
|
477
|
+
nowDate = getGlobalNow();
|
|
478
|
+
}
|
|
479
|
+
const dateDate = new Date(date);
|
|
480
|
+
const seconds = (dateDate.getTime() - nowDate.getTime()) / 1000;
|
|
481
|
+
if (!unit) {
|
|
482
|
+
unit = resolveRelativeTimeUnit(seconds);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// `numeric: 'auto'` can theoretically produce output like "yesterday",
|
|
486
|
+
// but it only works with integers. E.g. -1 day will produce "yesterday",
|
|
487
|
+
// but -1.1 days will produce "-1.1 days". Rounding before formatting is
|
|
488
|
+
// not desired, as the given dates might cross a threshold were the
|
|
489
|
+
// output isn't correct anymore. Example: 2024-01-08T23:00:00.000Z and
|
|
490
|
+
// 2024-01-08T01:00:00.000Z would produce "yesterday", which is not the
|
|
491
|
+
// case. By using `always` we can ensure correct output. The only exception
|
|
492
|
+
// is the formatting of times <1 second as "now".
|
|
493
|
+
opts.numeric = unit === 'second' ? 'auto' : 'always';
|
|
494
|
+
const value = calculateRelativeTimeValue(seconds, unit);
|
|
495
|
+
return formatters.getRelativeTimeFormat(locale, opts).format(value, unit);
|
|
496
|
+
} catch (error) {
|
|
497
|
+
onError(new initializeConfig.IntlError(initializeConfig.IntlErrorCode.FORMATTING_ERROR, error.message));
|
|
498
|
+
return String(date);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
function list(value, formatOrOptions) {
|
|
502
|
+
const serializedValue = [];
|
|
503
|
+
const richValues = new Map();
|
|
504
|
+
|
|
505
|
+
// `formatToParts` only accepts strings, therefore we have to temporarily
|
|
506
|
+
// replace React elements with a placeholder ID that can be used to retrieve
|
|
507
|
+
// the original value afterwards.
|
|
508
|
+
let index = 0;
|
|
509
|
+
for (const item of value) {
|
|
510
|
+
let serializedItem;
|
|
511
|
+
if (typeof item === 'object') {
|
|
512
|
+
serializedItem = String(index);
|
|
513
|
+
richValues.set(serializedItem, item);
|
|
514
|
+
} else {
|
|
515
|
+
serializedItem = String(item);
|
|
516
|
+
}
|
|
517
|
+
serializedValue.push(serializedItem);
|
|
518
|
+
index++;
|
|
519
|
+
}
|
|
520
|
+
return getFormattedValue(formatOrOptions, formats === null || formats === void 0 ? void 0 : formats.list,
|
|
521
|
+
// @ts-expect-error -- `richValues.size` is used to determine the return type, but TypeScript can't infer the meaning of this correctly
|
|
522
|
+
options => {
|
|
523
|
+
const result = formatters.getListFormat(locale, options).formatToParts(serializedValue).map(part => part.type === 'literal' ? part.value : richValues.get(part.value) || part.value);
|
|
524
|
+
if (richValues.size > 0) {
|
|
525
|
+
return result;
|
|
526
|
+
} else {
|
|
527
|
+
return result.join('');
|
|
528
|
+
}
|
|
529
|
+
}, () => String(value));
|
|
530
|
+
}
|
|
531
|
+
return {
|
|
532
|
+
dateTime,
|
|
533
|
+
number,
|
|
534
|
+
relativeTime,
|
|
535
|
+
list,
|
|
536
|
+
dateTimeRange
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
exports.createBaseTranslator = createBaseTranslator;
|
|
541
|
+
exports.createFormatter = createFormatter;
|
|
542
|
+
exports.resolveNamespace = resolveNamespace;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var initializeConfig = require('./initializeConfig-o7L_y07P.js');
|
|
6
|
+
var core = require('./core.js');
|
|
7
|
+
var createFormatter = require('./createFormatter-TZTkYRKI.js');
|
|
8
|
+
var _IntlProvider = require('./_IntlProvider.js');
|
|
9
|
+
var react = require('./react.js');
|
|
10
|
+
var _useLocale = require('./_useLocale-0Rl9uR82.js');
|
|
11
|
+
require('@formatjs/fast-memoize');
|
|
12
|
+
require('intl-messageformat');
|
|
13
|
+
require('react');
|
|
14
|
+
require('./IntlContext-BKfsnzBx.js');
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
exports.IntlError = initializeConfig.IntlError;
|
|
19
|
+
exports.IntlErrorCode = initializeConfig.IntlErrorCode;
|
|
20
|
+
exports._createCache = initializeConfig.createCache;
|
|
21
|
+
exports._createIntlFormatters = initializeConfig.createIntlFormatters;
|
|
22
|
+
exports.initializeConfig = initializeConfig.initializeConfig;
|
|
23
|
+
exports.createTranslator = core.createTranslator;
|
|
24
|
+
exports.createFormatter = createFormatter.createFormatter;
|
|
25
|
+
exports.IntlProvider = _IntlProvider.IntlProvider;
|
|
26
|
+
exports.useFormatter = react.useFormatter;
|
|
27
|
+
exports.useMessages = react.useMessages;
|
|
28
|
+
exports.useNow = react.useNow;
|
|
29
|
+
exports.useTimeZone = react.useTimeZone;
|
|
30
|
+
exports.useTranslations = react.useTranslations;
|
|
31
|
+
exports.useLocale = _useLocale.useLocale;
|