Files
klz-cables.com/.pnpm-store/v10/files/94/f871fd77dc5d049c68fa1f8300f1e9b5124a8da2404ca30b1d0283acf38a91650ba10b5910255e141fa8616a653fef1774651b43e4456e3461a12a18b79ae1
Marc Mintel 5397309103
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Failing after 34s
Build & Deploy / 🏗️ Build (push) Has started running
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Smoke Test (push) Has been cancelled
Build & Deploy / ⚡ Lighthouse (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
fix(products): fix breadcrumbs and product filtering (backport from main)
2026-02-24 16:04:21 +01:00

521 lines
17 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { cloneElement, isValidElement } from 'react';
import formatMessage from 'use-intl/format-message';
import { I as IntlError, a as IntlErrorCode, c as createIntlFormatters, b as createCache } from './formatters-r4aAmsMP.js';
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 prepareTranslationValues(values) {
// Related to 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 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 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 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);
}
}
}
try {
const messagePath = joinPath(namespace, key);
return formatMessage(messagePath,
// @ts-expect-error -- We have additional validation either in `compile-format.tsx` or in case of `format-only.tsx` in the loader
message, values ? prepareTranslationValues(values) : values, {
cache,
formatters,
globalFormats,
formats,
locale,
timeZone
});
} catch (error) {
let errorCode, errorMessage;
if (error instanceof IntlError) {
errorCode = error.code;
errorMessage = error.originalMessage;
} else {
errorCode = IntlErrorCode.FORMATTING_ERROR;
errorMessage = error.message;
}
return getFallbackFromErrorAndNotify(key, errorCode, errorMessage, 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 (!formatMessage.raw) {
throw new Error('`t.raw` is not supported when messages are precompiled.');
}
}
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 { createBaseTranslator as a, defaultOnError as b, createFormatter as c, defaultGetMessageFallback as d, initializeConfig as i, resolveNamespace as r };