first commit

This commit is contained in:
Ichitux
2026-04-05 03:08:53 +02:00
commit 1082d36c12
28015 changed files with 3767672 additions and 0 deletions

7
node_modules/react-i18next/src/I18nextProvider.js generated vendored Normal file
View File

@@ -0,0 +1,7 @@
import { createElement, useMemo } from 'react';
import { I18nContext } from './context.js';
export function I18nextProvider({ i18n, defaultNS, children }) {
const value = useMemo(() => ({ i18n, defaultNS }), [i18n, defaultNS]);
return createElement(I18nContext.Provider, { value }, children);
}

103
node_modules/react-i18next/src/IcuTrans.js generated vendored Normal file
View File

@@ -0,0 +1,103 @@
import { useContext } from 'react';
import { IcuTransWithoutContext } from './IcuTransWithoutContext.js';
import { getI18n, I18nContext } from './context.js';
/**
* IcuTrans component for rendering ICU MessageFormat translations with React components
*
* This component provides a context-aware wrapper around IcuTransWithoutContext,
* automatically retrieving the i18n instance from React context when used within
* an I18nextProvider. It uses a declaration tree approach where components are
* defined as type + props blueprints, fetches the translated string, and reconstructs
* the React element tree by replacing numbered tags with actual components.
*
* Key features:
* - Supports React Context (I18nextProvider)
* - Falls back to global i18n instance
* - ICU MessageFormat compatible
* - Type-safe component declarations
* - Automatic HTML entity decoding
*
* @param {Object} props - Component props
* @param {string} props.i18nKey - The i18n key to look up the translation
* @param {string} props.defaultTranslation - The default translation in ICU format with numbered tags (e.g., "<0>Click here</0>")
* @param {Array<{type: string|React.ComponentType, props?: Object}>} props.content - Declaration tree describing React components and their props
* @param {string|string[]} [props.ns] - Optional namespace(s) for the translation
* @param {Object} [props.values] - Optional values for ICU variable interpolation
* @param {Object} [props.i18n] - Optional i18next instance (overrides context)
* @param {Function} [props.t] - Optional translation function (overrides context)
* @returns {React.ReactElement} React fragment containing the rendered translation
*
* @example
* ```jsx
* // Basic usage with context
* <I18nextProvider i18n={i18n}>
* <IcuTrans
* i18nKey="welcome.message"
* defaultTranslation="Welcome <0>friend</0>!"
* content={[
* { type: 'strong', props: { className: 'highlight' } }
* ]}
* />
* </I18nextProvider>
* ```
*
* @example
* ```jsx
* // With custom components and nested structure
* <IcuTrans
* i18nKey="docs.link"
* defaultTranslation="Read the <0>documentation <1></1></0> for more info"
* content={[
* { type: 'a', props: { href: '/docs' } },
* { type: Icon, props: { name: 'external' } }
* ]}
* />
* ```
*
* @example
* ```jsx
* // With nested children in declarations
* <IcuTrans
* i18nKey="list.items"
* defaultTranslation="<0><0>First item</0><1>Second item</1></0>"
* content={[
* {
* type: 'ul',
* props: {
* children: [
* { type: 'li', props: {} },
* { type: 'li', props: {} }
* ]
* }
* }
* ]}
* />
* ```
*/
export function IcuTrans({
i18nKey,
defaultTranslation,
content,
ns,
values = {},
i18n: i18nFromProps,
t: tFromProps,
}) {
const { i18n: i18nFromContext, defaultNS: defaultNSFromContext } = useContext(I18nContext) || {};
const i18n = i18nFromProps || i18nFromContext || getI18n();
const t = tFromProps || i18n?.t.bind(i18n);
return IcuTransWithoutContext({
i18nKey,
defaultTranslation,
content,
ns: ns || t?.ns || defaultNSFromContext || i18n?.options?.defaultNS,
values,
i18n,
t: tFromProps,
});
}
IcuTrans.displayName = 'IcuTrans';

View File

@@ -0,0 +1,24 @@
/**
* Error thrown during translation parsing
*/
export class TranslationParserError extends Error {
/**
* @param {string} message - Error message
* @param {number} [position] - Position in the translation string where the error occurred
* @param {string} [translationString] - The full translation string being parsed
*/
constructor(message, position, translationString) {
super(message);
this.name = 'TranslationParserError';
this.position = position;
this.translationString = translationString;
// Maintains proper stack trace for where our error was thrown (only available on V8)
if (Error.captureStackTrace) {
Error.captureStackTrace(this, TranslationParserError);
}
}
}

View File

@@ -0,0 +1,264 @@
/**
* Common HTML entities map for fast lookup
*/
const commonEntities = {
// Basic entities
'&nbsp;': '\u00A0', // Non-breaking space
'&amp;': '&',
'&lt;': '<',
'&gt;': '>',
'&quot;': '"',
'&apos;': "'",
// Copyright, trademark, and registration
'&copy;': '©',
'&reg;': '®',
'&trade;': '™',
// Punctuation
'&hellip;': '…',
'&ndash;': '',
'&mdash;': '—',
'&lsquo;': '\u2018',
'&rsquo;': '\u2019',
'&sbquo;': '\u201A',
'&ldquo;': '\u201C',
'&rdquo;': '\u201D',
'&bdquo;': '\u201E',
'&dagger;': '†',
'&Dagger;': '‡',
'&bull;': '•',
'&prime;': '',
'&Prime;': '″',
'&lsaquo;': '',
'&rsaquo;': '',
'&sect;': '§',
'&para;': '¶',
'&middot;': '·',
// Spaces
'&ensp;': '\u2002',
'&emsp;': '\u2003',
'&thinsp;': '\u2009',
// Currency
'&euro;': '€',
'&pound;': '£',
'&yen;': '¥',
'&cent;': '¢',
'&curren;': '¤',
// Math symbols
'&times;': '×',
'&divide;': '÷',
'&minus;': '',
'&plusmn;': '±',
'&ne;': '≠',
'&le;': '≤',
'&ge;': '≥',
'&asymp;': '≈',
'&equiv;': '≡',
'&infin;': '∞',
'&int;': '∫',
'&sum;': '∑',
'&prod;': '∏',
'&radic;': '√',
'&part;': '∂',
'&permil;': '‰',
'&deg;': '°',
'&micro;': 'µ',
// Arrows
'&larr;': '←',
'&uarr;': '↑',
'&rarr;': '→',
'&darr;': '↓',
'&harr;': '↔',
'&crarr;': '↵',
'&lArr;': '⇐',
'&uArr;': '⇑',
'&rArr;': '⇒',
'&dArr;': '⇓',
'&hArr;': '⇔',
// Greek letters (lowercase)
'&alpha;': 'α',
'&beta;': 'β',
'&gamma;': 'γ',
'&delta;': 'δ',
'&epsilon;': 'ε',
'&zeta;': 'ζ',
'&eta;': 'η',
'&theta;': 'θ',
'&iota;': 'ι',
'&kappa;': 'κ',
'&lambda;': 'λ',
'&mu;': 'μ',
'&nu;': 'ν',
'&xi;': 'ξ',
'&omicron;': 'ο',
'&pi;': 'π',
'&rho;': 'ρ',
'&sigma;': 'σ',
'&tau;': 'τ',
'&upsilon;': 'υ',
'&phi;': 'φ',
'&chi;': 'χ',
'&psi;': 'ψ',
'&omega;': 'ω',
// Greek letters (uppercase)
'&Alpha;': 'Α',
'&Beta;': 'Β',
'&Gamma;': 'Γ',
'&Delta;': 'Δ',
'&Epsilon;': 'Ε',
'&Zeta;': 'Ζ',
'&Eta;': 'Η',
'&Theta;': 'Θ',
'&Iota;': 'Ι',
'&Kappa;': 'Κ',
'&Lambda;': 'Λ',
'&Mu;': 'Μ',
'&Nu;': 'Ν',
'&Xi;': 'Ξ',
'&Omicron;': 'Ο',
'&Pi;': 'Π',
'&Rho;': 'Ρ',
'&Sigma;': 'Σ',
'&Tau;': 'Τ',
'&Upsilon;': 'Υ',
'&Phi;': 'Φ',
'&Chi;': 'Χ',
'&Psi;': 'Ψ',
'&Omega;': 'Ω',
// Latin extended
'&Agrave;': 'À',
'&Aacute;': 'Á',
'&Acirc;': 'Â',
'&Atilde;': 'Ã',
'&Auml;': 'Ä',
'&Aring;': 'Å',
'&AElig;': 'Æ',
'&Ccedil;': 'Ç',
'&Egrave;': 'È',
'&Eacute;': 'É',
'&Ecirc;': 'Ê',
'&Euml;': 'Ë',
'&Igrave;': 'Ì',
'&Iacute;': 'Í',
'&Icirc;': 'Î',
'&Iuml;': 'Ï',
'&ETH;': 'Ð',
'&Ntilde;': 'Ñ',
'&Ograve;': 'Ò',
'&Oacute;': 'Ó',
'&Ocirc;': 'Ô',
'&Otilde;': 'Õ',
'&Ouml;': 'Ö',
'&Oslash;': 'Ø',
'&Ugrave;': 'Ù',
'&Uacute;': 'Ú',
'&Ucirc;': 'Û',
'&Uuml;': 'Ü',
'&Yacute;': 'Ý',
'&THORN;': 'Þ',
'&szlig;': 'ß',
'&agrave;': 'à',
'&aacute;': 'á',
'&acirc;': 'â',
'&atilde;': 'ã',
'&auml;': 'ä',
'&aring;': 'å',
'&aelig;': 'æ',
'&ccedil;': 'ç',
'&egrave;': 'è',
'&eacute;': 'é',
'&ecirc;': 'ê',
'&euml;': 'ë',
'&igrave;': 'ì',
'&iacute;': 'í',
'&icirc;': 'î',
'&iuml;': 'ï',
'&eth;': 'ð',
'&ntilde;': 'ñ',
'&ograve;': 'ò',
'&oacute;': 'ó',
'&ocirc;': 'ô',
'&otilde;': 'õ',
'&ouml;': 'ö',
'&oslash;': 'ø',
'&ugrave;': 'ù',
'&uacute;': 'ú',
'&ucirc;': 'û',
'&uuml;': 'ü',
'&yacute;': 'ý',
'&thorn;': 'þ',
'&yuml;': 'ÿ',
// Special characters
'&iexcl;': '¡',
'&iquest;': '¿',
'&fnof;': 'ƒ',
'&circ;': 'ˆ',
'&tilde;': '˜',
'&OElig;': 'Œ',
'&oelig;': 'œ',
'&Scaron;': 'Š',
'&scaron;': 'š',
'&Yuml;': 'Ÿ',
'&ordf;': 'ª',
'&ordm;': 'º',
'&macr;': '¯',
'&acute;': '´',
'&cedil;': '¸',
'&sup1;': '¹',
'&sup2;': '²',
'&sup3;': '³',
'&frac14;': '¼',
'&frac12;': '½',
'&frac34;': '¾',
// Card suits
'&spades;': '♠',
'&clubs;': '♣',
'&hearts;': '♥',
'&diams;': '♦',
// Miscellaneous
'&loz;': '◊',
'&oline;': '‾',
'&frasl;': '',
'&weierp;': '℘',
'&image;': '',
'&real;': '',
'&alefsym;': 'ℵ',
};
// Create regex pattern for all entities
const entityPattern = new RegExp(
Object.keys(commonEntities)
.map((entity) => entity.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
.join('|'),
'g',
);
/**
* Decode HTML entities in text
*
* Uses a hybrid approach:
* 1. First pass: decode common named entities using a map
* 2. Second pass: decode numeric entities (decimal and hexadecimal)
*
* @param {string} text - Text with HTML entities
* @returns {string} Decoded text
*/
export const decodeHtmlEntities = (text) =>
text
// First pass: common named entities
.replace(entityPattern, (match) => commonEntities[match])
// Second pass: numeric entities (decimal)
.replace(/&#(\d+);/g, (_, num) => String.fromCharCode(parseInt(num, 10)))
// Third pass: numeric entities (hexadecimal)
.replace(/&#x([0-9a-fA-F]+);/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)));

View File

@@ -0,0 +1,4 @@
export * from './TranslationParserError.js';
export * from './htmlEntityDecoder.js';
export * from './tokenizer.js';
export * from './renderTranslation.js';

View File

@@ -0,0 +1,215 @@
import React from 'react';
import { TranslationParserError } from './TranslationParserError.js';
import { tokenize } from './tokenizer.js';
import { decodeHtmlEntities } from './htmlEntityDecoder.js';
/**
* Render a React element tree from a declaration node and its children
*
* @param {Object} declaration - The component declaration (type + props)
* @param {Array<React.ReactNode>} children - Array of child nodes (text, numbers, React elements)
* @param {Array<Object>} [childDeclarations] - Optional array of child declarations to use for nested rendering
* @returns {React.ReactElement} A React element
*/
const renderDeclarationNode = (declaration, children, childDeclarations) => {
const { type, props = {} } = declaration;
// If props contain a children declaration AND we have childDeclarations to work with,
// we need to recursively render the content with those child declarations
if (props.children && Array.isArray(props.children) && childDeclarations) {
// The children array contains the parsed content from inside this tag
// We need to rebuild the translation string and re-parse it with child declarations
// For now, we'll use the children directly as they're already parsed
// This happens when renderTranslation is called recursively
// Remove children from props since we'll pass them as the third argument
// eslint-disable-next-line no-unused-vars
const { children: _childrenToRemove, ...propsWithoutChildren } = props;
return React.createElement(type, propsWithoutChildren, ...children);
}
// Standard rendering with children from translation
if (children.length === 0) {
return React.createElement(type, props);
}
if (children.length === 1) {
return React.createElement(type, props, children[0]);
}
return React.createElement(type, props, ...children);
};
/**
* Render translation string with declaration tree to create React elements
*
* This function parses an ICU format translation string and reconstructs
* a React element tree using the provided declaration tree. It replaces
* numbered tags (e.g., <0>, <1>) with the corresponding components from
* the declaration array and fills them with the translated text.
*
* @param {string} translation - ICU format string (e.g., "<0>Click here</0>")
* @param {Array<Object>} [declarations=[]] - Array of component declarations matching tag numbers
* @returns {Array<React.ReactNode>} Array of React nodes (elements and text)
*
* @example
* ```jsx
* const result = renderTranslation(
* "<0>bonjour</0> monde",
* [{ type: 'strong', props: { className: 'bold' } }]
* );
* // Returns: [<strong className="bold">bonjour</strong>, " monde"]
* ```
*
* @example
* ```jsx
* // With nested children in declaration
* const result = renderTranslation(
* "<0>Click <1>here</1></0>",
* [
* {
* type: 'div',
* props: {
* children: [{ type: 'span', props: {} }]
* }
* }
* ]
* );
* ```
*/
export const renderTranslation = (translation, declarations = []) => {
if (!translation) {
return [];
}
const tokens = tokenize(translation);
const result = [];
const stack = [];
// Track tag numbers that should be treated as literal text (no declaration found)
const literalTagNumbers = new Set();
// Helper to get the current declarations array based on context
const getCurrentDeclarations = () => {
if (stack.length === 0) {
return declarations;
}
const parentFrame = stack[stack.length - 1];
// If the parent declaration has children declarations, use those
if (
parentFrame.declaration.props?.children &&
Array.isArray(parentFrame.declaration.props.children)
) {
return parentFrame.declaration.props.children;
}
// Otherwise, use the parent's declarations array
return parentFrame.declarations;
};
tokens.forEach((token) => {
// eslint-disable-next-line default-case
switch (token.type) {
case 'Text':
{
const decoded = decodeHtmlEntities(token.value);
const targetArray = stack.length > 0 ? stack[stack.length - 1].children : result;
targetArray.push(decoded);
}
break;
case 'TagOpen':
{
const { tagNumber } = token;
const currentDeclarations = getCurrentDeclarations();
const declaration = currentDeclarations[tagNumber];
if (!declaration) {
// No declaration found - treat this tag as literal text
literalTagNumbers.add(tagNumber);
const literalText = `<${tagNumber}>`;
const targetArray = stack.length > 0 ? stack[stack.length - 1].children : result;
targetArray.push(literalText);
break;
}
stack.push({
tagNumber,
children: [],
position: token.position,
declaration,
declarations: currentDeclarations,
});
}
break;
case 'TagClose':
{
const { tagNumber } = token;
// If this tag was treated as literal, output the closing tag as literal text
if (literalTagNumbers.has(tagNumber)) {
const literalText = `</${tagNumber}>`;
const literalTargetArray = stack.length > 0 ? stack[stack.length - 1].children : result;
literalTargetArray.push(literalText);
literalTagNumbers.delete(tagNumber);
break;
}
if (stack.length === 0) {
throw new TranslationParserError(
`Unexpected closing tag </${tagNumber}> at position ${token.position}`,
token.position,
translation,
);
}
const frame = stack.pop();
if (frame.tagNumber !== tagNumber) {
throw new TranslationParserError(
`Mismatched tags: expected </${frame.tagNumber}> but got </${tagNumber}> at position ${token.position}`,
token.position,
translation,
);
}
// Render the element using the declaration and collected children
const element = renderDeclarationNode(
frame.declaration,
frame.children,
frame.declarations,
);
const elementTargetArray = stack.length > 0 ? stack[stack.length - 1].children : result;
elementTargetArray.push(element);
}
break;
}
});
if (stack.length > 0) {
const unclosed = stack[stack.length - 1];
throw new TranslationParserError(
`Unclosed tag <${unclosed.tagNumber}> at position ${unclosed.position}`,
unclosed.position,
translation,
);
}
return result;
};

View File

@@ -0,0 +1,78 @@
/**
* Tokenize a translation string with numbered tags
* Note: Variables are already interpolated by the i18n system before we receive the string
*
* @param {string} translation - Translation string with numbered tags
* @returns {Array<Token>} Array of tokens
*/
export const tokenize = (translation) => {
const tokens = [];
let position = 0;
let currentText = '';
const flushText = () => {
if (currentText) {
tokens.push({
type: 'Text',
value: currentText,
position: position - currentText.length,
});
currentText = '';
}
};
while (position < translation.length) {
const char = translation[position];
// Check for opening tag: <0>, <1>, etc.
if (char === '<') {
const tagMatch = translation.slice(position).match(/^<(\d+)>/);
if (tagMatch) {
flushText();
tokens.push({
type: 'TagOpen',
value: tagMatch[0],
position,
tagNumber: parseInt(tagMatch[1], 10),
});
position += tagMatch[0].length;
} else {
// Check for closing tag: </0>, </1>, etc.
const closeTagMatch = translation.slice(position).match(/^<\/(\d+)>/);
if (closeTagMatch) {
flushText();
tokens.push({
type: 'TagClose',
value: closeTagMatch[0],
position,
tagNumber: parseInt(closeTagMatch[1], 10),
});
position += closeTagMatch[0].length;
} else {
// Regular text (including any { } characters that aren't our tags)
currentText += char;
position += 1;
}
}
} else {
// Regular text (including any { } characters that aren't our tags)
currentText += char;
position += 1;
}
}
flushText();
return tokens;
};

View File

@@ -0,0 +1,146 @@
import React from 'react';
import { warn, warnOnce, isString } from './utils.js';
import { getI18n } from './i18nInstance.js';
import { renderTranslation } from './IcuTransUtils/index.js';
/**
* IcuTrans component for rendering ICU MessageFormat translations (without React Context)
*
* This is the core implementation without React hooks or context dependencies,
* making it suitable for use in any environment. It uses a declaration tree
* approach where components are defined as type + props blueprints, fetches
* the translated string via i18next, and reconstructs the React element tree
* by replacing numbered tags (<0>, <1>) with actual components.
*
* Key features:
* - No React hooks or context (can be used anywhere)
* - ICU MessageFormat compatible
* - Supports nested component declarations
* - Automatic HTML entity decoding
* - Graceful error handling with fallbacks
* - Merges default interpolation variables
*
* Note: Users should typically use the IcuTrans export which provides automatic
* context support. This component is exposed for advanced use cases where direct
* i18n instance control is needed, or for use outside of React Context.
*
* @param {Object} props - Component props
* @param {string} props.i18nKey - The i18n key to look up the translation
* @param {string} props.defaultTranslation - The default translation in ICU format with numbered tags (e.g., "<0>Click here</0>")
* @param {Array<{type: string|React.ComponentType, props?: Object}>} props.content - Declaration tree describing React components and their props
* @param {string|string[]} [props.ns] - Optional namespace(s) for the translation. Falls back to t.ns, then i18n.options.defaultNS, then 'translation'
* @param {Object} [props.values={}] - Optional values for ICU variable interpolation (merged with i18n.options.interpolation.defaultVariables if present)
* @param {Object} [props.i18n] - i18next instance. If not provided, uses global instance from getI18n()
* @param {Function} [props.t] - Custom translation function. If not provided, uses i18n.t.bind(i18n)
* @returns {React.ReactElement} React fragment containing the rendered translation
*
* @example
* ```jsx
* // Direct usage with i18n instance
* <IcuTransWithoutContext
* i18nKey="welcome.message"
* defaultTranslation="Welcome <0>back</0>!"
* content={[
* { type: 'strong', props: { className: 'highlight' } }
* ]}
* i18n={i18nInstance}
* />
* ```
*
* @example
* ```jsx
* // With nested declarations for list rendering
* <IcuTransWithoutContext
* i18nKey="features.list"
* defaultTranslation="Features: <0><0>Fast</0><1>Reliable</1><2>Secure</2></0>"
* content={[
* {
* type: 'ul',
* props: {
* children: [
* { type: 'li', props: {} },
* { type: 'li', props: {} },
* { type: 'li', props: {} }
* ]
* }
* }
* ]}
* i18n={i18nInstance}
* />
* ```
*
* @example
* ```jsx
* // With values for ICU variable interpolation
* <IcuTransWithoutContext
* i18nKey="greeting"
* defaultTranslation="Hello <0>{name}</0>!"
* content={[{ type: 'strong', props: {} }]}
* values={{ name: 'Alice' }}
* i18n={i18nInstance}
* />
* ```
*/
export function IcuTransWithoutContext({
i18nKey,
defaultTranslation,
content,
ns,
values = {},
i18n: i18nFromProps,
t: tFromProps,
}) {
const i18n = i18nFromProps || getI18n();
if (!i18n) {
warnOnce(
i18n,
'NO_I18NEXT_INSTANCE',
`IcuTrans: You need to pass in an i18next instance using i18nextReactModule`,
{ i18nKey },
);
return React.createElement(React.Fragment, {}, defaultTranslation);
}
const t = tFromProps || i18n.t?.bind(i18n) || ((k) => k);
// prepare having a namespace
let namespaces = ns || t.ns || i18n.options?.defaultNS;
namespaces = isString(namespaces) ? [namespaces] : namespaces || ['translation'];
// Merge default interpolation variables if they exist
let mergedValues = values;
if (i18n.options?.interpolation?.defaultVariables) {
mergedValues =
values && Object.keys(values).length > 0
? { ...values, ...i18n.options.interpolation.defaultVariables }
: { ...i18n.options.interpolation.defaultVariables };
}
// Get the translation, falling back to defaultTranslation
const translation = t(i18nKey, {
defaultValue: defaultTranslation,
...mergedValues,
ns: namespaces,
});
// Render the translation with the declaration tree
try {
const rendered = renderTranslation(translation, content);
// Return as a React fragment to avoid extra wrapper
return React.createElement(React.Fragment, {}, ...rendered);
} catch (error) {
// If rendering fails, warn and fall back to the translation string
warn(
i18n,
'ICU_TRANS_RENDER_ERROR',
`IcuTrans component error for key "${i18nKey}": ${error.message}`,
{ i18nKey, error },
);
return React.createElement(React.Fragment, {}, translation);
}
}
IcuTransWithoutContext.displayName = 'IcuTransWithoutContext';

45
node_modules/react-i18next/src/Trans.js generated vendored Normal file
View File

@@ -0,0 +1,45 @@
import { useContext } from 'react';
import { nodesToString, Trans as TransWithoutContext } from './TransWithoutContext.js';
import { getI18n, I18nContext } from './context.js';
export { nodesToString };
export function Trans({
children,
count,
parent,
i18nKey,
context,
tOptions = {},
values,
defaults,
components,
ns,
i18n: i18nFromProps,
t: tFromProps,
shouldUnescape,
...additionalProps
}) {
const { i18n: i18nFromContext, defaultNS: defaultNSFromContext } = useContext(I18nContext) || {};
const i18n = i18nFromProps || i18nFromContext || getI18n();
const t = tFromProps || i18n?.t.bind(i18n);
return TransWithoutContext({
children,
count,
parent,
i18nKey,
context,
tOptions,
values,
defaults,
components,
// prepare having a namespace
ns: ns || t?.ns || defaultNSFromContext || i18n?.options?.defaultNS,
i18n,
t: tFromProps,
shouldUnescape,
...additionalProps,
});
}

631
node_modules/react-i18next/src/TransWithoutContext.js generated vendored Normal file
View File

@@ -0,0 +1,631 @@
import { Fragment, isValidElement, cloneElement, createElement, Children } from 'react';
import { keyFromSelector } from 'i18next';
import HTML from 'html-parse-stringify';
import { isObject, isString, warn, warnOnce } from './utils.js';
import { getDefaults } from './defaults.js';
import { getI18n } from './i18nInstance.js';
import { unescape } from './unescape.js';
const hasChildren = (node, checkLength) => {
if (!node) return false;
const base = node.props?.children ?? node.children;
if (checkLength) return base.length > 0;
return !!base;
};
const getChildren = (node) => {
if (!node) return [];
const children = node.props?.children ?? node.children;
return node.props?.i18nIsDynamicList ? getAsArray(children) : children;
};
const hasValidReactChildren = (children) =>
Array.isArray(children) && children.every(isValidElement);
const getAsArray = (data) => (Array.isArray(data) ? data : [data]);
const mergeProps = (source, target) => {
const newTarget = { ...target };
// translation props (source.props) should override component props (target.props)
newTarget.props = { ...target.props, ...source.props };
return newTarget;
};
const getValuesFromChildren = (children) => {
const values = {};
if (!children) return values;
const getData = (childs) => {
const childrenArray = getAsArray(childs);
childrenArray.forEach((child) => {
if (isString(child)) return;
if (hasChildren(child)) getData(getChildren(child));
else if (isObject(child) && !isValidElement(child)) Object.assign(values, child);
});
};
getData(children);
return values;
};
export const nodesToString = (children, i18nOptions, i18n, i18nKey) => {
if (!children) return '';
let stringNode = '';
// do not use `React.Children.toArray`, will fail at object children
const childrenArray = getAsArray(children);
const keepArray = i18nOptions?.transSupportBasicHtmlNodes
? (i18nOptions.transKeepBasicHtmlNodesFor ?? [])
: [];
// e.g. lorem <br/> ipsum {{ messageCount, format }} dolor <strong>bold</strong> amet
childrenArray.forEach((child, childIndex) => {
if (isString(child)) {
// actual e.g. lorem
// expected e.g. lorem
stringNode += `${child}`;
return;
}
if (isValidElement(child)) {
const { props, type } = child;
const childPropsCount = Object.keys(props).length;
const shouldKeepChild = keepArray.indexOf(type) > -1;
const childChildren = props.children;
if (!childChildren && shouldKeepChild && !childPropsCount) {
// actual e.g. lorem <br/> ipsum
// expected e.g. lorem <br/> ipsum
stringNode += `<${type}/>`;
return;
}
if ((!childChildren && (!shouldKeepChild || childPropsCount)) || props.i18nIsDynamicList) {
// actual e.g. lorem <hr className="test" /> ipsum
// expected e.g. lorem <0></0> ipsum
// or
// we got a dynamic list like
// e.g. <ul i18nIsDynamicList>{['a', 'b'].map(item => ( <li key={item}>{item}</li> ))}</ul>
// expected e.g. "<0></0>", not e.g. "<0><0>a</0><1>b</1></0>"
stringNode += `<${childIndex}></${childIndex}>`;
return;
}
if (shouldKeepChild && childPropsCount <= 1) {
// actual e.g. dolor <strong>bold</strong> amet
// expected e.g. dolor <strong>bold</strong> amet
const cnt = isString(childChildren)
? childChildren
: nodesToString(childChildren, i18nOptions, i18n, i18nKey);
stringNode += `<${type}>${cnt}</${type}>`;
return;
}
// regular case mapping the inner children
const content = nodesToString(childChildren, i18nOptions, i18n, i18nKey);
stringNode += `<${childIndex}>${content}</${childIndex}>`;
return;
}
if (child === null) {
warn(i18n, 'TRANS_NULL_VALUE', `Passed in a null value as child`, { i18nKey });
return;
}
if (isObject(child)) {
// e.g. lorem {{ value, format }} ipsum
const { format, ...clone } = child;
const keys = Object.keys(clone);
if (keys.length === 1) {
const value = format ? `${keys[0]}, ${format}` : keys[0];
stringNode += `{{${value}}}`;
return;
}
warn(
i18n,
'TRANS_INVALID_OBJ',
`Invalid child - Object should only have keys {{ value, format }} (format is optional).`,
{ i18nKey, child },
);
return;
}
warn(
i18n,
'TRANS_INVALID_VAR',
`Passed in a variable like {number} - pass variables for interpolation as full objects like {{number}}.`,
{ i18nKey, child },
);
});
return stringNode;
};
/**
* Escape literal < characters that are not part of valid tags
* Valid tags are: numbered tags like <0>, </0> or named tags from keepArray/knownComponents
* @param {string} str - The string to escape
* @param {Array<string>} keepArray - Array of HTML tag names to keep
* @param {Object} knownComponentsMap - Map of known component names
* @returns {string} String with literal < characters escaped
*/
const escapeLiteralLessThan = (str, keepArray = [], knownComponentsMap = {}) => {
if (!str) return str;
// Build a list of valid tag names (numbered indices and known component names)
const knownNames = Object.keys(knownComponentsMap);
const allValidNames = [...keepArray, ...knownNames];
// Pattern to match:
// 1. Opening tags: <number> or <name> where name is in allValidNames
// 2. Closing tags: </number> or </name> where name is in allValidNames
// 3. Self-closing tags: <name/> or <name /> where name is in keepArray
// Everything else starting with < should be escaped
let result = '';
let i = 0;
while (i < str.length) {
if (str[i] === '<') {
// Check if this is a valid tag
let isValidTag = false;
// Check for closing tag: </number> or </name>
const closingMatch = str.slice(i).match(/^<\/(\d+|[a-zA-Z][a-zA-Z0-9_-]*)>/);
if (closingMatch) {
const tagName = closingMatch[1];
// Valid if it's a number or in our valid names list
if (/^\d+$/.test(tagName) || allValidNames.includes(tagName)) {
isValidTag = true;
result += closingMatch[0];
i += closingMatch[0].length;
}
}
// Check for opening tag: <number> or <name> or <name/> or <name />
// Also handle tags with attributes: <0 href="..."> or <name class="...">
if (!isValidTag) {
// Match: <tagName [attributes] [/]>
// Attributes pattern: name="value" or name='value' or name (boolean)
const openingMatch = str
.slice(i)
.match(
/^<(\d+|[a-zA-Z][a-zA-Z0-9_-]*)(\s+[\w-]+(?:=(?:"[^"]*"|'[^']*'|[^\s>]+))?)*\s*(\/)?>/,
);
if (openingMatch) {
const tagName = openingMatch[1];
// Valid if it's a number or in our valid names list
if (/^\d+$/.test(tagName) || allValidNames.includes(tagName)) {
isValidTag = true;
result += openingMatch[0];
i += openingMatch[0].length;
}
}
}
// If not a valid tag, escape the <
if (!isValidTag) {
result += '&lt;';
i += 1;
}
} else {
result += str[i];
i += 1;
}
}
return result;
};
const renderNodes = (
children,
knownComponentsMap,
targetString,
i18n,
i18nOptions,
combinedTOpts,
shouldUnescape,
) => {
if (targetString === '') return [];
// check if contains tags we need to replace from html string to react nodes
const keepArray = i18nOptions.transKeepBasicHtmlNodesFor || [];
const emptyChildrenButNeedsHandling =
targetString && new RegExp(keepArray.map((keep) => `<${keep}`).join('|')).test(targetString);
// no need to replace tags in the targetstring
if (!children && !knownComponentsMap && !emptyChildrenButNeedsHandling && !shouldUnescape)
return [targetString];
// v2 -> interpolates upfront no need for "some <0>{{var}}</0>"" -> will be just "some {{var}}" in translation file
const data = knownComponentsMap ?? {};
const getData = (childs) => {
const childrenArray = getAsArray(childs);
childrenArray.forEach((child) => {
if (isString(child)) return;
if (hasChildren(child)) getData(getChildren(child));
else if (isObject(child) && !isValidElement(child)) Object.assign(data, child);
});
};
getData(children);
// Escape literal < characters that are not part of valid tags before parsing
const escapedString = escapeLiteralLessThan(targetString, keepArray, data);
// parse ast from string with additional wrapper tag
// -> avoids issues in parser removing prepending text nodes
const ast = HTML.parse(`<0>${escapedString}</0>`);
const opts = { ...data, ...combinedTOpts };
const renderInner = (child, node, rootReactNode) => {
const childs = getChildren(child);
const mappedChildren = mapAST(childs, node.children, rootReactNode);
// `mappedChildren` will always be empty if using the `i18nIsDynamicList` prop,
// but the children might not necessarily be react components
return (hasValidReactChildren(childs) && mappedChildren.length === 0) ||
child.props?.i18nIsDynamicList
? childs
: mappedChildren;
};
const pushTranslatedJSX = (child, inner, mem, i, isVoid) => {
if (child.dummy) {
child.children = inner; // needed on preact!
mem.push(cloneElement(child, { key: i }, isVoid ? undefined : inner));
} else {
mem.push(
...Children.map([child], (c) => {
// Build an override props object while deliberately NOT reading c.ref or c.props.ref
// use a DOM-safe marker name and never forward it to DOM nodes
const INTERNAL_DYNAMIC_MARKER = 'data-i18n-is-dynamic-list';
const override = { key: i, [INTERNAL_DYNAMIC_MARKER]: undefined };
if (c && c.props) {
Object.keys(c.props).forEach((k) => {
// skip special/internal props and the dynamic-list marker so it never reaches DOM
if (
k === 'ref' ||
k === 'children' ||
k === 'i18nIsDynamicList' ||
k === INTERNAL_DYNAMIC_MARKER
)
return;
override[k] = c.props[k];
});
}
// Use cloneElement for all element types so React preserves/forwards refs internally
// and we don't access element.ref nor c.props.ref ourselves.
return cloneElement(c, override, isVoid ? null : inner);
}),
);
}
};
// reactNode (the jsx root element or child)
// astNode (the translation string as html ast)
// rootReactNode (the most outer jsx children array or trans components prop)
const mapAST = (reactNode, astNode, rootReactNode) => {
const reactNodes = getAsArray(reactNode);
const astNodes = getAsArray(astNode);
return astNodes.reduce((mem, node, i) => {
const translationContent =
node.children?.[0]?.content &&
i18n.services.interpolator.interpolate(node.children[0].content, opts, i18n.language);
if (node.type === 'tag') {
// regular array (components or children)
let tmp = reactNodes[parseInt(node.name, 10)];
if (!tmp && knownComponentsMap) tmp = knownComponentsMap[node.name];
// trans components is an object
if (rootReactNode.length === 1 && !tmp) tmp = rootReactNode[0][node.name];
// neither
if (!tmp) tmp = {};
// should fix #1893
const props = { ...node.attrs };
if (shouldUnescape) {
Object.keys(props).forEach((p) => {
const val = props[p];
if (isString(val)) {
props[p] = unescape(val);
}
});
}
const child = Object.keys(props).length !== 0 ? mergeProps({ props }, tmp) : tmp;
const isElement = isValidElement(child);
const isValidTranslationWithChildren =
isElement && hasChildren(node, true) && !node.voidElement;
const isEmptyTransWithHTML =
emptyChildrenButNeedsHandling && isObject(child) && child.dummy && !isElement;
const isKnownComponent =
isObject(knownComponentsMap) && Object.hasOwnProperty.call(knownComponentsMap, node.name);
if (isString(child)) {
const value = i18n.services.interpolator.interpolate(child, opts, i18n.language);
mem.push(value);
} else if (
hasChildren(child) || // the jsx element has children -> loop
isValidTranslationWithChildren // valid jsx element with no children but the translation has -> loop
) {
const inner = renderInner(child, node, rootReactNode);
pushTranslatedJSX(child, inner, mem, i);
} else if (isEmptyTransWithHTML) {
// we have a empty Trans node (the dummy element) with a targetstring that contains html tags needing
// conversion to react nodes
// so we just need to map the inner stuff
const inner = mapAST(
reactNodes /* wrong but we need something */,
node.children,
rootReactNode,
);
pushTranslatedJSX(child, inner, mem, i);
} else if (Number.isNaN(parseFloat(node.name))) {
if (isKnownComponent) {
const inner = renderInner(child, node, rootReactNode);
pushTranslatedJSX(child, inner, mem, i, node.voidElement);
} else if (i18nOptions.transSupportBasicHtmlNodes && keepArray.indexOf(node.name) > -1) {
if (node.voidElement) {
mem.push(createElement(node.name, { key: `${node.name}-${i}` }));
} else {
const inner = mapAST(
reactNodes /* wrong but we need something */,
node.children,
rootReactNode,
);
mem.push(createElement(node.name, { key: `${node.name}-${i}` }, inner));
}
} else if (node.voidElement) {
mem.push(`<${node.name} />`);
} else {
const inner = mapAST(
reactNodes /* wrong but we need something */,
node.children,
rootReactNode,
);
mem.push(`<${node.name}>${inner}</${node.name}>`);
}
} else if (isObject(child) && !isElement) {
const content = node.children[0] ? translationContent : null;
// v1
// as interpolation was done already we just have a regular content node
// in the translation AST while having an object in reactNodes
// -> push the content no need to interpolate again
if (content) mem.push(content);
} else {
// If component does not have children, but translation - has
// with this in component could be components={[<span class='make-beautiful'/>]} and in translation - 'some text <0>some highlighted message</0>'
pushTranslatedJSX(
child,
translationContent,
mem,
i,
node.children.length !== 1 || !translationContent,
);
}
} else if (node.type === 'text') {
const wrapTextNodes = i18nOptions.transWrapTextNodes;
const unescapeFn =
typeof i18nOptions.unescape === 'function'
? i18nOptions.unescape
: getDefaults().unescape;
const content = shouldUnescape
? unescapeFn(i18n.services.interpolator.interpolate(node.content, opts, i18n.language))
: i18n.services.interpolator.interpolate(node.content, opts, i18n.language);
if (wrapTextNodes) {
mem.push(createElement(wrapTextNodes, { key: `${node.name}-${i}` }, content));
} else {
mem.push(content);
}
}
return mem;
}, []);
};
// call mapAST with having react nodes nested into additional node like
// we did for the string ast from translation
// return the children of that extra node to get expected result
const result = mapAST(
[{ dummy: true, children: children || [] }],
ast,
getAsArray(children || []),
);
return getChildren(result[0]);
};
const fixComponentProps = (component, index, translation) => {
const componentKey = component.key || index;
const comp = cloneElement(component, { key: componentKey });
if (
!comp.props ||
!comp.props.children ||
(translation.indexOf(`${index}/>`) < 0 && translation.indexOf(`${index} />`) < 0)
) {
return comp;
}
function Componentized() {
// <>{comp}</>
return createElement(Fragment, null, comp);
}
// <Componentized />
return createElement(Componentized, { key: componentKey });
};
const generateArrayComponents = (components, translation) =>
components.map((c, index) => fixComponentProps(c, index, translation));
const generateObjectComponents = (components, translation) => {
const componentMap = {};
Object.keys(components).forEach((c) => {
Object.assign(componentMap, {
[c]: fixComponentProps(components[c], c, translation),
});
});
return componentMap;
};
const generateComponents = (components, translation, i18n, i18nKey) => {
if (!components) return null;
// components could be either an array or an object
if (Array.isArray(components)) {
return generateArrayComponents(components, translation);
}
if (isObject(components)) {
return generateObjectComponents(components, translation);
}
// if components is not an array or an object, warn the user
// and return null
warnOnce(
i18n,
'TRANS_INVALID_COMPONENTS',
`<Trans /> "components" prop expects an object or array`,
{ i18nKey },
);
return null;
};
// A component map is an object like: { Button: <button> }, but not an object like { 1: <button> }
const isComponentsMap = (object) => {
if (!isObject(object)) return false;
if (Array.isArray(object)) return false;
return Object.keys(object).reduce(
(acc, key) => acc && Number.isNaN(Number.parseFloat(key)),
true,
);
};
export function Trans({
children,
count,
parent,
i18nKey,
context,
tOptions = {},
values,
defaults,
components,
ns,
i18n: i18nFromProps,
t: tFromProps,
shouldUnescape,
...additionalProps
}) {
const i18n = i18nFromProps || getI18n();
if (!i18n) {
warnOnce(
i18n,
'NO_I18NEXT_INSTANCE',
`Trans: You need to pass in an i18next instance using i18nextReactModule`,
{ i18nKey },
);
return children;
}
const t = tFromProps || i18n.t.bind(i18n) || ((k) => k);
const reactI18nextOptions = { ...getDefaults(), ...i18n.options?.react };
// prepare having a namespace
let namespaces = ns || t.ns || i18n.options?.defaultNS;
namespaces = isString(namespaces) ? [namespaces] : namespaces || ['translation'];
const { transDefaultProps } = reactI18nextOptions;
const mergedTOptions = transDefaultProps?.tOptions
? { ...transDefaultProps.tOptions, ...tOptions }
: tOptions;
const mergedShouldUnescape = shouldUnescape ?? transDefaultProps?.shouldUnescape;
const mergedValues = transDefaultProps?.values
? { ...transDefaultProps.values, ...values }
: values;
const mergedComponents = transDefaultProps?.components
? { ...transDefaultProps.components, ...components }
: components;
const nodeAsString = nodesToString(children, reactI18nextOptions, i18n, i18nKey);
const defaultValue =
defaults ||
mergedTOptions?.defaultValue ||
nodeAsString ||
reactI18nextOptions.transEmptyNodeValue ||
(typeof i18nKey === 'function' ? keyFromSelector(i18nKey) : i18nKey);
const { hashTransKey } = reactI18nextOptions;
const key =
i18nKey ||
(hashTransKey ? hashTransKey(nodeAsString || defaultValue) : nodeAsString || defaultValue);
if (i18n.options?.interpolation?.defaultVariables) {
// eslint-disable-next-line no-param-reassign
values =
mergedValues && Object.keys(mergedValues).length > 0
? { ...mergedValues, ...i18n.options.interpolation.defaultVariables }
: { ...i18n.options.interpolation.defaultVariables };
} else {
// eslint-disable-next-line no-param-reassign
values = mergedValues;
}
const valuesFromChildren = getValuesFromChildren(children);
if (valuesFromChildren && typeof valuesFromChildren.count === 'number' && count === undefined) {
// eslint-disable-next-line no-param-reassign
count = valuesFromChildren.count;
}
const interpolationOverride =
values ||
(count !== undefined && !i18n.options?.interpolation?.alwaysFormat) || // https://github.com/i18next/react-i18next/issues/1719 + https://github.com/i18next/react-i18next/issues/1801
!children // if !children gets problems in future, undo that fix: https://github.com/i18next/react-i18next/issues/1729 by removing !children from this condition
? mergedTOptions.interpolation
: { interpolation: { ...mergedTOptions.interpolation, prefix: '#$?', suffix: '?$#' } };
const combinedTOpts = {
...mergedTOptions,
context: context || mergedTOptions.context, // Add `context` from the props or fallback to the value from `tOptions`
count,
...values,
...interpolationOverride,
defaultValue,
ns: namespaces,
};
let translation = key ? t(key, combinedTOpts) : defaultValue;
if (translation === key && defaultValue) translation = defaultValue;
const generatedComponents = generateComponents(mergedComponents, translation, i18n, i18nKey);
let indexedChildren = generatedComponents || children;
let componentsMap = null;
if (isComponentsMap(generatedComponents)) {
componentsMap = generatedComponents;
indexedChildren = children;
}
const content = renderNodes(
indexedChildren,
componentsMap,
translation,
i18n,
reactI18nextOptions,
combinedTOpts,
mergedShouldUnescape,
);
// allows user to pass `null` to `parent`
// and override `defaultTransParent` if is present
const useAsParent = parent ?? reactI18nextOptions.defaultTransParent;
return useAsParent ? createElement(useAsParent, additionalProps, content) : content;
}

14
node_modules/react-i18next/src/Translation.js generated vendored Normal file
View File

@@ -0,0 +1,14 @@
import { useTranslation } from './useTranslation.js';
export const Translation = ({ ns, children, ...options }) => {
const [t, i18n, ready] = useTranslation(ns, options);
return children(
t,
{
i18n,
lng: i18n?.language,
},
ready,
);
};

60
node_modules/react-i18next/src/context.js generated vendored Normal file
View File

@@ -0,0 +1,60 @@
import { createContext } from 'react';
import { getDefaults, setDefaults } from './defaults.js';
import { getI18n, setI18n } from './i18nInstance.js';
import { initReactI18next } from './initReactI18next.js';
export { getDefaults, setDefaults, getI18n, setI18n, initReactI18next };
export const I18nContext = createContext();
export class ReportNamespaces {
constructor() {
this.usedNamespaces = {};
}
addUsedNamespaces(namespaces) {
namespaces.forEach((ns) => {
if (!this.usedNamespaces[ns]) this.usedNamespaces[ns] = true;
});
}
getUsedNamespaces() {
return Object.keys(this.usedNamespaces);
}
}
export const composeInitialProps = (ForComponent) => async (ctx) => {
const componentsInitialProps = (await ForComponent.getInitialProps?.(ctx)) ?? {};
const i18nInitialProps = getInitialProps();
return {
...componentsInitialProps,
...i18nInitialProps,
};
};
export const getInitialProps = () => {
const i18n = getI18n();
if (!i18n) {
console.warn(
'react-i18next:: getInitialProps: You will need to pass in an i18next instance by using initReactI18next',
);
return {};
}
const namespaces = i18n.reportNamespaces?.getUsedNamespaces() ?? [];
const ret = {};
const initialI18nStore = {};
i18n.languages.forEach((l) => {
initialI18nStore[l] = {};
namespaces.forEach((ns) => {
initialI18nStore[l][ns] = i18n.getResourceBundle(l, ns) || {};
});
});
ret.initialI18nStore = initialI18nStore;
ret.initialLanguage = i18n.language;
return ret;
};

21
node_modules/react-i18next/src/defaults.js generated vendored Normal file
View File

@@ -0,0 +1,21 @@
import { unescape } from './unescape.js';
let defaultOptions = {
bindI18n: 'languageChanged',
bindI18nStore: '',
// nsMode: 'fallback' // loop through all namespaces given to hook, HOC, render prop for key lookup
transEmptyNodeValue: '',
transSupportBasicHtmlNodes: true,
transWrapTextNodes: '',
transKeepBasicHtmlNodesFor: ['br', 'strong', 'i', 'p'],
// hashTransKey: key => key // calculate a key for Trans component based on defaultValue
useSuspense: true,
unescape,
transDefaultProps: undefined, // { tOptions: {}, shouldUnescape: false, values: {}, components: [] }
};
export const setDefaults = (options = {}) => {
defaultOptions = { ...defaultOptions, ...options };
};
export const getDefaults = () => defaultOptions;

7
node_modules/react-i18next/src/i18nInstance.js generated vendored Normal file
View File

@@ -0,0 +1,7 @@
let i18nInstance;
export const setI18n = (instance) => {
i18nInstance = instance;
};
export const getI18n = () => i18nInstance;

26
node_modules/react-i18next/src/index.js generated vendored Normal file
View File

@@ -0,0 +1,26 @@
export { Trans } from './Trans.js';
export { Trans as TransWithoutContext } from './TransWithoutContext.js';
export { IcuTrans } from './IcuTrans.js';
export { IcuTransWithoutContext } from './IcuTransWithoutContext.js';
export { useTranslation } from './useTranslation.js';
export { withTranslation } from './withTranslation.js';
export { Translation } from './Translation.js';
export { I18nextProvider } from './I18nextProvider.js';
export { withSSR } from './withSSR.js';
export { useSSR } from './useSSR.js';
export { initReactI18next } from './initReactI18next.js';
export { setDefaults, getDefaults } from './defaults.js';
export { setI18n, getI18n } from './i18nInstance.js';
export { nodesToString } from './Trans.js';
export { I18nContext, composeInitialProps, getInitialProps } from './context.js';
// dummy functions for icu.macro support
export const date = () => '';
export const time = () => '';
export const number = () => '';
export const select = () => '';
export const plural = () => '';
export const selectOrdinal = () => '';

11
node_modules/react-i18next/src/initReactI18next.js generated vendored Normal file
View File

@@ -0,0 +1,11 @@
import { setDefaults } from './defaults.js';
import { setI18n } from './i18nInstance.js';
export const initReactI18next = {
type: '3rdParty',
init(instance) {
setDefaults(instance.options.react);
setI18n(instance);
},
};

31
node_modules/react-i18next/src/unescape.js generated vendored Normal file
View File

@@ -0,0 +1,31 @@
// unescape common html entities
const matchHtmlEntity =
/&(?:amp|#38|lt|#60|gt|#62|apos|#39|quot|#34|nbsp|#160|copy|#169|reg|#174|hellip|#8230|#x2F|#47);/g;
const htmlEntities = {
'&amp;': '&',
'&#38;': '&',
'&lt;': '<',
'&#60;': '<',
'&gt;': '>',
'&#62;': '>',
'&apos;': "'",
'&#39;': "'",
'&quot;': '"',
'&#34;': '"',
'&nbsp;': ' ',
'&#160;': ' ',
'&copy;': '©',
'&#169;': '©',
'&reg;': '®',
'&#174;': '®',
'&hellip;': '…',
'&#8230;': '…',
'&#x2F;': '/',
'&#47;': '/',
};
const unescapeHtmlEntity = (m) => htmlEntities[m];
export const unescape = (text) => text.replace(matchHtmlEntity, unescapeHtmlEntity);

51
node_modules/react-i18next/src/useSSR.js generated vendored Normal file
View File

@@ -0,0 +1,51 @@
import { useContext } from 'react';
import { getI18n, I18nContext } from './context.js';
import { warnOnce } from './utils.js';
export const useSSR = (initialI18nStore, initialLanguage, props = {}) => {
const { i18n: i18nFromProps } = props;
const { i18n: i18nFromContext } = useContext(I18nContext) || {};
const i18n = i18nFromProps || i18nFromContext || getI18n();
if (!i18n) {
warnOnce(
i18n,
'NO_I18NEXT_INSTANCE',
'useSSR: You will need to pass in an i18next instance by using initReactI18next or by passing it via props or context. In monorepo setups, make sure there is only one instance of react-i18next.',
);
return;
}
// opt out if is a cloned instance, eg. created by i18next-http-middleware on request
// -> do not set initial stuff on server side
if (i18n.options?.isClone) return;
// nextjs / SSR: getting data from next.js or other ssr stack
if (initialI18nStore && !i18n.initializedStoreOnce) {
if (!i18n.services?.resourceStore) {
warnOnce(
i18n,
'I18N_NOT_INITIALIZED',
'useSSR: i18n instance was found but not initialized (services.resourceStore is missing). Make sure you call i18next.init() before using useSSR — e.g. at module level, not only in getStaticProps/getServerSideProps.',
);
return;
}
i18n.services.resourceStore.data = initialI18nStore;
// add namespaces to the config - so a languageChange call loads all namespaces needed
i18n.options.ns = Object.values(initialI18nStore).reduce((mem, lngResources) => {
Object.keys(lngResources).forEach((ns) => {
if (mem.indexOf(ns) < 0) mem.push(ns);
});
return mem;
}, i18n.options.ns);
i18n.initializedStoreOnce = true;
i18n.isInitialized = true;
}
if (initialLanguage && !i18n.initializedLanguageOnce) {
i18n.changeLanguage(initialLanguage);
i18n.initializedLanguageOnce = true;
}
};

222
node_modules/react-i18next/src/useTranslation.js generated vendored Normal file
View File

@@ -0,0 +1,222 @@
import { useContext, useCallback, useMemo, useEffect, useRef, useState } from 'react';
// eslint-disable-next-line import/no-extraneous-dependencies
import { useSyncExternalStore } from 'use-sync-external-store/shim';
import { getI18n, getDefaults, ReportNamespaces, I18nContext } from './context.js';
import {
warnOnce,
loadNamespaces,
loadLanguages,
hasLoadedNamespace,
isString,
isObject,
} from './utils.js';
const notReadyT = (k, optsOrDefaultValue) => {
if (isString(optsOrDefaultValue)) return optsOrDefaultValue;
if (isObject(optsOrDefaultValue) && isString(optsOrDefaultValue.defaultValue))
return optsOrDefaultValue.defaultValue;
// Selector functions and arrays of selector functions cannot be meaningfully resolved
// before i18n is ready — return empty string rather than leaking a function reference.
if (typeof k === 'function') return '';
if (Array.isArray(k)) {
const last = k[k.length - 1];
return typeof last === 'function' ? '' : last;
}
return k;
};
const notReadySnapshot = { t: notReadyT, ready: false };
const dummySubscribe = () => () => {};
export const useTranslation = (ns, props = {}) => {
const { i18n: i18nFromProps } = props;
const { i18n: i18nFromContext, defaultNS: defaultNSFromContext } = useContext(I18nContext) || {};
const i18n = i18nFromProps || i18nFromContext || getI18n();
if (i18n && !i18n.reportNamespaces) i18n.reportNamespaces = new ReportNamespaces();
if (!i18n) {
warnOnce(
i18n,
'NO_I18NEXT_INSTANCE',
'useTranslation: You will need to pass in an i18next instance by using initReactI18next',
);
}
const i18nOptions = useMemo(
() => ({ ...getDefaults(), ...i18n?.options?.react, ...props }),
[i18n, props],
);
const { useSuspense, keyPrefix } = i18nOptions;
const nsOrContext = ns || defaultNSFromContext || i18n?.options?.defaultNS;
const unstableNamespaces = isString(nsOrContext) ? [nsOrContext] : nsOrContext || ['translation'];
const namespaces = useMemo(() => unstableNamespaces, unstableNamespaces);
i18n?.reportNamespaces?.addUsedNamespaces?.(namespaces);
const revisionRef = useRef(0);
const subscribe = useCallback(
(callback) => {
if (!i18n) return dummySubscribe;
const { bindI18n, bindI18nStore } = i18nOptions;
const wrappedCallback = () => {
revisionRef.current += 1;
callback();
};
if (bindI18n) i18n.on(bindI18n, wrappedCallback);
if (bindI18nStore) i18n.store.on(bindI18nStore, wrappedCallback);
return () => {
if (bindI18n) bindI18n.split(' ').forEach((e) => i18n.off(e, wrappedCallback));
if (bindI18nStore)
bindI18nStore.split(' ').forEach((e) => i18n.store.off(e, wrappedCallback));
};
},
[i18n, i18nOptions],
);
const snapshotRef = useRef();
const getSnapshot = useCallback(() => {
if (!i18n) {
return notReadySnapshot;
}
const calculatedReady =
!!(i18n.isInitialized || i18n.initializedStoreOnce) &&
namespaces.every((n) => hasLoadedNamespace(n, i18n, i18nOptions));
const currentLng = props.lng || i18n.language;
const currentRevision = revisionRef.current;
const lastSnapshot = snapshotRef.current;
if (
lastSnapshot &&
lastSnapshot.ready === calculatedReady &&
lastSnapshot.lng === currentLng &&
lastSnapshot.keyPrefix === keyPrefix &&
lastSnapshot.revision === currentRevision // Check revision
) {
return lastSnapshot;
}
const calculatedT = i18n.getFixedT(
currentLng,
i18nOptions.nsMode === 'fallback' ? namespaces : namespaces[0],
keyPrefix,
);
const newSnapshot = {
t: calculatedT,
ready: calculatedReady,
lng: currentLng,
keyPrefix,
revision: currentRevision, // Store revision
};
snapshotRef.current = newSnapshot;
return newSnapshot;
}, [i18n, namespaces, keyPrefix, i18nOptions, props.lng]);
// We still need a state to manually trigger a re-render on load when the store doesn't emit an event.
const [loadCount, setLoadCount] = useState(0);
const { t, ready } = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
useEffect(() => {
if (i18n && !ready && !useSuspense) {
const onLoaded = () => setLoadCount((c) => c + 1);
if (props.lng) {
loadLanguages(i18n, props.lng, namespaces, onLoaded);
} else {
loadNamespaces(i18n, namespaces, onLoaded);
}
}
}, [i18n, props.lng, namespaces, ready, useSuspense, loadCount]);
const finalI18n = i18n || {};
// cache one wrapper per hook caller and only recreate it when language changes
const wrapperRef = useRef(null);
const wrapperLangRef = useRef();
// helper to create a wrapper instance (avoid duplicating descriptor logic)
const createI18nWrapper = (original) => {
const descriptors = Object.getOwnPropertyDescriptors(original);
if (descriptors.__original) delete descriptors.__original;
const wrapper = Object.create(Object.getPrototypeOf(original), descriptors);
if (!Object.prototype.hasOwnProperty.call(wrapper, '__original')) {
try {
Object.defineProperty(wrapper, '__original', {
value: original,
writable: false,
enumerable: false,
configurable: false,
});
} catch (_) {
/* ignore */
}
}
return wrapper;
};
const ret = useMemo(() => {
const original = finalI18n;
const lang = original?.language;
let i18nWrapper = original;
if (original) {
// if we already created a wrapper for this original instance
if (wrapperRef.current && wrapperRef.current.__original === original) {
// language changed -> create fresh wrapper so identity changes
if (wrapperLangRef.current !== lang) {
i18nWrapper = createI18nWrapper(original);
wrapperRef.current = i18nWrapper;
wrapperLangRef.current = lang;
} else {
// reuse existing wrapper when language didn't change
i18nWrapper = wrapperRef.current;
}
} else {
// first time for this original instance -> create wrapper
i18nWrapper = createI18nWrapper(original);
wrapperRef.current = i18nWrapper;
wrapperLangRef.current = lang;
}
}
const effectiveT =
!ready && !useSuspense
? (...args) => {
warnOnce(
i18n,
'USE_T_BEFORE_READY',
'useTranslation: t was called before ready. When using useSuspense: false, make sure to check the ready flag before using t.',
);
return t(...args);
}
: t;
const arr = [effectiveT, i18nWrapper, ready];
arr.t = effectiveT;
arr.i18n = i18nWrapper;
arr.ready = ready;
return arr;
}, [t, finalI18n, ready, finalI18n.resolvedLanguage, finalI18n.language, finalI18n.languages]);
if (i18n && useSuspense && !ready) {
throw new Promise((resolve) => {
const onLoaded = () => resolve();
if (props.lng) {
loadLanguages(i18n, props.lng, namespaces, onLoaded);
} else {
loadNamespaces(i18n, namespaces, onLoaded);
}
});
}
return ret;
};

93
node_modules/react-i18next/src/utils.js generated vendored Normal file
View File

@@ -0,0 +1,93 @@
/** @type {(i18n:any,code:import('../TransWithoutContext').ErrorCode,msg?:string, rest?:{[key:string]: any})=>void} */
export const warn = (i18n, code, msg, rest) => {
const args = [msg, { code, ...(rest || {}) }];
if (i18n?.services?.logger?.forward) {
return i18n.services.logger.forward(args, 'warn', 'react-i18next::', true);
}
if (isString(args[0])) args[0] = `react-i18next:: ${args[0]}`;
if (i18n?.services?.logger?.warn) {
i18n.services.logger.warn(...args);
} else if (console?.warn) {
console.warn(...args);
}
};
const alreadyWarned = {};
/** @type {typeof warn} */
export const warnOnce = (i18n, code, msg, rest) => {
if (isString(msg) && alreadyWarned[msg]) return;
if (isString(msg)) alreadyWarned[msg] = new Date();
warn(i18n, code, msg, rest);
};
// not needed right now
//
// export const deprecated = (i18n, ...args) => {
// if (process && process.env && (!process.env.NODE_ENV || process.env.NODE_ENV === 'development')) {
// if (isString(args[0])) args[0] = `deprecation warning -> ${args[0]}`;
// warnOnce(i18n, ...args);
// }
// }
const loadedClb = (i18n, cb) => () => {
// delay ready if not yet initialized i18n instance
if (i18n.isInitialized) {
cb();
} else {
const initialized = () => {
// due to emitter removing issue in i18next we need to delay remove
setTimeout(() => {
i18n.off('initialized', initialized);
}, 0);
cb();
};
i18n.on('initialized', initialized);
}
};
export const loadNamespaces = (i18n, ns, cb) => {
i18n.loadNamespaces(ns, loadedClb(i18n, cb));
};
// should work with I18NEXT >= v22.5.0
export const loadLanguages = (i18n, lng, ns, cb) => {
// eslint-disable-next-line no-param-reassign
if (isString(ns)) ns = [ns];
if (i18n.options.preload && i18n.options.preload.indexOf(lng) > -1)
return loadNamespaces(i18n, ns, cb);
ns.forEach((n) => {
if (i18n.options.ns.indexOf(n) < 0) i18n.options.ns.push(n);
});
i18n.loadLanguages(lng, loadedClb(i18n, cb));
};
export const hasLoadedNamespace = (ns, i18n, options = {}) => {
if (!i18n.languages || !i18n.languages.length) {
warnOnce(i18n, 'NO_LANGUAGES', 'i18n.languages were undefined or empty', {
languages: i18n.languages,
});
return true;
}
return i18n.hasLoadedNamespace(ns, {
lng: options.lng,
precheck: (i18nInstance, loadNotPending) => {
if (
options.bindI18n &&
options.bindI18n.indexOf('languageChanging') > -1 &&
i18nInstance.services.backendConnector.backend &&
i18nInstance.isLanguageChangingTo &&
!loadNotPending(i18nInstance.isLanguageChangingTo, ns)
)
return false;
},
});
};
export const getDisplayName = (Component) =>
Component.displayName ||
Component.name ||
(isString(Component) && Component.length > 0 ? Component : 'Unknown');
export const isString = (obj) => typeof obj === 'string';
export const isObject = (obj) => typeof obj === 'object' && obj !== null;

21
node_modules/react-i18next/src/withSSR.js generated vendored Normal file
View File

@@ -0,0 +1,21 @@
import { createElement } from 'react';
import { useSSR } from './useSSR.js';
import { composeInitialProps } from './context.js';
import { getDisplayName } from './utils.js';
export const withSSR = () =>
function Extend(WrappedComponent) {
function I18nextWithSSR({ initialI18nStore, initialLanguage, ...rest }) {
useSSR(initialI18nStore, initialLanguage);
return createElement(WrappedComponent, {
...rest,
});
}
I18nextWithSSR.getInitialProps = composeInitialProps(WrappedComponent);
I18nextWithSSR.displayName = `withI18nextSSR(${getDisplayName(WrappedComponent)})`;
I18nextWithSSR.WrappedComponent = WrappedComponent;
return I18nextWithSSR;
};

35
node_modules/react-i18next/src/withTranslation.js generated vendored Normal file
View File

@@ -0,0 +1,35 @@
import { createElement, forwardRef as forwardRefReact } from 'react';
import { useTranslation } from './useTranslation.js';
import { getDisplayName } from './utils.js';
export const withTranslation = (ns, options = {}) =>
function Extend(WrappedComponent) {
function I18nextWithTranslation({ forwardedRef, ...rest }) {
const [t, i18n, ready] = useTranslation(ns, { ...rest, keyPrefix: options.keyPrefix });
const passDownProps = {
...rest,
t,
i18n,
tReady: ready,
};
if (options.withRef && forwardedRef) {
passDownProps.ref = forwardedRef;
} else if (!options.withRef && forwardedRef) {
passDownProps.forwardedRef = forwardedRef;
}
return createElement(WrappedComponent, passDownProps);
}
I18nextWithTranslation.displayName = `withI18nextTranslation(${getDisplayName(
WrappedComponent,
)})`;
I18nextWithTranslation.WrappedComponent = WrappedComponent;
const forwardRef = (props, ref) =>
// eslint-disable-next-line prefer-object-spread
createElement(I18nextWithTranslation, Object.assign({}, props, { forwardedRef: ref }));
return options.withRef ? forwardRefReact(forwardRef) : I18nextWithTranslation;
};