deploy: v0.12 fix 存档key名

This commit is contained in:
2026-06-24 03:09:02 +00:00
parent 7a08d49fe3
commit e0a5281119
58743 changed files with 7297269 additions and 39505 deletions
+74
View File
@@ -0,0 +1,74 @@
import { r as resolveNamespace, e as createBaseTranslator, f as defaultGetMessageFallback, b as createIntlFormatters, d as createCache, g as defaultOnError } from './initializeConfig-CIDVMS2E.js';
export { I as IntlError, a as IntlErrorCode, c as createFormatter, i as initializeConfig } from './initializeConfig-CIDVMS2E.js';
function createTranslatorImpl({
messages,
namespace,
...rest
}, namespacePrefix) {
// The `namespacePrefix` is part of the type system.
// See the comment in the function invocation.
messages = messages[namespacePrefix];
namespace = resolveNamespace(namespace, namespacePrefix);
return createBaseTranslator({
...rest,
messages,
namespace
});
}
// This type is slightly more loose than `AbstractIntlMessages`
// in order to avoid a type error.
/**
* @private Not intended for direct use.
*/
/**
* Translates messages from the given namespace by using the ICU syntax.
* See https://formatjs.io/docs/core-concepts/icu-syntax.
*
* If no namespace is provided, all available messages are returned.
* The namespace can also indicate nesting by using a dot
* (e.g. `namespace.Component`).
*/
function createTranslator({
_cache = createCache(),
_formatters = createIntlFormatters(_cache),
getMessageFallback = defaultGetMessageFallback,
messages,
namespace,
onError = defaultOnError,
...rest
}) {
// We have to wrap the actual function so the type inference for the optional
// namespace works correctly. See https://stackoverflow.com/a/71529575/343045
// The prefix ("!") is arbitrary.
// @ts-expect-error Use the explicit annotation instead
return createTranslatorImpl({
...rest,
onError,
cache: _cache,
formatters: _formatters,
getMessageFallback,
// @ts-expect-error `messages` is allowed to be `undefined` here and will be handled internally
messages: {
'!': messages
},
namespace: namespace ? `!.${namespace}` : '!'
}, '!');
}
/**
* Checks if a locale exists in a list of locales.
*
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale
*/
function hasLocale(locales, candidate) {
return locales.includes(candidate);
}
export { createCache as _createCache, createIntlFormatters as _createIntlFormatters, createTranslator, hasLocale };
+7
View File
@@ -0,0 +1,7 @@
export { I as IntlError, a as IntlErrorCode, d as _createCache, b as _createIntlFormatters, c as createFormatter, i as initializeConfig } from './initializeConfig-CIDVMS2E.js';
export { createTranslator, hasLocale } from './core.js';
export { IntlProvider, _useExtracted, useFormatter, useLocale, useMessages, useNow, useTimeZone, useTranslations } from './react.js';
+695
View File
@@ -0,0 +1,695 @@
import { IntlMessageFormat } from 'intl-messageformat';
import { isValidElement, cloneElement } from 'react';
import { memoize, strategies } from '@formatjs/fast-memoize';
class IntlError extends Error {
constructor(code, originalMessage) {
let message = code;
if (originalMessage) {
message += ': ' + originalMessage;
}
super(message);
this.code = code;
if (originalMessage) {
this.originalMessage = originalMessage;
}
}
}
var IntlErrorCode = /*#__PURE__*/function (IntlErrorCode) {
IntlErrorCode["MISSING_MESSAGE"] = "MISSING_MESSAGE";
IntlErrorCode["MISSING_FORMAT"] = "MISSING_FORMAT";
IntlErrorCode["ENVIRONMENT_FALLBACK"] = "ENVIRONMENT_FALLBACK";
IntlErrorCode["INSUFFICIENT_PATH"] = "INSUFFICIENT_PATH";
IntlErrorCode["INVALID_MESSAGE"] = "INVALID_MESSAGE";
IntlErrorCode["INVALID_KEY"] = "INVALID_KEY";
IntlErrorCode["FORMATTING_ERROR"] = "FORMATTING_ERROR";
return IntlErrorCode;
}(IntlErrorCode || {});
/**
* `intl-messageformat` uses separate keys for `date` and `time`, but there's
* only one native API: `Intl.DateTimeFormat`. Additionally you might want to
* include both a time and a date in a value, therefore the separation doesn't
* seem so useful. We offer a single `dateTime` namespace instead, but we have
* to convert the format before `intl-messageformat` can be used.
*/
function convertFormatsToIntlMessageFormat(globalFormats, inlineFormats, timeZone) {
const mfDateDefaults = IntlMessageFormat.formats.date;
const mfTimeDefaults = IntlMessageFormat.formats.time;
const dateTimeFormats = {
...globalFormats?.dateTime,
...inlineFormats?.dateTime
};
const allFormats = {
date: {
...mfDateDefaults,
...dateTimeFormats
},
time: {
...mfTimeDefaults,
...dateTimeFormats
},
number: {
...globalFormats?.number,
...inlineFormats?.number
}
// (list is not supported in ICU messages)
};
if (timeZone) {
// The only way to set a time zone with `intl-messageformat` is to merge it into the formats
// https://github.com/formatjs/formatjs/blob/8256c5271505cf2606e48e3c97ecdd16ede4f1b5/packages/intl/src/message.ts#L15
['date', 'time'].forEach(property => {
const formats = allFormats[property];
for (const [key, value] of Object.entries(formats)) {
formats[key] = {
timeZone,
...value
};
}
});
}
return allFormats;
}
function joinPath(...parts) {
return parts.filter(Boolean).join('.');
}
/**
* Contains defaults that are used for all entry points into the core.
* See also `InitializedIntlConfiguration`.
*/
function defaultGetMessageFallback(props) {
return joinPath(props.namespace, props.key);
}
function defaultOnError(error) {
console.error(error);
}
function createCache() {
return {
dateTime: {},
number: {},
message: {},
relativeTime: {},
pluralRules: {},
list: {},
displayNames: {}
};
}
function createMemoCache(store) {
return {
create() {
return {
get(key) {
return store[key];
},
set(key, value) {
store[key] = value;
}
};
}
};
}
function memoFn(fn, cache) {
return memoize(fn, {
cache: createMemoCache(cache),
strategy: strategies.variadic
});
}
function memoConstructor(ConstructorFn, cache) {
return memoFn((...args) => new ConstructorFn(...args), cache);
}
function createIntlFormatters(cache) {
const getDateTimeFormat = memoConstructor(Intl.DateTimeFormat, cache.dateTime);
const getNumberFormat = memoConstructor(Intl.NumberFormat, cache.number);
const getPluralRules = memoConstructor(Intl.PluralRules, cache.pluralRules);
const getRelativeTimeFormat = memoConstructor(Intl.RelativeTimeFormat, cache.relativeTime);
const getListFormat = memoConstructor(Intl.ListFormat, cache.list);
const getDisplayNames = memoConstructor(Intl.DisplayNames, cache.displayNames);
return {
getDateTimeFormat,
getNumberFormat,
getPluralRules,
getRelativeTimeFormat,
getListFormat,
getDisplayNames
};
}
// Placed here for improved tree shaking. Somehow when this is placed in
// `formatters.tsx`, then it can't be shaken off from `next-intl`.
function createMessageFormatter(cache, intlFormatters) {
const getMessageFormat = memoFn((...args) => new IntlMessageFormat(args[0], args[1], args[2], {
formatters: intlFormatters,
...args[3]
}), cache.message);
return getMessageFormat;
}
function resolvePath(locale, messages, key, namespace) {
const fullKey = joinPath(namespace, key);
if (!messages) {
throw new Error(`No messages available at \`${namespace}\`.` );
}
let message = messages;
key.split('.').forEach(part => {
const next = message[part];
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (part == null || next == null) {
throw new Error(`Could not resolve \`${fullKey}\` in messages for locale \`${locale}\`.` );
}
message = next;
});
return message;
}
function prepareTranslationValues(values) {
// Workaround for https://github.com/formatjs/formatjs/issues/1467
const transformedValues = {};
Object.keys(values).forEach(key => {
let index = 0;
const value = values[key];
let transformed;
if (typeof value === 'function') {
transformed = chunks => {
const result = value(chunks);
return /*#__PURE__*/isValidElement(result) ? /*#__PURE__*/cloneElement(result, {
key: key + index++
}) : result;
};
} else {
transformed = value;
}
transformedValues[key] = transformed;
});
return transformedValues;
}
function getMessagesOrError(locale, messages, namespace) {
try {
if (!messages) {
throw new Error(`No messages were configured.` );
}
const retrievedMessages = namespace ? resolvePath(locale, messages, namespace) : messages;
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (!retrievedMessages) {
throw new Error(`No messages for namespace \`${namespace}\` found.` );
}
return retrievedMessages;
} catch (error) {
const intlError = new IntlError(IntlErrorCode.MISSING_MESSAGE, error.message);
return intlError;
}
}
function getPlainMessage(candidate, values) {
// To improve runtime performance, only compile message if:
return (
// 1. Values are provided
values ||
// 2. There are escaped braces (e.g. "'{name'}")
/'[{}]/.test(candidate) ||
// 3. There are missing arguments or tags (dev-only error handling)
/<|{/.test(candidate) ? undefined // Compile
: candidate // Don't compile
);
}
function createBaseTranslator(config) {
const messagesOrError = getMessagesOrError(config.locale, config.messages, config.namespace);
return createBaseTranslatorImpl({
...config,
messagesOrError
});
}
function createBaseTranslatorImpl({
cache,
formats: globalFormats,
formatters,
getMessageFallback = defaultGetMessageFallback,
locale,
messagesOrError,
namespace,
onError,
timeZone
}) {
const hasMessagesError = messagesOrError instanceof IntlError;
function getFallbackFromErrorAndNotify(key, code, message, fallback) {
const error = new IntlError(code, message);
onError(error);
return fallback ?? getMessageFallback({
error,
key,
namespace
});
}
function translateBaseFn(/** Use a dot to indicate a level of nesting (e.g. `namespace.nestedLabel`). */
key, /** Key value pairs for values to interpolate into the message. */
values, /** Provide custom formats for numbers, dates and times. */
formats, _fallback) {
const fallback = _fallback;
let message;
if (hasMessagesError) {
if (fallback) {
message = fallback;
} else {
onError(messagesOrError);
return getMessageFallback({
error: messagesOrError,
key,
namespace
});
}
} else {
const messages = messagesOrError;
try {
message = resolvePath(locale, messages, key, namespace);
} catch (error) {
if (fallback) {
message = fallback;
} else {
return getFallbackFromErrorAndNotify(key, IntlErrorCode.MISSING_MESSAGE, error.message, fallback);
}
}
}
if (typeof message === 'object') {
let code, errorMessage;
if (Array.isArray(message)) {
code = IntlErrorCode.INVALID_MESSAGE;
{
errorMessage = `Message at \`${joinPath(namespace, key)}\` resolved to an array, but only strings are supported. See https://next-intl.dev/docs/usage/translations#arrays-of-messages`;
}
} else {
code = IntlErrorCode.INSUFFICIENT_PATH;
{
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.dev/docs/usage/translations#structuring-messages`;
}
}
return getFallbackFromErrorAndNotify(key, code, errorMessage);
}
let messageFormat;
// Hot path that avoids creating an `IntlMessageFormat` instance
const plainMessage = getPlainMessage(message, values);
if (plainMessage) return plainMessage;
// Lazy init the message formatter for better tree
// shaking in case message formatting is not used.
if (!formatters.getMessageFormat) {
formatters.getMessageFormat = createMessageFormatter(cache, formatters);
}
try {
messageFormat = formatters.getMessageFormat(message, locale, convertFormatsToIntlMessageFormat(globalFormats, formats, timeZone), {
formatters: {
...formatters,
getDateTimeFormat(locales, options) {
// Workaround for https://github.com/formatjs/formatjs/issues/4279
return formatters.getDateTimeFormat(locales, {
timeZone,
...options
});
}
}
});
} catch (error) {
const thrownError = error;
return getFallbackFromErrorAndNotify(key, IntlErrorCode.INVALID_MESSAGE, thrownError.message + ('originalMessage' in thrownError ? ` (${thrownError.originalMessage})` : '') , fallback);
}
try {
const formattedMessage = messageFormat.format(
// @ts-expect-error `intl-messageformat` expects a different format
// for rich text elements since a recent minor update. This
// needs to be evaluated in detail, possibly also in regards
// to be able to format to parts.
values ? prepareTranslationValues(values) : values);
if (formattedMessage == null) {
throw new Error(`Unable to format \`${key}\` in ${namespace ? `namespace \`${namespace}\`` : 'messages'}` );
}
// Limit the function signature to return strings or React elements
return /*#__PURE__*/isValidElement(formattedMessage) ||
// Arrays of React elements
Array.isArray(formattedMessage) || typeof formattedMessage === 'string' ? formattedMessage : String(formattedMessage);
} catch (error) {
return getFallbackFromErrorAndNotify(key, IntlErrorCode.FORMATTING_ERROR, error.message, fallback);
}
}
function translateFn(/** Use a dot to indicate a level of nesting (e.g. `namespace.nestedLabel`). */
key, /** Key value pairs for values to interpolate into the message. */
values, /** Custom formats for numbers, dates and times. */
formats, _fallback) {
const result = translateBaseFn(key, values, formats, _fallback);
if (typeof result !== 'string') {
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.` );
}
return result;
}
translateFn.rich = translateBaseFn;
// Augment `translateBaseFn` to return plain strings
translateFn.markup = (key, values, formats, _fallback) => {
const result = translateBaseFn(key,
// @ts-expect-error -- `MarkupTranslationValues` is practically a sub type
// of `RichTranslationValues` but TypeScript isn't smart enough here.
values, formats, _fallback);
if (typeof result !== 'string') {
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>`})");
onError(error);
return getMessageFallback({
error,
key,
namespace
});
}
return result;
};
translateFn.raw = key => {
if (hasMessagesError) {
onError(messagesOrError);
return getMessageFallback({
error: messagesOrError,
key,
namespace
});
}
const messages = messagesOrError;
try {
return resolvePath(locale, messages, key, namespace);
} catch (error) {
return getFallbackFromErrorAndNotify(key, IntlErrorCode.MISSING_MESSAGE, error.message);
}
};
translateFn.has = key => {
if (hasMessagesError) {
return false;
}
try {
resolvePath(locale, messagesOrError, key, namespace);
return true;
} catch {
return false;
}
};
return translateFn;
}
/**
* For the strictly typed messages to work we have to wrap the namespace into
* a mandatory prefix. See https://stackoverflow.com/a/71529575/343045
*/
function resolveNamespace(namespace, namespacePrefix) {
return namespace === namespacePrefix ? undefined : namespace.slice((namespacePrefix + '.').length);
}
const SECOND = 1;
const MINUTE = SECOND * 60;
const HOUR = MINUTE * 60;
const DAY = HOUR * 24;
const WEEK = DAY * 7;
const MONTH = DAY * (365 / 12); // Approximation
const QUARTER = MONTH * 3;
const YEAR = DAY * 365;
const UNIT_SECONDS = {
second: SECOND,
seconds: SECOND,
minute: MINUTE,
minutes: MINUTE,
hour: HOUR,
hours: HOUR,
day: DAY,
days: DAY,
week: WEEK,
weeks: WEEK,
month: MONTH,
months: MONTH,
quarter: QUARTER,
quarters: QUARTER,
year: YEAR,
years: YEAR
};
function resolveRelativeTimeUnit(seconds) {
const absValue = Math.abs(seconds);
if (absValue < MINUTE) {
return 'second';
} else if (absValue < HOUR) {
return 'minute';
} else if (absValue < DAY) {
return 'hour';
} else if (absValue < WEEK) {
return 'day';
} else if (absValue < MONTH) {
return 'week';
} else if (absValue < YEAR) {
return 'month';
}
return 'year';
}
function calculateRelativeTimeValue(seconds, unit) {
// We have to round the resulting values, as `Intl.RelativeTimeFormat`
// will include fractions like '2.1 hours ago'.
return Math.round(seconds / UNIT_SECONDS[unit]);
}
function createFormatter(props) {
const {
_cache: cache = createCache(),
_formatters: formatters = createIntlFormatters(cache),
formats,
locale,
onError = defaultOnError,
timeZone: globalTimeZone
} = props;
function applyTimeZone(options) {
if (!options?.timeZone) {
if (globalTimeZone) {
options = {
...options,
timeZone: globalTimeZone
};
} else {
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.dev/docs/configuration#time-zone` ));
}
}
return options;
}
function resolveFormatOrOptions(typeFormats, formatOrOptions, overrides) {
let options;
if (typeof formatOrOptions === 'string') {
const formatName = formatOrOptions;
options = typeFormats?.[formatName];
if (!options) {
const error = new IntlError(IntlErrorCode.MISSING_FORMAT, `Format \`${formatName}\` is not available.` );
onError(error);
throw error;
}
} else {
options = formatOrOptions;
}
if (overrides) {
options = {
...options,
...overrides
};
}
return options;
}
function getFormattedValue(formatOrOptions, overrides, typeFormats, formatter, getFallback) {
let options;
try {
options = resolveFormatOrOptions(typeFormats, formatOrOptions, overrides);
} catch {
return getFallback();
}
try {
return formatter(options);
} catch (error) {
onError(new IntlError(IntlErrorCode.FORMATTING_ERROR, error.message));
return getFallback();
}
}
function dateTime(value, formatOrOptions, overrides) {
return getFormattedValue(formatOrOptions, overrides, formats?.dateTime, options => {
options = applyTimeZone(options);
return formatters.getDateTimeFormat(locale, options).format(value);
}, () => String(value));
}
function dateTimeRange(start, end, formatOrOptions, overrides) {
return getFormattedValue(formatOrOptions, overrides, formats?.dateTime, options => {
options = applyTimeZone(options);
return formatters.getDateTimeFormat(locale, options).formatRange(start, end);
}, () => [dateTime(start), dateTime(end)].join('  '));
}
function number(value, formatOrOptions, overrides) {
return getFormattedValue(formatOrOptions, overrides, formats?.number, options => formatters.getNumberFormat(locale, options).format(value), () => String(value));
}
function getGlobalNow() {
// Only read when necessary to avoid triggering a `dynamicIO` error
// unnecessarily (`now` is only needed for `format.relativeTime`)
if (props.now) {
return props.now;
} else {
onError(new IntlError(IntlErrorCode.ENVIRONMENT_FALLBACK, `The \`now\` parameter wasn't provided to \`relativeTime\` and there is no global default configured, therefore the current time will be used as a fallback. See https://next-intl.dev/docs/usage/dates-times#relative-times-usenow` ));
return new Date();
}
}
function relativeTime(date, nowOrOptions) {
try {
let nowDate, unit;
const opts = {};
if (nowOrOptions instanceof Date || typeof nowOrOptions === 'number') {
nowDate = new Date(nowOrOptions);
} else if (nowOrOptions) {
if (nowOrOptions.now != null) {
nowDate = new Date(nowOrOptions.now);
} else {
nowDate = getGlobalNow();
}
unit = nowOrOptions.unit;
opts.style = nowOrOptions.style;
// @ts-expect-error -- Types are slightly outdated
opts.numberingSystem = nowOrOptions.numberingSystem;
}
if (!nowDate) {
nowDate = getGlobalNow();
}
const dateDate = new Date(date);
const seconds = (dateDate.getTime() - nowDate.getTime()) / 1000;
if (!unit) {
unit = resolveRelativeTimeUnit(seconds);
}
// `numeric: 'auto'` can theoretically produce output like "yesterday",
// but it only works with integers. E.g. -1 day will produce "yesterday",
// but -1.1 days will produce "-1.1 days". Rounding before formatting is
// not desired, as the given dates might cross a threshold were the
// output isn't correct anymore. Example: 2024-01-08T23:00:00.000Z and
// 2024-01-08T01:00:00.000Z would produce "yesterday", which is not the
// case. By using `always` we can ensure correct output. The only exception
// is the formatting of times <1 second as "now".
opts.numeric = unit === 'second' ? 'auto' : 'always';
const value = calculateRelativeTimeValue(seconds, unit);
return formatters.getRelativeTimeFormat(locale, opts).format(value, unit);
} catch (error) {
onError(new IntlError(IntlErrorCode.FORMATTING_ERROR, error.message));
return String(date);
}
}
function list(value, formatOrOptions, overrides) {
const serializedValue = [];
const richValues = new Map();
// `formatToParts` only accepts strings, therefore we have to temporarily
// replace React elements with a placeholder ID that can be used to retrieve
// the original value afterwards.
let index = 0;
for (const item of value) {
let serializedItem;
if (typeof item === 'object') {
serializedItem = String(index);
richValues.set(serializedItem, item);
} else {
serializedItem = String(item);
}
serializedValue.push(serializedItem);
index++;
}
return getFormattedValue(formatOrOptions, overrides, formats?.list,
// @ts-expect-error -- `richValues.size` is used to determine the return type, but TypeScript can't infer the meaning of this correctly
options => {
const result = formatters.getListFormat(locale, options).formatToParts(serializedValue).map(part => part.type === 'literal' ? part.value : richValues.get(part.value) || part.value);
if (richValues.size > 0) {
return result;
} else {
return result.join('');
}
}, () => String(value));
}
return {
dateTime,
number,
relativeTime,
list,
dateTimeRange
};
}
function validateMessagesSegment(messages, invalidKeyLabels, parentPath) {
Object.entries(messages).forEach(([key, messageOrMessages]) => {
if (key.includes('.')) {
let keyLabel = key;
if (parentPath) keyLabel += ` (at ${parentPath})`;
invalidKeyLabels.push(keyLabel);
}
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (messageOrMessages != null && typeof messageOrMessages === 'object') {
validateMessagesSegment(messageOrMessages, invalidKeyLabels, joinPath(parentPath, key));
}
});
}
function validateMessages(messages, onError) {
const invalidKeyLabels = [];
validateMessagesSegment(messages, invalidKeyLabels);
if (invalidKeyLabels.length > 0) {
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.
Invalid ${invalidKeyLabels.length === 1 ? 'key' : 'keys'}: ${invalidKeyLabels.join(', ')}
If you're migrating from a flat structure, you can convert your messages as follows:
import {set} from "lodash";
const input = {
"one.one": "1.1",
"one.two": "1.2",
"two.one.one": "2.1.1"
};
const output = Object.entries(input).reduce(
(acc, [key, value]) => set(acc, key, value),
{}
);
// Output:
//
// {
// "one": {
// "one": "1.1",
// "two": "1.2"
// },
// "two": {
// "one": {
// "one": "2.1.1"
// }
// }
// }
` ));
}
}
/**
* Enhances the incoming props with defaults.
*/
function initializeConfig({
formats,
getMessageFallback,
messages,
onError,
...rest
}) {
const finalOnError = onError || defaultOnError;
const finalGetMessageFallback = getMessageFallback || defaultGetMessageFallback;
{
if (messages) {
validateMessages(messages, finalOnError);
}
}
return {
...rest,
formats: formats || undefined,
messages: messages || undefined,
onError: finalOnError,
getMessageFallback: finalGetMessageFallback
};
}
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 };
+230
View File
@@ -0,0 +1,230 @@
import { createContext, useContext, useMemo, useState, useEffect } from 'react';
import { d as createCache, b as createIntlFormatters, i as initializeConfig, r as resolveNamespace, I as IntlError, a as IntlErrorCode, e as createBaseTranslator, c as createFormatter } from './initializeConfig-CIDVMS2E.js';
import { jsx } from 'react/jsx-runtime';
const IntlContext = /*#__PURE__*/createContext(undefined);
function IntlProvider({
children,
formats,
getMessageFallback,
locale,
messages,
now,
onError,
timeZone
}) {
const prevContext = useContext(IntlContext);
// The formatter cache is released when the locale changes. For
// long-running apps with a persistent `IntlProvider` at the root,
// this can reduce the memory footprint (e.g. in React Native).
const cache = useMemo(() => {
return prevContext?.cache || createCache();
}, [locale, prevContext?.cache]);
const formatters = useMemo(() => prevContext?.formatters || createIntlFormatters(cache), [cache, prevContext?.formatters]);
// Memoizing this value helps to avoid triggering a re-render of all
// context consumers in case the configuration didn't change. However,
// if some of the non-primitive values change, a re-render will still
// be triggered. Note that there's no need to put `memo` on `IntlProvider`
// itself, because the `children` typically change on every render.
// There's some burden on the consumer side if it's important to reduce
// re-renders, put that's how React works.
// See: https://blog.isquaredsoftware.com/2020/05/blogged-answers-a-mostly-complete-guide-to-react-rendering-behavior/#context-updates-and-render-optimizations
const value = useMemo(() => ({
...initializeConfig({
locale,
// (required by provider)
formats: formats === undefined ? prevContext?.formats : formats,
getMessageFallback: getMessageFallback || prevContext?.getMessageFallback,
messages: messages === undefined ? prevContext?.messages : messages,
now: now || prevContext?.now,
onError: onError || prevContext?.onError,
timeZone: timeZone || prevContext?.timeZone
}),
formatters,
cache
}), [cache, formats, formatters, getMessageFallback, locale, messages, now, onError, prevContext, timeZone]);
return /*#__PURE__*/jsx(IntlContext.Provider, {
value: value,
children: children
});
}
function useIntlContext() {
const context = useContext(IntlContext);
if (!context) {
throw new Error('No intl context found. Have you configured the provider? See https://next-intl.dev/docs/usage/configuration#server-client-components' );
}
return context;
}
let hasWarnedForMissingTimezone = false;
const isServer = typeof window === 'undefined';
function useTranslationsImpl(allMessagesPrefixed, namespacePrefixed, namespacePrefix) {
const {
cache,
formats: globalFormats,
formatters,
getMessageFallback,
locale,
onError,
timeZone
} = useIntlContext();
// The `namespacePrefix` is part of the type system.
// See the comment in the hook invocation.
const allMessages = allMessagesPrefixed[namespacePrefix];
const namespace = resolveNamespace(namespacePrefixed, namespacePrefix);
if (!timeZone && !hasWarnedForMissingTimezone && isServer) {
// eslint-disable-next-line react-compiler/react-compiler
hasWarnedForMissingTimezone = true;
onError(new IntlError(IntlErrorCode.ENVIRONMENT_FALLBACK, `There is no \`timeZone\` configured, this can lead to markup mismatches caused by environment differences. Consider adding a global default: https://next-intl.dev/docs/configuration#time-zone` ));
}
const translate = useMemo(() => createBaseTranslator({
cache,
formatters,
getMessageFallback,
messages: allMessages,
namespace,
onError,
formats: globalFormats,
locale,
timeZone
}), [cache, formatters, getMessageFallback, allMessages, namespace, onError, globalFormats, locale, timeZone]);
return translate;
}
/**
* Translates messages from the given namespace by using the ICU syntax.
* See https://formatjs.io/docs/core-concepts/icu-syntax.
*
* If no namespace is provided, all available messages are returned.
* The namespace can also indicate nesting by using a dot
* (e.g. `namespace.Component`).
*/
function useTranslations(namespace) {
const context = useIntlContext();
const messages = context.messages;
// We have to wrap the actual hook so the type inference for the optional
// namespace works correctly. See https://stackoverflow.com/a/71529575/343045
// The prefix ("!") is arbitrary.
// @ts-expect-error Use the explicit annotation instead
return useTranslationsImpl({
'!': messages
},
// @ts-expect-error
namespace ? `!.${namespace}` : '!', '!');
}
function useLocale() {
return useIntlContext().locale;
}
function getNow() {
return new Date();
}
/**
* @see https://next-intl.dev/docs/usage/dates-times#relative-times-usenow
*/
function useNow(options) {
const updateInterval = options?.updateInterval;
const {
now: globalNow
} = useIntlContext();
const [now, setNow] = useState(globalNow || getNow());
useEffect(() => {
if (!updateInterval) return;
const intervalId = setInterval(() => {
setNow(getNow());
}, updateInterval);
return () => {
clearInterval(intervalId);
};
}, [globalNow, updateInterval]);
return updateInterval == null && globalNow ? globalNow : now;
}
function useTimeZone() {
return useIntlContext().timeZone;
}
function useMessages() {
const context = useIntlContext();
if (!context.messages) {
throw new Error('No messages found. Have you configured them correctly? See https://next-intl.dev/docs/configuration#messages' );
}
return context.messages;
}
function useFormatter() {
const {
formats,
formatters,
locale,
now: globalNow,
onError,
timeZone
} = useIntlContext();
return useMemo(() => createFormatter({
formats,
locale,
now: globalNow,
onError,
timeZone,
_formatters: formatters
}), [formats, formatters, globalNow, locale, onError, timeZone]);
}
function getArgs(messageOrParams, ...rest) {
let message, values, formats;
if (typeof messageOrParams === 'string') {
message = messageOrParams;
values = rest[0];
formats = rest[1];
} else {
message = messageOrParams.message;
values = messageOrParams.values;
formats = messageOrParams.formats;
// `description` is is not used at runtime
}
// @ts-expect-error -- Secret fallback parameter
return [undefined,
// Always use fallback if not compiled
values, formats, message ];
}
// Note: This API is usually compiled into `useTranslations`,
// but there is some fallback handling which allows this hook
// to still work when not being compiled.
//
// This is relevant for:
// - Isolated environments like tests, Storybook, etc.
// - Fallbacks in case an extracted message is not yet available
function useExtracted(namespace) {
const t = useTranslations(namespace);
function translateFn(...params) {
// @ts-expect-error -- Passing `undefined` as an ID is secretly allowed here
return t(...getArgs(...params));
}
translateFn.rich = (...params) =>
// @ts-expect-error -- Passing `undefined` as an ID is secretly allowed here
t.rich(...getArgs(...params));
translateFn.markup = (...params) =>
// @ts-expect-error -- Passing `undefined` as an ID is secretly allowed here
t.markup(...getArgs(...params));
translateFn.has = function translateHasFn(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
message) {
// Not really something better we can do here
return true;
};
return translateFn;
}
export { IntlProvider, useExtracted as _useExtracted, useFormatter, useLocale, useMessages, useNow, useTimeZone, useTranslations };
+1
View File
@@ -0,0 +1 @@
import{r as e,e as s,f as r,b as t,d as o,g as n}from"./initializeConfig-CzP0yD8_.js";export{I as IntlError,a as IntlErrorCode,c as createFormatter,i as initializeConfig}from"./initializeConfig-CzP0yD8_.js";function m({_cache:a=o(),_formatters:i=t(a),getMessageFallback:m=r,messages:c,namespace:f,onError:g=n,...l}){return function({messages:a,namespace:r,...t},o){return a=a[o],r=e(r,o),s({...t,messages:a,namespace:r})}({...l,onError:g,cache:a,formatters:i,getMessageFallback:m,messages:{"!":c},namespace:f?`!.${f}`:"!"},"!")}function f(e,a){return e.includes(a)}export{o as _createCache,t as _createIntlFormatters,m as createTranslator,f as hasLocale};
+1
View File
@@ -0,0 +1 @@
export{I as IntlError,a as IntlErrorCode,d as _createCache,b as _createIntlFormatters,c as createFormatter,i as initializeConfig}from"./initializeConfig-CzP0yD8_.js";export{createTranslator,hasLocale}from"./core.js";export{IntlProvider,_useExtracted,useFormatter,useLocale,useMessages,useNow,useTimeZone,useTranslations}from"./react.js";
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
import{createContext as e,useContext as r,useMemo as t,useState as o,useEffect as n}from"react";import{d as a,b as s,i as c,r as i,I as m,a as f,e as u,c as l}from"./initializeConfig-CzP0yD8_.js";import{jsx as g}from"react/jsx-runtime";const d=e(void 0);function v({children:e,formats:o,getMessageFallback:n,locale:i,messages:m,now:f,onError:u,timeZone:l}){const v=r(d),w=t((()=>v?.cache||a()),[i,v?.cache]),h=t((()=>v?.formatters||s(w)),[w,v?.formatters]),p=t((()=>({...c({locale:i,formats:void 0===o?v?.formats:o,getMessageFallback:n||v?.getMessageFallback,messages:void 0===m?v?.messages:m,now:f||v?.now,onError:u||v?.onError,timeZone:l||v?.timeZone}),formatters:h,cache:w})),[w,o,h,n,i,m,f,u,v,l]);return g(d.Provider,{value:p,children:e})}function w(){const e=r(d);if(!e)throw new Error(void 0);return e}let h=!1;const p="undefined"==typeof window;function E(e){return function(e,r,o){const{cache:n,formats:a,formatters:s,getMessageFallback:c,locale:l,onError:g,timeZone:d}=w(),v=e[o],E=i(r,o);return d||h||!p||(h=!0,g(new m(f.ENVIRONMENT_FALLBACK,void 0))),t((()=>u({cache:n,formatters:s,getMessageFallback:c,messages:v,namespace:E,onError:g,formats:a,locale:l,timeZone:d})),[n,s,c,v,E,g,a,l,d])}({"!":w().messages},e?`!.${e}`:"!","!")}function Z(){return w().locale}function k(){return new Date}function b(e){const r=e?.updateInterval,{now:t}=w(),[a,s]=o(t||k());return n((()=>{if(!r)return;const e=setInterval((()=>{s(k())}),r);return()=>{clearInterval(e)}}),[t,r]),null==r&&t?t:a}function F(){return w().timeZone}function M(){const e=w();if(!e.messages)throw new Error(void 0);return e.messages}function I(){const{formats:e,formatters:r,locale:o,now:n,onError:a,timeZone:s}=w();return t((()=>l({formats:e,locale:o,now:n,onError:a,timeZone:s,_formatters:r})),[e,r,n,o,a,s])}function j(e,...r){let t,o;return"string"==typeof e?(t=r[0],o=r[1]):(t=e.values,o=e.formats),[void 0,t,o,void 0]}function x(e){const r=E(e);function t(...e){return r(...j(...e))}return t.rich=(...e)=>r.rich(...j(...e)),t.markup=(...e)=>r.markup(...j(...e)),t.has=function(e){return!0},t}export{v as IntlProvider,x as _useExtracted,I as useFormatter,Z as useLocale,M as useMessages,b as useNow,F as useTimeZone,E as useTranslations};
+1
View File
@@ -0,0 +1 @@
export * from './core/index.js';
+10
View File
@@ -0,0 +1,10 @@
/**
* A generic type that describes the shape of messages.
*
* Optionally, messages can be strictly-typed in order to get type safety for message
* namespaces and keys. See https://next-intl.dev/docs/usage/typescript
*/
type AbstractIntlMessages = {
[id: string]: AbstractIntlMessages | string;
};
export default AbstractIntlMessages;
+25
View File
@@ -0,0 +1,25 @@
export default interface AppConfig {
}
export type Locale = AppConfig extends {
Locale: infer AppLocale;
} ? AppLocale : string;
export type FormatNames = AppConfig extends {
Formats: infer AppFormats;
} ? {
dateTime: AppFormats extends {
dateTime: infer AppDateTimeFormats;
} ? keyof AppDateTimeFormats : string;
number: AppFormats extends {
number: infer AppNumberFormats;
} ? keyof AppNumberFormats : string;
list: AppFormats extends {
list: infer AppListFormats;
} ? keyof AppListFormats : string;
} : {
dateTime: string;
number: string;
list: string;
};
export type Messages = AppConfig extends {
Messages: infer AppMessages;
} ? AppMessages : Record<string, any>;
+73
View File
@@ -0,0 +1,73 @@
import type TimeZone from './TimeZone.js';
/**
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat
*/
type DateTimeFormatOptions = Intl.DateTimeFormatOptions & {
/**
* Examples:
* - numeric: "2021"
* - 2-digit: "21"
*/
year?: 'numeric' | '2-digit';
/** Examples:
* - numeric: "3"
* - 2-digit: "03"
* - long: "March"
* - short: "Mar"
* - narrow: "M"
*/
month?: 'numeric' | '2-digit' | 'long' | 'short' | 'narrow';
/** Examples:
* - numeric: "2"
* - 2-digit: "02"
*/
day?: 'numeric' | '2-digit';
/** Examples:
* - numeric: "2"
* - 2-digit: "02"
*/
hour?: 'numeric' | '2-digit';
/** Examples:
* - numeric: "2"
* - 2-digit: "02"
*/
minute?: 'numeric' | '2-digit';
/** Examples:
* - numeric: "2"
* - 2-digit: "02"
*/
second?: 'numeric' | '2-digit';
/** Examples:
* - long: "Thursday"
* - short: "Thu"
* - narrow: "T"
*/
weekday?: 'long' | 'short' | 'narrow';
/** Examples:
* - long: "Anno Domini"
* - short: "AD", narrow "A"
*/
era?: 'long' | 'short' | 'narrow';
/** If this is set to `true`, a 12-hour am/pm format is used. Otherwise a 24-hour time.
*
*/
hour12?: boolean;
/** Examples:
* - long: "Pacific Daylight Time"
* - short: "PDT"
*/
timeZoneName?: 'long' | 'short';
/**
* One of the [database names from the TZ database](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List).
*/
timeZone?: TimeZone;
localeMatcher?: 'best fit' | 'lookup';
formatMatcher?: 'best fit' | 'basic';
dateStyle?: 'full' | 'long' | 'medium' | 'short';
timeStyle?: 'full' | 'long' | 'medium' | 'short';
calendar?: 'buddhist' | 'chinese' | 'coptic' | 'ethiopia' | 'ethiopic' | 'gregory' | 'hebrew' | 'indian' | 'islamic' | 'iso8601' | 'japanese' | 'persian' | 'roc';
dayPeriod?: 'narrow' | 'short' | 'long';
numberingSystem?: 'arab' | 'arabext' | 'bali' | 'beng' | 'deva' | 'fullwide' | 'gujr' | 'guru' | 'hanidec' | 'khmr' | 'knda' | 'laoo' | 'latn' | 'limb' | 'mlym' | 'mong' | 'mymr' | 'orya' | 'tamldec' | 'telu' | 'thai' | 'tibt';
hourCycle?: 'h11' | 'h12' | 'h23' | 'h24';
};
export default DateTimeFormatOptions;
+8
View File
@@ -0,0 +1,8 @@
import type DateTimeFormatOptions from './DateTimeFormatOptions.js';
import type NumberFormatOptions from './NumberFormatOptions.js';
type Formats = {
number?: Record<string, NumberFormatOptions>;
dateTime?: Record<string, DateTimeFormatOptions>;
list?: Record<string, Intl.ListFormatOptions>;
};
export default Formats;
+3
View File
@@ -0,0 +1,3 @@
import type { GetICUArgs, GetICUArgsOptions } from '@schummar/icu-type-parser';
type ICUArgs<Message extends string, Options extends GetICUArgsOptions> = string extends Message ? {} : GetICUArgs<Message, Options>;
export default ICUArgs;
+2
View File
@@ -0,0 +1,2 @@
type ICUTags<MessageString extends string, TagsFn> = MessageString extends `${infer Prefix}<${infer TagName}>${infer Content}</${string}>${infer Tail}` ? Record<TagName, TagsFn> & ICUTags<`${Prefix}${Content}${Tail}`, TagsFn> : {};
export default ICUTags;
+54
View File
@@ -0,0 +1,54 @@
import type { Locale, Messages } from './AppConfig.js';
import type Formats from './Formats.js';
import type IntlError from './IntlError.js';
import type TimeZone from './TimeZone.js';
import type { DeepPartial } from './types.js';
/**
* Should be used for entry points that configure the library.
*/
type IntlConfig = {
/** A valid Unicode locale tag (e.g. "en" or "en-GB"). */
locale: Locale;
/** Global formats can be provided to achieve consistent
* formatting across components. */
formats?: Formats | null;
/** A time zone as defined in [the tz database](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) which will be applied when formatting dates and times. If this is absent, the user time zone will be used. You can override this by supplying an explicit time zone to `formatDateTime`. */
timeZone?: TimeZone;
/** This callback will be invoked when an error is encountered during
* resolving a message or formatting it. This defaults to `console.error` to
* keep your app running. You can customize the handling by taking
* `error.code` into account. */
onError?(error: IntlError): void;
/** Will be called when a message couldn't be resolved or formatting it led to
* an error. This defaults to `${namespace}.${key}` You can use this to
* customize what will be rendered in this case. */
getMessageFallback?(info: {
error: IntlError;
key: string;
namespace?: string;
}): string;
/**
* Providing this value will have two effects:
* 1. It will be used as the default for the `now` argument of
* `useFormatter().formatRelativeTime` if no explicit value is provided.
* 2. It will be returned as a static value from the `useNow` hook. Note
* however that when `updateInterval` is configured on the `useNow` hook,
* the global `now` value will only be used for the initial render, but
* afterwards the current date will be returned continuously.
*/
now?: Date;
/** All messages that will be available. */
messages?: DeepPartial<Messages> | null;
};
/**
/**
* A stricter set of the configuration that should be used internally
* once defaults are assigned to `IntlConfiguration`.
*/
export type InitializedIntlConfig = Omit<IntlConfig, 'formats' | 'messages' | 'onError' | 'getMessageFallback'> & {
formats?: NonNullable<IntlConfig['formats']>;
messages?: NonNullable<IntlConfig['messages']>;
onError: NonNullable<IntlConfig['onError']>;
getMessageFallback: NonNullable<IntlConfig['getMessageFallback']>;
};
export default IntlConfig;
+6
View File
@@ -0,0 +1,6 @@
import type IntlErrorCode from './IntlErrorCode.js';
export default class IntlError extends Error {
readonly code: IntlErrorCode;
readonly originalMessage: string | undefined;
constructor(code: IntlErrorCode, originalMessage?: string);
}
+10
View File
@@ -0,0 +1,10 @@
declare enum IntlErrorCode {
MISSING_MESSAGE = "MISSING_MESSAGE",
MISSING_FORMAT = "MISSING_FORMAT",
ENVIRONMENT_FALLBACK = "ENVIRONMENT_FALLBACK",
INSUFFICIENT_PATH = "INSUFFICIENT_PATH",
INVALID_MESSAGE = "INVALID_MESSAGE",
INVALID_KEY = "INVALID_KEY",
FORMATTING_ERROR = "FORMATTING_ERROR"
}
export default IntlErrorCode;
+10
View File
@@ -0,0 +1,10 @@
export type NestedKeyOf<ObjectType> = ObjectType extends object ? {
[Property in keyof ObjectType]: `${Property & string}` | `${Property & string}.${NestedKeyOf<ObjectType[Property]>}`;
}[keyof ObjectType] : never;
export type NestedValueOf<ObjectType, Path extends string> = Path extends `${infer Cur}.${infer Rest}` ? Cur extends keyof ObjectType ? NestedValueOf<ObjectType[Cur], Rest> : never : Path extends keyof ObjectType ? ObjectType[Path] : never;
export type NamespaceKeys<ObjectType, AllKeys extends string> = {
[PropertyPath in AllKeys]: NestedValueOf<ObjectType, PropertyPath> extends string ? never : PropertyPath;
}[AllKeys];
export type MessageKeys<ObjectType, AllKeys extends string> = {
[PropertyPath in AllKeys]: NestedValueOf<ObjectType, PropertyPath> extends string ? PropertyPath : never;
}[AllKeys];
+3
View File
@@ -0,0 +1,3 @@
import type { Formats } from 'intl-messageformat';
type NumberFormatOptions = Formats['number'][string];
export default NumberFormatOptions;
+7
View File
@@ -0,0 +1,7 @@
type RelativeTimeFormatOptions = {
now?: number | Date;
unit?: Intl.RelativeTimeFormatUnit;
numberingSystem?: string;
style?: Intl.RelativeTimeFormatStyle;
};
export default RelativeTimeFormatOptions;
File diff suppressed because one or more lines are too long
+6
View File
@@ -0,0 +1,6 @@
import type { ReactNode } from 'react';
export type TranslationValues = Record<string, string | number | Date>;
export type RichTagsFunction = (chunks: ReactNode) => ReactNode;
export type MarkupTagsFunction = (chunks: string) => string;
export type RichTranslationValues = Record<string, TranslationValues[string] | RichTagsFunction>;
export type MarkupTranslationValues = Record<string, TranslationValues[string] | MarkupTagsFunction>;
@@ -0,0 +1,11 @@
import { type Formats as IntlFormats } from 'intl-messageformat';
import type Formats from './Formats.js';
import type TimeZone from './TimeZone.js';
/**
* `intl-messageformat` uses separate keys for `date` and `time`, but there's
* only one native API: `Intl.DateTimeFormat`. Additionally you might want to
* include both a time and a date in a value, therefore the separation doesn't
* seem so useful. We offer a single `dateTime` namespace instead, but we have
* to convert the format before `intl-messageformat` can be used.
*/
export default function convertFormatsToIntlMessageFormat(globalFormats?: Formats, inlineFormats?: Formats, timeZone?: TimeZone): Partial<IntlFormats>;
+21
View File
@@ -0,0 +1,21 @@
import { type ReactNode } from 'react';
import type AbstractIntlMessages from './AbstractIntlMessages.js';
import type Formats from './Formats.js';
import type { InitializedIntlConfig } from './IntlConfig.js';
import IntlError from './IntlError.js';
import type { MessageKeys, NestedKeyOf, NestedValueOf } from './MessageKeys.js';
import type { MarkupTranslationValues, RichTranslationValues, TranslationValues } from './TranslationValues.js';
import { type Formatters, type IntlCache } from './formatters.js';
export type CreateBaseTranslatorProps<Messages> = InitializedIntlConfig & {
cache: IntlCache;
formatters: Formatters;
namespace?: string;
messagesOrError: Messages | IntlError;
};
export default function createBaseTranslator<Messages extends AbstractIntlMessages, NestedKey extends NestedKeyOf<Messages>>(config: Omit<CreateBaseTranslatorProps<Messages>, 'messagesOrError'>): {
<TargetKey extends MessageKeys<NestedValueOf<Messages, NestedKey>, NestedKeyOf<NestedValueOf<Messages, NestedKey>>>>(key: TargetKey, values?: TranslationValues, formats?: Formats, _fallback?: never): string;
rich: (key: string, values?: RichTranslationValues, formats?: Formats, _fallback?: never) => ReactNode;
markup(key: Parameters<(key: string, values?: RichTranslationValues, formats?: Formats, _fallback?: never) => ReactNode>[0], values: MarkupTranslationValues, formats?: Parameters<(key: string, values?: RichTranslationValues, formats?: Formats, _fallback?: never) => ReactNode>[2], _fallback?: never): string;
raw(key: string): any;
has(key: string): boolean;
};
+43
View File
@@ -0,0 +1,43 @@
import type { ReactElement } from 'react';
import type { FormatNames, Locale } from './AppConfig.js';
import type DateTimeFormatOptions from './DateTimeFormatOptions.js';
import type Formats from './Formats.js';
import IntlError from './IntlError.js';
import type NumberFormatOptions from './NumberFormatOptions.js';
import type RelativeTimeFormatOptions from './RelativeTimeFormatOptions.js';
import type TimeZone from './TimeZone.js';
import { type Formatters, type IntlCache } from './formatters.js';
type Props = {
locale: Locale;
timeZone?: TimeZone;
onError?(error: IntlError): void;
formats?: Formats;
now?: Date;
/** @private */
_formatters?: Formatters;
/** @private */
_cache?: IntlCache;
};
export default function createFormatter(props: Props): {
dateTime: {
(value: Date | number, options?: DateTimeFormatOptions): string;
(value: Date | number, format?: FormatNames["dateTime"], options?: DateTimeFormatOptions): string;
};
number: {
(value: number | bigint, options?: NumberFormatOptions): string;
(value: number | bigint, format?: FormatNames["number"], options?: NumberFormatOptions): string;
};
relativeTime: {
(date: number | Date, now?: RelativeTimeFormatOptions["now"]): string;
(date: number | Date, options?: RelativeTimeFormatOptions): string;
};
list: {
<Value extends string | ReactElement<unknown, string | import("react").JSXElementConstructor<any>>>(value: Iterable<Value>, options?: Intl.ListFormatOptions): Value extends string ? string : Iterable<ReactElement>;
<Value extends string | ReactElement<unknown, string | import("react").JSXElementConstructor<any>>>(value: Iterable<Value>, format?: FormatNames["list"], options?: Intl.ListFormatOptions): Value extends string ? string : Iterable<ReactElement>;
};
dateTimeRange: {
(start: Date | number, end: Date | number, options?: DateTimeFormatOptions): string;
(start: Date | number, end: Date | number, format?: FormatNames["dateTime"], options?: DateTimeFormatOptions): string;
};
};
export {};
+59
View File
@@ -0,0 +1,59 @@
import type { ReactNode } from 'react';
import type Formats from './Formats.js';
import type ICUArgs from './ICUArgs.js';
import type ICUTags from './ICUTags.js';
import type IntlConfig from './IntlConfig.js';
import type { MessageKeys, NamespaceKeys, NestedKeyOf, NestedValueOf } from './MessageKeys.js';
import type { MarkupTagsFunction, RichTagsFunction, TranslationValues } from './TranslationValues.js';
import { type Formatters, type IntlCache } from './formatters.js';
import type { Prettify } from './types.js';
type ICUArgsWithTags<MessageString extends string, TagsFn extends RichTagsFunction | MarkupTagsFunction = never> = ICUArgs<MessageString, {
ICUArgument: string;
ICUNumberArgument: number | bigint;
ICUDateArgument: Date;
}> & ([TagsFn] extends [never] ? {} : ICUTags<MessageString, TagsFn>);
type OnlyOptional<T> = Partial<T> extends T ? true : false;
export type TranslateArgs<Value extends string, TagsFn extends RichTagsFunction | MarkupTagsFunction = never> = string extends Value ? [
values?: Record<string, TranslationValues[string] | TagsFn>,
formats?: Formats
] : (Value extends any ? (key: ICUArgsWithTags<Value, TagsFn>) => void : never) extends (key: infer Args) => void ? OnlyOptional<Args> extends true ? [values?: undefined, formats?: Formats] : [values: Prettify<Args>, formats?: Formats] : never;
type IntlMessages = Record<string, any>;
type NamespacedMessageKeys<TranslatorMessages extends IntlMessages, Namespace extends NamespaceKeys<TranslatorMessages, NestedKeyOf<TranslatorMessages>> = never> = MessageKeys<NestedValueOf<{
'!': TranslatorMessages;
}, [
Namespace
] extends [never] ? '!' : `!.${Namespace}`>, NestedKeyOf<NestedValueOf<{
'!': TranslatorMessages;
}, [
Namespace
] extends [never] ? '!' : `!.${Namespace}`>>>;
type NamespacedValue<TranslatorMessages extends IntlMessages, Namespace extends NamespaceKeys<TranslatorMessages, NestedKeyOf<TranslatorMessages>>, TargetKey extends NamespacedMessageKeys<TranslatorMessages, Namespace>> = NestedValueOf<TranslatorMessages, [
Namespace
] extends [never] ? TargetKey : `${Namespace}.${TargetKey}`>;
/**
* @private Not intended for direct use.
*/
export type Translator<TranslatorMessages extends IntlMessages = IntlMessages, Namespace extends NamespaceKeys<TranslatorMessages, NestedKeyOf<TranslatorMessages>> = never> = {
<TargetKey extends NamespacedMessageKeys<TranslatorMessages, Namespace>>(key: TargetKey, ...args: TranslateArgs<NamespacedValue<TranslatorMessages, Namespace, TargetKey>>): string;
rich<TargetKey extends NamespacedMessageKeys<TranslatorMessages, Namespace>>(key: TargetKey, ...args: TranslateArgs<NamespacedValue<TranslatorMessages, Namespace, TargetKey>, RichTagsFunction>): ReactNode;
markup<TargetKey extends NamespacedMessageKeys<TranslatorMessages, Namespace>>(key: TargetKey, ...args: TranslateArgs<NamespacedValue<TranslatorMessages, Namespace, TargetKey>, MarkupTagsFunction>): string;
raw<TargetKey extends NamespacedMessageKeys<TranslatorMessages, Namespace>>(key: TargetKey): any;
has<TargetKey extends NamespacedMessageKeys<TranslatorMessages, Namespace>>(key: TargetKey): boolean;
};
/**
* Translates messages from the given namespace by using the ICU syntax.
* See https://formatjs.io/docs/core-concepts/icu-syntax.
*
* If no namespace is provided, all available messages are returned.
* The namespace can also indicate nesting by using a dot
* (e.g. `namespace.Component`).
*/
export default function createTranslator<const TranslatorMessages extends IntlMessages, const Namespace extends NamespaceKeys<TranslatorMessages, NestedKeyOf<TranslatorMessages>> = never>({ _cache, _formatters, getMessageFallback, messages, namespace, onError, ...rest }: Omit<IntlConfig, 'messages'> & {
messages?: TranslatorMessages;
namespace?: Namespace;
/** @private */
_formatters?: Formatters;
/** @private */
_cache?: IntlCache;
}): Translator<TranslatorMessages, Namespace>;
export {};
+17
View File
@@ -0,0 +1,17 @@
import type AbstractIntlMessages from './AbstractIntlMessages.js';
import type { InitializedIntlConfig } from './IntlConfig.js';
import type { NestedKeyOf } from './MessageKeys.js';
import type { Formatters, IntlCache } from './formatters.js';
export type CreateTranslatorImplProps<Messages> = Omit<InitializedIntlConfig, 'messages'> & {
namespace: string;
messages: Messages;
formatters: Formatters;
cache: IntlCache;
};
export default function createTranslatorImpl<Messages extends AbstractIntlMessages, NestedKey extends NestedKeyOf<Messages>>({ messages, namespace, ...rest }: CreateTranslatorImplProps<Messages>, namespacePrefix: string): {
<TargetKey extends import("./MessageKeys.js").MessageKeys<import("./MessageKeys.js").NestedValueOf<Messages, NestedKey>, NestedKeyOf<import("./MessageKeys.js").NestedValueOf<Messages, NestedKey>>>>(key: TargetKey, values?: import("./TranslationValues.js").TranslationValues, formats?: import("./Formats.js").default, _fallback?: never): string;
rich: (key: string, values?: import("./TranslationValues.js").RichTranslationValues, formats?: import("./Formats.js").default, _fallback?: never) => import("react").ReactNode;
markup(key: Parameters<(key: string, values?: import("./TranslationValues.js").RichTranslationValues, formats?: import("./Formats.js").default, _fallback?: never) => import("react").ReactNode>[0], values: import("./TranslationValues.js").MarkupTranslationValues, formats?: Parameters<(key: string, values?: import("./TranslationValues.js").RichTranslationValues, formats?: import("./Formats.js").default, _fallback?: never) => import("react").ReactNode>[2], _fallback?: never): string;
raw(key: string): any;
has(key: string): boolean;
};
+11
View File
@@ -0,0 +1,11 @@
import type IntlError from './IntlError.js';
/**
* Contains defaults that are used for all entry points into the core.
* See also `InitializedIntlConfiguration`.
*/
export declare function defaultGetMessageFallback(props: {
error: IntlError;
key: string;
namespace?: string;
}): string;
export declare function defaultOnError(error: IntlError): void;
+25
View File
@@ -0,0 +1,25 @@
import type { IntlMessageFormat } from 'intl-messageformat';
export type IntlCache = {
dateTime: Record<string, Intl.DateTimeFormat>;
number: Record<string, Intl.NumberFormat>;
message: Record<string, IntlMessageFormat>;
relativeTime: Record<string, Intl.RelativeTimeFormat>;
pluralRules: Record<string, Intl.PluralRules>;
list: Record<string, Intl.ListFormat>;
displayNames: Record<string, Intl.DisplayNames>;
};
export declare function createCache(): IntlCache;
export declare function memoFn<Fn extends (...args: Array<any>) => any>(fn: Fn, cache: Record<string, ReturnType<Fn> | undefined>): Fn;
export type IntlFormatters = {
getDateTimeFormat(...args: ConstructorParameters<typeof Intl.DateTimeFormat>): Intl.DateTimeFormat;
getNumberFormat(...args: ConstructorParameters<typeof Intl.NumberFormat>): Intl.NumberFormat;
getPluralRules(...args: ConstructorParameters<typeof Intl.PluralRules>): Intl.PluralRules;
getRelativeTimeFormat(...args: ConstructorParameters<typeof Intl.RelativeTimeFormat>): Intl.RelativeTimeFormat;
getListFormat(...args: ConstructorParameters<typeof Intl.ListFormat>): Intl.ListFormat;
getDisplayNames(...args: ConstructorParameters<typeof Intl.DisplayNames>): Intl.DisplayNames;
};
export declare function createIntlFormatters(cache: IntlCache): IntlFormatters;
export type MessageFormatter = (...args: ConstructorParameters<typeof IntlMessageFormat>) => IntlMessageFormat;
export type Formatters = IntlFormatters & {
getMessageFormat?: MessageFormatter;
};
+7
View File
@@ -0,0 +1,7 @@
import type { Locale } from './AppConfig.js';
/**
* Checks if a locale exists in a list of locales.
*
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale
*/
export default function hasLocale<LocaleType extends Locale>(locales: ReadonlyArray<LocaleType>, candidate: unknown): candidate is LocaleType;
+22
View File
@@ -0,0 +1,22 @@
export type { default as AbstractIntlMessages } from './AbstractIntlMessages.js';
export type { TranslationValues, RichTranslationValues, MarkupTranslationValues, RichTagsFunction, MarkupTagsFunction } from './TranslationValues.js';
export type { default as Formats } from './Formats.js';
export type { default as IntlConfig } from './IntlConfig.js';
export type { default as DateTimeFormatOptions } from './DateTimeFormatOptions.js';
export type { default as NumberFormatOptions } from './NumberFormatOptions.js';
export { default as IntlError } from './IntlError.js';
export { default as IntlErrorCode } from './IntlErrorCode.js';
export { default as createTranslator } from './createTranslator.js';
export { default as createFormatter } from './createFormatter.js';
export { default as initializeConfig } from './initializeConfig.js';
export type { MessageKeys, NamespaceKeys, NestedKeyOf, NestedValueOf } from './MessageKeys.js';
export { createIntlFormatters as _createIntlFormatters } from './formatters.js';
export { createCache as _createCache } from './formatters.js';
export type { default as AppConfig, Locale, Messages } from './AppConfig.js';
export { default as hasLocale } from './hasLocale.js';
export type { default as RelativeTimeFormatOptions } from './RelativeTimeFormatOptions.js';
export type { default as Timezone } from './TimeZone.js';
export type { default as ICUArgs } from './ICUArgs.js';
export type { default as ICUTags } from './ICUTags.js';
/** @private -- Only for type portability */
export type { Translator as _Translator } from './createTranslator.js';
+14
View File
@@ -0,0 +1,14 @@
import type IntlConfig from './IntlConfig.js';
/**
* Enhances the incoming props with defaults.
*/
export default function initializeConfig<Props extends IntlConfig>({ formats, getMessageFallback, messages, onError, ...rest }: Props): Omit<Props, "formats" | "messages" | "onError" | "getMessageFallback"> & {
formats: NonNullable<IntlConfig["formats"]> | undefined;
messages: NonNullable<IntlConfig["messages"]> | undefined;
onError: (error: import("./IntlError.js").default) => void;
getMessageFallback: (info: {
error: import("./IntlError.js").default;
key: string;
namespace?: string;
}) => string;
};
+1
View File
@@ -0,0 +1 @@
export default function joinPath(...parts: Array<string | undefined>): string;
+5
View File
@@ -0,0 +1,5 @@
/**
* For the strictly typed messages to work we have to wrap the namespace into
* a mandatory prefix. See https://stackoverflow.com/a/71529575/343045
*/
export default function resolveNamespace(namespace: string, namespacePrefix: string): string | undefined;
+6
View File
@@ -0,0 +1,6 @@
export type Prettify<T> = {
[K in keyof T]: T[K];
} & {};
export type DeepPartial<Type> = {
[Key in keyof Type]?: Type[Key] extends object ? DeepPartial<Type[Key]> : Type[Key];
};
+3
View File
@@ -0,0 +1,3 @@
import type AbstractIntlMessages from './AbstractIntlMessages.js';
import IntlError from './IntlError.js';
export default function validateMessages(messages: AbstractIntlMessages, onError: (error: IntlError) => void): void;
+2
View File
@@ -0,0 +1,2 @@
export * from './core.js';
export * from './react.js';
+1
View File
@@ -0,0 +1 @@
export * from './react/index.js';
+8
View File
@@ -0,0 +1,8 @@
import type { InitializedIntlConfig } from '../core/IntlConfig.js';
import type { Formatters, IntlCache } from '../core/formatters.js';
export type IntlContextValue = InitializedIntlConfig & {
formatters: Formatters;
cache: IntlCache;
};
declare const IntlContext: import("react").Context<IntlContextValue | undefined>;
export default IntlContext;
+7
View File
@@ -0,0 +1,7 @@
import { type ReactNode } from 'react';
import type IntlConfig from '../core/IntlConfig.js';
type Props = IntlConfig & {
children: ReactNode;
};
export default function IntlProvider({ children, formats, getMessageFallback, locale, messages, now, onError, timeZone }: Props): import("react/jsx-runtime").JSX.Element;
export {};
+9
View File
@@ -0,0 +1,9 @@
export { default as IntlProvider } from './IntlProvider.js';
export { default as useTranslations } from './useTranslations.js';
export { default as useLocale } from './useLocale.js';
export { default as useNow } from './useNow.js';
export { default as useTimeZone } from './useTimeZone.js';
export { default as useMessages } from './useMessages.js';
export { default as useFormatter } from './useFormatter.js';
/** @private -- Only for usage in `next-intl` currently */
export { default as _useExtracted } from './useExtracted.js';
+42
View File
@@ -0,0 +1,42 @@
import type { ReactNode } from 'react';
import type { MarkupTagsFunction, RichTagsFunction } from '../core/TranslationValues.js';
import type { TranslateArgs } from '../core/createTranslator.js';
type TranslateArgsObject<Value extends string, TagsFn extends RichTagsFunction | MarkupTagsFunction = never> = TranslateArgs<Value, TagsFn> extends readonly [any?, any?] ? undefined extends TranslateArgs<Value, TagsFn>[0] ? {
values?: TranslateArgs<Value, TagsFn>[0];
formats?: TranslateArgs<Value, TagsFn>[1];
} : {
values: TranslateArgs<Value, TagsFn>[0];
formats?: TranslateArgs<Value, TagsFn>[1];
} : never;
export default function useExtracted(namespace?: string): {
<Message extends string>(message: Message, ...[values, formats]: TranslateArgs<Message>): string;
<Message extends string>(params: {
id?: string;
/** Inline ICU message in the source locale. */
message: Message;
/** Description for translators and tooling. */
description?: string;
} & TranslateArgsObject<Message>): string;
rich: {
<Message extends string>(message: Message, ...[values, formats]: TranslateArgs<Message, RichTagsFunction>): ReactNode;
<Message extends string>(params: {
id?: string;
/** Inline ICU message in the source locale. */
message: Message;
/** Description for translators and tooling. */
description?: string;
} & TranslateArgsObject<Message, RichTagsFunction>): ReactNode;
};
markup: {
<Message extends string>(message: Message, ...[values, formats]: TranslateArgs<Message, MarkupTagsFunction>): string;
<Message extends string>(params: {
id?: string;
/** Inline ICU message in the source locale. */
message: Message;
/** Description for translators and tooling. */
description?: string;
} & TranslateArgsObject<Message, MarkupTagsFunction>): string;
};
has<Message extends string>(message: Message): boolean;
};
export {};
+2
View File
@@ -0,0 +1,2 @@
import createFormatter from '../core/createFormatter.js';
export default function useFormatter(): ReturnType<typeof createFormatter>;
+2
View File
@@ -0,0 +1,2 @@
import { type IntlContextValue } from './IntlContext.js';
export default function useIntlContext(): IntlContextValue;
+2
View File
@@ -0,0 +1,2 @@
import type { Locale } from '../core.js';
export default function useLocale(): Locale;
+2
View File
@@ -0,0 +1,2 @@
import type { Messages } from '../core/AppConfig.js';
export default function useMessages(): Messages;
+8
View File
@@ -0,0 +1,8 @@
type Options = {
updateInterval?: number;
};
/**
* @see https://next-intl.dev/docs/usage/dates-times#relative-times-usenow
*/
export default function useNow(options?: Options): Date;
export {};
+1
View File
@@ -0,0 +1 @@
export default function useTimeZone(): import("../core.js").Timezone | undefined;
+12
View File
@@ -0,0 +1,12 @@
import type { Messages } from '../core/AppConfig.js';
import type { NamespaceKeys, NestedKeyOf } from '../core/MessageKeys.js';
import type createTranslator from '../core/createTranslator.js';
/**
* Translates messages from the given namespace by using the ICU syntax.
* See https://formatjs.io/docs/core-concepts/icu-syntax.
*
* If no namespace is provided, all available messages are returned.
* The namespace can also indicate nesting by using a dot
* (e.g. `namespace.Component`).
*/
export default function useTranslations<NestedKey extends NamespaceKeys<Messages, NestedKeyOf<Messages>> = never>(namespace?: NestedKey): ReturnType<typeof createTranslator<Messages, NestedKey>>;
+9
View File
@@ -0,0 +1,9 @@
import type AbstractIntlMessages from '../core/AbstractIntlMessages.js';
import type { NestedKeyOf } from '../core/MessageKeys.js';
export default function useTranslationsImpl<Messages extends AbstractIntlMessages, NestedKey extends NestedKeyOf<Messages>>(allMessagesPrefixed: Messages, namespacePrefixed: NestedKey, namespacePrefix: string): {
<TargetKey extends unknown>(key: TargetKey, values?: import("../core.js").TranslationValues, formats?: import("../core.js").Formats, _fallback?: never): string;
rich: (key: string, values?: import("../core.js").RichTranslationValues, formats?: import("../core.js").Formats, _fallback?: never) => import("react").ReactNode;
markup(key: Parameters<(key: string, values?: import("../core.js").RichTranslationValues, formats?: import("../core.js").Formats, _fallback?: never) => import("react").ReactNode>[0], values: import("../core.js").MarkupTranslationValues, formats?: Parameters<(key: string, values?: import("../core.js").RichTranslationValues, formats?: import("../core.js").Formats, _fallback?: never) => import("react").ReactNode>[2], _fallback?: never): string;
raw(key: string): any;
has(key: string): boolean;
};